1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
let default_timeout = 30.
let connect ?(timeout = default_timeout) (caps : < Cap.network ; .. >) ~(host : string) ~(port : int) () :
Unix.file_descr =
let (_ : Cap.Network.t) = caps#network host in
let addresses = Unix.getaddrinfo host (string_of_int port) [ Unix.AI_SOCKTYPE Unix.SOCK_STREAM ] in
if addresses = [] then failwith (Printf.sprintf "Tcp.connect: can't resolve %S" host);
let rec try_ = function
| [] -> assert false
| (a : Unix.addr_info) :: others -> (
let fd = Unix.socket a.ai_family a.ai_socktype a.ai_protocol in
try
Unix.setsockopt_float fd Unix.SO_RCVTIMEO timeout;
Unix.setsockopt_float fd Unix.SO_SNDTIMEO timeout;
Unix.connect fd a.ai_addr;
fd
with Unix.Unix_error _ as e ->
Unix.close fd;
if others = [] then raise e else try_ others)
in
try_ addresses
let send_all (fd : Unix.file_descr) (s : string) : unit =
let rec go pos = if pos < String.length s then go (pos + Unix.write_substring fd s pos (String.length s - pos)) in
go 0
let receive_all (fd : Unix.file_descr) : string =
let b = Buffer.create 65536 in
let chunk = Bytes.create 65536 in
let rec go () =
match Unix.read fd chunk 0 (Bytes.length chunk) with
| 0 -> Buffer.contents b
| n ->
Buffer.add_subbytes b chunk 0 n;
go ()
in
go ()
let exchange ?timeout (caps : < Cap.network ; .. >) ~(host : string) ~(port : int) (s : string) : string =
let fd = connect ?timeout caps ~host ~port () in
Fun.protect
~finally:(fun () -> Unix.close fd)
(fun () ->
send_all fd s;
receive_all fd)