1 /** 2 This module contains windows API definitions that are ABI compatible 3 but may be slightly enhanced to take advantage of D semantics. 4 */ 5 module more.os.windows.sock; 6 7 import more.c : cint, cuint; 8 import more.types : passfail; 9 10 import more.os.windows.core : 11 WindowsErrorCode, HANDLE, 12 GetModuleHandleA, GetProcAddress; 13 import more.net.sock : 14 AddressFamily, SocketType, Protocol, 15 ntohl, sockaddr, SocketHandle, 16 SockResult, SockLengthResult, SendResult, 17 Blocking, fd_set; 18 19 pragma (lib, "ws2_32.lib"); 20 pragma (lib, "wsock32.lib"); 21 22 immutable __gshared typeof(&getnameinfo) getnameinfoPointer; 23 immutable __gshared typeof(&getaddrinfo) getaddrinfoPointer; 24 immutable __gshared typeof(&freeaddrinfo) freeaddrinfoPointer; 25 26 shared static this() @system 27 { 28 { 29 WSADATA wsaData; 30 auto result = WSAStartup(0x2020, &wsaData); 31 import std.format : format; 32 assert(result.passed, format("WSAStartup failed (returned %s)", result)); 33 } 34 35 getnameinfoPointer = &getnameinfo; 36 getaddrinfoPointer = &getaddrinfo; 37 freeaddrinfoPointer = &freeaddrinfo; 38 /* 39 40 // These functions may not be present on older Windows versions. 41 // See the comment in InternetAddress.toHostNameString() for details. 42 auto ws2Lib = GetModuleHandleA("ws2_32.dll"); 43 //assert(ws2Lib, format("GetModuleHandleA(\"ws2_32.dll\") failed error=%s", WSAGetLastError())); 44 if (ws2Lib.isInvalid) 45 { 46 getnameinfoPointer = cast(typeof(getnameinfoPointer)) 47 GetProcAddress(ws2Lib, "getnameinfo"); 48 getaddrinfoPointer = cast(typeof(getaddrinfoPointer)) 49 GetProcAddress(ws2Lib, "getaddrinfo"); 50 freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer)) 51 GetProcAddress(ws2Lib, "freeaddrinfo"); 52 } 53 */ 54 } 55 56 shared static ~this() @system nothrow @nogc 57 { 58 version(Windows) 59 { 60 WSACleanup(); 61 } 62 } 63 64 enum : cint 65 { 66 SOCKET_ERROR = -1, 67 68 AF_UNSPEC = 0, 69 70 AF_UNIX = 1, 71 AF_INET = 2, 72 AF_IMPLINK = 3, 73 AF_PUP = 4, 74 AF_CHAOS = 5, 75 AF_NS = 6, 76 AF_IPX = AF_NS, 77 AF_ISO = 7, 78 AF_OSI = AF_ISO, 79 AF_ECMA = 8, 80 AF_DATAKIT = 9, 81 AF_CCITT = 10, 82 AF_SNA = 11, 83 AF_DECnet = 12, 84 AF_DLI = 13, 85 AF_LAT = 14, 86 AF_HYLINK = 15, 87 AF_APPLETALK = 16, 88 AF_NETBIOS = 17, 89 AF_VOICEVIEW = 18, 90 AF_FIREFOX = 19, 91 AF_UNKNOWN1 = 20, 92 AF_BAN = 21, 93 AF_ATM = 22, 94 AF_INET6 = 23, 95 AF_CLUSTER = 24, 96 AF_12844 = 25, 97 AF_IRDA = 26, 98 AF_NETDES = 28, 99 100 AF_MAX = 29, 101 102 PF_UNSPEC = AF_UNSPEC, 103 104 PF_UNIX = AF_UNIX, 105 PF_INET = AF_INET, 106 PF_IMPLINK = AF_IMPLINK, 107 PF_PUP = AF_PUP, 108 PF_CHAOS = AF_CHAOS, 109 PF_NS = AF_NS, 110 PF_IPX = AF_IPX, 111 PF_ISO = AF_ISO, 112 PF_OSI = AF_OSI, 113 PF_ECMA = AF_ECMA, 114 PF_DATAKIT = AF_DATAKIT, 115 PF_CCITT = AF_CCITT, 116 PF_SNA = AF_SNA, 117 PF_DECnet = AF_DECnet, 118 PF_DLI = AF_DLI, 119 PF_LAT = AF_LAT, 120 PF_HYLINK = AF_HYLINK, 121 PF_APPLETALK = AF_APPLETALK, 122 PF_VOICEVIEW = AF_VOICEVIEW, 123 PF_FIREFOX = AF_FIREFOX, 124 PF_UNKNOWN1 = AF_UNKNOWN1, 125 PF_BAN = AF_BAN, 126 PF_INET6 = AF_INET6, 127 128 PF_MAX = AF_MAX, 129 130 SOL_SOCKET = 0xFFFF, 131 132 SO_DEBUG = 0x0001, 133 SO_ACCEPTCONN = 0x0002, 134 SO_REUSEADDR = 0x0004, 135 SO_KEEPALIVE = 0x0008, 136 SO_DONTROUTE = 0x0010, 137 SO_BROADCAST = 0x0020, 138 SO_USELOOPBACK = 0x0040, 139 SO_LINGER = 0x0080, 140 SO_DONTLINGER = ~SO_LINGER, 141 SO_OOBINLINE = 0x0100, 142 SO_SNDBUF = 0x1001, 143 SO_RCVBUF = 0x1002, 144 SO_SNDLOWAT = 0x1003, 145 SO_RCVLOWAT = 0x1004, 146 SO_SNDTIMEO = 0x1005, 147 SO_RCVTIMEO = 0x1006, 148 SO_ERROR = 0x1007, 149 SO_TYPE = 0x1008, 150 SO_EXCLUSIVEADDRUSE = ~SO_REUSEADDR, 151 152 TCP_NODELAY = 1, 153 154 IP_OPTIONS = 1, 155 156 IP_HDRINCL = 2, 157 IP_TOS = 3, 158 IP_TTL = 4, 159 IP_MULTICAST_IF = 9, 160 IP_MULTICAST_TTL = 10, 161 IP_MULTICAST_LOOP = 11, 162 IP_ADD_MEMBERSHIP = 12, 163 IP_DROP_MEMBERSHIP = 13, 164 IP_DONTFRAGMENT = 14, 165 IP_ADD_SOURCE_MEMBERSHIP = 15, 166 IP_DROP_SOURCE_MEMBERSHIP = 16, 167 IP_BLOCK_SOURCE = 17, 168 IP_UNBLOCK_SOURCE = 18, 169 IP_PKTINFO = 19, 170 171 IPV6_UNICAST_HOPS = 4, 172 IPV6_MULTICAST_IF = 9, 173 IPV6_MULTICAST_HOPS = 10, 174 IPV6_MULTICAST_LOOP = 11, 175 IPV6_ADD_MEMBERSHIP = 12, 176 IPV6_DROP_MEMBERSHIP = 13, 177 IPV6_JOIN_GROUP = IPV6_ADD_MEMBERSHIP, 178 IPV6_LEAVE_GROUP = IPV6_DROP_MEMBERSHIP, 179 IPV6_V6ONLY = 27, 180 181 SOCK_STREAM = 1, 182 SOCK_DGRAM = 2, 183 SOCK_RAW = 3, 184 SOCK_RDM = 4, 185 SOCK_SEQPACKET = 5, 186 187 IPPROTO_IP = 0, 188 IPPROTO_ICMP = 1, 189 IPPROTO_IGMP = 2, 190 IPPROTO_GGP = 3, 191 IPPROTO_TCP = 6, 192 IPPROTO_PUP = 12, 193 IPPROTO_UDP = 17, 194 IPPROTO_IDP = 22, 195 IPPROTO_IPV6 = 41, 196 IPPROTO_ND = 77, 197 IPPROTO_RAW = 255, 198 199 IPPROTO_MAX = 256, 200 201 MSG_OOB = 0x1, 202 MSG_PEEK = 0x2, 203 MSG_DONTROUTE = 0x4, 204 205 SD_RECEIVE = 0, 206 SD_SEND = 1, 207 SD_BOTH = 2, 208 209 INADDR_ANY = 0, 210 INADDR_LOOPBACK = 0x7F000001, 211 INADDR_BROADCAST = 0xFFFFFFFF, 212 INADDR_NONE = 0xFFFFFFFF, 213 ADDR_ANY = INADDR_ANY, 214 215 AI_PASSIVE = 0x1, 216 AI_CANONNAME = 0x2, 217 AI_NUMERICHOST = 0x4, 218 AI_ADDRCONFIG = 0x0400, 219 AI_NON_AUTHORITATIVE = 0x04000, 220 AI_SECURE = 0x08000, 221 AI_RETURN_PREFERRED_NAMES = 0x010000, 222 223 FIONBIO = cast(int)(IOC_IN | ((uint.sizeof & IOCPARM_MASK) << 16) | (102 << 8) | 126), 224 } 225 struct timeval 226 { 227 cint tv_sec; 228 cint tv_usec; 229 } 230 231 struct WSADATA 232 { 233 ushort Version; 234 ushort HighVersion; 235 char[257] Description; 236 char[129] SystemStatus; 237 ushort MaxSockets; 238 ushort MaxUdpDg; 239 char* VendorInfo; 240 } 241 242 struct WSAOVERLAPPED 243 { 244 uint* Internal; 245 uint* InternalHigh; 246 union 247 { 248 struct 249 { 250 uint Offset; 251 uint OffsetHigh; 252 } 253 void* Pointer; 254 } 255 HANDLE Event; 256 } 257 258 struct WSAOVERLAPPED_COMPLETION_ROUTINE 259 { 260 int placeholder; 261 } 262 263 extern(Windows) nothrow @nogc 264 { 265 WindowsErrorCode WSAStartup(ushort VersionRequested, WSADATA* lpWSAData); 266 SockResult WSACleanup(); 267 268 SocketHandle socket(cint af, cint type, cint protocol) nothrow @nogc; 269 SockResult shutdown(SocketHandle sock, Shutdown how); 270 271 SockResult bind(SocketHandle sock, const(sockaddr)* addr, cuint addrlen); 272 SockResult connect(SocketHandle sock, const(sockaddr)* addr, cuint addrlen); 273 274 SockResult listen(SocketHandle sock, cuint backlog); 275 276 SocketHandle WSAAccept(SocketHandle sock, sockaddr* addr, uint* addrlen, void*, void*); 277 SocketHandle accept(SocketHandle sock, sockaddr* addr, int* addrlen); 278 279 SockResult getsockname(SocketHandle sock, sockaddr* addr, uint* namelen); 280 281 SockResult ioctlsocket(SocketHandle sock, uint cmd, void* arg); 282 SockResult WSAIoctl(SocketHandle sock, uint code, 283 ubyte* inBuffer, uint inBufferLength, 284 ubyte* outBuffer, uint outBufferLength, 285 uint* bytesReturned, WSAOVERLAPPED* overlapped, WSAOVERLAPPED_COMPLETION_ROUTINE* completionRoutine); 286 287 SockLengthResult recv(SocketHandle sock, ubyte* buffer, cuint len, cuint flags); 288 SockLengthResult send(SocketHandle sock, const(ubyte)* buffer, cuint len, cuint flags); 289 290 SockLengthResult recvfrom(SocketHandle sock, ubyte* buffer, 291 uint len, uint flags, sockaddr* from, uint* fromlen); 292 SockLengthResult sendto(SocketHandle sock, const(ubyte)* buffer, 293 uint len, uint flags, const(sockaddr)* to, uint tolen); 294 295 SockResult gethostname(const(char)* name, cint namelen); 296 SockResult getaddrinfo(const(char)* nodename, const(char)* servname, 297 const(addrinfo)* hints, addrinfo** res); 298 void freeaddrinfo(addrinfo* ai); 299 SockResult getnameinfo(const(sockaddr)* sa, SocketHandle salen, char* host, 300 cuint hostlen, char* serv, cuint servlen, cuint flags); 301 } 302 303 enum Shutdown 304 { 305 recv = SD_RECEIVE, 306 send = SD_SEND, 307 both = SD_BOTH, 308 } 309 struct fd_set_dynamic(Allocator) 310 { 311 static size_t fdCountToMemSize(uint fd_count) 312 { 313 return uint.sizeof + fd_count * SocketHandle.sizeof; 314 } 315 static uint memSizeToFdCount(size_t memSize) 316 { 317 if(memSize == 0) return 0; 318 return cast(uint)((memSize - uint.sizeof) / SocketHandle.sizeof); 319 } 320 321 //static assert(hasMember!(Expander, "expand"), Expander.stringof~" does not have an expand function"); 322 private fd_set* set; 323 private uint fd_capacity; 324 @property fd_set* ptr() 325 { 326 return set; 327 } 328 void reset() 329 { 330 if(set) 331 { 332 set.fd_count = 0; 333 } 334 } 335 void addNoCheck(SocketHandle sock) 336 { 337 import more.alloc : Mem; 338 339 if(set is null) 340 { 341 auto mem = Allocator.alloc(Mem(null, 0), fdCountToMemSize(1)); 342 this.set = cast(fd_set*)mem.ptr; 343 this.fd_capacity = memSizeToFdCount(mem.size); 344 assert(this.fd_capacity >= 1); 345 this.set.fd_count = 1; 346 this.set.fd_array_first = sock; 347 } 348 else 349 { 350 if(set.fd_count >= fd_capacity) 351 { 352 auto currentMemSize = fdCountToMemSize(fd_capacity); 353 auto mem = Allocator.alloc(Mem(set, currentMemSize), fdCountToMemSize(fd_capacity + 1), 0, currentMemSize); 354 this.set = cast(fd_set*)mem.ptr; 355 auto newFdCapacity = memSizeToFdCount(mem.size); 356 assert(newFdCapacity > this.fd_capacity); 357 this.fd_capacity = newFdCapacity; 358 } 359 (&set.fd_array_first)[set.fd_count++] = sock; 360 } 361 } 362 } 363 364 /* 365 * Commands for ioctlsocket(), taken from the BSD file fcntl.h. 366 * 367 * 368 * Ioctl's have the command encoded in the lower word, 369 * and the size of any in or out parameters in the upper 370 * word. The high 2 bits of the upper word are used 371 * to encode the in/out status of the parameter; for now 372 * we restrict parameters to at most 128 bytes. 373 */ 374 enum IOCPARM_MASK = 0x7f; /* parameters must be < 128 bytes */ 375 enum IOC_VOID = 0x20000000; /* no parameters */ 376 enum IOC_OUT = 0x40000000; /* copy out parameters */ 377 enum IOC_IN = 0x80000000; /* copy in parameters */ 378 enum IOC_INOUT = IOC_IN | IOC_OUT; 379 /* 0x20000000 distinguishes new & 380 old ioctl's */ 381 uint _WSAIO(uint x, uint y) { return IOC_VOID | x | y; } 382 uint _WSAIOR(uint x, uint y) { return IOC_OUT | x | y; } 383 uint _WSAIOW(uint x, uint y) { return IOC_IN | x | y; } 384 uint _WSAIORW(uint x, uint y) { return IOC_INOUT | x | y; } 385 386 enum IOC_WS2 = 0x08000000; 387 enum SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW(IOC_WS2, 6); 388 389 /+ 390 LPFN_ACCEPTEX loadAcceptEx(SocketHandle socket) 391 { 392 LPFN_ACCEPTEX functionPointer = null; 393 GUID acceptExGuid = WSAID_ACCEPTEX; 394 uint bytes; 395 if(failed(WSAIoctl(socket, SIO_GET_EXTENSION_FUNCTION_POINTER, 396 &acceptExGuid, acceptExGuid.sizeof, 397 &functionPointer, functionPointer.sizeof, &bytes, null, null))) 398 { 399 return null; 400 } 401 assert(functionPointer, "WSAIoctl SIO_GET_EXTENSION_FUNCTION_POINTER returned success but function pointer is null"); 402 return functionPointer; 403 } 404 +/ 405 406 struct addrinfo 407 { 408 cint ai_flags; 409 cint ai_family; 410 cint ai_socktype; 411 cint ai_protocol; 412 size_t ai_addrlen; 413 char* ai_canonname; 414 sockaddr* ai_addr; 415 addrinfo* ai_next; 416 }