From 404d3787b50d7cb8a86c2fade1c39748f5899e80 Mon Sep 17 00:00:00 2001 From: reito Date: Wed, 11 Dec 2024 00:05:01 +0800 Subject: [PATCH] src: acceptex/connectex get once at init, code review 2 --- include/uv/win.h | 3 + src/win/internal.h | 7 +- src/win/pipe.c | 163 ++++++++++++++++++++++++--------------------- src/win/tcp.c | 63 +++++++----------- src/win/winsock.c | 25 +++---- 5 files changed, 124 insertions(+), 137 deletions(-) diff --git a/include/uv/win.h b/include/uv/win.h index 31fc1399..7b285270 100644 --- a/include/uv/win.h +++ b/include/uv/win.h @@ -376,6 +376,9 @@ typedef struct { ULONG_PTR result; /* overlapped.Internal is reused to hold the result */\ HANDLE pipeHandle; \ DWORD duplex_flags; \ + /* When using unix domain socket, ConnectEx IOCP result will overwrite + * result + pipeHandle, to keep the ABI, reusing the name field. + */ \ union { \ WCHAR* name; \ SOCKET uds_socket; \ diff --git a/src/win/internal.h b/src/win/internal.h index be408af6..5755a145 100644 --- a/src/win/internal.h +++ b/src/win/internal.h @@ -298,9 +298,6 @@ void uv__winsock_init(void); int uv__ntstatus_to_winsock_error(NTSTATUS status); -BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target); -BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target); - int WSAAPI uv__wsarecv_workaround(SOCKET socket, WSABUF* buffers, DWORD buffer_count, DWORD* bytes, DWORD* flags, WSAOVERLAPPED *overlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine); @@ -320,6 +317,10 @@ extern int uv_tcp_non_ifs_lsp_ipv6; extern struct sockaddr_in uv_addr_ip4_any_; extern struct sockaddr_in6 uv_addr_ip6_any_; +/* WSA function pointers */ +extern LPFN_ACCEPTEX uv_wsa_acceptex; +extern LPFN_CONNECTEX uv_wsa_connectex; + /* * Wake all loops with fake message */ diff --git a/src/win/pipe.c b/src/win/pipe.c index 8ac901ca..286f64b8 100644 --- a/src/win/pipe.c +++ b/src/win/pipe.c @@ -37,9 +37,6 @@ #if defined(_WIN32) && !defined(__MINGW32__) && !defined(__MINGW64__) #define UV__ENABLE_WIN_UDS_PIPE -#endif - -#if defined(UV__ENABLE_WIN_UDS_PIPE) #include #endif @@ -108,16 +105,12 @@ static void eof_timer_close_cb(uv_handle_t* handle); static int uv__should_use_uds_pipe(const char *s) { #if defined(UV__ENABLE_WIN_UDS_PIPE) - /* Tell if the name is started by the named pipe prefix */ - if (strstr(s, pipe_prefix) == s) { - return 0; - } - - return 1; -#endif - - /* Disable uds on mingw */ + /* Tell if the name is not started by the named pipe prefix */ + return strstr(s, pipe_prefix) != s; +#else + /* Disable this on mingw */ return 0; +#endif } @@ -606,6 +599,8 @@ static int pipe_alloc_accept_unix_domain_socket(uv_loop_t* loop, uv_pipe_t* hand struct sockaddr_un addr = {0}; addr.sun_family = AF_UNIX; + /* `name` is guaranteed to be a null terminated string + * length (with '\0') <= UNIX_PATH_MAX */ strcpy(addr.sun_path, name); int ret = bind(server_fd, (const struct sockaddr*)&addr, sizeof(struct sockaddr_un)); @@ -795,6 +790,11 @@ void uv__pipe_endgame(uv_loop_t* loop, uv_pipe_t* handle) { void uv_pipe_pending_instances(uv_pipe_t* handle, int count) { if (handle->flags & UV_HANDLE_BOUND) return; + + /* Unix domain socket only use 1 pending instance. */ + if (handle->flags & UV_HANDLE_WIN_UDS_PIPE) + return; + handle->pipe.serv.pending_instances = count; handle->flags |= UV_HANDLE_PIPESERVER; } @@ -833,14 +833,20 @@ int uv_pipe_bind2(uv_pipe_t* handle, int use_uds_pipe = uv__should_use_uds_pipe(name); +#if !defined(UV__ENABLE_WIN_UDS_PIPE) + if (use_uds_pipe) { + return UV_ENOSYS; + } +#endif + #if defined(UV__ENABLE_WIN_UDS_PIPE) if (use_uds_pipe) { if (flags & UV_PIPE_NO_TRUNCATE) - if (namelen > UNIX_PATH_MAX) + if (namelen >= UNIX_PATH_MAX) return UV_EINVAL; - if (namelen > UNIX_PATH_MAX) - namelen = UNIX_PATH_MAX; + if (namelen >= UNIX_PATH_MAX) + namelen = UNIX_PATH_MAX - 1; } #endif @@ -902,40 +908,43 @@ int uv_pipe_bind2(uv_pipe_t* handle, goto error; } +#if defined(UV__ENABLE_WIN_UDS_PIPE) if (use_uds_pipe) { /* * Prefix not match named pipe, use unix domain socket. */ -#if defined(UV__ENABLE_WIN_UDS_PIPE) handle->flags |= UV_HANDLE_WIN_UDS_PIPE; int uds_err = pipe_alloc_accept_unix_domain_socket( - loop, handle, &handle->pipe.serv.accept_reqs[0], name, TRUE); + loop, handle, &handle->pipe.serv.accept_reqs[0], handle->pathname, TRUE); if (uds_err) { err = uv_translate_sys_error(uds_err); goto error; } + + goto uds_pipe; + } #endif - } else { - /* - * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. - * If this fails then there's already a pipe server for the given pipe name. - */ - if (!pipe_alloc_accept_named_pipe(loop, - handle, - &handle->pipe.serv.accept_reqs[0], - TRUE)) { - err = GetLastError(); - if (err == ERROR_ACCESS_DENIED) { - err = UV_EADDRINUSE; - } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { - err = UV_EACCES; - } else { - err = uv_translate_sys_error(err); - } - goto error; + + /* + * Attempt to create the first pipe with FILE_FLAG_FIRST_PIPE_INSTANCE. + * If this fails then there's already a pipe server for the given pipe name. + */ + if (!pipe_alloc_accept_named_pipe(loop, + handle, + &handle->pipe.serv.accept_reqs[0], + TRUE)) { + err = GetLastError(); + if (err == ERROR_ACCESS_DENIED) { + err = UV_EADDRINUSE; + } else if (err == ERROR_PATH_NOT_FOUND || err == ERROR_INVALID_NAME) { + err = UV_EACCES; + } else { + err = uv_translate_sys_error(err); } + goto error; } +uds_pipe: handle->pipe.serv.pending_accepts = NULL; handle->flags |= UV_HANDLE_PIPESERVER; handle->flags |= UV_HANDLE_BOUND; @@ -1054,14 +1063,22 @@ int uv_pipe_connect2(uv_connect_t* req, int use_uds_pipe = uv__should_use_uds_pipe(name); +#if !defined(UV__ENABLE_WIN_UDS_PIPE) + if (use_uds_pipe) { + return UV_ENOSYS; + } +#endif + #if defined(UV__ENABLE_WIN_UDS_PIPE) if (use_uds_pipe) { + /* https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/ */ + /* a null-terminated UTF-8 file system path */ if (flags & UV_PIPE_NO_TRUNCATE) - if (namelen > UNIX_PATH_MAX) + if (namelen >= UNIX_PATH_MAX) return UV_EINVAL; - if (namelen > UNIX_PATH_MAX) - namelen = UNIX_PATH_MAX; + if (namelen >= UNIX_PATH_MAX) + namelen = UNIX_PATH_MAX - 1; } #endif @@ -1109,12 +1126,6 @@ int uv_pipe_connect2(uv_connect_t* req, * of the pipe is not matched. */ - LPFN_CONNECTEX func_connectex = NULL; - if (!uv__get_connectex_function((SOCKET)handle->handle, &func_connectex)) { - err = WSAEAFNOSUPPORT; - goto error; - } - SOCKET client_fd = socket(AF_UNIX, SOCK_STREAM, IPPROTO_IP); if (client_fd == INVALID_SOCKET) { err = WSAGetLastError(); @@ -1133,24 +1144,27 @@ int uv_pipe_connect2(uv_connect_t* req, struct sockaddr_un addr2 = {0}; addr2.sun_family = AF_UNIX; - strcpy(addr2.sun_path, name); + memcpy(addr2.sun_path, name, namelen); + addr2.sun_path[namelen] = '\0'; /* Associate it with IOCP so we can get events. */ if (CreateIoCompletionPort((HANDLE) client_fd, loop->iocp, (ULONG_PTR) handle, 0) == NULL) { - uv_fatal_error(GetLastError(), "CreateIoCompletionPort"); + closesocket(client_fd); + err = GetLastError(); + goto error; } memset(&req->u.io.overlapped, 0, sizeof(req->u.io.overlapped)); - ret = func_connectex(client_fd, - (const struct sockaddr*)&addr2, - sizeof(struct sockaddr_un), - NULL, - 0, - NULL, - &req->u.io.overlapped); + ret = uv_wsa_connectex(client_fd, + (const struct sockaddr*)&addr2, + sizeof(struct sockaddr_un), + NULL, + 0, + NULL, + &req->u.io.overlapped); if (!ret) { err = WSAGetLastError(); @@ -1362,17 +1376,9 @@ static void uv__pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, uv_pipe_accept_t* req, BOOL firstInstance) { assert(handle->flags & UV_HANDLE_LISTENING); - LPFN_ACCEPTEX func_acceptex = NULL; - if (!uv__get_acceptex_function((SOCKET)handle->handle, &func_acceptex)) { - SET_REQ_ERROR(req, WSAEAFNOSUPPORT); - uv__insert_pending_req(loop, (uv_req_t*)req); - handle->reqs_pending++; - return; - } - if (!firstInstance) { - if (handle->flags & UV_HANDLE_WIN_UDS_PIPE) { #if defined(UV__ENABLE_WIN_UDS_PIPE) + if (handle->flags & UV_HANDLE_WIN_UDS_PIPE) { int uds_err = pipe_alloc_accept_unix_domain_socket( loop, handle, req, handle->pathname, FALSE); if (uds_err) { @@ -1381,17 +1387,20 @@ static void uv__pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, handle->reqs_pending++; return; } + + goto uds_pipe; + } #endif - } else { - if (!pipe_alloc_accept_named_pipe(loop, handle, req, FALSE)) { - SET_REQ_ERROR(req, GetLastError()); - uv__insert_pending_req(loop, (uv_req_t*) req); - handle->reqs_pending++; - return; - } + + if (!pipe_alloc_accept_named_pipe(loop, handle, req, FALSE)) { + SET_REQ_ERROR(req, GetLastError()); + uv__insert_pending_req(loop, (uv_req_t*) req); + handle->reqs_pending++; + return; } } +uds_pipe: assert(req->pipeHandle != INVALID_HANDLE_VALUE); /* Prepare the overlapped structure. */ @@ -1401,14 +1410,14 @@ static void uv__pipe_queue_accept(uv_loop_t* loop, uv_pipe_t* handle, DWORD bytes_received; CHAR accept_buf[2 * (sizeof(SOCKADDR_STORAGE) + 16)]; - if (!func_acceptex((SOCKET)handle->handle, - (SOCKET)req->pipeHandle, - accept_buf, - 0, - sizeof(SOCKADDR_STORAGE) + 16, - sizeof(SOCKADDR_STORAGE) + 16, - &bytes_received, - &req->u.io.overlapped)) { + if (!uv_wsa_acceptex((SOCKET)handle->handle, + (SOCKET)req->pipeHandle, + accept_buf, + 0, + sizeof(SOCKADDR_STORAGE) + 16, + sizeof(SOCKADDR_STORAGE) + 16, + &bytes_received, + &req->u.io.overlapped)) { int wsa_err = WSAGetLastError(); if (wsa_err != ERROR_IO_PENDING) { closesocket((SOCKET) req->pipeHandle); diff --git a/src/win/tcp.c b/src/win/tcp.c index c452c12e..697f7505 100644 --- a/src/win/tcp.c +++ b/src/win/tcp.c @@ -432,14 +432,14 @@ static void uv__tcp_queue_accept(uv_tcp_t* handle, uv_tcp_accept_t* req) { req->u.io.overlapped.hEvent = (HANDLE) ((ULONG_PTR) req->event_handle | 1); } - success = handle->tcp.serv.func_acceptex(handle->socket, - accept_socket, - (void*)req->accept_buffer, - 0, - sizeof(struct sockaddr_storage), - sizeof(struct sockaddr_storage), - &bytes, - &req->u.io.overlapped); + success = uv_wsa_acceptex(handle->socket, + accept_socket, + (void*)req->accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &req->u.io.overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ @@ -576,12 +576,6 @@ int uv__tcp_listen(uv_tcp_t* handle, int backlog, uv_connection_cb cb) { return handle->delayed_error; } - if (!handle->tcp.serv.func_acceptex) { - if (!uv__get_acceptex_function(handle->socket, &handle->tcp.serv.func_acceptex)) { - return WSAEAFNOSUPPORT; - } - } - /* If this flag is set, we already made this listen call in xfer. */ if (!(handle->flags & UV_HANDLE_SHARED_TCP_SOCKET) && listen(handle->socket, backlog) == SOCKET_ERROR) { @@ -799,12 +793,6 @@ static int uv__tcp_try_connect(uv_connect_t* req, goto out; } - if (!handle->tcp.conn.func_connectex) { - if (!uv__get_connectex_function(handle->socket, &handle->tcp.conn.func_connectex)) { - return WSAEAFNOSUPPORT; - } - } - /* This makes connect() fail instantly if the target port on the localhost * is not reachable, instead of waiting for 2s. We do not care if this fails. * This only works on Windows version 10.0.16299 and later. @@ -839,13 +827,13 @@ out: return 0; } - success = handle->tcp.conn.func_connectex(handle->socket, - (const struct sockaddr*) &converted, - addrlen, - NULL, - 0, - &bytes, - &req->u.io.overlapped); + success = uv_wsa_connectex(handle->socket, + (const struct sockaddr*)&converted, + addrlen, + NULL, + 0, + &bytes, + &req->u.io.overlapped); if (UV_SUCCEEDED_WITHOUT_IOCP(success)) { /* Process the req without IOCP. */ @@ -1569,7 +1557,6 @@ int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int f SOCKET client0 = INVALID_SOCKET; SOCKET client1 = INVALID_SOCKET; SOCKADDR_IN name; - LPFN_ACCEPTEX func_acceptex; WSAOVERLAPPED overlap; char accept_buffer[sizeof(struct sockaddr_storage) * 2 + 32]; int namelen; @@ -1612,19 +1599,15 @@ int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int f goto wsaerror; if (!SetHandleInformation((HANDLE) client1, HANDLE_FLAG_INHERIT, 0)) goto error; - if (!uv__get_acceptex_function(server, &func_acceptex)) { - err = WSAEAFNOSUPPORT; - goto cleanup; - } memset(&overlap, 0, sizeof(overlap)); - if (!func_acceptex(server, - client1, - accept_buffer, - 0, - sizeof(struct sockaddr_storage), - sizeof(struct sockaddr_storage), - &bytes, - &overlap)) { + if (!uv_wsa_acceptex(server, + client1, + accept_buffer, + 0, + sizeof(struct sockaddr_storage), + sizeof(struct sockaddr_storage), + &bytes, + &overlap)) { err = WSAGetLastError(); if (err == ERROR_IO_PENDING) { /* Result should complete immediately, since we already called connect, diff --git a/src/win/winsock.c b/src/win/winsock.c index 1477f2a6..4491acfc 100644 --- a/src/win/winsock.c +++ b/src/win/winsock.c @@ -35,8 +35,8 @@ struct sockaddr_in uv_addr_ip4_any_; struct sockaddr_in6 uv_addr_ip6_any_; /* WSA function pointers */ -static LPFN_ACCEPTEX uv_wsa_acceptex = NULL; -static LPFN_CONNECTEX uv_wsa_connectex = NULL; +LPFN_ACCEPTEX uv_wsa_acceptex = NULL; +LPFN_CONNECTEX uv_wsa_connectex = NULL; /* @@ -66,18 +66,6 @@ static BOOL uv__get_extension_function(SOCKET socket, GUID guid, } -BOOL uv__get_acceptex_function(SOCKET socket, LPFN_ACCEPTEX* target) { - *target = uv_wsa_acceptex; - return uv_wsa_acceptex != NULL; -} - - -BOOL uv__get_connectex_function(SOCKET socket, LPFN_CONNECTEX* target) { - *target = uv_wsa_connectex; - return uv_wsa_connectex != NULL; -} - - void uv__winsock_init(void) { WSADATA wsa_data; int errorno; @@ -141,9 +129,12 @@ void uv__winsock_init(void) { const GUID wsaid_acceptex = WSAID_ACCEPTEX; const GUID wsaid_connectex = WSAID_CONNECTEX; - /* If anyone failed, will return false when get them later. */ - uv__get_extension_function(dummy, wsaid_acceptex, (void**)uv_wsa_acceptex); - uv__get_extension_function(dummy, wsaid_connectex, (void**)uv_wsa_connectex); + if (!uv__get_extension_function( + dummy, wsaid_acceptex, (void**)uv_wsa_acceptex) || + !uv__get_extension_function( + dummy, wsaid_connectex, (void**)uv_wsa_connectex)) { + uv_fatal_error(WSAGetLastError(), "WSAIoctl"); + } closesocket(dummy); }