Skip to content

Commit 594bc12

Browse files
committed
Eio.Net.connect: optionally bind before connect
1 parent 14ae3cf commit 594bc12

File tree

9 files changed

+36
-21
lines changed

9 files changed

+36
-21
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 ?bind:_ 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: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ module Pi = struct
235235
type tag
236236

237237
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
238+
val connect : t -> sw:Switch.t -> ?bind:Sockaddr.stream -> Sockaddr.stream -> tag stream_socket_ty r
239239
val datagram_socket :
240240
t
241241
-> reuse_addr:bool
@@ -295,10 +295,10 @@ let listen (type tag) ?(reuse_addr=false) ?(reuse_port=false) ~backlog ~sw (t:[>
295295
let module X = (val (Resource.get ops Pi.Network)) in
296296
X.listen t ~reuse_addr ~reuse_port ~backlog ~sw
297297

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

lib_eio/net.mli

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,10 +129,12 @@ 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+
val connect : sw:Switch.t -> ?bind:Sockaddr.stream -> [> 'tag ty] t -> Sockaddr.stream -> 'tag stream_socket_ty r
133133
(** [connect ~sw t addr] is a new socket connected to remote address [addr].
134134
135-
The new socket will be closed when [sw] finishes, unless closed manually first. *)
135+
The new socket will be closed when [sw] finishes, unless closed manually first.
136+
137+
@param bind Set the outbound client address. *)
136138

137139
val with_tcp_connect :
138140
?timeout:Time.Timeout.t ->
@@ -346,7 +348,7 @@ module Pi : sig
346348
t -> reuse_addr:bool -> reuse_port:bool -> backlog:int -> sw:Switch.t ->
347349
Sockaddr.stream -> tag listening_socket_ty r
348350

349-
val connect : t -> sw:Switch.t -> Sockaddr.stream -> tag stream_socket_ty r
351+
val connect : t -> sw:Switch.t -> ?bind:Sockaddr.stream -> Sockaddr.stream -> tag stream_socket_ty r
350352

351353
val datagram_socket :
352354
t

lib_eio_linux/eio_linux.ml

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

259-
let connect ~sw connect_addr =
259+
let connect ~sw ?bind 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-
Low_level.connect sock addr;
263+
let bind = Option.map Eio_unix.Net.sockaddr_to_unix bind in
264+
Low_level.connect sock ?bind addr;
264265
(flow sock :> _ Eio_unix.Net.stream_socket)
265266

266267
module Impl = struct
@@ -296,7 +297,8 @@ module Impl = struct
296297
Unix.listen sock_unix backlog;
297298
(listening_socket sock :> _ Eio.Net.listening_socket_ty r)
298299

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

301303
let datagram_socket () ~reuse_addr ~reuse_port ~sw saddr =
302304
if reuse_addr then (

lib_eio_linux/low_level.ml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,15 @@ 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 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 =
225231
Fd.use_exn "connect" fd @@ fun fd ->
232+
try_bind fd bind;
226233
let res = Sched.enter "connect" (enqueue_connect fd addr) in
227234
if res < 0 then (
228235
let ex =

lib_eio_linux/low_level.mli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ 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
114+
val connect : fd -> ?bind:Unix.sockaddr -> Unix.sockaddr -> unit
115115
(** [connect fd addr] attempts to connect socket [fd] to [addr]. *)
116116

117117
val await_readable : fd -> unit

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 ?bind addr =
7171
try
72-
Fd.use_exn "connect" fd (fun fd -> Unix.connect fd addr)
72+
Fd.use_exn "connect" fd @@ fun fd ->
73+
Option.iter (Unix.bind fd) bind;
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 -> ?bind:Unix.sockaddr -> 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: 5 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 ?bind connect_addr =
142142
let socket_type, addr =
143143
match connect_addr with
144144
| `Unix path -> Unix.SOCK_STREAM, Unix.ADDR_UNIX path
@@ -147,8 +147,9 @@ let connect ~sw connect_addr =
147147
Unix.SOCK_STREAM, Unix.ADDR_INET (host, port)
148148
in
149149
let sock = Low_level.socket ~sw (socket_domain_of connect_addr) socket_type 0 in
150+
let bind = Option.map Eio_unix.Net.sockaddr_to_unix bind in
150151
try
151-
Low_level.connect sock addr;
152+
Low_level.connect sock ?bind addr;
152153
(Flow.of_fd sock :> _ Eio_unix.Net.stream_socket)
153154
with Unix.Unix_error (code, name, arg) -> raise (Err.wrap code name arg)
154155

@@ -174,8 +175,8 @@ module Impl = struct
174175

175176
let listen () = listen
176177

177-
let connect () ~sw addr =
178-
let socket = connect ~sw addr in
178+
let connect () ~sw ?bind addr =
179+
let socket = connect ~sw ?bind addr in
179180
(socket :> [`Generic | `Unix] Eio.Net.stream_socket_ty r)
180181

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

0 commit comments

Comments
 (0)