ws2_32: Reimplement WSASocketW() on top of NtOpenFile() and IOCTL_AFD_CREATE.

Signed-off-by: Zebediah Figura <z.figura12@gmail.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2020-09-19 17:13:37 -05:00 committed by Alexandre Julliard
parent 2933448979
commit 18df4912f4
1 changed files with 66 additions and 49 deletions

View File

@ -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);