Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0004894OCamlOCaml generalpublic2009-10-16 02:162012-03-24 15:01
Reportergerd 
Assigned Togildor 
PrioritynormalSeveritymajorReproducibilityalways
StatusclosedResolutionfixed 
PlatformOSOS Version
Product Version3.11.1 
Target VersionFixed in Version3.12.0+dev 
Summary0004894: Windows (mingw): Unix.select and non-blocking sockets
DescriptionAfter 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:

Unix.set_nonblock t;;
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 InformationIf 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.
TagsNo tags attached.
Attached Files

- Relationships

-  Notes
(0005328)
xleroy (administrator)
2010-04-18 18:50

Sylvain, if you can spare the time, could you please have a look at this one? Thanks.
(0005449)
gildor (developer)
2010-05-10 18:56

Gerd,

Thanks for the information. This is enough to reproduce the bug.
(0005450)
gildor (developer)
2010-05-10 18:59

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.
(0005464)
gildor (developer)
2010-05-19 19:49

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?
(0005465)
gildor (developer)
2010-05-20 10:43

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?
(0005466)
xleroy (administrator)
2010-05-20 10:55
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.

(0005477)
gildor (developer)
2010-05-20 19:13

Xavier, I reread the MSDN webpage about ioctlsocket and try it, I don't think ioctlsocket get the previous mode...
http://msdn.microsoft.com/en-us/library/ms738573%28VS.85%29.aspx [^]

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;
check_error(lpSelectData,
  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.
(0005482)
xleroy (administrator)
2010-05-21 09:52
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.

(0005503)
gildor (developer)
2010-05-25 15:17

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.

- Issue History
Date Modified Username Field Change
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
Powered by Mantis Bugtracker