Skip to content

Commit 6a5cc49

Browse files
committed
Eio.Net.connect: add options to bind source addr and reuse_addr/port
1 parent 3be614e commit 6a5cc49

File tree

14 files changed

+62
-26
lines changed

14 files changed

+62
-26
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 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: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ 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 +=
185+
| Source_addr of Sockaddr.stream
186+
| Reuse_addr
187+
| Reuse_port
188+
183189
module Pi = struct
184190
module type STREAM_SOCKET = sig
185191
type tag
@@ -235,7 +241,7 @@ module Pi = struct
235241
type tag
236242

237243
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 -> Sockaddr.stream -> tag stream_socket_ty r
244+
val connect : t -> sw:Switch.t -> options:option list -> Sockaddr.stream -> tag stream_socket_ty r
239245
val datagram_socket :
240246
t
241247
-> reuse_addr:bool
@@ -295,10 +301,10 @@ let listen (type tag) ?(reuse_addr=false) ?(reuse_port=false) ~backlog ~sw (t:[>
295301
let module X = (val (Resource.get ops Pi.Network)) in
296302
X.listen t ~reuse_addr ~reuse_port ~backlog ~sw
297303

298-
let connect (type tag) ~sw (t:[> tag ty] r) addr =
304+
let connect (type tag) ~sw ?(options = []) (t:[> tag ty] r) addr =
299305
let (Resource.T (t, ops)) = t in
300306
let module X = (val (Resource.get ops Pi.Network)) in
301-
try X.connect t ~sw addr
307+
try X.connect t ~sw ~options addr
302308
with Exn.Io _ as ex ->
303309
let bt = Printexc.get_raw_backtrace () in
304310
Exn.reraise_with_context ex bt "connecting to %a" Sockaddr.pp addr

lib_eio/net.mli

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

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

132-
val connect : sw:Switch.t -> [> 'tag ty] t -> Sockaddr.stream -> 'tag stream_socket_ty r
132+
type option = ..
133+
type option +=
134+
| Source_addr of Sockaddr.stream
135+
| Reuse_addr
136+
| Reuse_port
137+
138+
val connect : sw:Switch.t -> ?options:option list -> [> 'tag ty] t -> Sockaddr.stream -> 'tag stream_socket_ty r
133139
(** [connect ~sw t addr] is a new socket connected to remote address [addr].
134140
135141
The new socket will be closed when [sw] finishes, unless closed manually first. *)
@@ -346,7 +352,7 @@ module Pi : sig
346352
t -> reuse_addr:bool -> reuse_port:bool -> backlog:int -> sw:Switch.t ->
347353
Sockaddr.stream -> tag listening_socket_ty r
348354

349-
val connect : t -> sw:Switch.t -> Sockaddr.stream -> tag stream_socket_ty r
355+
val connect : t -> sw:Switch.t -> options:option list -> Sockaddr.stream -> tag stream_socket_ty r
350356

351357
val datagram_socket :
352358
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.Source_addr addr ->
91+
Unix.bind fd (sockaddr_to_unix 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 & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -249,11 +249,11 @@ let socket_domain_of = function
249249
~v4:(fun _ -> Unix.PF_INET)
250250
~v6:(fun _ -> Unix.PF_INET6)
251251

252-
let connect ~sw connect_addr =
252+
let connect ~sw ~options connect_addr =
253253
let addr = Eio_unix.Net.sockaddr_to_unix connect_addr in
254254
let sock_unix = Unix.socket ~cloexec:true (socket_domain_of connect_addr) Unix.SOCK_STREAM 0 in
255255
let sock = Fd.of_unix ~sw ~seekable:false ~close_unix:true sock_unix in
256-
Low_level.connect sock addr;
256+
Low_level.connect sock ~options addr;
257257
(flow sock :> _ Eio_unix.Net.stream_socket)
258258

259259
module Impl = struct
@@ -289,7 +289,8 @@ module Impl = struct
289289
Unix.listen sock_unix backlog;
290290
(listening_socket sock :> _ Eio.Net.listening_socket_ty r)
291291

292-
let connect () ~sw addr = (connect ~sw addr :> [`Generic | `Unix] Eio.Net.stream_socket_ty r)
292+
let connect () ~sw ~options addr =
293+
(connect ~sw ~options addr :> [`Generic | `Unix] Eio.Net.stream_socket_ty r)
293294

294295
let datagram_socket () ~reuse_addr ~reuse_port ~sw saddr =
295296
if reuse_addr then (

lib_eio_linux/low_level.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,9 @@ 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 connect fd addr =
224+
let connect fd ~options addr =
225225
Fd.use_exn "connect" fd @@ fun fd ->
226+
Eio_unix.Net.configure options fd ;
226227
let res = Sched.enter "connect" (enqueue_connect fd addr) in
227228
if res < 0 then (
228229
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 -> 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: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,18 @@ 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 addr =
70+
let connect fd ~options addr =
7171
try
72-
Fd.use_exn "connect" fd (fun fd -> Unix.connect fd addr)
72+
Fd.use_exn "connect" fd @@ fun fd ->
73+
Eio_unix.Net.configure options fd ;
74+
Unix.connect fd addr
7375
with
7476
| Unix.Unix_error ((EINTR | EAGAIN | EWOULDBLOCK | EINPROGRESS), _, _) ->
7577
await_writable "connect" fd;
76-
match Fd.use_exn "connect" fd Unix.getsockopt_error with
78+
(match Fd.use_exn "connect" fd Unix.getsockopt_error with
7779
| None -> ()
78-
| Some code -> raise (Err.wrap code "connect-in-progress" "")
80+
| Some code -> raise (Err.wrap code "connect-in-progress" ""))
81+
| Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg)
7982

8083
let accept ~sw sock =
8184
Fd.use_exn "accept" sock @@ fun sock ->

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 -> 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

lib_eio_posix/net.ml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr.
138138
);
139139
(listening_socket ~hook sock :> _ Eio.Net.listening_socket_ty r)
140140

141-
let connect ~sw connect_addr =
141+
let connect ~sw ~options connect_addr =
142142
let socket_type, addr =
143143
match connect_addr with
144144
| `Unix path -> Unix.SOCK_STREAM, Unix.ADDR_UNIX path
@@ -148,7 +148,7 @@ let connect ~sw connect_addr =
148148
in
149149
let sock = Low_level.socket ~sw (socket_domain_of connect_addr) socket_type 0 in
150150
try
151-
Low_level.connect sock addr;
151+
Low_level.connect sock ~options addr;
152152
(Flow.of_fd sock :> _ Eio_unix.Net.stream_socket)
153153
with Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg)
154154

@@ -174,8 +174,8 @@ module Impl = struct
174174

175175
let listen () = listen
176176

177-
let connect () ~sw addr =
178-
let socket = connect ~sw addr in
177+
let connect () ~sw ~options addr =
178+
let socket = connect ~sw ~options addr in
179179
(socket :> [`Generic | `Unix] Eio.Net.stream_socket_ty r)
180180

181181
let datagram_socket () ~reuse_addr ~reuse_port ~sw saddr =

lib_eio_windows/low_level.ml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,18 @@ let socket ~sw socket_domain socket_type protocol =
6060
Unix.set_nonblock sock_unix;
6161
Fd.of_unix ~sw ~blocking:false ~close_unix:true sock_unix
6262

63-
let connect fd addr =
63+
let connect fd ~options addr =
6464
try
65-
Fd.use_exn "connect" fd (fun fd -> Unix.connect fd addr)
65+
Fd.use_exn "connect" fd @@ fun fd ->
66+
Eio_unix.Net.configure options fd ;
67+
Unix.connect fd addr
6668
with
6769
| Unix.Unix_error ((EINTR | EAGAIN | EWOULDBLOCK | EINPROGRESS), _, _) ->
6870
await_writable fd;
6971
match Fd.use_exn "connect" fd Unix.getsockopt_error with
7072
| None -> ()
7173
| Some code -> raise (Err.wrap code "connect-in-progress" "")
74+
| Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg)
7275

7376
let accept ~sw sock =
7477
Fd.use_exn "accept" sock @@ fun sock ->

lib_eio_windows/low_level.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ val read_cstruct : fd -> Cstruct.t -> int
2424
val write : fd -> bytes -> int -> int -> int
2525

2626
val socket : sw:Switch.t -> Unix.socket_domain -> Unix.socket_type -> int -> fd
27-
val connect : fd -> Unix.sockaddr -> unit
27+
val connect : fd -> options:Eio.Net.option list -> Unix.sockaddr -> unit
2828
val accept : sw:Switch.t -> fd -> fd * Unix.sockaddr
2929

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

lib_eio_windows/net.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr.
142142
);
143143
(listening_socket ~hook sock :> _ Eio.Net.listening_socket_ty r)
144144

145-
let connect ~sw connect_addr =
145+
let connect ~sw ~options connect_addr =
146146
let socket_type, addr =
147147
match connect_addr with
148148
| `Unix path -> Unix.SOCK_STREAM, Unix.ADDR_UNIX path
@@ -152,7 +152,7 @@ let connect ~sw connect_addr =
152152
in
153153
let sock = Low_level.socket ~sw (socket_domain_of connect_addr) socket_type 0 in
154154
try
155-
Low_level.connect sock addr;
155+
Low_level.connect sock ~options addr;
156156
(Flow.of_fd sock :> _ Eio_unix.Net.stream_socket)
157157
with Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg)
158158

0 commit comments

Comments
 (0)