src: acceptex/connectex get once at init, code review 2
This commit is contained in:
parent
801b2476b8
commit
404d3787b5
@ -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; \
|
||||
|
||||
@ -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
|
||||
*/
|
||||
|
||||
163
src/win/pipe.c
163
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 <afunix.h>
|
||||
#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);
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user