diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 5e27f0af95..ab801ace5c 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -1480,6 +1480,9 @@ @ cdecl wine_server_send_fd(long) @ cdecl __wine_make_process_system() +# Virtual memory +@ cdecl __wine_locked_recvmsg(long ptr long) + # Version @ cdecl wine_get_version() NTDLL_wine_get_version @ cdecl wine_get_build_id() NTDLL_wine_get_build_id diff --git a/dlls/ntdll/virtual.c b/dlls/ntdll/virtual.c index d0d25c7c3c..7bb4eb4787 100644 --- a/dlls/ntdll/virtual.c +++ b/dlls/ntdll/virtual.c @@ -32,6 +32,9 @@ #include #include #include +#ifdef HAVE_SYS_SOCKET_H +# include +#endif #ifdef HAVE_SYS_STAT_H # include #endif @@ -1904,6 +1907,36 @@ ssize_t virtual_locked_pread( int fd, void *addr, size_t size, off_t offset ) } +/*********************************************************************** + * __wine_locked_recvmsg + */ +ssize_t CDECL __wine_locked_recvmsg( int fd, struct msghdr *hdr, int flags ) +{ + sigset_t sigset; + size_t i; + BOOL has_write_watch = FALSE; + int err = EFAULT; + + ssize_t ret = recvmsg( fd, hdr, flags ); + if (ret != -1 || errno != EFAULT) return ret; + + server_enter_uninterrupted_section( &csVirtual, &sigset ); + for (i = 0; i < hdr->msg_iovlen; i++) + if (check_write_access( hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, &has_write_watch )) + break; + if (i == hdr->msg_iovlen) + { + ret = recvmsg( fd, hdr, flags ); + err = errno; + } + if (has_write_watch) + while (i--) update_write_watches( hdr->msg_iov[i].iov_base, hdr->msg_iov[i].iov_len, 0 ); + + server_leave_uninterrupted_section( &csVirtual, &sigset ); + errno = err; + return ret; +} + /*********************************************************************** * virtual_is_valid_code_address diff --git a/dlls/ws2_32/socket.c b/dlls/ws2_32/socket.c index 681f340bc6..79b93339eb 100644 --- a/dlls/ws2_32/socket.c +++ b/dlls/ws2_32/socket.c @@ -241,6 +241,8 @@ 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 @@ -2356,7 +2358,7 @@ static int WS2_recv( int fd, struct ws2_async *wsa, int flags ) hdr.msg_flags = 0; #endif - while ((n = recvmsg(fd, &hdr, flags)) == -1) + while ((n = __wine_locked_recvmsg( fd, &hdr, flags )) == -1) { if (errno != EINTR) return -1; diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index 02f7473215..91305f9f01 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -6962,13 +6962,10 @@ static void test_write_watch(void) send(src, "test message", sizeof("test message"), 0); ret = GetOverlappedResult( (HANDLE)dest, &ov, &bytesReturned, TRUE ); - todo_wine - { ok( ret, "GetOverlappedResult failed %u\n", GetLastError() ); ok( bytesReturned == sizeof("test message"), "wrong size %u\n", bytesReturned ); ok( !memcmp( base, "test ", 5 ), "wrong data %s\n", base ); ok( !memcmp( base + 0x4000, "message", 8 ), "wrong data %s\n", base + 0x4000 ); - } count = 64; ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); @@ -6984,7 +6981,6 @@ static void test_write_watch(void) bufs[1].len = 0x4000; bufs[1].buf = base + 0x2000; ret = WSARecvFrom( dest, bufs, 2, NULL, &flags, &addr, &addr_len, &ov, NULL); - todo_wine ok(ret == SOCKET_ERROR && GetLastError() == ERROR_IO_PENDING, "WSARecv failed - %d error %d\n", ret, GetLastError()); @@ -6992,7 +6988,6 @@ static void test_write_watch(void) ret = pGetWriteWatch( WRITE_WATCH_FLAG_RESET, base, size, results, &count, &pagesize ); ok( !ret, "GetWriteWatch failed %u\n", GetLastError() ); ok( count == 5, "wrong count %lu\n", count ); - todo_wine ok( !base[0], "data set\n" ); send(src, "test message", sizeof("test message"), 0);