On Windows it seems sending to port 0 does nothing and does not error. Presently sendmsg errors with EINVAL. This works around it, by checking if it's port 0 then skipping the data.
-- v5: ntdll: Do not send data to port 0. tests: Added to check if sending port 0 succeeds
From: Jason Beetham beefers331@gmail.com
--- dlls/ws2_32/tests/sock.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/ws2_32/tests/sock.c b/dlls/ws2_32/tests/sock.c index d29e1c768dc..ae8bb15f074 100644 --- a/dlls/ws2_32/tests/sock.c +++ b/dlls/ws2_32/tests/sock.c @@ -13659,6 +13659,31 @@ static void test_connect_udp(void) closesocket(client); }
+static void test_WSASendto_port0(void) +{ + SOCKET s; + struct sockaddr_in addr; + char buf[12] = "hello world"; + WSABUF data_buf; + DWORD bytesSent = 0; + int ret; + + addr.sin_family = AF_INET; + addr.sin_port = htons(0); + addr.sin_addr.s_addr = inet_addr("127.0.0.1"); + data_buf.len = sizeof(buf); + data_buf.buf = buf; + + s = socket(AF_INET, SOCK_DGRAM, 0); + ok(s != INVALID_SOCKET, "failed to create socket, error %u\n", WSAGetLastError()); + + ret = WSASendTo(s, &data_buf, 1, &bytesSent, 0, (struct sockaddr *)&addr, sizeof(addr), NULL, NULL); + todo_wine ok(!ret, "got error %u\n", WSAGetLastError()); + todo_wine ok(bytesSent == sizeof(buf), "Failed to send full data(%lu) only sent(%lu)\n", (unsigned long) sizeof(buf), (unsigned long) bytesSent); + closesocket(s); +} + + START_TEST( sock ) { int i; @@ -13740,6 +13765,7 @@ START_TEST( sock ) test_tcp_reset(); test_icmp(); test_connect_udp(); + test_WSASendto_port0();
/* this is an io heavy test, do it at the end so the kernel doesn't start dropping packets */ test_send();
From: Jason Beetham beefers331@gmail.com
--- On Windows it seems sending to port 0 does nothing and does not error. Presently sendmsg errors with EINVAL. This works around it, by checking if it's port 0 then skipping the data. --- dlls/ntdll/unix/socket.c | 56 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index ac351a17a70..d3af99be693 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -979,6 +979,41 @@ NTSTATUS sock_read( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, return sock_recv( handle, event, apc, apc_user, io, fd, async, 1 ); }
+static int is_port0( const union unix_sockaddr *uaddr) +{ + switch (uaddr->addr.sa_family) + { + case AF_INET: + { + return uaddr->in.sin_port == 0; + } + + case AF_INET6: + { + return uaddr->in6.sin6_port == 0; + } + + #ifdef HAS_IPX + case AF_IPX: + { + return uaddr->ipx.sipx_port == 0; + } + #endif + + #ifdef HAS_IRDA + case AF_IRDA: + { + return FALSE; + } + #endif + + case AF_UNSPEC: + return FALSE; + + default: + return FALSE; + } +}
static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) { @@ -1018,6 +1053,7 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) hdr.msg_iov = async->iov + async->iov_cursor; hdr.msg_iovlen = async->count - async->iov_cursor;
+ while ((ret = sendmsg( fd, &hdr, async->unix_flags )) == -1) { if (errno == EISCONN) @@ -1027,8 +1063,24 @@ static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) } else if (errno != EINTR) { - if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) ); - return sock_errno_to_status( errno ); + if(errno == EINVAL && is_port0(&unix_addr)){ + + /* + * Some Windows applications(Spellforce 3 is known to) send to port 0. + * This causes 'sendmsg' to throw a EINVAL error on Windows this does nothing but consume the data. + * This workaround says we successfully sent data even though we didnt send anything. + * Matching the Windows behaviour, making the program work(in theory). + */ + ret = 0; + for(ssize_t i = 0; i < hdr.msg_iovlen; i++){ + ret += hdr.msg_iov[i].iov_len; + } + WARN("Attempting to send to port 0, skipping over %zd bytes\n", ret); + break; + }else{ + if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) ); + return sock_errno_to_status( errno ); + } } }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=129123
Your paranoid android.
=== debian11 (32 bit report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit ar:MA report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit de report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit fr report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit he:IL report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit hi:IN report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit ja:JP report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11 (32 bit zh:CN report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11b (32 bit WoW report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)
=== debian11b (64 bit WoW report) ===
ws2_32: sock.c:13681: Test succeeded inside todo block: got error 0 sock.c:13682: Test succeeded inside todo block: Failed to send full data(12) only sent(12)