adopt: allow binding to parent at same time
authorPer Bothner <per@bothner.com>
Thu, 2 Mar 2017 23:36:08 +0000 (07:36 +0800)
committerAndy Green <andy@warmcat.com>
Thu, 2 Mar 2017 23:36:08 +0000 (07:36 +0800)
 - if protocol set, allocate own user_space

   If the child wsi wants the parent wsi user_space, it can use

       lws_wsi_user(lws_get_parent(child_wsi))

 - raw file close processing handles parent-child relationship

lib/libwebsockets.c
lib/libwebsockets.h
lib/server.c
plugins/protocol_lws_raw_test.c

index eebbe36..7d568a1 100755 (executable)
@@ -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 */
 
index cf15ad1..c5244ad 100644 (file)
@@ -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
index 61eebda..73be40a 100644 (file)
@@ -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;
        }
 
+       if (parent) {
+               new_wsi->parent = parent;
+               new_wsi->sibling_list = parent->child_list;
+               parent->child_list = new_wsi;
+       }
+
        new_wsi->desc = fd;
-       new_wsi->protocol = &context->vhost_list->
-                       protocols[vh->default_protocol_index];
 
-       if (!(type & LWS_ADOPT_SOCKET)) {
+       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 *
index 1655750..047f136 100644 (file)
@@ -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;