Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
## v1.4

Changes:

- Add support for setting/getting socket options (@avsm #575)
This adds a Eio.Net.Sockopt.t extensible variant where portable
options are exposed, and backend-specific sockopts for Unix/Linux.

## v1.3

Bug fixes:
Expand Down
3 changes: 3 additions & 0 deletions lib_eio/mock/flow.ml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ module Mock_flow = struct
done;
traceln "%s: closed" t.label

let setsockopt t opt v = Sockopt.setsockopt t.label opt v
let getsockopt t opt = Sockopt.getsockopt t.label opt

let make ?(pp=pp_default) label =
{
pp;
Expand Down
3 changes: 3 additions & 0 deletions lib_eio/mock/net.ml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ module Listening_socket = struct

let listening_addr { listening_addr; _ } = listening_addr

let setsockopt t opt v = Sockopt.setsockopt t.label opt v
let getsockopt t opt = Sockopt.getsockopt t.label opt

type (_, _, _) Eio.Resource.pi += Type : ('t, 't -> t, listening_socket_ty) Eio.Resource.pi
let raw (Eio.Resource.T (t, ops)) = Eio.Resource.get ops Type t
end
Expand Down
47 changes: 47 additions & 0 deletions lib_eio/mock/sockopt.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
open Eio.Std

let pp_sockopt_value : type a. a Eio.Net.Sockopt.t -> a -> string = fun opt v ->
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> Fmt.str "SO_DEBUG = %b" v
Comment on lines +3 to +5
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be slightly simpler and more consistent to make this an actual pretty-printer, e.g.

Suggested change
let pp_sockopt_value : type a. a Eio.Net.Sockopt.t -> a -> string = fun opt v ->
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> Fmt.str "SO_DEBUG = %b" v
let pp_sockopt_value (type a) (opt : a Eio.Net.Sockopt.t) f (v : a) =
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> Fmt.pf f "SO_DEBUG = %b" v

| Eio.Net.Sockopt.SO_BROADCAST -> Fmt.str "SO_BROADCAST = %b" v
| Eio.Net.Sockopt.SO_REUSEADDR -> Fmt.str "SO_REUSEADDR = %b" v
| Eio.Net.Sockopt.SO_KEEPALIVE -> Fmt.str "SO_KEEPALIVE = %b" v
| Eio.Net.Sockopt.SO_DONTROUTE -> Fmt.str "SO_DONTROUTE = %b" v
| Eio.Net.Sockopt.SO_OOBINLINE -> Fmt.str "SO_OOBINLINE = %b" v
| Eio.Net.Sockopt.TCP_NODELAY -> Fmt.str "TCP_NODELAY = %b" v
| Eio.Net.Sockopt.IPV6_ONLY -> Fmt.str "IPV6_ONLY = %b" v
| Eio.Net.Sockopt.SO_REUSEPORT -> Fmt.str "SO_REUSEPORT = %b" v
| Eio.Net.Sockopt.SO_SNDBUF -> Fmt.str "SO_SNDBUF = %d" v
| Eio.Net.Sockopt.SO_RCVBUF -> Fmt.str "SO_RCVBUF = %d" v
| Eio.Net.Sockopt.SO_TYPE -> Fmt.str "SO_TYPE = %d" v
| Eio.Net.Sockopt.SO_RCVLOWAT -> Fmt.str "SO_RCVLOWAT = %d" v
| Eio.Net.Sockopt.SO_SNDLOWAT -> Fmt.str "SO_SNDLOWAT = %d" v
| Eio.Net.Sockopt.SO_LINGER -> Fmt.str "SO_LINGER = %s" (match v with None -> "None" | Some n -> string_of_int n)
| Eio.Net.Sockopt.SO_RCVTIMEO -> Fmt.str "SO_RCVTIMEO = %f" v
| Eio.Net.Sockopt.SO_SNDTIMEO -> Fmt.str "SO_SNDTIMEO = %f" v
| _ -> "unknown"

let setsockopt : type a. string -> a Eio.Net.Sockopt.t -> a -> unit = fun label opt v ->
let opt_desc = pp_sockopt_value opt v in
traceln "%s: setsockopt %s" label opt_desc
Comment on lines +24 to +26
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then this is just:

Suggested change
let setsockopt : type a. string -> a Eio.Net.Sockopt.t -> a -> unit = fun label opt v ->
let opt_desc = pp_sockopt_value opt v in
traceln "%s: setsockopt %s" label opt_desc
let setsockopt label opt v =
traceln "%s: setsockopt %a" label (pp_sockopt_value opt) v


let getsockopt : type a. string -> a Eio.Net.Sockopt.t -> a = fun label opt ->
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> traceln "%s: getsockopt SO_DEBUG = false" label; false
| Eio.Net.Sockopt.SO_BROADCAST -> traceln "%s: getsockopt SO_BROADCAST = false" label; false
| Eio.Net.Sockopt.SO_REUSEADDR -> traceln "%s: getsockopt SO_REUSEADDR = false" label; false
| Eio.Net.Sockopt.SO_KEEPALIVE -> traceln "%s: getsockopt SO_KEEPALIVE = false" label; false
| Eio.Net.Sockopt.SO_DONTROUTE -> traceln "%s: getsockopt SO_DONTROUTE = false" label; false
| Eio.Net.Sockopt.SO_OOBINLINE -> traceln "%s: getsockopt SO_OOBINLINE = false" label; false
| Eio.Net.Sockopt.TCP_NODELAY -> traceln "%s: getsockopt TCP_NODELAY = false" label; false
| Eio.Net.Sockopt.IPV6_ONLY -> traceln "%s: getsockopt IPV6_ONLY = false" label; false
| Eio.Net.Sockopt.SO_REUSEPORT -> traceln "%s: getsockopt SO_REUSEPORT = false" label; false
| Eio.Net.Sockopt.SO_SNDBUF -> traceln "%s: getsockopt SO_SNDBUF = 0" label; 0
| Eio.Net.Sockopt.SO_RCVBUF -> traceln "%s: getsockopt SO_RCVBUF = 0" label; 0
| Eio.Net.Sockopt.SO_TYPE -> traceln "%s: getsockopt SO_TYPE = 0" label; 0
| Eio.Net.Sockopt.SO_RCVLOWAT -> traceln "%s: getsockopt SO_RCVLOWAT = 0" label; 0
| Eio.Net.Sockopt.SO_SNDLOWAT -> traceln "%s: getsockopt SO_SNDLOWAT = 0" label; 0
| Eio.Net.Sockopt.SO_LINGER -> traceln "%s: getsockopt SO_LINGER = None" label; None
| Eio.Net.Sockopt.SO_RCVTIMEO -> traceln "%s: getsockopt SO_RCVTIMEO = 0.0" label; 0.0
| Eio.Net.Sockopt.SO_SNDTIMEO -> traceln "%s: getsockopt SO_SNDTIMEO = 0.0" label; 0.0
| _ -> raise (Failure "Mock getsockopt not implemented")
Comment on lines +28 to +47
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems a shame not to reuse the printer from above:

Suggested change
let getsockopt : type a. string -> a Eio.Net.Sockopt.t -> a = fun label opt ->
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> traceln "%s: getsockopt SO_DEBUG = false" label; false
| Eio.Net.Sockopt.SO_BROADCAST -> traceln "%s: getsockopt SO_BROADCAST = false" label; false
| Eio.Net.Sockopt.SO_REUSEADDR -> traceln "%s: getsockopt SO_REUSEADDR = false" label; false
| Eio.Net.Sockopt.SO_KEEPALIVE -> traceln "%s: getsockopt SO_KEEPALIVE = false" label; false
| Eio.Net.Sockopt.SO_DONTROUTE -> traceln "%s: getsockopt SO_DONTROUTE = false" label; false
| Eio.Net.Sockopt.SO_OOBINLINE -> traceln "%s: getsockopt SO_OOBINLINE = false" label; false
| Eio.Net.Sockopt.TCP_NODELAY -> traceln "%s: getsockopt TCP_NODELAY = false" label; false
| Eio.Net.Sockopt.IPV6_ONLY -> traceln "%s: getsockopt IPV6_ONLY = false" label; false
| Eio.Net.Sockopt.SO_REUSEPORT -> traceln "%s: getsockopt SO_REUSEPORT = false" label; false
| Eio.Net.Sockopt.SO_SNDBUF -> traceln "%s: getsockopt SO_SNDBUF = 0" label; 0
| Eio.Net.Sockopt.SO_RCVBUF -> traceln "%s: getsockopt SO_RCVBUF = 0" label; 0
| Eio.Net.Sockopt.SO_TYPE -> traceln "%s: getsockopt SO_TYPE = 0" label; 0
| Eio.Net.Sockopt.SO_RCVLOWAT -> traceln "%s: getsockopt SO_RCVLOWAT = 0" label; 0
| Eio.Net.Sockopt.SO_SNDLOWAT -> traceln "%s: getsockopt SO_SNDLOWAT = 0" label; 0
| Eio.Net.Sockopt.SO_LINGER -> traceln "%s: getsockopt SO_LINGER = None" label; None
| Eio.Net.Sockopt.SO_RCVTIMEO -> traceln "%s: getsockopt SO_RCVTIMEO = 0.0" label; 0.0
| Eio.Net.Sockopt.SO_SNDTIMEO -> traceln "%s: getsockopt SO_SNDTIMEO = 0.0" label; 0.0
| _ -> raise (Failure "Mock getsockopt not implemented")
let default (type a) (opt : a Eio.Net.Sockopt.t) : a =
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> false
| Eio.Net.Sockopt.SO_BROADCAST -> false
| Eio.Net.Sockopt.SO_REUSEADDR -> false
| Eio.Net.Sockopt.SO_KEEPALIVE -> false
| Eio.Net.Sockopt.SO_DONTROUTE -> false
| Eio.Net.Sockopt.SO_OOBINLINE -> false
| Eio.Net.Sockopt.TCP_NODELAY -> false
| Eio.Net.Sockopt.IPV6_ONLY -> false
| Eio.Net.Sockopt.SO_REUSEPORT -> false
| Eio.Net.Sockopt.SO_SNDBUF -> 0
| Eio.Net.Sockopt.SO_RCVBUF -> 0
| Eio.Net.Sockopt.SO_TYPE -> 0
| Eio.Net.Sockopt.SO_RCVLOWAT -> 0
| Eio.Net.Sockopt.SO_SNDLOWAT -> 0
| Eio.Net.Sockopt.SO_LINGER -> None
| Eio.Net.Sockopt.SO_RCVTIMEO -> 0.0
| Eio.Net.Sockopt.SO_SNDTIMEO -> 0.0
| _ -> raise (Failure "Mock getsockopt not implemented")
let getsockopt label opt =
let v = default opt in
traceln "%s: getsockopt %a" label (pp_sockopt_value opt) v;
v

(though not 100% sure it's useful to log gets... might be a bit noisy)

21 changes: 21 additions & 0 deletions lib_eio/mock/sockopt.mli
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
(** Mock socket option helpers *)

val pp_sockopt_value : 'a Eio.Net.Sockopt.t -> 'a -> string
(** [pp_sockopt_value opt v] formats socket option [opt] with value [v] as a string
for trace output. Returns [unknown] for unrecognised options. *)

val setsockopt : string -> 'a Eio.Net.Sockopt.t -> 'a -> unit
(** [setsockopt label opt v] simulates setting socket option [opt] to value [v].
Outputs a trace message using [label] to identify the socket. *)

val getsockopt : string -> 'a Eio.Net.Sockopt.t -> 'a
(** [getsockopt label opt] simulates getting the value of socket option [opt].
Outputs a trace message using [label] to identify the socket.
Returns default mock values for all standard options.

Default values:
- Boolean options: [false]
- Integer options: [0]
- Timeout options: [0.0]

@raise Failure if the option is not recognized. *)
47 changes: 46 additions & 1 deletion lib_eio/net.ml
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,29 @@ module Sockaddr = struct
Format.fprintf f "udp:%a:%d" Ipaddr.pp_for_uri addr port
end

module Sockopt = struct
type _ t = ..

type _ t +=
| SO_DEBUG : bool t
| SO_BROADCAST : bool t
| SO_REUSEADDR : bool t
| SO_KEEPALIVE : bool t
| SO_DONTROUTE : bool t
| SO_OOBINLINE : bool t
| TCP_NODELAY : bool t
| IPV6_ONLY : bool t
| SO_REUSEPORT : bool t
| SO_SNDBUF : int t
| SO_RCVBUF : int t
| SO_TYPE : int t
| SO_RCVLOWAT : int t
| SO_SNDLOWAT : int t
| SO_LINGER : int option t
| SO_RCVTIMEO : float t
| SO_SNDTIMEO : float t
end

type socket_ty = [`Socket | `Close]
type 'a socket = ([> socket_ty] as 'a) r

Expand All @@ -181,22 +204,34 @@ type 'a t = 'a r
constraint 'a = [> [> `Generic] ty]

module Pi = struct
module type SOCKET = sig
type t
val setsockopt : t -> 'a Sockopt.t -> 'a -> unit
val getsockopt : t -> 'a Sockopt.t -> 'a
end

type (_, _, _) Resource.pi +=
| Socket : ('t, (module SOCKET with type t = 't), [> `Socket]) Resource.pi

module type STREAM_SOCKET = sig
type tag
include Flow.Pi.SHUTDOWN
include Flow.Pi.SOURCE with type t := t
include Flow.Pi.SINK with type t := t
include SOCKET with type t := t
val close : t -> unit
end

let stream_socket (type t tag) (module X : STREAM_SOCKET with type t = t and type tag = tag) =
Resource.handler @@
H (Resource.Close, X.close) ::
H (Socket, (module X)) ::
Resource.bindings (Flow.Pi.two_way (module X))

module type DATAGRAM_SOCKET = sig
type tag
include Flow.Pi.SHUTDOWN
include SOCKET with type t := t
val send : t -> ?dst:Sockaddr.datagram -> Cstruct.t list -> unit
val recv : t -> Cstruct.t -> Sockaddr.datagram * int
val close : t -> unit
Expand All @@ -208,14 +243,15 @@ module Pi = struct
let datagram_socket (type t tag) (module X : DATAGRAM_SOCKET with type t = t and type tag = tag) =
Resource.handler @@
Resource.bindings (Flow.Pi.shutdown (module X)) @ [
H (Socket, (module X));
H (Datagram_socket, (module X));
H (Resource.Close, X.close)
]

module type LISTENING_SOCKET = sig
type t
type tag

include SOCKET with type t := t
val accept : t -> sw:Switch.t -> tag stream_socket_ty r * Sockaddr.stream
val close : t -> unit
val listening_addr : t -> Sockaddr.stream
Expand All @@ -227,6 +263,7 @@ module Pi = struct
let listening_socket (type t tag) (module X : LISTENING_SOCKET with type t = t and type tag = tag) =
Resource.handler [
H (Resource.Close, X.close);
H (Socket, (module X));
H (Listening_socket, (module X))
]

Expand Down Expand Up @@ -278,6 +315,14 @@ let accept_fork ~sw (t : [> 'a listening_socket_ty] r) ~on_error handle =
)
)

let setsockopt (Resource.T (t, ops)) opt v =
let module X = (val (Resource.get ops Pi.Socket)) in
X.setsockopt t opt v

let getsockopt (Resource.T (t, ops)) opt =
let module X = (val (Resource.get ops Pi.Socket)) in
X.getsockopt t opt

let listening_addr (type tag) (Resource.T (t, ops) : [> tag listening_socket_ty] r) =
let module X = (val (Resource.get ops Pi.Listening_socket)) in
X.listening_addr t
Expand Down
49 changes: 48 additions & 1 deletion lib_eio/net.mli
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,33 @@ module Sockaddr : sig
val pp : Format.formatter -> [< t] -> unit
end

(** Socket options. *)
module Sockopt : sig
(** An extensible type for socket options. Portable options can be defined
here, while platform-specific options can be added by backends. *)

type _ t = ..

type _ t +=
| SO_DEBUG : bool t (** Enable socket debugging *)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps SO should be a sub-module?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean separate the socket options fro the TCP/IP level options? Seems easier to just keep the types corresponding to the names of the sockopts themselves as they're well known.

| SO_BROADCAST : bool t (** Permit sending of broadcast messages *)
| SO_REUSEADDR : bool t (** Allow reuse of local addresses *)
| SO_KEEPALIVE : bool t (** Keep TCP connection alive *)
| SO_DONTROUTE : bool t (** Bypass routing tables *)
| SO_OOBINLINE : bool t (** Leave out-of-band data in line *)
| TCP_NODELAY : bool t (** Disable Nagle's algorithm *)
| IPV6_ONLY : bool t (** Restrict to IPv6 only *)
| SO_REUSEPORT : bool t (** Allow reuse of local port *)
| SO_SNDBUF : int t (** Send buffer size *)
| SO_RCVBUF : int t (** Receive buffer size *)
| SO_TYPE : int t (** Socket type (get only) *)
| SO_RCVLOWAT : int t (** Receive low water mark *)
| SO_SNDLOWAT : int t (** Send low water mark *)
| SO_LINGER : int option t (** Linger on close if data present *)
| SO_RCVTIMEO : float t (** Receive timeout *)
| SO_SNDTIMEO : float t (** Send timeout *)
end

(** {2 Types} *)

type socket_ty = [`Socket | `Close]
Expand All @@ -127,6 +154,18 @@ type 'tag ty = [`Network | `Platform of 'tag]
type 'a t = 'a r
constraint 'a = [> [> `Generic] ty]

(** {2 Socket options} *)

val setsockopt : [> `Socket] r -> 'a Sockopt.t -> 'a -> unit
(** [setsockopt s opt v] sets socket option [opt] to value [v] on socket [s].

@raise Invalid_argument if the socket option is not supported by the backend. *)

val getsockopt : [> `Socket] r -> 'a Sockopt.t -> 'a
(** [getsockopt s opt] gets the value of socket option [opt] on socket [s].

@raise Invalid_argument if the socket option is not supported by the backend. *)

(** {2 Out-bound Connections} *)

val connect : sw:Switch.t -> [> 'tag ty] t -> Sockaddr.stream -> 'tag stream_socket_ty r
Expand Down Expand Up @@ -304,11 +343,18 @@ val close : [> `Close] r -> unit
(** {2 Provider Interface} *)

module Pi : sig
module type SOCKET = sig
type t
val setsockopt : t -> 'a Sockopt.t -> 'a -> unit
val getsockopt : t -> 'a Sockopt.t -> 'a
end

module type STREAM_SOCKET = sig
type tag
include Flow.Pi.SHUTDOWN
include Flow.Pi.SOURCE with type t := t
include Flow.Pi.SINK with type t := t
include SOCKET with type t := t
val close : t -> unit
end

Expand All @@ -319,6 +365,7 @@ module Pi : sig
module type DATAGRAM_SOCKET = sig
type tag
include Flow.Pi.SHUTDOWN
include SOCKET with type t := t
val send : t -> ?dst:Sockaddr.datagram -> Cstruct.t list -> unit
val recv : t -> Cstruct.t -> Sockaddr.datagram * int
val close : t -> unit
Expand All @@ -331,7 +378,7 @@ module Pi : sig
module type LISTENING_SOCKET = sig
type t
type tag

include SOCKET with type t := t
val accept : t -> sw:Switch.t -> tag stream_socket_ty r * Sockaddr.stream
val close : t -> unit
val listening_addr : t -> Sockaddr.stream
Expand Down
62 changes: 62 additions & 0 deletions lib_eio/unix/net.ml
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,65 @@ let socketpair_datagram ~sw ?(domain=Unix.PF_UNIX) ?(protocol=0) () =

let fd socket =
Option.get (Resource.fd_opt socket)

module Sockopt = struct
type _ Eio.Net.Sockopt.t +=
| Unix_bool : Unix.socket_bool_option -> bool Eio.Net.Sockopt.t
| Unix_int : Unix.socket_int_option -> int Eio.Net.Sockopt.t
| Unix_optint : Unix.socket_optint_option -> int option Eio.Net.Sockopt.t
| Unix_float : Unix.socket_float_option -> float Eio.Net.Sockopt.t

let set : type a. Fd.t -> a Eio.Net.Sockopt.t -> a -> unit = fun fd opt v ->
Fd.use_exn "setsockopt" fd @@ fun fd ->
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> Unix.setsockopt fd Unix.SO_DEBUG v
| Eio.Net.Sockopt.SO_BROADCAST -> Unix.setsockopt fd Unix.SO_BROADCAST v
| Eio.Net.Sockopt.SO_REUSEADDR -> Unix.setsockopt fd Unix.SO_REUSEADDR v
| Eio.Net.Sockopt.SO_KEEPALIVE -> Unix.setsockopt fd Unix.SO_KEEPALIVE v
| Eio.Net.Sockopt.SO_DONTROUTE -> Unix.setsockopt fd Unix.SO_DONTROUTE v
| Eio.Net.Sockopt.SO_OOBINLINE -> Unix.setsockopt fd Unix.SO_OOBINLINE v
| Eio.Net.Sockopt.TCP_NODELAY -> Unix.setsockopt fd Unix.TCP_NODELAY v
| Eio.Net.Sockopt.IPV6_ONLY -> Unix.setsockopt fd Unix.IPV6_ONLY v
| Eio.Net.Sockopt.SO_REUSEPORT -> Unix.setsockopt fd Unix.SO_REUSEPORT v
| Eio.Net.Sockopt.SO_SNDBUF -> Unix.setsockopt_int fd Unix.SO_SNDBUF v
| Eio.Net.Sockopt.SO_RCVBUF -> Unix.setsockopt_int fd Unix.SO_RCVBUF v
| Eio.Net.Sockopt.SO_TYPE -> invalid_arg "SO_TYPE is read-only"
| Eio.Net.Sockopt.SO_RCVLOWAT -> Unix.setsockopt_int fd Unix.SO_RCVLOWAT v
| Eio.Net.Sockopt.SO_SNDLOWAT -> Unix.setsockopt_int fd Unix.SO_SNDLOWAT v
| Eio.Net.Sockopt.SO_LINGER -> Unix.setsockopt_optint fd Unix.SO_LINGER v
| Eio.Net.Sockopt.SO_RCVTIMEO -> Unix.setsockopt_float fd Unix.SO_RCVTIMEO v
| Eio.Net.Sockopt.SO_SNDTIMEO -> Unix.setsockopt_float fd Unix.SO_SNDTIMEO v
| Unix_bool bo -> Unix.setsockopt fd bo v
| Unix_int bo -> Unix.setsockopt_int fd bo v
| Unix_optint bo -> Unix.setsockopt_optint fd bo v
| Unix_float bo -> Unix.setsockopt_float fd bo v
| _ -> raise (Invalid_argument "Unsupported socket option")

let get_descr : type a. Unix.file_descr -> a Eio.Net.Sockopt.t -> a = fun fd opt ->
match opt with
| Eio.Net.Sockopt.SO_DEBUG -> Unix.getsockopt fd Unix.SO_DEBUG
| Eio.Net.Sockopt.SO_BROADCAST -> Unix.getsockopt fd Unix.SO_BROADCAST
| Eio.Net.Sockopt.SO_REUSEADDR -> Unix.getsockopt fd Unix.SO_REUSEADDR
| Eio.Net.Sockopt.SO_KEEPALIVE -> Unix.getsockopt fd Unix.SO_KEEPALIVE
| Eio.Net.Sockopt.SO_DONTROUTE -> Unix.getsockopt fd Unix.SO_DONTROUTE
| Eio.Net.Sockopt.SO_OOBINLINE -> Unix.getsockopt fd Unix.SO_OOBINLINE
| Eio.Net.Sockopt.TCP_NODELAY -> Unix.getsockopt fd Unix.TCP_NODELAY
| Eio.Net.Sockopt.IPV6_ONLY -> Unix.getsockopt fd Unix.IPV6_ONLY
| Eio.Net.Sockopt.SO_REUSEPORT -> Unix.getsockopt fd Unix.SO_REUSEPORT
| Eio.Net.Sockopt.SO_SNDBUF -> Unix.getsockopt_int fd Unix.SO_SNDBUF
| Eio.Net.Sockopt.SO_RCVBUF -> Unix.getsockopt_int fd Unix.SO_RCVBUF
| Eio.Net.Sockopt.SO_TYPE -> Unix.getsockopt_int fd Unix.SO_TYPE
| Eio.Net.Sockopt.SO_RCVLOWAT -> Unix.getsockopt_int fd Unix.SO_RCVLOWAT
| Eio.Net.Sockopt.SO_SNDLOWAT -> Unix.getsockopt_int fd Unix.SO_SNDLOWAT
| Eio.Net.Sockopt.SO_LINGER -> Unix.getsockopt_optint fd Unix.SO_LINGER
| Eio.Net.Sockopt.SO_RCVTIMEO -> Unix.getsockopt_float fd Unix.SO_RCVTIMEO
| Eio.Net.Sockopt.SO_SNDTIMEO -> Unix.getsockopt_float fd Unix.SO_SNDTIMEO
| Unix_bool bo -> Unix.getsockopt fd bo
| Unix_int bo -> Unix.getsockopt_int fd bo
| Unix_optint bo -> Unix.getsockopt_optint fd bo
| Unix_float bo -> Unix.getsockopt_float fd bo
| _ -> raise (Invalid_argument "Unsupported socket option")

let get : type a. Fd.t -> a Eio.Net.Sockopt.t -> a = fun fd opt ->
Fd.use_exn "getsockopt" fd @@ fun fd -> get_descr fd opt
end
Loading