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 | 68 ++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/unix/socket.c b/dlls/ntdll/unix/socket.c index ac351a17a70..b4fceb95c05 100644 --- a/dlls/ntdll/unix/socket.c +++ b/dlls/ntdll/unix/socket.c @@ -980,6 +980,43 @@ NTSTATUS sock_read( HANDLE handle, int fd, HANDLE event, PIO_APC_ROUTINE apc, }
+static int isPort0( 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: + FIXME( "unknown address family %d\n", uaddr->addr.sa_family ); + return FALSE; + } +} + static NTSTATUS try_send( int fd, struct async_send_ioctl *async ) { union unix_sockaddr unix_addr; @@ -1018,17 +1055,30 @@ 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) - { - hdr.msg_name = NULL; - hdr.msg_namelen = 0; + if(isPort0(&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(int i = 0; i < hdr.msg_iovlen; i++){ + ret += hdr.msg_iov[i].iov_len; } - else if (errno != EINTR) + WARN("Attempting to send to port 0, skipping over %d bytes\n", ret); + }else{ + while ((ret = sendmsg( fd, &hdr, async->unix_flags )) == -1) { - if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) ); - return sock_errno_to_status( errno ); + if (errno == EISCONN) + { + hdr.msg_name = NULL; + hdr.msg_namelen = 0; + } + else if (errno != EINTR) + { + if (errno != EWOULDBLOCK) WARN( "sendmsg: %s\n", strerror( errno ) ); + return sock_errno_to_status( errno ); + } } }