Implement simple (synchronous) DNS lookup for the WinAPI driver.

This commit is contained in:
Sönke Ludwig 2017-01-23 21:37:35 +01:00
parent e8a0968ded
commit 356a34fad2
5 changed files with 251 additions and 2 deletions

View file

@ -30,7 +30,7 @@ Feature | SelectEventDriver | EpollEventDriver | WinAPIEventDriver | Kq
TCP Sockets | yes | yes | — | yes TCP Sockets | yes | yes | — | yes
UDP Sockets | yes | yes | — | yes UDP Sockets | yes | yes | — | yes
USDS | yes | yes | — | yes USDS | yes | yes | — | yes
DNS | yes | yes | — | yes DNS | yes | yes | yes | yes
Timers | yes | yes | yes | yes Timers | yes | yes | yes | yes
Events | yes | yes | yes | yes Events | yes | yes | yes | yes
Unix Signals | yes² | yes² | — | — Unix Signals | yes² | yes² | — | —

View file

@ -7,6 +7,7 @@ targetType "library"
libs "anl" platform="linux" libs "anl" platform="linux"
libs "ws2_32" "user32" platform="windows" libs "ws2_32" "user32" platform="windows"
sourceFiles "lib/ws2_32.lib" platform="windows-x86-dmd"
dependency "taggedalgebraic" version="~>0.10.4" dependency "taggedalgebraic" version="~>0.10.4"

BIN
lib/ws2_32.lib Normal file

Binary file not shown.

View file

@ -13,6 +13,7 @@ import eventcore.driver;
import eventcore.drivers.timer; import eventcore.drivers.timer;
import eventcore.internal.consumablequeue : ConsumableQueue; import eventcore.internal.consumablequeue : ConsumableQueue;
import eventcore.internal.utils; import eventcore.internal.utils;
import eventcore.internal.win32;
import taggedalgebraic; import taggedalgebraic;
import core.sys.windows.windows; import core.sys.windows.windows;
import core.sys.windows.winsock2; import core.sys.windows.winsock2;
@ -357,7 +358,91 @@ final class WinAPIEventDriverDNS : EventDriverDNS {
DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished) DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished)
{ {
assert(false, "TODO!"); import std.typecons : scoped;
import std.utf : toUTF16z;
auto id = DNSLookupID(0);
static immutable ushort[] addrfamilies = [AF_INET, AF_INET6];
const(WCHAR)* namew;
try namew = name.toUTF16z;
catch (Exception e) return DNSLookupID.invalid;
foreach (af; addrfamilies) {
//if (family != af && family != AF_UNSPEC) continue;
SOCKADDR_STORAGE sa;
INT addrlen = sa.sizeof;
auto ret = () @trusted { return WSAStringToAddressW(namew, af, null, cast(sockaddr*)&sa, &addrlen); } ();
if (ret != 0) continue;
scope addr = new RefAddress(() @trusted { return cast(sockaddr*)&sa; } (), addrlen);
RefAddress[1] addrs;
addrs[0] = addr;
on_lookup_finished(id, DNSStatus.ok, addrs);
return id;
}
version(none){ // Windows 8+
LookupStatus status;
status.task = Task.getThis();
status.driver = this;
status.finished = false;
WSAOVERLAPPEDX overlapped;
overlapped.Internal = 0;
overlapped.InternalHigh = 0;
overlapped.hEvent = cast(HANDLE)cast(void*)&status;
void* aif;
ADDRINFOEXW addr_hint;
ADDRINFOEXW* addr_ret;
addr_hint.ai_family = family;
addr_hint.ai_socktype = SOCK_STREAM;
addr_hint.ai_protocol = IPPROTO_TCP;
enforce(GetAddrInfoExW(namew, null, NS_DNS, null, &addr_hint, &addr_ret, null, &overlapped, &onDnsResult, null) == 0, "Failed to lookup host");
while( !status.finished ) m_core.yieldForEvent();
enforce(!status.error, "Failed to lookup host: "~to!string(status.error));
aif = addr_ret;
addr.family = cast(ubyte)addr_ret.ai_family;
switch(addr.family){
default: assert(false, "Invalid address family returned from host lookup.");
case AF_INET: addr.sockAddrInet4 = *cast(sockaddr_in*)addr_ret.ai_addr; break;
case AF_INET6: addr.sockAddrInet6 = *cast(sockaddr_in6*)addr_ret.ai_addr; break;
}
FreeAddrInfoExW(addr_ret);
} else {
ADDRINFOW* results;
if (auto ret = () @trusted { return GetAddrInfoW(namew, null, null, &results); } ()) {
on_lookup_finished(id, DNSStatus.error, null);
return id;
}
scope(failure) assert(false);
() @trusted {
typeof(scoped!RefAddress())[16] addr_storage = [
scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(),
scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(),
scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(),
scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress(), scoped!RefAddress()
];
RefAddress[16] buf;
size_t naddr = 0;
while (results) {
RefAddress addr = addr_storage[naddr];
addr.set(results.ai_addr, results.ai_addrlen);
buf[naddr++] = addr;
results = results.ai_next;
}
on_lookup_finished(id, DNSStatus.ok, buf[0 .. naddr]);
} ();
}
return id;
} }
void cancelLookup(DNSLookupID handle) void cancelLookup(DNSLookupID handle)

View file

@ -0,0 +1,163 @@
module eventcore.internal.win32;
version(Windows):
public import core.sys.windows.windows;
public import core.sys.windows.winsock2;
extern(System) nothrow @nogc:
BOOL GetFileSizeEx(HANDLE hFile, long *lpFileSize);
enum {
FD_READ = 0x0001,
FD_WRITE = 0x0002,
FD_OOB = 0x0004,
FD_ACCEPT = 0x0008,
FD_CONNECT = 0x0010,
FD_CLOSE = 0x0020,
FD_QOS = 0x0040,
FD_GROUP_QOS = 0x0080,
FD_ROUTING_INTERFACE_CHANGE = 0x0100,
FD_ADDRESS_LIST_CHANGE = 0x0200
}
enum {
WSA_FLAG_OVERLAPPED = 0x01
}
enum {
WSAPROTOCOL_LEN = 255,
MAX_PROTOCOL_CHAIN = 7,
}
enum WSA_IO_PENDING = 997;
struct WSAPROTOCOL_INFOW {
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlags4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
WCHAR[WSAPROTOCOL_LEN+1] szProtocol;
}
struct WSAPROTOCOLCHAIN {
int ChainLen;
DWORD[MAX_PROTOCOL_CHAIN] ChainEntries;
}
struct WSABUF {
size_t len;
ubyte *buf;
}
struct ADDRINFOEXW {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
LPCWSTR ai_canonname;
sockaddr* ai_addr;
void* ai_blob;
size_t ai_bloblen;
GUID* ai_provider;
ADDRINFOEXW* ai_next;
}
struct ADDRINFOA {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
LPSTR ai_canonname;
sockaddr* ai_addr;
ADDRINFOA* ai_next;
}
struct ADDRINFOW {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol;
size_t ai_addrlen;
LPWSTR ai_canonname;
sockaddr* ai_addr;
ADDRINFOW* ai_next;
}
struct WSAPROTOCOL_INFO {
DWORD dwServiceFlags1;
DWORD dwServiceFlags2;
DWORD dwServiceFlags3;
DWORD dwServiceFlags4;
DWORD dwProviderFlags;
GUID ProviderId;
DWORD dwCatalogEntryId;
WSAPROTOCOLCHAIN ProtocolChain;
int iVersion;
int iAddressFamily;
int iMaxSockAddr;
int iMinSockAddr;
int iSocketType;
int iProtocol;
int iProtocolMaxOffset;
int iNetworkByteOrder;
int iSecurityScheme;
DWORD dwMessageSize;
DWORD dwProviderReserved;
CHAR[WSAPROTOCOL_LEN+1] szProtocol;
}
alias SOCKADDR = sockaddr;
alias LPWSAOVERLAPPED_COMPLETION_ROUTINEX = void function(DWORD, DWORD, WSAOVERLAPPEDX*, DWORD);
alias LPLOOKUPSERVICE_COMPLETION_ROUTINE = void function(DWORD, DWORD, WSAOVERLAPPEDX*);
alias LPCONDITIONPROC = void*;
alias LPTRANSMIT_FILE_BUFFERS = void*;
SOCKET WSAAccept(SOCKET s, sockaddr *addr, INT* addrlen, LPCONDITIONPROC lpfnCondition, DWORD_PTR dwCallbackData);
int WSAAsyncSelect(SOCKET s, HWND hWnd, uint wMsg, sizediff_t lEvent);
SOCKET WSASocketW(int af, int type, int protocol, WSAPROTOCOL_INFOW *lpProtocolInfo, uint g, DWORD dwFlags);
int WSARecv(SOCKET s, WSABUF* lpBuffers, DWORD dwBufferCount, DWORD* lpNumberOfBytesRecvd, DWORD* lpFlags, in WSAOVERLAPPEDX* lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINEX lpCompletionRoutine);
int WSASend(SOCKET s, in WSABUF* lpBuffers, DWORD dwBufferCount, DWORD* lpNumberOfBytesSent, DWORD dwFlags, in WSAOVERLAPPEDX* lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINEX lpCompletionRoutine);
int WSASendDisconnect(SOCKET s, WSABUF* lpOutboundDisconnectData);
INT WSAStringToAddressA(in LPTSTR AddressString, INT AddressFamily, in WSAPROTOCOL_INFO* lpProtocolInfo, SOCKADDR* lpAddress, INT* lpAddressLength);
INT WSAStringToAddressW(in LPWSTR AddressString, INT AddressFamily, in WSAPROTOCOL_INFOW* lpProtocolInfo, SOCKADDR* lpAddress, INT* lpAddressLength);
INT WSAAddressToStringW(in SOCKADDR* lpsaAddress, DWORD dwAddressLength, in WSAPROTOCOL_INFO* lpProtocolInfo, LPWSTR lpszAddressString, DWORD* lpdwAddressStringLength);
int GetAddrInfoExW(LPCWSTR pName, LPCWSTR pServiceName, DWORD dwNameSpace, GUID* lpNspId, const ADDRINFOEXW *pHints, ADDRINFOEXW **ppResult, timeval *timeout, WSAOVERLAPPEDX* lpOverlapped, LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine, HANDLE* lpNameHandle);
int GetAddrInfoW(LPCWSTR pName, LPCWSTR pServiceName, const ADDRINFOW *pHints, ADDRINFOW **ppResult);
int getaddrinfo(LPCSTR pName, LPCSTR pServiceName, const ADDRINFOA *pHints, ADDRINFOA **ppResult);
void FreeAddrInfoW(ADDRINFOW* pAddrInfo);
void FreeAddrInfoExW(ADDRINFOEXW* pAddrInfo);
void freeaddrinfo(ADDRINFOA* ai);
BOOL TransmitFile(SOCKET hSocket, HANDLE hFile, DWORD nNumberOfBytesToWrite, DWORD nNumberOfBytesPerSend, OVERLAPPED* lpOverlapped, LPTRANSMIT_FILE_BUFFERS lpTransmitBuffers, DWORD dwFlags);
struct WSAOVERLAPPEDX {
ULONG_PTR Internal;
ULONG_PTR InternalHigh;
union {
struct {
DWORD Offset;
DWORD OffsetHigh;
}
PVOID Pointer;
}
HANDLE hEvent;
}