Skip to content

Commit 7fd9a62

Browse files
committed
Eio.Net.connect: add options for bind and reuse_addr/port
1 parent d3f243c commit 7fd9a62

File tree

14 files changed

+60
-44
lines changed

14 files changed

+60
-44
lines changed

lib_eio/mock/net.ml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ module Impl = struct
3636
Switch.on_release sw (fun () -> Eio.Resource.close socket);
3737
socket
3838

39-
let connect t ~sw ?bind:_ addr =
39+
let connect t ~sw ~options:_ addr =
4040
traceln "%s: connect to %a" t.label Eio.Net.Sockaddr.pp addr;
4141
let socket = Handler.run t.on_connect in
4242
Switch.on_release sw (fun () -> Eio.Flow.close socket);

lib_eio/net.ml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,11 @@ type 'tag ty = [`Network | `Platform of 'tag]
180180
type 'a t = 'a r
181181
constraint 'a = [> [> `Generic] ty]
182182

183+
type option = ..
184+
type option += Bind of Sockaddr.stream
185+
| Reuse_addr
186+
| Reuse_port
187+
183188
module Pi = struct
184189
module type STREAM_SOCKET = sig
185190
type tag
@@ -235,7 +240,7 @@ module Pi = struct
235240
type tag
236241

237242
val listen : t -> reuse_addr:bool -> reuse_port:bool -> backlog:int -> sw:Switch.t -> Sockaddr.stream -> tag listening_socket_ty r
238-
val connect : t -> sw:Switch.t -> ?bind:Sockaddr.stream -> Sockaddr.stream -> tag stream_socket_ty r
243+
val connect : t -> sw:Switch.t -> options:option list -> Sockaddr.stream -> tag stream_socket_ty r
239244
val datagram_socket :
240245
t
241246
-> reuse_addr:bool
@@ -295,10 +300,10 @@ let listen (type tag) ?(reuse_addr=false) ?(reuse_port=false) ~backlog ~sw (t:[>
295300
let module X = (val (Resource.get ops Pi.Network)) in
296301
X.listen t ~reuse_addr ~reuse_port ~backlog ~sw
297302

298-
let connect (type tag) ~sw ?bind (t:[> tag ty] r) addr =
303+
let connect (type tag) ~sw ?(options = []) (t:[> tag ty] r) addr =
299304
let (Resource.T (t, ops)) = t in
300305
let module X = (val (Resource.get ops Pi.Network)) in
301-
try X.connect t ~sw ?bind addr
306+
try X.connect t ~sw ~options addr
302307
with Exn.Io _ as ex ->
303308
let bt = Printexc.get_raw_backtrace () in
304309
Exn.reraise_with_context ex bt "connecting to %a" Sockaddr.pp addr

lib_eio/net.mli

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,15 @@ type 'a t = 'a r
129129

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

132-
val connect : sw:Switch.t -> ?bind:Sockaddr.stream -> [> 'tag ty] t -> Sockaddr.stream -> 'tag stream_socket_ty r
133-
(** [connect ~sw t addr] is a new socket connected to remote address [addr].
132+
type option = ..
133+
type option += Bind of Sockaddr.stream
134+
| Reuse_addr
135+
| Reuse_port
134136

135-
The new socket will be closed when [sw] finishes, unless closed manually first.
137+
val connect : sw:Switch.t -> ?options:option list -> [> 'tag ty] t -> Sockaddr.stream -> 'tag stream_socket_ty r
138+
(** [connect ~sw t addr] is a new socket connected to remote address [addr].
136139
137-
@param bind Set the outbound client address. *)
140+
The new socket will be closed when [sw] finishes, unless closed manually first. *)
138141

139142
val with_tcp_connect :
140143
?timeout:Time.Timeout.t ->
@@ -348,7 +351,7 @@ module Pi : sig
348351
t -> reuse_addr:bool -> reuse_port:bool -> backlog:int -> sw:Switch.t ->
349352
Sockaddr.stream -> tag listening_socket_ty r
350353

351-
val connect : t -> sw:Switch.t -> ?bind:Sockaddr.stream -> Sockaddr.stream -> tag stream_socket_ty r
354+
val connect : t -> sw:Switch.t -> options:option list -> Sockaddr.stream -> tag stream_socket_ty r
352355

353356
val datagram_socket :
354357
t

lib_eio/unix/net.ml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,15 @@ let socketpair_datagram ~sw ?(domain=Unix.PF_UNIX) ?(protocol=0) () =
8585

8686
let fd socket =
8787
Option.get (Resource.fd_opt socket)
88+
89+
let apply_option fd = function
90+
| Eio.Net.Bind bind_addr ->
91+
Unix.bind fd (sockaddr_to_unix bind_addr)
92+
| Eio.Net.Reuse_addr ->
93+
Unix.setsockopt fd Unix.SO_REUSEADDR true
94+
| Eio.Net.Reuse_port ->
95+
Unix.setsockopt fd Unix.SO_REUSEPORT true
96+
| _ ->
97+
invalid_arg "Unknown Eio.Net.option"
98+
99+
let configure options fd = List.iter (apply_option fd) options

lib_eio/unix/net.mli

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,9 @@ val socketpair_datagram :
9797
val getnameinfo : Eio.Net.Sockaddr.t -> (string * string)
9898
(** [getnameinfo sockaddr] returns domain name and service for [sockaddr]. *)
9999

100+
val configure : Eio.Net.option list -> Unix.file_descr -> unit
101+
(** [configure options fd] prepare the socket with the chosen options. *)
102+
100103
type _ Effect.t +=
101104
| Import_socket_stream :
102105
Switch.t * bool * Unix.file_descr -> [`Unix_fd | stream_socket_ty] r Effect.t (** See {!import_socket_stream} *)

lib_eio_linux/eio_linux.ml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,12 +256,11 @@ let socket_domain_of = function
256256
~v4:(fun _ -> Unix.PF_INET)
257257
~v6:(fun _ -> Unix.PF_INET6)
258258

259-
let connect ~sw ?bind connect_addr =
259+
let connect ~sw ~options connect_addr =
260260
let addr = Eio_unix.Net.sockaddr_to_unix connect_addr in
261261
let sock_unix = Unix.socket ~cloexec:true (socket_domain_of connect_addr) Unix.SOCK_STREAM 0 in
262262
let sock = Fd.of_unix ~sw ~seekable:false ~close_unix:true sock_unix in
263-
let bind = Option.map Eio_unix.Net.sockaddr_to_unix bind in
264-
Low_level.connect sock ?bind addr;
263+
Low_level.connect sock ~options addr;
265264
(flow sock :> _ Eio_unix.Net.stream_socket)
266265

267266
module Impl = struct
@@ -297,8 +296,8 @@ module Impl = struct
297296
Unix.listen sock_unix backlog;
298297
(listening_socket sock :> _ Eio.Net.listening_socket_ty r)
299298

300-
let connect () ~sw ?bind addr =
301-
(connect ~sw ?bind addr :> [`Generic | `Unix] Eio.Net.stream_socket_ty r)
299+
let connect () ~sw ~options addr =
300+
(connect ~sw ~options addr :> [`Generic | `Unix] Eio.Net.stream_socket_ty r)
302301

303302
let datagram_socket () ~reuse_addr ~reuse_port ~sw saddr =
304303
if reuse_addr then (

lib_eio_linux/low_level.ml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -221,15 +221,16 @@ let splice src ~dst ~len =
221221
else if res = 0 then raise End_of_file
222222
else raise @@ Err.wrap (Uring.error_of_errno res) "splice" ""
223223

224-
let try_bind fd = function
225-
| None -> ()
226-
| Some bind_addr ->
227-
try Unix.bind fd bind_addr
228-
with Unix.Unix_error (code, name, arg) -> raise @@ Err.wrap_fs code name arg
229-
230-
let connect fd ?bind addr =
224+
let apply_option fd = function
225+
| Eio.Net.Bind bind_addr ->
226+
let bind_addr = Eio_unix.Net.sockaddr_to_unix bind_addr in
227+
(try Unix.bind fd bind_addr
228+
with Unix.Unix_error (code, name, arg) -> raise @@ Err.wrap_fs code name arg)
229+
| _ -> invalid_arg "Unknown option"
230+
231+
let connect fd ~options addr =
231232
Fd.use_exn "connect" fd @@ fun fd ->
232-
try_bind fd bind;
233+
List.iter (apply_option fd) options ;
233234
let res = Sched.enter "connect" (enqueue_connect fd addr) in
234235
if res < 0 then (
235236
let ex =

lib_eio_linux/low_level.mli

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,9 @@ val splice : fd -> dst:fd -> len:int -> int
111111
@raise End_of_file [src] is at the end of the file.
112112
@raise Unix.Unix_error(EINVAL, "splice", _) if splice is not supported for these FDs. *)
113113

114-
val connect : fd -> ?bind:Unix.sockaddr -> Unix.sockaddr -> unit
115-
(** [connect fd addr] attempts to connect socket [fd] to [addr]. *)
114+
val connect : fd -> options:Eio.Net.option list -> Unix.sockaddr -> unit
115+
(** [connect fd ~options addr] attempts to connect socket [fd] to [addr]
116+
after configuring the socket with [options]. *)
116117

117118
val await_readable : fd -> unit
118119
(** [await_readable fd] blocks until [fd] is readable (or has an error). *)

lib_eio_posix/low_level.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ let socket ~sw socket_domain socket_type protocol =
6767
Unix.set_nonblock sock_unix;
6868
Fd.of_unix ~sw ~blocking:false ~close_unix:true sock_unix
6969

70-
let connect fd ?bind addr =
70+
let connect fd ~options addr =
7171
try
7272
Fd.use_exn "connect" fd @@ fun fd ->
73-
Option.iter (Unix.bind fd) bind;
73+
Eio_unix.Net.configure options fd ;
7474
Unix.connect fd addr
7575
with
7676
| Unix.Unix_error ((EINTR | EAGAIN | EWOULDBLOCK | EINPROGRESS), _, _) ->

lib_eio_posix/low_level.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ val read : fd -> bytes -> int -> int -> int
2828
val write : fd -> bytes -> int -> int -> int
2929

3030
val socket : sw:Switch.t -> Unix.socket_domain -> Unix.socket_type -> int -> fd
31-
val connect : fd -> ?bind:Unix.sockaddr -> Unix.sockaddr -> unit
31+
val connect : fd -> options:Eio.Net.option list -> Unix.sockaddr -> unit
3232
val accept : sw:Switch.t -> fd -> fd * Unix.sockaddr
3333

3434
val shutdown : fd -> Unix.shutdown_command -> unit

0 commit comments

Comments
 (0)