1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 /**
6  * Low-level socket programming.
7  *
8  * Current API supports only server-side TCP communication.
9  *
10  * For an example of an asynchronous server refer to the documentation of the
11  * $(D_PSYMBOL tanya.async.loop) module.
12  *
13  * Copyright: Eugene Wissner 2016-2020.
14  * License: $(LINK2 https://www.mozilla.org/en-US/MPL/2.0/,
15  *                  Mozilla Public License, v. 2.0).
16  * Authors: $(LINK2 mailto:info@caraus.de, Eugene Wissner)
17  * Source: $(LINK2 https://github.com/caraus-ecms/tanya/blob/master/source/tanya/network/socket.d,
18  *                 tanya/network/socket.d)
19  */
20 module tanya.net.socket;
21 
22 import core.stdc.errno;
23 import core.time;
24 public import std.socket : SocketOption, SocketOptionLevel;
25 import tanya.bitmanip;
26 import tanya.memory.allocator;
27 import tanya.meta.trait;
28 import tanya.os.error;
29 import tanya.net.iface;
30 import tanya.net.ip;
31 
32 /// Value returned by socket operations on error.
33 enum int socketError = -1;
34 
35 version (Posix)
36 {
37     import core.stdc.errno;
38     import core.sys.posix.fcntl;
39     import core.sys.posix.netdb;
40     import core.sys.posix.netinet.in_;
41     import core.sys.posix.sys.socket;
42     import core.sys.posix.sys.time;
43     import core.sys.posix.unistd;
44 
45     enum SocketType : int
46     {
47         init = -1,
48     }
49 
50     private alias LingerField = int;
51 }
52 else version (Windows)
53 {
54     import core.sys.windows.winbase;
55     import core.sys.windows.winerror;
56     import core.sys.windows.winsock2 : accept,
57                                        addrinfo,
58                                        bind,
59                                        closesocket,
60                                        FIONBIO,
61                                        freeaddrinfo,
62                                        getaddrinfo,
63                                        getsockopt,
64                                        ioctlsocket,
65                                        listen,
66                                        MSG_DONTROUTE,
67                                        MSG_OOB,
68                                        MSG_PEEK,
69                                        recv,
70                                        SD_BOTH,
71                                        SD_RECEIVE,
72                                        SD_SEND,
73                                        send,
74                                        setsockopt,
75                                        shutdown,
76                                        SO_TYPE,
77                                        SOCKADDR,
78                                        sockaddr,
79                                        sockaddr_in,
80                                        sockaddr_in6,
81                                        SOCKADDR_STORAGE,
82                                        socket,
83                                        socklen_t,
84                                        SOL_SOCKET,
85                                        WSAEWOULDBLOCK,
86                                        WSAGetLastError;
87     import tanya.async.iocp;
88     import tanya.sys.windows.def;
89     public import tanya.sys.windows.winbase;
90     public import tanya.sys.windows.winsock2;
91 
92     enum SocketType : size_t
93     {
94         init = ~0,
95     }
96 
97     private alias LingerField = ushort;
98 
99     enum OverlappedSocketEvent
100     {
101         accept = 1,
102         read = 2,
103         write = 3,
104     }
105 
106     class SocketState : State
107     {
108         private WSABUF buffer;
109     }
110 
111     /**
112      * Socket returned if a connection has been established.
113      *
114      * Note: Available only on Windows.
115      */
116     class OverlappedConnectedSocket : ConnectedSocket
117     {
118         /**
119          * Create a socket.
120          *
121          * Params:
122          *  handle = Socket handle.
123          *  af     = Address family.
124          */
125         this(SocketType handle, AddressFamily af) @nogc
126         {
127             super(handle, af);
128         }
129 
130         /**
131          * Begins to asynchronously receive data from a connected socket.
132          *
133          * Params:
134          *  buffer     = Storage location for the received data.
135          *  flags      = Flags.
136          *  overlapped = Unique operation identifier.
137          *
138          * Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
139          *          $(D_KEYWORD false) otherwise.
140          *
141          * Throws: $(D_PSYMBOL SocketException) if unable to receive.
142          */
143         bool beginReceive(ubyte[] buffer,
144                           SocketState overlapped,
145                           Flags flags = Flags(Flag.none)) @nogc @trusted
146         {
147             auto receiveFlags = cast(DWORD) flags;
148 
149             overlapped.handle = cast(HANDLE) handle_;
150             overlapped.event = OverlappedSocketEvent.read;
151             overlapped.buffer.len = cast(ULONG) buffer.length;
152             overlapped.buffer.buf = cast(char*) buffer.ptr;
153 
154             auto result = WSARecv(handle_,
155                                   cast(WSABUF*) &overlapped.buffer,
156                                   1u,
157                                   null,
158                                   &receiveFlags,
159                                   &overlapped.overlapped,
160                                   null);
161 
162             if (result == socketError && !wouldHaveBlocked)
163             {
164                 throw defaultAllocator.make!SocketException("Unable to receive");
165             }
166             return result == 0;
167         }
168 
169         /**
170          * Ends a pending asynchronous read.
171          *
172          * Params:
173          *  overlapped = Unique operation identifier.
174          *
175          * Returns: Number of bytes received.
176          *
177          * Throws: $(D_PSYMBOL SocketException) if unable to receive.
178          *
179          * Postcondition: $(D_INLINECODE result >= 0).
180          */
181         int endReceive(SocketState overlapped) @nogc @trusted
182         out (count)
183         {
184             assert(count >= 0);
185         }
186         do
187         {
188             DWORD lpNumber;
189             BOOL result = GetOverlappedResult(overlapped.handle,
190                                               &overlapped.overlapped,
191                                               &lpNumber,
192                                               FALSE);
193             if (result == FALSE && !wouldHaveBlocked)
194             {
195                 disconnected_ = true;
196                 throw defaultAllocator.make!SocketException("Unable to receive");
197             }
198             if (lpNumber == 0)
199             {
200                 disconnected_ = true;
201             }
202             return lpNumber;
203         }
204 
205         /**
206          * Sends data asynchronously to a connected socket.
207          *
208          * Params:
209          *  buffer     = Data to be sent.
210          *  flags      = Flags.
211          *  overlapped = Unique operation identifier.
212          *
213          * Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
214          *          $(D_KEYWORD false) otherwise.
215          *
216          * Throws: $(D_PSYMBOL SocketException) if unable to send.
217          */
218         bool beginSend(ubyte[] buffer,
219                        SocketState overlapped,
220                        Flags flags = Flags(Flag.none)) @nogc @trusted
221         {
222             overlapped.handle = cast(HANDLE) handle_;
223             overlapped.event = OverlappedSocketEvent.write;
224             overlapped.buffer.len = cast(ULONG) buffer.length;
225             overlapped.buffer.buf = cast(char*) buffer.ptr;
226 
227             auto result = WSASend(handle_,
228                                   &overlapped.buffer,
229                                   1u,
230                                   null,
231                                   cast(DWORD) flags,
232                                   &overlapped.overlapped,
233                                   null);
234 
235             if (result == socketError && !wouldHaveBlocked)
236             {
237                 disconnected_ = true;
238                 throw defaultAllocator.make!SocketException("Unable to send");
239             }
240             return result == 0;
241         }
242 
243         /**
244          * Ends a pending asynchronous send.
245          *
246          * Params:
247          *  overlapped = Unique operation identifier.
248          *
249          * Returns: Number of bytes sent.
250          *
251          * Throws: $(D_PSYMBOL SocketException) if unable to receive.
252          *
253          * Postcondition: $(D_INLINECODE result >= 0).
254         */
255         int endSend(SocketState overlapped) @nogc @trusted
256         out (count)
257         {
258             assert(count >= 0);
259         }
260         do
261         {
262             DWORD lpNumber;
263             BOOL result = GetOverlappedResult(overlapped.handle,
264                                               &overlapped.overlapped,
265                                               &lpNumber,
266                                               FALSE);
267             if (result == FALSE && !wouldHaveBlocked)
268             {
269                 disconnected_ = true;
270                 throw defaultAllocator.make!SocketException("Unable to receive");
271             }
272             return lpNumber;
273         }
274     }
275 
276     /**
277      * Windows stream socket overlapped I/O.
278      */
279     class OverlappedStreamSocket : StreamSocket
280     {
281         // Accept extension function pointer.
282         package LPFN_ACCEPTEX acceptExtension;
283 
284         /**
285          * Create a socket.
286          *
287          * Params:
288          *  af = Address family.
289          *
290          * Throws: $(D_PSYMBOL SocketException) on errors.
291          */
292         this(AddressFamily af) @nogc @trusted
293         {
294             super(af);
295             scope (failure)
296             {
297                 this.close();
298             }
299             blocking = false;
300 
301             GUID guidAcceptEx = WSAID_ACCEPTEX;
302             DWORD dwBytes;
303 
304             auto result = WSAIoctl(handle_,
305                                    SIO_GET_EXTENSION_FUNCTION_POINTER,
306                                    &guidAcceptEx,
307                                    guidAcceptEx.sizeof,
308                                    &acceptExtension,
309                                    acceptExtension.sizeof,
310                                    &dwBytes,
311                                    null,
312                                    null);
313             if (!result == socketError)
314             {
315                 throw make!SocketException(defaultAllocator,
316                                            "Unable to retrieve an accept extension function pointer");
317             }
318         }
319 
320         /**
321          * Begins an asynchronous operation to accept an incoming connection attempt.
322          *
323          * Params:
324          *  overlapped = Unique operation identifier.
325          *
326          * Returns: $(D_KEYWORD true) if the operation could be finished synchronously.
327          *          $(D_KEYWORD false) otherwise.
328          *
329          * Throws: $(D_PSYMBOL SocketException) on accept errors.
330          */
331         bool beginAccept(SocketState overlapped) @nogc @trusted
332         {
333             auto socket = cast(SocketType) socket(addressFamily, 1, 0);
334             if (socket == SocketType.init)
335             {
336                 throw defaultAllocator.make!SocketException("Unable to create socket");
337             }
338             scope (failure)
339             {
340                 closesocket(socket);
341             }
342             DWORD dwBytes;
343             overlapped.handle = cast(HANDLE) socket;
344             overlapped.event = OverlappedSocketEvent.accept;
345 
346             const len = (sockaddr_in.sizeof + 16) * 2;
347             overlapped.buffer.len = len;
348             overlapped.buffer.buf = cast(char*) defaultAllocator.allocate(len).ptr;
349 
350             // We don't want to get any data now, but only start to accept the connections
351             BOOL result = acceptExtension(handle_,
352                                           socket,
353                                           overlapped.buffer.buf,
354                                           0u,
355                                           sockaddr_in.sizeof + 16,
356                                           sockaddr_in.sizeof + 16,
357                                           &dwBytes,
358                                           &overlapped.overlapped);
359             if (result == FALSE && !wouldHaveBlocked)
360             {
361                 throw defaultAllocator.make!SocketException("Unable to accept socket connection");
362             }
363             return result == TRUE;
364         }
365 
366         /**
367          * Asynchronously accepts an incoming connection attempt and creates a
368          * new socket to handle remote host communication.
369          *
370          * Params:
371          *  overlapped = Unique operation identifier.
372          *
373          * Returns: Connected socket.
374          *
375          * Throws: $(D_PSYMBOL SocketException) if unable to accept.
376          */
377         OverlappedConnectedSocket endAccept(SocketState overlapped)
378         @nogc @trusted
379         {
380             scope (exit)
381             {
382                 defaultAllocator.dispose(overlapped.buffer.buf[0 .. overlapped.buffer.len]);
383             }
384             auto socket = make!OverlappedConnectedSocket(defaultAllocator,
385                                                          cast(SocketType) overlapped.handle,
386                                                          addressFamily);
387             scope (failure)
388             {
389                 defaultAllocator.dispose(socket);
390             }
391             socket.setOption(SocketOptionLevel.SOCKET,
392                              cast(SocketOption) SO_UPDATE_ACCEPT_CONTEXT,
393                              cast(size_t) handle);
394             return socket;
395         }
396     }
397 }
398 
399 /**
400  * Socket option that specifies what should happen when the socket that
401  * promises reliable delivery still has untransmitted messages when
402  * it is closed.
403  */
404 struct Linger
405 {
406     /// If nonzero, $(D_PSYMBOL close) and $(D_PSYMBOL shutdown) block until
407     /// the data are transmitted or the timeout period has expired.
408     LingerField l_onoff;
409 
410     /// Time, in seconds to wait before any buffered data to be sent is
411     /// discarded.
412     LingerField l_linger;
413 
414     /**
415      * If $(D_PARAM timeout) is `0`, linger is disabled, otherwise enables the
416      * linger and sets the timeout.
417      *
418      * Params:
419      *  timeout = Timeout, in seconds.
420      */
421     this(const ushort timeout)
422     {
423         time = timeout;
424     }
425 
426     ///
427     unittest
428     {
429         {
430             auto linger = Linger(5);
431             assert(linger.enabled);
432             assert(linger.time == 5);
433         }
434         {
435             auto linger = Linger(0);
436             assert(!linger.enabled);
437         }
438         { // Default constructor.
439             Linger linger;
440             assert(!linger.enabled);
441         }
442     }
443 
444     /**
445      * System dependent constructor.
446      *
447      * Params:
448      *  l_onoff  = $(D_PSYMBOL l_onoff) value.
449      *  l_linger = $(D_PSYMBOL l_linger) value.
450      */
451     this(LingerField l_onoff, LingerField l_linger)
452     {
453         this.l_onoff = l_onoff;
454         this.l_linger = l_linger;
455     }
456 
457     ///
458     unittest
459     {
460         auto linger = Linger(1, 5);
461         assert(linger.l_onoff == 1);
462         assert(linger.l_linger == 5);
463     }
464 
465     /**
466      * Params:
467      *  value = Whether to linger after the socket is closed.
468      *
469      * See_Also: $(D_PSYMBOL time).
470      */
471     @property void enabled(const bool value) pure nothrow @safe @nogc
472     {
473         this.l_onoff = value;
474     }
475 
476     /**
477      * Returns: Whether to linger after the socket is closed.
478      */
479     @property bool enabled() const pure nothrow @safe @nogc
480     {
481         return this.l_onoff != 0;
482     }
483 
484     /**
485      * Returns: Timeout period, in seconds, to wait before closing the socket
486      *          if the $(D_PSYMBOL Linger) is $(D_PSYMBOL enabled).
487      */
488     @property ushort time() const pure nothrow @safe @nogc
489     {
490         return this.l_linger & ushort.max;
491     }
492 
493     /**
494      *  Sets timeout period, to wait before closing the socket if the
495      *  $(D_PSYMBOL Linger) is $(D_PSYMBOL enabled), ignored otherwise.
496      *
497      * Params:
498      *  timeout = Timeout period, in seconds.
499      */
500     @property void time(const ushort timeout) pure nothrow @safe @nogc
501     {
502         this.l_onoff = timeout > 0;
503         this.l_linger = timeout;
504     }
505 }
506 
507 version (linux)
508 {
509     enum SOCK_NONBLOCK = O_NONBLOCK;
510     extern(C) int accept4(int, sockaddr*, socklen_t*, int flags) @nogc nothrow;
511 }
512 else version (OSX)
513 {
514     version = MacBSD;
515 }
516 else version (iOS)
517 {
518     version = MacBSD;
519 }
520 else version (FreeBSD)
521 {
522     version = MacBSD;
523 }
524 else version (OpenBSD)
525 {
526     version = MacBSD;
527 }
528 else version (DragonFlyBSD)
529 {
530     version = MacBSD;
531 }
532 
533 version (MacBSD)
534 {
535     enum ESOCKTNOSUPPORT = 44; // Socket type not suppoted.
536 }
537 
538 private immutable
539 {
540     typeof(&getaddrinfo) getaddrinfoPointer;
541     typeof(&freeaddrinfo) freeaddrinfoPointer;
542 }
543 
544 shared static this()
545 {
546     version (Windows)
547     {
548         auto ws2Lib = GetModuleHandle("ws2_32.dll");
549 
550         getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
551             GetProcAddress(ws2Lib, "getaddrinfo");
552         freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
553             GetProcAddress(ws2Lib, "freeaddrinfo");
554     }
555     else version (Posix)
556     {
557         getaddrinfoPointer = &getaddrinfo;
558         freeaddrinfoPointer = &freeaddrinfo;
559     }
560 }
561 
562 /**
563  * $(D_PSYMBOL SocketException) should be thrown only if one of the socket functions
564  * $(D_PSYMBOL socketError) and sets $(D_PSYMBOL errno), because
565  * $(D_PSYMBOL SocketException) relies on the $(D_PSYMBOL errno) value.
566  */
567 class SocketException : Exception
568 {
569     const ErrorCode.ErrorNo error = ErrorCode.ErrorNo.success;
570 
571     /**
572      * Params:
573      *  msg  = The message for the exception.
574      *  file = The file where the exception occurred.
575      *  line = The line number where the exception occurred.
576      *  next = The previous exception in the chain of exceptions, if any.
577      */
578     this(string msg,
579          string file = __FILE__,
580          size_t line = __LINE__,
581          Throwable next = null) @nogc @safe nothrow
582     {
583         super(msg, file, line, next);
584 
585         foreach (member; EnumMembers!(ErrorCode.ErrorNo))
586         {
587             if (member == lastError)
588             {
589                 error = member;
590                 return;
591             }
592         }
593         if (lastError == ENOMEM)
594         {
595             error = ErrorCode.ErrorNo.noBufferSpace;
596         }
597         else if (lastError == EMFILE)
598         {
599             error = ErrorCode.ErrorNo.tooManyDescriptors;
600         }
601         else version (linux)
602         {
603             if (lastError == ENOSR)
604             {
605                 error = ErrorCode.ErrorNo.networkDown;
606             }
607         }
608         else version (Posix)
609         {
610             if (lastError == EPROTO)
611             {
612                 error = ErrorCode.ErrorNo.networkDown;
613             }
614         }
615     }
616 }
617 
618 /**
619  * Class for creating a network communication endpoint using the Berkeley
620  * sockets interfaces of different types.
621  */
622 abstract class Socket
623 {
624     version (Posix)
625     {
626         /**
627          * How a socket is shutdown.
628          */
629         enum Shutdown : int
630         {
631             receive = SHUT_RD,   /// Socket receives are disallowed
632             send    = SHUT_WR,   /// Socket sends are disallowed
633             both    = SHUT_RDWR, /// Both receive and send
634         }
635     }
636     else version (Windows)
637     {
638         /// Property to get or set whether the socket is blocking or nonblocking.
639         private bool blocking_ = true;
640 
641         /**
642          * How a socket is shutdown.
643          */
644         enum Shutdown : int
645         {
646             receive = SD_RECEIVE, /// Socket receives are disallowed.
647             send    = SD_SEND,    /// Socket sends are disallowed.
648             both    = SD_BOTH,    /// Both receive and send.
649         }
650 
651         // The WinSock timeouts seem to be effectively skewed by a constant
652         // offset of about half a second (in milliseconds).
653         private enum WINSOCK_TIMEOUT_SKEW = 500;
654     }
655 
656     /// Socket handle.
657     protected SocketType handle_;
658 
659     /// Address family.
660     protected AddressFamily family;
661 
662     private @property void handle(SocketType handle) @nogc
663     in
664     {
665         assert(handle != SocketType.init);
666         assert(handle_ == SocketType.init, "Socket handle cannot be changed");
667     }
668     do
669     {
670         handle_ = handle;
671 
672         // Set the option to disable SIGPIPE on send() if the platform
673         // has it (e.g. on OS X).
674         static if (is(typeof(SO_NOSIGPIPE)))
675         {
676             setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_NOSIGPIPE, true);
677         }
678     }
679 
680     @property inout(SocketType) handle() inout const pure nothrow @safe @nogc
681     {
682         return handle_;
683     }
684 
685     /**
686      * Create a socket.
687      *
688      * Params:
689      *  handle = Socket.
690      *  af     = Address family.
691      */
692     this(SocketType handle, AddressFamily af) @nogc
693     in
694     {
695         assert(handle != SocketType.init);
696     }
697     do
698     {
699         scope (failure)
700         {
701             this.close();
702         }
703         this.handle = handle;
704         family = af;
705     }
706 
707     /**
708      * Closes the socket and calls the destructor on itself.
709      */
710     ~this() nothrow @trusted @nogc
711     {
712         this.close();
713     }
714 
715     /**
716      * Get a socket option.
717      *
718      * Params:
719      *  level  = Protocol level at that the option exists.
720      *  option = Option.
721      *  result = Buffer to save the result.
722      *
723      * Returns: The number of bytes written to $(D_PARAM result).
724      *
725      * Throws: $(D_PSYMBOL SocketException) on error.
726      */
727     protected int getOption(SocketOptionLevel level,
728                             SocketOption option,
729                             void[] result) const @trusted @nogc
730     {
731         auto length = cast(socklen_t) result.length;
732         if (getsockopt(handle_,
733                        cast(int) level,
734                        cast(int) option,
735                        result.ptr,
736                        &length) == socketError)
737         {
738             throw defaultAllocator.make!SocketException("Unable to get socket option");
739         }
740         return length;
741     }
742 
743     /// Ditto.
744     int getOption(SocketOptionLevel level,
745                   SocketOption option,
746                   out size_t result) const @trusted @nogc
747     {
748         return getOption(level, option, (&result)[0 .. 1]);
749     }
750 
751     /// Ditto.
752     int getOption(SocketOptionLevel level,
753                   SocketOption option,
754                   out Linger result) const @trusted @nogc
755     {
756         return getOption(level, option, (&result)[0 .. 1]);
757     }
758 
759     /// Ditto.
760     int getOption(SocketOptionLevel level,
761                   SocketOption option,
762                   out Duration result) const @trusted @nogc
763     {
764         // WinSock returns the timeout values as a milliseconds DWORD,
765         // while Linux and BSD return a timeval struct.
766         version (Posix)
767         {
768             timeval tv;
769             auto ret = getOption(level, option, (&tv)[0 .. 1]);
770             result = dur!"seconds"(tv.tv_sec) + dur!"usecs"(tv.tv_usec);
771         }
772         else version (Windows)
773         {
774             int msecs;
775             auto ret = getOption(level, option, (&msecs)[0 .. 1]);
776             if (option == SocketOption.RCVTIMEO)
777             {
778                 msecs += WINSOCK_TIMEOUT_SKEW;
779             }
780             result = dur!"msecs"(msecs);
781         }
782         return ret;
783     }
784 
785     /**
786      * Set a socket option.
787      *
788      * Params:
789      *  level  = Protocol level at that the option exists.
790      *  option = Option.
791      *  value  = Option value.
792      *
793      * Throws: $(D_PSYMBOL SocketException) on error.
794      */
795     protected void setOption(SocketOptionLevel level,
796                              SocketOption option,
797                              void[] value) const @trusted @nogc
798     {
799         if (setsockopt(handle_,
800                        cast(int)level,
801                        cast(int)option,
802                        value.ptr,
803                        cast(uint) value.length) == socketError)
804         {
805             throw defaultAllocator.make!SocketException("Unable to set socket option");
806         }
807     }
808 
809     /// Ditto.
810     void setOption(SocketOptionLevel level, SocketOption option, size_t value)
811     const @trusted @nogc
812     {
813         setOption(level, option, (&value)[0 .. 1]);
814     }
815 
816     /// Ditto.
817     void setOption(SocketOptionLevel level, SocketOption option, Linger value)
818     const @trusted @nogc
819     {
820         setOption(level, option, (&value)[0 .. 1]);
821     }
822 
823     /// Ditto.
824     void setOption(SocketOptionLevel level, SocketOption option, Duration value)
825     const @trusted @nogc
826     {
827         version (Posix)
828         {
829             timeval tv;
830             value.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec);
831             setOption(level, option, (&tv)[0 .. 1]);
832         }
833         else version (Windows)
834         {
835             auto msecs = cast(int) value.total!"msecs";
836             if (msecs > 0 && option == SocketOption.RCVTIMEO)
837             {
838                 msecs = max(1, msecs - WINSOCK_TIMEOUT_SKEW);
839             }
840             setOption(level, option, msecs);
841         }
842     }
843 
844     /**
845      * Returns: Socket's blocking flag.
846      */
847     @property inout(bool) blocking() inout const nothrow @nogc
848     {
849         version (Posix)
850         {
851             return !(fcntl(handle_, F_GETFL, 0) & O_NONBLOCK);
852         }
853         else version (Windows)
854         {
855             return this.blocking_;
856         }
857     }
858 
859     /**
860      * Params:
861      *  yes = Socket's blocking flag.
862      */
863     @property void blocking(bool yes) @nogc
864     {
865         version (Posix)
866         {
867             int fl = fcntl(handle_, F_GETFL, 0);
868 
869             if (fl != socketError)
870             {
871                 fl = yes ? fl & ~O_NONBLOCK : fl | O_NONBLOCK;
872                 fl = fcntl(handle_, F_SETFL, fl);
873             }
874             if (fl == socketError)
875             {
876                 throw make!SocketException(defaultAllocator,
877                                            "Unable to set socket blocking");
878             }
879         }
880         else version (Windows)
881         {
882             uint num = !yes;
883             if (ioctlsocket(handle_, FIONBIO, &num) == socketError)
884             {
885                 throw make!SocketException(defaultAllocator,
886                                            "Unable to set socket blocking");
887             }
888             this.blocking_ = yes;
889         }
890     }
891 
892     /**
893      * Returns: The socket's address family.
894      */
895     @property AddressFamily addressFamily() const @nogc @safe pure nothrow
896     {
897         return family;
898     }
899 
900     /**
901      * Returns: $(D_KEYWORD true) if this is a valid, alive socket.
902      */
903     @property bool isAlive() @trusted const nothrow @nogc
904     {
905         int type;
906         socklen_t typesize = cast(socklen_t) type.sizeof;
907         return !getsockopt(handle_, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
908     }
909 
910     /**
911      * Disables sends and/or receives.
912      *
913      * Params:
914      *  how = What to disable.
915      *
916      * See_Also:
917      *  $(D_PSYMBOL Shutdown)
918      */
919     void shutdown(Shutdown how = Shutdown.both) @nogc @trusted const nothrow
920     {
921         .shutdown(handle_, cast(int)how);
922     }
923 
924     /**
925      * Immediately drop any connections and release socket resources.
926      * Calling $(D_PSYMBOL shutdown) before $(D_PSYMBOL close) is recommended
927      * for connection-oriented sockets. The $(D_PSYMBOL Socket) object is no
928      * longer usable after $(D_PSYMBOL close).
929      */
930     void close() nothrow @trusted @nogc
931     {
932         version(Windows)
933         {
934             .closesocket(handle_);
935         }
936         else version(Posix)
937         {
938             .close(handle_);
939         }
940         handle_ = SocketType.init;
941     }
942 
943     /**
944      * Listen for an incoming connection. $(D_PSYMBOL bind) must be called before you
945      * can $(D_PSYMBOL listen).
946      *
947      * Params:
948      *  backlog = Request of how many pending incoming connections are
949      *            queued until $(D_PSYMBOL accept)ed.
950      */
951     void listen(int backlog) const @trusted @nogc
952     {
953         if (.listen(handle_, backlog) == socketError)
954         {
955             throw defaultAllocator.make!SocketException("Unable to listen on socket");
956         }
957     }
958 
959     /**
960      * Compare handles.
961      *
962      * Params:
963      *  that = Another handle.
964      *
965      * Returns: Comparision result.
966      */
967     int opCmp(size_t that) const pure nothrow @safe @nogc
968     {
969         return handle_ < that ? -1 : handle_ > that ? 1 : 0;
970     }
971 }
972 
973 /**
974  * Interface with common fileds for stream and connected sockets.
975  */
976 interface ConnectionOrientedSocket
977 {
978     /**
979      * Flags may be OR'ed together.
980      */
981     enum Flag : int
982     {
983         /// No flags specified.
984         none      = 0,
985         /// Out-of-band stream data.
986         outOfBand = MSG_OOB,
987         /// Peek at incoming data without removing it from the queue, only for receiving.
988         peek      = MSG_PEEK,
989         /// Data should not be subject to routing; this flag may be ignored. Only for sending.
990         dontRoute = MSG_DONTROUTE,
991     }
992 
993     alias Flags = BitFlags!Flag;
994 }
995 
996 class StreamSocket : Socket, ConnectionOrientedSocket
997 {
998     /**
999      * Create a socket.
1000      *
1001      * Params:
1002      *  af = Address family.
1003      */
1004     this(AddressFamily af) @trusted @nogc
1005     {
1006         auto handle = cast(SocketType) socket(af, 1, 0);
1007         if (handle == SocketType.init)
1008         {
1009             throw defaultAllocator.make!SocketException("Unable to create socket");
1010         }
1011         super(handle, af);
1012     }
1013 
1014     /**
1015      * Associate a local address with this socket.
1016      *
1017      * Params:
1018      *  endpoint = Local address.
1019      *
1020      * Throws: $(D_PSYMBOL SocketException) if unable to bind.
1021      */
1022     void bind(const Endpoint endpoint) const @nogc
1023     {
1024         if (.bind(handle_, cast(const(sockaddr)*) &endpoint, Endpoint.sizeof))
1025         {
1026             throw defaultAllocator.make!SocketException("Unable to bind socket");
1027         }
1028     }
1029 
1030     /**
1031      * Accept an incoming connection.
1032      *
1033      * The blocking mode is always inherited.
1034      *
1035      * Returns: $(D_PSYMBOL Socket) for the accepted connection or
1036      *          $(D_KEYWORD null) if the call would block on a
1037      *          non-blocking socket.
1038      *
1039      * Throws: $(D_PSYMBOL SocketException) if unable to accept.
1040      */
1041     ConnectedSocket accept() @trusted @nogc
1042     {
1043         SocketType sock;
1044 
1045         version (linux)
1046         {
1047             int flags;
1048             if (!blocking)
1049             {
1050                 flags |= SOCK_NONBLOCK;
1051             }
1052             sock = cast(SocketType).accept4(handle_, null, null, flags);
1053         }
1054         else
1055         {
1056             sock = cast(SocketType).accept(handle_, null, null);
1057         }
1058 
1059         if (sock == SocketType.init)
1060         {
1061             if (wouldHaveBlocked())
1062             {
1063                 return null;
1064             }
1065             throw make!SocketException(defaultAllocator,
1066                                        "Unable to accept socket connection");
1067         }
1068 
1069         auto newSocket = defaultAllocator.make!ConnectedSocket(sock, addressFamily);
1070 
1071         version (linux)
1072         { // Blocking mode already set
1073         }
1074         else version (Posix)
1075         {
1076             if (!blocking)
1077             {
1078                 try
1079                 {
1080                     newSocket.blocking = blocking;
1081                 }
1082                 catch (SocketException e)
1083                 {
1084                     defaultAllocator.dispose(newSocket);
1085                     throw e;
1086                 }
1087             }
1088         }
1089         else version (Windows)
1090         { // Inherits blocking mode
1091             newSocket.blocking_ = blocking;
1092         }
1093         return newSocket;
1094     }
1095 }
1096 
1097 /**
1098  * Socket returned if a connection has been established.
1099  */
1100 class ConnectedSocket : Socket, ConnectionOrientedSocket
1101 {
1102     /**
1103      * $(D_KEYWORD true) if the stream socket peer has performed an orderly
1104      * shutdown.
1105      */
1106     protected bool disconnected_;
1107 
1108     /**
1109      * Returns: $(D_KEYWORD true) if the stream socket peer has performed an orderly
1110      *          shutdown.
1111      */
1112     @property inout(bool) disconnected() inout const pure nothrow @safe @nogc
1113     {
1114         return disconnected_;
1115     }
1116 
1117     /**
1118      * Create a socket.
1119      *
1120      * Params:
1121      *  handle = Socket.
1122      *  af     = Address family.
1123      */
1124     this(SocketType handle, AddressFamily af) @nogc
1125     {
1126         super(handle, af);
1127     }
1128 
1129     version (Windows)
1130     {
1131         private static int capToMaxBuffer(size_t size) pure nothrow @safe @nogc
1132         {
1133             // Windows uses int instead of size_t for length arguments.
1134             // Luckily, the send/recv functions make no guarantee that
1135             // all the data is sent, so we use that to send at most
1136             // int.max bytes.
1137             return size > size_t (int.max) ? int.max : cast(int) size;
1138         }
1139     }
1140     else
1141     {
1142         private static size_t capToMaxBuffer(size_t size) pure nothrow @safe @nogc
1143         {
1144             return size;
1145         }
1146     }
1147 
1148     /**
1149      * Receive data on the connection.
1150      *
1151      * Params:
1152      *  buf   = Buffer to save received data.
1153      *  flags = Flags.
1154      *
1155      * Returns: The number of bytes received or 0 if nothing received
1156      *          because the call would block.
1157      *
1158      * Throws: $(D_PSYMBOL SocketException) if unable to receive.
1159      */
1160     ptrdiff_t receive(ubyte[] buf, Flags flags = Flag.none) @trusted @nogc
1161     {
1162         ptrdiff_t ret;
1163         if (!buf.length)
1164         {
1165             return 0;
1166         }
1167 
1168         ret = recv(handle_, buf.ptr, capToMaxBuffer(buf.length), cast(int) flags);
1169         if (ret == 0)
1170         {
1171             disconnected_ = true;
1172         }
1173         else if (ret == socketError)
1174         {
1175             if (wouldHaveBlocked())
1176             {
1177                 return 0;
1178             }
1179             disconnected_ = true;
1180             throw defaultAllocator.make!SocketException("Unable to receive");
1181         }
1182         return ret;
1183     }
1184 
1185     /**
1186      * Send data on the connection. If the socket is blocking and there is no
1187      * buffer space left, $(D_PSYMBOL send) waits, non-blocking socket returns
1188      * 0 in this case.
1189      *
1190      * Params:
1191      *  buf   = Data to be sent.
1192      *  flags = Flags.
1193      *
1194      * Returns: The number of bytes actually sent.
1195      *
1196      * Throws: $(D_PSYMBOL SocketException) if unable to send.
1197      */
1198     ptrdiff_t send(const(ubyte)[] buf, Flags flags = Flag.none)
1199     const @trusted @nogc
1200     {
1201         int sendFlags = cast(int) flags;
1202         ptrdiff_t sent;
1203 
1204         static if (is(typeof(MSG_NOSIGNAL)))
1205         {
1206             sendFlags |= MSG_NOSIGNAL;
1207         }
1208 
1209         sent = .send(handle_, buf.ptr, capToMaxBuffer(buf.length), sendFlags);
1210         if (sent != socketError)
1211         {
1212             return sent;
1213         }
1214         else if (wouldHaveBlocked())
1215         {
1216             return 0;
1217         }
1218         throw defaultAllocator.make!SocketException("Unable to send");
1219     }
1220 }
1221 
1222 /**
1223  * Checks if the last error is a serious error or just a special
1224  * behaviour error of non-blocking sockets (for example an error
1225  * returned because the socket would block or because the
1226  * asynchronous operation was successfully started but not finished yet).
1227  *
1228  * Returns: $(D_KEYWORD false) if a serious error happened, $(D_KEYWORD true)
1229  *          otherwise.
1230  */
1231 bool wouldHaveBlocked() nothrow @trusted @nogc
1232 {
1233     version (Posix)
1234     {
1235         return errno == EAGAIN || errno == EWOULDBLOCK;
1236     }
1237     else version (Windows)
1238     {
1239         return WSAGetLastError() == ERROR_IO_PENDING
1240             || WSAGetLastError() == WSAEWOULDBLOCK
1241             || WSAGetLastError() == ERROR_IO_INCOMPLETE;
1242     }
1243 }
1244 
1245 /**
1246  * Returns: Platform specific error code.
1247  */
1248 private @property int lastError() nothrow @safe @nogc
1249 {
1250     version (Windows)
1251     {
1252         return WSAGetLastError();
1253     }
1254     else
1255     {
1256         return errno;
1257     }
1258 }