Skip to content

Commit be714e6

Browse files
authored
Merge pull request #321 from djs55/async-dns
Mac: make the DNS more scalable
2 parents 17c0b7e + 2603574 commit be714e6

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

src/bin/main.ml

+5
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,11 @@ let hvsock_addr_of_uri ~default_serviceid uri =
352352
if debug || env_debug then Some Logs.Debug else Some Logs.Info in
353353
Logging.setup log_destination level;
354354

355+
if Sys.os_type = "Unix" then begin
356+
Log.info (fun f -> f "Increasing preemptive thread pool size to 1024 threads");
357+
Uwt_preemptive.set_bounds (0, 1024);
358+
end;
359+
355360
let host_names = List.map Dns.Name.of_string @@ Astring.String.cuts ~sep:"," host_names in
356361
let dns_path, resolver = match dns with
357362
| None -> None, Configuration.default_resolver

src/hostnet/host.ml

+60-5
Original file line numberDiff line numberDiff line change
@@ -1133,11 +1133,66 @@ module Dns = struct
11331133

11341134
let resolve_dnssd question =
11351135
let open Dns.Packet in
1136-
let query name ty =
1137-
Uwt_preemptive.detach
1138-
(fun () ->
1139-
Dnssd.query (Dns.Name.to_string name) ty
1140-
) () in
1136+
let query_one name ty =
1137+
let query = Dnssd.LowLevel.query (Dns.Name.to_string name) ty in
1138+
let socket = Dnssd.LowLevel.socket query in
1139+
let t, u = Lwt.task () in
1140+
match Uwt.Poll.start socket [ Uwt.Poll.Readable ]
1141+
~cb:(fun _poll events ->
1142+
match events with
1143+
| Error error ->
1144+
Log.err (fun f -> f "Uwt.Poll callback failed with %s" (Uwt.strerror error))
1145+
| Ok events ->
1146+
List.iter (fun event ->
1147+
if event = Uwt.Poll.Readable then Lwt.wakeup_later u ()
1148+
) events
1149+
) with
1150+
| Error error ->
1151+
Log.err (fun f -> f "Uwt.Poll.start failed with %s" (Uwt.strerror error));
1152+
Lwt.return (Ok [])
1153+
| Ok poll ->
1154+
t >>= fun () ->
1155+
let result = Uwt.Poll.close poll in
1156+
if not (Uwt.Int_result.is_ok result) then begin
1157+
let error = Uwt.Int_result.to_error result in
1158+
Log.err (fun f -> f "Uwt.Poll.close failed with %s" (Uwt.strerror error));
1159+
Lwt.return (Ok [])
1160+
end else begin
1161+
Uwt_preemptive.detach
1162+
(fun () ->
1163+
Dnssd.LowLevel.response query
1164+
) ()
1165+
end in
1166+
1167+
let query requested_name ty =
1168+
(* The DNSServiceRef API will return CNAMEs first, without resolving to
1169+
A/AAAA/... This function recursively resolves the CNAMES while avoiding
1170+
returning duplicate records. *)
1171+
(* NB we only return NoSuchRecord if we find no records. This is because it
1172+
is possible to query a CNAME which exists, but which points to a non-existent
1173+
record. *)
1174+
let open Dnssd in
1175+
let rec loop acc name ty =
1176+
query_one name ty
1177+
>>= function
1178+
(* When we're recursing, ignore the NoSuchRecord error *)
1179+
| Error NoSuchRecord when name <> requested_name -> Lwt.return (Ok acc)
1180+
| Error e -> Lwt.return (Error e)
1181+
| Ok rrs ->
1182+
let not_seen_before = List.filter (fun x -> not (List.mem x acc)) rrs in
1183+
(* If there are any CNAMEs, resolve these too *)
1184+
let cnames = List.rev @@ List.fold_left (fun acc rr ->
1185+
match rr.Dns.Packet.rdata with
1186+
| CNAME name -> name :: acc
1187+
| _ -> acc
1188+
) [] not_seen_before in
1189+
Lwt_list.fold_left_s
1190+
(fun acc name -> match acc with
1191+
| Error e -> Lwt.return (Error e)
1192+
| Ok acc ->
1193+
loop acc name ty
1194+
) (Ok (acc @ not_seen_before)) cnames in
1195+
loop [] requested_name ty in
11411196

11421197
begin match question with
11431198
| { q_class = Q_IN; q_name; _ } when q_name = localhost_local ->

0 commit comments

Comments
 (0)