1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-09 00:00:04 +01:00

connect: enforce timeout for connect async wait

This patch allows client connections to recover from a nonresponsive
(ie, does not complete connect()) peer and continue to try subsequent
DNS results.
This commit is contained in:
Andy Green 2020-05-11 09:07:45 +01:00
parent e4a9307b11
commit c97b68272c
2 changed files with 40 additions and 1 deletions

View file

@ -680,6 +680,7 @@ struct lws {
lws_sorted_usec_list_t sul_timeout;
lws_sorted_usec_list_t sul_hrtimer;
lws_sorted_usec_list_t sul_validity;
lws_sorted_usec_list_t sul_connect_timeout;
struct lws_dll2 dll_buflist; /* guys with pending rxflow */
struct lws_dll2 same_vh_protocol;

View file

@ -346,6 +346,20 @@ failed:
return NULL;
}
static void
lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul)
{
struct lws *wsi = lws_container_of(sul, struct lws, sul_connect_timeout);
/*
* This is used to constrain the time we're willing to wait for a
* connection before giving up on it and retrying.
*/
lwsl_info("%s: connect wait timeout has fired\n", __func__);
lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
}
struct lws *
lws_client_connect_3_connect(struct lws *wsi, const char *ads,
const struct addrinfo *result, int n, void *opaque)
@ -392,6 +406,9 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
socklen_t sl = sizeof(int);
int e = 0;
if (!result && !wsi->sul_connect_timeout.list.owner)
goto connect_to;
/*
* this resets SO_ERROR after reading it. If there's an error
* condition the connect definitively failed.
@ -668,6 +685,9 @@ ads_known:
wsi->detlat.earliest_write_req_pre_write = lws_now_usecs();
#endif
if (!result && !wsi->sul_connect_timeout.list.owner)
goto connect_to;
m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa, n);
if (m == -1) {
int errno_copy = LWS_ERRNO;
@ -698,6 +718,15 @@ ads_known:
goto conn_good;
#endif
/*
* Let's set a specialized timeout for the connect completion,
* it uses wsi->sul_connect_timeout just for this purpose
*/
lws_sul_schedule(wsi->context, 0, &wsi->sul_connect_timeout,
lws_client_conn_wait_timeout,
wsi->context->timeout_secs * LWS_USEC_PER_SEC);
/*
* must do specifically a POLLOUT poll to hear
* about the connect completion
@ -709,7 +738,8 @@ ads_known:
}
conn_good:
lws_sul_schedule(wsi->context, 0, &wsi->sul_connect_timeout, NULL,
LWS_SET_TIMER_USEC_CANCEL);
lwsl_info("%s: Connection started %p\n", __func__, wsi->dns_results);
/* the tcp connection has happend */
@ -773,6 +803,12 @@ oom4:
return NULL;
connect_to:
/*
* It looks like the sul_connect_timeout fired
*/
lwsl_info("%s: abandoning connect due to timeout\n", __func__);
try_next_result_fds:
__remove_wsi_socket_from_fds(wsi);
@ -784,6 +820,8 @@ try_next_result_closesock:
wsi->desc.sockfd = LWS_SOCK_INVALID;
try_next_result:
lws_sul_schedule(wsi->context, 0, &wsi->sul_connect_timeout,
NULL, LWS_SET_TIMER_USEC_CANCEL);
if (wsi->dns_results_next) {
wsi->dns_results_next = wsi->dns_results_next->ai_next;
if (wsi->dns_results_next)