From 68cea67f47662993a6327881c658684cc0664837 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Fri, 7 Jul 2023 19:33:12 +0100 Subject: [PATCH 1/9] add Eio_unix.Sockopt for setting socket options --- lib_eio/unix/dune | 2 +- lib_eio/unix/eio_unix.ml | 1 + lib_eio/unix/eio_unix.mli | 14 +++++++++ lib_eio/unix/sockopt.c | 65 +++++++++++++++++++++++++++++++++++++++ lib_eio/unix/sockopt.ml | 43 ++++++++++++++++++++++++++ lib_eio/unix/sockopt.mli | 11 +++++++ lib_eio_posix/net.ml | 18 +++++------ 7 files changed, 142 insertions(+), 12 deletions(-) create mode 100644 lib_eio/unix/sockopt.c create mode 100644 lib_eio/unix/sockopt.ml create mode 100644 lib_eio/unix/sockopt.mli diff --git a/lib_eio/unix/dune b/lib_eio/unix/dune index 258fa7377..4fd06069f 100644 --- a/lib_eio/unix/dune +++ b/lib_eio/unix/dune @@ -4,5 +4,5 @@ (foreign_stubs (language c) (include_dirs include) - (names fork_action stubs)) + (names sockopt fork_action stubs)) (libraries eio unix threads mtime.clock.os)) diff --git a/lib_eio/unix/eio_unix.ml b/lib_eio/unix/eio_unix.ml index 472eade08..f18e8e030 100644 --- a/lib_eio/unix/eio_unix.ml +++ b/lib_eio/unix/eio_unix.ml @@ -3,6 +3,7 @@ module Fd = Fd module Resource = Resource module Private = Private +module Sockopt = Sockopt include Types type socket = Net.stream_socket diff --git a/lib_eio/unix/eio_unix.mli b/lib_eio/unix/eio_unix.mli index 8f83b284b..ad60280fe 100644 --- a/lib_eio/unix/eio_unix.mli +++ b/lib_eio/unix/eio_unix.mli @@ -84,6 +84,20 @@ module Stdenv : sig You can use the functions in {!Eio.Stdenv} to access these fields if you prefer. *) end +module Sockopt : sig + type 'a t = 'a Eio_unix__Sockopt.t = + | SO_KEEPALIVE : bool t + | SO_REUSEADDR : bool t + | SO_REUSEPORT : bool t + | TCP_CORK : int t + | TCP_KEEPCNT : int t + | TCP_KEEPIDLE : int t + | TCP_KEEPINTVL : int t + + val set : Fd.t -> 'a t -> 'a -> unit + val get : Fd.t -> 'a t -> 'a +end + (** API for Eio backends only. *) module Private : sig type _ Effect.t += diff --git a/lib_eio/unix/sockopt.c b/lib_eio/unix/sockopt.c new file mode 100644 index 000000000..323e9cccc --- /dev/null +++ b/lib_eio/unix/sockopt.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#ifdef __linux__ +#include +#include +#endif + +#include +#include +#include + +#ifndef TCP_CORK +#define TCP_CORK (-1) +#endif + +#ifndef TCP_KEEPCNT +#define TCP_KEEPCNT (-1) +#endif + +#ifndef TCP_KEEPIDLE +#define TCP_KEEPIDLE (-1) +#endif + +#ifndef TCP_KEEPINTVL +#define TCP_KEEPINTVL (-1) +#endif + +struct socket_option { + int level; + int option; +}; + +/* Not exported by caml/sockaddr.h */ +CAMLexport value caml_unix_getsockopt_aux(char *, int, int, int, value); +CAMLexport value caml_unix_setsockopt_aux(char *, int, int, int, value, value); + +static struct socket_option sockopt_int[] = { + { IPPROTO_TCP, TCP_CORK }, + { IPPROTO_TCP, TCP_KEEPCNT }, + { IPPROTO_TCP, TCP_KEEPIDLE }, + { IPPROTO_TCP, TCP_KEEPINTVL } +}; + +CAMLprim value eio_unix_getsockopt_int(value vsocket, value voption) +{ + struct socket_option *opt = &(sockopt_int[Int_val(voption)]); + return caml_unix_getsockopt_aux("eio_unix_getsockopt_int", + 1, /* TYPE_INT */ + opt->level, + opt->option, + vsocket); +} + +CAMLprim value eio_unix_setsockopt_int(value vsocket, value voption, value val) +{ + struct socket_option *opt = &(sockopt_int[Int_val(voption)]); + return caml_unix_setsockopt_aux("eio_unix_setsockopt_int", + 1, /* TYPE_INT */ + opt->level, + opt->option, + vsocket, + val); +} diff --git a/lib_eio/unix/sockopt.ml b/lib_eio/unix/sockopt.ml new file mode 100644 index 000000000..4273e6069 --- /dev/null +++ b/lib_eio/unix/sockopt.ml @@ -0,0 +1,43 @@ +type socket_int_option = + EIO_TCP_CORK + | EIO_TCP_KEEPCNT + | EIO_TCP_KEEPIDLE + | EIO_TCP_KEEPINTVL + +external setsockopt_int : Unix.file_descr -> socket_int_option -> int -> unit = + "eio_unix_setsockopt_int" +external getsockopt_int : Unix.file_descr -> socket_int_option -> int = + "eio_unix_getsockopt_int" + +type _ t = + | SO_KEEPALIVE : bool t + | SO_REUSEADDR : bool t + | SO_REUSEPORT : bool t + | TCP_CORK : int t + | TCP_KEEPCNT : int t + | TCP_KEEPIDLE : int t + | TCP_KEEPINTVL : int t + +let set : type a . Fd.t -> a t -> a -> unit = fun sock k v -> + Fd.use_exn "Sockaddr.set" sock @@ fun fd -> + match k with + | TCP_CORK -> setsockopt_int fd EIO_TCP_CORK v + | TCP_KEEPCNT -> setsockopt_int fd EIO_TCP_KEEPCNT v + | TCP_KEEPIDLE -> setsockopt_int fd EIO_TCP_KEEPIDLE v + | TCP_KEEPINTVL -> setsockopt_int fd EIO_TCP_KEEPINTVL v + | SO_KEEPALIVE -> Unix.(setsockopt fd SO_KEEPALIVE v) + | SO_REUSEADDR -> Unix.(setsockopt fd SO_REUSEADDR v) + | SO_REUSEPORT -> Unix.(setsockopt fd SO_REUSEPORT v) + +let get_descr : type a . Unix.file_descr -> a t -> a = fun fd k -> + match k with + | TCP_CORK -> getsockopt_int fd EIO_TCP_CORK + | TCP_KEEPCNT -> getsockopt_int fd EIO_TCP_KEEPCNT + | TCP_KEEPIDLE -> getsockopt_int fd EIO_TCP_KEEPIDLE + | TCP_KEEPINTVL -> getsockopt_int fd EIO_TCP_KEEPINTVL + | SO_KEEPALIVE -> Unix.(getsockopt fd SO_KEEPALIVE) + | SO_REUSEADDR -> Unix.(getsockopt fd SO_REUSEADDR) + | SO_REUSEPORT -> Unix.(getsockopt fd SO_REUSEPORT) + +let get : type a . Fd.t -> a t -> a = fun sock k -> + Fd.use_exn "Sockaddr.get" sock (fun fd -> get_descr fd k) diff --git a/lib_eio/unix/sockopt.mli b/lib_eio/unix/sockopt.mli new file mode 100644 index 000000000..c3e32a15d --- /dev/null +++ b/lib_eio/unix/sockopt.mli @@ -0,0 +1,11 @@ +type _ t = + | SO_KEEPALIVE : bool t + | SO_REUSEADDR : bool t + | SO_REUSEPORT : bool t + | TCP_CORK : int t + | TCP_KEEPCNT : int t + | TCP_KEEPIDLE : int t + | TCP_KEEPINTVL : int t + +val set : Fd.t -> 'a t -> 'a -> unit +val get : Fd.t -> 'a t -> 'a diff --git a/lib_eio_posix/net.ml b/lib_eio_posix/net.ml index 747fc772a..566be54b9 100644 --- a/lib_eio_posix/net.ml +++ b/lib_eio_posix/net.ml @@ -97,11 +97,11 @@ let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr. | `Unix _ | `Tcp _ -> Switch.null_hook in + if reuse_addr then + Eio_unix.Sockopt.(set sock SO_REUSEADDR true); + if reuse_port then + Eio_unix.Sockopt.(set sock SO_REUSEPORT true); Fd.use_exn "listen" sock (fun fd -> - if reuse_addr then - Unix.setsockopt fd Unix.SO_REUSEADDR true; - if reuse_port then - Unix.setsockopt fd Unix.SO_REUSEPORT true; Unix.bind fd addr; Unix.listen fd backlog; ); @@ -126,13 +126,9 @@ let create_datagram_socket ~reuse_addr ~reuse_port ~sw saddr = begin match saddr with | `Udp _ | `Unix _ as saddr -> let addr = Eio_unix.Net.sockaddr_to_unix saddr in - Fd.use_exn "datagram_socket" sock (fun fd -> - if reuse_addr then - Unix.setsockopt fd Unix.SO_REUSEADDR true; - if reuse_port then - Unix.setsockopt fd Unix.SO_REUSEPORT true; - Unix.bind fd addr - ) + if reuse_addr then Eio_unix.Sockopt.(set sock SO_REUSEADDR true); + if reuse_port then Eio_unix.Sockopt.(set sock SO_REUSEPORT true); + Fd.use_exn "datagram_socket" sock (fun fd -> Unix.bind fd addr) | `UdpV4 | `UdpV6 -> () end; (datagram_socket sock :> Eio.Net.datagram_socket) From 92a06fe38597fae48c2f520d2d7d070e62cf23a3 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Thu, 13 Jul 2023 17:42:45 +0100 Subject: [PATCH 2/9] use extensible types and move to Eio_unix.Net --- lib_eio/mock/eio_mock.mli | 2 ++ lib_eio/mock/flow.ml | 9 ++++++++ lib_eio/mock/net.ml | 7 ++++++ lib_eio/net.ml | 9 ++++++++ lib_eio/net.mli | 17 ++++++++++++++ lib_eio/unix/eio_unix.ml | 1 - lib_eio/unix/eio_unix.mli | 14 ------------ lib_eio/unix/net.ml | 48 +++++++++++++++++++++++++++++++++++++++ lib_eio/unix/net.mli | 19 ++++++++++++++++ lib_eio/unix/sockopt.ml | 43 ----------------------------------- lib_eio/unix/sockopt.mli | 11 --------- lib_eio_posix/flow.ml | 5 ++++ lib_eio_posix/net.ml | 14 ++++++++---- 13 files changed, 126 insertions(+), 73 deletions(-) delete mode 100644 lib_eio/unix/sockopt.ml delete mode 100644 lib_eio/unix/sockopt.mli diff --git a/lib_eio/mock/eio_mock.mli b/lib_eio/mock/eio_mock.mli index 28066c18f..3d8a74caf 100644 --- a/lib_eio/mock/eio_mock.mli +++ b/lib_eio/mock/eio_mock.mli @@ -96,6 +96,8 @@ module Flow : sig on_copy_bytes : int Handler.t; set_copy_method : copy_method -> unit; attach_to_switch : Eio.Switch.t -> unit; + getsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a; + setsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a -> unit; > val make : ?pp:string Fmt.t -> string -> t diff --git a/lib_eio/mock/flow.ml b/lib_eio/mock/flow.ml index 50ef67ab6..f008d711f 100644 --- a/lib_eio/mock/flow.ml +++ b/lib_eio/mock/flow.ml @@ -12,6 +12,8 @@ type t = < on_copy_bytes : int Handler.t; set_copy_method : copy_method -> unit; attach_to_switch : Switch.t -> unit; + getsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a; + setsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a -> unit; > let pp_default f s = @@ -34,6 +36,7 @@ let rec takev len = function | x :: _ when Cstruct.length x >= len -> [Cstruct.sub x 0 len] | x :: xs -> x :: takev (len - Cstruct.length x) xs + let make ?(pp=pp_default) label = let on_read = Handler.make (`Raise End_of_file) in let on_copy_bytes = Handler.make (`Return 4096) in @@ -108,6 +111,12 @@ let make ?(pp=pp_default) label = Queue.take on_close () done; traceln "%s: closed" label + + method getsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a = fun _ -> + failwith label + + method setsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a -> unit = fun _ -> + failwith "TODO" end let on_read (t:t) = Handler.seq t#on_read diff --git a/lib_eio/mock/net.ml b/lib_eio/mock/net.ml index 4104c1c39..9f5843b61 100644 --- a/lib_eio/mock/net.ml +++ b/lib_eio/mock/net.ml @@ -91,6 +91,13 @@ let listening_socket label = method close = traceln "%s: closed" label + + method getsockopt _opt = + traceln "%s: getsockopt" label; + failwith "TODO" + + method setsockopt (_: _ Eio.Net.Sockopt.t) _ = + traceln "%s: setsockopt TODO" label end let on_accept (l:listening_socket) actions = diff --git a/lib_eio/net.ml b/lib_eio/net.ml index ee9eeee42..236481bc3 100644 --- a/lib_eio/net.ml +++ b/lib_eio/net.ml @@ -157,10 +157,19 @@ module Sockaddr = struct Format.fprintf f "udp:%a:%d" Ipaddr.pp_for_uri addr port end +module Sockopt = struct + type _ t = .. +end + class virtual socket = object (_ : ) method probe _ = None + method virtual setsockopt : 'a . 'a Sockopt.t -> 'a -> unit + method virtual getsockopt : 'a . 'a Sockopt.t -> 'a end +let setsockopt (s: #socket) opt v = s#setsockopt opt v +let getsockopt (s: #socket) opt = s#getsockopt opt + class virtual stream_socket = object (_ : #socket) inherit Flow.two_way end diff --git a/lib_eio/net.mli b/lib_eio/net.mli index 71f13b542..5eee1fa2b 100644 --- a/lib_eio/net.mli +++ b/lib_eio/net.mli @@ -100,10 +100,17 @@ module Sockaddr : sig val pp : Format.formatter -> [< t] -> unit end +(* Socket options. *) +module Sockopt : sig + type _ t = .. +end + (** {2 Provider Interfaces} *) class virtual socket : object () inherit Generic.t + method virtual setsockopt : 'a . 'a Sockopt.t -> 'a -> unit + method virtual getsockopt : 'a . 'a Sockopt.t -> 'a end class virtual stream_socket : object @@ -136,6 +143,16 @@ class virtual t : object method virtual getnameinfo : Sockaddr.t -> (string * string) end +(** {2 Socket options} *) + +val setsockopt : #socket -> 'a Sockopt.t -> 'a -> unit +(** [setsockopt s opt v] sets the [opt] option to value [v] on socket [s]. + See {!Eio_unix.Net.Sockopt} for common Unix socket options. *) + +val getsockopt : #socket -> 'a Sockopt.t -> 'a +(** [getsockopt s opt] retrieves the [opt] option on socket [fd]. + See {!Eio_unix.Net.Sockopt} for common Unix socket options. *) + (** {2 Out-bound Connections} *) val connect : sw:Switch.t -> #t -> Sockaddr.stream -> stream_socket diff --git a/lib_eio/unix/eio_unix.ml b/lib_eio/unix/eio_unix.ml index f18e8e030..472eade08 100644 --- a/lib_eio/unix/eio_unix.ml +++ b/lib_eio/unix/eio_unix.ml @@ -3,7 +3,6 @@ module Fd = Fd module Resource = Resource module Private = Private -module Sockopt = Sockopt include Types type socket = Net.stream_socket diff --git a/lib_eio/unix/eio_unix.mli b/lib_eio/unix/eio_unix.mli index ad60280fe..8f83b284b 100644 --- a/lib_eio/unix/eio_unix.mli +++ b/lib_eio/unix/eio_unix.mli @@ -84,20 +84,6 @@ module Stdenv : sig You can use the functions in {!Eio.Stdenv} to access these fields if you prefer. *) end -module Sockopt : sig - type 'a t = 'a Eio_unix__Sockopt.t = - | SO_KEEPALIVE : bool t - | SO_REUSEADDR : bool t - | SO_REUSEPORT : bool t - | TCP_CORK : int t - | TCP_KEEPCNT : int t - | TCP_KEEPIDLE : int t - | TCP_KEEPINTVL : int t - - val set : Fd.t -> 'a t -> 'a -> unit - val get : Fd.t -> 'a t -> 'a -end - (** API for Eio backends only. *) module Private : sig type _ Effect.t += diff --git a/lib_eio/unix/net.ml b/lib_eio/unix/net.ml index 95dcb8d48..ccaa52fc0 100644 --- a/lib_eio/unix/net.ml +++ b/lib_eio/unix/net.ml @@ -48,6 +48,54 @@ class virtual t = object method getnameinfo = getnameinfo end +type socket_int_option = + EIO_TCP_CORK + | EIO_TCP_KEEPCNT + | EIO_TCP_KEEPIDLE + | EIO_TCP_KEEPINTVL + +external setsockopt_int : Unix.file_descr -> socket_int_option -> int -> unit = + "eio_unix_setsockopt_int" +external getsockopt_int : Unix.file_descr -> socket_int_option -> int = + "eio_unix_getsockopt_int" + +module Sockopt = struct + type _ Eio.Net.Sockopt.t += + | SO_KEEPALIVE : bool Eio.Net.Sockopt.t + | SO_REUSEADDR : bool Eio.Net.Sockopt.t + | SO_REUSEPORT : bool Eio.Net.Sockopt.t + | TCP_CORK : int Eio.Net.Sockopt.t + | TCP_KEEPCNT : int Eio.Net.Sockopt.t + | TCP_KEEPIDLE : int Eio.Net.Sockopt.t + | TCP_KEEPINTVL : int Eio.Net.Sockopt.t + + let set : type a . Fd.t -> a Eio.Net.Sockopt.t -> a -> unit = fun sock k v -> + Fd.use_exn "Sockopt.set" sock @@ fun fd -> + match k with + | TCP_CORK -> setsockopt_int fd EIO_TCP_CORK v + | TCP_KEEPCNT -> setsockopt_int fd EIO_TCP_KEEPCNT v + | TCP_KEEPIDLE -> setsockopt_int fd EIO_TCP_KEEPIDLE v + | TCP_KEEPINTVL -> setsockopt_int fd EIO_TCP_KEEPINTVL v + | SO_KEEPALIVE -> Unix.(setsockopt fd SO_KEEPALIVE v) + | SO_REUSEADDR -> Unix.(setsockopt fd SO_REUSEADDR v) + | SO_REUSEPORT -> Unix.(setsockopt fd SO_REUSEPORT v) + | _ -> raise (Invalid_argument "TODO pp value") + + let get_descr : type a . Unix.file_descr -> a Eio.Net.Sockopt.t -> a = fun fd k -> + match k with + | TCP_CORK -> getsockopt_int fd EIO_TCP_CORK + | TCP_KEEPCNT -> getsockopt_int fd EIO_TCP_KEEPCNT + | TCP_KEEPIDLE -> getsockopt_int fd EIO_TCP_KEEPIDLE + | TCP_KEEPINTVL -> getsockopt_int fd EIO_TCP_KEEPINTVL + | SO_KEEPALIVE -> Unix.(getsockopt fd SO_KEEPALIVE) + | SO_REUSEADDR -> Unix.(getsockopt fd SO_REUSEADDR) + | SO_REUSEPORT -> Unix.(getsockopt fd SO_REUSEPORT) + | _ -> raise (Invalid_argument "TODO pp value") + + let get : type a . Fd.t -> a Eio.Net.Sockopt.t -> a = fun sock k -> + Fd.use_exn "Sockopt.get" sock (fun fd -> get_descr fd k) +end + [@@@alert "-unstable"] type _ Effect.t += diff --git a/lib_eio/unix/net.mli b/lib_eio/unix/net.mli index 4b53c58c6..08812d371 100644 --- a/lib_eio/unix/net.mli +++ b/lib_eio/unix/net.mli @@ -76,6 +76,25 @@ val socketpair_datagram : This creates OS-level resources using [socketpair(2)]. Note that, like all FDs created by Eio, they are both marked as close-on-exec by default. *) +module Sockopt : sig + (** Socket options *) + + type _ Eio.Net.Sockopt.t += + SO_KEEPALIVE : bool Eio.Net.Sockopt.t + | SO_REUSEADDR : bool Eio.Net.Sockopt.t + | SO_REUSEPORT : bool Eio.Net.Sockopt.t + | TCP_CORK : int Eio.Net.Sockopt.t (* TODO These are Linux-only; move to Eio_linux.Net? *) + | TCP_KEEPCNT : int Eio.Net.Sockopt.t + | TCP_KEEPIDLE : int Eio.Net.Sockopt.t + | TCP_KEEPINTVL : int Eio.Net.Sockopt.t + + val set : Fd.t -> 'a Eio.Net.Sockopt.t -> 'a -> unit + (** [set fd opt v] sets the [opt] option to value [v] on socket [fd]. *) + + val get : Fd.t -> 'a Eio.Net.Sockopt.t -> 'a + (** [get fd opt v] retrieves the [opt] option on socket [fd]. *) +end + (** {2 Private API for backends} *) val getnameinfo : Eio.Net.Sockaddr.t -> (string * string) diff --git a/lib_eio/unix/sockopt.ml b/lib_eio/unix/sockopt.ml deleted file mode 100644 index 4273e6069..000000000 --- a/lib_eio/unix/sockopt.ml +++ /dev/null @@ -1,43 +0,0 @@ -type socket_int_option = - EIO_TCP_CORK - | EIO_TCP_KEEPCNT - | EIO_TCP_KEEPIDLE - | EIO_TCP_KEEPINTVL - -external setsockopt_int : Unix.file_descr -> socket_int_option -> int -> unit = - "eio_unix_setsockopt_int" -external getsockopt_int : Unix.file_descr -> socket_int_option -> int = - "eio_unix_getsockopt_int" - -type _ t = - | SO_KEEPALIVE : bool t - | SO_REUSEADDR : bool t - | SO_REUSEPORT : bool t - | TCP_CORK : int t - | TCP_KEEPCNT : int t - | TCP_KEEPIDLE : int t - | TCP_KEEPINTVL : int t - -let set : type a . Fd.t -> a t -> a -> unit = fun sock k v -> - Fd.use_exn "Sockaddr.set" sock @@ fun fd -> - match k with - | TCP_CORK -> setsockopt_int fd EIO_TCP_CORK v - | TCP_KEEPCNT -> setsockopt_int fd EIO_TCP_KEEPCNT v - | TCP_KEEPIDLE -> setsockopt_int fd EIO_TCP_KEEPIDLE v - | TCP_KEEPINTVL -> setsockopt_int fd EIO_TCP_KEEPINTVL v - | SO_KEEPALIVE -> Unix.(setsockopt fd SO_KEEPALIVE v) - | SO_REUSEADDR -> Unix.(setsockopt fd SO_REUSEADDR v) - | SO_REUSEPORT -> Unix.(setsockopt fd SO_REUSEPORT v) - -let get_descr : type a . Unix.file_descr -> a t -> a = fun fd k -> - match k with - | TCP_CORK -> getsockopt_int fd EIO_TCP_CORK - | TCP_KEEPCNT -> getsockopt_int fd EIO_TCP_KEEPCNT - | TCP_KEEPIDLE -> getsockopt_int fd EIO_TCP_KEEPIDLE - | TCP_KEEPINTVL -> getsockopt_int fd EIO_TCP_KEEPINTVL - | SO_KEEPALIVE -> Unix.(getsockopt fd SO_KEEPALIVE) - | SO_REUSEADDR -> Unix.(getsockopt fd SO_REUSEADDR) - | SO_REUSEPORT -> Unix.(getsockopt fd SO_REUSEPORT) - -let get : type a . Fd.t -> a t -> a = fun sock k -> - Fd.use_exn "Sockaddr.get" sock (fun fd -> get_descr fd k) diff --git a/lib_eio/unix/sockopt.mli b/lib_eio/unix/sockopt.mli deleted file mode 100644 index c3e32a15d..000000000 --- a/lib_eio/unix/sockopt.mli +++ /dev/null @@ -1,11 +0,0 @@ -type _ t = - | SO_KEEPALIVE : bool t - | SO_REUSEADDR : bool t - | SO_REUSEPORT : bool t - | TCP_CORK : int t - | TCP_KEEPCNT : int t - | TCP_KEEPIDLE : int t - | TCP_KEEPINTVL : int t - -val set : Fd.t -> 'a t -> 'a -> unit -val get : Fd.t -> 'a t -> 'a diff --git a/lib_eio_posix/flow.ml b/lib_eio_posix/flow.ml index dd1f3eb25..71d844d02 100644 --- a/lib_eio_posix/flow.ml +++ b/lib_eio_posix/flow.ml @@ -65,6 +65,9 @@ let shutdown fd cmd = | Unix.Unix_error (Unix.ENOTCONN, _, _) -> () | Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg) +let setsockopt fd opt v = Eio_unix.Net.Sockopt.set fd opt v +let getsockopt fd opt = Eio_unix.Net.Sockopt.get fd opt + let of_fd fd = object (_ : ) method fd = fd @@ -83,6 +86,8 @@ let of_fd fd = object (_ : ) method write bufs = write_bufs fd bufs method shutdown cmd = shutdown fd cmd method close = Fd.close fd + method setsockopt opt v = setsockopt fd opt v + method getsockopt opt = getsockopt fd opt method probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Resource.FD -> Some fd diff --git a/lib_eio_posix/net.ml b/lib_eio_posix/net.ml index 566be54b9..50e1704d4 100644 --- a/lib_eio_posix/net.ml +++ b/lib_eio_posix/net.ml @@ -31,6 +31,9 @@ let listening_socket ~hook fd = object method! probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Resource.FD -> Some fd | _ -> None + + method getsockopt opt = Eio_unix.Net.Sockopt.get fd opt + method setsockopt opt v = Eio_unix.Net.Sockopt.set fd opt v end let datagram_socket sock = object @@ -48,6 +51,9 @@ let datagram_socket sock = object method recv buf = let addr, recv = Err.run (Low_level.recv_msg sock) [| buf |] in Eio_unix.Net.sockaddr_of_unix_datagram addr, recv + + method getsockopt opt = Eio_unix.Net.Sockopt.get sock opt + method setsockopt opt v = Eio_unix.Net.Sockopt.set sock opt v end (* https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml *) @@ -98,9 +104,9 @@ let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr. Switch.null_hook in if reuse_addr then - Eio_unix.Sockopt.(set sock SO_REUSEADDR true); + Eio_unix.Net.Sockopt.(set sock SO_REUSEADDR true); if reuse_port then - Eio_unix.Sockopt.(set sock SO_REUSEPORT true); + Eio_unix.Net.Sockopt.(set sock SO_REUSEPORT true); Fd.use_exn "listen" sock (fun fd -> Unix.bind fd addr; Unix.listen fd backlog; @@ -126,8 +132,8 @@ let create_datagram_socket ~reuse_addr ~reuse_port ~sw saddr = begin match saddr with | `Udp _ | `Unix _ as saddr -> let addr = Eio_unix.Net.sockaddr_to_unix saddr in - if reuse_addr then Eio_unix.Sockopt.(set sock SO_REUSEADDR true); - if reuse_port then Eio_unix.Sockopt.(set sock SO_REUSEPORT true); + if reuse_addr then Eio_unix.Net.Sockopt.(set sock SO_REUSEADDR true); + if reuse_port then Eio_unix.Net.Sockopt.(set sock SO_REUSEPORT true); Fd.use_exn "datagram_socket" sock (fun fd -> Unix.bind fd addr) | `UdpV4 | `UdpV6 -> () end; From 804a18bb9265b65ed01ea345a1ce440ff450b37f Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sat, 22 Jul 2023 15:58:50 +0100 Subject: [PATCH 3/9] add TCP_DEFER_ACCEPT and TCP_NO_DELAY socket options --- lib_eio/unix/net.ml | 8 ++++++++ lib_eio/unix/net.mli | 2 ++ lib_eio/unix/sockopt.c | 12 +++++++++++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/lib_eio/unix/net.ml b/lib_eio/unix/net.ml index ccaa52fc0..dd29fd508 100644 --- a/lib_eio/unix/net.ml +++ b/lib_eio/unix/net.ml @@ -53,6 +53,8 @@ type socket_int_option = | EIO_TCP_KEEPCNT | EIO_TCP_KEEPIDLE | EIO_TCP_KEEPINTVL + | EIO_TCP_DEFER_ACCEPT + | EIO_TCP_NODELAY external setsockopt_int : Unix.file_descr -> socket_int_option -> int -> unit = "eio_unix_setsockopt_int" @@ -64,10 +66,12 @@ module Sockopt = struct | SO_KEEPALIVE : bool Eio.Net.Sockopt.t | SO_REUSEADDR : bool Eio.Net.Sockopt.t | SO_REUSEPORT : bool Eio.Net.Sockopt.t + | TCP_NODELAY : bool Eio.Net.Sockopt.t | TCP_CORK : int Eio.Net.Sockopt.t | TCP_KEEPCNT : int Eio.Net.Sockopt.t | TCP_KEEPIDLE : int Eio.Net.Sockopt.t | TCP_KEEPINTVL : int Eio.Net.Sockopt.t + | TCP_DEFER_ACCEPT : int Eio.Net.Sockopt.t let set : type a . Fd.t -> a Eio.Net.Sockopt.t -> a -> unit = fun sock k v -> Fd.use_exn "Sockopt.set" sock @@ fun fd -> @@ -76,6 +80,8 @@ module Sockopt = struct | TCP_KEEPCNT -> setsockopt_int fd EIO_TCP_KEEPCNT v | TCP_KEEPIDLE -> setsockopt_int fd EIO_TCP_KEEPIDLE v | TCP_KEEPINTVL -> setsockopt_int fd EIO_TCP_KEEPINTVL v + | TCP_DEFER_ACCEPT -> setsockopt_int fd EIO_TCP_DEFER_ACCEPT v + | TCP_NODELAY -> setsockopt_int fd EIO_TCP_DEFER_ACCEPT (if v then 1 else 0) | SO_KEEPALIVE -> Unix.(setsockopt fd SO_KEEPALIVE v) | SO_REUSEADDR -> Unix.(setsockopt fd SO_REUSEADDR v) | SO_REUSEPORT -> Unix.(setsockopt fd SO_REUSEPORT v) @@ -87,6 +93,8 @@ module Sockopt = struct | TCP_KEEPCNT -> getsockopt_int fd EIO_TCP_KEEPCNT | TCP_KEEPIDLE -> getsockopt_int fd EIO_TCP_KEEPIDLE | TCP_KEEPINTVL -> getsockopt_int fd EIO_TCP_KEEPINTVL + | TCP_DEFER_ACCEPT -> getsockopt_int fd EIO_TCP_DEFER_ACCEPT + | TCP_NODELAY -> getsockopt_int fd EIO_TCP_NODELAY = 1 | SO_KEEPALIVE -> Unix.(getsockopt fd SO_KEEPALIVE) | SO_REUSEADDR -> Unix.(getsockopt fd SO_REUSEADDR) | SO_REUSEPORT -> Unix.(getsockopt fd SO_REUSEPORT) diff --git a/lib_eio/unix/net.mli b/lib_eio/unix/net.mli index 08812d371..f286feb68 100644 --- a/lib_eio/unix/net.mli +++ b/lib_eio/unix/net.mli @@ -87,6 +87,8 @@ module Sockopt : sig | TCP_KEEPCNT : int Eio.Net.Sockopt.t | TCP_KEEPIDLE : int Eio.Net.Sockopt.t | TCP_KEEPINTVL : int Eio.Net.Sockopt.t + | TCP_DEFER_ACCEPT : int Eio.Net.Sockopt.t + | TCP_NODELAY : bool Eio.Net.Sockopt.t val set : Fd.t -> 'a Eio.Net.Sockopt.t -> 'a -> unit (** [set fd opt v] sets the [opt] option to value [v] on socket [fd]. *) diff --git a/lib_eio/unix/sockopt.c b/lib_eio/unix/sockopt.c index 323e9cccc..351222edc 100644 --- a/lib_eio/unix/sockopt.c +++ b/lib_eio/unix/sockopt.c @@ -27,6 +27,14 @@ #define TCP_KEEPINTVL (-1) #endif +#ifndef TCP_DEFER_ACCEPT +#define TCP_DEFER_ACCEPT (-1) +#endif + +#ifndef TCP_NODELAY +#define TCP_NODELAY (-1) +#endif + struct socket_option { int level; int option; @@ -40,7 +48,9 @@ static struct socket_option sockopt_int[] = { { IPPROTO_TCP, TCP_CORK }, { IPPROTO_TCP, TCP_KEEPCNT }, { IPPROTO_TCP, TCP_KEEPIDLE }, - { IPPROTO_TCP, TCP_KEEPINTVL } + { IPPROTO_TCP, TCP_KEEPINTVL }, + { IPPROTO_TCP, TCP_DEFER_ACCEPT }, + { IPPROTO_TCP, TCP_NODELAY }, }; CAMLprim value eio_unix_getsockopt_int(value vsocket, value voption) From e329d2156b88ef566138126054aba6b807a2a7a3 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sat, 22 Jul 2023 16:02:29 +0100 Subject: [PATCH 4/9] sockopt: build on windows --- lib_eio/unix/sockopt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib_eio/unix/sockopt.c b/lib_eio/unix/sockopt.c index 351222edc..0fff27d54 100644 --- a/lib_eio/unix/sockopt.c +++ b/lib_eio/unix/sockopt.c @@ -1,6 +1,9 @@ #include #include + +#ifndef _WIN32 #include +#endif #ifdef __linux__ #include From fb941d66969a94d2c97f0f63b0d5063967172d19 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sat, 22 Jul 2023 15:29:18 +0000 Subject: [PATCH 5/9] sockopt: add Linux support --- lib_eio_linux/eio_linux.ml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib_eio_linux/eio_linux.ml b/lib_eio_linux/eio_linux.ml index fcab8996c..05eea76b1 100644 --- a/lib_eio_linux/eio_linux.ml +++ b/lib_eio_linux/eio_linux.ml @@ -118,6 +118,14 @@ let datagram_socket sock = object method recv buf = let addr, recv = Low_level.recv_msg sock [buf] in Eio_unix.Net.sockaddr_of_unix_datagram (Uring.Sockaddr.get addr), recv + + method setsockopt opt v = + (* No uring support for sockopt yet, but will be in the future. + https://github.com/axboe/liburing/issues/234#issuecomment-1080605124 *) + Eio_unix.Net.Sockopt.set sock opt v + + method getsockopt opt = + Eio_unix.Net.Sockopt.get sock opt end let flow fd = @@ -166,6 +174,12 @@ let flow fd = | `Receive -> Unix.SHUTDOWN_RECEIVE | `Send -> Unix.SHUTDOWN_SEND | `All -> Unix.SHUTDOWN_ALL + + method setsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a -> unit = fun opt v -> + Eio_unix.Net.Sockopt.set fd opt v + + method getsockopt : 'a . 'a Eio.Net.Sockopt.t -> 'a = fun opt -> + Eio_unix.Net.Sockopt.get fd opt end let source fd = (flow fd :> source) @@ -189,6 +203,9 @@ let listening_socket fd = object method! probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Resource.FD -> Some fd | _ -> None + + method setsockopt opt v = Eio_unix.Net.Sockopt.set fd opt v + method getsockopt opt = Eio_unix.Net.Sockopt.get fd opt end let socket_domain_of = function From 65fa53b819da3a35e677eb0fdc31b2c9e7420b8f Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sat, 22 Jul 2023 16:54:45 +0100 Subject: [PATCH 6/9] sockopt: fix windows build --- lib_eio_windows/flow.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib_eio_windows/flow.ml b/lib_eio_windows/flow.ml index dccf0aafa..929ddd114 100755 --- a/lib_eio_windows/flow.ml +++ b/lib_eio_windows/flow.ml @@ -81,6 +81,12 @@ let of_fd fd = object (_ : ) method probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Resource.FD -> Some fd | _ -> None + + method getsockopt : type a. a Eio.Net.Sockopt.t -> a = fun opt -> + Eio_unix.Net.Sockopt.get fd opt + + method setsockopt : type a. a Eio.Net.Sockopt.t -> a -> unit = fun opt v -> + Eio_unix.Net.Sockopt.set fd opt v end let secure_random = object From 5f4d9fe52bf5ad6c53bb5a9f064375be2d4b1644 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sat, 22 Jul 2023 18:10:43 +0100 Subject: [PATCH 7/9] more windows --- lib_eio_windows/net.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib_eio_windows/net.ml b/lib_eio_windows/net.ml index 659eacdac..753342cc4 100755 --- a/lib_eio_windows/net.ml +++ b/lib_eio_windows/net.ml @@ -31,6 +31,12 @@ let listening_socket ~hook fd = object method! probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Resource.FD -> Some fd | _ -> None + + method getsockopt : type a. a Eio.Net.Sockopt.t -> a = fun opt -> + Eio_unix.Net.Sockopt.get fd opt + + method setsockopt : type a. a Eio.Net.Sockopt.t -> a -> unit = fun opt v -> + Eio_unix.Net.Sockopt.set fd opt v end (* todo: would be nice to avoid copying between bytes and cstructs here *) From 287940d38d81dbbb478e883f5d0c2a15972bb726 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sun, 23 Jul 2023 13:13:20 +0100 Subject: [PATCH 8/9] more windows --- lib_eio_windows/net.ml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib_eio_windows/net.ml b/lib_eio_windows/net.ml index 753342cc4..46a489ca2 100755 --- a/lib_eio_windows/net.ml +++ b/lib_eio_windows/net.ml @@ -57,6 +57,12 @@ let datagram_socket sock = object let recv, addr = Err.run (Low_level.recv_msg sock) b in Cstruct.blit_from_bytes b 0 buf 0 recv; Eio_unix.Net.sockaddr_of_unix_datagram addr, recv + + method getsockopt : type a. a Eio.Net.Sockopt.t -> a = fun opt -> + Eio_unix.Net.Sockopt.get fd opt + + method setsockopt : type a. a Eio.Net.Sockopt.t -> a -> unit = fun opt v -> + Eio_unix.Net.Sockopt.set fd opt v end (* https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml *) From b12fc6562d086df5f162c2f36958e1c0942ea312 Mon Sep 17 00:00:00 2001 From: Anil Madhavapeddy Date: Sun, 23 Jul 2023 13:30:23 +0100 Subject: [PATCH 9/9] more windows --- lib_eio_windows/net.ml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib_eio_windows/net.ml b/lib_eio_windows/net.ml index 46a489ca2..6a9b9a4d9 100755 --- a/lib_eio_windows/net.ml +++ b/lib_eio_windows/net.ml @@ -59,10 +59,10 @@ let datagram_socket sock = object Eio_unix.Net.sockaddr_of_unix_datagram addr, recv method getsockopt : type a. a Eio.Net.Sockopt.t -> a = fun opt -> - Eio_unix.Net.Sockopt.get fd opt + Eio_unix.Net.Sockopt.get sock opt method setsockopt : type a. a Eio.Net.Sockopt.t -> a -> unit = fun opt v -> - Eio_unix.Net.Sockopt.set fd opt v + Eio_unix.Net.Sockopt.set sock opt v end (* https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml *)