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