1 module dast.async.iocp;
2 
3 version (Windows)  : import dast.async.tcpserver;
4 package import core.sys.windows.windows,
5 core.sys.windows.mswsock;
6 
7 package(dast.async) bool checkErr()(int ret, string prefix = null) nothrow {
8 	import core.sys.windows.winerror;
9 
10 	const err = WSAGetLastError();
11 	if (ret != 0 || err == 0)
12 		return false;
13 
14 	if (err == WSAEWOULDBLOCK || err == ERROR_IO_PENDING)
15 		return false;
16 	onError(text(prefix, " error: code=", err));
17 	return true;
18 }
19 
20 enum IocpOperation {
21 	accept,
22 	connect,
23 	read,
24 	write,
25 	event,
26 	close
27 }
28 
29 struct IocpContext {
30 	OVERLAPPED overlapped;
31 	IocpOperation operation;
32 }
33 
34 alias LPWSAOVERLAPPED = OVERLAPPED*,
35 GROUP = uint;
36 package alias LPWSAPROTOCOL_INFO = void*;
37 
38 immutable {
39 	LPFN_ACCEPTEX AcceptEx;
40 	extern(Windows) BOOL function(SOCKET, const sockaddr*, int, PVOID, DWORD, LPDWORD, LPOVERLAPPED) nothrow ConnectEx;
41 	/*
42 	LPFN_DISCONNECTEX DisconnectEx;
43 	LPFN_GETACCEPTEXSOCKADDRS GetAcceptexSockAddrs;
44 	LPFN_TRANSMITFILE TransmitFile;
45 	LPFN_TRANSMITPACKETS TransmitPackets;
46 	LPFN_WSARECVMSG WSARecvMsg;
47 	LPFN_WSASENDMSG WSASendMsg;*/
48 }
49 
50 shared static this() {
51 	auto sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
52 	scope (exit)
53 		closesocket(sock);
54 	sock.getFuncPointer!AcceptEx(WSAID_ACCEPTEX);
55 	sock.getFuncPointer!ConnectEx(WSAID_CONNECTEX);
56 	/* sock.getFuncPointer!DisconnectEx(WSAID_DISCONNECTEX);
57 	sock.getFuncPointer!GetAcceptexSockAddrs(WSAID_GETACCEPTEXSOCKADDRS);
58 	sock.getFuncPointer!TransmitFile(WSAID_TRANSMITFILE);
59 	sock.getFuncPointer!TransmitPackets(WSAID_TRANSMITPACKETS);
60 	sock.getFuncPointer!WSARecvMsg(WSAID_WSARECVMSG); */
61 }
62 
63 private void getFuncPointer(alias pfn)(SOCKET sock, GUID guid) {
64 	import std.exception;
65 
66 	DWORD bytesReturned = void;
67 	if (WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, guid.sizeof,
68 			cast(void*)&pfn, pfn.sizeof, &bytesReturned, null, null) == SOCKET_ERROR)
69 		throw new ErrnoException("Get function failed", WSAGetLastError());
70 }
71 
72 enum : DWORD {
73 	IOCPARAM_MASK = 0x7f,
74 	IOC_VOID = 0x20000000,
75 	IOC_OUT = 0x40000000,
76 	IOC_IN = 0x80000000,
77 	IOC_INOUT = IOC_IN | IOC_OUT
78 }
79 
80 enum {
81 	IOC_UNIX = 0x00000000,
82 	IOC_WS2 = 0x08000000,
83 	IOC_PROTOCOL = 0x10000000,
84 	IOC_VENDOR = 0x18000000
85 }
86 
87 enum _WSAIORW(int x, int y) = IOC_INOUT | x | y;
88 
89 enum SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW!(IOC_WS2, 6);
90 enum WSA_FLAG_OVERLAPPED = 1;
91 
92 extern (Windows) nothrow @nogc:
93 
94 int WSARecv(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, LPWSAOVERLAPPED,
95 	LPWSAOVERLAPPED_COMPLETION_ROUTINE);
96 int WSARecvDisconnect(SOCKET, LPWSABUF);
97 int WSARecvFrom(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, SOCKADDR*, LPINT,
98 	LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
99 
100 int WSASend(SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, LPWSAOVERLAPPED,
101 	LPWSAOVERLAPPED_COMPLETION_ROUTINE);
102 int WSASendDisconnect(SOCKET, LPWSABUF);
103 int WSASendTo(SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, const(SOCKADDR)*, int,
104 	LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
105 
106 int GetQueuedCompletionStatusEx(HANDLE, LPOVERLAPPED_ENTRY, ULONG, PULONG,
107 	DWORD, BOOL);
108 
109 SOCKET WSASocketW(int af, int type, int protocol, LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORD dwFlags);
110 
111 alias WSASocket = WSASocketW;
112 alias LPOVERLAPPED_ENTRY = OVERLAPPED_ENTRY*;
113 
114 struct OVERLAPPED_ENTRY {
115 	ULONG_PTR lpCompletionKey;
116 	LPOVERLAPPED lpOverlapped;
117 	ULONG_PTR Internal;
118 	DWORD dwNumberOfBytesTransferred;
119 }