From 1d17d6214533d4d27249071c3d45ee725c5b098a 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 | 2 ++ 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, 54 insertions(+), 22 deletions(-) diff --git a/lib_eio/net.ml b/lib_eio/net.ml index c3447970b..653cc9d69 100644 --- a/lib_eio/net.ml +++ b/lib_eio/net.ml @@ -260,3 +260,5 @@ let with_tcp_connect ?(timeout=Time.Timeout.none) ~host ~service t f = | `Unix _ -> None ) |> aux + +let setsockopt (s:#socket) = s#setsockopt diff --git a/lib_eio/net.mli b/lib_eio/net.mli index 360c848d3..bfaabd8e7 100644 --- a/lib_eio/net.mli +++ b/lib_eio/net.mli @@ -267,6 +267,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 7fa3207ad..fb01fd9b2 100644 --- a/lib_eio/unix/eio_unix.mli +++ b/lib_eio/unix/eio_unix.mli @@ -103,3 +103,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 058fa8c24..c11f883be 100644 --- a/lib_eio_linux/eio_linux.ml +++ b/lib_eio_linux/eio_linux.ml @@ -1031,8 +1031,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 @@ -1053,15 +1059,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 @@ -1080,9 +1088,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 @@ -1101,14 +1107,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) @@ -1123,8 +1137,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 @@ -1183,7 +1197,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 01b583d62..8d5f6a068 100644 --- a/lib_eio_luv/eio_luv.ml +++ b/lib_eio_luv/eio_luv.ml @@ -674,8 +674,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 @@ -714,7 +720,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 @@ -736,7 +743,7 @@ class virtual ['a] listening_socket ~backlog sock = object (self) raise (Luv_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 @@ -800,7 +807,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 @@ -865,10 +873,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 @@ -1178,7 +1186,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; - continue k (socket handle :> Eio_unix.socket) + continue k (stream_socket handle :> Eio_unix.socket) with Luv_error _ as ex -> discontinue k ex ) @@ -1197,7 +1205,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 continue k (wrap a, wrap b) with Luv_error _ as ex ->