add explicit parent child wsi relationships
authorAndy Green <andy.green@linaro.org>
Wed, 2 Mar 2016 01:17:22 +0000 (09:17 +0800)
committerAndy Green <andy.green@linaro.org>
Wed, 2 Mar 2016 10:57:41 +0000 (18:57 +0800)
wsi can have a full tree relationship with each other using
linked lists.  closing the parent ensures the children are
closed first.

Convert cgi to use this instead of his cgi-specific sub-wsi
management.

Signed-off-by: Andy Green <andy.green@linaro.org>
changelog
lib/client-handshake.c
lib/libwebsockets.c
lib/libwebsockets.h
lib/private-libwebsockets.h
lib/service.c
test-server/lws-cgi-test.sh

index 9be1268..8ce86c9 100644 (file)
--- a/changelog
+++ b/changelog
@@ -149,6 +149,13 @@ There are 4 new related callbacks
        LWS_CALLBACK_RECEIVE_CLIENT_HTTP                        = 46,
        LWS_CALLBACK_COMPLETED_CLIENT_HTTP                      = 47,
 
+6) struct lws_client_connect_info has a new member
+
+ const char *parent_wsi
+if non-NULL, the client wsi is set to be a child of parent_wsi.  This ensures
+if parent_wsi closes, then the client child is closed just before.
+
 
 v1.7.0
 ======
index d1baa0e..ba7a44a 100644 (file)
@@ -407,7 +407,12 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
        if (wsi && !wsi->user_space && i->userdata) {
                wsi->user_space_externally_allocated = 1;
                wsi->user_space = i->userdata;
-       }
+       } else
+               /* if we stay in http, we can assign the user space now,
+                * otherwise do it after the protocol negotiated
+                */
+               if (i->method)
+                       lws_ensure_user_space(wsi);
 
 #ifdef LWS_OPENSSL_SUPPORT
        wsi->use_ssl = i->ssl_connection;
@@ -417,11 +422,6 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
                goto bail;
        }
 #endif
-       wsi->protocol = &i->context->protocols[0];
-       if (wsi && !wsi->user_space && i->userdata) {
-               wsi->user_space_externally_allocated = 1;
-               wsi->user_space = i->userdata;
-       }
 
        /* 2) stash the things from connect_info that we can't process without
         * an ah.  Because if no ah, we will go on the ah waiting list and
@@ -469,6 +469,14 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
        if (lws_header_table_attach(wsi, 0))
                lwsl_debug("%s: went on ah wait list\n", __func__);
 
+       if (i->parent_wsi) {
+               lwsl_info("%s: created child %p of parent %p\n", __func__,
+                               wsi, i->parent_wsi);
+               wsi->parent = i->parent_wsi;
+               wsi->sibling_list = i->parent_wsi->child_list;
+               i->parent_wsi->child_list = wsi;
+       }
+
        return wsi;
 
 bail:
index 056921e..72cc2fd 100644 (file)
@@ -142,10 +142,11 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
 void
 lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 {
-       struct lws_context *context;
        struct lws_context_per_thread *pt;
-       int n, m, ret;
+       struct lws **pwsi, *wsi1, *wsi2;
+       struct lws_context *context;
        struct lws_tokens eff_buf;
+       int n, m, ret;
 
        if (!wsi)
                return;
@@ -153,24 +154,31 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
        context = wsi->context;
        pt = &context->pt[(int)wsi->tsi];
 
+       /* if we have children, close them first */
+       if (wsi->child_list) {
+               wsi2 = wsi->child_list;
+               while (wsi2) {
+                       lwsl_notice("%s: closing %p: close child %p\n",
+                                       __func__, wsi, wsi2);
+                       wsi1 = wsi2->sibling_list;
+                       lws_close_free_wsi(wsi2, reason);
+                       wsi2 = wsi1;
+               }
+       }
+
 #ifdef LWS_WITH_CGI
        if (wsi->mode == LWSCM_CGI) {
                /* we are not a network connection, but a handler for CGI io */
-               assert(wsi->master);
-               assert(wsi->master->cgi);
-               assert(wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] == wsi);
+               if (wsi->parent && wsi->parent->cgi)
                /* end the binding between us and master */
-               wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
-               wsi->master = NULL;
+               wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
                wsi->socket_is_permanently_unusable = 1;
 
                goto just_kill_connection;
        }
 
        if (wsi->cgi) {
-               /* we have a cgi going, we must kill it and close the
-                * related stdin/out/err wsis first
-                */
+               /* we have a cgi going, we must kill it */
                wsi->cgi->being_closed = 1;
                lws_cgi_kill(wsi);
        }
@@ -327,6 +335,22 @@ 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__);
+       }
 
 #if LWS_POSIX
        /*
@@ -1182,6 +1206,18 @@ lws_wsi_user(struct lws *wsi)
        return wsi->user_space;
 }
 
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_get_parent(const struct lws *wsi)
+{
+       return wsi->parent;
+}
+
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_get_child(const struct lws *wsi)
+{
+       return wsi->child_list;
+}
+
 LWS_VISIBLE LWS_EXTERN void
 lws_close_reason(struct lws *wsi, enum lws_close_status status,
                 unsigned char *buf, size_t len)
@@ -1480,9 +1516,11 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
        }
 
        for (n = 0; n < 3; n++) {
-               cgi->stdwsi[n]->master = wsi;
                if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
                        goto bail3;
+               cgi->stdwsi[n]->parent = wsi;
+               cgi->stdwsi[n]->sibling_list = wsi->child_list;
+               wsi->child_list = cgi->stdwsi[n];
        }
 
        lws_change_pollfd(cgi->stdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT);
@@ -1496,6 +1534,8 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
 
        lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
 
+
+
        /* add us to the pt list of active cgis */
        cgi->cgi_list = pt->cgi_list;
        pt->cgi_list = cgi;
@@ -1633,8 +1673,6 @@ lws_cgi_kill(struct lws *wsi)
                if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) {
                        close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
                        wsi->cgi->pipe_fds[n][!!(n == 0)] = -1;
-
-                       lws_close_free_wsi(wsi->cgi->stdwsi[n], 0);
                }
        }
 
index f38fc56..3126e84 100644 (file)
@@ -1410,6 +1410,9 @@ struct lws_context_creation_info {
  * @client_exts: array of extensions that may be used on connection
  * @method:    if non-NULL, do this http method instead of ws[s] upgrade.
  *             use "GET" to be a simple http client connection
+ * @parent_wsi:        if another wsi is responsible for this connection, give it here.
+ *             this is used to make sure if the parent closes so do any
+ *             child connections first.
  */
 
 struct lws_client_connect_info {
@@ -1425,6 +1428,7 @@ struct lws_client_connect_info {
        void *userdata;
        const struct lws_extension *client_exts;
        const char *method;
+       struct lws *parent_wsi;
 
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility
@@ -1847,6 +1851,12 @@ lws_get_context(const struct lws *wsi);
 LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
 lws_get_count_threads(struct lws_context *context);
 
+LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
+lws_get_parent(const struct lws *wsi);
+
+LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
+lws_get_child(const struct lws *wsi);
+
 #ifdef LWS_WITH_CGI
 enum lws_enum_stdinouterr {
        LWS_STDIN = 0,
index 4a9a92b..c93f688 100644 (file)
@@ -1075,9 +1075,11 @@ struct lws {
        /* pointers */
 
        struct lws_context *context;
+       struct lws *parent; /* points to parent, if any */
+       struct lws *child_list; /* points to first child */
+       struct lws *sibling_list; /* subsequent children at same level */
 #ifdef LWS_WITH_CGI
        struct lws_cgi *cgi; /* wsi being cgi master have one of these */
-       struct lws *master; /* for stdin/out/err wsi to point to cgi master */
 #endif
        const struct lws_protocols *protocol;
        struct lws *timeout_list;
index d27e4e0..bec262d 100644 (file)
@@ -871,12 +871,12 @@ handle_pending:
                                }
 
                        args.ch = wsi->cgi_channel;
-                       args.stdwsi = &wsi->master->cgi->stdwsi[0];
+                       args.stdwsi = &wsi->parent->cgi->stdwsi[0];
 
                        if (user_callback_handle_rxflow(
-                                       wsi->master->protocol->callback,
-                                       wsi->master, LWS_CALLBACK_CGI,
-                                       wsi->master->user_space,
+                                       wsi->parent->protocol->callback,
+                                       wsi->parent, LWS_CALLBACK_CGI,
+                                       wsi->parent->user_space,
                                        (void *)&args, 0))
                                return 1;
 
index 90c804e..2f5df11 100755 (executable)
@@ -8,6 +8,8 @@ echo "REQUEST_METHOD=$REQUEST_METHOD"
 if [ "$REQUEST_METHOD" = "POST" ] ; then
        read line
        echo "read=\"$line\""
+else
+       cat /proc/meminfo
 fi
 
 echo "done"