|
@@ -832,7 +832,7 @@ struct mg_request_handler_info {
|
|
mg_websocket_connect_handler connect_handler;
|
|
mg_websocket_connect_handler connect_handler;
|
|
mg_websocket_ready_handler ready_handler;
|
|
mg_websocket_ready_handler ready_handler;
|
|
mg_websocket_data_handler data_handler;
|
|
mg_websocket_data_handler data_handler;
|
|
- mg_connection_close_handler close_handler;
|
|
|
|
|
|
+ mg_websocket_close_handler close_handler;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
|
|
@@ -5748,7 +5748,7 @@ static void send_websocket_handshake(struct mg_connection *conn)
|
|
"Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
|
|
"Sec-WebSocket-Accept: ", b64_sha, "\r\n\r\n");
|
|
}
|
|
}
|
|
|
|
|
|
-static void read_websocket(struct mg_connection *conn)
|
|
|
|
|
|
+static void read_websocket(struct mg_connection *conn, mg_websocket_data_handler ws_data_handler, void *callback_data)
|
|
{
|
|
{
|
|
/* Pointer to the beginning of the portion of the incoming websocket
|
|
/* Pointer to the beginning of the portion of the incoming websocket
|
|
message queue.
|
|
message queue.
|
|
@@ -5867,11 +5867,11 @@ static void read_websocket(struct mg_connection *conn)
|
|
|
|
|
|
/* Exit the loop if callback signalled to exit,
|
|
/* Exit the loop if callback signalled to exit,
|
|
or "connection close" opcode received. */
|
|
or "connection close" opcode received. */
|
|
- if ((conn->ctx->callbacks.websocket_data != NULL &&
|
|
|
|
|
|
+ if ((ws_data_handler != NULL &&
|
|
#ifdef USE_LUA
|
|
#ifdef USE_LUA
|
|
(conn->lua_websocket_state == NULL) &&
|
|
(conn->lua_websocket_state == NULL) &&
|
|
#endif
|
|
#endif
|
|
- !conn->ctx->callbacks.websocket_data(conn, mop, data, data_len)) ||
|
|
|
|
|
|
+ !ws_data_handler(conn, mop, data, data_len, callback_data)) ||
|
|
#ifdef USE_LUA
|
|
#ifdef USE_LUA
|
|
(conn->lua_websocket_state &&
|
|
(conn->lua_websocket_state &&
|
|
!lua_websocket_data(conn, conn->lua_websocket_state, mop, data, data_len)) ||
|
|
!lua_websocket_data(conn, conn->lua_websocket_state, mop, data, data_len)) ||
|
|
@@ -5939,7 +5939,15 @@ int mg_websocket_write(struct mg_connection* conn, int opcode, const char* data,
|
|
return retval;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
|
|
-static void handle_websocket_request(struct mg_connection *conn, const char *path, int is_script_resource)
|
|
|
|
|
|
+static void handle_websocket_request(struct mg_connection *conn,
|
|
|
|
+ const char *path,
|
|
|
|
+ int is_script_resource,
|
|
|
|
+ mg_websocket_connect_handler ws_connect_handler,
|
|
|
|
+ mg_websocket_ready_handler ws_ready_handler,
|
|
|
|
+ mg_websocket_data_handler ws_data_handler,
|
|
|
|
+ mg_websocket_close_handler ws_close_handler,
|
|
|
|
+ void *cbData
|
|
|
|
+ )
|
|
{
|
|
{
|
|
const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
|
|
const char *version = mg_get_header(conn, "Sec-WebSocket-Version");
|
|
#ifdef USE_LUA
|
|
#ifdef USE_LUA
|
|
@@ -5953,8 +5961,8 @@ static void handle_websocket_request(struct mg_connection *conn, const char *pat
|
|
|
|
|
|
if (version == NULL || strcmp(version, "13") != 0) {
|
|
if (version == NULL || strcmp(version, "13") != 0) {
|
|
send_http_error(conn, 426, "%s", "Protocol upgrade required");
|
|
send_http_error(conn, 426, "%s", "Protocol upgrade required");
|
|
- } else if (conn->ctx->callbacks.websocket_connect != NULL &&
|
|
|
|
- conn->ctx->callbacks.websocket_connect(conn) != 0) {
|
|
|
|
|
|
+ } else if (ws_connect_handler != NULL &&
|
|
|
|
+ ws_connect_handler(conn, cbData) != 0) {
|
|
/* C callback has returned non-zero, do not proceed with handshake. */
|
|
/* C callback has returned non-zero, do not proceed with handshake. */
|
|
/* The C callback is called before Lua and may prevent Lua from handling the websocket. */
|
|
/* The C callback is called before Lua and may prevent Lua from handling the websocket. */
|
|
} else {
|
|
} else {
|
|
@@ -5978,10 +5986,14 @@ static void handle_websocket_request(struct mg_connection *conn, const char *pat
|
|
{
|
|
{
|
|
/* No Lua websock script specified. */
|
|
/* No Lua websock script specified. */
|
|
send_websocket_handshake(conn);
|
|
send_websocket_handshake(conn);
|
|
- if (conn->ctx->callbacks.websocket_ready != NULL) {
|
|
|
|
- conn->ctx->callbacks.websocket_ready(conn);
|
|
|
|
|
|
+ if (ws_ready_handler != NULL) {
|
|
|
|
+ ws_ready_handler(conn, cbData);
|
|
}
|
|
}
|
|
- read_websocket(conn);
|
|
|
|
|
|
+ read_websocket(conn, ws_data_handler, cbData);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (ws_close_handler) {
|
|
|
|
+ ws_close_handler(conn, cbData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -6269,7 +6281,7 @@ static void mg_set_request_handler_type(struct mg_context *ctx,
|
|
mg_websocket_connect_handler connect_handler,
|
|
mg_websocket_connect_handler connect_handler,
|
|
mg_websocket_ready_handler ready_handler,
|
|
mg_websocket_ready_handler ready_handler,
|
|
mg_websocket_data_handler data_handler,
|
|
mg_websocket_data_handler data_handler,
|
|
- mg_connection_close_handler close_handler,
|
|
|
|
|
|
+ mg_websocket_close_handler close_handler,
|
|
void *cbdata)
|
|
void *cbdata)
|
|
{
|
|
{
|
|
struct mg_request_handler_info *tmp_rh, **lastref;
|
|
struct mg_request_handler_info *tmp_rh, **lastref;
|
|
@@ -6360,15 +6372,23 @@ void mg_set_websocket_handler(struct mg_context *ctx,
|
|
mg_websocket_connect_handler connect_handler,
|
|
mg_websocket_connect_handler connect_handler,
|
|
mg_websocket_ready_handler ready_handler,
|
|
mg_websocket_ready_handler ready_handler,
|
|
mg_websocket_data_handler data_handler,
|
|
mg_websocket_data_handler data_handler,
|
|
- mg_connection_close_handler close_handler,
|
|
|
|
|
|
+ mg_websocket_close_handler close_handler,
|
|
void *cbdata
|
|
void *cbdata
|
|
)
|
|
)
|
|
{
|
|
{
|
|
- int is_delete_request = (connect_handler!=NULL) || (ready_handler!=NULL) || (data_handler!=NULL) || (close_handler!=NULL);
|
|
|
|
|
|
+ int is_delete_request = (connect_handler==NULL) && (ready_handler==NULL) && (data_handler==NULL) && (close_handler==NULL);
|
|
mg_set_request_handler_type(ctx, uri, 1, is_delete_request, NULL, connect_handler, ready_handler, data_handler, close_handler, cbdata);
|
|
mg_set_request_handler_type(ctx, uri, 1, is_delete_request, NULL, connect_handler, ready_handler, data_handler, close_handler, cbdata);
|
|
}
|
|
}
|
|
|
|
|
|
-static int get_request_handler(struct mg_connection *conn, int is_websocket_request, mg_request_handler *handler, void **cbdata)
|
|
|
|
|
|
+static int get_request_handler(struct mg_connection *conn,
|
|
|
|
+ int is_websocket_request,
|
|
|
|
+ mg_request_handler *handler,
|
|
|
|
+ mg_websocket_connect_handler *connect_handler,
|
|
|
|
+ mg_websocket_ready_handler *ready_handler,
|
|
|
|
+ mg_websocket_data_handler *data_handler,
|
|
|
|
+ mg_websocket_close_handler *close_handler,
|
|
|
|
+ void **cbdata
|
|
|
|
+ )
|
|
{
|
|
{
|
|
struct mg_request_info *request_info = mg_get_request_info(conn);
|
|
struct mg_request_info *request_info = mg_get_request_info(conn);
|
|
const char *uri = request_info->uri;
|
|
const char *uri = request_info->uri;
|
|
@@ -6381,7 +6401,15 @@ static int get_request_handler(struct mg_connection *conn, int is_websocket_requ
|
|
for (tmp_rh = conn->ctx->request_handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
|
|
for (tmp_rh = conn->ctx->request_handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
|
|
if (tmp_rh->is_websocket_handler == is_websocket_request) {
|
|
if (tmp_rh->is_websocket_handler == is_websocket_request) {
|
|
if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri,uri)) {
|
|
if (urilen == tmp_rh->uri_len && !strcmp(tmp_rh->uri,uri)) {
|
|
- *handler = tmp_rh->handler;
|
|
|
|
|
|
+
|
|
|
|
+ if (is_websocket_request) {
|
|
|
|
+ *connect_handler = tmp_rh->connect_handler;
|
|
|
|
+ *ready_handler = tmp_rh->ready_handler;
|
|
|
|
+ *data_handler = tmp_rh->data_handler;
|
|
|
|
+ *close_handler = tmp_rh->close_handler;
|
|
|
|
+ } else {
|
|
|
|
+ *handler = tmp_rh->handler;
|
|
|
|
+ }
|
|
*cbdata = tmp_rh->cbdata;
|
|
*cbdata = tmp_rh->cbdata;
|
|
mg_unlock_context(conn->ctx);
|
|
mg_unlock_context(conn->ctx);
|
|
return 1;
|
|
return 1;
|
|
@@ -6396,7 +6424,14 @@ static int get_request_handler(struct mg_connection *conn, int is_websocket_requ
|
|
&& uri[tmp_rh->uri_len] == '/'
|
|
&& uri[tmp_rh->uri_len] == '/'
|
|
&& memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
|
|
&& memcmp(tmp_rh->uri, uri, tmp_rh->uri_len) == 0) {
|
|
|
|
|
|
- *handler = tmp_rh->handler;
|
|
|
|
|
|
+ if (is_websocket_request) {
|
|
|
|
+ *connect_handler = tmp_rh->connect_handler;
|
|
|
|
+ *ready_handler = tmp_rh->ready_handler;
|
|
|
|
+ *data_handler = tmp_rh->data_handler;
|
|
|
|
+ *close_handler = tmp_rh->close_handler;
|
|
|
|
+ } else {
|
|
|
|
+ *handler = tmp_rh->handler;
|
|
|
|
+ }
|
|
*cbdata = tmp_rh->cbdata;
|
|
*cbdata = tmp_rh->cbdata;
|
|
mg_unlock_context(conn->ctx);
|
|
mg_unlock_context(conn->ctx);
|
|
return 1;
|
|
return 1;
|
|
@@ -6408,7 +6443,15 @@ static int get_request_handler(struct mg_connection *conn, int is_websocket_requ
|
|
for (tmp_rh = conn->ctx->request_handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
|
|
for (tmp_rh = conn->ctx->request_handlers; tmp_rh != NULL; tmp_rh = tmp_rh->next) {
|
|
if (tmp_rh->is_websocket_handler == is_websocket_request) {
|
|
if (tmp_rh->is_websocket_handler == is_websocket_request) {
|
|
if (match_prefix(tmp_rh->uri, (int)tmp_rh->uri_len, uri) > 0) {
|
|
if (match_prefix(tmp_rh->uri, (int)tmp_rh->uri_len, uri) > 0) {
|
|
- *handler = tmp_rh->handler;
|
|
|
|
|
|
+
|
|
|
|
+ if (is_websocket_request) {
|
|
|
|
+ *connect_handler = tmp_rh->connect_handler;
|
|
|
|
+ *ready_handler = tmp_rh->ready_handler;
|
|
|
|
+ *data_handler = tmp_rh->data_handler;
|
|
|
|
+ *close_handler = tmp_rh->close_handler;
|
|
|
|
+ } else {
|
|
|
|
+ *handler = tmp_rh->handler;
|
|
|
|
+ }
|
|
*cbdata = tmp_rh->cbdata;
|
|
*cbdata = tmp_rh->cbdata;
|
|
mg_unlock_context(conn->ctx);
|
|
mg_unlock_context(conn->ctx);
|
|
return 1;
|
|
return 1;
|
|
@@ -6420,6 +6463,33 @@ static int get_request_handler(struct mg_connection *conn, int is_websocket_requ
|
|
return 0; /* none found */
|
|
return 0; /* none found */
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
|
|
+static int deprecated_websocket_connect_wrapper(const struct mg_connection * conn, void *cbdata)
|
|
|
|
+{
|
|
|
|
+ struct mg_callbacks *pcallbacks = (struct mg_callbacks*)cbdata;
|
|
|
|
+ if (pcallbacks->websocket_connect) {
|
|
|
|
+ return pcallbacks->websocket_connect(conn);
|
|
|
|
+ }
|
|
|
|
+ return 1;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void deprecated_websocket_ready_wrapper(const struct mg_connection * conn, void *cbdata)
|
|
|
|
+{
|
|
|
|
+ struct mg_callbacks *pcallbacks = (struct mg_callbacks*)cbdata;
|
|
|
|
+ if (pcallbacks->websocket_ready) {
|
|
|
|
+ pcallbacks->websocket_ready((struct mg_connection *)conn);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int deprecated_websocket_data_wrapper(const struct mg_connection * conn, int bits, char * data, size_t len, void *cbdata)
|
|
|
|
+{
|
|
|
|
+ struct mg_callbacks *pcallbacks = (struct mg_callbacks*)cbdata;
|
|
|
|
+ if (pcallbacks->websocket_data) {
|
|
|
|
+ return pcallbacks->websocket_data((struct mg_connection *)conn, bits, data, len);
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
/* This is the heart of the Civetweb's logic.
|
|
/* This is the heart of the Civetweb's logic.
|
|
This function is called when the request is read, parsed and validated,
|
|
This function is called when the request is read, parsed and validated,
|
|
and Civetweb must decide what action to take: serve a file, or
|
|
and Civetweb must decide what action to take: serve a file, or
|
|
@@ -6428,11 +6498,15 @@ static void handle_request(struct mg_connection *conn)
|
|
{
|
|
{
|
|
struct mg_request_info *ri = &conn->request_info;
|
|
struct mg_request_info *ri = &conn->request_info;
|
|
char path[PATH_MAX];
|
|
char path[PATH_MAX];
|
|
- int uri_len, ssl_index, is_script_resource, is_websocket_request, is_put_or_delete_request;
|
|
|
|
|
|
+ int uri_len, ssl_index, is_script_resource, is_websocket_request, is_put_or_delete_request, is_callback_resource;
|
|
int i;
|
|
int i;
|
|
struct file file = STRUCT_FILE_INITIALIZER;
|
|
struct file file = STRUCT_FILE_INITIALIZER;
|
|
time_t curtime = time(NULL);
|
|
time_t curtime = time(NULL);
|
|
mg_request_handler callback_handler = NULL;
|
|
mg_request_handler callback_handler = NULL;
|
|
|
|
+ mg_websocket_connect_handler ws_connect_handler = NULL;
|
|
|
|
+ mg_websocket_ready_handler ws_ready_handler = NULL;
|
|
|
|
+ mg_websocket_data_handler ws_data_handler = NULL;
|
|
|
|
+ mg_websocket_close_handler ws_close_handler = NULL;
|
|
void * callback_data = NULL;
|
|
void * callback_data = NULL;
|
|
#if !defined(NO_FILES)
|
|
#if !defined(NO_FILES)
|
|
char date[64];
|
|
char date[64];
|
|
@@ -6505,14 +6579,19 @@ static void handle_request(struct mg_connection *conn)
|
|
is_websocket_request = is_websocket_protocol(conn);
|
|
is_websocket_request = is_websocket_protocol(conn);
|
|
|
|
|
|
/* 5.2. check if the request will be handled by a callback */
|
|
/* 5.2. check if the request will be handled by a callback */
|
|
- if (get_request_handler(conn, is_websocket_request, &callback_handler, &callback_data)) {
|
|
|
|
|
|
+ if (get_request_handler(conn, is_websocket_request,
|
|
|
|
+ &callback_handler,
|
|
|
|
+ &ws_connect_handler, &ws_ready_handler, &ws_data_handler, &ws_close_handler,
|
|
|
|
+ &callback_data)) {
|
|
/* 5.2.1. A callback will handle this request. All requests handled by a callback
|
|
/* 5.2.1. A callback will handle this request. All requests handled by a callback
|
|
have to be considered as requests to a script resource. */
|
|
have to be considered as requests to a script resource. */
|
|
|
|
+ is_callback_resource = 1;
|
|
is_script_resource = 1;
|
|
is_script_resource = 1;
|
|
is_put_or_delete_request = is_put_or_delete_method(conn);
|
|
is_put_or_delete_request = is_put_or_delete_method(conn);
|
|
} else {
|
|
} else {
|
|
/* 5.2.2. No callback is responsible for this request. The URI addresses a file
|
|
/* 5.2.2. No callback is responsible for this request. The URI addresses a file
|
|
based resource (static content or Lua/cgi scripts in the file system). */
|
|
based resource (static content or Lua/cgi scripts in the file system). */
|
|
|
|
+ is_callback_resource = 0;
|
|
interpret_uri(conn, path, sizeof(path), &file, &is_script_resource, &is_websocket_request, &is_put_or_delete_request);
|
|
interpret_uri(conn, path, sizeof(path), &file, &is_script_resource, &is_websocket_request, &is_put_or_delete_request);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -6552,34 +6631,44 @@ static void handle_request(struct mg_connection *conn)
|
|
/* request is authorized or does not need authorization */
|
|
/* request is authorized or does not need authorization */
|
|
|
|
|
|
/* 7. check if there are request handlers for this uri */
|
|
/* 7. check if there are request handlers for this uri */
|
|
- if (callback_handler != NULL) {
|
|
|
|
- if (callback_handler(conn, callback_data)) {
|
|
|
|
- /* Do nothing, callback has served the request */
|
|
|
|
- discard_unread_request_data(conn);
|
|
|
|
- return;
|
|
|
|
|
|
+ if (is_callback_resource) {
|
|
|
|
+ if (!is_websocket_request) {
|
|
|
|
+ if (callback_handler(conn, callback_data)) {
|
|
|
|
+ /* Do nothing, callback has served the request */
|
|
|
|
+ discard_unread_request_data(conn);
|
|
|
|
+ } else {
|
|
|
|
+ /* TODO: what if the handler did NOT handle the request */
|
|
|
|
+ /* The last version did handle this as a file request, but
|
|
|
|
+ since a file request is not always a script resource,
|
|
|
|
+ the authorization check might be different */
|
|
|
|
+ interpret_uri(conn, path, sizeof(path), &file, &is_script_resource, &is_websocket_request, &is_put_or_delete_request);
|
|
|
|
+ callback_handler = NULL;
|
|
|
|
+
|
|
|
|
+ /* TODO: for the moment, a goto is simpler than some curious loop. */
|
|
|
|
+ /* The situation "callback does not handle the request" needs to be reconsidered anyway. */
|
|
|
|
+ goto auth_check;
|
|
|
|
+ }
|
|
} else {
|
|
} else {
|
|
- /* TODO: what if the handler did NOT handle the request */
|
|
|
|
- /* The last version did handle this as a file request, but
|
|
|
|
- since a file request is not always a script resource,
|
|
|
|
- the authorization check might be different */
|
|
|
|
- interpret_uri(conn, path, sizeof(path), &file, &is_script_resource, &is_websocket_request, &is_put_or_delete_request);
|
|
|
|
- callback_handler = NULL;
|
|
|
|
-
|
|
|
|
- /* TODO: for the moment, a goto is simpler than some curious loop. */
|
|
|
|
- /* The situation "callback does not handle the request" needs to be reconsidered anyway. */
|
|
|
|
- goto auth_check;
|
|
|
|
|
|
+#if defined(USE_WEBSOCKET)
|
|
|
|
+ handle_websocket_request(conn, path, is_script_resource, ws_connect_handler, ws_ready_handler, ws_data_handler, ws_close_handler, callback_data);
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
|
|
+ return;
|
|
}
|
|
}
|
|
|
|
|
|
/* 8. handle websocket requests */
|
|
/* 8. handle websocket requests */
|
|
#if defined(USE_WEBSOCKET)
|
|
#if defined(USE_WEBSOCKET)
|
|
if (is_websocket_request) {
|
|
if (is_websocket_request) {
|
|
- handle_websocket_request(conn, path, is_script_resource);
|
|
|
|
|
|
+ handle_websocket_request(conn, path, is_script_resource,
|
|
|
|
+ deprecated_websocket_connect_wrapper,
|
|
|
|
+ deprecated_websocket_ready_wrapper,
|
|
|
|
+ deprecated_websocket_data_wrapper,
|
|
|
|
+ NULL,
|
|
|
|
+ &conn->ctx->callbacks
|
|
|
|
+ );
|
|
return;
|
|
return;
|
|
} else
|
|
} else
|
|
#endif
|
|
#endif
|
|
- {
|
|
|
|
- }
|
|
|
|
|
|
|
|
#if defined(NO_FILES)
|
|
#if defined(NO_FILES)
|
|
/* 9a. In case the server uses only callbacks, this uri is unknown.
|
|
/* 9a. In case the server uses only callbacks, this uri is unknown.
|
|
@@ -7532,6 +7621,13 @@ struct mg_connection *mg_download(const char *host, int port, int use_ssl,
|
|
return conn;
|
|
return conn;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+struct websocket_client_thread_data {
|
|
|
|
+ struct mg_connection* conn;
|
|
|
|
+ mg_websocket_data_handler data_handler;
|
|
|
|
+ mg_websocket_close_handler close_handler;
|
|
|
|
+ void *callback_data;
|
|
|
|
+};
|
|
|
|
+
|
|
#if defined(USE_WEBSOCKET)
|
|
#if defined(USE_WEBSOCKET)
|
|
#ifdef _WIN32
|
|
#ifdef _WIN32
|
|
static unsigned __stdcall websocket_client_thread(void *data)
|
|
static unsigned __stdcall websocket_client_thread(void *data)
|
|
@@ -7539,15 +7635,17 @@ static unsigned __stdcall websocket_client_thread(void *data)
|
|
static void* websocket_client_thread(void *data)
|
|
static void* websocket_client_thread(void *data)
|
|
#endif
|
|
#endif
|
|
{
|
|
{
|
|
- struct mg_connection* conn = (struct mg_connection*)data;
|
|
|
|
- read_websocket(conn);
|
|
|
|
|
|
+ struct websocket_client_thread_data* cdata = (struct websocket_client_thread_data*)data;
|
|
|
|
+ read_websocket(cdata->conn, cdata->data_handler, cdata->callback_data);
|
|
|
|
|
|
DEBUG_TRACE("%s", "Websocket client thread exited\n");
|
|
DEBUG_TRACE("%s", "Websocket client thread exited\n");
|
|
|
|
|
|
- if (conn->ctx->callbacks.connection_close != NULL) {
|
|
|
|
- conn->ctx->callbacks.connection_close(conn);
|
|
|
|
|
|
+ if (cdata->close_handler != NULL) {
|
|
|
|
+ cdata->close_handler(cdata->conn, cdata->callback_data);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ mg_free((void*)cdata);
|
|
|
|
+
|
|
#ifdef _WIN32
|
|
#ifdef _WIN32
|
|
return 0;
|
|
return 0;
|
|
#else
|
|
#else
|
|
@@ -7559,13 +7657,14 @@ static void* websocket_client_thread(void *data)
|
|
struct mg_connection *mg_connect_websocket_client(const char *host, int port, int use_ssl,
|
|
struct mg_connection *mg_connect_websocket_client(const char *host, int port, int use_ssl,
|
|
char *error_buffer, size_t error_buffer_size,
|
|
char *error_buffer, size_t error_buffer_size,
|
|
const char *path, const char *origin,
|
|
const char *path, const char *origin,
|
|
- websocket_data_func data_func, websocket_close_func close_func,
|
|
|
|
|
|
+ mg_websocket_data_handler data_func, mg_websocket_close_handler close_func,
|
|
void * user_data)
|
|
void * user_data)
|
|
{
|
|
{
|
|
struct mg_connection* conn = NULL;
|
|
struct mg_connection* conn = NULL;
|
|
|
|
|
|
#if defined(USE_WEBSOCKET)
|
|
#if defined(USE_WEBSOCKET)
|
|
struct mg_context * newctx = NULL;
|
|
struct mg_context * newctx = NULL;
|
|
|
|
+ struct websocket_client_thread_data *thread_data;
|
|
static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
|
|
static const char *magic = "x3JJHMbDL1EzLkh9GBhXDw==";
|
|
static const char *handshake_req;
|
|
static const char *handshake_req;
|
|
|
|
|
|
@@ -7597,7 +7696,7 @@ struct mg_connection *mg_connect_websocket_client(const char *host, int port, in
|
|
handshake_req, path, host, magic, origin);
|
|
handshake_req, path, host, magic, origin);
|
|
|
|
|
|
/* Connection object will be null if something goes wrong */
|
|
/* Connection object will be null if something goes wrong */
|
|
- if(conn == NULL || (strcmp(conn->request_info.uri, "101") != 0))
|
|
|
|
|
|
+ if (conn == NULL || (strcmp(conn->request_info.uri, "101") != 0))
|
|
{
|
|
{
|
|
DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
|
|
DEBUG_TRACE("Websocket client connect error: %s\r\n", error_buffer);
|
|
if(conn != NULL) { mg_free(conn); conn = NULL; }
|
|
if(conn != NULL) { mg_free(conn); conn = NULL; }
|
|
@@ -7608,19 +7707,23 @@ struct mg_connection *mg_connect_websocket_client(const char *host, int port, in
|
|
function, we need to create a copy and modify it. */
|
|
function, we need to create a copy and modify it. */
|
|
newctx = (struct mg_context *) mg_malloc(sizeof(struct mg_context));
|
|
newctx = (struct mg_context *) mg_malloc(sizeof(struct mg_context));
|
|
memcpy(newctx, conn->ctx, sizeof(struct mg_context));
|
|
memcpy(newctx, conn->ctx, sizeof(struct mg_context));
|
|
- newctx->callbacks.websocket_data = data_func; /* read_websocket will automatically call it */
|
|
|
|
- newctx->callbacks.connection_close = close_func;
|
|
|
|
newctx->user_data = user_data;
|
|
newctx->user_data = user_data;
|
|
newctx->context_type = 2; /* client context type */
|
|
newctx->context_type = 2; /* client context type */
|
|
newctx->workerthreadcount = 1; /* one worker thread will be created */
|
|
newctx->workerthreadcount = 1; /* one worker thread will be created */
|
|
newctx->workerthreadids = (pthread_t*) mg_calloc(newctx->workerthreadcount, sizeof(pthread_t));
|
|
newctx->workerthreadids = (pthread_t*) mg_calloc(newctx->workerthreadcount, sizeof(pthread_t));
|
|
conn->ctx = newctx;
|
|
conn->ctx = newctx;
|
|
|
|
+ thread_data = (struct websocket_client_thread_data*) mg_calloc(sizeof(struct websocket_client_thread_data), 1);
|
|
|
|
+ thread_data->conn = conn;
|
|
|
|
+ thread_data->data_handler = data_func;
|
|
|
|
+ thread_data->close_handler = close_func;
|
|
|
|
+ thread_data->callback_data = NULL;
|
|
|
|
|
|
/* Start a thread to read the websocket client connection
|
|
/* Start a thread to read the websocket client connection
|
|
This thread will automatically stop when mg_disconnect is
|
|
This thread will automatically stop when mg_disconnect is
|
|
called on the client connection */
|
|
called on the client connection */
|
|
- if (mg_start_thread_with_id(websocket_client_thread, (void*)conn, newctx->workerthreadids) != 0)
|
|
|
|
|
|
+ if (mg_start_thread_with_id(websocket_client_thread, (void*)thread_data, newctx->workerthreadids) != 0)
|
|
{
|
|
{
|
|
|
|
+ mg_free((void*)thread_data);
|
|
mg_free((void*)newctx->workerthreadids);
|
|
mg_free((void*)newctx->workerthreadids);
|
|
mg_free((void*)newctx);
|
|
mg_free((void*)newctx);
|
|
mg_free((void*)conn);
|
|
mg_free((void*)conn);
|