From 91e3b31ff7a5db7f06d3b042867f4d1769e9e297 Mon Sep 17 00:00:00 2001 From: Bikal Lem Date: Tue, 8 Nov 2022 14:30:07 +0000 Subject: [PATCH] sockopt: implement setsockopt() for linux and luv backends --- lib_eio/net.ml | 6 ++++-- lib_eio/net.mli | 6 ++++++ lib_eio/unix/eio_unix.mli | 2 ++ lib_eio_linux/eio_linux.ml | 40 +++++++++++++++++++++++++------------- lib_eio_luv/eio_luv.ml | 26 ++++++++++++++++--------- 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/lib_eio/net.ml b/lib_eio/net.ml index 45f19fc64..a6cf660ff 100644 --- a/lib_eio/net.ml +++ b/lib_eio/net.ml @@ -67,7 +67,7 @@ module Ipaddr = struct let elide = min elide zeros in let parts = if zeros = 0 then acc else zeros :: acc in ((if elide < -1 then Some elide else None), List.rev parts) - + in loop 0 0 [] t @@ -243,7 +243,7 @@ let connect ~sw (t:#t) addr = Exn.reraise_with_context ex bt "connecting to %a" Sockaddr.pp addr let datagram_socket ?(reuse_addr=false) ?(reuse_port=false) ~sw (t:#t) addr = - let addr = (addr :> [Sockaddr.datagram | `UdpV4 | `UdpV6]) in + let addr = (addr :> [Sockaddr.datagram | `UdpV4 | `UdpV6]) in t#datagram_socket ~reuse_addr ~reuse_port ~sw addr let getaddrinfo ?(service="") (t:#t) hostname = t#getaddrinfo ~service hostname @@ -289,3 +289,5 @@ let with_tcp_connect ?(timeout=Time.Timeout.none) ~host ~service t f = | exception (Exn.Io _ as ex) -> let bt = Printexc.get_raw_backtrace () in Exn.reraise_with_context ex bt "connecting to %S:%s" host service + +let setsockopt (s:#socket) = s#setsockopt diff --git a/lib_eio/net.mli b/lib_eio/net.mli index 80ca7d275..207e5ad44 100644 --- a/lib_eio/net.mli +++ b/lib_eio/net.mli @@ -278,6 +278,12 @@ val getnameinfo : #t -> Sockaddr.t -> (string * string) registered domain name represented by [sockaddr]. [service] is the IANA specified textual name of the port specified in [sockaddr], e.g. 'ftp', 'http', 'https', etc. *) +(** {2 Socket} *) + +val setsockopt : #socket -> 'a sockopt -> 'a -> unit +(** [setsockopt s opt v] configures socket [s] with socket option and value [opt] + and [v] respectively. *) + (** {2 Closing} *) val close : -> unit (** [close t] marks the socket as closed. It can no longer be used after this. *) diff --git a/lib_eio/unix/eio_unix.mli b/lib_eio/unix/eio_unix.mli index 0981f9a16..d3ad13cae 100644 --- a/lib_eio/unix/eio_unix.mli +++ b/lib_eio/unix/eio_unix.mli @@ -106,3 +106,5 @@ module Ctf = Ctf_unix val getnameinfo : Eio.Net.Sockaddr.t -> (string * string) (** [getnameinfo sockaddr] returns domain name and service for [sockaddr]. *) + +val setsockopt : Unix.file_descr -> 'a Eio.Net.sockopt -> 'a -> unit diff --git a/lib_eio_linux/eio_linux.ml b/lib_eio_linux/eio_linux.ml index 684bbecff..b286e9a30 100644 --- a/lib_eio_linux/eio_linux.ml +++ b/lib_eio_linux/eio_linux.ml @@ -1074,8 +1074,14 @@ let fallback_copy src dst = done with End_of_file -> () +class socket sock = object + inherit Eio.Net.socket + method setsockopt = Eio_unix.setsockopt (FD.to_unix `Peek sock) +end + let udp_socket sock = object - inherit Eio.Net.datagram_socket + inherit socket sock + inherit! Eio.Net.datagram_socket method close = FD.close sock @@ -1096,15 +1102,17 @@ let udp_socket sock = object raise (Failure "Expected INET UDP socket address but got Unix domain socket address.") end -let flow fd = +class flow fd = let is_tty = lazy (Unix.isatty (FD.get_exn "isatty" fd)) in - object (_ : ) + object + inherit Eio.Flow.two_way + method fd = fd method close = FD.close fd method stat = FD.fstat fd - method probe : type a. a Eio.Generic.ty -> a option = function + method! probe : type a. a Eio.Generic.ty -> a option = function | FD -> Some fd | Eio_unix.Private.Unix_file_descr op -> Some (FD.to_unix op fd) | _ -> None @@ -1123,9 +1131,7 @@ let flow fd = method pwrite ~file_offset bufs = Low_level.writev_single ~file_offset fd bufs - method read_methods = [] - - method write bufs = Low_level.writev fd bufs + method! write bufs = Low_level.writev fd bufs method copy src = match get_fd_opt src with @@ -1144,14 +1150,22 @@ let flow fd = | `Send -> Unix.SHUTDOWN_SEND | `All -> Unix.SHUTDOWN_ALL - method unix_fd op = FD.to_unix op fd - end + method unix_fd (op: [`Peek | `Take]) = FD.to_unix op fd +end + +let flow fd = new flow fd + +let stream_socket fd = object(_ : ) + inherit socket fd + inherit! flow fd +end let source fd = (flow fd :> source) let sink fd = (flow fd :> sink) let listening_socket fd = object - inherit Eio.Net.listening_socket + inherit socket fd + inherit! Eio.Net.listening_socket method! probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Private.Unix_file_descr op -> Some (FD.to_unix op fd) @@ -1166,8 +1180,8 @@ let listening_socket fd = object | Unix.ADDR_UNIX path -> `Unix path | Unix.ADDR_INET (host, port) -> `Tcp (Eio_unix.Ipaddr.of_unix host, port) in - let flow = (flow client :> ) in - flow, client_addr + let stream_socket = (stream_socket client :> ) in + stream_socket, client_addr end let socket_domain_of = function @@ -1227,7 +1241,7 @@ let net = object let sock_unix = Unix.socket (socket_domain_of connect_addr) socket_type 0 in let sock = FD.of_unix ~sw ~seekable:false ~close_unix:true sock_unix in Low_level.connect sock addr; - (flow sock :> ) + (stream_socket sock :> ) method datagram_socket ~reuse_addr ~reuse_port ~sw saddr = let sock_unix = Unix.socket ~cloexec:true (socket_domain_of saddr) Unix.SOCK_DGRAM 0 in diff --git a/lib_eio_luv/eio_luv.ml b/lib_eio_luv/eio_luv.ml index 82beaaab6..5cca523bc 100644 --- a/lib_eio_luv/eio_luv.ml +++ b/lib_eio_luv/eio_luv.ml @@ -727,8 +727,14 @@ end let source fd = (flow fd :> source) let sink fd = (flow fd :> sink) -let socket sock = object - inherit Eio.Flow.two_way as super +class socket f sock = object + inherit Eio.Net.socket + method setsockopt = Eio_unix.setsockopt (f `Peek sock |> Option.get) +end + +let stream_socket sock = object + inherit socket (Stream.to_unix_opt) sock + inherit! Eio.Net.stream_socket as super method! probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Private.Unix_file_descr op -> Stream.to_unix_opt op sock @@ -767,7 +773,8 @@ let socket sock = object end class virtual ['a] listening_socket ~backlog sock = object (self) - inherit Eio.Net.listening_socket as super + inherit socket Stream.to_unix_opt sock + inherit! Eio.Net.listening_socket as super method! probe : type a. a Eio.Generic.ty -> a option = function | Eio_unix.Private.Unix_file_descr op -> Stream.to_unix_opt op sock @@ -789,7 +796,7 @@ class virtual ['a] listening_socket ~backlog sock = object (self) raise (wrap_error e) | Ok () -> Switch.on_release sw (fun () -> Handle.ensure_closed client); - let flow = (socket client :> ) in + let flow = (stream_socket client :> ) in let client_addr = self#get_client_addr client in flow, client_addr @@ -853,7 +860,8 @@ module Udp = struct end let udp_socket endp = object - inherit Eio.Net.datagram_socket + inherit socket Handle.to_unix_opt endp + inherit! Eio.Net.datagram_socket method close = Handle.close endp @@ -918,10 +926,10 @@ let net = object method connect ~sw = function | `Tcp (host, port) -> let sock = Stream.connect_tcp ~sw (luv_addr_of_eio host port) in - (socket sock :> < Eio.Flow.two_way; Eio.Flow.close >) + (stream_socket sock :> < Eio.Net.stream_socket; Eio.Flow.close >) | `Unix path -> let sock = Stream.connect_pipe ~sw path in - (socket sock :> < Eio.Flow.two_way; Eio.Flow.close >) + (stream_socket sock :> < Eio.Net.stream_socket; Eio.Flow.close >) method datagram_socket ~reuse_addr ~reuse_port ~sw saddr = let domain = socket_domain_of saddr in @@ -1245,7 +1253,7 @@ let rec run : type a. (_ -> a) -> a = fun main -> let sock = Luv.TCP.init ~loop () |> or_raise in let handle = Handle.of_luv ~sw ~close_unix sock in Luv.TCP.open_ sock fd |> or_raise; - (socket handle :> Eio_unix.socket) + (stream_socket handle :> Eio_unix.socket) with | sock -> continue k sock | exception (Eio.Io _ as ex) -> discontinue k ex @@ -1265,7 +1273,7 @@ let rec run : type a. (_ -> a) -> a = fun main -> let sock = Luv.TCP.init ~loop () |> or_raise in Luv.TCP.open_ sock x |> or_raise; let h = Handle.of_luv ~sw ~close_unix:true sock in - (socket h :> Eio_unix.socket) + (stream_socket h :> Eio_unix.socket) in (wrap a, wrap b) with