diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index eebbe36b..7d568a15 100755 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -142,11 +142,34 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs) lws_remove_from_timeout_list(wsi); } +static void +lws_remove_child_from_any_parent(struct lws *wsi) +{ + struct lws **pwsi; + + if (wsi->parent) { + /* detach ourselves from parent's child list */ + pwsi = &wsi->parent->child_list; + while (*pwsi) { + if (*pwsi == wsi) { + //lwsl_notice("%s: detach %p from parent %p\n", + // __func__, wsi, wsi->parent); + *pwsi = wsi->sibling_list; + break; + } + pwsi = &(*pwsi)->sibling_list; + } + if (*pwsi) + lwsl_err("%s: failed to detach from parent\n", + __func__); + } +} + void lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason) { struct lws_context_per_thread *pt; - struct lws **pwsi, *wsi1, *wsi2; + struct lws *wsi1, *wsi2; struct lws_context *context; struct lws_tokens eff_buf; int n, m, ret; @@ -154,15 +177,6 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason) if (!wsi) return; - if (wsi->mode == LWSCM_RAW_FILEDESC) { - remove_wsi_socket_from_fds(wsi); - wsi->protocol->callback(wsi, - LWS_CALLBACK_RAW_CLOSE_FILE, wsi->user_space, NULL, 0); - lws_free_wsi(wsi); - - return; - } - lws_access_log(wsi); #if defined(LWS_WITH_ESP8266) if (wsi->premature_rx) @@ -200,6 +214,17 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason) wsi->child_list = NULL; } + if (wsi->mode == LWSCM_RAW_FILEDESC) { + lws_remove_child_from_any_parent(wsi); + remove_wsi_socket_from_fds(wsi); + wsi->protocol->callback(wsi, + LWS_CALLBACK_RAW_CLOSE_FILE, + wsi->user_space, NULL, 0); + lws_free_wsi(wsi); + + return; + } + #ifdef LWS_WITH_CGI if (wsi->mode == LWSCM_CGI) { /* we are not a network connection, but a handler for CGI io */ @@ -400,22 +425,8 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason) just_kill_connection: - if (wsi->parent) { - /* detach ourselves from parent's child list */ - pwsi = &wsi->parent->child_list; - while (*pwsi) { - if (*pwsi == wsi) { - //lwsl_notice("%s: detach %p from parent %p\n", - // __func__, wsi, wsi->parent); - *pwsi = wsi->sibling_list; - break; - } - pwsi = &(*pwsi)->sibling_list; - } - if (*pwsi) - lwsl_err("%s: failed to detach from parent\n", - __func__); - } + lws_remove_child_from_any_parent(wsi); + #if 0 /* manage the vhost same protocol list entry */ diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index cf15ad11..c5244ad8 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -3725,9 +3725,10 @@ LWS_VISIBLE LWS_EXTERN struct lws * lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd); typedef enum { - LWS_ADOPT_HTTP = 1, /* absent implies RAW */ - LWS_ADOPT_SOCKET = 2, /* absent implies file descriptor */ - LWS_ADOPT_ALLOW_SSL = 4 /* if set requires LWS_ADOPT_SOCKET */ + LWS_ADOPT_RAW_FILE_DESC = 0, /* convenience constant */ + LWS_ADOPT_HTTP = 1, /* flag: absent implies RAW */ + LWS_ADOPT_SOCKET = 2, /* flag: absent implies file descr */ + LWS_ADOPT_ALLOW_SSL = 4 /* flag: if set requires LWS_ADOPT_SOCKET */ } lws_adoption_type; typedef union { @@ -3743,17 +3744,21 @@ typedef union { * \param type: OR-ed combinations of lws_adoption_type flags * \param fd: union with either .sockfd or .filefd set * \param vh_prot_name: NULL or vh protocol name to bind raw connection to +* \param parent: NULL or struct lws to attach new_wsi to as a child * * Either returns new wsi bound to accept_fd, or closes accept_fd and * returns NULL, having cleaned up any new wsi pieces. * * If LWS_ADOPT_SOCKET is set, LWS adopts the socket in http serving mode, it's * ready to accept an upgrade to ws or just serve http. +* +* parent may be NULL, if given it should be an existing wsi that will become the +* parent of the new wsi created by this call. */ LWS_VISIBLE struct lws * lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, - lws_sock_file_fd_type fd, const char *vh_prot_name); - + lws_sock_file_fd_type fd, const char *vh_prot_name, + struct lws *parent); /** * lws_adopt_socket_readbuf() - adopt foreign socket and first rx as if listen socket accepted it diff --git a/lib/server.c b/lib/server.c index 61eebda3..73be40a2 100644 --- a/lib/server.c +++ b/lib/server.c @@ -1690,7 +1690,8 @@ lws_http_transaction_completed(struct lws *wsi) LWS_VISIBLE struct lws * lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, - lws_sock_file_fd_type fd, const char *vh_prot_name) + lws_sock_file_fd_type fd, const char *vh_prot_name, + struct lws *parent) { struct lws_context *context = vh->context; struct lws *new_wsi = lws_create_new_server_wsi(vh); @@ -1702,27 +1703,32 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, return NULL; } - new_wsi->desc = fd; - new_wsi->protocol = &context->vhost_list-> - protocols[vh->default_protocol_index]; + if (parent) { + new_wsi->parent = parent; + new_wsi->sibling_list = parent->child_list; + parent->child_list = new_wsi; + } - if (!(type & LWS_ADOPT_SOCKET)) { + new_wsi->desc = fd; + + if (vh_prot_name) { new_wsi->protocol = lws_vhost_name_to_protocol(new_wsi->vhost, - vh_prot_name); + vh_prot_name); if (!new_wsi->protocol) { lwsl_err("Protocol %s not enabled on vhost %s\n", vh_prot_name, new_wsi->vhost->name); - lws_free(new_wsi); - - return NULL; + goto bail; } - } - if (type & LWS_ADOPT_SOCKET) { + if (lws_ensure_user_space(new_wsi)) + goto bail; + } else + new_wsi->protocol = &context->vhost_list-> + protocols[vh->default_protocol_index]; + if (type & LWS_ADOPT_SOCKET) { /* socket desc */ lwsl_debug("%s: new wsi %p, sockfd %d\n", __func__, new_wsi, (int)(size_t)fd.sockfd); - /* the transport is accepted... give him time to negotiate */ lws_set_timeout(new_wsi, PENDING_TIMEOUT_ESTABLISH_WITH_SERVER, context->timeout_secs); @@ -1732,7 +1738,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, esp8266_tcp_stream_accept(accept_fd, new_wsi); #endif #endif - } else //* file desc */ + } else /* file desc */ lwsl_debug("%s: new wsi %p, filefd %d\n", __func__, new_wsi, (int)(size_t)fd.filefd); @@ -1756,8 +1762,7 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type, lws_set_timeout(new_wsi, NO_PENDING_TIMEOUT, 0); compatible_close(new_wsi->desc.sockfd); } - lws_free(new_wsi); - return NULL; + goto bail; } if (!LWS_SSL_ENABLED(new_wsi->vhost) || !(type & LWS_ADOPT_ALLOW_SSL) || @@ -1804,6 +1809,15 @@ fail: lws_close_free_wsi(new_wsi, LWS_CLOSE_STATUS_NOSTATUS); return NULL; + +bail: + if (parent) + parent->child_list = new_wsi->sibling_list; + if (new_wsi->user_space) + lws_free(new_wsi->user_space); + lws_free(new_wsi); + + return NULL; } LWS_VISIBLE struct lws * @@ -1813,7 +1827,7 @@ lws_adopt_socket_vhost(struct lws_vhost *vh, lws_sockfd_type accept_fd) fd.sockfd = accept_fd; return lws_adopt_descriptor_vhost(vh, LWS_ADOPT_SOCKET | - LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL); + LWS_ADOPT_HTTP | LWS_ADOPT_ALLOW_SSL, fd, NULL, NULL); } LWS_VISIBLE struct lws * diff --git a/plugins/protocol_lws_raw_test.c b/plugins/protocol_lws_raw_test.c index 16557509..047f136e 100644 --- a/plugins/protocol_lws_raw_test.c +++ b/plugins/protocol_lws_raw_test.c @@ -101,7 +101,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, } lwsl_notice("FIFO %s created\n", vhd->fifo_path); u.filefd = vhd->fifo; - if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test")) { + if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test", NULL)) { lwsl_err("Failed to adopt fifo descriptor\n"); close(vhd->fifo); unlink(vhd->fifo_path); @@ -167,7 +167,7 @@ callback_raw_test(struct lws *wsi, enum lws_callback_reasons reason, } lwsl_notice("FIFO %s reopened\n", vhd->fifo_path); u.filefd = vhd->fifo; - if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test")) { + if (!lws_adopt_descriptor_vhost(vhd->vhost, 0, u, "protocol-lws-raw-test", NULL)) { lwsl_err("Failed to adopt fifo descriptor\n"); close(vhd->fifo); return 1;