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 }