diff --git a/README.md b/README.md index a97c815..39a3268 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Feature | SelectEventDriver | EpollEventDriver | WinAPIEventDriver | Kq TCP Sockets | yes | yes | — | yes UDP Sockets | yes | yes | — | yes USDS | yes | yes | — | yes -DNS | yes | yes | — | yes +DNS | yes | yes | yes | yes Timers | yes | yes | yes | yes Events | yes | yes | yes | yes Unix Signals | yes² | yes² | — | — diff --git a/dub.sdl b/dub.sdl index d207b87..b717909 100644 --- a/dub.sdl +++ b/dub.sdl @@ -7,6 +7,7 @@ targetType "library" libs "anl" platform="linux" libs "ws2_32" "user32" platform="windows" +sourceFiles "lib/ws2_32.lib" platform="windows-x86-dmd" dependency "taggedalgebraic" version="~>0.10.4" diff --git a/lib/ws2_32.lib b/lib/ws2_32.lib new file mode 100644 index 0000000..ec2490a Binary files /dev/null and b/lib/ws2_32.lib differ diff --git a/source/eventcore/drivers/winapi.d b/source/eventcore/drivers/winapi.d index 4c35631..0b3ab80 100644 --- a/source/eventcore/drivers/winapi.d +++ b/source/eventcore/drivers/winapi.d @@ -13,6 +13,7 @@ import eventcore.driver; import eventcore.drivers.timer; import eventcore.internal.consumablequeue : ConsumableQueue; import eventcore.internal.utils; +import eventcore.internal.win32; import taggedalgebraic; import core.sys.windows.windows; import core.sys.windows.winsock2; @@ -357,7 +358,91 @@ final class WinAPIEventDriverDNS : EventDriverDNS { 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) diff --git a/source/eventcore/internal/win32.d b/source/eventcore/internal/win32.d new file mode 100644 index 0000000..549cdea --- /dev/null +++ b/source/eventcore/internal/win32.d @@ -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; +}