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
#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 ---^
* This is part of the ABI, don't needlessly break compatibility
*

View file

@ -24,6 +24,30 @@
#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
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;
}
#else
fd_set write_set, except_set;
struct timeval tv;
int ret;
if (!connect(wsi->desc.sockfd, (const struct sockaddr *)&wsi->sa46_peer.sa4,
#if defined(WIN32)
sizeof(struct sockaddr)))
#else
0))
#endif
FD_ZERO(&write_set);
FD_ZERO(&except_set);
FD_SET(wsi->desc.sockfd, &write_set);
FD_SET(wsi->desc.sockfd, &except_set);
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;
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 ||
en == WSAEWOULDBLOCK ||
en == WSAEALREADY) {
lwsl_wsi_debug(wsi, "%s",
lws_errno_describe(en, t16, sizeof(t16)));
if (FD_ISSET(wsi->desc.sockfd, &except_set)) {
/* Failed to connect */
lwsl_wsi_notice(wsi, "connect failed, select exception fd set");
return LCCCR_FAILED;
}
if (!ret) {
lwsl_wsi_debug(wsi, "select timeout");
return LCCCR_CONTINUE;
}
en = LWS_ERRNO;
#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)));
return LCCCR_FAILED;
@ -261,7 +286,14 @@ lws_client_connect_3_connect(struct lws *wsi, const char *ads,
*/
goto conn_good;
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;
default:
if (!real_errno)
real_errno = LWS_ERRNO;
@ -627,13 +659,25 @@ ads_known:
lws_client_conn_wait_timeout,
wsi->a.context->timeout_secs *
LWS_USEC_PER_SEC);
#if defined(WIN32)
/*
* must do specifically a POLLOUT poll to hear
* about the connect completion
* Windows is not properly POSIX, we have to manually schedule a
* 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))
goto try_next_dns_result_fds;
#endif
return wsi;
}
@ -673,8 +717,10 @@ conn_good:
#endif
}
#endif
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_addrinfo_clean(wsi);
@ -745,6 +791,9 @@ try_next_dns_result_closesock:
try_next_dns_result:
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))
goto next_dns_result;

View file

@ -581,6 +581,9 @@ just_kill_connection:
#endif
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)
lws_async_dns_cancel(wsi);
#endif

View file

@ -665,6 +665,9 @@ struct lws {
lws_sorted_usec_list_t sul_hrtimer;
lws_sorted_usec_list_t sul_validity;
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 same_vh_protocol;

View file

@ -1059,12 +1059,20 @@ lws_create_context(const struct lws_context_creation_info *info)
}
#endif
context->timeout_secs = 15;
#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)
context->timeout_secs = info->timeout_secs;
else
#endif
context->timeout_secs = 15;
#endif /* WITH_NETWORK */
#if defined(LWS_ROLE_H1) || defined(LWS_ROLE_H2)
if (info->max_http_header_data)

View file

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