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

client: win32: sul for client connection status polling

https://github.com/warmcat/libwebsockets/pull/2715
https://github.com/warmcat/libwebsockets/pull/2722
This commit is contained in:
Vladimir 2022-09-03 22:19:14 +02:00 committed by Andy Green
parent a5ea6eabca
commit 8ab44ae28b
6 changed files with 104 additions and 30 deletions

View file

@ -941,6 +941,14 @@ struct lws_context_creation_info {
*/ */
#endif #endif
#if defined(WIN32)
unsigned int win32_connect_check_interval_usec;
/**< CONTEXT: win32 needs client connection status checking at intervals
* to work reliably. This sets the interval in us, up to 999999. By
* default, it's 500us.
*/
#endif
/* Add new things just above here ---^ /* Add new things just above here ---^
* This is part of the ABI, don't needlessly break compatibility * This is part of the ABI, don't needlessly break compatibility
* *

View file

@ -24,6 +24,30 @@
#include "private-lib-core.h" #include "private-lib-core.h"
#if defined(WIN32)
/*
* Windows doesn't offer a Posix connect() event... we use a sul
* to check the connection status periodically while a connection
* is ongoing.
*
* Leaving this to POLLOUT to retry which is the way for Posix
* platforms instead on win32 causes event-loop busywaiting
* so for win32 we manage the retry interval directly with the sul.
*/
void
lws_client_win32_conn_async_check(lws_sorted_usec_list_t *sul)
{
struct lws *wsi = lws_container_of(sul, struct lws,
win32_sul_connect_async_check);
lwsl_wsi_debug(wsi, "checking ongoing connection attempt");
lws_client_connect_3_connect(wsi, NULL, NULL, 0, NULL);
}
#endif
void void
lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul) lws_client_conn_wait_timeout(lws_sorted_usec_list_t *sul)
{ {
@ -107,40 +131,41 @@ lws_client_connect_check(struct lws *wsi, int *real_errno)
return LCCCR_FAILED; return LCCCR_FAILED;
} }
#else #else
fd_set write_set, except_set;
struct timeval tv;
int ret;
if (!connect(wsi->desc.sockfd, (const struct sockaddr *)&wsi->sa46_peer.sa4, FD_ZERO(&write_set);
#if defined(WIN32) FD_ZERO(&except_set);
sizeof(struct sockaddr))) FD_SET(wsi->desc.sockfd, &write_set);
#else FD_SET(wsi->desc.sockfd, &except_set);
0))
#endif
tv.tv_sec = 0;
tv.tv_usec = 0;
ret = select((int)wsi->desc.sockfd + 1, NULL, &write_set, &except_set, &tv);
if (FD_ISSET(wsi->desc.sockfd, &write_set)) {
/* actually connected */
lwsl_wsi_debug(wsi, "select write fd set, conn OK");
return LCCCR_CONNECTED; return LCCCR_CONNECTED;
en = LWS_ERRNO;
if (en == WSAEISCONN) /* already connected */
return LCCCR_CONNECTED;
if (en == WSAEALREADY) {
/* reset the POLLOUT wait */
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
lwsl_wsi_notice(wsi, "pollfd failed");
} }
if (!en || en == WSAEINVAL || if (FD_ISSET(wsi->desc.sockfd, &except_set)) {
en == WSAEWOULDBLOCK || /* Failed to connect */
en == WSAEALREADY) { lwsl_wsi_notice(wsi, "connect failed, select exception fd set");
lwsl_wsi_debug(wsi, "%s", return LCCCR_FAILED;
lws_errno_describe(en, t16, sizeof(t16))); }
if (!ret) {
lwsl_wsi_debug(wsi, "select timeout");
return LCCCR_CONTINUE; return LCCCR_CONTINUE;
} }
en = LWS_ERRNO;
#endif #endif
lwsl_wsi_notice(wsi, "connect check FAILED: %s", lwsl_wsi_notice(wsi, "connection check FAILED: %s",
lws_errno_describe(*real_errno || en, t16, sizeof(t16))); lws_errno_describe(*real_errno || en, t16, sizeof(t16)));
return LCCCR_FAILED; return LCCCR_FAILED;
@ -261,7 +286,14 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
*/ */
goto conn_good; goto conn_good;
case LCCCR_CONTINUE: case LCCCR_CONTINUE:
#if defined(WIN32)
lws_sul_schedule(wsi->a.context, 0, &wsi->win32_sul_connect_async_check,
lws_client_win32_conn_async_check,
wsi->a.context->win32_connect_check_interval_usec);
#endif
return NULL; return NULL;
default: default:
if (!real_errno) if (!real_errno)
real_errno = LWS_ERRNO; real_errno = LWS_ERRNO;
@ -627,13 +659,25 @@ ads_known:
lws_client_conn_wait_timeout, lws_client_conn_wait_timeout,
wsi->a.context->timeout_secs * wsi->a.context->timeout_secs *
LWS_USEC_PER_SEC); LWS_USEC_PER_SEC);
#if defined(WIN32)
/* /*
* must do specifically a POLLOUT poll to hear * Windows is not properly POSIX, we have to manually schedule a
* about the connect completion * callback to poll checking its status
*/ */
lws_sul_schedule(wsi->a.context, 0, &wsi->win32_sul_connect_async_check,
lws_client_win32_conn_async_check,
wsi->a.context->win32_connect_check_interval_usec
);
#else
/*
* POSIX platforms must do specifically a POLLOUT poll to hear
* about the connect completion as a POLLOUT event
*/
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT)) if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
goto try_next_dns_result_fds; goto try_next_dns_result_fds;
#endif
return wsi; return wsi;
} }
@ -673,8 +717,10 @@ conn_good:
#endif #endif
} }
#endif #endif
lws_sul_cancel(&wsi->sul_connect_timeout); lws_sul_cancel(&wsi->sul_connect_timeout);
#if defined(WIN32)
lws_sul_cancel(&wsi->win32_sul_connect_async_check);
#endif
lws_metrics_caliper_report(wsi->cal_conn, METRES_GO); lws_metrics_caliper_report(wsi->cal_conn, METRES_GO);
lws_addrinfo_clean(wsi); lws_addrinfo_clean(wsi);
@ -745,6 +791,9 @@ try_next_dns_result_closesock:
try_next_dns_result: try_next_dns_result:
lws_sul_cancel(&wsi->sul_connect_timeout); lws_sul_cancel(&wsi->sul_connect_timeout);
#if defined(WIN32)
lws_sul_cancel(&wsi->win32_sul_connect_async_check);
#endif
if (lws_dll2_get_head(&wsi->dns_sorted_list)) if (lws_dll2_get_head(&wsi->dns_sorted_list))
goto next_dns_result; goto next_dns_result;

View file

@ -581,6 +581,9 @@ just_kill_connection:
#endif #endif
lws_sul_cancel(&wsi->sul_connect_timeout); lws_sul_cancel(&wsi->sul_connect_timeout);
#if defined(WIN32)
lws_sul_cancel(&wsi->win32_sul_connect_async_check);
#endif
#if defined(LWS_WITH_SYS_ASYNC_DNS) #if defined(LWS_WITH_SYS_ASYNC_DNS)
lws_async_dns_cancel(wsi); lws_async_dns_cancel(wsi);
#endif #endif

View file

@ -665,6 +665,9 @@ struct lws {
lws_sorted_usec_list_t sul_hrtimer; lws_sorted_usec_list_t sul_hrtimer;
lws_sorted_usec_list_t sul_validity; lws_sorted_usec_list_t sul_validity;
lws_sorted_usec_list_t sul_connect_timeout; lws_sorted_usec_list_t sul_connect_timeout;
#if defined(WIN32)
lws_sorted_usec_list_t win32_sul_connect_async_check;
#endif
struct lws_dll2 dll_buflist; /* guys with pending rxflow */ struct lws_dll2 dll_buflist; /* guys with pending rxflow */
struct lws_dll2 same_vh_protocol; struct lws_dll2 same_vh_protocol;

View file

@ -1059,12 +1059,20 @@ lws_create_context(const struct lws_context_creation_info *info)
} }
#endif #endif
context->timeout_secs = 15;
#if defined(LWS_WITH_NETWORK) #if defined(LWS_WITH_NETWORK)
#if defined(WIN32)
if (!info->win32_connect_check_interval_usec)
context->win32_connect_check_interval_usec = 1000;
else
context->win32_connect_check_interval_usec =
info->win32_connect_check_interval_usec;
#endif
if (info->timeout_secs) if (info->timeout_secs)
context->timeout_secs = info->timeout_secs; context->timeout_secs = info->timeout_secs;
else #endif /* WITH_NETWORK */
#endif
context->timeout_secs = 15;
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2) #if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
if (info->max_http_header_data) if (info->max_http_header_data)

View file

@ -737,6 +737,9 @@ struct lws_context {
int fd_random; int fd_random;
int count_cgi_spawned; int count_cgi_spawned;
#endif #endif
#if defined(WIN32)
unsigned int win32_connect_check_interval_usec;
#endif
unsigned int fd_limit_per_thread; unsigned int fd_limit_per_thread;
unsigned int timeout_secs; unsigned int timeout_secs;