From 18df4912f455e0fb09b232a409c5825a44ee8f2c Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 19 Sep 2020 17:13:37 -0500 Subject: [PATCH] ws2_32: Reimplement WSASocketW() on top of NtOpenFile() and IOCTL_AFD_CREATE. Signed-off-by: Zebediah Figura Signed-off-by: Alexandre Julliard --- dlls/ws2_32/socket.c | 115 +++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 49 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 4162549d8b1..1136ec87b95 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -155,6 +155,7 @@ #define USE_WC_PREFIX /* For CMSG_DATA */ #include "iphlpapi.h" #include "ip2string.h" +#include "wine/afd.h" #include "wine/server.h" #include "wine/debug.h" #include "wine/exception.h" @@ -7593,8 +7594,15 @@ SOCKET WINAPI WSASocketA(int af, int type, int protocol, */ SOCKET WINAPI WSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFOW lpProtocolInfo, - GROUP g, DWORD dwFlags) + GROUP g, DWORD flags) { + static const WCHAR afdW[] = {'\\','D','e','v','i','c','e','\\','A','f','d',0}; + struct afd_create_params create_params; + OBJECT_ATTRIBUTES attr; + UNICODE_STRING string; + IO_STATUS_BLOCK io; + NTSTATUS status; + HANDLE handle; SOCKET ret; DWORD err; int unixaf, unixtype, ipxptype = -1; @@ -7605,7 +7613,7 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol, */ TRACE("af=%d type=%d protocol=%d protocol_info=%p group=%d flags=0x%x\n", - af, type, protocol, lpProtocolInfo, g, dwFlags ); + af, type, protocol, lpProtocolInfo, g, flags ); if (!num_startup) { @@ -7706,62 +7714,71 @@ SOCKET WINAPI WSASocketW(int af, int type, int protocol, goto done; } - SERVER_START_REQ( create_socket ) + RtlInitUnicodeString(&string, afdW); + InitializeObjectAttributes(&attr, &string, (flags & WSA_FLAG_NO_HANDLE_INHERIT) ? 0 : OBJ_INHERIT, NULL, NULL); + if ((status = NtOpenFile(&handle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, &attr, &io, 0, 0))) { - req->family = unixaf; - req->type = unixtype; - req->protocol = protocol; - req->access = GENERIC_READ|GENERIC_WRITE|SYNCHRONIZE; - req->attributes = (dwFlags & WSA_FLAG_NO_HANDLE_INHERIT) ? 0 : OBJ_INHERIT; - req->flags = dwFlags & ~WSA_FLAG_NO_HANDLE_INHERIT; - err = NtStatusToWSAError( wine_server_call( req ) ); - ret = HANDLE2SOCKET( wine_server_ptr_handle( reply->handle )); + WARN("Failed to create socket, status %#x.\n", status); + WSASetLastError(NtStatusToWSAError(status)); + return INVALID_SOCKET; } - SERVER_END_REQ; - if (ret) - { - TRACE("\tcreated %04lx\n", ret ); - if (ipxptype > 0) - set_ipx_packettype(ret, ipxptype); - if (unixaf == AF_INET || unixaf == AF_INET6) + create_params.family = unixaf; + create_params.type = unixtype; + create_params.protocol = protocol; + create_params.flags = flags & ~WSA_FLAG_NO_HANDLE_INHERIT; + if ((status = NtDeviceIoControlFile(handle, NULL, NULL, NULL, &io, + IOCTL_AFD_CREATE, &create_params, sizeof(create_params), NULL, 0))) + { + WARN("Failed to initialize socket, status %#x.\n", status); + err = NtStatusToWSAError(status); + if (err == WSAEACCES) /* raw socket denied */ { - /* ensure IP_DONTFRAGMENT is disabled for SOCK_DGRAM and SOCK_RAW, enabled for SOCK_STREAM */ - if (unixtype == SOCK_DGRAM || unixtype == SOCK_RAW) /* in Linux the global default can be enabled */ - set_dont_fragment(ret, unixaf == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, FALSE); - else if (unixtype == SOCK_STREAM) - set_dont_fragment(ret, unixaf == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, TRUE); + if (type == SOCK_RAW) + ERR_(winediag)("Failed to create a socket of type SOCK_RAW, this requires special permissions.\n"); + else + ERR_(winediag)("Failed to create socket, this requires special permissions.\n"); } + WSASetLastError(err); + NtClose(handle); + return INVALID_SOCKET; + } + + ret = HANDLE2SOCKET(handle); + TRACE("\tcreated %04lx\n", ret ); + + if (ipxptype > 0) + set_ipx_packettype(ret, ipxptype); + + if (unixaf == AF_INET || unixaf == AF_INET6) + { + /* ensure IP_DONTFRAGMENT is disabled for SOCK_DGRAM and SOCK_RAW, enabled for SOCK_STREAM */ + if (unixtype == SOCK_DGRAM || unixtype == SOCK_RAW) /* in Linux the global default can be enabled */ + set_dont_fragment(ret, unixaf == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, FALSE); + else if (unixtype == SOCK_STREAM) + set_dont_fragment(ret, unixaf == AF_INET6 ? IPPROTO_IPV6 : IPPROTO_IP, TRUE); + } #ifdef IPV6_V6ONLY - if (unixaf == AF_INET6) - { - int fd = get_sock_fd(ret, 0, NULL); - if (fd != -1) - { - /* IPV6_V6ONLY is set by default on Windows */ - int enable = 1; - if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable))) - WARN("\tsetting IPV6_V6ONLY failed - errno = %i\n", errno); - release_sock_fd(ret, fd); - } - } -#endif - if (!socket_list_add(ret)) - { - CloseHandle(SOCKET2HANDLE(ret)); - return INVALID_SOCKET; - } - return ret; - } - - if (err == WSAEACCES) /* raw socket denied */ + if (unixaf == AF_INET6) { - if (type == SOCK_RAW) - ERR_(winediag)("Failed to create a socket of type SOCK_RAW, this requires special permissions.\n"); - else - ERR_(winediag)("Failed to create socket, this requires special permissions.\n"); + int fd = get_sock_fd(ret, 0, NULL); + if (fd != -1) + { + /* IPV6_V6ONLY is set by default on Windows */ + int enable = 1; + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &enable, sizeof(enable))) + WARN("\tsetting IPV6_V6ONLY failed - errno = %i\n", errno); + release_sock_fd(ret, fd); + } } +#endif + if (!socket_list_add(ret)) + { + CloseHandle(handle); + return INVALID_SOCKET; + } + return ret; done: WARN("\t\tfailed, error %d!\n", err);