-
Notifications
You must be signed in to change notification settings - Fork 177
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lwt_io.open_connection hangs on Windows when opening a connection to an address that is not listening. #550
Comments
I looked in the Lwt source code, and a bit in OCaml, and I don't immediately see the problem. Since I don't have easy access to a MinGW install to try things out, here is what I suggest:
I'm not sure about the extra connections. My suggestion for that is to write a similar short program using only |
Programs written using Unix don't seem to have the same problems on Windows. let () =
let _ = Unix.open_connection (Unix.ADDR_INET (Unix.inet_addr_of_string "127.0.0.1",46000)) in
() let () =
let sock_addr = Unix.ADDR_INET (Unix.inet_addr_of_string "127.0.0.1",46000) in
let sock = Unix.socket (Unix.domain_of_sockaddr sock_addr) Unix.SOCK_STREAM 0 in
Unix.connect sock sock_addr Both of the above programs error out with The client/server programs written using Unix don't create extra connections either. let () =
let rec handler out_ch = output_string stdout "Hello\n" ; output_string out_ch "Hello\n" ; handler out_ch in
let _, out_ch = Unix.open_connection (Unix.ADDR_INET (Unix.inet_addr_of_string "127.0.0.1",46000)) in
handler out_ch let () =
let rec handler_fn in_ch out_ch =
let s = input_line in_ch in
output_string stdout ("Got " ^ s ^ " from client.") ;
output_string out_ch s ;
handler_fn in_ch out_ch
in
let sock_addr = Unix.ADDR_INET (Unix.inet_addr_any , 46000) in
let sock = Unix.socket (Unix.domain_of_sockaddr sock_addr) Unix.SOCK_STREAM 0 in
Unix.bind sock sock_addr ;
Unix.listen sock 3;
let (s, _) = Unix.accept sock in
let in_ch = Unix.in_channel_of_descr s
and out_ch = Unix.out_channel_of_descr s in
handler_fn in_ch out_ch Starting server then client results in the following netstat output :
I can investigate further by looking at the lwt codebase. |
That would probably be the most helpful. Thanks if you do. In addition to the code I linked above, If you haven't already done so, I suggest getting the Lwt source and inserting prints to figure out what is really being called and when among all these functions. Using Let me know if you have any questions that I can readily answer (i.e. without actually being on a MinGW system :/). |
I can confirm that the select engine is being used. The two sockets connections that are always made look to be a Windows implementation detail (I don't think this is pertinent to the issue). The issue seems to be related to API differences between Linux and Windows when it comes to connect on nonblocking sockets. When calling Lwt_io.open_connection without supplying a file descriptor the first thing it does is create a socket by calling Lwt_unix.socket which sets the socket to be nonblocking.
This lines up with the implementation of Lwt_unix.connect for Linux. For Windows the documentation is slightly different :
In the lwt implementation the connection is first attempted then the EWOULDBLOCK is caught and a writeable is registered with the select engine. The problem with lwt's nonblocking connect on Windows can be demonstrated with the following Unix based program : let () =
let sock_addr = Unix.ADDR_INET (Unix.inet_addr_of_string "127.0.0.1",46000) in
let sock = Unix.socket (Unix.domain_of_sockaddr sock_addr) Unix.SOCK_STREAM 0 in
Unix.set_nonblock sock ;
try
Unix.connect sock sock_addr
with
| Unix.Unix_error (Unix.EWOULDBLOCK, _, _) -> let _ = Unix.select [] [sock] [] (-1.0) in ()
| _ -> assert false The above program just waits forever on the select call. If the program is modified so that the socket is passed into the error set as well on the select call then it does not hang and exits. |
Excellent investigation, thank you. It looks like the select engine and the code that interacts with it in A really dirty fix might be to put the socket into blocking mode for |
@essdotteedot You may benefit by replacing |
(...and we would like to replace |
Thank you for the comments. I was not aware of uwt, hopefully it solves my Windows issues. |
The following program hangs on Windows :
On Linux this works as expected (the program errors out with
Unix.Unix_error (Unix.ECONNREFUSED, "connect", "")
).Doing a
netstat -a -b -n -o
on Windows I see the following:These two additional connections happen even when a successful connection is established. Consider the following programs :
client.ml
server.ml
Running server then client the netstat output is as follows :
I've tested against, lwt 3.2.1, safer-semantics branch, pre-compiled OCaml version 4.02.3+mingw64c and 4.05.0+mingw64c. The pre-compiled OCaml versions are sourced from https://github.com/fdopen/opam-repository-mingw.
The text was updated successfully, but these errors were encountered: