From: Paul Gofman pgofman@codeweavers.com
--- server/sock.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/server/sock.c b/server/sock.c index 3ad1ce39194..8a95caded8b 100644 --- a/server/sock.c +++ b/server/sock.c @@ -813,7 +813,7 @@ static void post_sock_messages( struct sock *sock ) } }
-static inline int sock_error( struct sock *sock ) +static inline int sock_error( struct sock *sock, int *poll_event ) { int error = 0; socklen_t len = sizeof(error); @@ -839,8 +839,14 @@ static inline int sock_error( struct sock *sock ) error = sock->errors[AFD_POLL_BIT_ACCEPT]; break;
- case SOCK_CONNECTED: case SOCK_CONNECTIONLESS: + if (error == ENETUNREACH || error == EHOSTUNREACH || error == ECONNRESET) + { + if (poll_event) *poll_event &= ~POLLERR; + return 0; + } + /* fallthrough */ + case SOCK_CONNECTED: if (error == ECONNRESET || error == EPIPE) { sock->reset = 1; @@ -1346,7 +1352,7 @@ static void sock_poll_event( struct fd *fd, int event ) fprintf(stderr, "socket %p select event: %x\n", sock, event);
if (event & (POLLERR | POLLHUP)) - error = sock_error( sock ); + error = sock_error( sock, &event );
switch (sock->state) { @@ -3115,7 +3121,7 @@ static void sock_ioctl( struct fd *fd, ioctl_code_t code, struct async *async ) return; }
- error = sock_error( sock ); + error = sock_error( sock, NULL ); if (!error) { for (i = 0; i < ARRAY_SIZE( sock->errors ); ++i)
Fixes Witch Slide Playest which worked at times but stopped some time ago probably after some winsock redesign. The game does select() on UDP socket with read and exceptions output and treats non-zero select result as if the socket has something to read, after which goes for blocking read which hangs infinitely.
I think it is known by now from similar changes that Windows never exposes ICMP errors on UDP sockets (unless maybe some special Windows-specific socket options we currently don't support). I am attaching the test which reproduces the issue fixed by the patch. I haven't included it in the MR because I could not find a special IP or other network setup independent way to trigger the error which happens with that IP address (where probably the destination network replies with ICMP which gets translated to EHOSTUNREACH).
[test.patch](/uploads/6ce2c2cd06bbc87a5bb81df5a4c0927e/test.patch)
It is not the first time ICMP errors pop up on UDP sockets, previous time that was with send() returning ECONNREFUSED. I tried to search for some more generic way to detect ICMP related errors without hunting specific error codes which vary across socket operations. I only found IP_RECVERR socket option which allows to get detailed and full error stack with recvmsg(), with the returned info allowing to explicitly attribute the error to ICMP. But unfortunately it is Linux specific and probably doing this Linux specific doesn't worth it in this case.
This merge request was approved by Zebediah Figura.