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);