http://bugs.winehq.org/show_bug.cgi?id=5774
------- Additional Comments From damjan.jov@gmail.com 2007-12-05 04:39 ------- Created an attachment (id=6242) --> (http://bugs.winehq.org/attachment.cgi?id=6242&action=view) patch select to ensure readability
So looking over an enormous emule log that someone sent me, I see that emule only ever creates 3 UDP sockets, all of them early on.
In order of creation: * fd 38, handle 0xa8, bound to 0.0.0.0:0, closed very close to the end, works perfectly sending and receiving * fd 43, handle 0x3fc, emule tries to bind it to 0.0.0.0:11291 and fails because it's already in use, then closes it immediately * fd 144, handle 0x404, bound to 0.0.0.0:47772, closed very close to the end, works perfectly sending, but receiving, after some time it hits EWOULDBLOCK, and never tries to receive again!
Elaborating on that very suspicious last socket just before it breaks:
0009: get_message( flags=00000001, get_win=(nil), get_first=00000000, get_last=ffffffff, hw_id=00000000 ) 0009: get_message() = 0 { win=0x1002e, type=6, msg=00000373, wparam=404, lparam=1, info=0, x=0, y=0, time=00a8e216, hw_id=00000000, active_hooks=80000041, total=0, data={} } 0009:trace:winsock:WS_select read 0x34d078, write (nil), excp (nil) timeout 0x34d17c 0009:trace:winsock:WSARecvFrom socket 0404, wsabuf 0x34bc14, nbufs 1, flags 0, from 0x34d030, fromlen 16, ovl (nil), func (nil) 0009:trace:winsock:WSARecvFrom fd=158, options=0 0009: get_socket_event( handle=0x404, service=0, c_event=(nil) ) 0009: get_socket_event() = 0 { mask=00000003, pmask=00000000, state=20000003, errors={} } 0009:trace:winsock:WS2_recv fd 158, iovec 0x171c348, count 1 addr { family 0, address 0.0.0.0, port 0 }, len 0x34d020, flags 0 0009:trace:winsock:WS2_recv recvmsg error 11 0009:trace:winsock:WS2_recv -> -1 0009:warn:winsock:wsaErrno errno 11, (Resource temporarily unavailable). 0009:warn:winsock:WSARecvFrom -> ERROR 10035
For some reason, emule tries a WSARecvFrom() on socket 404, which immediately fails with EWOULDBLOCK (10035), normally an innocent error that means "try again". It's the first and only time that emule ever gets EWOULDBLOCK on any socket, but emule never tries again to receive from that socket.
If emule was a UNIX app this would be an application bug. But this behaviour clearly never happens on Windows, so it's a wine bug.
Why does it try a WSARecvFrom() on a socket that has no data? * The call to WSARecvFrom is preceded by a call to select(), which asks for readability (but we don't know for which sockets). So select() could be reporting readability for sockets that aren't readable (this is a possibility, it's a known fact that for eg. TCP sockets you cannot use a blocking listening socket and poll for readability and then call accept(), because readability is signalled before a successful connection is established, so your accept() could block until the next connection comes in. Maybe in the case of UDP sockets, readability is signalled before the UDP packet is verified/checksummed, and then when you try read, the packet is discarded, and if the socket is non-blocking, there is now no data and it fails with EWOULDBLOCK. This theory is very difficult to prove, it would require crafting a corrupt UDP packet and seeing what happens to a select() on the socket that receives it (any volunteers?)). * Socket 404 is also WSAAsyncSelect()-ed just after creation to deliver event mask 3 (FD_READ | FD_WRITE) to a window. Just before the call to select(), the FD_READ event is delivered for socket 404, which, combined with select(), could be causing emule to try WSARecvFrom, which fails for the same reasons as above.
Either way, it looks like non-blocking I/O availability must only be signalled when we are absolutely certain it can be performed.
This patch modifies select() to ensure there is data to read before it returns readability. It could well be this is not enough, reading over the source code for emule 0.47a I see that it didn't even use select(), but just try to do I/O straight away when the FD_READ notification arrived, so event notifications might need to be patched as well.
So please try this patch, and report whether emule/uTorrent work any better.