extensions change child count to highest child subchannel
authorAndy Green <andy@warmcat.com>
Wed, 25 May 2011 20:07:20 +0000 (21:07 +0100)
committerAndy Green <andy@warmcat.com>
Wed, 25 May 2011 20:07:20 +0000 (21:07 +0100)
This also changes the wsi_children array to be indexed by subchannel - 2,
non-existent channels are NULL in there and highest_child_subchannel
is a highwater mark for the highest subchannel ever used.  That way we
can immediately get the wsi for a subchannel at the cost of some extra
sparse skipping during management.

This also takes care of scanning for empty slots on allocation and
NULLing on close of subchannel instead of deletion.

Signed-off-by: Andy Green <andy@warmcat.com>
lib/extension-x-google-mux.c
lib/extension-x-google-mux.h

index ae5975f..e8ceec2 100644 (file)
@@ -431,8 +431,8 @@ bail2:
 
 
                conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET] = wsi_child;
-               if (conn->count_children <= conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET)
-                       conn->count_children = conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET + 1;
+               if (conn->highest_child_subchannel <= conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET)
+                       conn->highest_child_subchannel = conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET + 1;
 
 
                /* notify user code that we're ready to roll */
@@ -481,7 +481,7 @@ bail2:
                 * to tell us when it ate a full frame, so we watch its state
                 * afterwards
                 */
-               if (conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET > conn->count_children) {
+               if (conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET >= conn->highest_child_subchannel) {
                        fprintf(stderr, "Illegal subchannel\n");
                        return -1;
                }
@@ -547,6 +547,7 @@ int lws_extension_callback_x_google_mux(
        struct lws_ext_x_google_mux_context *mux_ctx =
                                                  ext->per_context_private_data;
        struct libwebsocket *wsi_parent;
+       struct libwebsocket *wsi_child;
        struct libwebsocket *wsi_temp;
        unsigned char *pin = (unsigned char *)in;
        unsigned char *basepin;
@@ -658,10 +659,12 @@ int lws_extension_callback_x_google_mux(
                                 continue;
                        }
 
-                       if (parent_conn->count_children >=
+                       if (parent_conn->highest_child_subchannel >=
                                        sizeof(parent_conn->wsi_children) /
-                                          sizeof(parent_conn->wsi_children[0]))
+                                          sizeof(parent_conn->wsi_children[0])) {
+                               fprintf(stderr, "Can't add any more children\n");
                                continue;
+                       }
                        /*
                         * this established connection will do, bind them
                         * from now on child will only operate through parent
@@ -721,14 +724,9 @@ int lws_extension_callback_x_google_mux(
                                fprintf(stderr, "failed to get parent conn\n");
                                break;
                        }
-                       for (n = 0; n < parent_conn->count_children; n++)
-                               if (parent_conn->wsi_children[n] == wsi) {
-                                       parent_conn->count_children--;
-                                       while (n < parent_conn->count_children) {
-                                               parent_conn->wsi_children[n] = parent_conn->wsi_children[n + 1];
-                                               n++;
-                                       }
-                               }
+                       for (n = 0; n < parent_conn->highest_child_subchannel; n++)
+                               if (parent_conn->wsi_children[n] == wsi)
+                                       parent_conn->wsi_children[n] = NULL;
                }
 
                break;
@@ -777,12 +775,12 @@ handle_additions:
                         * them all go it alone
                         */
 
-                       wsi_parent = wsi->candidate_children_list;
-                       while (wsi_parent) {
-                               wsi_temp = wsi_parent->candidate_children_list;
+                       wsi_child = wsi->candidate_children_list;
+                       while (wsi_child) {
+                               wsi_temp = wsi_child->candidate_children_list;
                                /* let them each connect privately then */
-                               __libwebsocket_client_connect_2(context, wsi_parent);
-                               wsi_parent = wsi_temp;
+                               __libwebsocket_client_connect_2(context, wsi_child);
+                               wsi_child = wsi_temp;
                        }
 
                        return 1;
@@ -794,23 +792,43 @@ handle_additions:
                 * as mux subchannel real children
                 */
                
-               wsi_parent = wsi->candidate_children_list;
-               while (wsi_parent) {
+               wsi_child = wsi->candidate_children_list;
+               n = 0;
+               while (wsi_child) {
+
+                       wsi_temp = wsi_child->candidate_children_list;
+
+                       /* find an empty subchannel */
+
+                       while ((n < (sizeof(conn->wsi_children) / sizeof(conn->wsi_children[0]))) &&
+                                       conn->wsi_children[n] != NULL)
+                               n++;
+
+                       if (n >= (sizeof(conn->wsi_children) / sizeof(conn->wsi_children[0]))) {
+                               /* no room at the inn */
+
+                               /* let them each connect privately then */
+                               __libwebsocket_client_connect_2(context, wsi_child);
+                               wsi_child = wsi_temp;
+                               continue;
+                       }
 
                        muxdebug("  using mux addchannel action for candidate child\n");
                        
-                       wsi_temp = wsi_parent->candidate_children_list;
-                       /* let them each connect privately then */
+                       /* pile the children on the parent */
                        lws_ext_x_google_mux__send_addchannel(context, wsi,
-                                       conn, wsi_parent,
-                                       conn->count_children + MUX_REAL_CHILD_INDEX_OFFSET, wsi->c_path);
+                                       conn, wsi_child,
+                                       n + MUX_REAL_CHILD_INDEX_OFFSET, wsi->c_path);
 
                        conn->sticky_mux_used = 1;
 
-                       conn->wsi_children[conn->count_children++] = wsi_parent;
+                       conn->wsi_children[n] = wsi_child;
+                       if ((n + 1) > conn->highest_child_subchannel)
+                               conn->highest_child_subchannel = n + 1;
+
                        muxdebug("Setting CHILD LIST entry %d to %p\n",
-                                 conn->count_children - 1, (void *)wsi_parent);
-                       wsi_parent = wsi_temp;
+                                 n + MUX_REAL_CHILD_INDEX_OFFSET, (void *)wsi_parent);
+                       wsi_child = wsi_temp;
                }
                wsi->candidate_children_list = NULL;
                return 1;
@@ -910,8 +928,9 @@ handle_additions:
                 * if we have children, service their timeouts using the same
                 * handler as toplevel guys to allow recursion
                 */
-               for (n = 0; n < conn->count_children; n++)
-                       libwebsocket_service_timeout_check(context,
+               for (n = 0; n < conn->highest_child_subchannel; n++)
+                       if (conn->wsi_children[n])
+                               libwebsocket_service_timeout_check(context,
                                                    conn->wsi_children[n], len);
                break;
 
@@ -983,7 +1002,10 @@ handle_additions:
                        return 0;
                }
 
-               for (n = 0; n < conn->count_children; n++) {
+               for (n = 0; n < conn->highest_child_subchannel; n++) {
+
+                       if (!conn->wsi_children[n])
+                               continue;
 
                        child_conn = NULL;
                        for (m = 0; m < conn->wsi_children[n]->count_active_extensions; m++)
index 425a5ca..6626bea 100644 (file)
@@ -79,7 +79,7 @@ struct lws_ext_x_google_mux_conn {
        struct libwebsocket *wsi_parent;
        int subchannel;
        struct libwebsocket *wsi_children[MAX_CLIENTS];
-       int count_children;
+       int highest_child_subchannel;
        char awaiting_POLLOUT;
        int count_children_needing_POLLOUT;
        int sticky_mux_used;