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 }