Skip to content

Commit 15a8db2

Browse files
committed
Add more windows tests and fix network code
1 parent 23f87f7 commit 15a8db2

File tree

5 files changed

+139
-56
lines changed

5 files changed

+139
-56
lines changed

lib_eio_windows/domain_mgr.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ let run_event_loop fn x =
3030
| Eio_unix.Private.Get_monotonic_clock -> Some (fun k -> continue k (Time.mono_clock : Eio.Time.Mono.t))
3131
| Eio_unix.Private.Socket_of_fd (sw, close_unix, unix_fd) -> Some (fun k ->
3232
let fd = Fd.of_unix ~sw ~blocking:false ~close_unix unix_fd in
33-
Unix.set_nonblock unix_fd;
33+
(* TODO: On Windows, if the FD from Unix.pipe () is passed this will fail *)
34+
(try Unix.set_nonblock unix_fd with Unix.Unix_error (Unix.ENOTSOCK, _, _) -> ());
3435
continue k (Flow.of_fd fd :> Eio_unix.socket)
3536
)
3637
| Eio_unix.Private.Socketpair (sw, domain, ty, protocol) -> Some (fun k ->

lib_eio_windows/low_level.ml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -162,12 +162,6 @@ module Open_flags = struct
162162
let cloexec = Config.o_noinherit
163163
let creat = Config.o_creat
164164
let excl = Config.o_excl
165-
(* let directory = Config.o_directory
166-
let dsync = Config.o_dsync
167-
let noctty = Config.o_noctty
168-
let nofollow = Config.o_nofollow *)
169-
(* let nonblock = Config.o_nonblock *)
170-
(* let sync = Config.o_sync *)
171165
let trunc = Config.o_trunc
172166

173167
let empty = 0

lib_eio_windows/net.ml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ let getaddrinfo ~service node =
8282
aux ()
8383

8484
let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr.stream) =
85-
let socket_type, addr =
85+
let socket_type, addr, is_unix_socket =
8686
match listen_addr with
8787
| `Unix path ->
8888
if reuse_addr then (
@@ -92,10 +92,10 @@ let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr.
9292
| exception Unix.Unix_error (Unix.ENOENT, _, _) -> ()
9393
| exception Unix.Unix_error (code, name, arg) -> raise @@ Err.wrap code name arg
9494
);
95-
Unix.SOCK_STREAM, Unix.ADDR_UNIX path
95+
Unix.SOCK_STREAM, Unix.ADDR_UNIX path, true
9696
| `Tcp (host, port) ->
9797
let host = Eio_unix.Ipaddr.to_unix host in
98-
Unix.SOCK_STREAM, Unix.ADDR_INET (host, port)
98+
Unix.SOCK_STREAM, Unix.ADDR_INET (host, port), false
9999
in
100100
let sock = Low_level.socket ~sw (socket_domain_of listen_addr) socket_type 0 in
101101
(* For Unix domain sockets, remove the path when done (except for abstract sockets). *)
@@ -107,12 +107,14 @@ let listen ~reuse_addr ~reuse_port ~backlog ~sw (listen_addr : Eio.Net.Sockaddr.
107107
Switch.null_hook
108108
in
109109
Fd.use_exn "listen" sock (fun fd ->
110-
if reuse_addr then
110+
(* REUSEADDR cannot be set on a Windows UNIX domain socket,
111+
otherwise the Unix.bind will fail! *)
112+
if not is_unix_socket && reuse_addr then
111113
Unix.setsockopt fd Unix.SO_REUSEADDR true;
112114
if reuse_port then
113115
Unix.setsockopt fd Unix.SO_REUSEPORT true;
114116
Unix.bind fd addr;
115-
Unix.listen fd backlog;
117+
Unix.listen fd backlog
116118
);
117119
listening_socket ~hook sock
118120

lib_eio_windows/test/test.ml

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,56 +12,24 @@ module Timeout = struct
1212
]
1313
end
1414

15-
module Net = struct
16-
open Eio.Std
17-
18-
let read_all flow =
19-
let b = Buffer.create 100 in
20-
Eio.Flow.copy flow (Eio.Flow.buffer_sink b);
21-
Buffer.contents b
22-
23-
let run_client ~sw ~net ~addr =
24-
traceln "Connecting to server...";
25-
let flow = Eio.Net.connect ~sw net addr in
26-
Eio.traceln "connected";
27-
Eio.Flow.copy_string "Hello from client" flow;
28-
Eio.Flow.shutdown flow `Send;
29-
let msg = read_all flow in
30-
msg
31-
32-
let run_server ~sw msg socket =
33-
Eio.Net.accept_fork socket ~sw (fun flow _addr ->
34-
traceln "Server accepted connection from client";
35-
Fun.protect (fun () ->
36-
let msg = read_all flow in
37-
traceln "Server received: %S" msg
38-
) ~finally:(fun () -> Eio.Flow.copy_string msg flow)
39-
)
40-
~on_error:(function
41-
| ex -> traceln "Error handling connection: %s" (Printexc.to_string ex)
42-
)
43-
44-
let test_client_server env () =
45-
Eio.Switch.run @@ fun sw ->
46-
let addr = `Tcp (Eio.Net.Ipaddr.V4.loopback, 8081) in
47-
let server = Eio.Net.listen env#net ~sw ~reuse_addr:true ~backlog:5 addr in
48-
let msg = "From the server" in
49-
Fiber.both
50-
(fun () -> run_server ~sw msg server)
51-
(fun () ->
52-
let client_msg = run_client ~sw ~net:env#net ~addr in
53-
Alcotest.(check string) "same message" msg client_msg
54-
)
55-
15+
module Random = struct
16+
let test_random env () =
17+
let src = Eio.Stdenv.secure_random env in
18+
let b1 = Cstruct.create 8 in
19+
let b2 = Cstruct.create 8 in
20+
Eio.Flow.read_exact src b1;
21+
Eio.Flow.read_exact src b2;
22+
Alcotest.(check bool) "different random" (not (Cstruct.equal b1 b2)) true
5623

5724
let tests env = [
58-
"server-client", `Quick, test_client_server env
25+
"different", `Quick, test_random env
5926
]
6027
end
6128

6229
let () =
6330
Eio_windows.run @@ fun env ->
6431
Alcotest.run "eio_windows" [
65-
"net", Net.tests env;
66-
"timeout", Timeout.tests env
32+
"net", Test_net.tests env;
33+
"timeout", Timeout.tests env;
34+
"random", Random.tests env
6735
]

lib_eio_windows/test/test_net.ml

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
open Eio.Std
2+
3+
let read_all flow =
4+
let b = Buffer.create 100 in
5+
Eio.Flow.copy flow (Eio.Flow.buffer_sink b);
6+
Buffer.contents b
7+
8+
let run_client ~sw ~net ~addr =
9+
traceln "Connecting to server...";
10+
let flow = Eio.Net.connect ~sw net addr in
11+
Eio.traceln "connected";
12+
Eio.Flow.copy_string "Hello from client" flow;
13+
Eio.Flow.shutdown flow `Send;
14+
let msg = read_all flow in
15+
msg
16+
17+
let run_server ~sw msg socket =
18+
Eio.Net.accept_fork socket ~sw (fun flow _addr ->
19+
traceln "Server accepted connection from client";
20+
Fun.protect (fun () ->
21+
let msg = read_all flow in
22+
traceln "Server received: %S" msg
23+
) ~finally:(fun () -> Eio.Flow.copy_string msg flow)
24+
)
25+
~on_error:(function
26+
| ex -> traceln "Error handling connection: %s" (Printexc.to_string ex)
27+
)
28+
29+
let test_client_server env addr () =
30+
Eio.Switch.run @@ fun sw ->
31+
let server = Eio.Net.listen env#net ~sw ~reuse_addr:true ~backlog:5 addr in
32+
let msg = "From the server" in
33+
Fiber.both
34+
(fun () -> run_server ~sw msg server)
35+
(fun () ->
36+
let client_msg = run_client ~sw ~net:env#net ~addr in
37+
Alcotest.(check string) "same message" msg client_msg
38+
)
39+
40+
let run_dgram addr ~net sw msg =
41+
let e1 = `Udp (addr, 8081) in
42+
let e2 = `Udp (addr, 8082) in
43+
let listening_socket = Eio.Net.datagram_socket ~sw net e2 in
44+
Fiber.both
45+
(fun () ->
46+
let buf = Cstruct.create 20 in
47+
traceln "Waiting to receive data on %a" Eio.Net.Sockaddr.pp e2;
48+
let addr, recv = Eio.Net.recv listening_socket buf in
49+
traceln "Received message from %a"
50+
Eio.Net.Sockaddr.pp addr;
51+
Alcotest.(check string) "same udp msg" msg (Cstruct.(to_string (sub buf 0 recv)))
52+
)
53+
(fun () ->
54+
let e = Eio.Net.datagram_socket ~sw net e1 in
55+
traceln "Sending data from %a to %a" Eio.Net.Sockaddr.pp e1 Eio.Net.Sockaddr.pp e2;
56+
Eio.Net.send e e2 (Cstruct.of_string msg))
57+
58+
let test_udp env addr () =
59+
Eio.Switch.run @@ fun sw ->
60+
run_dgram addr ~net:env#net sw "UDP on Windows"
61+
62+
let test_fd env addr () =
63+
Eio.Switch.run @@ fun sw ->
64+
let addr = `Tcp (addr, 8081) in
65+
let server = Eio.Net.listen env#net ~sw ~reuse_addr:true ~backlog:5 addr in
66+
Alcotest.(check bool) "Listening socket has Unix FD" (Eio_unix.Resource.fd_opt server <> None) true;
67+
let have_client, have_server =
68+
Fiber.pair
69+
(fun () ->
70+
let flow = Eio.Net.connect ~sw env#net addr in
71+
(Eio_unix.Resource.fd_opt flow <> None)
72+
)
73+
(fun () ->
74+
let flow, _addr = Eio.Net.accept ~sw server in
75+
(Eio_unix.Resource.fd_opt flow <> None)
76+
)
77+
in
78+
Alcotest.(check bool) "Client-side socket has Unix FD" have_client true;
79+
Alcotest.(check bool) "Server-side socket has Unix FD" have_server true
80+
81+
let test_wrap_socket pipe_or_socketpair () =
82+
Switch.run @@ fun sw ->
83+
let r, w =
84+
match pipe_or_socketpair with
85+
| `Pipe -> Unix.pipe ()
86+
| `Socketpair -> Unix.socketpair Unix.PF_UNIX Unix.SOCK_STREAM 0
87+
in
88+
let source = (Eio_unix.import_socket_stream ~sw ~close_unix:true r :> Eio.Flow.source) in
89+
let sink = (Eio_unix.import_socket_stream ~sw ~close_unix:true w :> Eio.Flow.sink) in
90+
let msg = "Hello" in
91+
Fiber.both
92+
(fun () -> Eio.Flow.copy_string (msg ^ "\n") sink)
93+
(fun () ->
94+
let b = Eio.Buf_read.of_flow source ~max_size:1000 in
95+
Alcotest.(check string) "same message" (Eio.Buf_read.line b) msg
96+
)
97+
98+
let test_eio_socketpair () =
99+
Switch.run @@ fun sw ->
100+
let a, b = Eio_unix.socketpair ~sw () in
101+
ignore (Eio_unix.Resource.fd a : Eio_unix.Fd.t);
102+
ignore (Eio_unix.Resource.fd b : Eio_unix.Fd.t);
103+
Eio.Flow.copy_string "foo" a;
104+
Eio.Flow.close a;
105+
let msg = Eio.Buf_read.of_flow b ~max_size:10 |> Eio.Buf_read.take_all in
106+
Alcotest.(check string) "same messagw" "foo" msg
107+
108+
let tests env = [
109+
"tcp-ip4", `Quick, test_client_server env (`Tcp (Eio.Net.Ipaddr.V4.loopback, 8081));
110+
"tcp-ip6", `Quick, test_client_server env (`Tcp (Eio.Net.Ipaddr.V6.loopback, 8081));
111+
"unix", `Quick, test_client_server env (`Unix "eio-test.sock");
112+
"udp-ip4", `Quick, test_udp env Eio.Net.Ipaddr.V4.loopback;
113+
"udp-ip6", `Quick, test_udp env Eio.Net.Ipaddr.V6.loopback;
114+
"fds", `Quick, test_fd env Eio.Net.Ipaddr.V4.loopback;
115+
"wrap-pipe", `Quick, test_wrap_socket `Pipe;
116+
"wrap-socketpair", `Quick, test_wrap_socket `Socketpair;
117+
"eio-socketpair", `Quick, test_eio_socketpair
118+
]

0 commit comments

Comments
 (0)