x google mux implement child close
authorAndy Green <andy@warmcat.com>
Tue, 24 May 2011 21:07:45 +0000 (22:07 +0100)
committerAndy Green <andy@warmcat.com>
Tue, 24 May 2011 21:07:45 +0000 (22:07 +0100)
This implements clean client and server close for mux child connections,
and deals with accounting for parent child lists.

The mux link can then survive constant connection bringup and teardown
found in the new test client.

Signed-off-by: Andy Green <andy@warmcat.com>
lib/client-handshake.c
lib/extension-x-google-mux.c
lib/handshake.c
lib/libwebsockets.c
lib/parsers.c
test-server/test-server-extpoll.c

index d41777c..235ee07 100644 (file)
@@ -40,6 +40,8 @@ struct libwebsocket * __libwebsocket_client_connect_2(
         * prepare the actual connection (to the proxy, if any)
         */
 
+       fprintf(stderr, "__libwebsocket_client_connect_2: address %s", wsi->c_address);
+
        server_hostent = gethostbyname(wsi->c_address);
        if (server_hostent == NULL) {
                fprintf(stderr, "Unable to get host name from %s\n",
index 1f56994..006f404 100644 (file)
@@ -342,11 +342,11 @@ bail2:
 
                wsi_child = conn->wsi_children[conn->block_subchannel];
 
-               muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS in\n");
+               muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS in %d\n", conn->length);
 
                libwebsocket_read(context, wsi_child, &c, 1);
 
-               if (--conn->length >= 0)
+               if (--conn->length > 0)
                        break;
 
                muxdebug("Server LWS_EXT_XGM_STATE__ADDCHANNEL_HEADERS done\n");
@@ -359,7 +359,10 @@ bail2:
                /* reply with ADDCHANNEL to ack it */
 
                wsi->xor_mask = xor_no_mask;
+               child_conn = lws_get_extension_user_matching_ext(wsi_child, this_ext);
+               child_conn->wsi_parent = wsi;
 
+               muxdebug("Setting child conn parent to %p\n", (void *)wsi);
 
 //             lws_ext_x_google_mux__send_addchannel(context, wsi, wsi_child,
 //                                                 conn->block_subchannel, "url-parsing-not-done-yet");
@@ -450,7 +453,12 @@ bail2:
                case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
                case LWS_CONNMODE_WS_CLIENT:
 //                     fprintf(stderr, "  client\n");
-                       libwebsocket_client_rx_sm(wsi_child, c);
+                       if (libwebsocket_client_rx_sm(wsi_child, c) < 0) {
+                               libwebsocket_close_and_free_session(
+                                       context,
+                                       wsi_child,
+                                       LWS_CLOSE_STATUS_GOINGAWAY);
+                       }
 
                        return 0;
 
@@ -458,9 +466,13 @@ bail2:
 
                default:
 //                     fprintf(stderr, "  server\n");
-                       if (libwebsocket_rx_sm(wsi_child, c) < 0)
+                       if (libwebsocket_rx_sm(wsi_child, c) < 0) {
                                fprintf(stderr, "probs\n");
-
+                               libwebsocket_close_and_free_session(
+                                       context,
+                                       wsi_child,
+                                       LWS_CLOSE_STATUS_GOINGAWAY);
+                       }
                        break;
                }
                break;
@@ -611,28 +623,17 @@ int lws_extension_callback_x_google_mux(
                         * connection
                         */
 
-                       conn->wsi_parent = wsi_parent;
-                       parent_conn->wsi_children[
-                                            parent_conn->count_children] = wsi;
+                       wsi->candidate_children_list = wsi_parent->candidate_children_list;
+                       wsi_parent->candidate_children_list = wsi;
+                       wsi->mode = LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD;
 
-                       /*
-                        * and now we have to ask the server to allow us to do
-                        * this
-                        */
+                       fprintf(stderr, "attaching to existing mux\n");
 
-                       if (lws_ext_x_google_mux__send_addchannel(context,
-                                  wsi_parent, wsi, parent_conn->count_children,
-                                           (const char *)in) < 0) {
-                               fprintf(stderr, "Addchannel failed\n");
-                               continue;
-                       }
+                       conn = parent_conn;
+                       wsi = wsi_parent;
 
-                       parent_conn->count_children++;
+                       goto handle_additions;
 
-                       fprintf(stderr, "!x-google-mux: muxing connection!  CHILD ADD %d to %p\n", parent_conn->count_children - 1, (void *)wsi);
-
-                       done = 1;
-                       n = mux_ctx->active_conns;
                }
 
                /*
@@ -663,6 +664,28 @@ int lws_extension_callback_x_google_mux(
 
        case LWS_EXT_CALLBACK_DESTROY:
                muxdebug("LWS_EXT_CALLBACK_DESTROY\n");
+
+               /*
+                * remove us from parent if noted in parent
+                */
+
+               if (conn->wsi_parent) {
+
+                       parent_conn = lws_get_extension_user_matching_ext(conn->wsi_parent, ext);
+                       if (parent_conn == 0) {
+                               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++;
+                                       }
+                               }
+               }
+
                break;
 
        case LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING:
@@ -694,6 +717,7 @@ int lws_extension_callback_x_google_mux(
        case LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED:
                muxdebug("LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED\n");
 
+handle_additions:
                /*
                 * did this putative parent get x-google-mux authorized in the
                 * end?
@@ -716,7 +740,7 @@ int lws_extension_callback_x_google_mux(
                                wsi_parent = wsi_temp;
                        }
 
-                       break;
+                       return 1;
                }
 
                /*
@@ -741,7 +765,7 @@ int lws_extension_callback_x_google_mux(
                        wsi_parent = wsi_temp;
                }
                wsi->candidate_children_list = NULL;
-               break;
+               return 1;
 
        /*
         * whenever we receive something on a muxed link
@@ -776,8 +800,10 @@ int lws_extension_callback_x_google_mux(
                 * he's not a child connection of a mux
                 */
 
-               if (!conn->wsi_parent)
+               if (!conn->wsi_parent) {
+//                     fprintf(stderr, "conn %p has no parent\n", (void *)conn);
                        return 0;
+               }
 
                /*
                 * get parent / transport mux context
@@ -794,8 +820,10 @@ int lws_extension_callback_x_google_mux(
                 * no more muxified than it already is
                 */
 
-               if (parent_conn->count_children == 0)
+               if (parent_conn->count_children == 0) {
+//                     fprintf(stderr, "parent in singular mode\n");
                        return 0;
+               }
 
                /*
                 * otherwise we need to take care of the sending action using
index 14adbba..d41414b 100644 (file)
@@ -721,7 +721,8 @@ libwebsocket_read(struct libwebsocket_context *context, struct libwebsocket *wsi
                switch (wsi->mode) {
                case LWS_CONNMODE_WS_CLIENT:
                        for (n = 0; n < len; n++)
-                               libwebsocket_client_rx_sm(wsi, *buf++);
+                               if (libwebsocket_client_rx_sm(wsi, *buf++) < 0)
+                                       goto bail;
 
                        return 0;
                default:
index f3bee80..7de11da 100644 (file)
@@ -222,6 +222,9 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
 
        if (old_state == WSI_STATE_ESTABLISHED &&
                                          reason != LWS_CLOSE_STATUS_NOSTATUS) {
+
+               fprintf(stderr, "sending close indication...\n");
+
                n = libwebsocket_write(wsi, &buf[LWS_SEND_BUFFER_PRE_PADDING],
                                                            0, LWS_WRITE_CLOSE);
                if (!n) {
@@ -246,6 +249,9 @@ libwebsocket_close_and_free_session(struct libwebsocket_context *context,
        }
 
 just_kill_connection:
+
+       fprintf(stderr, "libwebsocket_close_and_free_session: just_kill_connection\n");
+
        /*
         * we won't be servicing or receiving anything further from this guy
         * remove this fd from wsi mapping hashtable
@@ -278,9 +284,15 @@ just_kill_connection:
        /* tell the user it's all over for this guy */
 
        if (wsi->protocol && wsi->protocol->callback &&
-                                            old_state == WSI_STATE_ESTABLISHED)
+                               ((old_state == WSI_STATE_ESTABLISHED) ||
+                                (old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) ||
+                                (old_state == WSI_STATE_AWAITING_CLOSE_ACK))) {
+               fprintf(stderr, "calling back CLOSED\n");
                wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
                                                      wsi->user_space, NULL, 0);
+       } else {
+               fprintf(stderr, "not calling back closed due to old_state=%d\n", old_state);
+       }
 
        /* deallocate any active extension contexts */
 
@@ -334,9 +346,11 @@ just_kill_connection:
 #endif
                shutdown(wsi->sock, SHUT_RDWR);
 #ifdef WIN32
-               closesocket(wsi->sock);
+               if (wsi->sock)
+                       closesocket(wsi->sock);
 #else
-               close(wsi->sock);
+               if (wsi->sock)
+                       close(wsi->sock);
 #endif
 #ifdef LWS_OPENSSL_SUPPORT
        }
index 2c2b603..3e3ac19 100644 (file)
@@ -1409,8 +1409,14 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
                        fprintf(stderr, "Extension reports fatal error\n");
                        return -1;
                }
-               if (m) /* handled */
+               if (m) /* handled */ {
+//                     fprintf(stderr, "ext sent it\n");
                        return 0;
+               }
+       }
+
+       if (!wsi->sock) {
+               fprintf(stderr, "** error 0 sock but expected to send\n");
        }
 
        /*
index f2594d9..f550ff6 100644 (file)
@@ -192,6 +192,7 @@ dump_handshake_info(struct lws_tokens *lwst)
                [WSI_TOKEN_ACCEPT] = "Accept",
                [WSI_TOKEN_NONCE] = "Nonce",
                [WSI_TOKEN_HTTP] = "Http",
+               [WSI_TOKEN_MUXURL]      = "MuxURL",
        };
        
        for (n = 0; n < WSI_TOKEN_COUNT; n++) {