|Anonymous | Login | Signup for a new account||2014-09-03 07:03 CEST|
|Main | My View | View Issues | Change Log | Roadmap|
|View Issue Details|
|ID||Project||Category||View Status||Date Submitted||Last Update|
|0004894||OCaml||OCaml general||public||2009-10-16 02:16||2012-03-24 15:01|
|Target Version||Fixed in Version||3.12.0+dev|
|Summary||0004894: Windows (mingw): Unix.select and non-blocking sockets|
|Description||After calling Unix.select on Ocaml 3.11.1 on a non-blocking socket, a following Unix.recv may nevertheless block.|
This server code reproduces the problem:
let s = Unix.socket Unix.PF_INET Unix.SOCK_STREAM 0;;
Unix.bind s (Unix.ADDR_INET(Unix.addr_inet_any,9999));;
Unix.listen s 10;;
let t,_ = Unix.accept s;;
Now a client connects to this port, and tries to read (!) from the connection.
The server goes on like:
let _,_,_ = Unix.select [t] [t] (-1.0);;
This select() returns immediately. However, now the socket has forgotten that it is non-blocking:
let p = String.make 1 'x';;
Unix.recv ts p 0 1 ;;
The latter hangs forever.
The OS is Win XP, newest patch level.
|Additional Information||If I replace the Unix.select with a call to the old (Ocaml 3.10) select wrapper, everything works as expected.|
It is a bit unintuitive that a Unix.select is followed by a recv when the select said the socket is only writable, but actually this happens in some networking code. When the socket is non-blocking, the recv should be harmless, and usually fails with EWOULDBLOCK.
|Tags||No tags attached.|
|Sylvain, if you can spare the time, could you please have a look at this one? Thanks.|
Thanks for the information. This is enough to reproduce the bug.
Test case created. I can find the bug on Windows Vista 64bits Profesionnal, I cannot find the bug on Linux (which is normal).
I browse the source code and the bug is at line 556 in otherlibs/win32unix/select.c.
I work on a patch for this.
The main problem here is to be able to know if the socket is non-blocking.
I don't see any winsock call that retrieves this information. (if you have an idea, let me know).
So basically there are two solutions:
1) add a field in the Windows filedescr structure which contains this data
2) go back to Winsock select call, in a separate thread. If the console exit before, cancel the running Winsock select thread...
1) break compatibility, 2) can generate side effect...
What's your opinion?
Thread cancellation is not an option. It will make select exit too early and will probably leak resources. So running select in a separate thread is not a good idea.
I think the best option at hand is to add a "flag" field at the end of filedescr structure to store extra data. On of this data could be a FLAG_SOCKET_NONBLOCKING. We could also store more precise information about HANDLE, like combined result of GetFileType and GetConsoleMode...
Xavier and Gerd, do you have an opinion on this matter?
edited on: 2010-05-21 09:47
To determine whether a socket is non-blocking, you should be able to do
[EDIT: non-working solution, deleted]
As to recording non-blocking status in struct filedescr, I see no problem with that, compatibility or otherwise. While third-party libraries might (perhaps) use this struct, they should always go through the functions win_alloc_handle and win_alloc_socket to allocate them.
Xavier, I reread the MSDN webpage about ioctlsocket and try it, I don't think ioctlsocket get the previous mode...
Where did you find this information? I probably did something wrong in my code.
However the good news, is that I was forcing the non-blocking mode with this code (select.c):
iMode = 0;
WSAEventSelect((SOCKET)(iterQuery->hFileDescr), aEvents[i], 0) != 0 ||
ioctlsocket((SOCKET)(iterQuery->hFileDescr), FIONBIO, &iMode) != 0)
Just removing the ioctlsocket call seems to solve the problem. I think the MSDN statement about WSAEventSelect modifying the non-blocking state is not true, though I am not sure it works on all version of Windows.
I have tried with Windows Vista and it seems ok.
edited on: 2010-05-21 09:53
You're right, the "solution" I outlined probably doesn't work, I misread the MSDN doc for ioctlsocket. I edited it out of my previous comment so that no one else is mislead :-)
> I think the MSDN statement about WSAEventSelect modifying the non-blocking state is not true, though I am not sure it works on all version of Windows.
Be careful. The MSDN page is very specific about what needs to be done:
"The WSAEventSelect function automatically sets socket s to nonblocking mode, regardless of the value of lNetworkEvents. To set socket s back to blocking mode, it is first necessary to clear the event record associated with socket s via a call to WSAEventSelect with lNetworkEvents set to zero and the hEventObject parameter set to NULL. You can then call ioctlsocket or WSAIoctl to set the socket back to blocking mode."
Again, recording blocking/nonblocking status in struct filedescr is easy and unproblematic, if it can help fixing this particular issue.
|Add a filedescr.flags_fd in win32unix/unixsupport.h. It contains the non-blocking status of the associated filedescr and helps to restore this status after a select.|
|2009-10-16 02:16||gerd||New Issue|
|2010-04-18 18:50||xleroy||Note Added: 0005328|
|2010-04-18 18:50||xleroy||Assigned To||=> gildor|
|2010-04-18 18:50||xleroy||Status||new => feedback|
|2010-05-10 18:56||gildor||Note Added: 0005449|
|2010-05-10 18:59||gildor||Note Added: 0005450|
|2010-05-10 18:59||gildor||Status||feedback => confirmed|
|2010-05-19 19:49||gildor||Note Added: 0005464|
|2010-05-20 10:43||gildor||Note Added: 0005465|
|2010-05-20 10:55||xleroy||Note Added: 0005466|
|2010-05-20 19:13||gildor||Note Added: 0005477|
|2010-05-21 09:47||xleroy||Note Edited: 0005466|
|2010-05-21 09:52||xleroy||Note Added: 0005482|
|2010-05-21 09:53||xleroy||Note Edited: 0005482|
|2010-05-25 15:17||gildor||Note Added: 0005503|
|2010-05-25 15:17||gildor||Status||confirmed => resolved|
|2010-05-25 15:17||gildor||Fixed in Version||=> 3.12.0+dev|
|2010-05-25 15:17||gildor||Resolution||open => fixed|
|2012-03-24 15:01||xleroy||Status||resolved => closed|
|Copyright © 2000 - 2011 MantisBT Group|