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