1 /*
2 Copyright (c) 2016-2021 Eugene Wissner
3 
4 Boost Software License - Version 1.0 - August 17th, 2003
5 
6 Permission is hereby granted, free of charge, to any person or organization
7 obtaining a copy of the software and accompanying documentation covered by
8 this license (the "Software") to use, reproduce, display, distribute,
9 execute, and transmit the Software, and to prepare derivative works of the
10 Software, and to permit third-parties to whom the Software is furnished to
11 do so, all subject to the following:
12 
13 The copyright notices in the Software and this entire statement, including
14 the above license grant, this restriction and the following disclaimer,
15 must be included in all copies of the Software, in whole or in part, and
16 all derivative works of the Software, unless such copies or derivative
17 works are solely in the form of machine-executable object code generated by
18 a source language processor.
19 
20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26 DEALINGS IN THE SOFTWARE.
27 */
28 
29 /**
30  * Platform-independent socket API
31  *
32  * Copyright: Eugene Wissner 2016-2021.
33  * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0).
34  * Authors: Eugene Wissner
35  */
36 module dlib.network.socket;
37 
38 import dlib.memory;
39 import err = dlib.network.errno;
40 import core.time;
41 import std.algorithm.comparison;
42 import std.algorithm.searching;
43 public import std.socket: AddressException, socket_t, Linger, SocketOptionLevel,
44                           SocketType, AddressFamily, AddressInfo,
45                           SocketOption;
46 import std.traits;
47 import std.typecons;
48 
49 version (Posix)
50 {
51     import core.sys.posix.fcntl;
52     import core.sys.posix.netdb;
53     import core.sys.posix.netinet.in_;
54     import core.sys.posix.sys.socket;
55     import core.sys.posix.sys.time;
56     import core.sys.posix.unistd;
57 
58     private enum SOCKET_ERROR = -1;
59 }
60 else version (Windows)
61 {
62     //import dlib.async.iocp;
63     import core.sys.windows.winbase;
64     import core.sys.windows.windef;
65 
66     import core.sys.windows.basetyps;
67     import core.sys.windows.mswsock;
68     import core.sys.windows.winbase;
69     import core.sys.windows.windef;
70     import core.sys.windows.winsock2;
71 
72     enum : uint
73     {
74         IOC_UNIX     = 0x00000000,
75         IOC_WS2      = 0x08000000,
76         IOC_PROTOCOL = 0x10000000,
77         IOC_VOID     = 0x20000000,         /// No parameters.
78         IOC_OUT      = 0x40000000,         /// Copy parameters back.
79         IOC_IN       = 0x80000000,         /// Copy parameters into.
80         IOC_VENDOR   = 0x18000000,
81         IOC_INOUT    = (IOC_IN | IOC_OUT), /// Copy parameter into and get back.
82     }
83 
84     template _WSAIO(int x, int y)
85     {
86         enum _WSAIO = IOC_VOID | x | y;
87     }
88     template _WSAIOR(int x, int y)
89     {
90         enum _WSAIOR = IOC_OUT | x | y;
91     }
92     template _WSAIOW(int x, int y)
93     {
94         enum _WSAIOW = IOC_IN | x | y;
95     }
96     template _WSAIORW(int x, int y)
97     {
98         enum _WSAIORW = IOC_INOUT | x | y;
99     }
100 
101     alias SIO_ASSOCIATE_HANDLE               = _WSAIOW!(IOC_WS2, 1);
102     alias SIO_ENABLE_CIRCULAR_QUEUEING       = _WSAIO!(IOC_WS2, 2);
103     alias SIO_FIND_ROUTE                     = _WSAIOR!(IOC_WS2, 3);
104     alias SIO_FLUSH                          = _WSAIO!(IOC_WS2, 4);
105     alias SIO_GET_BROADCAST_ADDRESS          = _WSAIOR!(IOC_WS2, 5);
106     alias SIO_GET_EXTENSION_FUNCTION_POINTER = _WSAIORW!(IOC_WS2, 6);
107     alias SIO_GET_QOS                        = _WSAIORW!(IOC_WS2, 7);
108     alias SIO_GET_GROUP_QOS                  = _WSAIORW!(IOC_WS2, 8);
109     alias SIO_MULTIPOINT_LOOPBACK            = _WSAIOW!(IOC_WS2, 9);
110     alias SIO_MULTICAST_SCOPE                = _WSAIOW!(IOC_WS2, 10);
111     alias SIO_SET_QOS                        = _WSAIOW!(IOC_WS2, 11);
112     alias SIO_SET_GROUP_QOS                  = _WSAIOW!(IOC_WS2, 12);
113     alias SIO_TRANSLATE_HANDLE               = _WSAIORW!(IOC_WS2, 13);
114     alias SIO_ROUTING_INTERFACE_QUERY        = _WSAIORW!(IOC_WS2, 20);
115     alias SIO_ROUTING_INTERFACE_CHANGE       = _WSAIOW!(IOC_WS2, 21);
116     alias SIO_ADDRESS_LIST_QUERY             = _WSAIOR!(IOC_WS2, 22);
117     alias SIO_ADDRESS_LIST_CHANGE            = _WSAIO!(IOC_WS2, 23);
118     alias SIO_QUERY_TARGET_PNP_HANDLE        = _WSAIOR!(IOC_WS2, 24);
119     alias SIO_NSP_NOTIFY_CHANGE              = _WSAIOW!(IOC_WS2, 25);
120 
121     private alias GROUP = uint;
122 
123     enum
124     {
125         WSA_FLAG_OVERLAPPED = 0x01,
126         MAX_PROTOCOL_CHAIN = 7,
127         WSAPROTOCOL_LEN = 255,
128     }
129 
130     struct WSAPROTOCOLCHAIN
131     {
132         int                       ChainLen;
133         DWORD[MAX_PROTOCOL_CHAIN] ChainEntries;
134     }
135     alias LPWSAPROTOCOLCHAIN = WSAPROTOCOLCHAIN*;
136 
137     struct WSAPROTOCOL_INFO
138     {
139         DWORD                      dwServiceFlags1;
140         DWORD                      dwServiceFlags2;
141         DWORD                      dwServiceFlags3;
142         DWORD                      dwServiceFlags4;
143         DWORD                      dwProviderFlags;
144         GUID                       ProviderId;
145         DWORD                      dwCatalogEntryId;
146         WSAPROTOCOLCHAIN           ProtocolChain;
147         int                        iVersion;
148         int                        iAddressFamily;
149         int                        iMaxSockAddr;
150         int                        iMinSockAddr;
151         int                        iSocketType;
152         int                        iProtocol;
153         int                        iProtocolMaxOffset;
154         int                        iNetworkByteOrder;
155         int                        iSecurityScheme;
156         DWORD                      dwMessageSize;
157         DWORD                      dwProviderReserved;
158         TCHAR[WSAPROTOCOL_LEN + 1] szProtocol;
159     }
160     alias LPWSAPROTOCOL_INFO = WSAPROTOCOL_INFO*;
161 
162     extern (Windows) @nogc nothrow
163     {
164         private SOCKET WSASocketW(int af,
165                                   int type,
166                                   int protocol,
167                                   LPWSAPROTOCOL_INFO lpProtocolInfo,
168                                   GROUP g,
169                                   DWORD dwFlags);
170         int WSARecv(SOCKET s,
171                     LPWSABUF lpBuffers,
172                     DWORD dwBufferCount,
173                     LPDWORD lpNumberOfBytesRecvd,
174                     LPDWORD lpFlags,
175                     LPOVERLAPPED lpOverlapped,
176                     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
177         int WSASend(SOCKET s,
178                     LPWSABUF lpBuffers,
179                     DWORD dwBufferCount,
180                     LPDWORD lpNumberOfBytesRecvd,
181                     DWORD lpFlags,
182                     LPOVERLAPPED lpOverlapped,
183                     LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine);
184     }
185     alias WSASocket = WSASocketW;
186 
187     alias LPFN_GETACCEPTEXSOCKADDRS = VOID function(PVOID,
188                                                     DWORD,
189                                                     DWORD,
190                                                     DWORD,
191                                                     SOCKADDR**,
192                                                     LPINT,
193                                                     SOCKADDR**,
194                                                     LPINT);
195     const GUID WSAID_GETACCEPTEXSOCKADDRS = {0xb5367df2,0xcbac,0x11cf,[0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
196 
197     struct WSABUF
198     {
199         ULONG len;
200         CHAR* buf;
201     }
202     alias WSABUF* LPWSABUF;
203 
204     struct WSAOVERLAPPED
205     {
206         ULONG_PTR Internal;
207         ULONG_PTR InternalHigh;
208         union
209         {
210             struct
211             {
212                 DWORD Offset;
213                 DWORD OffsetHigh;
214             }
215             PVOID  Pointer;
216         }
217         HANDLE hEvent;
218     }
219     alias LPWSAOVERLAPPED = WSAOVERLAPPED*;
220 
221     enum SO_UPDATE_ACCEPT_CONTEXT = 0x700B;
222 
223     enum OverlappedSocketEvent
224     {
225         accept = 1,
226         read = 2,
227         write = 3,
228     }
229 
230     class State
231     {
232         /// For internal use by Windows API.
233         align(1) OVERLAPPED overlapped;
234 
235         /// File/socket handle.
236         HANDLE handle;
237 
238         /// For keeping events or event masks.
239         int event;
240     }
241 
242     class SocketState : State
243     {
244         private WSABUF buffer;
245     }
246 
247     /**
248      * Socket returned if a connection has been established.
249      */
250     class OverlappedConnectedSocket : ConnectedSocket
251     {
252         /**
253          * Create a socket.
254          *
255          * Params:
256          *     handle   = Socket handle.
257          *     af       = Address family.
258          */
259         this(socket_t handle, AddressFamily af)
260         {
261             super(handle, af);
262         }
263 
264         /**
265          * Begins to asynchronously receive data from a connected socket.
266          *
267          * Params:
268          *     buffer     = Storage location for the received data.
269          *     flags      = Flags.
270          *     overlapped = Unique operation identifier.
271          *
272          * Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
273          *          $(D_KEYWORD false) otherwise.
274          *
275          * Throws: $(D_PSYMBOL SocketException) if unable to receive.
276          */
277         bool beginReceive(ubyte[] buffer,
278                           SocketState overlapped,
279                           Flags flags = Flags(Flag.none)) @trusted
280         {
281             auto receiveFlags = cast(DWORD) flags;
282 
283             overlapped.handle = cast(HANDLE) handle_;
284             overlapped.event = OverlappedSocketEvent.read;
285             overlapped.buffer.len = cast(uint) buffer.length;
286             overlapped.buffer.buf = cast(char*) buffer.ptr;
287 
288             auto result = WSARecv(handle_,
289                                   &overlapped.buffer,
290                                   1u,
291                                   NULL,
292                                   &receiveFlags,
293                                   &overlapped.overlapped,
294                                   NULL);
295 
296             if (result == SOCKET_ERROR && !wouldHaveBlocked)
297             {
298                 throw defaultAllocator.make!SocketException("Unable to receive");
299             }
300             return result == 0;
301         }
302 
303         /**
304          * Ends a pending asynchronous read.
305          *
306          * Params
307          *     overlapped = Unique operation identifier.
308          *
309          * Returns: Number of bytes received.
310          *
311          * Throws: $(D_PSYMBOL SocketException) if unable to receive.
312          */
313         int endReceive(SocketState overlapped) @trusted
314         out (count)
315         {
316             assert(count >= 0);
317         }
318         do
319         {
320             DWORD lpNumber;
321             BOOL result = GetOverlappedResult(overlapped.handle,
322                                               &overlapped.overlapped,
323                                               &lpNumber,
324                                               FALSE);
325             if (result == FALSE && !wouldHaveBlocked)
326             {
327                 disconnected_ = true;
328                 throw defaultAllocator.make!SocketException("Unable to receive");
329             }
330             if (lpNumber == 0)
331             {
332                 disconnected_ = true;
333             }
334             return lpNumber;
335         }
336 
337         /**
338          * Sends data asynchronously to a connected socket.
339          *
340          * Params:
341          *     buffer     = Data to be sent.
342          *     flags      = Flags.
343          *     overlapped = Unique operation identifier.
344          *
345          * Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
346          *          $(D_KEYWORD false) otherwise.
347          *
348          * Throws: $(D_PSYMBOL SocketException) if unable to send.
349          */
350         bool beginSend(ubyte[] buffer,
351                        SocketState overlapped,
352                        Flags flags = Flags(Flag.none)) @trusted
353         {
354             overlapped.handle = cast(HANDLE) handle_;
355             overlapped.event = OverlappedSocketEvent.write;
356             overlapped.buffer.len = cast(uint) buffer.length;
357             overlapped.buffer.buf = cast(char*) buffer.ptr;
358 
359             auto result = WSASend(handle_,
360                                   &overlapped.buffer,
361                                   1u,
362                                   NULL,
363                                   cast(DWORD) flags,
364                                   &overlapped.overlapped,
365                                   NULL);
366 
367             if (result == SOCKET_ERROR && !wouldHaveBlocked)
368             {
369                 disconnected_ = true;
370                 throw defaultAllocator.make!SocketException("Unable to send");
371             }
372             return result == 0;
373         }
374 
375         /**
376          * Ends a pending asynchronous send.
377          *
378          * Params
379          *     overlapped = Unique operation identifier.
380          *
381          * Returns: Number of bytes sent.
382          *
383          * Throws: $(D_PSYMBOL SocketException) if unable to receive.
384         */
385         int endSend(SocketState overlapped) @trusted
386         out (count)
387         {
388             assert(count >= 0);
389         }
390         do
391         {
392             DWORD lpNumber;
393             BOOL result = GetOverlappedResult(overlapped.handle,
394                                               &overlapped.overlapped,
395                                               &lpNumber,
396                                               FALSE);
397             if (result == FALSE && !wouldHaveBlocked)
398             {
399                 disconnected_ = true;
400                 throw defaultAllocator.make!SocketException("Unable to receive");
401             }
402             return lpNumber;
403         }
404     }
405 
406     class OverlappedStreamSocket : StreamSocket
407     {
408         /// Accept extension function pointer.
409         package LPFN_ACCEPTEX acceptExtension;
410 
411         /**
412          * Create a socket.
413          *
414          * Params:
415          *     af       = Address family.
416          *
417          * Throws: $(D_PSYMBOL SocketException) on errors.
418          */
419         this(AddressFamily af) @trusted
420         {
421             super(af);
422             scope (failure)
423             {
424                 this.close();
425             }
426             blocking = false;
427 
428             GUID guidAcceptEx = WSAID_ACCEPTEX;
429             DWORD dwBytes;
430 
431             auto result = WSAIoctl(handle_,
432                                    SIO_GET_EXTENSION_FUNCTION_POINTER,
433                                    &guidAcceptEx,
434                                    guidAcceptEx.sizeof,
435                                    &acceptExtension,
436                                    acceptExtension.sizeof,
437                                    &dwBytes,
438                                    NULL,
439                                    NULL);
440             if (!result == SOCKET_ERROR)
441             {
442                 throw defaultAllocator.make!SocketException("Unable to retrieve an accept extension function pointer");
443             }
444         }
445 
446         /**
447          * Begins an asynchronous operation to accept an incoming connection attempt.
448          *
449          * Params:
450          *     overlapped = Unique operation identifier.
451          *
452          * Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
453          *          $(D_KEYWORD false) otherwise.
454          *
455          * Throws: $(D_PSYMBOL SocketException) on accept errors.
456          */
457         bool beginAccept(SocketState overlapped) @trusted
458         {
459             auto socket = cast(socket_t) socket(addressFamily, SOCK_STREAM, 0);
460             if (socket == socket_t.init)
461             {
462                 throw defaultAllocator.make!SocketException("Unable to create socket");
463             }
464             scope (failure)
465             {
466                 closesocket(socket);
467             }
468             DWORD dwBytes;
469             overlapped.handle = cast(HANDLE) socket;
470             overlapped.event = OverlappedSocketEvent.accept;
471             overlapped.buffer.len = (sockaddr_in.sizeof + 16) * 2;
472             overlapped.buffer.buf = defaultAllocator.makeArray!char(overlapped.buffer.len).ptr;
473 
474             // We don't want to get any data now, but only start to accept the connections
475             BOOL result = acceptExtension(handle_,
476                                           socket,
477                                           overlapped.buffer.buf,
478                                           0u,
479                                           sockaddr_in.sizeof + 16,
480                                           sockaddr_in.sizeof + 16,
481                                           &dwBytes,
482                                           &overlapped.overlapped);
483             if (result == FALSE && !wouldHaveBlocked)
484             {
485                 throw defaultAllocator.make!SocketException("Unable to accept socket connection");
486             }
487             return result == TRUE;
488         }
489 
490         /**
491          * Asynchronously accepts an incoming connection attempt and creates a
492          * new socket to handle remote host communication.
493          *
494          * Params:
495          *     overlapped = Unique operation identifier.
496          *
497          * Returns: Connected socket.
498          *
499          * Throws: $(D_PSYMBOL SocketException) if unable to accept.
500          */
501         OverlappedConnectedSocket endAccept(SocketState overlapped) @trusted
502         {
503             scope (exit)
504             {
505                 defaultAllocator.dispose(overlapped.buffer.buf[0..overlapped.buffer.len]);
506             }
507             auto socket = defaultAllocator.make!OverlappedConnectedSocket(cast(socket_t) overlapped.handle,
508                                                                           addressFamily);
509             scope (failure)
510             {
511                 defaultAllocator.dispose(socket);
512             }
513             socket.setOption(SocketOptionLevel.SOCKET,
514                              cast(SocketOption) SO_UPDATE_ACCEPT_CONTEXT,
515                              cast(size_t) handle);
516             return socket;
517         }
518     }
519 }
520 
521 version (linux)
522 {
523     enum SOCK_NONBLOCK = O_NONBLOCK;
524     extern(C) int accept4(int, sockaddr*, socklen_t*, int flags) @nogc nothrow;
525 }
526 
527 private immutable
528 {
529     typeof(&getaddrinfo) getaddrinfoPointer;
530     typeof(&freeaddrinfo) freeaddrinfoPointer;
531 }
532 
533 shared static this()
534 {
535     version (Windows)
536     {
537         auto ws2Lib = GetModuleHandle("ws2_32.dll");
538 
539         getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
540                              GetProcAddress(ws2Lib, "getaddrinfo");
541         freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
542                               GetProcAddress(ws2Lib, "freeaddrinfo");
543     }
544     else version (Posix)
545     {
546         getaddrinfoPointer = &getaddrinfo;
547         freeaddrinfoPointer = &freeaddrinfo;
548     }
549 }
550 
551 /**
552  * Error codes for $(D_PSYMBOL Socket).
553  */
554 enum SocketError : int
555 {
556     /// Unknown error
557     unknown                = 0,
558     /// Firewall rules forbid connection.
559     accessDenied           = err.EPERM,
560     /// A socket operation was attempted on a non-socket.
561     notSocket              = err.EBADF,
562     /// The network is not available.
563     networkDown            = err.ECONNABORTED,
564     /// An invalid pointer address was detected by the underlying socket provider.
565     fault                  = err.EFAULT,
566     /// An invalid argument was supplied to a $(D_PSYMBOL Socket) member.
567     invalidArgument        = err.EINVAL,
568     /// The limit on the number of open sockets has been reached.
569     tooManyOpenSockets     = err.ENFILE,
570     /// No free buffer space is available for a Socket operation.
571     noBufferSpaceAvailable = err.ENOBUFS,
572     /// The address family is not supported by the protocol family.
573     operationNotSupported  = err.EOPNOTSUPP,
574     /// The protocol is not implemented or has not been configured.
575     protocolNotSupported   = err.EPROTONOSUPPORT,
576     /// Protocol error.
577     protocolError          = err.EPROTOTYPE,
578     /// The connection attempt timed out, or the connected host has failed to respond.
579     timedOut               = err.ETIMEDOUT,
580     /// The support for the specified socket type does not exist in this address family.
581     socketNotSupported     = err.ESOCKTNOSUPPORT,
582 }
583 
584 /**
585  * $(D_PSYMBOL SocketException) should be thrown only if one of the socket functions
586  * returns -1 or $(D_PSYMBOL SOCKET_ERROR) and sets $(D_PSYMBOL errno),
587  * because $(D_PSYMBOL SocketException) relies on the $(D_PSYMBOL errno) value.
588  */
589 class SocketException : Exception
590 {
591     immutable SocketError error = SocketError.unknown;
592 
593     /**
594      * Params:
595      *     msg  = The message for the exception.
596      *     file = The file where the exception occurred.
597      *     line = The line number where the exception occurred.
598      *     next = The previous exception in the chain of exceptions, if any.
599      */
600     this(string msg,
601          string file = __FILE__,
602          size_t line = __LINE__,
603          Throwable next = null) @nogc @safe nothrow
604     {
605         super(msg, file, line, next);
606 
607         foreach (member; EnumMembers!SocketError)
608         {
609             if (member == lastError)
610             {
611                 error = member;
612                 return;
613             }
614         }
615         if (lastError == err.ENOMEM)
616         {
617             error = SocketError.noBufferSpaceAvailable;
618         }
619         else if (lastError == err.EMFILE)
620         {
621             error = SocketError.tooManyOpenSockets;
622         }
623         else version (linux)
624         {
625             if (lastError == err.ENOSR)
626             {
627                 error = SocketError.networkDown;
628             }
629         }
630         else version (Posix)
631         {
632             if (lastError == err.EPROTO)
633             {
634                 error = SocketError.networkDown;
635             }
636         }
637     }
638 }
639 
640 /**
641  * Class for creating a network communication endpoint using the Berkeley
642  * sockets interfaces of different types.
643  */
644 abstract class Socket
645 {
646     version (Posix)
647     {
648         /**
649          * How a socket is shutdown.
650          */
651         enum Shutdown : int
652         {
653             receive = SHUT_RD,   /// Socket receives are disallowed
654             send    = SHUT_WR,   /// Socket sends are disallowed
655             both    = SHUT_RDWR, /// Both receive and send
656         }
657     }
658     else version (Windows)
659     {
660         /// Property to get or set whether the socket is blocking or nonblocking.
661         private bool blocking_ = true;
662 
663         /**
664          * How a socket is shutdown.
665          */
666         enum Shutdown : int
667         {
668             receive = SD_RECEIVE, /// Socket receives are disallowed.
669             send    = SD_SEND,    /// Socket sends are disallowed.
670             both    = SD_BOTH,    /// Both receive and send.
671         }
672 
673         // The WinSock timeouts seem to be effectively skewed by a constant
674         // offset of about half a second (in milliseconds).
675         private enum WINSOCK_TIMEOUT_SKEW = 500;
676     }
677 
678     /// Socket handle.
679     protected socket_t handle_;
680 
681     /// Address family.
682     protected AddressFamily family;
683 
684     private @property void handle(socket_t handle)
685     in
686     {
687         assert(handle != socket_t.init);
688         assert(handle_ == socket_t.init, "Socket handle cannot be changed");
689     }
690     do
691     {
692         handle_ = handle;
693 
694         // Set the option to disable SIGPIPE on send() if the platform
695         // has it (e.g. on OS X).
696         static if (is(typeof(SO_NOSIGPIPE)))
697         {
698             setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_NOSIGPIPE, true);
699         }
700     }
701 
702     @property inout(socket_t) handle() inout const pure nothrow @safe @nogc
703     {
704         return handle_;
705     }
706 
707     /**
708      * Create a socket.
709      *
710      * Params:
711      *     handle   = Socket.
712      *     af       = Address family.
713      */
714     this(socket_t handle, AddressFamily af)
715     in
716     {
717         assert(handle != socket_t.init);
718     }
719     do
720     {
721         scope (failure)
722         {
723             this.close();
724         }
725         this.handle = handle;
726         family = af;
727     }
728 
729     /**
730      * Closes the socket and calls the destructor on itself.
731      */
732     ~this() nothrow @trusted @nogc
733     {
734         this.close();
735     }
736 
737     /**
738      * Get a socket option.
739      *
740      * Params:
741      *     level  = Protocol level at that the option exists.
742      *     option = Option.
743      *     result = Buffer to save the result.
744      *
745      * Returns: The number of bytes written to $(D_PARAM result).
746      *
747      * Throws: $(D_PSYMBOL SocketException) on error.
748      */
749     protected int getOption(SocketOptionLevel level, SocketOption option, void[] result) const @trusted
750     {
751         auto length = cast(socklen_t) result.length;
752         if (getsockopt(handle_,
753                        cast(int) level,
754                        cast(int) option,
755                        result.ptr,
756                        &length) == SOCKET_ERROR)
757         {
758             throw defaultAllocator.make!SocketException("Unable to get socket option");
759         }
760         return length;
761     }
762 
763     /// Ditto.
764     int getOption(SocketOptionLevel level, SocketOption option, out size_t result) const @trusted
765     {
766         return getOption(level, option, (&result)[0..1]);
767     }
768 
769     /// Ditto.
770     int getOption(SocketOptionLevel level, SocketOption option, out Linger result) const @trusted
771     {
772         return getOption(level, option, (&result.clinger)[0..1]);
773     }
774 
775     /// Ditto.
776     int getOption(SocketOptionLevel level, SocketOption option, out Duration result) const @trusted
777     {
778         // WinSock returns the timeout values as a milliseconds DWORD,
779         // while Linux and BSD return a timeval struct.
780         version (Posix)
781         {
782             timeval tv;
783             auto ret = getOption(level, option, (&tv)[0..1]);
784             result = dur!"seconds"(tv.tv_sec) + dur!"usecs"(tv.tv_usec);
785         }
786         else version (Windows)
787         {
788             int msecs;
789             auto ret = getOption(level, option, (&msecs)[0 .. 1]);
790             if (option == SocketOption.RCVTIMEO)
791             {
792                 msecs += WINSOCK_TIMEOUT_SKEW;
793             }
794             result = dur!"msecs"(msecs);
795         }
796         return ret;
797     }
798 
799     /**
800      * Set a socket option.
801      *
802      * Params:
803      *     level  = Protocol level at that the option exists.
804      *     option = Option.
805      *     value = Option value.
806      *
807      * Throws: $(D_PSYMBOL SocketException) on error.
808      */
809     protected void setOption(SocketOptionLevel level, SocketOption option, void[] value)
810     const @trusted
811     {
812         if (setsockopt(handle_,
813                        cast(int)level,
814                        cast(int)option,
815                        value.ptr,
816                        cast(uint) value.length) == SOCKET_ERROR)
817         {
818             throw defaultAllocator.make!SocketException("Unable to set socket option");
819         }
820     }
821 
822     /// Ditto.
823     void setOption(SocketOptionLevel level, SocketOption option, size_t value) const @trusted
824     {
825         setOption(level, option, (&value)[0..1]);
826     }
827 
828     /// Ditto.
829     void setOption(SocketOptionLevel level, SocketOption option, Linger value) const @trusted
830     {
831         setOption(level, option, (&value.clinger)[0..1]);
832     }
833 
834     /// Ditto.
835     void setOption(SocketOptionLevel level, SocketOption option, Duration value) const @trusted
836     {
837         version (Posix)
838         {
839             timeval tv;
840             value.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec);
841             setOption(level, option, (&tv)[0..1]);
842         }
843         else version (Windows)
844         {
845             auto msecs = cast(int) value.total!"msecs";
846             if (msecs > 0 && option == SocketOption.RCVTIMEO)
847             {
848                 msecs = max(1, msecs - WINSOCK_TIMEOUT_SKEW);
849             }
850             setOption(level, option, msecs);
851         }
852     }
853 
854     /**
855      * Returns: Socket's blocking flag.
856      */
857     @property inout(bool) blocking() inout const nothrow @nogc
858     {
859         version (Posix)
860         {
861             return !(fcntl(handle_, F_GETFL, 0) & O_NONBLOCK);
862         }
863         else version (Windows)
864         {
865             return blocking_;
866         }
867     }
868 
869     /**
870      * Params:
871      *     yes = Socket's blocking flag.
872      */
873     @property void blocking(bool yes)
874     {
875         version (Posix)
876         {
877             int fl = fcntl(handle_, F_GETFL, 0);
878 
879             if (fl != SOCKET_ERROR)
880             {
881                 fl = yes ? fl & ~O_NONBLOCK : fl | O_NONBLOCK;
882                 fl = fcntl(handle_, F_SETFL, fl);
883             }
884             if (fl == SOCKET_ERROR)
885             {
886                 throw defaultAllocator.make!SocketException("Unable to set socket blocking");
887             }
888         }
889         else version (Windows)
890         {
891             uint num = !yes;
892             if (ioctlsocket(handle_, FIONBIO, &num) == SOCKET_ERROR)
893             {
894                 throw defaultAllocator.make!SocketException("Unable to set socket blocking");
895             }
896             blocking_ = yes;
897         }
898     }
899 
900     /**
901      * Returns: The socket's address family.
902      */
903     @property AddressFamily addressFamily() const @nogc @safe pure nothrow
904     {
905         return family;
906     }
907 
908     /**
909      * Returns: $(D_KEYWORD true) if this is a valid, alive socket.
910      */
911     @property bool isAlive() @trusted const nothrow @nogc
912     {
913         int type;
914         socklen_t typesize = cast(socklen_t) type.sizeof;
915         return !getsockopt(handle_, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
916     }
917 
918     /**
919      * Disables sends and/or receives.
920      *
921      * Params:
922      *     how = What to disable.
923      *
924      * See_Also:
925      *     $(D_PSYMBOL Shutdown)
926      */
927     void shutdown(Shutdown how = Shutdown.both) @nogc @trusted const nothrow
928     {
929         .shutdown(handle_, cast(int)how);
930     }
931 
932     /**
933      * Immediately drop any connections and release socket resources.
934      * Calling $(D_PSYMBOL shutdown) before $(D_PSYMBOL close) is recommended
935      * for connection-oriented sockets. The $(D_PSYMBOL Socket) object is no
936      * longer usable after $(D_PSYMBOL close).
937      */
938     void close() nothrow @trusted @nogc
939     {
940         version(Windows)
941         {
942             .closesocket(handle_);
943         }
944         else version(Posix)
945         {
946             .close(handle_);
947         }
948         handle_ = socket_t.init;
949     }
950 
951     /**
952      * Listen for an incoming connection. $(D_PSYMBOL bind) must be called before you
953      * can $(D_PSYMBOL listen).
954      *
955      * Params:
956      *     backlog = Request of how many pending incoming connections are
957      *               queued until $(D_PSYMBOL accept)ed.
958      */
959     void listen(int backlog) const @trusted
960     {
961         if (.listen(handle_, backlog) == SOCKET_ERROR)
962         {
963             throw defaultAllocator.make!SocketException("Unable to listen on socket");
964         }
965     }
966 
967     /**
968      * Compare handles.
969      *
970      * Params:
971      *     that = Another handle.
972      *
973      * Returns: Comparision result.
974      */
975     int opCmp(size_t that) const pure nothrow @safe @nogc
976     {
977         return handle_ < that ? -1 : handle_ > that ? 1 : 0;
978     }
979 }
980 
981 /**
982  * Interface with common fileds for stream and connected sockets.
983  */
984 interface ConnectionOrientedSocket
985 {
986     /**
987      * Flags may be OR'ed together.
988      */
989     enum Flag : int
990     {
991         none      = 0,             /// No flags specified
992         outOfBand = MSG_OOB,       /// Out-of-band stream data
993         peek      = MSG_PEEK,      /// Peek at incoming data without removing it from the queue, only for receiving
994         dontRoute = MSG_DONTROUTE, /// Data should not be subject to routing; this flag may be ignored. Only for sending
995     }
996 
997     alias Flags = BitFlags!Flag;
998 }
999 
1000 class StreamSocket : Socket, ConnectionOrientedSocket
1001 {
1002     /**
1003     * Create a socket.
1004     *
1005     * Params:
1006     *     af       = Address family.
1007     */
1008     this(AddressFamily af) @trusted
1009     {
1010         auto handle = cast(socket_t) socket(af, SOCK_STREAM, 0);
1011         if (handle == socket_t.init)
1012         {
1013             throw defaultAllocator.make!SocketException("Unable to create socket");
1014         }
1015         super(handle, af);
1016     }
1017 
1018     /**
1019      * Associate a local address with this socket.
1020      *
1021      * Params:
1022      *     address = Local address.
1023      *
1024      * Throws: $(D_PSYMBOL SocketException) if unable to bind.
1025      */
1026     void bind(Address address) @trusted const
1027     {
1028         if (.bind(handle_, address.name, address.length) == SOCKET_ERROR)
1029         {
1030             throw defaultAllocator.make!SocketException("Unable to bind socket");
1031         }
1032     }
1033 
1034     /**
1035      * Accept an incoming connection.
1036      *
1037      * The blocking mode is always inherited.
1038      *
1039      * Returns: $(D_PSYMBOL Socket) for the accepted connection or
1040      *          $(D_KEYWORD null) if the call would block on a
1041      *          non-blocking socket.
1042      *
1043      * Throws: $(D_PSYMBOL SocketException) if unable to accept.
1044      */
1045     ConnectedSocket accept() @trusted
1046     {
1047         socket_t sock;
1048 
1049         version (linux)
1050         {
1051             int flags;
1052             if (!blocking)
1053             {
1054                 flags |= SOCK_NONBLOCK;
1055             }
1056             sock = cast(socket_t).accept4(handle_, null, null, flags);
1057         }
1058         else
1059         {
1060             sock = cast(socket_t).accept(handle_, null, null);
1061         }
1062 
1063         if (sock == socket_t.init)
1064         {
1065             if (wouldHaveBlocked())
1066             {
1067                 return null;
1068             }
1069             throw defaultAllocator.make!SocketException("Unable to accept socket connection");
1070         }
1071 
1072         auto newSocket = defaultAllocator.make!ConnectedSocket(sock, addressFamily);
1073 
1074         version (linux)
1075         { // Blocking mode already set
1076         }
1077         else version (Posix)
1078         {
1079             if (!blocking)
1080             {
1081                 try
1082                 {
1083                     newSocket.blocking = blocking;
1084                 }
1085                 catch (SocketException e)
1086                 {
1087                     defaultAllocator.dispose(newSocket);
1088                     throw e;
1089                 }
1090             }
1091         }
1092         else version (Windows)
1093         { // Inherits blocking mode
1094             newSocket.blocking_ = blocking;
1095         }
1096         return newSocket;
1097     }
1098 }
1099 
1100 /**
1101  * Socket returned if a connection has been established.
1102  */
1103 class ConnectedSocket : Socket, ConnectionOrientedSocket
1104 {
1105     /**
1106      * $(D_KEYWORD true) if the stream socket peer has performed an orderly
1107      * shutdown.
1108      */
1109     protected bool disconnected_;
1110 
1111     /**
1112      * Returns: $(D_KEYWORD true) if the stream socket peer has performed an orderly
1113      *          shutdown.
1114      */
1115     @property inout(bool) disconnected() inout const pure nothrow @safe @nogc
1116     {
1117         return disconnected_;
1118     }
1119 
1120     /**
1121      * Create a socket.
1122      *
1123      * Params:
1124      *     handle   = Socket.
1125      *     af       = Address family.
1126      */
1127     this(socket_t handle, AddressFamily af)
1128     {
1129         super(handle, af);
1130     }
1131 
1132     version (Windows)
1133     {
1134         private static int capToMaxBuffer(size_t size) pure nothrow @safe @nogc
1135         {
1136             // Windows uses int instead of size_t for length arguments.
1137             // Luckily, the send/recv functions make no guarantee that
1138             // all the data is sent, so we use that to send at most
1139             // int.max bytes.
1140             return size > size_t (int.max) ? int.max : cast(int) size;
1141         }
1142     }
1143     else
1144     {
1145         private static size_t capToMaxBuffer(size_t size) pure nothrow @safe @nogc
1146         {
1147             return size;
1148         }
1149     }
1150 
1151     /**
1152      * Receive data on the connection.
1153      *
1154      * Params:
1155      *     buf =   Buffer to save received data.
1156      *     flags = Flags.
1157      *
1158      * Returns: The number of bytes received or 0 if nothing received
1159      *          because the call would block.
1160      *
1161      * Throws: $(D_PSYMBOL SocketException) if unable to receive.
1162      */
1163     ptrdiff_t receive(ubyte[] buf, Flags flags = Flag.none) @trusted
1164     {
1165         ptrdiff_t ret;
1166         if (!buf.length)
1167         {
1168             return 0;
1169         }
1170 
1171         ret = recv(handle_, buf.ptr, capToMaxBuffer(buf.length), cast(int) flags);
1172         if (ret == 0)
1173         {
1174             disconnected_ = true;
1175         }
1176         else if (ret == SOCKET_ERROR)
1177         {
1178             if (wouldHaveBlocked())
1179             {
1180                 return 0;
1181             }
1182             disconnected_ = true;
1183             throw defaultAllocator.make!SocketException("Unable to receive");
1184         }
1185         return ret;
1186     }
1187 
1188     /**
1189      * Send data on the connection. If the socket is blocking and there is no
1190      * buffer space left, $(D_PSYMBOL send) waits, non-blocking socket returns
1191      * 0 in this case.
1192      *
1193      * Params:
1194      *     buf   = Data to be sent.
1195      *     flags = Flags.
1196      *
1197      * Returns: The number of bytes actually sent.
1198      *
1199      * Throws: $(D_PSYMBOL SocketException) if unable to send.
1200      */
1201     ptrdiff_t send(const(ubyte)[] buf, Flags flags = Flag.none) const @trusted
1202     {
1203         int sendFlags = cast(int) flags;
1204         ptrdiff_t sent;
1205 
1206         static if (is(typeof(MSG_NOSIGNAL)))
1207         {
1208             sendFlags |= MSG_NOSIGNAL;
1209         }
1210 
1211         sent = .send(handle_, buf.ptr, capToMaxBuffer(buf.length), sendFlags);
1212         if (sent != SOCKET_ERROR)
1213         {
1214             return sent;
1215         }
1216         else if (wouldHaveBlocked())
1217         {
1218             return 0;
1219         }
1220         throw defaultAllocator.make!SocketException("Unable to send");
1221     }
1222 }
1223 
1224 /**
1225  * Socket address representation.
1226  */
1227 abstract class Address
1228 {
1229     /**
1230      * Returns: Pointer to underlying $(D_PSYMBOL sockaddr) structure.
1231      */
1232     abstract @property inout(sockaddr)* name() inout pure nothrow @nogc;
1233 
1234     /**
1235      * Returns: Actual size of underlying $(D_PSYMBOL sockaddr) structure.
1236      */
1237     abstract @property inout(socklen_t) length() inout const pure nothrow @nogc;
1238 }
1239 
1240 class InternetAddress : Address
1241 {
1242     version (Windows)
1243     {
1244         /// Internal internet address representation.
1245         protected SOCKADDR_STORAGE storage;
1246     }
1247     else version (Posix)
1248     {
1249         /// Internal internet address representation.
1250         protected sockaddr_storage storage;
1251     }
1252     immutable ushort port_;
1253 
1254     enum
1255     {
1256         anyPort = 0,
1257     }
1258 
1259     this(in string host, ushort port = anyPort)
1260     {
1261         if (getaddrinfoPointer is null || freeaddrinfoPointer is null)
1262         {
1263             throw defaultAllocator.make!AddressException("Address info lookup is not available on this system");
1264         }
1265         addrinfo* ai_res;
1266         port_ = port;
1267 
1268         // Make C-string from host.
1269         char[] node = defaultAllocator.makeArray!char(host.length + 1);
1270         node[0.. $ - 1] = host;
1271         node[$ - 1] = '\0';
1272         scope (exit)
1273         {
1274             defaultAllocator.dispose(node);
1275         }
1276 
1277         // Convert port to a C-string.
1278         char[6] service = [0, 0, 0, 0, 0, 0];
1279         const(char)* servicePointer;
1280         if (port)
1281         {
1282             ushort start;
1283             for (ushort j = 10, i = 4; i > 0; j *= 10, --i)
1284             {
1285                 ushort rest = port % 10;
1286                 if (rest != 0)
1287                 {
1288                     service[i] = cast(char) (rest + '0');
1289                     start = i;
1290                 }
1291                 port /= 10;
1292             }
1293             servicePointer = service[start..$].ptr;
1294         }
1295 
1296         auto ret = getaddrinfoPointer(node.ptr, servicePointer, null, &ai_res);
1297         if (ret)
1298         {
1299             throw defaultAllocator.make!AddressException("Address info lookup failed");
1300         }
1301         scope (exit)
1302         {
1303             freeaddrinfoPointer(ai_res);
1304         }
1305 
1306         ubyte* dp = cast(ubyte*) &storage, sp = cast(ubyte*) ai_res.ai_addr;
1307         for (auto i = ai_res.ai_addrlen; i > 0; --i, *dp++, *sp++)
1308         {
1309             *dp = *sp;
1310         }
1311         if (ai_res.ai_family != AddressFamily.INET && ai_res.ai_family != AddressFamily.INET6)
1312         {
1313             throw defaultAllocator.make!AddressException("Wrong address family");
1314         }
1315     }
1316 
1317     /**
1318      * Returns: Pointer to underlying $(D_PSYMBOL sockaddr) structure.
1319      */
1320     override @property inout(sockaddr)* name() inout pure nothrow @nogc
1321     {
1322         return cast(sockaddr*) &storage;
1323     }
1324 
1325     /**
1326      * Returns: Actual size of underlying $(D_PSYMBOL sockaddr) structure.
1327      */
1328     override @property inout(socklen_t) length() inout const pure nothrow @nogc
1329     {
1330         // FreeBSD wants to know the exact length of the address on bind.
1331         switch (family)
1332         {
1333             case AddressFamily.INET:
1334                 return sockaddr_in.sizeof;
1335             case AddressFamily.INET6:
1336                 return sockaddr_in6.sizeof;
1337             default:
1338                 assert(false);
1339         }
1340     }
1341 
1342     /**
1343      * Returns: Family of this address.
1344      */
1345     @property inout(AddressFamily) family() inout const pure nothrow @nogc
1346     {
1347         return cast(AddressFamily) storage.ss_family;
1348     }
1349 
1350     @property inout(ushort) port() inout const pure nothrow @nogc
1351     {
1352         return port_;
1353     }
1354 }
1355 
1356 /**
1357  * Checks if the last error is a serious error or just a special
1358  * behaviour error of non-blocking sockets (for example an error
1359  * returned because the socket would block or because the
1360  * asynchronous operation was successfully started but not finished yet).
1361  *
1362  * Returns: $(D_KEYWORD false) if a serious error happened, $(D_KEYWORD true)
1363  *          otherwise.
1364  */
1365 bool wouldHaveBlocked() nothrow @trusted @nogc
1366 {
1367     version (Posix)
1368     {
1369         return err.errno == err.EAGAIN || err.errno == err.EWOULDBLOCK;
1370     }
1371     else version (Windows)
1372     {
1373         return WSAGetLastError() == ERROR_IO_PENDING || WSAGetLastError() == err.EWOULDBLOCK
1374             || WSAGetLastError() == ERROR_IO_INCOMPLETE;
1375     }
1376 }
1377 
1378 /**
1379  * Returns: Platform specific error code.
1380  */
1381 private @property int lastError() nothrow @safe @nogc
1382 {
1383     version (Windows)
1384     {
1385         return WSAGetLastError();
1386     }
1387     else
1388     {
1389         return err.errno;
1390     }
1391 }