1 module hunt.io.channel.iocp.Common;
2 
3 
4 // dfmt off
5 version (HAVE_IOCP) : 
6 
7 pragma(lib, "Ws2_32");
8 // dfmt on
9 
10 import hunt.io.ByteBuffer;
11 import hunt.io.channel.AbstractChannel;
12 import hunt.io.channel.Common;
13 import hunt.logging;
14 import hunt.Functions;
15 
16 import core.atomic;
17 import core.sys.windows.windows;
18 import core.sys.windows.winsock2;
19 import core.sys.windows.mswsock;
20 
21 import std.conv;
22 import std.exception;
23 import std.format;
24 import std.process;
25 import std.socket;
26 import std.stdio;
27 
28 
29 /**
30  * 
31  */
32 mixin template CheckIocpError() {
33     void checkErro(int ret, int erro = 0) {
34         DWORD dwLastError = GetLastError();
35         version (HUNT_IO_DEBUG)
36             infof("ret=%d, erro=%d, dwLastError=%d", ret, erro, dwLastError);
37         if (ret != erro || dwLastError == 0)
38             return;
39 
40         if (ERROR_IO_PENDING != dwLastError) { // ERROR_IO_PENDING
41             import hunt.system.Error;
42             warningf("erro=%d, dwLastError=%d", erro, dwLastError);
43             this._error = true;
44             this._errorMessage = getErrorMessage(dwLastError); // format("IOCP error: code=%s", dwLastError);
45         }
46     }
47 }
48 
49 enum IocpOperation {
50     accept,
51     connect,
52     read,
53     write,
54     event,
55     close
56 }
57 
58 struct IocpContext {
59     OVERLAPPED overlapped;
60     IocpOperation operation;
61     AbstractChannel channel = null;
62 }
63 
64 alias WSAOVERLAPPED = OVERLAPPED;
65 alias LPWSAOVERLAPPED = OVERLAPPED*;
66 
67 __gshared static LPFN_ACCEPTEX AcceptEx;
68 __gshared static LPFN_CONNECTEX ConnectEx;
69 /*__gshared LPFN_DISCONNECTEX DisconnectEx;
70 __gshared LPFN_GETACCEPTEXSOCKADDRS GetAcceptexSockAddrs;
71 __gshared LPFN_TRANSMITFILE TransmitFile;
72 __gshared LPFN_TRANSMITPACKETS TransmitPackets;
73 __gshared LPFN_WSARECVMSG WSARecvMsg;
74 __gshared LPFN_WSASENDMSG WSASendMsg;*/
75 
76 shared static this() {
77     WSADATA wsaData;
78     int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
79     if (iResult != 0) {
80         stderr.writeln("unable to load Winsock!");
81     }
82 }
83 
84 shared static ~this() {
85     WSACleanup();
86 }
87 
88 void loadWinsockExtension(SOCKET socket) {
89     if (isApiLoaded)
90         return;
91     isApiLoaded = true;
92 
93     // SOCKET ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
94     // scope (exit)
95     //     closesocket(ListenSocket);
96     GUID guid;
97     mixin(GET_FUNC_POINTER("WSAID_ACCEPTEX", "AcceptEx", socket.stringof));
98     mixin(GET_FUNC_POINTER("WSAID_CONNECTEX", "ConnectEx"));
99     /* mixin(GET_FUNC_POINTER("WSAID_DISCONNECTEX", "DisconnectEx"));
100      mixin(GET_FUNC_POINTER("WSAID_GETACCEPTEXSOCKADDRS", "GetAcceptexSockAddrs"));
101      mixin(GET_FUNC_POINTER("WSAID_TRANSMITFILE", "TransmitFile"));
102      mixin(GET_FUNC_POINTER("WSAID_TRANSMITPACKETS", "TransmitPackets"));
103      mixin(GET_FUNC_POINTER("WSAID_WSARECVMSG", "WSARecvMsg"));*/
104 }
105 
106 private __gshared bool isApiLoaded = false;
107 
108 private bool GetFunctionPointer(FuncPointer)(SOCKET sock, ref FuncPointer pfn, ref GUID guid) {
109     DWORD dwBytesReturned = 0;
110     if (WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, guid.sizeof,
111             &pfn, pfn.sizeof, &dwBytesReturned, null, null) == SOCKET_ERROR) {
112         error("Get function failed with error:", GetLastError());
113         return false;
114     }
115 
116     return true;
117 }
118 
119 private string GET_FUNC_POINTER(string GuidValue, string pft, string socket = "socket") {
120     string str = " guid = " ~ GuidValue ~ ";";
121     str ~= "if( !GetFunctionPointer( " ~ socket ~ ", " ~ pft
122         ~ ", guid ) ) { errnoEnforce(false,\"get function error!\"); } ";
123     return str;
124 }
125 
126 enum : DWORD {
127     IOCPARAM_MASK = 0x7f,
128     IOC_VOID = 0x20000000,
129     IOC_OUT = 0x40000000,
130     IOC_IN = 0x80000000,
131     IOC_INOUT = IOC_IN | IOC_OUT
132 }
133 
134 enum IOC_UNIX = 0x00000000;
135 enum IOC_WS2 = 0x08000000;
136 enum IOC_PROTOCOL = 0x10000000;
137 enum IOC_VENDOR = 0x18000000;
138 
139 template _WSAIO(int x, int y) {
140     enum _WSAIO = IOC_VOID | x | y;
141 }
142 
143 template _WSAIOR(int x, int y) {
144     enum _WSAIOR = IOC_OUT | x | y;
145 }
146 
147 template _WSAIOW(int x, int y) {
148     enum _WSAIOW = IOC_IN | x | y;
149 }
150 
151 template _WSAIORW(int x, int y) {
152     enum _WSAIORW = IOC_INOUT | x | y;
153 }
154 
155 enum SIO_ASSOCIATE_HANDLE = _WSAIOW!(IOC_WS2, 1);
156 enum SIO_ENABLE_CIRCULAR_QUEUEING = _WSAIO!(IOC_WS2, 2);
157 enum SIO_FIND_ROUTE = _WSAIOR!(IOC_WS2, 3);
158 enum SIO_FLUSH = _WSAIO!(IOC_WS2, 4);
159 enum SIO_GET_BROADCAST_ADDRESS = _WSAIOR!(IOC_WS2, 5);
160 enum SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW!(IOC_WS2, 6);
161 enum SIO_GET_QOS = _WSAIORW!(IOC_WS2, 7);
162 enum SIO_GET_GROUP_QOS = _WSAIORW!(IOC_WS2, 8);
163 enum SIO_MULTIPOINT_LOOPBACK = _WSAIOW!(IOC_WS2, 9);
164 enum SIO_MULTICAST_SCOPE = _WSAIOW!(IOC_WS2, 10);
165 enum SIO_SET_QOS = _WSAIOW!(IOC_WS2, 11);
166 enum SIO_SET_GROUP_QOS = _WSAIOW!(IOC_WS2, 12);
167 enum SIO_TRANSLATE_HANDLE = _WSAIORW!(IOC_WS2, 13);
168 enum SIO_ROUTING_INTERFACE_QUERY = _WSAIORW!(IOC_WS2, 20);
169 enum SIO_ROUTING_INTERFACE_CHANGE = _WSAIOW!(IOC_WS2, 21);
170 enum SIO_ADDRESS_LIST_QUERY = _WSAIOR!(IOC_WS2, 22);
171 enum SIO_ADDRESS_LIST_CHANGE = _WSAIO!(IOC_WS2, 23);
172 enum SIO_QUERY_TARGET_PNP_HANDLE = _WSAIOR!(IOC_WS2, 24);
173 enum SIO_NSP_NOTIFY_CHANGE = _WSAIOW!(IOC_WS2, 25);
174 
175 extern (Windows):
176 int WSARecv(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, LPWSAOVERLAPPED,
177         LPWSAOVERLAPPED_COMPLETION_ROUTINE);
178 int WSARecvDisconnect(SOCKET, LPWSABUF);
179 int WSARecvFrom(SOCKET, LPWSABUF, DWORD, LPDWORD, LPDWORD, SOCKADDR*, LPINT,
180         LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE);
181 
182 int WSASend(SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, LPWSAOVERLAPPED,
183         LPWSAOVERLAPPED_COMPLETION_ROUTINE);
184 int WSASendDisconnect(SOCKET, LPWSABUF);
185 int WSASendTo(SOCKET, LPWSABUF, DWORD, LPDWORD, DWORD, const(SOCKADDR)*, int,
186         LPWSAOVERLAPPED, LPWSAOVERLAPPED_COMPLETION_ROUTINE);