1 module upromised.dns;
2 import deimos.libuv.uv : uv_getaddrinfo, uv_getaddrinfo_t, uv_freeaddrinfo, uv_loop_t, uv_interface_address_t, uv_interface_addresses, uv_free_interface_addresses;
3 import deimos.libuv._d : addrinfo;
4 import std.socket : Address;
5 import upromised.promise : DelegatePromise, Promise;
6 import upromised.memory : getSelf, gcretain, gcrelease;
7 import upromised.uv : uvCheck;
8 version(Posix) {
9 	public import core.sys.posix.netdb : sockaddr, sockaddr_in, sockaddr_in6;
10 } else version(Windows) {
11 	public import core.sys.windows.winsock2 : sockaddr, sockaddr_in, sockaddr_in6;
12 }
13 
14 Address[] toAddress(const(addrinfo)* each) nothrow {
15 	Address[] r;
16 	while (each !is null) {
17 		r ~= each.ai_addr.toAddress(each.ai_addrlen);
18 		each = each.ai_next;
19 	}
20 	return r;
21 }
22 
23 Address toAddress(const(sockaddr)* each, size_t len = 16) nothrow {
24 	import std.socket : AddressFamily, InternetAddress, Internet6Address, UnknownAddressReference;
25 
26 	if (each is null) {
27 		return null;
28 	} else if (each.sa_family == AddressFamily.INET) {
29 		return new InternetAddress(*cast(sockaddr_in*)each);
30 	} else if (each.sa_family == AddressFamily.INET6) {
31 		return new Internet6Address(*cast(sockaddr_in6*)each);
32 	} else {
33 		ubyte[] copy = new ubyte[len];
34 		copy[] = (cast(const(ubyte)*)(each))[0..len];
35 		return new UnknownAddressReference(cast(sockaddr*)copy.ptr, cast(int)copy.length);
36 	}
37 }
38 
39 Promise!(Address[]) getAddrinfo(uv_loop_t* ctx, const(char)[] node, ushort port) nothrow {
40     import std.conv : to;
41     return getAddrinfo(ctx, node, port.to!string);
42 }
43 Promise!(Address[]) getAddrinfo(uv_loop_t* ctx, const(char)[] node, const(char)[] service) nothrow {
44 	import std..string : toStringz;
45 	auto r = new GetAddrinfoPromise;
46 	
47 	if (node !is null) {
48 		r.node = node.toStringz;
49 	}
50 
51 	if (service !is null) {
52 		r.service = service.toStringz;
53 	}
54 
55 	gcretain(r);
56 	int err = uv_getaddrinfo(ctx, &r.self, (rSelf, status, res) nothrow {
57 		auto r = getSelf!GetAddrinfoPromise(rSelf);
58 		if (status.uvCheck(r)) return;
59 		r.resolve(res.toAddress);
60 		uv_freeaddrinfo(res);
61 	}, r.node, r.service, null);
62 	err.uvCheck(r);
63 	r.finall(() => gcrelease(r));
64 	return r;
65 }
66 private class GetAddrinfoPromise : DelegatePromise!(Address[]) {
67 	const(char)* node;
68 	const(char)* service;
69 	uv_getaddrinfo_t self;
70 }
71 
72 Address[] listLocalAddresses() {
73 	import std.array : array;
74 	import std.algorithm : filter, map;
75 	import std.socket : AddressFamily;
76 
77 	uv_interface_address_t* info;
78 	int count;
79 	uv_interface_addresses(&info, &count);
80 	scope(exit) uv_free_interface_addresses(info, count);
81 
82 	return info[0..count]
83 	.filter!((x) => !x.is_internal)
84 	.map!((x) {
85 		if (x.address.address4.sin_family == AddressFamily.INET6) {
86 			return toAddress(cast(const(sockaddr)*)&x.address.address6, x.address.address6.sizeof);
87 		} else  {
88 			return toAddress(cast(const(sockaddr)*)&x.address.address4, x.address.address4.sizeof);
89 		}
90 	}).array;
91 }