shithub: mc

Download patch

ref: 3b6a42aaa1dfb75db06e9bf8cb7953cecefc647f
parent: 41046c6382017e0297f8e07a7493c2cd779b8f0b
author: Frank Smit <frank@61924.nl>
date: Fri Sep 18 13:21:29 EDT 2020

Query nameservers in parallel.

--- a/lib/std/resolve+posixy.myr
+++ b/lib/std/resolve+posixy.myr
@@ -22,8 +22,6 @@
 use "types"
 use "utf"
 
-use "fmt"
-
 pkg std =
 	type rectype = union
 		`DnsA		/* host address */
@@ -61,6 +59,8 @@
 	const resolve		: (host : byte[:]	-> result(hostinfo[:], resolveerr))
 	const resolvemx		: (host : byte[:]	-> result(hostinfo[:], resolveerr))
 	const resolverec	: (host : byte[:], t : rectype[:]	-> result(hostinfo[:], resolveerr))
+
+	const maxns = 5
 ;;
 
 const Hostfile = "/etc/hosts"
@@ -152,7 +152,7 @@
 				invalid addresses are ignored: we don't want to break stuff
 				with invalid or unsupported addresses
 				*/
-				
+
 			;;
 		| `None:
 		;;
@@ -222,7 +222,7 @@
 	match word(rest)
 	| `Some (name, _):
 		match ipparse(name)
-		| `Some addr: 
+		| `Some addr:
 			slpush(&nameservers, addr)
 		| `None:
 			/* nothing */
@@ -247,23 +247,32 @@
 	;;
 }
 
-
 const dnsresolve = {host, rt
-	var nsrv, r
+	var srv : sys.pollfd[maxns]
+	var cutoff
+	var ret
 
 	if !valid(host)
 		-> `Err (`Badhost)
 	;;
-	/* FIXME: Assumption: nameservers is not modified by other threads */
-	for ns : nameservers
-		nsrv = dnsconnect(ns)
-		if nsrv >= 0
-			r = dnsquery(nsrv, host, rt)
-			sys.close(nsrv)
-			-> r
-		;;
+
+	cutoff = std.min(maxns, nameservers.len)
+
+	for var i = 0; i < cutoff; i++
+		srv[i] = [
+			.fd=dnsconnect(nameservers[i]),
+			.events=sys.Pollout,
+			.revents=0,
+		]
 	;;
-	-> `Err (`Badsrv)
+
+	ret = dnsquery(srv[:cutoff], host, rt)
+
+	for s : srv[:cutoff]
+		sys.close(s.fd)
+	;;
+
+	-> ret
 }
 
 const dnsconnect = {ns
@@ -295,10 +304,55 @@
 }
 
 const dnsquery = {srv, host, t
-	var id
+	var pkt : byte[512] /* big enough */
+	var id : uint16[maxns]
+	var query
+	var fail
+	var giveup
 
-	id = tquery(srv, host, t)
-	-> rquery(srv, host, id)
+	fail = 0
+	giveup = now() + 1000*Timeout
+
+	while true
+		/* all failed */
+		if fail == srv.len
+			break
+		;;
+
+		var r = sys.poll(srv, (giveup - std.now() : int)/1000)
+		if r < 0
+			-> `Err `Badconn
+		elif r == 0
+			-> `Err `Timeout
+		;;
+
+		for var i = 0; i < srv.len; i++
+			var s = &srv[i]
+
+			if (s.revents & sys.Pollout) != 0
+				(id[i], query) = mkquery(host, t)
+				sys.write(s.fd, query)
+				s.events = sys.Pollin
+			elif (s.revents & sys.Pollin) != 0
+				var n = sys.read(s.fd, pkt[:])
+				if n < 0
+					-> `Err `Badconn
+				;;
+
+				var inf = hosts(pkt[:n], host, id[i])
+				match inf
+				| `std.Err `Badresp:
+					/* continue polling */
+				| _:
+					-> inf
+				;;
+			else
+				fail++
+			;;
+		;;
+	;;
+
+	-> `Err (`Badsrv)
 }
 
 const Qr : uint16 = 1 << 0
@@ -308,7 +362,7 @@
 const Ra : uint16 = 1 << 8
 
 var nextid : uint16 = 42
-const tquery = {srv, host, t
+const mkquery = {host, t
 	var pkt : byte[512] /* big enough */
 	var off : size
 
@@ -327,39 +381,7 @@
 	off += pack16(pkt[:], off, (t : uint16)) /* qtype: a record */
 	off += pack16(pkt[:], off, 0x1) /* qclass: inet4 */
 
-	sys.write(srv, pkt[:off])
-	-> nextid
-}
-
-const rquery = {srv, host, id
-	var pktbuf : byte[1024]
-	var pkt, pfd, giveup
-	var r, n, inf
-
-	giveup = std.now() + 1000*Timeout
-:again
-	pfd = [
-		[.fd=srv, .events=sys.Pollin, .revents=0]
-	][:]
-	r = sys.poll(pfd[:], (giveup - std.now() : int)/1000)
-	if r < 0
-		-> `Err `Badconn
-	elif r == 0
-		-> `Err `Timeout
-	else
-		n = sys.read(srv, pktbuf[:])
-		if n < 0
-			-> `Err `Badconn
-		;;
-		pkt = pktbuf[:n]
-		inf = hosts(pkt, host, id)
-		match inf
-		| `std.Err `Badresp:
-			goto again
-		| _:	
-			-> inf
-		;;
-	;;
+	-> (nextid, pkt[:off])
 }
 
 const hosts = {pkt, host, id