http://bugs.winehq.org/show_bug.cgi?id=10176
Ken Richardson ktrichardson@eastlink.ca changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |ktrichardson@eastlink.ca
--- Comment #34 from Ken Richardson ktrichardson@eastlink.ca 2010-10-16 16:03:39 CDT --- I have spent significant time troubleshooting this issue and found the cause and solution. I have tested with ARCA Sim Racing and rFactor. Both these applications use common code and therefore have the same issue.
The problem is how Wine handles the Winsock2 "Select" function. When a call is made to Select and you pass read, write, and exception fd_set structures with all three fd_count values set to 0, Windows will return error code WSAEINVAL but Wine returns 0 (no error). The rFactor and ASR code is written to handle the WSAEINVAL return value by re-initializing the fd_set structures and looping to call select again. Because Wine does not return this error for this condition the structures do not get re-initialized.
You are probably asking how the structures get changed? rFactor and ASR both initialize the fd_set structure fd_count value to 1 and provide one socket handle in the fd_array member for the read and exception parameters. The write parameter fd_count is set to 0, not used. This is done in the listening thread initialization code. The Winsock2 "Select" function modifies the fd_count values by decrementing them to 0. This behavior is true for Windows and Wine. The difference, and cause of this bug, is Wine does not return WSAEINVAL if you pass 0 for all fd_count values.
I fixed the problem by "hacking" the NetCommUtilPlugin.dll rFactor and ASR file to re-initialize the fd_set structures and now it works perfectly under Wine. I have also passed this on to ISI who will likely not care about supporting Wine.
Here's the rFactor code, see my comments:
.text:1000CCD3 loc_1000CCD3: ; CODE XREF: sub_1000CC60+198j .text:1000CCD3 lea ecx, [esp+6A4h+timeout] ; <-- Start of loop, push fd_set structure pointers to stack and make Select call. .text:1000CCD7 push ecx ; timeout .text:1000CCD8 lea edx, [esp+6A8h+timeout.fd_array+14h] .text:1000CCDC push edx ; exceptfds .text:1000CCDD lea eax, [esp+6ACh+writefds] .text:1000CCE4 push eax ; writefds .text:1000CCE5 lea ecx, [esp+6B0h+buf] .text:1000CCEC push ecx ; readfds .text:1000CCED push 0 ; nfds .text:1000CCEF mov [esp+6B8h+var_698], 10h .text:1000CCF7 call ds:select .text:1000CCFD test eax, eax .text:1000CCFF jz loc_1000CDF1 ; <-- Return 0, nothing ready to read and no exception. Wine always takes this jump. .text:1000CD05 mov eax, s .text:1000CD0A lea edx, [esp+6B8h+timeout.fd_array] .text:1000CD0E push edx ; fd_set * .text:1000CD0F push eax ; SOCKET .text:1000CD10 call __WSAFDIsSet .text:1000CD15 test eax, eax .text:1000CD17 jnz loc_1000CDF1 ; <-- Timeout, jump to end of loop. .text:1000CD1D mov edx, s .text:1000CD23 lea ecx, [esp+6C0h+timeout.fd_array+0FCh] .text:1000CD2A push ecx ; fd_set * .text:1000CD2B push edx ; SOCKET .text:1000CD2C call __WSAFDIsSet .text:1000CD31 test eax, eax .text:1000CD33 jz loc_1000CDD6 ; <-- WSAEINVAL error, jump to re-initialization code, then end of loop .text:1000CD39 lea eax, [esp+6C8h+to.sa_data+0Ah] .text:1000CD3D push eax ; fromlen .text:1000CD3E mov eax, s
Hope this helps. Ken