Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/ws2_32/socket.c | 466 ++++++--------------------------------- dlls/ws2_32/tests/sock.c | 18 +- 2 files changed, 72 insertions(+), 412 deletions(-)
diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 3632397ef3d..620226d7296 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -197,8 +197,6 @@ static struct interface_filter generic_interface_filter = { }; #endif /* LINUX_BOUND_IF */
-extern ssize_t CDECL __wine_locked_recvmsg( int fd, struct msghdr *hdr, int flags ); - /* * The actual definition of WSASendTo, wrapped in a different function name * so that internal calls from ws2_32 itself will not trigger programs like @@ -210,17 +208,6 @@ static int WS2_sendto( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine );
-/* - * Internal fundamental receive function, essentially WSARecvFrom with an - * additional parameter to support message control headers. - */ -static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, - LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, - struct WS_sockaddr *lpFrom, - LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - LPWSABUF lpControlBuffer ); - DECLARE_CRITICAL_SECTION(cs_if_addr_cache); DECLARE_CRITICAL_SECTION(cs_socket_list);
@@ -715,95 +702,6 @@ static const int ws_poll_map[][2] = { WS_POLLRDBAND, POLLPRI } };
-#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS -#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) -static inline WSACMSGHDR *fill_control_message(int level, int type, WSACMSGHDR *current, ULONG *maxsize, void *data, int len) -{ - ULONG msgsize = sizeof(WSACMSGHDR) + WSA_CMSG_ALIGN(len); - char *ptr = (char *) current + sizeof(WSACMSGHDR); - - /* Make sure there is at least enough room for this entry */ - if (msgsize > *maxsize) - return NULL; - *maxsize -= msgsize; - /* Fill in the entry */ - current->cmsg_len = sizeof(WSACMSGHDR) + len; - current->cmsg_level = level; - current->cmsg_type = type; - memcpy(ptr, data, len); - /* Return the pointer to where next entry should go */ - return (WSACMSGHDR *) (ptr + WSA_CMSG_ALIGN(len)); -} -#endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */ - -static inline int convert_control_headers(struct msghdr *hdr, WSABUF *control) -{ -#if defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) - WSACMSGHDR *cmsg_win = (WSACMSGHDR *) control->buf, *ptr; - ULONG ctlsize = control->len; - struct cmsghdr *cmsg_unix; - - ptr = cmsg_win; - /* Loop over all the headers, converting as appropriate */ - for (cmsg_unix = CMSG_FIRSTHDR(hdr); cmsg_unix != NULL; cmsg_unix = CMSG_NXTHDR(hdr, cmsg_unix)) - { - switch(cmsg_unix->cmsg_level) - { - case IPPROTO_IP: - switch(cmsg_unix->cmsg_type) - { -#if defined(IP_PKTINFO) - case IP_PKTINFO: - { - /* Convert the Unix IP_PKTINFO structure to the Windows version */ - struct in_pktinfo *data_unix = (struct in_pktinfo *) CMSG_DATA(cmsg_unix); - struct WS_in_pktinfo data_win; - - memcpy(&data_win.ipi_addr,&data_unix->ipi_addr.s_addr,4); /* 4 bytes = 32 address bits */ - data_win.ipi_ifindex = data_unix->ipi_ifindex; - ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize, - (void*)&data_win, sizeof(data_win)); - if (!ptr) goto error; - } break; -#elif defined(IP_RECVDSTADDR) - case IP_RECVDSTADDR: - { - struct in_addr *addr_unix = (struct in_addr *) CMSG_DATA(cmsg_unix); - struct WS_in_pktinfo data_win; - - memcpy(&data_win.ipi_addr, &addr_unix->s_addr, 4); /* 4 bytes = 32 address bits */ - data_win.ipi_ifindex = 0; /* FIXME */ - ptr = fill_control_message(WS_IPPROTO_IP, WS_IP_PKTINFO, ptr, &ctlsize, - (void*)&data_win, sizeof(data_win)); - if (!ptr) goto error; - } break; -#endif /* IP_PKTINFO */ - default: - FIXME("Unhandled IPPROTO_IP message header type %d\n", cmsg_unix->cmsg_type); - break; - } - break; - default: - FIXME("Unhandled message header level %d\n", cmsg_unix->cmsg_level); - break; - } - } - - /* Set the length of the returned control headers */ - control->len = (char*)ptr - (char*)cmsg_win; - return 1; -error: - control->len = 0; - return 0; -#else /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */ - control->len = 0; - return 1; -#endif /* defined(IP_PKTINFO) || defined(IP_RECVDSTADDR) */ -} -#endif /* HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS */ - -/* ----------------------------------- error handling */ - static NTSTATUS sock_get_ntstatus( int err ) { switch ( err ) @@ -2021,127 +1919,6 @@ static void WINAPI ws2_async_apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserv release_async_io( &wsa->io ); }
-/*********************************************************************** - * WS2_recv (INTERNAL) - * - * Workhorse for both synchronous and asynchronous recv() operations. - */ -static int WS2_recv( int fd, struct ws2_async *wsa, int flags ) -{ -#ifndef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS - char pktbuf[512]; -#endif - struct msghdr hdr; - union generic_unix_sockaddr unix_sockaddr; - int n; - - hdr.msg_name = NULL; - - if (wsa->addr) - { - hdr.msg_namelen = sizeof(unix_sockaddr); - hdr.msg_name = &unix_sockaddr; - } - else - hdr.msg_namelen = 0; - - hdr.msg_iov = wsa->iovec + wsa->first_iovec; - hdr.msg_iovlen = wsa->n_iovecs - wsa->first_iovec; -#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS - hdr.msg_accrights = NULL; - hdr.msg_accrightslen = 0; -#else - hdr.msg_control = pktbuf; - hdr.msg_controllen = sizeof(pktbuf); - hdr.msg_flags = 0; -#endif - - while ((n = __wine_locked_recvmsg( fd, &hdr, flags )) == -1) - { - if (errno != EINTR) - return -1; - } - -#ifdef HAVE_STRUCT_MSGHDR_MSG_ACCRIGHTS - if (wsa->control) - { - ERR("Message control headers cannot be properly supported on this system.\n"); - wsa->control->len = 0; - } -#else - if (wsa->control && !convert_control_headers(&hdr, wsa->control)) - { - WARN("Application passed insufficient room for control headers.\n"); - *wsa->lpFlags |= WS_MSG_CTRUNC; - errno = EMSGSIZE; - return -1; - } -#endif - - /* if this socket is connected and lpFrom is not NULL, Linux doesn't give us - * msg_name and msg_namelen from recvmsg, but it does set msg_namelen to zero. - * - * quoting linux 2.6 net/ipv4/tcp.c: - * "According to UNIX98, msg_name/msg_namelen are ignored - * on connected socket. I was just happy when found this 8) --ANK" - * - * likewise MSDN says that lpFrom and lpFromlen are ignored for - * connection-oriented sockets, so don't try to update lpFrom. - */ - if (wsa->addr && hdr.msg_namelen) - ws_sockaddr_u2ws( &unix_sockaddr.addr, wsa->addr, wsa->addrlen.ptr ); - - return n; -} - -/*********************************************************************** - * WS2_async_recv (INTERNAL) - * - * Handler for overlapped recv() operations. - */ -static NTSTATUS WS2_async_recv( void *user, IO_STATUS_BLOCK *iosb, NTSTATUS status ) -{ - struct ws2_async *wsa = user; - int result = 0, fd; - - switch (status) - { - case STATUS_ALERTED: - if ((status = wine_server_handle_to_fd( wsa->hSocket, FILE_READ_DATA, &fd, NULL ) )) - break; - - result = WS2_recv( fd, wsa, convert_flags(wsa->flags) ); - close( fd ); - if (result >= 0) - { - status = STATUS_SUCCESS; - _enable_event( wsa->hSocket, (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0 ); - } - else - { - if (errno == EAGAIN) - { - status = STATUS_PENDING; - _enable_event( wsa->hSocket, (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0 ); - } - else - { - result = 0; - status = wsaErrStatus(); - } - } - break; - } - if (status != STATUS_PENDING) - { - iosb->u.Status = status; - iosb->Information = result; - if (!wsa->completion_func) - release_async_io( &wsa->io ); - } - return status; -} - /*********************************************************************** * WS2_send (INTERNAL) * @@ -2663,6 +2440,69 @@ static void WINAPI WS2_GetAcceptExSockaddrs(PVOID buffer, DWORD data_size, DWORD *remote_addr = (struct WS_sockaddr *)(cbuf + sizeof(int)); }
+ +static void WINAPI socket_apc( void *apc_user, IO_STATUS_BLOCK *io, ULONG reserved ) +{ + LPWSAOVERLAPPED_COMPLETION_ROUTINE func = apc_user; + func( NtStatusToWSAError( io->u.Status ), io->Information, (OVERLAPPED *)io, 0 ); +} + +static int WS2_recv_base( SOCKET s, WSABUF *buffers, DWORD buffer_count, DWORD *ret_size, DWORD *flags, + struct WS_sockaddr *addr, int *addr_len, OVERLAPPED *overlapped, + LPWSAOVERLAPPED_COMPLETION_ROUTINE completion, WSABUF *control ) +{ + IO_STATUS_BLOCK iosb, *piosb = &iosb; + struct afd_recvmsg_params params; + PIO_APC_ROUTINE apc = NULL; + HANDLE event = NULL; + void *cvalue = NULL; + NTSTATUS status; + + TRACE( "socket %#lx, buffers %p, buffer_count %u, flags %#x, addr %p, " + "addr_len %d, overlapped %p, completion %p, control %p\n", + s, buffers, buffer_count, *flags, addr, addr_len ? *addr_len : -1, overlapped, completion, control ); + + if (overlapped) + { + piosb = (IO_STATUS_BLOCK *)overlapped; + if (!((ULONG_PTR)overlapped->hEvent & 1)) cvalue = overlapped; + event = overlapped->hEvent; + } + else + { + if (!(event = get_sync_event())) return -1; + } + piosb->u.Status = STATUS_PENDING; + + if (completion) + { + event = NULL; + cvalue = completion; + apc = socket_apc; + } + + params.control = control; + params.addr = addr; + params.addr_len = addr_len; + params.ws_flags = flags; + params.force_async = !!overlapped; + params.count = buffer_count; + params.buffers = buffers; + + status = NtDeviceIoControlFile( (HANDLE)s, event, apc, cvalue, piosb, + IOCTL_AFD_WINE_RECVMSG, ¶ms, sizeof(params), NULL, 0 ); + if (status == STATUS_PENDING && !overlapped) + { + if (WaitForSingleObject( event, INFINITE ) == WAIT_FAILED) + return -1; + status = piosb->u.Status; + } + if (!status && ret_size) *ret_size = piosb->Information; + SetLastError( NtStatusToWSAError( status ) ); + return status ? -1 : 0; +} + + /*********************************************************************** * WSASendMsg */ @@ -5900,186 +5740,6 @@ int WINAPI WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, NULL, NULL, lpOverlapped, lpCompletionRoutine, NULL); }
-static int WS2_recv_base( SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, - LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, - struct WS_sockaddr *lpFrom, - LPINT lpFromlen, LPWSAOVERLAPPED lpOverlapped, - LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine, - LPWSABUF lpControlBuffer ) -{ - unsigned int i, options; - int n, fd, err, overlapped, flags; - struct ws2_async *wsa = NULL, localwsa; - BOOL is_blocking; - DWORD timeout_start = GetTickCount(); - ULONG_PTR cvalue = (lpOverlapped && ((ULONG_PTR)lpOverlapped->hEvent & 1) == 0) ? (ULONG_PTR)lpOverlapped : 0; - - TRACE("socket %04lx, wsabuf %p, nbufs %d, flags %d, from %p, fromlen %d, ovl %p, func %p\n", - s, lpBuffers, dwBufferCount, *lpFlags, lpFrom, - (lpFromlen ? *lpFromlen : -1), - lpOverlapped, lpCompletionRoutine); - - fd = get_sock_fd( s, FILE_READ_DATA, &options ); - TRACE( "fd=%d, options=%x\n", fd, options ); - - if (fd == -1) return SOCKET_ERROR; - - if (*lpFlags & WS_MSG_OOB) - { - /* It's invalid to receive OOB data from an OOBINLINED socket - * as OOB data is turned into normal data. */ - socklen_t len = sizeof(n); - if (!getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*) &n, &len) && n) - { - err = WSAEINVAL; - goto error; - } - } - - overlapped = (lpOverlapped || lpCompletionRoutine) && - !(options & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)); - if (overlapped || dwBufferCount > 1) - { - if (!(wsa = (struct ws2_async *)alloc_async_io( offsetof(struct ws2_async, iovec[dwBufferCount]), - WS2_async_recv ))) - { - err = WSAEFAULT; - goto error; - } - } - else - wsa = &localwsa; - - wsa->hSocket = SOCKET2HANDLE(s); - wsa->flags = *lpFlags; - wsa->lpFlags = lpFlags; - wsa->addr = lpFrom; - wsa->addrlen.ptr = lpFromlen; - wsa->control = lpControlBuffer; - wsa->n_iovecs = dwBufferCount; - wsa->first_iovec = 0; - for (i = 0; i < dwBufferCount; i++) - { - /* check buffer first to trigger write watches */ - if (IsBadWritePtr( lpBuffers[i].buf, lpBuffers[i].len )) - { - err = WSAEFAULT; - goto error; - } - wsa->iovec[i].iov_base = lpBuffers[i].buf; - wsa->iovec[i].iov_len = lpBuffers[i].len; - } - - flags = convert_flags(wsa->flags); - for (;;) - { - n = WS2_recv( fd, wsa, flags ); - if (n == -1) - { - /* Unix-like systems return EINVAL when attempting to read OOB data from - * an empty socket buffer, convert that to a Windows expected return. */ - if ((flags & MSG_OOB) && errno == EINVAL) - errno = EWOULDBLOCK; - - if (errno != EAGAIN) - { - err = wsaErrno(); - goto error; - } - } - else if (lpNumberOfBytesRecvd) *lpNumberOfBytesRecvd = n; - - if (overlapped) - { - IO_STATUS_BLOCK *iosb = lpOverlapped ? (IO_STATUS_BLOCK *)lpOverlapped : &wsa->local_iosb; - - wsa->user_overlapped = lpOverlapped; - wsa->completion_func = lpCompletionRoutine; - release_sock_fd( s, fd ); - - if (n == -1) - { - iosb->u.Status = STATUS_PENDING; - iosb->Information = 0; - - if (wsa->completion_func) - err = register_async( ASYNC_TYPE_READ, wsa->hSocket, &wsa->io, NULL, - ws2_async_apc, wsa, iosb ); - else - err = register_async( ASYNC_TYPE_READ, wsa->hSocket, &wsa->io, lpOverlapped->hEvent, - NULL, (void *)cvalue, iosb ); - - if (err != STATUS_PENDING) HeapFree( GetProcessHeap(), 0, wsa ); - SetLastError(NtStatusToWSAError( err )); - return SOCKET_ERROR; - } - - iosb->u.Status = STATUS_SUCCESS; - iosb->Information = n; - if (!wsa->completion_func) - { - if (cvalue) WS_AddCompletion( s, cvalue, STATUS_SUCCESS, n, FALSE ); - if (lpOverlapped->hEvent) SetEvent( lpOverlapped->hEvent ); - HeapFree( GetProcessHeap(), 0, wsa ); - } - else NtQueueApcThread( GetCurrentThread(), (PNTAPCFUNC)ws2_async_apc, - (ULONG_PTR)wsa, (ULONG_PTR)iosb, 0 ); - _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0); - return 0; - } - - if (n != -1) break; - - if ((err = sock_is_blocking( s, &is_blocking ))) goto error; - - if ( is_blocking ) - { - struct pollfd pfd; - int poll_timeout = -1; - INT64 timeout = get_rcvsnd_timeo(fd, TRUE); - - if (timeout) - { - timeout -= GetTickCount() - timeout_start; - if (timeout < 0) poll_timeout = 0; - else poll_timeout = timeout <= INT_MAX ? timeout : INT_MAX; - } - - pfd.fd = fd; - pfd.events = POLLIN; - if (*lpFlags & WS_MSG_OOB) pfd.events |= POLLPRI; - - if (!poll_timeout || !poll( &pfd, 1, poll_timeout )) - { - err = WSAETIMEDOUT; - /* a timeout is not fatal */ - _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0); - goto error; - } - } - else - { - _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0); - err = WSAEWOULDBLOCK; - goto error; - } - } - - TRACE(" -> %i bytes\n", n); - if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa ); - release_sock_fd( s, fd ); - _enable_event(SOCKET2HANDLE(s), (wsa->flags & WS_MSG_OOB) ? FD_OOB : FD_READ, 0, 0); - SetLastError(ERROR_SUCCESS); - - return 0; - -error: - if (wsa != &localwsa) HeapFree( GetProcessHeap(), 0, wsa ); - release_sock_fd( s, fd ); - WARN(" -> ERROR %d\n", err); - SetLastError( err ); - return SOCKET_ERROR; -}
/*********************************************************************** * WSARecvFrom (WS2_32.69) diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 912bf9ee5d8..6801392be1e 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -1891,14 +1891,14 @@ static void test_ip_pktinfo(void) ok(GetLastError() == ERROR_SUCCESS, "Expected 0, got %d\n", GetLastError()); ok(!WaitForSingleObject(ov.hEvent, 100), "wait failed\n"); ok((NTSTATUS)ov.Internal == STATUS_BUFFER_OVERFLOW, "got status %#x\n", (NTSTATUS)ov.Internal); - todo_wine ok(ov.InternalHigh == sizeof(msg), "got size %Iu\n", ov.InternalHigh); + ok(ov.InternalHigh == sizeof(msg), "got size %Iu\n", ov.InternalHigh); ok(ov.Offset == 0xdead3, "got Offset %Iu\n", ov.Offset); ok(ov.OffsetHigh == 0xdead4, "got OffsetHigh %Iu\n", ov.OffsetHigh); dwFlags = 0xdeadbeef; rc = WSAGetOverlappedResult(s1, &ov, &dwSize, FALSE, &dwFlags); ok(!rc, "expected failure\n"); ok(WSAGetLastError() == WSAEMSGSIZE, "got error %u\n", WSAGetLastError()); - todo_wine ok(dwSize == sizeof(msg), "got size %u\n", dwSize); + ok(dwSize == sizeof(msg), "got size %u\n", dwSize); todo_wine ok(dwFlags == 0xdeadbeef, "got flags %#x\n", dwFlags); ok(hdr.dwFlags == MSG_CTRUNC, "WSARecvMsg() overlapped operation set unexpected flags %d.\n", hdr.dwFlags); @@ -9698,11 +9698,11 @@ static DWORD CALLBACK nonblocking_async_recv_thread(void *arg) wsabuf.len = sizeof(buffer); memset(buffer, 0, sizeof(buffer)); ret = WSARecv(params->client, &wsabuf, 1, NULL, &flags, &overlapped, NULL); - todo_wine_if (!params->event) ok(!ret, "got %d\n", ret); + ok(!ret, "got %d\n", ret); ret = GetOverlappedResult((HANDLE)params->client, &overlapped, &size, FALSE); ok(ret, "got error %u\n", GetLastError()); - todo_wine ok(size == 4, "got size %u\n", size); - todo_wine_if (!params->event) ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size)); + ok(size == 4, "got size %u\n", size); + ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size));
return 0; } @@ -9827,7 +9827,7 @@ static void test_nonblocking_async_recv(void) thread = CreateThread(NULL, 0, nonblocking_async_recv_thread, ¶ms, 0, NULL);
ret = WaitForSingleObject(thread, 200); - todo_wine ok(ret == WAIT_TIMEOUT, "expected timeout\n"); + ok(ret == WAIT_TIMEOUT, "expected timeout\n");
ret = send(server, "data", 4, 0); ok(ret == 4, "got %d\n", ret); @@ -9843,7 +9843,7 @@ static void test_nonblocking_async_recv(void) thread = CreateThread(NULL, 0, nonblocking_async_recv_thread, ¶ms, 0, NULL);
ret = WaitForSingleObject(thread, 200); - todo_wine ok(ret == WAIT_TIMEOUT, "expected timeout\n"); + ok(ret == WAIT_TIMEOUT, "expected timeout\n");
ret = send(server, "data", 4, 0); ok(ret == 4, "got %d\n", ret); @@ -9861,9 +9861,9 @@ static void test_nonblocking_async_recv(void) ret = WSARecv(client, &wsabuf, 1, NULL, &flags, &overlapped, NULL); ok(!ret, "got %d\n", ret); ret = GetOverlappedResult((HANDLE)client, &overlapped, &size, FALSE); - todo_wine ok(ret, "got error %u\n", GetLastError()); + ok(ret, "got error %u\n", GetLastError()); ok(size == 4, "got size %u\n", size); - todo_wine ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size)); + ok(!strcmp(buffer, "data"), "got %s\n", debugstr_an(buffer, size));
closesocket(client); closesocket(server);