From cd1b50ef65eaf4b54a3cc3c606ed1c03bdf3450d Mon Sep 17 00:00:00 2001 From: Andy Green Date: Mon, 11 Feb 2013 13:04:45 +0800 Subject: [PATCH] client convert to new headers scheme eliminating mallocs This removes all the direct wsi members specific to clients, most of them are moved to being fake headers in the next 3-layer header scheme, c_port moves to being a member of the u.hdr unionized struct. It gets rid of a lot of fiddly mallocs and frees(), despite it adds a small internal API to create the fake headers, actually the patch deletes more than it adds... Signed-off-by: Andy Green --- lib/client-handshake.c | 120 ++++++++++++++++---------------------------- lib/client.c | 50 ++++-------------- lib/libwebsockets.c | 4 -- lib/libwebsockets.h | 8 +++ lib/parsers.c | 27 ++++++++++ lib/private-libwebsockets.h | 15 ++---- 6 files changed, 93 insertions(+), 131 deletions(-) diff --git a/lib/client-handshake.c b/lib/client-handshake.c index 01aae4d..1a0d362 100644 --- a/lib/client-handshake.c +++ b/lib/client-handshake.c @@ -9,6 +9,7 @@ struct libwebsocket *__libwebsocket_client_connect_2( struct sockaddr_in server_addr; int n; int plen = 0; + const char *ads; lwsl_client("__libwebsocket_client_connect_2\n"); @@ -21,25 +22,29 @@ struct libwebsocket *__libwebsocket_client_connect_2( "CONNECT %s:%u HTTP/1.0\x0d\x0a" "User-agent: libwebsockets\x0d\x0a" /*Proxy-authorization: basic aGVsbG86d29ybGQ= */ - "\x0d\x0a", wsi->c_address, wsi->c_port); + "\x0d\x0a", + lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS), + wsi->u.hdr.c_port); - /* OK from now on we talk via the proxy */ + /* OK from now on we talk via the proxy, so connect to that */ - free(wsi->c_address); - wsi->c_address = strdup(context->http_proxy_address); - wsi->c_port = context->http_proxy_port; + /* (will overwrite existing pointer, leaving old string/frag there but unreferenced) */ + if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, context->http_proxy_address)) + goto oom4; + wsi->u.hdr.c_port = context->http_proxy_port; } /* * prepare the actual connection (to the proxy, if any) */ - lwsl_client("__libwebsocket_client_connect_2: address %s\n", - wsi->c_address); + ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS); - server_hostent = gethostbyname(wsi->c_address); + lwsl_client("__libwebsocket_client_connect_2: address %s\n", ads); + + server_hostent = gethostbyname(ads); if (server_hostent == NULL) { - lwsl_err("Unable to get host name from %s\n", wsi->c_address); + lwsl_err("Unable to get host name from %s\n", ads); goto oom4; } @@ -51,7 +56,7 @@ struct libwebsocket *__libwebsocket_client_connect_2( } server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(wsi->c_port); + server_addr.sin_port = htons(wsi->u.hdr.c_port); server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr); bzero(&server_addr.sin_zero, 8); @@ -119,15 +124,7 @@ struct libwebsocket *__libwebsocket_client_connect_2( return wsi; oom4: - if (wsi->c_protocol) - free(wsi->c_protocol); - - if (wsi->c_origin) - free(wsi->c_origin); - - free(wsi->c_host); - free(wsi->c_path); - + free(wsi->u.hdr.ah); bail1: free(wsi); @@ -203,58 +200,37 @@ libwebsocket_client_connect(struct libwebsocket_context *context, wsi->use_ssl = ssl_connection; #endif - wsi->c_port = port; - wsi->c_address = strdup(address); + if (lws_allocate_header_table(wsi)) + goto bail; + + /* + * we're not necessarily in a position to action these right away, + * stash them... we only need during connect phase so u.hdr is fine + */ + wsi->u.hdr.c_port = port; + if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address)) + goto bail1; - /* copy parameters over so state machine has access */ + /* these only need u.hdr lifetime as well */ - wsi->c_path = (char *)malloc(strlen(path) + 1); - if (wsi->c_path == NULL) + if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path)) goto bail1; - strcpy(wsi->c_path, path); - - wsi->c_host = (char *)malloc(strlen(host) + 1); - if (wsi->c_host == NULL) - goto oom1; - strcpy(wsi->c_host, host); - - if (origin) { - wsi->c_origin = (char *)malloc(strlen(origin) + 1); - if (wsi->c_origin == NULL) - goto oom2; - strcpy(wsi->c_origin, origin); - } else - wsi->c_origin = NULL; - - wsi->c_callback = NULL; - if (protocol) { - const char *pc; - struct libwebsocket_protocols *pp; - - wsi->c_protocol = (char *)malloc(strlen(protocol) + 1); - if (wsi->c_protocol == NULL) - goto oom3; - - strcpy(wsi->c_protocol, protocol); - - pc = protocol; - while (*pc && *pc != ',') - pc++; - n = pc - protocol; - pp = context->protocols; - while (pp->name && !wsi->c_callback) { - if (!strncmp(protocol, pp->name, n)) - wsi->c_callback = pp->callback; - pp++; - } - } else - wsi->c_protocol = NULL; - if (!wsi->c_callback) - wsi->c_callback = context->protocols[0].callback; + if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host)) + goto bail1; - if (lws_allocate_header_table(wsi)) - goto oom3; + if (origin) + if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, origin)) + goto bail1; + /* + * this is a list of protocols we tell the server we're okay with + * stash it for later when we compare server response with it + */ + if (protocol) + if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol)) + goto bail1; + + wsi->protocol = &context->protocols[0]; #ifndef LWS_NO_EXTENSIONS /* @@ -293,17 +269,9 @@ libwebsocket_client_connect(struct libwebsocket_context *context, return __libwebsocket_client_connect_2(context, wsi); -oom3: - if (wsi->c_origin) - free(wsi->c_origin); - -oom2: - free(wsi->c_host); - -oom1: - free(wsi->c_path); - bail1: + free(wsi->u.hdr.ah); +bail: free(wsi); return NULL; diff --git a/lib/client.c b/lib/client.c index 200b3ad..c9c6274 100644 --- a/lib/client.c +++ b/lib/client.c @@ -309,8 +309,6 @@ int lws_client_socket_service(struct libwebsocket_context *context, struct libwe return lws_client_interpret_server_handshake(context, wsi); bail3: - if (wsi->c_protocol) - free(wsi->c_protocol); lwsl_info("closing connection at LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY\n"); libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); @@ -398,7 +396,7 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, goto bail3; } - pc = wsi->c_protocol; + pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS); if (pc == NULL) lwsl_parser("lws_client_interpret_server_handshake: " "NULL c_protocol\n"); @@ -421,9 +419,6 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, * default to first protocol */ wsi->protocol = &context->protocols[0]; - wsi->c_callback = wsi->protocol->callback; - free(wsi->c_protocol); - goto check_extensions; } @@ -441,11 +436,6 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, pc++; } - /* done with him now */ - - if (wsi->c_protocol) - free(wsi->c_protocol); - if (!okay) { lwsl_err("libwebsocket_client_handshake server " "sent bad protocol '%s'\n", p); @@ -460,7 +450,6 @@ lws_client_interpret_server_handshake(struct libwebsocket_context *context, while (context->protocols[n].callback && !wsi->protocol) { if (strcmp(p, context->protocols[n].name) == 0) { wsi->protocol = &context->protocols[n]; - wsi->c_callback = wsi->protocol->callback; break; } n++; @@ -659,12 +648,10 @@ check_accept: return 0; bail3: - if (wsi->c_protocol) - free(wsi->c_protocol); bail2: - if (wsi->c_callback) - wsi->c_callback(context, wsi, + if (wsi->protocol) + wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLIENT_CONNECTION_ERROR, wsi->user_space, NULL, 0); @@ -707,12 +694,6 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, if (n != 16) { lwsl_err("Unable to read from random dev %s\n", SYSTEM_RANDOM_FILEPATH); - free(wsi->c_path); - free(wsi->c_host); - if (wsi->c_origin) - free(wsi->c_origin); - if (wsi->c_protocol) - free(wsi->c_protocol); libwebsocket_close_and_free_session(context, wsi, LWS_CLOSE_STATUS_NOSTATUS); return NULL; @@ -746,28 +727,24 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, * Sec-WebSocket-Version: 4 */ - p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path); + p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI)); p += sprintf(p, "Pragma: no-cache\x0d\x0a" "Cache-Control: no-cache\x0d\x0a"); - p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host); + p += sprintf(p, "Host: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST)); p += sprintf(p, "Upgrade: websocket\x0d\x0a" "Connection: Upgrade\x0d\x0a" "Sec-WebSocket-Key: "); strcpy(p, key_b64); p += strlen(key_b64); p += sprintf(p, "\x0d\x0a"); - if (wsi->c_origin) { - if (wsi->ietf_spec_revision == 13) - p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin); - else - p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a", - wsi->c_origin); - } - if (wsi->c_protocol) + if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)) + p += sprintf(p, "Origin: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN)); + + if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS)) p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a", - wsi->c_protocol); + lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS)); /* tell the server what extensions we could support */ @@ -843,13 +820,6 @@ libwebsockets_generate_client_handshake(struct libwebsocket_context *context, wsi->u.hdr.initial_handshake_hash_base64, sizeof wsi->u.hdr.initial_handshake_hash_base64); - /* done with these now */ - - free(wsi->c_path); - free(wsi->c_host); - if (wsi->c_origin) - free(wsi->c_origin); - return p; } diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index 4d0f474..d8abe7e 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -358,10 +358,6 @@ just_kill_connection: } #endif -#ifndef LWS_NO_CLIENT - if (wsi->c_address) - free(wsi->c_address); -#endif if (wsi->u.ws.rxflow_buffer) free(wsi->u.ws.rxflow_buffer); diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h index 8ead410..98c76c0 100644 --- a/lib/libwebsockets.h +++ b/lib/libwebsockets.h @@ -240,6 +240,14 @@ enum lws_token_indexes { WSI_TOKEN_HTTP, WSI_TOKEN_MUXURL, + /* use token storage to stash these */ + + _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, + _WSI_TOKEN_CLIENT_PEER_ADDRESS, + _WSI_TOKEN_CLIENT_URI, + _WSI_TOKEN_CLIENT_HOST, + _WSI_TOKEN_CLIENT_ORIGIN, + /* always last real token index*/ WSI_TOKEN_COUNT, /* parser state additions */ diff --git a/lib/parsers.c b/lib/parsers.c index e445aac..dcd5383 100644 --- a/lib/parsers.c +++ b/lib/parsers.c @@ -370,6 +370,33 @@ char * lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h) return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]; } +int lws_hdr_simple_create(struct libwebsocket *wsi, enum lws_token_indexes h, const char *s) +{ + wsi->u.hdr.ah->next_frag_index++; + if (wsi->u.hdr.ah->next_frag_index == sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) { + lwsl_warn("More header fragments than we can deal with, dropping\n"); + return -1; + } + + wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index; + + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset = wsi->u.hdr.ah->pos; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0; + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index = 0; + + do { + if (wsi->u.hdr.ah->pos == sizeof wsi->u.hdr.ah->data) { + lwsl_err("Ran out of header data space\n"); + return -1; + } + wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s; + if (*s) + wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++; + } while (*s++); + + return 0; +} + int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c) { int n; diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h index a24d584..3ab20c9 100644 --- a/lib/private-libwebsockets.h +++ b/lib/private-libwebsockets.h @@ -330,6 +330,7 @@ struct _lws_header_related { int current_alloc_len; #ifndef LWS_NO_CLIENT char initial_handshake_hash_base64[30]; + unsigned short c_port; #endif }; @@ -391,17 +392,6 @@ struct libwebsocket { struct _lws_websocket_related ws; } u; -#ifndef LWS_NO_CLIENT - char *c_path; - char *c_host; - char *c_origin; - char *c_protocol; - callback_function *c_callback; - - char *c_address; - unsigned short c_port; -#endif - #ifdef LWS_OPENSSL_SUPPORT SSL *ssl; BIO *client_bio; @@ -504,6 +494,9 @@ lws_allocate_header_table(struct libwebsocket *wsi); extern char * lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h); +extern int +lws_hdr_simple_create(struct libwebsocket *wsi, enum lws_token_indexes h, const char *s); + #ifndef LWS_OPENSSL_SUPPORT unsigned char * -- 2.7.4