From cc400c27b172a64fa70812f9535fb3655f73a8c5 Mon Sep 17 00:00:00 2001 From: Thomas Leonard Date: Mon, 5 Jun 2023 15:08:41 +0100 Subject: [PATCH] Restore close to socket type Now that double-close is permitted, we can simplify the types by making all sockets closable. This reverts commit ccf147474ee3c2c222c2e9c7694b2c69445734c8. --- lib_eio/mock/eio_mock.mli | 8 ++++---- lib_eio/mock/net.ml | 12 ++++++------ lib_eio/net.ml | 8 ++++---- lib_eio/net.mli | 16 ++++++++-------- lib_eio/unix/net.ml | 4 ++-- lib_eio/unix/net.mli | 4 ++-- lib_eio_linux/eio_linux.ml | 6 +++--- lib_eio_posix/net.ml | 6 +++--- lib_eio_windows/net.ml | 6 +++--- tests/network.md | 25 +++++++++++++++++++++++++ 10 files changed, 60 insertions(+), 35 deletions(-) diff --git a/lib_eio/mock/eio_mock.mli b/lib_eio/mock/eio_mock.mli index 9cde0098d..28066c18f 100644 --- a/lib_eio/mock/eio_mock.mli +++ b/lib_eio/mock/eio_mock.mli @@ -119,8 +119,8 @@ module Net : sig type t = < Eio.Net.t; on_listen : Eio.Net.listening_socket Handler.t; - on_connect : Handler.t; - on_datagram_socket : Handler.t; + on_connect : Eio.Net.stream_socket Handler.t; + on_datagram_socket : Eio.Net.datagram_socket Handler.t; on_getaddrinfo : Eio.Net.Sockaddr.t list Handler.t; on_getnameinfo : (string * string) Handler.t; > @@ -133,13 +133,13 @@ module Net : sig val make : string -> t (** [make label] is a new mock network. *) - val on_connect : t -> Handler.actions -> unit + val on_connect : t -> Handler.actions -> unit (** [on_connect t actions] configures what to do when a client tries to connect somewhere. *) val on_listen : t -> #Eio.Net.listening_socket Handler.actions -> unit (** [on_listen t actions] configures what to do when a server starts listening for incoming connections. *) - val on_datagram_socket : t -> Handler.actions -> unit + val on_datagram_socket : t -> Handler.actions -> unit (** [on_datagram_socket t actions] configures how to create datagram sockets. *) val on_getaddrinfo : t -> Eio.Net.Sockaddr.t list Handler.actions -> unit diff --git a/lib_eio/mock/net.ml b/lib_eio/mock/net.ml index 902d5d013..4104c1c39 100644 --- a/lib_eio/mock/net.ml +++ b/lib_eio/mock/net.ml @@ -3,8 +3,8 @@ open Eio.Std type t = < Eio.Net.t; on_listen : Eio.Net.listening_socket Handler.t; - on_connect : Handler.t; - on_datagram_socket : Handler.t; + on_connect : Eio.Net.stream_socket Handler.t; + on_datagram_socket : Eio.Net.datagram_socket Handler.t; on_getaddrinfo : Eio.Net.Sockaddr.t list Handler.t; on_getnameinfo : (string * string) Handler.t; > @@ -56,15 +56,15 @@ let make label = end let on_connect (t:t) actions = - let as_socket x = (x :> ) in + let as_socket x = (x :> Eio.Net.stream_socket) in Handler.seq t#on_connect (List.map (Action.map as_socket) actions) let on_listen (t:t) actions = - let as_socket x = (x :> ) in + let as_socket x = (x :> Eio.Net.listening_socket) in Handler.seq t#on_listen (List.map (Action.map as_socket) actions) let on_datagram_socket (t:t) actions = - let as_socket x = (x :> ) in + let as_socket x = (x :> Eio.Net.datagram_socket) in Handler.seq t#on_datagram_socket (List.map (Action.map as_socket) actions) let on_getaddrinfo (t:t) actions = Handler.seq t#on_getaddrinfo actions @@ -87,7 +87,7 @@ let listening_socket label = let socket, addr = Handler.run on_accept in Flow.attach_to_switch socket sw; traceln "%s: accepted connection from %a" label Eio.Net.Sockaddr.pp addr; - (socket :> ), addr + (socket :> Eio.Net.stream_socket), addr method close = traceln "%s: closed" label diff --git a/lib_eio/net.ml b/lib_eio/net.ml index 741df90e5..ee9eeee42 100644 --- a/lib_eio/net.ml +++ b/lib_eio/net.ml @@ -157,7 +157,7 @@ module Sockaddr = struct Format.fprintf f "udp:%a:%d" Ipaddr.pp_for_uri addr port end -class virtual socket = object (_ : #Generic.t) +class virtual socket = object (_ : ) method probe _ = None end @@ -167,7 +167,7 @@ end class virtual listening_socket = object (_ : ) inherit socket - method virtual accept : sw:Switch.t -> * Sockaddr.stream + method virtual accept : sw:Switch.t -> stream_socket * Sockaddr.stream end type connection_handler = stream_socket -> Sockaddr.stream -> unit @@ -202,13 +202,13 @@ let recv (t:#datagram_socket) = t#recv class virtual t = object method virtual listen : reuse_addr:bool -> reuse_port:bool -> backlog:int -> sw:Switch.t -> Sockaddr.stream -> listening_socket - method virtual connect : sw:Switch.t -> Sockaddr.stream -> + method virtual connect : sw:Switch.t -> Sockaddr.stream -> stream_socket method virtual datagram_socket : reuse_addr:bool -> reuse_port:bool -> sw:Switch.t -> [Sockaddr.datagram | `UdpV4 | `UdpV6] - -> + -> datagram_socket method virtual getaddrinfo : service:string -> string -> Sockaddr.t list method virtual getnameinfo : Sockaddr.t -> (string * string) diff --git a/lib_eio/net.mli b/lib_eio/net.mli index a1ddf126f..71f13b542 100644 --- a/lib_eio/net.mli +++ b/lib_eio/net.mli @@ -102,7 +102,7 @@ end (** {2 Provider Interfaces} *) -class virtual socket : object +class virtual socket : object () inherit Generic.t end @@ -119,18 +119,18 @@ end class virtual listening_socket : object () inherit socket - method virtual accept : sw:Switch.t -> * Sockaddr.stream + method virtual accept : sw:Switch.t -> stream_socket * Sockaddr.stream end class virtual t : object method virtual listen : reuse_addr:bool -> reuse_port:bool -> backlog:int -> sw:Switch.t -> Sockaddr.stream -> listening_socket - method virtual connect : sw:Switch.t -> Sockaddr.stream -> + method virtual connect : sw:Switch.t -> Sockaddr.stream -> stream_socket method virtual datagram_socket : reuse_addr:bool -> reuse_port:bool -> sw:Switch.t -> [Sockaddr.datagram | `UdpV4 | `UdpV6] - -> + -> datagram_socket method virtual getaddrinfo : service:string -> string -> Sockaddr.t list method virtual getnameinfo : Sockaddr.t -> (string * string) @@ -138,7 +138,7 @@ end (** {2 Out-bound Connections} *) -val connect : sw:Switch.t -> #t -> Sockaddr.stream -> +val connect : sw:Switch.t -> #t -> Sockaddr.stream -> stream_socket (** [connect ~sw t addr] is a new socket connected to remote address [addr]. The new socket will be closed when [sw] finishes, unless closed manually first. *) @@ -148,7 +148,7 @@ val with_tcp_connect : host:string -> service:string -> #t -> - ( -> 'b) -> + (stream_socket -> 'b) -> 'b (** [with_tcp_connect ~host ~service t f] creates a tcp connection [conn] to [host] and [service] and executes [f conn]. @@ -184,7 +184,7 @@ val listen : ?reuse_addr:bool -> ?reuse_port:bool -> backlog:int -> sw:Switch.t val accept : sw:Switch.t -> #listening_socket -> - * Sockaddr.stream + stream_socket * Sockaddr.stream (** [accept ~sw socket] waits until a new connection is ready on [socket] and returns it. The new socket will be closed automatically when [sw] finishes, if not closed earlier. @@ -255,7 +255,7 @@ val datagram_socket : -> sw:Switch.t -> #t -> [< Sockaddr.datagram | `UdpV4 | `UdpV6] - -> + -> datagram_socket (** [datagram_socket ~sw t addr] creates a new datagram socket bound to [addr]. The new socket will be closed when [sw] finishes. diff --git a/lib_eio/unix/net.ml b/lib_eio/unix/net.ml index 03ec922b4..95dcb8d48 100644 --- a/lib_eio/unix/net.ml +++ b/lib_eio/unix/net.ml @@ -23,11 +23,11 @@ let sockaddr_of_unix_datagram = function let host = Ipaddr.of_unix host in `Udp (host, port) -class virtual stream_socket = object (_ : ) +class virtual stream_socket = object (_ : ) inherit Eio.Net.stream_socket end -class virtual datagram_socket = object (_ : ) +class virtual datagram_socket = object (_ : ) inherit Eio.Net.datagram_socket end diff --git a/lib_eio/unix/net.mli b/lib_eio/unix/net.mli index b597c8487..4b53c58c6 100644 --- a/lib_eio/unix/net.mli +++ b/lib_eio/unix/net.mli @@ -4,11 +4,11 @@ open Eio.Std These extend the types in {!Eio.Net} with support for file descriptors. *) -class virtual stream_socket : object () +class virtual stream_socket : object () inherit Eio.Net.stream_socket end -class virtual datagram_socket : object () +class virtual datagram_socket : object () inherit Eio.Net.datagram_socket end diff --git a/lib_eio_linux/eio_linux.ml b/lib_eio_linux/eio_linux.ml index c66d94fd0..773f847fe 100644 --- a/lib_eio_linux/eio_linux.ml +++ b/lib_eio_linux/eio_linux.ml @@ -187,7 +187,7 @@ let listening_socket fd = object | Unix.ADDR_UNIX path -> `Unix path | Unix.ADDR_INET (host, port) -> `Tcp (Eio_unix.Net.Ipaddr.of_unix host, port) in - let flow = (flow client :> ) in + let flow = (flow client :> Eio.Net.stream_socket) in flow, client_addr method! probe : type a. a Eio.Generic.ty -> a option = function @@ -210,7 +210,7 @@ let connect ~sw connect_addr = let sock_unix = Unix.socket ~cloexec:true (socket_domain_of connect_addr) Unix.SOCK_STREAM 0 in let sock = FD.of_unix ~sw ~seekable:false ~close_unix:true sock_unix in Low_level.connect sock addr; - (flow sock :> ) + (flow sock :> Eio.Net.stream_socket) let net = object inherit Eio_unix.Net.t @@ -269,7 +269,7 @@ let net = object Unix.bind sock_unix addr | `UdpV4 | `UdpV6 -> () end; - (datagram_socket sock :> ) + (datagram_socket sock :> Eio.Net.datagram_socket) method getaddrinfo = Low_level.getaddrinfo end diff --git a/lib_eio_posix/net.ml b/lib_eio_posix/net.ml index 27ae84661..747fc772a 100644 --- a/lib_eio_posix/net.ml +++ b/lib_eio_posix/net.ml @@ -25,7 +25,7 @@ let listening_socket ~hook fd = object | Unix.ADDR_UNIX path -> `Unix path | Unix.ADDR_INET (host, port) -> `Tcp (Eio_unix.Net.Ipaddr.of_unix host, port) in - let flow = (Flow.of_fd client :> ) in + let flow = (Flow.of_fd client :> Eio.Net.stream_socket) in flow, client_addr method! probe : type a. a Eio.Generic.ty -> a option = function @@ -118,7 +118,7 @@ let connect ~sw connect_addr = let sock = Low_level.socket ~sw (socket_domain_of connect_addr) socket_type 0 in try Low_level.connect sock addr; - (Flow.of_fd sock :> ) + (Flow.of_fd sock :> Eio.Net.stream_socket) with Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg) let create_datagram_socket ~reuse_addr ~reuse_port ~sw saddr = @@ -135,7 +135,7 @@ let create_datagram_socket ~reuse_addr ~reuse_port ~sw saddr = ) | `UdpV4 | `UdpV6 -> () end; - (datagram_socket sock :> ) + (datagram_socket sock :> Eio.Net.datagram_socket) let v = object inherit Eio_unix.Net.t diff --git a/lib_eio_windows/net.ml b/lib_eio_windows/net.ml index cd8909791..659eacdac 100755 --- a/lib_eio_windows/net.ml +++ b/lib_eio_windows/net.ml @@ -25,7 +25,7 @@ let listening_socket ~hook fd = object | Unix.ADDR_UNIX path -> `Unix path | Unix.ADDR_INET (host, port) -> `Tcp (Eio_unix.Net.Ipaddr.of_unix host, port) in - let flow = (Flow.of_fd client :> ) in + let flow = (Flow.of_fd client :> Eio.Net.stream_socket) in flow, client_addr method! probe : type a. a Eio.Generic.ty -> a option = function @@ -123,7 +123,7 @@ let connect ~sw connect_addr = let sock = Low_level.socket ~sw (socket_domain_of connect_addr) socket_type 0 in try Low_level.connect sock addr; - (Flow.of_fd sock :> ) + (Flow.of_fd sock :> Eio.Net.stream_socket) with Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg) let create_datagram_socket ~reuse_addr ~reuse_port ~sw saddr = @@ -140,7 +140,7 @@ let create_datagram_socket ~reuse_addr ~reuse_port ~sw saddr = ) | `UdpV4 | `UdpV6 -> () end; - (datagram_socket sock :> ) + (datagram_socket sock :> Eio.Net.datagram_socket) let v = object inherit Eio_unix.Net.t diff --git a/tests/network.md b/tests/network.md index ab9c7787e..f1b66a358 100644 --- a/tests/network.md +++ b/tests/network.md @@ -249,6 +249,31 @@ Handling one UDP packet using IPv6: - : unit = () ``` +It's not an error to close the socket before the handler returns: + +```ocaml +# run @@ fun ~net sw -> + let addr = `Tcp (Eio.Net.Ipaddr.V4.loopback, 8083) in + let server = Eio.Net.listen net ~sw ~reuse_addr:true ~backlog:5 addr in + Fiber.both + (fun () -> + Eio.Net.accept_fork server ~sw ~on_error:raise @@ fun flow _addr -> + traceln "Server got connection"; + Eio.Flow.copy_string "Hi" flow; + Eio.Flow.close flow + ) + (fun () -> + traceln "Connecting to server..."; + let flow = Eio.Net.connect ~sw net addr in + let msg = Eio.Buf_read.(parse_exn take_all) flow ~max_size:100 in + traceln "Client got %S" msg; + );; ++Connecting to server... ++Server got connection ++Client got "Hi" +- : unit = () +``` + ## Unix interop Extracting file descriptors from Eio objects: