diff options
-rw-r--r-- | README-test-server | 23 | ||||
-rw-r--r-- | lib/extension-x-google-mux.c | 32 | ||||
-rw-r--r-- | lib/libwebsockets.c | 21 | ||||
-rw-r--r-- | lib/libwebsockets.h | 1 | ||||
-rw-r--r-- | lib/parsers.c | 155 | ||||
-rw-r--r-- | lib/private-libwebsockets.h | 4 |
6 files changed, 144 insertions, 92 deletions
diff --git a/README-test-server b/README-test-server index 9c8475f..c140b8b 100644 --- a/README-test-server +++ b/README-test-server @@ -263,25 +263,18 @@ It has the following notes: 1) To enable it, reconfigure with --enable-x-google-mux - 2) It conflicts with deflate-stream, use the -u switch on - the test client to disable deflate-stream - - 3) It deviates from the google standard by sending full + 2) It deviates from the google standard by sending full headers in the addchannel subcommand rather than just changed ones from original connect - 4) Quota is not implemented yet - - 5) Close of subchannel is not really implemented yet - - 6) Google opcode 0xf is changed to 0x7 to account for - v7 protocol changes to opcode layout + 3) Quota is not implemented yet - However despite those caveats, in fact it can run the - test client reliably over one socket (both dumb-increment - and lws-mirror-protocol), you can open a browser on the - same test server too and see the circles, etc. +However despite those caveats, in fact it can run the +test client reliably over one socket (both dumb-increment +and lws-mirror-protocol), you can open a browser on the +same test server too and see the circles, etc. +It also works compatibly with deflate-stream automatically. -2011-05-23 Andy Green <andy@warmcat.com> +2011-05-28 Andy Green <andy@warmcat.com> diff --git a/lib/extension-x-google-mux.c b/lib/extension-x-google-mux.c index 13bc461..95253b4 100644 --- a/lib/extension-x-google-mux.c +++ b/lib/extension-x-google-mux.c @@ -5,6 +5,7 @@ static int ongoing_subchannel; static struct libwebsocket * tag_with_parent = NULL; +static int client_handshake_generation_is_for_mux_child; static int lws_addheader_mux_opcode(unsigned char *pb, int len) { @@ -96,8 +97,10 @@ static int lws_ext_x_google_mux__send_addchannel( wsi_child->ietf_spec_revision = wsi->ietf_spec_revision; + client_handshake_generation_is_for_mux_child = 1; p = libwebsockets_generate_client_handshake(context, wsi_child, delta_headers); + client_handshake_generation_is_for_mux_child = 0; delta_headers_len = p - delta_headers; subcommand_length = lws_mux_subcommand_header( @@ -122,7 +125,7 @@ static int lws_ext_x_google_mux__send_addchannel( /* send the request to the server */ - n = lws_issue_raw(wsi, &send_buf[LWS_SEND_BUFFER_PRE_PADDING], + n = lws_issue_raw_ext_access(wsi, &send_buf[LWS_SEND_BUFFER_PRE_PADDING], pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]); parent_conn->defeat_mux_opcode_wrapping = 0; @@ -443,6 +446,10 @@ bail2: wsi->xor_mask = xor_no_mask; child_conn = lws_get_extension_user_matching_ext(wsi_child, this_ext); + if (!child_conn) { + fprintf(stderr, "wsi_child %p has no child conn!", (void *)wsi_child); + break; + } child_conn->wsi_parent = wsi; conn->sticky_mux_used = 1; child_conn->subchannel = conn->block_subchannel; @@ -526,7 +533,7 @@ bail2: * afterwards */ if (conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET >= conn->highest_child_subchannel) { - fprintf(stderr, "Illegal subchannel\n"); + fprintf(stderr, "Illegal subchannel %d\n", conn->block_subchannel); return -1; } @@ -541,6 +548,11 @@ bail2: } else wsi_child = conn->wsi_children[conn->block_subchannel - MUX_REAL_CHILD_INDEX_OFFSET]; + if (!wsi_child) { + fprintf(stderr, "Bad subchannel %d\n", conn->block_subchannel); + return -1; + } + switch (wsi_child->mode) { /* client receives something */ @@ -1078,7 +1090,7 @@ handle_additions: * recurse to allow nesting */ - lws_issue_raw(wsi_parent, basepin, (pin - basepin) + len); + lws_issue_raw_ext_access(wsi_parent, basepin, (pin - basepin) + len); return 1; /* handled */ @@ -1144,7 +1156,7 @@ handle_additions: memcpy(pb, in, len); pb += len; - lws_issue_raw(wsi->extension_handles, &send_buf[LWS_SEND_BUFFER_PRE_PADDING], + lws_issue_raw_ext_access(wsi->extension_handles, &send_buf[LWS_SEND_BUFFER_PRE_PADDING], pb - &send_buf[LWS_SEND_BUFFER_PRE_PADDING]); @@ -1190,6 +1202,18 @@ handle_additions: } break; + case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION: + + /* disallow deflate-stream if we are a mux child connection */ + + if (strcmp(in, "deflate-stream") == 0 && + client_handshake_generation_is_for_mux_child) { + + fprintf(stderr, "mux banned deflate-stream on child connection\n"); + return 1; /* disallow */ + } + break; + default: break; } diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 0021eb4..90e1fbe 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -784,6 +784,7 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, char *p = pkt; int n; struct libwebsocket_extension *ext; + struct libwebsocket_extension *ext1; int ext_count = 0; unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 1 + MAX_BROADCAST_PAYLOAD + LWS_SEND_BUFFER_POST_PADDING]; @@ -957,6 +958,24 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, while (ext && ext->callback) { n = 0; + ext1 = context->extensions; + while (ext1 && ext1->callback) { + + n |= ext1->callback(context, ext1, wsi, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, + NULL, (char *)ext->name, 0); + + ext1++; + } + + if (n) { + + /* an extension vetos us */ + fprintf(stderr, "ext %s vetoed\n", (char *)ext->name); + ext++; + continue; + } + n = context->protocols[0].callback(context, wsi, LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED, wsi->user_space, (char *)ext->name, 0); @@ -1010,6 +1029,8 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, issue_hdr: + puts(pkt); + /* done with these now */ free(wsi->c_path); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 49bf648..2ab918d 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -83,6 +83,7 @@ enum libwebsocket_extension_callback_reasons { LWS_EXT_CALLBACK_CONSTRUCT, LWS_EXT_CALLBACK_CLIENT_CONSTRUCT, LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, + LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION, LWS_EXT_CALLBACK_DESTROY, LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, diff --git a/lib/parsers.c b/lib/parsers.c index 3e3ac19..7ad040e 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -1450,6 +1450,87 @@ int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len) return 0; } +int +lws_issue_raw_ext_access(struct libwebsocket *wsi, + unsigned char *buf, size_t len) +{ + int ret; + struct lws_tokens eff_buf; + int m; + int n; + + eff_buf.token = (char *)buf; + eff_buf.token_len = len; + + /* + * while we have original buf to spill ourselves, or extensions report + * more in their pipeline + */ + + ret = 1; + while (ret == 1) { + + /* default to nobody has more to spill */ + + ret = 0; + + /* show every extension the new incoming data */ + + for (n = 0; n < wsi->count_active_extensions; n++) { + m = wsi->active_extensions[n]->callback( + wsi->protocol->owning_server, + wsi->active_extensions[n], wsi, + LWS_EXT_CALLBACK_PACKET_TX_PRESEND, + wsi->active_extensions_user[n], &eff_buf, 0); + if (m < 0) { + fprintf(stderr, "Extension reports fatal error\n"); + return -1; + } + if (m) + /* + * at least one extension told us he has more + * to spill, so we will go around again after + */ + ret = 1; + } + + /* assuming they left us something to send, send it */ + + if (eff_buf.token_len) + if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, + eff_buf.token_len)) + return -1; + + /* we used up what we had */ + + eff_buf.token = NULL; + eff_buf.token_len = 0; + + /* + * Did that leave the pipe choked? + */ + + if (!lws_send_pipe_choked(wsi)) + /* no we could add more */ + continue; + + fprintf(stderr, "choked\n"); + + /* + * Yes, he's choked. Don't spill the rest now get a callback + * when he is ready to send and take care of it there + */ + libwebsocket_callback_on_writable( + wsi->protocol->owning_server, wsi); + wsi->extension_data_pending = 1; + ret = 0; + } + + debug("written %d bytes to client\n", eff_buf.token_len); + + return 0; +} + /** * libwebsocket_write() - Apply protocol then write data to client * @wsi: Websocket instance (available from user callback) @@ -1479,12 +1560,9 @@ int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf, size_t len, enum libwebsocket_write_protocol protocol) { int n; - int m; int pre = 0; int post = 0; int shift = 7; - struct lws_tokens eff_buf; - int ret; int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT && wsi->xor_mask != xor_no_mask; unsigned char *dropmask = NULL; unsigned char is_masked_bit = 0; @@ -1780,76 +1858,7 @@ send_raw: * callback returns 1 in case it wants to spill more buffers */ - eff_buf.token = (char *)buf - pre; - eff_buf.token_len = len + pre + post; - - /* - * while we have original buf to spill ourselves, or extensions report - * more in their pipeline - */ - - ret = 1; - while (ret == 1) { - - /* default to nobody has more to spill */ - - ret = 0; - - /* show every extension the new incoming data */ - - for (n = 0; n < wsi->count_active_extensions; n++) { - m = wsi->active_extensions[n]->callback( - wsi->protocol->owning_server, - wsi->active_extensions[n], wsi, - LWS_EXT_CALLBACK_PACKET_TX_PRESEND, - wsi->active_extensions_user[n], &eff_buf, 0); - if (m < 0) { - fprintf(stderr, "Extension reports fatal error\n"); - return -1; - } - if (m) - /* - * at least one extension told us he has more - * to spill, so we will go around again after - */ - ret = 1; - } - - /* assuming they left us something to send, send it */ - - if (eff_buf.token_len) - if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token, - eff_buf.token_len)) - return -1; - - /* we used up what we had */ - - eff_buf.token = NULL; - eff_buf.token_len = 0; - - /* - * Did that leave the pipe choked? - */ - - if (!lws_send_pipe_choked(wsi)) - /* no we could add more */ - continue; - - fprintf(stderr, "choked\n"); - - /* - * Yes, he's choked. Don't spill the rest now get a callback - * when he is ready to send and take care of it there - */ - libwebsocket_callback_on_writable( - wsi->protocol->owning_server, wsi); - wsi->extension_data_pending = 1; - ret = 0; - } - - debug("written %d bytes to client\n", eff_buf.token_len); - - return 0; + return lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post); } diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index bf2865d..e706bf5 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -415,6 +415,10 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, extern int libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c); +extern int +lws_issue_raw_ext_access(struct libwebsocket *wsi, + unsigned char *buf, size_t len); + #ifndef LWS_OPENSSL_SUPPORT unsigned char * |