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 }