client accept connection request even if no free ah
It can join the free ah list and pick up client connect processing later when the ah becomes available; this simplifies the code doing the request since he won't have to deal with unexpected failures / retries based on dynamic ah availability. To do this though we have to handle that the connect_info members may not have scope that lets them still exist after we return from the first connect call, we stash them in a malloc'd buffer so the connect processing can have them much later even so. Signed-off-by: Andy Green <andy.green@linaro.org>
This commit is contained in:
parent
f859e2d3ed
commit
2d8d35a1be
4 changed files with 143 additions and 45 deletions
|
@ -72,6 +72,10 @@ with systemd
|
|||
6) test server html is updated with tabs and a new live server monitoring
|
||||
feature. Input sanitization added to the js.
|
||||
|
||||
7) client connections attempted when no ah is free no longer fail, they are
|
||||
just deferred until an ah becomes available.
|
||||
|
||||
|
||||
User API additions
|
||||
------------------
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ lws_client_connect_2(struct lws *wsi)
|
|||
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
|
||||
"User-agent: libwebsockets\x0d\x0a",
|
||||
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
|
||||
wsi->u.hdr.ah->c_port);
|
||||
wsi->u.hdr.c_port);
|
||||
|
||||
if (context->proxy_basic_auth_token[0])
|
||||
plen += sprintf((char *)pt->serv_buf + plen,
|
||||
|
@ -49,10 +49,10 @@ lws_client_connect_2(struct lws *wsi)
|
|||
#ifdef LWS_USE_IPV6
|
||||
if (LWS_IPV6_ENABLED(context)) {
|
||||
memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
|
||||
server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
|
||||
server_addr6.sin6_port = htons(wsi->u.hdr.c_port);
|
||||
} else
|
||||
#endif
|
||||
server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
|
||||
server_addr4.sin_port = htons(wsi->u.hdr.c_port);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -258,7 +258,7 @@ lws_client_connect_2(struct lws *wsi)
|
|||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
context->http_proxy_address))
|
||||
goto failed;
|
||||
wsi->u.hdr.ah->c_port = context->http_proxy_port;
|
||||
wsi->u.hdr.c_port = context->http_proxy_port;
|
||||
|
||||
n = send(wsi->sock, (char *)pt->serv_buf, plen,
|
||||
MSG_NOSIGNAL);
|
||||
|
@ -358,7 +358,7 @@ lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const
|
|||
wsi->state = LWSS_CLIENT_UNCONNECTED;
|
||||
wsi->protocol = NULL;
|
||||
wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
wsi->u.hdr.ah->c_port = port;
|
||||
wsi->u.hdr.c_port = port;
|
||||
|
||||
return lws_client_connect_2(wsi);
|
||||
}
|
||||
|
@ -382,10 +382,16 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
goto bail;
|
||||
|
||||
wsi->context = i->context;
|
||||
/* assert the mode and union status (hdr) clearly */
|
||||
lws_union_transition(wsi, LWSCM_HTTP_SERVING);
|
||||
wsi->sock = LWS_SOCK_INVALID;
|
||||
|
||||
/* -1 means just use latest supported */
|
||||
/* 1) fill up the wsi with stuff from the connect_info as far as it
|
||||
* can go. It's because not only is our connection async, we might
|
||||
* not even be able to get ahold of an ah at this point.
|
||||
*/
|
||||
|
||||
/* -1 means just use latest supported */
|
||||
if (i->ietf_version_or_minus_one != -1 && i->ietf_version_or_minus_one)
|
||||
v = i->ietf_version_or_minus_one;
|
||||
|
||||
|
@ -395,6 +401,13 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
wsi->protocol = NULL;
|
||||
wsi->pending_timeout = NO_PENDING_TIMEOUT;
|
||||
wsi->position_in_fds_table = -1;
|
||||
wsi->u.hdr.c_port = i->port;
|
||||
|
||||
wsi->protocol = &i->context->protocols[0];
|
||||
if (wsi && !wsi->user_space && i->userdata) {
|
||||
wsi->user_space_externally_allocated = 1;
|
||||
wsi->user_space = i->userdata;
|
||||
}
|
||||
|
||||
#ifdef LWS_OPENSSL_SUPPORT
|
||||
wsi->use_ssl = i->ssl_connection;
|
||||
|
@ -405,42 +418,93 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (lws_header_table_attach(wsi, 0))
|
||||
/* 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
|
||||
* process those things later (after the connect_info and maybe the
|
||||
* things pointed to have gone out of scope.
|
||||
*/
|
||||
|
||||
wsi->u.hdr.stash = lws_malloc(sizeof(*wsi->u.hdr.stash));
|
||||
if (!wsi->u.hdr.stash) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
goto bail;
|
||||
}
|
||||
|
||||
wsi->u.hdr.stash->origin[0] = '\0';
|
||||
wsi->u.hdr.stash->protocol[0] = '\0';
|
||||
|
||||
strncpy(wsi->u.hdr.stash->address, i->address,
|
||||
sizeof(wsi->u.hdr.stash->address) - 1);
|
||||
strncpy(wsi->u.hdr.stash->path, i->path,
|
||||
sizeof(wsi->u.hdr.stash->path) - 1);
|
||||
strncpy(wsi->u.hdr.stash->host, i->host,
|
||||
sizeof(wsi->u.hdr.stash->host) - 1);
|
||||
if (i->origin)
|
||||
strncpy(wsi->u.hdr.stash->origin, i->origin,
|
||||
sizeof(wsi->u.hdr.stash->origin) - 1);
|
||||
if (i->protocol)
|
||||
strncpy(wsi->u.hdr.stash->protocol, i->protocol,
|
||||
sizeof(wsi->u.hdr.stash->protocol) - 1);
|
||||
|
||||
wsi->u.hdr.stash->address[sizeof(wsi->u.hdr.stash->address) - 1] = '\0';
|
||||
wsi->u.hdr.stash->path[sizeof(wsi->u.hdr.stash->path) - 1] = '\0';
|
||||
wsi->u.hdr.stash->host[sizeof(wsi->u.hdr.stash->host) - 1] = '\0';
|
||||
wsi->u.hdr.stash->origin[sizeof(wsi->u.hdr.stash->origin) - 1] = '\0';
|
||||
wsi->u.hdr.stash->protocol[sizeof(wsi->u.hdr.stash->protocol) - 1] = '\0';
|
||||
|
||||
/* if we went on the waiting list, no probs just return the wsi
|
||||
* when we get the ah, now or later, he will call
|
||||
* lws_client_connect_via_info2() below
|
||||
*/
|
||||
if (lws_header_table_attach(wsi, 0))
|
||||
lwsl_debug("%s: went on ah wait list\n", __func__);
|
||||
|
||||
return wsi;
|
||||
|
||||
bail:
|
||||
lws_free(wsi);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct lws *
|
||||
lws_client_connect_via_info2(struct lws *wsi)
|
||||
{
|
||||
struct client_info_stash *stash = wsi->u.hdr.stash;
|
||||
|
||||
if (!stash)
|
||||
return wsi;
|
||||
|
||||
/*
|
||||
* 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.ah->c_port = i->port;
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, i->address))
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
|
||||
stash->address))
|
||||
goto bail1;
|
||||
|
||||
/* these only need u.hdr lifetime as well */
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, i->path))
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, stash->path))
|
||||
goto bail1;
|
||||
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, i->host))
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, stash->host))
|
||||
goto bail1;
|
||||
|
||||
if (i->origin)
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, i->origin))
|
||||
if (stash->origin[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN,
|
||||
stash->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 (i->protocol)
|
||||
if (stash->protocol[0])
|
||||
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
|
||||
i->protocol))
|
||||
stash->protocol))
|
||||
goto bail1;
|
||||
|
||||
wsi->protocol = &i->context->protocols[0];
|
||||
if (wsi && !wsi->user_space && i->userdata) {
|
||||
wsi->user_space_externally_allocated = 1;
|
||||
wsi->user_space = i->userdata;
|
||||
}
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
|
||||
/*
|
||||
* Check with each extension if it is able to route and proxy this
|
||||
|
@ -449,9 +513,10 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
* connection.
|
||||
*/
|
||||
|
||||
if (lws_ext_cb_all_exts(i->context, wsi,
|
||||
LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
|
||||
(void *)i->address, i->port) > 0) {
|
||||
if (lws_ext_cb_all_exts(wsi->context, wsi,
|
||||
LWS_EXT_CB_CAN_PROXY_CLIENT_CONNECTION,
|
||||
(void *)stash->address,
|
||||
wsi->u.hdr.c_port) > 0) {
|
||||
lwsl_client("lws_client_connect: ext handling conn\n");
|
||||
|
||||
lws_set_timeout(wsi,
|
||||
|
@ -462,17 +527,12 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
|
|||
return wsi;
|
||||
}
|
||||
lwsl_client("lws_client_connect: direct conn\n");
|
||||
|
||||
wsi->context->count_wsi_allocated++;
|
||||
|
||||
return lws_client_connect_2(wsi);
|
||||
|
||||
bail1:
|
||||
/* we're closing, losing some rx is OK */
|
||||
wsi->u.hdr.ah->rxpos = wsi->u.hdr.ah->rxlen;
|
||||
lws_header_table_detach(wsi, 0);
|
||||
bail:
|
||||
lws_free(wsi);
|
||||
lws_free_set_NULL(wsi->u.hdr.stash);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -185,6 +185,11 @@ reset:
|
|||
lws_header_table_reset(wsi, autoservice);
|
||||
time(&wsi->u.hdr.ah->assigned);
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if (wsi->state == LWSS_CLIENT_UNCONNECTED)
|
||||
lws_client_connect_via_info2(wsi);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
bail:
|
||||
|
@ -293,6 +298,11 @@ int lws_header_table_detach(struct lws *wsi, int autoservice)
|
|||
wsi->u.hdr.ah_wait_list = NULL;
|
||||
pt->ah_wait_list_length--;
|
||||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
if (wsi->state == LWSS_CLIENT_UNCONNECTED)
|
||||
lws_client_connect_via_info2(wsi);
|
||||
#endif
|
||||
|
||||
assert(!!pt->ah_wait_list_length == !!(int)(long)pt->ah_wait_list);
|
||||
bail:
|
||||
lws_pt_unlock(pt);
|
||||
|
|
|
@ -359,7 +359,7 @@ enum lws_connection_states {
|
|||
LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS,
|
||||
LWSS_HTTP2_ESTABLISHED,
|
||||
|
||||
LWSS_CGI
|
||||
LWSS_CGI,
|
||||
};
|
||||
|
||||
enum http_version {
|
||||
|
@ -517,7 +517,6 @@ struct allocated_headers {
|
|||
|
||||
#ifndef LWS_NO_CLIENT
|
||||
char initial_handshake_hash_base64[30];
|
||||
unsigned short c_port;
|
||||
#endif
|
||||
|
||||
unsigned short pos;
|
||||
|
@ -788,10 +787,37 @@ enum uri_esc_states {
|
|||
* used interchangeably to access the same data
|
||||
*/
|
||||
|
||||
struct _lws_header_related {
|
||||
/* MUST be first in struct */
|
||||
struct allocated_headers *ah;
|
||||
struct lws *ah_wait_list;
|
||||
unsigned char *preamble_rx;
|
||||
#ifndef LWS_NO_CLIENT
|
||||
struct client_info_stash *stash;
|
||||
#endif
|
||||
unsigned int preamble_rx_len;
|
||||
enum uri_path_states ups;
|
||||
enum uri_esc_states ues;
|
||||
short lextable_pos;
|
||||
unsigned short current_token_limit;
|
||||
#ifndef LWS_NO_CLIENT
|
||||
unsigned short c_port;
|
||||
#endif
|
||||
char esc_stash;
|
||||
char post_literal_equal;
|
||||
unsigned char parser_state; /* enum lws_token_indexes */
|
||||
char redirects;
|
||||
};
|
||||
|
||||
struct _lws_http_mode_related {
|
||||
/* MUST be first in struct */
|
||||
struct allocated_headers *ah; /* mirroring _lws_header_related */
|
||||
struct lws *ah_wait_list;
|
||||
unsigned char *preamble_rx;
|
||||
#ifndef LWS_NO_CLIENT
|
||||
struct client_info_stash *stash;
|
||||
#endif
|
||||
unsigned int preamble_rx_len;
|
||||
struct lws *new_wsi_list;
|
||||
unsigned long filepos;
|
||||
unsigned long filelen;
|
||||
|
@ -950,21 +976,16 @@ struct _lws_http2_related {
|
|||
|
||||
#endif
|
||||
|
||||
struct _lws_header_related {
|
||||
/* MUST be first in struct */
|
||||
struct allocated_headers *ah;
|
||||
struct lws *ah_wait_list;
|
||||
unsigned char *preamble_rx;
|
||||
unsigned int preamble_rx_len;
|
||||
enum uri_path_states ups;
|
||||
enum uri_esc_states ues;
|
||||
short lextable_pos;
|
||||
unsigned short current_token_limit;
|
||||
char esc_stash;
|
||||
char post_literal_equal;
|
||||
unsigned char parser_state; /* enum lws_token_indexes */
|
||||
char redirects;
|
||||
#ifndef LWS_NO_CLIENT
|
||||
struct client_info_stash {
|
||||
char address[256];
|
||||
char path[1024];
|
||||
char host[256];
|
||||
char origin[256];
|
||||
char protocol[256];
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
struct _lws_websocket_related {
|
||||
/* cheapest way to deal with ah overlap with ws union transition */
|
||||
|
@ -1212,6 +1233,9 @@ lws_generate_client_handshake(struct lws *wsi, char *pkt);
|
|||
LWS_EXTERN int
|
||||
lws_handle_POLLOUT_event(struct lws *wsi, struct lws_pollfd *pollfd);
|
||||
|
||||
LWS_EXTERN struct lws *
|
||||
lws_client_connect_via_info2(struct lws *wsi);
|
||||
|
||||
/*
|
||||
* EXTENSIONS
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue