Skip to content

Commit 6feee83

Browse files
authored
fix: create fake socket rpc file on windows (#6329)
To allow connections to an rpc instance that isn't in the registry. Previously, the socket file was only created on Unix. So windows users couldn't point their clients at _build/.rpc/dune and connect. Signed-off-by: Rudi Grinberg <[email protected]>
1 parent d20388c commit 6feee83

File tree

7 files changed

+90
-59
lines changed

7 files changed

+90
-59
lines changed

Diff for: CHANGES.md

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Unreleased
2121
- Allow absolute build directories to find public executables. For example,
2222
those specified with `(deps %{bin:...})` (#6326, @anmonteiro)
2323

24+
- Create a fake socket file `_build/.rpc/dune` on windows to allow rpc clients
25+
to connect using the build directory. (#6329, @rgrinberg)
26+
2427
3.5.0 (2022-10-19)
2528
------------------
2629

Diff for: otherlibs/dune-rpc/private/where.mli

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ type t =
55
| `Ip of [ `Host of string ] * [ `Port of int ]
66
]
77

8+
val rpc_socket_relative_to_build_dir : string
9+
810
val to_string : t -> string
911

1012
val compare : t -> t -> Ordering.t

Diff for: src/csexp_rpc/csexp_rpc.ml

+62-58
Original file line numberDiff line numberDiff line change
@@ -226,21 +226,9 @@ module Server = struct
226226
; buf : Bytes.t
227227
}
228228

229-
let create sockaddr ~backlog =
230-
let fd =
231-
Unix.socket ~cloexec:true
232-
(Unix.domain_of_sockaddr sockaddr)
233-
Unix.SOCK_STREAM 0
234-
in
235-
Unix.setsockopt fd Unix.SO_REUSEADDR true;
229+
let create fd sockaddr ~backlog =
236230
Unix.set_nonblock fd;
237-
(match sockaddr with
238-
| ADDR_UNIX p ->
239-
let p = Path.of_string p in
240-
Path.unlink_no_err p;
241-
Path.mkdir_p (Path.parent_exn p);
242-
at_exit (fun () -> Path.unlink_no_err p)
243-
| _ -> ());
231+
Unix.setsockopt fd Unix.SO_REUSEADDR true;
244232
Socket.bind fd sockaddr;
245233
Unix.listen fd backlog;
246234
let r_interrupt_accept, w_interrupt_accept = Unix.pipe ~cloexec:true () in
@@ -276,61 +264,77 @@ module Server = struct
276264
end
277265

278266
type t =
279-
{ mutable transport : Transport.t option
267+
{ mutable state :
268+
[ `Init of Unix.file_descr | `Running of Transport.t | `Closed ]
280269
; backlog : int
281270
; sockaddr : Unix.sockaddr
282271
}
283272

284-
let create sockaddr ~backlog = { sockaddr; backlog; transport = None }
273+
let create sockaddr ~backlog =
274+
let fd =
275+
Unix.socket ~cloexec:true
276+
(Unix.domain_of_sockaddr sockaddr)
277+
Unix.SOCK_STREAM 0
278+
in
279+
{ sockaddr; backlog; state = `Init fd }
285280

286281
let serve (t : t) =
287282
let* async = Worker.create () in
288-
let+ transport =
289-
Worker.task_exn async ~f:(fun () ->
290-
Transport.create t.sockaddr ~backlog:t.backlog)
291-
in
292-
t.transport <- Some transport;
293-
let accept () =
294-
Worker.task async ~f:(fun () ->
295-
Transport.accept transport
296-
|> Option.map ~f:(fun client ->
297-
let in_ = Unix.in_channel_of_descr client in
298-
let out = Unix.out_channel_of_descr client in
299-
(in_, out)))
300-
in
301-
let loop () =
302-
let* accept = accept () in
303-
match accept with
304-
| Error `Stopped ->
305-
Log.info [ Pp.text "RPC stopped accepting." ];
306-
Fiber.return None
307-
| Error (`Exn exn) ->
308-
Log.info
309-
[ Pp.text "RPC accept failed. Server will not accept new clients"
310-
; Exn_with_backtrace.pp exn
311-
];
312-
Fiber.return None
313-
| Ok None ->
314-
Log.info
315-
[ Pp.text
316-
"RPC accepted the last client. No more clients will be accepted."
317-
];
318-
Fiber.return None
319-
| Ok (Some (in_, out)) ->
320-
let+ session = Session.create ~socket:true in_ out in
321-
Some session
322-
in
323-
Fiber.Stream.In.create loop
283+
match t.state with
284+
| `Closed -> Code_error.raise "already closed" []
285+
| `Running _ -> Code_error.raise "already running" []
286+
| `Init fd ->
287+
let+ transport =
288+
Worker.task_exn async ~f:(fun () ->
289+
Transport.create fd t.sockaddr ~backlog:t.backlog)
290+
in
291+
t.state <- `Running transport;
292+
let accept () =
293+
Worker.task async ~f:(fun () ->
294+
Transport.accept transport
295+
|> Option.map ~f:(fun client ->
296+
let in_ = Unix.in_channel_of_descr client in
297+
let out = Unix.out_channel_of_descr client in
298+
(in_, out)))
299+
in
300+
let loop () =
301+
let* accept = accept () in
302+
match accept with
303+
| Error `Stopped ->
304+
Log.info [ Pp.text "RPC stopped accepting." ];
305+
Fiber.return None
306+
| Error (`Exn exn) ->
307+
Log.info
308+
[ Pp.text "RPC accept failed. Server will not accept new clients"
309+
; Exn_with_backtrace.pp exn
310+
];
311+
Fiber.return None
312+
| Ok None ->
313+
Log.info
314+
[ Pp.text
315+
"RPC accepted the last client. No more clients will be \
316+
accepted."
317+
];
318+
Fiber.return None
319+
| Ok (Some (in_, out)) ->
320+
let+ session = Session.create ~socket:true in_ out in
321+
Some session
322+
in
323+
Fiber.Stream.In.create loop
324324

325325
let stop t =
326-
match t.transport with
327-
| None -> Code_error.raise "server not running" []
328-
| Some t -> Transport.stop t
326+
let () =
327+
match t.state with
328+
| `Closed -> ()
329+
| `Running t -> Transport.stop t
330+
| `Init fd -> Unix.close fd
331+
in
332+
t.state <- `Closed
329333

330334
let listening_address t =
331-
match t.transport with
332-
| None -> Code_error.raise "server not running" []
333-
| Some t -> Unix.getsockname t.fd
335+
match t.state with
336+
| `Init fd | `Running { Transport.fd; _ } -> Unix.getsockname fd
337+
| `Closed -> Code_error.raise "server is already closed" []
334338
end
335339

336340
module Client = struct

Diff for: src/dune_rpc_impl/server.ml

+5
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ module Run = struct
5757
let t_var : t Fiber.Var.t = Fiber.Var.create ()
5858

5959
let of_config { Config.handler; backlog; pool; root; where } stats =
60+
let () =
61+
let socket_file = Where.rpc_socket_file () in
62+
Path.mkdir_p (Path.build (Path.Build.parent_exn socket_file));
63+
at_exit (fun () -> Path.Build.unlink_no_err socket_file)
64+
in
6065
let server = Csexp_rpc.Server.create (Where.to_socket where) ~backlog in
6166
{ server; handler; stats; pool; root; where }
6267

Diff for: src/dune_rpc_impl/where.ml

+8
Original file line numberDiff line numberDiff line change
@@ -48,3 +48,11 @@ let to_socket = function
4848
let to_string = function
4949
| `Unix p -> sprintf "unix://%s" p
5050
| `Ip (`Host host, `Port port) -> sprintf "%s:%d" host port
51+
52+
let rpc_socket_file =
53+
let f =
54+
lazy
55+
(Path.Build.(relative root)
56+
Dune_rpc_private.Where.rpc_socket_relative_to_build_dir)
57+
in
58+
fun () -> Lazy.force f

Diff for: src/dune_rpc_impl/where.mli

+2
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@ val get : unit -> Dune_rpc.Where.t option
88

99
val to_socket : Dune_rpc.Where.t -> Unix.sockaddr
1010

11+
val rpc_socket_file : unit -> Path.Build.t
12+
1113
val to_string : Dune_rpc.Where.t -> string

Diff for: test/expect-tests/csexp_rpc/csexp_rpc_tests.ml

+8-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,14 @@ type event =
99
| Fill of Fiber.fill
1010
| Abort
1111

12-
let server where = Server.create where ~backlog:10
12+
let server (where : Unix.sockaddr) =
13+
(match where with
14+
| ADDR_UNIX p ->
15+
let p = Path.of_string p in
16+
Path.unlink_no_err p;
17+
Path.mkdir_p (Path.parent_exn p)
18+
| _ -> ());
19+
Server.create where ~backlog:10
1320

1421
let client where = Csexp_rpc.Client.create where
1522

0 commit comments

Comments
 (0)