diff --git a/lib_eio/unix/net.ml b/lib_eio/unix/net.ml index d32dabe3a..4a0fa298b 100644 --- a/lib_eio/unix/net.ml +++ b/lib_eio/unix/net.ml @@ -61,6 +61,7 @@ type t = [`Generic | `Unix] Eio.Net.ty r type _ Effect.t += | Import_socket_stream : Switch.t * bool * Unix.file_descr -> [`Unix_fd | stream_socket_ty] r Effect.t + | Import_socket_listening : Switch.t * bool * Unix.file_descr -> [`Unix_fd | listening_socket_ty] r Effect.t | Import_socket_datagram : Switch.t * bool * Unix.file_descr -> [`Unix_fd | datagram_socket_ty] r Effect.t | Socketpair_stream : Switch.t * Unix.socket_domain * int -> ([`Unix_fd | stream_socket_ty] r * [`Unix_fd | stream_socket_ty] r) Effect.t @@ -68,11 +69,15 @@ type _ Effect.t += ([`Unix_fd | datagram_socket_ty] r * [`Unix_fd | datagram_socket_ty] r) Effect.t let open_stream s = (s : _ stream_socket :> [< `Unix_fd | stream_socket_ty] r) +let open_listening s = (s : _ listening_socket :> [< `Unix_fd | listening_socket_ty] r) let open_datagram s = (s : _ datagram_socket :> [< `Unix_fd | datagram_socket_ty] r) let import_socket_stream ~sw ~close_unix fd = open_stream @@ Effect.perform (Import_socket_stream (sw, close_unix, fd)) +let import_socket_listening ~sw ~close_unix fd = + open_listening @@ Effect.perform (Import_socket_listening (sw, close_unix, fd)) + let import_socket_datagram ~sw ~close_unix fd = open_datagram @@ Effect.perform (Import_socket_datagram (sw, close_unix, fd)) diff --git a/lib_eio/unix/net.mli b/lib_eio/unix/net.mli index 16a5d3b0c..9ad834f3b 100644 --- a/lib_eio/unix/net.mli +++ b/lib_eio/unix/net.mli @@ -56,15 +56,22 @@ end (** {2 Creating or importing sockets} *) val import_socket_stream : sw:Switch.t -> close_unix:bool -> Unix.file_descr -> [`Unix_fd | stream_socket_ty] r -(** [import_socket_stream ~sw ~close_unix:true fd] is an Eio flow that uses [fd]. +(** [import_socket_stream ~sw ~close_unix fd] is an Eio flow that uses [fd]. It can be cast to e.g. {!source} for a one-way flow. The socket object will be closed when [sw] finishes. The [close_unix] and [sw] arguments are passed to {!Fd.of_unix}. *) +val import_socket_listening : sw:Switch.t -> close_unix:bool -> Unix.file_descr -> [`Unix_fd | listening_socket_ty] r +(** [import_socket_listening ~sw ~close_unix fd] is an Eio listening socket that uses [fd]. + + The socket object will be closed when [sw] finishes. + + The [close_unix] and [sw] arguments are passed to {!Fd.of_unix}. *) + val import_socket_datagram : sw:Switch.t -> close_unix:bool -> Unix.file_descr -> [`Unix_fd | datagram_socket_ty] r -(** [import_socket_datagram ~sw ~close_unix:true fd] is an Eio datagram socket that uses [fd]. +(** [import_socket_datagram ~sw ~close_unix fd] is an Eio datagram socket that uses [fd]. The socket object will be closed when [sw] finishes. @@ -100,6 +107,8 @@ val getnameinfo : Eio.Net.Sockaddr.t -> (string * string) type _ Effect.t += | Import_socket_stream : Switch.t * bool * Unix.file_descr -> [`Unix_fd | stream_socket_ty] r Effect.t (** See {!import_socket_stream} *) + | Import_socket_listening : + Switch.t * bool * Unix.file_descr -> [`Unix_fd | listening_socket_ty] r Effect.t (** See {!import_socket_listening} *) | Import_socket_datagram : Switch.t * bool * Unix.file_descr -> [`Unix_fd | datagram_socket_ty] r Effect.t (** See {!import_socket_datagram} *) | Socketpair_stream : Eio.Switch.t * Unix.socket_domain * int -> diff --git a/lib_eio_linux/eio_linux.ml b/lib_eio_linux/eio_linux.ml index 00a695098..ec9c8eb07 100644 --- a/lib_eio_linux/eio_linux.ml +++ b/lib_eio_linux/eio_linux.ml @@ -504,6 +504,10 @@ let run_event_loop (type a) ?fallback config (main : _ -> a) arg : a = let fd = Fd.of_unix ~sw ~seekable:false ~close_unix fd in continue k (Flow.of_fd fd :> _ Eio_unix.Net.stream_socket) ) + | Eio_unix.Net.Import_socket_listening (sw, close_unix, fd) -> Some (fun k -> + let fd = Fd.of_unix ~sw ~seekable:false ~close_unix fd in + continue k (listening_socket fd) + ) | Eio_unix.Net.Import_socket_datagram (sw, close_unix, fd) -> Some (fun k -> let fd = Fd.of_unix ~sw ~seekable:false ~close_unix fd in continue k (datagram_socket fd) diff --git a/lib_eio_posix/domain_mgr.ml b/lib_eio_posix/domain_mgr.ml index 0b49f4a25..f4bc98b9b 100644 --- a/lib_eio_posix/domain_mgr.ml +++ b/lib_eio_posix/domain_mgr.ml @@ -48,6 +48,11 @@ let run_event_loop fn x = Unix.set_nonblock unix_fd; continue k (Flow.of_fd fd :> _ Eio_unix.Net.stream_socket) ) + | Eio_unix.Net.Import_socket_listening (sw, close_unix, unix_fd) -> Some (fun k -> + let fd = Fd.of_unix ~sw ~blocking:false ~close_unix unix_fd in + Unix.set_nonblock unix_fd; + continue k (Net.listening_socket ~hook:Switch.null_hook fd) + ) | Eio_unix.Net.Import_socket_datagram (sw, close_unix, unix_fd) -> Some (fun k -> let fd = Fd.of_unix ~sw ~blocking:false ~close_unix unix_fd in Unix.set_nonblock unix_fd; diff --git a/lib_eio_windows/domain_mgr.ml b/lib_eio_windows/domain_mgr.ml index 5a63e78a9..24f036b31 100755 --- a/lib_eio_windows/domain_mgr.ml +++ b/lib_eio_windows/domain_mgr.ml @@ -48,6 +48,11 @@ let run_event_loop fn x = (try Unix.set_nonblock unix_fd with Unix.Unix_error (Unix.ENOTSOCK, _, _) -> ()); continue k (Flow.of_fd fd :> _ Eio_unix.Net.stream_socket) ) + | Eio_unix.Net.Import_socket_listening (sw, close_unix, unix_fd) -> Some (fun k -> + let fd = Fd.of_unix ~sw ~blocking:false ~close_unix unix_fd in + Unix.set_nonblock unix_fd; + continue k (Net.listening_socket ~hook:Switch.null_hook fd) + ) | Eio_unix.Net.Import_socket_datagram (sw, close_unix, unix_fd) -> Some (fun k -> let fd = Fd.of_unix ~sw ~blocking:false ~close_unix unix_fd in Unix.set_nonblock unix_fd; diff --git a/tests/network.md b/tests/network.md index eb83ceb7b..c22472925 100644 --- a/tests/network.md +++ b/tests/network.md @@ -373,6 +373,29 @@ Wrapping a Unix FD as an Eio stream socket: - : unit = () ``` +Wrapping a Unix FD as a listening Eio socket: + +```ocaml +# run @@ fun ~net sw -> + let l = Unix.(socket PF_INET SOCK_STREAM 0) in + Unix.bind l (Unix.ADDR_INET (Unix.inet_addr_loopback, 8082)); + Unix.listen l 40; + let l = Eio_unix.Net.import_socket_listening ~sw ~close_unix:true l in + Fiber.both + (fun () -> run_server ~sw l) + (fun () -> + run_client ~sw ~net ~addr:(`Tcp (Eio.Net.Ipaddr.V4.loopback, 8082)); + traceln "Client finished - cancelling server"; + raise Graceful_shutdown + );; ++Connecting to server... ++Server accepted connection from client ++Server received: "Hello from client" ++Client received: "Bye" ++Client finished - cancelling server +Exception: Graceful_shutdown. +``` + Wrapping a Unix FD as an datagram Eio socket: ```ocaml