janestreet / async_unix

Jane Street Capital's asynchronous execution library (unix)
MIT License
33 stars 21 forks source link

blocking_infer_using_stat doesn't work with Unix domain sockets #15

Closed prepor closed 11 months ago

prepor commented 6 years ago

Hey!

Code to reproduce:

open Core
open Async

let () =
  let doit () =
    let fd = Unix.Socket.create Unix.Socket.Type.unix
             |> Unix.Socket.fd
             |> Unix.Fd.file_descr_exn in
    Unix.Fd.Kind.infer_using_stat fd |> ignore
  in
  doit () |> ignore;
  Scheduler.go () |> never_returns

Result:

(((pid 57699) (thread_id 0)) "2018-08-15 13:29:29.288067Z"
 "unhandled exception in Async scheduler"
 ("unhandled exception"
  ((monitor.ml.Error
    (Unix.Unix_error "Protocol not available" getsockopt
     "((fd 3) (opt SO_ACCEPTCONN))")
    ("Raised at file \"src/import0.ml\" (inlined), line 351, characters 22-32"
     "Called from file \"src/result.ml\", line 168, characters 17-26"
     "Called from file \"src/deferred1.ml\", line 20, characters 40-45"
     "Called from file \"src/job_queue.ml\", line 159, characters 6-47"
     "Caught by monitor main"))
   ((pid 57699) (thread_id 1)))))

OS: macOS 10.13.4 Ocaml: 4.05.0

The problem is here https://github.com/janestreet/async_unix/blob/master/src/fd.ml#L31.

It means that we can't infer Unix.Fd from Unix domain sockets. Nodejs, for example, uses Unix domain sockets for stdio with child processes by default (so things like force Reader.stdin fails).

Code to reproduce with nodejs:

ocaml:

open Core
open Async

let () =
  force Reader.stdin |> ignore

JS:

const cp = require('child_process');

let res = cp.spawnSync("/path/to/binary");

console.log(res.stderr.toString());
ghost commented 6 years ago

It seems that you found the issue, could you submit a PR?

prepor commented 6 years ago

@diml I'm not sure how to fix it. What we have: at least on macOS Unix sockets don't support SO_ACCEPTCONN option. I can't find any RFC or something which describes this behavior.

ghost commented 6 years ago

I suppose the code could be changed to not call getsockopt/setsockopt with SO_ACCEPTCONN on OSX.

mscharley commented 6 years ago

I've just hit this with an Async-based HTTP server too. Seems that OSX (and possibly BSD generally) doesn't support SO_ACCEPTCONN from what I've been able to dig up.

mscharley commented 6 years ago

For completeness sake, this is the error I am getting the first time something tries to connect to the server:

(((pid 57454) (thread_id 0)) "2018-11-12 01:05:39.723251Z"
 "unhandled exception in Async scheduler"
 ("unhandled exception"
  ((monitor.ml.Error
    (Unix.Unix_error "Protocol not available" getsockopt
     "((fd 1) (opt SO_ACCEPTCONN))")
    ("Raised at file \"src/core_unix.ml\", line 50, characters 4-43"
     "Called from file \"src/fd.ml\", line 31, characters 17-57"
     "Called from file \"src/fd.ml\", line 54, characters 9-52"
     "Called from file \"camlinternalLazy.ml\", line 27, characters 17-27"
     "Re-raised at file \"camlinternalLazy.ml\", line 34, characters 4-11"
     "Called from file \"src/writer0.ml\", line 1409, characters 24-36"
     "Called from file \"src/result.ml\", line 161, characters 9-15"
     "Caught by monitor main"))
   ((pid 57454) (thread_id 0)))))