1 module eventcore.drivers.winapi.dns;
2 
3 version (Windows):
4 
5 import eventcore.driver;
6 import eventcore.internal.win32;
7 
8 
9 final class WinAPIEventDriverDNS : EventDriverDNS {
10 @safe: /*@nogc:*/ nothrow:
11 
12 	DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished)
13 	{
14 		import std.typecons : scoped;
15 		import std.utf : toUTF16z;
16 
17 		auto id = DNSLookupID(0, 0);
18 
19 		static immutable ushort[] addrfamilies = [AF_INET, AF_INET6];
20 
21 		const(WCHAR)* namew;
22 		try namew = name.toUTF16z;
23 		catch (Exception e) return DNSLookupID.invalid;
24 
25 		foreach (af; addrfamilies) {
26 			//if (family != af && family != AF_UNSPEC) continue;
27 
28 			SOCKADDR_STORAGE sa;
29 			INT addrlen = sa.sizeof;
30 			auto ret = () @trusted { return WSAStringToAddressW(namew, af, null, cast(sockaddr*)&sa, &addrlen); } ();
31 			if (ret != 0) continue;
32 
33 			scope addr = new RefAddress(() @trusted { return cast(sockaddr*)&sa; } (), addrlen);
34 			RefAddress[1] addrs;
35 			addrs[0] = addr;
36 			on_lookup_finished(id, DNSStatus.ok, addrs);
37 			return id;
38 		}
39 
40 		version (none) { // Windows 8+
41 			LookupStatus status;
42 			status.task = Task.getThis();
43 			status.driver = this;
44 			status.finished = false;
45 
46 			WSAOVERLAPPEDX overlapped;
47 			overlapped.Internal = 0;
48 			overlapped.InternalHigh = 0;
49 			overlapped.hEvent = cast(HANDLE)cast(void*)&status;
50 
51 			void* aif;
52 			ADDRINFOEXW addr_hint;
53 			ADDRINFOEXW* addr_ret;
54 			addr_hint.ai_family = family;
55 			addr_hint.ai_socktype = SOCK_STREAM;
56 			addr_hint.ai_protocol = IPPROTO_TCP;
57 
58 			enforce(GetAddrInfoExW(namew, null, NS_DNS, null, &addr_hint, &addr_ret, null, &overlapped, &onDnsResult, null) == 0, "Failed to lookup host");
59 			while (!status.finished) m_core.yieldForEvent();
60 			enforce(!status.error, "Failed to lookup host: "~to!string(status.error));
61 
62 			aif = addr_ret;
63 			addr.family = cast(ubyte)addr_ret.ai_family;
64 			switch (addr.family) {
65 				default: assert(false, "Invalid address family returned from host lookup.");
66 				case AF_INET: addr.sockAddrInet4 = *cast(sockaddr_in*)addr_ret.ai_addr; break;
67 				case AF_INET6: addr.sockAddrInet6 = *cast(sockaddr_in6*)addr_ret.ai_addr; break;
68 			}
69 			FreeAddrInfoExW(addr_ret);
70 		} else {
71 			ADDRINFOW* results;
72 			if (auto ret = () @trusted { return GetAddrInfoW(namew, null, null, &results); } ()) {
73 				on_lookup_finished(id, DNSStatus.error, null);
74 				return id;
75 			}
76 
77 			scope(failure) assert(false);
78 			() @trusted {
79 				typeof(scoped!RefAddress())[16] addr_storage = [
80 					scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(),
81 					scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(),
82 					scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(),
83 					scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress()
84 				];
85 				RefAddress[16] buf;
86 				size_t naddr = 0;
87 				while (results) {
88 					RefAddress addr = addr_storage[naddr];
89 					addr.set(results.ai_addr, cast(socklen_t)results.ai_addrlen);
90 					buf[naddr++] = addr;
91 					results = results.ai_next;
92 				}
93 
94 				on_lookup_finished(id, DNSStatus.ok, buf[0 .. naddr]);
95 			} ();
96 		}
97 
98 		return id;
99 	}
100 
101 	void cancelLookup(DNSLookupID handle)
102 	{
103 		if (!isValid(handle)) return;
104 
105 		assert(false, "TODO!");
106 	}
107 
108 	override bool isValid(DNSLookupID handle)
109 	const {
110 		return handle == DNSLookupID(0, 0);
111 	}
112 }