core-net: client: don't fan out parallel connects on foreign event loops#3621
Closed
saghul wants to merge 1 commit into
Closed
core-net: client: don't fan out parallel connects on foreign event loops#3621saghul wants to merge 1 commit into
saghul wants to merge 1 commit into
Conversation
The win32 async connect-completion poller (lws_client_win32_conn_async_check,
scheduled unconditionally on Windows in lws_client_connect_3_connect) re-enters
connect_3 with no specific fd. When it fires while the primary connect is still
in progress and DNS returned more than one address, the "else" branch falls
through and opens an additional *parallel* connect socket on the same wsi
(is_parallel = lws_socket_is_valid(wsi->desc.sockfd)).
Parallel connect sockets are only serviceable on the built-in "poll" core loop,
which polls every fd in pt->fds itself. A foreign event loop (event_lib_custom:
libuv/libev/libevent/glib/sd) tracks one fd per wsi via its io/sock_accept ops
and cannot poll the extra parallel sockets; adopting one corrupts the wsi's
fds-table bookkeeping. Observed on a libuv-based custom event lib on Windows:
__remove_wsi_socket_from_fds() trips
assert(m == LWS_NO_FDS_POS || (m >= 0 && (unsigned int)m < pt->fds_count))
(pollfd.c) because position_in_fds_table is left out of range; in NDEBUG builds
the same out-of-range index is used silently (OOB on pt->fds[]), and the
detached primary TLS socket stalls until SECS_WAITING_FOR_SSL ("Timed out
waiting SSL").
The happy-eyeballs timer is already gated on the "poll" loop where it is
scheduled; the win32 connect-check is scheduled regardless of the loop, so gate
the parallel fan-out itself: only fall through to spawn a parallel socket when
the context's event loop is the built-in "poll" core. Foreign loops fall back to
sequential connect, driven by their own POLLOUT, exactly as before happy
eyeballs.
|
Member
|
Ugh.... I didn't notice that we were in the position the HE races only supported poll()... I'm working on extending HE client ops to work on all the event loops the same. |
Contributor
Author
|
We seem to be :-) I worked around it in txiki.js, but having the support extended and working would be great! Would you like me to close this? |
Member
|
No it's fine to leave it open thanks. |
Contributor
Author
|
I see you fixed it in main, I'll test it shortly! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



The win32 async connect-completion poller (lws_client_win32_conn_async_check,
scheduled unconditionally on Windows in lws_client_connect_3_connect) re-enters
connect_3 with no specific fd. When it fires while the primary connect is still
in progress and DNS returned more than one address, the "else" branch falls
through and opens an additional parallel connect socket on the same wsi
(is_parallel = lws_socket_is_valid(wsi->desc.sockfd)).
Parallel connect sockets are only serviceable on the built-in "poll" core loop,
which polls every fd in pt->fds itself. A foreign event loop (event_lib_custom:
libuv/libev/libevent/glib/sd) tracks one fd per wsi via its io/sock_accept ops
and cannot poll the extra parallel sockets; adopting one corrupts the wsi's
fds-table bookkeeping. Observed on a libuv-based custom event lib on Windows:
__remove_wsi_socket_from_fds() trips
assert(m == LWS_NO_FDS_POS || (m >= 0 && (unsigned int)m < pt->fds_count))
(pollfd.c) because position_in_fds_table is left out of range; in NDEBUG builds
the same out-of-range index is used silently (OOB on pt->fds[]), and the
detached primary TLS socket stalls until SECS_WAITING_FOR_SSL ("Timed out
waiting SSL").
The happy-eyeballs timer is already gated on the "poll" loop where it is
scheduled; the win32 connect-check is scheduled regardless of the loop, so gate
the parallel fan-out itself: only fall through to spawn a parallel socket when
the context's event loop is the built-in "poll" core. Foreign loops fall back to
sequential connect, driven by their own POLLOUT, exactly as before happy
eyeballs.