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