@@ -97,9 +97,40 @@ lws_quic_prefaddr_swap_socket(struct lws *nwsi, const lws_sockaddr46 *to_sa46)
9797 lws_pt_lock (pt , __func__ );
9898 if (lws_socket_is_valid (nwsi -> desc .sockfd ))
9999 __remove_wsi_socket_from_fds (nwsi );
100- if (lws_socket_is_valid (nwsi -> desc .sockfd ))
101- compatible_close (nwsi -> desc .sockfd );
100+
101+ /*
102+ * The fd number itself is changing: the event-loop handle that was
103+ * bound to the old fd at accept time cannot be repointed to the new
104+ * fd. For libuv, leaving it in place leaks libuv's per-fd watcher
105+ * entry for the old fd (which was already closed below); when the
106+ * kernel later recycles that fd number, uv_poll_init_socket() trips
107+ * UV_EEXIST on the unrelated new socket. Tear down the old handle
108+ * through the event-lib ops (which also closes the old kernel fd),
109+ * then build a fresh handle for the new fd, exactly as the redirect
110+ * / fd-handoff paths do.
111+ */
112+ #if defined(LWS_WITH_EVENT_LIBS )
113+ if (cx -> event_loop_ops -> close_handle_manually )
114+ cx -> event_loop_ops -> close_handle_manually (nwsi );
115+ else
116+ #endif
117+ {
118+ if (lws_socket_is_valid (nwsi -> desc .sockfd ))
119+ compatible_close (nwsi -> desc .sockfd );
120+ nwsi -> desc .sockfd = LWS_SOCK_INVALID ;
121+ }
122+
102123 nwsi -> desc = new_sock ;
124+
125+ #if defined(LWS_WITH_EVENT_LIBS )
126+ if (cx -> event_loop_ops -> sock_accept )
127+ if (cx -> event_loop_ops -> sock_accept (nwsi )) {
128+ lws_pt_unlock (pt );
129+ compatible_close (n_fd );
130+ return 1 ;
131+ }
132+ #endif
133+
103134 if (__insert_wsi_socket_into_fds (cx , nwsi )) {
104135 lws_pt_unlock (pt );
105136 compatible_close (n_fd );
0 commit comments