From: Zebediah Figura Subject: [PATCH v3 4/5] ws2_32: Reimplement WSASocketW() on top of NtOpenFile() and IOCTL_AFD_CREATE. Message-Id: <20200919221338.1880691-4-z.figura12@gmail.com> Date: Sat, 19 Sep 2020 17:13:37 -0500 In-Reply-To: <20200919221338.1880691-1-z.figura12@gmail.com> References: <20200919221338.1880691-1-z.figura12@gmail.com> Signed-off-by: Zebediah Figura --- dlls/ws2_32/socket.c | 109 +++++++++++++++++++++++++------------------ 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 0ed1af3092a..fa9b46b1722 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" @@ -7590,8 +7591,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; @@ -7602,7 +7610,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) { @@ -7703,62 +7711,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)) + if (unixaf == AF_INET6) + { + int fd = get_sock_fd(ret, 0, NULL); + if (fd != -1) { - CloseHandle(SOCKET2HANDLE(ret)); - return INVALID_SOCKET; + /* 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); } - return ret; } - - if (err == WSAEACCES) /* raw socket denied */ +#endif + if (!socket_list_add(ret)) { - 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"); + CloseHandle(handle); + return INVALID_SOCKET; } + return ret; done: WARN("\t\tfailed, error %d!\n", err); -- 2.28.0