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 }