1 // Written in the D programming language 2 3 // NOTE: When working on this module, be sure to run tests with -debug=std_socket 4 // E.g.: dmd -version=StdUnittest -debug=std_socket -unittest -main -run socket 5 // This will enable some tests which are too slow or flaky to run as part of CI. 6 7 /* 8 Copyright (C) 2004-2011 Christopher E. Miller 9 10 socket.d 1.4 11 Jan 2011 12 13 Thanks to Benjamin Herr for his assistance. 14 */ 15 16 /** 17 * Socket primitives. 18 * Example: See $(SAMPLESRC listener.d) and $(SAMPLESRC htmlget.d) 19 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 20 * Authors: Christopher E. Miller, $(HTTP klickverbot.at, David Nadlinger), 21 * $(HTTP thecybershadow.net, Vladimir Panteleev) 22 * Source: $(PHOBOSSRC std/socket.d) 23 */ 24 25 module std.socket; 26 27 import core.stdc.stdint, core.stdc.stdlib, core.stdc..string, std.conv, std..string; 28 29 import core.stdc.config; 30 import core.time : dur, Duration; 31 import std.exception; 32 33 import std.internal.cstring; 34 35 version (iOS) 36 version = iOSDerived; 37 else version (TVOS) 38 version = iOSDerived; 39 else version (WatchOS) 40 version = iOSDerived; 41 42 @safe: 43 44 version (Windows) 45 { 46 pragma (lib, "ws2_32.lib"); 47 pragma (lib, "wsock32.lib"); 48 49 import core.sys.windows.winbase, std.windows.syserror; 50 public import core.sys.windows.winsock2; 51 private alias _ctimeval = core.sys.windows.winsock2.timeval; 52 private alias _clinger = core.sys.windows.winsock2.linger; 53 54 enum socket_t : SOCKET { INVALID_SOCKET } 55 private const int _SOCKET_ERROR = SOCKET_ERROR; 56 57 58 private int _lasterr() nothrow @nogc 59 { 60 return WSAGetLastError(); 61 } 62 } 63 else version (Posix) 64 { 65 version (linux) 66 { 67 enum : int 68 { 69 TCP_KEEPIDLE = 4, 70 TCP_KEEPINTVL = 5 71 } 72 } 73 74 public import core.sys.posix.netinet.in_; 75 import core.sys.posix.arpa.inet; 76 import core.sys.posix.fcntl; 77 import core.sys.posix.netdb; 78 import core.sys.posix.netinet.tcp; 79 import core.sys.posix.sys.select; 80 import core.sys.posix.sys.socket; 81 import core.sys.posix.sys.time; 82 import core.sys.posix.sys.un : sockaddr_un; 83 import core.sys.posix.unistd; 84 private alias _ctimeval = core.sys.posix.sys.time.timeval; 85 private alias _clinger = core.sys.posix.sys.socket.linger; 86 87 import core.stdc.errno; 88 89 enum socket_t : int32_t { init = -1 } 90 private const int _SOCKET_ERROR = -1; 91 92 private enum : int 93 { 94 SD_RECEIVE = SHUT_RD, 95 SD_SEND = SHUT_WR, 96 SD_BOTH = SHUT_RDWR 97 } 98 99 private int _lasterr() nothrow @nogc 100 { 101 return errno; 102 } 103 } 104 else 105 { 106 static assert(0, "No socket support for this platform yet."); 107 } 108 109 version (StdUnittest) 110 { 111 // Print a message on exception instead of failing the unittest. 112 private void softUnittest(void delegate() @safe test, int line = __LINE__) @trusted 113 { 114 debug (std_socket) 115 test(); 116 else 117 { 118 import std.stdio : writefln; 119 try 120 test(); 121 catch (Throwable e) 122 writefln("Ignoring std.socket(%d) test failure (likely caused by flaky environment): %s", line, e.msg); 123 } 124 } 125 } 126 127 /// Base exception thrown by `std.socket`. 128 class SocketException: Exception 129 { 130 mixin basicExceptionCtors; 131 } 132 133 version (CRuntime_Glibc) version = GNU_STRERROR; 134 version (CRuntime_UClibc) version = GNU_STRERROR; 135 136 /* 137 * Needs to be public so that SocketOSException can be thrown outside of 138 * std.socket (since it uses it as a default argument), but it probably doesn't 139 * need to actually show up in the docs, since there's not really any public 140 * need for it outside of being a default argument. 141 */ 142 string formatSocketError(int err) @trusted 143 { 144 version (Posix) 145 { 146 char[80] buf; 147 const(char)* cs; 148 version (GNU_STRERROR) 149 { 150 cs = strerror_r(err, buf.ptr, buf.length); 151 } 152 else 153 { 154 auto errs = strerror_r(err, buf.ptr, buf.length); 155 if (errs == 0) 156 cs = buf.ptr; 157 else 158 return "Socket error " ~ to!string(err); 159 } 160 161 auto len = strlen(cs); 162 163 if (cs[len - 1] == '\n') 164 len--; 165 if (cs[len - 1] == '\r') 166 len--; 167 return cs[0 .. len].idup; 168 } 169 else 170 version (Windows) 171 { 172 return sysErrorString(err); 173 } 174 else 175 return "Socket error " ~ to!string(err); 176 } 177 178 /// Retrieve the error message for the most recently encountered network error. 179 @property string lastSocketError() 180 { 181 return formatSocketError(_lasterr()); 182 } 183 184 /** 185 * Socket exceptions representing network errors reported by the operating 186 * system. 187 */ 188 class SocketOSException: SocketException 189 { 190 int errorCode; /// Platform-specific error code. 191 192 /// 193 this(string msg, 194 string file = __FILE__, 195 size_t line = __LINE__, 196 Throwable next = null, 197 int err = _lasterr(), 198 string function(int) @trusted errorFormatter = &formatSocketError) 199 { 200 errorCode = err; 201 202 if (msg.length) 203 super(msg ~ ": " ~ errorFormatter(err), file, line, next); 204 else 205 super(errorFormatter(err), file, line, next); 206 } 207 208 /// 209 this(string msg, 210 Throwable next, 211 string file = __FILE__, 212 size_t line = __LINE__, 213 int err = _lasterr(), 214 string function(int) @trusted errorFormatter = &formatSocketError) 215 { 216 this(msg, file, line, next, err, errorFormatter); 217 } 218 219 /// 220 this(string msg, 221 int err, 222 string function(int) @trusted errorFormatter = &formatSocketError, 223 string file = __FILE__, 224 size_t line = __LINE__, 225 Throwable next = null) 226 { 227 this(msg, file, line, next, err, errorFormatter); 228 } 229 } 230 231 /// Socket exceptions representing invalid parameters specified by user code. 232 class SocketParameterException: SocketException 233 { 234 mixin basicExceptionCtors; 235 } 236 237 /** 238 * Socket exceptions representing attempts to use network capabilities not 239 * available on the current system. 240 */ 241 class SocketFeatureException: SocketException 242 { 243 mixin basicExceptionCtors; 244 } 245 246 247 /** 248 * Returns: 249 * `true` if the last socket operation failed because the socket 250 * was in non-blocking mode and the operation would have blocked, 251 * or if the socket is in blocking mode and set a SNDTIMEO or RCVTIMEO, 252 * and the operation timed out. 253 */ 254 bool wouldHaveBlocked() nothrow @nogc 255 { 256 version (Windows) 257 return _lasterr() == WSAEWOULDBLOCK || _lasterr() == WSAETIMEDOUT; 258 else version (Posix) 259 return _lasterr() == EAGAIN; 260 else 261 static assert(0, "No socket support for this platform yet."); 262 } 263 264 @safe unittest 265 { 266 auto sockets = socketPair(); 267 auto s = sockets[0]; 268 s.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"msecs"(10)); 269 ubyte[] buffer = new ubyte[](16); 270 auto rec = s.receive(buffer); 271 assert(rec == -1 && wouldHaveBlocked()); 272 } 273 274 275 private immutable 276 { 277 typeof(&getnameinfo) getnameinfoPointer; 278 typeof(&getaddrinfo) getaddrinfoPointer; 279 typeof(&freeaddrinfo) freeaddrinfoPointer; 280 } 281 282 shared static this() @system 283 { 284 version (Windows) 285 { 286 WSADATA wd; 287 288 // Winsock will still load if an older version is present. 289 // The version is just a request. 290 int val; 291 val = WSAStartup(0x2020, &wd); 292 if (val) // Request Winsock 2.2 for IPv6. 293 throw new SocketOSException("Unable to initialize socket library", val); 294 295 // These functions may not be present on older Windows versions. 296 // See the comment in InternetAddress.toHostNameString() for details. 297 auto ws2Lib = GetModuleHandleA("ws2_32.dll"); 298 if (ws2Lib) 299 { 300 getnameinfoPointer = cast(typeof(getnameinfoPointer)) 301 GetProcAddress(ws2Lib, "getnameinfo"); 302 getaddrinfoPointer = cast(typeof(getaddrinfoPointer)) 303 GetProcAddress(ws2Lib, "getaddrinfo"); 304 freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer)) 305 GetProcAddress(ws2Lib, "freeaddrinfo"); 306 } 307 } 308 else version (Posix) 309 { 310 getnameinfoPointer = &getnameinfo; 311 getaddrinfoPointer = &getaddrinfo; 312 freeaddrinfoPointer = &freeaddrinfo; 313 } 314 } 315 316 317 shared static ~this() @system nothrow @nogc 318 { 319 version (Windows) 320 { 321 WSACleanup(); 322 } 323 } 324 325 /** 326 * The communication domain used to resolve an address. 327 */ 328 enum AddressFamily: ushort 329 { 330 UNSPEC = AF_UNSPEC, /// Unspecified address family 331 UNIX = AF_UNIX, /// Local communication 332 INET = AF_INET, /// Internet Protocol version 4 333 IPX = AF_IPX, /// Novell IPX 334 APPLETALK = AF_APPLETALK, /// AppleTalk 335 INET6 = AF_INET6, /// Internet Protocol version 6 336 } 337 338 339 /** 340 * Communication semantics 341 */ 342 enum SocketType: int 343 { 344 STREAM = SOCK_STREAM, /// Sequenced, reliable, two-way communication-based byte streams 345 DGRAM = SOCK_DGRAM, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order 346 RAW = SOCK_RAW, /// Raw protocol access 347 RDM = SOCK_RDM, /// Reliably-delivered message datagrams 348 SEQPACKET = SOCK_SEQPACKET, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length 349 } 350 351 352 /** 353 * Protocol 354 */ 355 enum ProtocolType: int 356 { 357 IP = IPPROTO_IP, /// Internet Protocol version 4 358 ICMP = IPPROTO_ICMP, /// Internet Control Message Protocol 359 IGMP = IPPROTO_IGMP, /// Internet Group Management Protocol 360 GGP = IPPROTO_GGP, /// Gateway to Gateway Protocol 361 TCP = IPPROTO_TCP, /// Transmission Control Protocol 362 PUP = IPPROTO_PUP, /// PARC Universal Packet Protocol 363 UDP = IPPROTO_UDP, /// User Datagram Protocol 364 IDP = IPPROTO_IDP, /// Xerox NS protocol 365 RAW = IPPROTO_RAW, /// Raw IP packets 366 IPV6 = IPPROTO_IPV6, /// Internet Protocol version 6 367 } 368 369 370 /** 371 * `Protocol` is a class for retrieving protocol information. 372 * 373 * Example: 374 * --- 375 * auto proto = new Protocol; 376 * writeln("About protocol TCP:"); 377 * if (proto.getProtocolByType(ProtocolType.TCP)) 378 * { 379 * writefln(" Name: %s", proto.name); 380 * foreach (string s; proto.aliases) 381 * writefln(" Alias: %s", s); 382 * } 383 * else 384 * writeln(" No information found"); 385 * --- 386 */ 387 class Protocol 388 { 389 /// These members are populated when one of the following functions are called successfully: 390 ProtocolType type; 391 string name; /// ditto 392 string[] aliases; /// ditto 393 394 395 void populate(protoent* proto) @system pure nothrow 396 { 397 type = cast(ProtocolType) proto.p_proto; 398 name = to!string(proto.p_name); 399 400 int i; 401 for (i = 0;; i++) 402 { 403 if (!proto.p_aliases[i]) 404 break; 405 } 406 407 if (i) 408 { 409 aliases = new string[i]; 410 for (i = 0; i != aliases.length; i++) 411 { 412 aliases[i] = 413 to!string(proto.p_aliases[i]); 414 } 415 } 416 else 417 { 418 aliases = null; 419 } 420 } 421 422 /** Returns: false on failure */ 423 bool getProtocolByName(scope const(char)[] name) @trusted nothrow 424 { 425 protoent* proto; 426 proto = getprotobyname(name.tempCString()); 427 if (!proto) 428 return false; 429 populate(proto); 430 return true; 431 } 432 433 434 /** Returns: false on failure */ 435 // Same as getprotobynumber(). 436 bool getProtocolByType(ProtocolType type) @trusted nothrow 437 { 438 protoent* proto; 439 proto = getprotobynumber(type); 440 if (!proto) 441 return false; 442 populate(proto); 443 return true; 444 } 445 } 446 447 448 // Skip this test on Android because getprotobyname/number are 449 // unimplemented in bionic. 450 version (CRuntime_Bionic) {} else 451 @safe unittest 452 { 453 // import std.stdio : writefln; 454 softUnittest({ 455 Protocol proto = new Protocol; 456 assert(proto.getProtocolByType(ProtocolType.TCP)); 457 //writeln("About protocol TCP:"); 458 //writefln("\tName: %s", proto.name); 459 // foreach (string s; proto.aliases) 460 // { 461 // writefln("\tAlias: %s", s); 462 // } 463 assert(proto.name == "tcp"); 464 assert(proto.aliases.length == 1 && proto.aliases[0] == "TCP"); 465 }); 466 } 467 468 469 /** 470 * `Service` is a class for retrieving service information. 471 * 472 * Example: 473 * --- 474 * auto serv = new Service; 475 * writeln("About service epmap:"); 476 * if (serv.getServiceByName("epmap", "tcp")) 477 * { 478 * writefln(" Service: %s", serv.name); 479 * writefln(" Port: %d", serv.port); 480 * writefln(" Protocol: %s", serv.protocolName); 481 * foreach (string s; serv.aliases) 482 * writefln(" Alias: %s", s); 483 * } 484 * else 485 * writefln(" No service for epmap."); 486 * --- 487 */ 488 class Service 489 { 490 /// These members are populated when one of the following functions are called successfully: 491 string name; 492 string[] aliases; /// ditto 493 ushort port; /// ditto 494 string protocolName; /// ditto 495 496 497 void populate(servent* serv) @system pure nothrow 498 { 499 name = to!string(serv.s_name); 500 port = ntohs(cast(ushort) serv.s_port); 501 protocolName = to!string(serv.s_proto); 502 503 int i; 504 for (i = 0;; i++) 505 { 506 if (!serv.s_aliases[i]) 507 break; 508 } 509 510 if (i) 511 { 512 aliases = new string[i]; 513 for (i = 0; i != aliases.length; i++) 514 { 515 aliases[i] = 516 to!string(serv.s_aliases[i]); 517 } 518 } 519 else 520 { 521 aliases = null; 522 } 523 } 524 525 /** 526 * If a protocol name is omitted, any protocol will be matched. 527 * Returns: false on failure. 528 */ 529 bool getServiceByName(scope const(char)[] name, scope const(char)[] protocolName = null) @trusted nothrow 530 { 531 servent* serv; 532 serv = getservbyname(name.tempCString(), protocolName.tempCString()); 533 if (!serv) 534 return false; 535 populate(serv); 536 return true; 537 } 538 539 540 /// ditto 541 bool getServiceByPort(ushort port, scope const(char)[] protocolName = null) @trusted nothrow 542 { 543 servent* serv; 544 serv = getservbyport(port, protocolName.tempCString()); 545 if (!serv) 546 return false; 547 populate(serv); 548 return true; 549 } 550 } 551 552 553 @safe unittest 554 { 555 import std.stdio : writefln; 556 softUnittest({ 557 Service serv = new Service; 558 if (serv.getServiceByName("epmap", "tcp")) 559 { 560 // writefln("About service epmap:"); 561 // writefln("\tService: %s", serv.name); 562 // writefln("\tPort: %d", serv.port); 563 // writefln("\tProtocol: %s", serv.protocolName); 564 // foreach (string s; serv.aliases) 565 // { 566 // writefln("\tAlias: %s", s); 567 // } 568 // For reasons unknown this is loc-srv on Wine and epmap on Windows 569 assert(serv.name == "loc-srv" || serv.name == "epmap", serv.name); 570 assert(serv.port == 135); 571 assert(serv.protocolName == "tcp"); 572 } 573 else 574 { 575 writefln("No service for epmap."); 576 } 577 }); 578 } 579 580 581 private mixin template socketOSExceptionCtors() 582 { 583 /// 584 this(string msg, string file = __FILE__, size_t line = __LINE__, 585 Throwable next = null, int err = _lasterr()) 586 { 587 super(msg, file, line, next, err); 588 } 589 590 /// 591 this(string msg, Throwable next, string file = __FILE__, 592 size_t line = __LINE__, int err = _lasterr()) 593 { 594 super(msg, next, file, line, err); 595 } 596 597 /// 598 this(string msg, int err, string file = __FILE__, size_t line = __LINE__, 599 Throwable next = null) 600 { 601 super(msg, next, file, line, err); 602 } 603 } 604 605 606 /** 607 * Class for exceptions thrown from an `InternetHost`. 608 */ 609 class HostException: SocketOSException 610 { 611 mixin socketOSExceptionCtors; 612 } 613 614 /** 615 * `InternetHost` is a class for resolving IPv4 addresses. 616 * 617 * Consider using `getAddress`, `parseAddress` and `Address` methods 618 * instead of using this class directly. 619 */ 620 class InternetHost 621 { 622 /// These members are populated when one of the following functions are called successfully: 623 string name; 624 string[] aliases; /// ditto 625 uint[] addrList; /// ditto 626 627 628 void validHostent(in hostent* he) 629 { 630 if (he.h_addrtype != cast(int) AddressFamily.INET || he.h_length != 4) 631 throw new HostException("Address family mismatch"); 632 } 633 634 635 void populate(hostent* he) @system pure nothrow 636 { 637 int i; 638 char* p; 639 640 name = to!string(he.h_name); 641 642 for (i = 0;; i++) 643 { 644 p = he.h_aliases[i]; 645 if (!p) 646 break; 647 } 648 649 if (i) 650 { 651 aliases = new string[i]; 652 for (i = 0; i != aliases.length; i++) 653 { 654 aliases[i] = 655 to!string(he.h_aliases[i]); 656 } 657 } 658 else 659 { 660 aliases = null; 661 } 662 663 for (i = 0;; i++) 664 { 665 p = he.h_addr_list[i]; 666 if (!p) 667 break; 668 } 669 670 if (i) 671 { 672 addrList = new uint[i]; 673 for (i = 0; i != addrList.length; i++) 674 { 675 addrList[i] = ntohl(*(cast(uint*) he.h_addr_list[i])); 676 } 677 } 678 else 679 { 680 addrList = null; 681 } 682 } 683 684 private bool getHostNoSync(string opMixin, T)(T param) @system 685 { 686 mixin(opMixin); 687 if (!he) 688 return false; 689 validHostent(he); 690 populate(he); 691 return true; 692 } 693 694 version (Windows) 695 alias getHost = getHostNoSync; 696 else 697 { 698 // posix systems use global state for return value, so we 699 // must synchronize across all threads 700 private bool getHost(string opMixin, T)(T param) @system 701 { 702 synchronized(this.classinfo) 703 return getHostNoSync!(opMixin, T)(param); 704 } 705 } 706 707 /** 708 * Resolve host name. 709 * Returns: false if unable to resolve. 710 */ 711 bool getHostByName(scope const(char)[] name) @trusted 712 { 713 static if (is(typeof(gethostbyname_r))) 714 { 715 return getHostNoSync!q{ 716 hostent he_v; 717 hostent* he; 718 ubyte[256] buffer_v = void; 719 auto buffer = buffer_v[]; 720 auto param_zTmp = param.tempCString(); 721 while (true) 722 { 723 he = &he_v; 724 int errno; 725 if (gethostbyname_r(param_zTmp, he, buffer.ptr, buffer.length, &he, &errno) == ERANGE) 726 buffer.length = buffer.length * 2; 727 else 728 break; 729 } 730 }(name); 731 } 732 else 733 { 734 return getHost!q{ 735 auto he = gethostbyname(param.tempCString()); 736 }(name); 737 } 738 } 739 740 /** 741 * Resolve IPv4 address number. 742 * 743 * Params: 744 * addr = The IPv4 address to resolve, in host byte order. 745 * Returns: 746 * false if unable to resolve. 747 */ 748 bool getHostByAddr(uint addr) @trusted 749 { 750 return getHost!q{ 751 auto x = htonl(param); 752 auto he = gethostbyaddr(&x, 4, cast(int) AddressFamily.INET); 753 }(addr); 754 } 755 756 /** 757 * Same as previous, but addr is an IPv4 address string in the 758 * dotted-decimal form $(I a.b.c.d). 759 * Returns: false if unable to resolve. 760 */ 761 bool getHostByAddr(scope const(char)[] addr) @trusted 762 { 763 return getHost!q{ 764 auto x = inet_addr(param.tempCString()); 765 enforce(x != INADDR_NONE, 766 new SocketParameterException("Invalid IPv4 address")); 767 auto he = gethostbyaddr(&x, 4, cast(int) AddressFamily.INET); 768 }(addr); 769 } 770 } 771 772 /// 773 @safe unittest 774 { 775 InternetHost ih = new InternetHost; 776 777 ih.getHostByAddr(0x7F_00_00_01); 778 assert(ih.addrList[0] == 0x7F_00_00_01); 779 ih.getHostByAddr("127.0.0.1"); 780 assert(ih.addrList[0] == 0x7F_00_00_01); 781 782 if (!ih.getHostByName("www.digitalmars.com")) 783 return; // don't fail if not connected to internet 784 785 assert(ih.addrList.length); 786 InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY); 787 assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com", 788 ih.name); 789 790 assert(ih.getHostByAddr(ih.addrList[0])); 791 string getHostNameFromInt = ih.name.dup; 792 793 assert(ih.getHostByAddr(ia.toAddrString())); 794 string getHostNameFromStr = ih.name.dup; 795 796 assert(getHostNameFromInt == getHostNameFromStr); 797 } 798 799 800 /// Holds information about a socket _address retrieved by `getAddressInfo`. 801 struct AddressInfo 802 { 803 AddressFamily family; /// Address _family 804 SocketType type; /// Socket _type 805 ProtocolType protocol; /// Protocol 806 Address address; /// Socket _address 807 string canonicalName; /// Canonical name, when `AddressInfoFlags.CANONNAME` is used. 808 } 809 810 /** 811 * A subset of flags supported on all platforms with getaddrinfo. 812 * Specifies option flags for `getAddressInfo`. 813 */ 814 enum AddressInfoFlags: int 815 { 816 /// The resulting addresses will be used in a call to `Socket.bind`. 817 PASSIVE = AI_PASSIVE, 818 819 /// The canonical name is returned in `canonicalName` member in the first `AddressInfo`. 820 CANONNAME = AI_CANONNAME, 821 822 /** 823 * The `node` parameter passed to `getAddressInfo` must be a numeric string. 824 * This will suppress any potentially lengthy network host address lookups. 825 */ 826 NUMERICHOST = AI_NUMERICHOST, 827 } 828 829 830 /** 831 * On POSIX, getaddrinfo uses its own error codes, and thus has its own 832 * formatting function. 833 */ 834 private string formatGaiError(int err) @trusted 835 { 836 version (Windows) 837 { 838 return sysErrorString(err); 839 } 840 else 841 { 842 synchronized 843 return to!string(gai_strerror(err)); 844 } 845 } 846 847 /** 848 * Provides _protocol-independent translation from host names to socket 849 * addresses. If advanced functionality is not required, consider using 850 * `getAddress` for compatibility with older systems. 851 * 852 * Returns: Array with one `AddressInfo` per socket address. 853 * 854 * Throws: `SocketOSException` on failure, or `SocketFeatureException` 855 * if this functionality is not available on the current system. 856 * 857 * Params: 858 * node = string containing host name or numeric address 859 * options = optional additional parameters, identified by type: 860 * $(UL $(LI `string` - service name or port number) 861 * $(LI `AddressInfoFlags` - option flags) 862 * $(LI `AddressFamily` - address family to filter by) 863 * $(LI `SocketType` - socket type to filter by) 864 * $(LI `ProtocolType` - protocol to filter by)) 865 * 866 * Example: 867 * --- 868 * // Roundtrip DNS resolution 869 * auto results = getAddressInfo("www.digitalmars.com"); 870 * assert(results[0].address.toHostNameString() == 871 * "digitalmars.com"); 872 * 873 * // Canonical name 874 * results = getAddressInfo("www.digitalmars.com", 875 * AddressInfoFlags.CANONNAME); 876 * assert(results[0].canonicalName == "digitalmars.com"); 877 * 878 * // IPv6 resolution 879 * results = getAddressInfo("ipv6.google.com"); 880 * assert(results[0].family == AddressFamily.INET6); 881 * 882 * // Multihomed resolution 883 * results = getAddressInfo("google.com"); 884 * assert(results.length > 1); 885 * 886 * // Parsing IPv4 887 * results = getAddressInfo("127.0.0.1", 888 * AddressInfoFlags.NUMERICHOST); 889 * assert(results.length && results[0].family == 890 * AddressFamily.INET); 891 * 892 * // Parsing IPv6 893 * results = getAddressInfo("::1", 894 * AddressInfoFlags.NUMERICHOST); 895 * assert(results.length && results[0].family == 896 * AddressFamily.INET6); 897 * --- 898 */ 899 AddressInfo[] getAddressInfo(T...)(scope const(char)[] node, scope T options) 900 { 901 const(char)[] service = null; 902 addrinfo hints; 903 hints.ai_family = AF_UNSPEC; 904 905 foreach (i, option; options) 906 { 907 static if (is(typeof(option) : const(char)[])) 908 service = options[i]; 909 else 910 static if (is(typeof(option) == AddressInfoFlags)) 911 hints.ai_flags |= option; 912 else 913 static if (is(typeof(option) == AddressFamily)) 914 hints.ai_family = option; 915 else 916 static if (is(typeof(option) == SocketType)) 917 hints.ai_socktype = option; 918 else 919 static if (is(typeof(option) == ProtocolType)) 920 hints.ai_protocol = option; 921 else 922 static assert(0, "Unknown getAddressInfo option type: " ~ typeof(option).stringof); 923 } 924 925 return () @trusted { return getAddressInfoImpl(node, service, &hints); }(); 926 } 927 928 @system unittest 929 { 930 struct Oops 931 { 932 const(char[]) breakSafety() 933 { 934 *cast(int*) 0xcafebabe = 0xdeadbeef; 935 return null; 936 } 937 alias breakSafety this; 938 } 939 assert(!__traits(compiles, () { 940 getAddressInfo("", Oops.init); 941 }), "getAddressInfo breaks @safe"); 942 } 943 944 private AddressInfo[] getAddressInfoImpl(scope const(char)[] node, scope const(char)[] service, addrinfo* hints) @system 945 { 946 import std.array : appender; 947 948 if (getaddrinfoPointer && freeaddrinfoPointer) 949 { 950 addrinfo* ai_res; 951 952 int ret = getaddrinfoPointer( 953 node.tempCString(), 954 service.tempCString(), 955 hints, &ai_res); 956 enforce(ret == 0, new SocketOSException("getaddrinfo error", ret, &formatGaiError)); 957 scope(exit) freeaddrinfoPointer(ai_res); 958 959 auto result = appender!(AddressInfo[])(); 960 961 // Use const to force UnknownAddressReference to copy the sockaddr. 962 for (const(addrinfo)* ai = ai_res; ai; ai = ai.ai_next) 963 result ~= AddressInfo( 964 cast(AddressFamily) ai.ai_family, 965 cast(SocketType ) ai.ai_socktype, 966 cast(ProtocolType ) ai.ai_protocol, 967 new UnknownAddressReference(ai.ai_addr, cast(socklen_t) ai.ai_addrlen), 968 ai.ai_canonname ? to!string(ai.ai_canonname) : null); 969 970 assert(result.data.length > 0); 971 return result.data; 972 } 973 974 throw new SocketFeatureException("Address info lookup is not available " ~ 975 "on this system."); 976 } 977 978 979 @safe unittest 980 { 981 softUnittest({ 982 if (getaddrinfoPointer) 983 { 984 // Roundtrip DNS resolution 985 auto results = getAddressInfo("www.digitalmars.com"); 986 assert(results[0].address.toHostNameString() == "digitalmars.com"); 987 988 // Canonical name 989 results = getAddressInfo("www.digitalmars.com", 990 AddressInfoFlags.CANONNAME); 991 assert(results[0].canonicalName == "digitalmars.com"); 992 993 // IPv6 resolution 994 //results = getAddressInfo("ipv6.google.com"); 995 //assert(results[0].family == AddressFamily.INET6); 996 997 // Multihomed resolution 998 //results = getAddressInfo("google.com"); 999 //assert(results.length > 1); 1000 1001 // Parsing IPv4 1002 results = getAddressInfo("127.0.0.1", AddressInfoFlags.NUMERICHOST); 1003 assert(results.length && results[0].family == AddressFamily.INET); 1004 1005 // Parsing IPv6 1006 results = getAddressInfo("::1", AddressInfoFlags.NUMERICHOST); 1007 assert(results.length && results[0].family == AddressFamily.INET6); 1008 } 1009 }); 1010 1011 if (getaddrinfoPointer) 1012 { 1013 auto results = getAddressInfo(null, "1234", AddressInfoFlags.PASSIVE, 1014 SocketType.STREAM, ProtocolType.TCP, AddressFamily.INET); 1015 assert(results.length == 1 && results[0].address.toString() == "0.0.0.0:1234"); 1016 } 1017 } 1018 1019 1020 private ushort serviceToPort(scope const(char)[] service) 1021 { 1022 if (service == "") 1023 return InternetAddress.PORT_ANY; 1024 else 1025 if (isNumeric(service)) 1026 return to!ushort(service); 1027 else 1028 { 1029 auto s = new Service(); 1030 s.getServiceByName(service); 1031 return s.port; 1032 } 1033 } 1034 1035 /** 1036 * Provides _protocol-independent translation from host names to socket 1037 * addresses. Uses `getAddressInfo` if the current system supports it, 1038 * and `InternetHost` otherwise. 1039 * 1040 * Returns: Array with one `Address` instance per socket address. 1041 * 1042 * Throws: `SocketOSException` on failure. 1043 * 1044 * Example: 1045 * --- 1046 * writeln("Resolving www.digitalmars.com:"); 1047 * try 1048 * { 1049 * auto addresses = getAddress("www.digitalmars.com"); 1050 * foreach (address; addresses) 1051 * writefln(" IP: %s", address.toAddrString()); 1052 * } 1053 * catch (SocketException e) 1054 * writefln(" Lookup failed: %s", e.msg); 1055 * --- 1056 */ 1057 Address[] getAddress(scope const(char)[] hostname, scope const(char)[] service = null) 1058 { 1059 if (getaddrinfoPointer && freeaddrinfoPointer) 1060 { 1061 // use getAddressInfo 1062 auto infos = getAddressInfo(hostname, service); 1063 Address[] results; 1064 results.length = infos.length; 1065 foreach (i, ref result; results) 1066 result = infos[i].address; 1067 return results; 1068 } 1069 else 1070 return getAddress(hostname, serviceToPort(service)); 1071 } 1072 1073 /// ditto 1074 Address[] getAddress(scope const(char)[] hostname, ushort port) 1075 { 1076 if (getaddrinfoPointer && freeaddrinfoPointer) 1077 return getAddress(hostname, to!string(port)); 1078 else 1079 { 1080 // use getHostByName 1081 auto ih = new InternetHost; 1082 if (!ih.getHostByName(hostname)) 1083 throw new AddressException( 1084 text("Unable to resolve host '", hostname, "'")); 1085 1086 Address[] results; 1087 foreach (uint addr; ih.addrList) 1088 results ~= new InternetAddress(addr, port); 1089 return results; 1090 } 1091 } 1092 1093 1094 @safe unittest 1095 { 1096 softUnittest({ 1097 auto addresses = getAddress("63.105.9.61"); 1098 assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61"); 1099 1100 if (getaddrinfoPointer) 1101 { 1102 // test via gethostbyname 1103 auto getaddrinfoPointerBackup = getaddrinfoPointer; 1104 cast() getaddrinfoPointer = null; 1105 scope(exit) cast() getaddrinfoPointer = getaddrinfoPointerBackup; 1106 1107 addresses = getAddress("63.105.9.61"); 1108 assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61"); 1109 } 1110 }); 1111 } 1112 1113 1114 /** 1115 * Provides _protocol-independent parsing of network addresses. Does not 1116 * attempt name resolution. Uses `getAddressInfo` with 1117 * `AddressInfoFlags.NUMERICHOST` if the current system supports it, and 1118 * `InternetAddress` otherwise. 1119 * 1120 * Returns: An `Address` instance representing specified address. 1121 * 1122 * Throws: `SocketException` on failure. 1123 * 1124 * Example: 1125 * --- 1126 * writeln("Enter IP address:"); 1127 * string ip = readln().chomp(); 1128 * try 1129 * { 1130 * Address address = parseAddress(ip); 1131 * writefln("Looking up reverse of %s:", 1132 * address.toAddrString()); 1133 * try 1134 * { 1135 * string reverse = address.toHostNameString(); 1136 * if (reverse) 1137 * writefln(" Reverse name: %s", reverse); 1138 * else 1139 * writeln(" Reverse hostname not found."); 1140 * } 1141 * catch (SocketException e) 1142 * writefln(" Lookup error: %s", e.msg); 1143 * } 1144 * catch (SocketException e) 1145 * { 1146 * writefln(" %s is not a valid IP address: %s", 1147 * ip, e.msg); 1148 * } 1149 * --- 1150 */ 1151 Address parseAddress(scope const(char)[] hostaddr, scope const(char)[] service = null) 1152 { 1153 if (getaddrinfoPointer && freeaddrinfoPointer) 1154 return getAddressInfo(hostaddr, service, AddressInfoFlags.NUMERICHOST)[0].address; 1155 else 1156 return parseAddress(hostaddr, serviceToPort(service)); 1157 } 1158 1159 /// ditto 1160 Address parseAddress(scope const(char)[] hostaddr, ushort port) 1161 { 1162 if (getaddrinfoPointer && freeaddrinfoPointer) 1163 return parseAddress(hostaddr, to!string(port)); 1164 else 1165 { 1166 auto in4_addr = InternetAddress.parse(hostaddr); 1167 enforce(in4_addr != InternetAddress.ADDR_NONE, 1168 new SocketParameterException("Invalid IP address")); 1169 return new InternetAddress(in4_addr, port); 1170 } 1171 } 1172 1173 1174 @safe unittest 1175 { 1176 softUnittest({ 1177 auto address = parseAddress("63.105.9.61"); 1178 assert(address.toAddrString() == "63.105.9.61"); 1179 1180 if (getaddrinfoPointer) 1181 { 1182 // test via inet_addr 1183 auto getaddrinfoPointerBackup = getaddrinfoPointer; 1184 cast() getaddrinfoPointer = null; 1185 scope(exit) cast() getaddrinfoPointer = getaddrinfoPointerBackup; 1186 1187 address = parseAddress("63.105.9.61"); 1188 assert(address.toAddrString() == "63.105.9.61"); 1189 } 1190 1191 assert(collectException!SocketException(parseAddress("Invalid IP address"))); 1192 }); 1193 } 1194 1195 1196 /** 1197 * Class for exceptions thrown from an `Address`. 1198 */ 1199 class AddressException: SocketOSException 1200 { 1201 mixin socketOSExceptionCtors; 1202 } 1203 1204 1205 /** 1206 * `Address` is an abstract class for representing a socket addresses. 1207 * 1208 * Example: 1209 * --- 1210 * writeln("About www.google.com port 80:"); 1211 * try 1212 * { 1213 * Address[] addresses = getAddress("www.google.com", 80); 1214 * writefln(" %d addresses found.", addresses.length); 1215 * foreach (int i, Address a; addresses) 1216 * { 1217 * writefln(" Address %d:", i+1); 1218 * writefln(" IP address: %s", a.toAddrString()); 1219 * writefln(" Hostname: %s", a.toHostNameString()); 1220 * writefln(" Port: %s", a.toPortString()); 1221 * writefln(" Service name: %s", 1222 * a.toServiceNameString()); 1223 * } 1224 * } 1225 * catch (SocketException e) 1226 * writefln(" Lookup error: %s", e.msg); 1227 * --- 1228 */ 1229 abstract class Address 1230 { 1231 /// Returns pointer to underlying `sockaddr` structure. 1232 abstract @property sockaddr* name() pure nothrow @nogc; 1233 abstract @property const(sockaddr)* name() const pure nothrow @nogc; /// ditto 1234 1235 /// Returns actual size of underlying `sockaddr` structure. 1236 abstract @property socklen_t nameLen() const pure nothrow @nogc; 1237 1238 // Socket.remoteAddress, Socket.localAddress, and Socket.receiveFrom 1239 // use setNameLen to set the actual size of the address as returned by 1240 // getsockname, getpeername, and recvfrom, respectively. 1241 // The following implementation is sufficient for fixed-length addresses, 1242 // and ensures that the length is not changed. 1243 // Must be overridden for variable-length addresses. 1244 protected void setNameLen(socklen_t len) 1245 { 1246 if (len != this.nameLen) 1247 throw new AddressException( 1248 format("%s expects address of length %d, not %d", typeid(this), 1249 this.nameLen, len), 0); 1250 } 1251 1252 /// Family of this address. 1253 @property AddressFamily addressFamily() const pure nothrow @nogc 1254 { 1255 return cast(AddressFamily) name.sa_family; 1256 } 1257 1258 // Common code for toAddrString and toHostNameString 1259 private string toHostString(bool numeric) @trusted const 1260 { 1261 // getnameinfo() is the recommended way to perform a reverse (name) 1262 // lookup on both Posix and Windows. However, it is only available 1263 // on Windows XP and above, and not included with the WinSock import 1264 // libraries shipped with DMD. Thus, we check for getnameinfo at 1265 // runtime in the shared module constructor, and use it if it's 1266 // available in the base class method. Classes for specific network 1267 // families (e.g. InternetHost) override this method and use a 1268 // deprecated, albeit commonly-available method when getnameinfo() 1269 // is not available. 1270 // http://technet.microsoft.com/en-us/library/aa450403.aspx 1271 if (getnameinfoPointer) 1272 { 1273 auto buf = new char[NI_MAXHOST]; 1274 auto ret = getnameinfoPointer( 1275 name, nameLen, 1276 buf.ptr, cast(uint) buf.length, 1277 null, 0, 1278 numeric ? NI_NUMERICHOST : NI_NAMEREQD); 1279 1280 if (!numeric) 1281 { 1282 if (ret == EAI_NONAME) 1283 return null; 1284 version (Windows) 1285 if (ret == WSANO_DATA) 1286 return null; 1287 } 1288 1289 enforce(ret == 0, new AddressException("Could not get " ~ 1290 (numeric ? "host address" : "host name"))); 1291 return assumeUnique(buf[0 .. strlen(buf.ptr)]); 1292 } 1293 1294 throw new SocketFeatureException((numeric ? "Host address" : "Host name") ~ 1295 " lookup for this address family is not available on this system."); 1296 } 1297 1298 // Common code for toPortString and toServiceNameString 1299 private string toServiceString(bool numeric) @trusted const 1300 { 1301 // See toHostNameString() for details about getnameinfo(). 1302 if (getnameinfoPointer) 1303 { 1304 auto buf = new char[NI_MAXSERV]; 1305 enforce(getnameinfoPointer( 1306 name, nameLen, 1307 null, 0, 1308 buf.ptr, cast(uint) buf.length, 1309 numeric ? NI_NUMERICSERV : NI_NAMEREQD 1310 ) == 0, new AddressException("Could not get " ~ 1311 (numeric ? "port number" : "service name"))); 1312 return assumeUnique(buf[0 .. strlen(buf.ptr)]); 1313 } 1314 1315 throw new SocketFeatureException((numeric ? "Port number" : "Service name") ~ 1316 " lookup for this address family is not available on this system."); 1317 } 1318 1319 /** 1320 * Attempts to retrieve the host address as a human-readable string. 1321 * 1322 * Throws: `AddressException` on failure, or `SocketFeatureException` 1323 * if address retrieval for this address family is not available on the 1324 * current system. 1325 */ 1326 string toAddrString() const 1327 { 1328 return toHostString(true); 1329 } 1330 1331 /** 1332 * Attempts to retrieve the host name as a fully qualified domain name. 1333 * 1334 * Returns: The FQDN corresponding to this `Address`, or `null` if 1335 * the host name did not resolve. 1336 * 1337 * Throws: `AddressException` on error, or `SocketFeatureException` 1338 * if host name lookup for this address family is not available on the 1339 * current system. 1340 */ 1341 string toHostNameString() const 1342 { 1343 return toHostString(false); 1344 } 1345 1346 /** 1347 * Attempts to retrieve the numeric port number as a string. 1348 * 1349 * Throws: `AddressException` on failure, or `SocketFeatureException` 1350 * if port number retrieval for this address family is not available on the 1351 * current system. 1352 */ 1353 string toPortString() const 1354 { 1355 return toServiceString(true); 1356 } 1357 1358 /** 1359 * Attempts to retrieve the service name as a string. 1360 * 1361 * Throws: `AddressException` on failure, or `SocketFeatureException` 1362 * if service name lookup for this address family is not available on the 1363 * current system. 1364 */ 1365 string toServiceNameString() const 1366 { 1367 return toServiceString(false); 1368 } 1369 1370 /// Human readable string representing this address. 1371 override string toString() const 1372 { 1373 try 1374 { 1375 string host = toAddrString(); 1376 string port = toPortString(); 1377 if (host.indexOf(':') >= 0) 1378 return "[" ~ host ~ "]:" ~ port; 1379 else 1380 return host ~ ":" ~ port; 1381 } 1382 catch (SocketException) 1383 return "Unknown"; 1384 } 1385 } 1386 1387 /** 1388 * `UnknownAddress` encapsulates an unknown socket address. 1389 */ 1390 class UnknownAddress: Address 1391 { 1392 protected: 1393 sockaddr sa; 1394 1395 1396 public: 1397 override @property sockaddr* name() 1398 { 1399 return &sa; 1400 } 1401 1402 override @property const(sockaddr)* name() const 1403 { 1404 return &sa; 1405 } 1406 1407 1408 override @property socklen_t nameLen() const 1409 { 1410 return cast(socklen_t) sa.sizeof; 1411 } 1412 1413 } 1414 1415 1416 /** 1417 * `UnknownAddressReference` encapsulates a reference to an arbitrary 1418 * socket address. 1419 */ 1420 class UnknownAddressReference: Address 1421 { 1422 protected: 1423 sockaddr* sa; 1424 socklen_t len; 1425 1426 public: 1427 /// Constructs an `Address` with a reference to the specified `sockaddr`. 1428 this(sockaddr* sa, socklen_t len) pure nothrow @nogc 1429 { 1430 this.sa = sa; 1431 this.len = len; 1432 } 1433 1434 /// Constructs an `Address` with a copy of the specified `sockaddr`. 1435 this(const(sockaddr)* sa, socklen_t len) @system pure nothrow 1436 { 1437 this.sa = cast(sockaddr*) (cast(ubyte*) sa)[0 .. len].dup.ptr; 1438 this.len = len; 1439 } 1440 1441 override @property sockaddr* name() 1442 { 1443 return sa; 1444 } 1445 1446 override @property const(sockaddr)* name() const 1447 { 1448 return sa; 1449 } 1450 1451 1452 override @property socklen_t nameLen() const 1453 { 1454 return cast(socklen_t) len; 1455 } 1456 } 1457 1458 1459 /** 1460 * `InternetAddress` encapsulates an IPv4 (Internet Protocol version 4) 1461 * socket address. 1462 * 1463 * Consider using `getAddress`, `parseAddress` and `Address` methods 1464 * instead of using this class directly. 1465 */ 1466 class InternetAddress: Address 1467 { 1468 protected: 1469 sockaddr_in sin; 1470 1471 1472 this() pure nothrow @nogc 1473 { 1474 } 1475 1476 1477 public: 1478 override @property sockaddr* name() 1479 { 1480 return cast(sockaddr*)&sin; 1481 } 1482 1483 override @property const(sockaddr)* name() const 1484 { 1485 return cast(const(sockaddr)*)&sin; 1486 } 1487 1488 1489 override @property socklen_t nameLen() const 1490 { 1491 return cast(socklen_t) sin.sizeof; 1492 } 1493 1494 1495 enum uint ADDR_ANY = INADDR_ANY; /// Any IPv4 host address. 1496 enum uint ADDR_NONE = INADDR_NONE; /// An invalid IPv4 host address. 1497 enum ushort PORT_ANY = 0; /// Any IPv4 port number. 1498 1499 /// Returns the IPv4 _port number (in host byte order). 1500 @property ushort port() const pure nothrow @nogc 1501 { 1502 return ntohs(sin.sin_port); 1503 } 1504 1505 /// Returns the IPv4 address number (in host byte order). 1506 @property uint addr() const pure nothrow @nogc 1507 { 1508 return ntohl(sin.sin_addr.s_addr); 1509 } 1510 1511 /** 1512 * Construct a new `InternetAddress`. 1513 * Params: 1514 * addr = an IPv4 address string in the dotted-decimal form a.b.c.d, 1515 * or a host name which will be resolved using an `InternetHost` 1516 * object. 1517 * port = port number, may be `PORT_ANY`. 1518 */ 1519 this(scope const(char)[] addr, ushort port) 1520 { 1521 uint uiaddr = parse(addr); 1522 if (ADDR_NONE == uiaddr) 1523 { 1524 InternetHost ih = new InternetHost; 1525 if (!ih.getHostByName(addr)) 1526 //throw new AddressException("Invalid internet address"); 1527 throw new AddressException( 1528 text("Unable to resolve host '", addr, "'")); 1529 uiaddr = ih.addrList[0]; 1530 } 1531 sin.sin_family = AddressFamily.INET; 1532 sin.sin_addr.s_addr = htonl(uiaddr); 1533 sin.sin_port = htons(port); 1534 } 1535 1536 /** 1537 * Construct a new `InternetAddress`. 1538 * Params: 1539 * addr = (optional) an IPv4 address in host byte order, may be `ADDR_ANY`. 1540 * port = port number, may be `PORT_ANY`. 1541 */ 1542 this(uint addr, ushort port) pure nothrow @nogc 1543 { 1544 sin.sin_family = AddressFamily.INET; 1545 sin.sin_addr.s_addr = htonl(addr); 1546 sin.sin_port = htons(port); 1547 } 1548 1549 /// ditto 1550 this(ushort port) pure nothrow @nogc 1551 { 1552 sin.sin_family = AddressFamily.INET; 1553 sin.sin_addr.s_addr = ADDR_ANY; 1554 sin.sin_port = htons(port); 1555 } 1556 1557 /** 1558 * Construct a new `InternetAddress`. 1559 * Params: 1560 * addr = A sockaddr_in as obtained from lower-level API calls such as getifaddrs. 1561 */ 1562 this(sockaddr_in addr) pure nothrow @nogc 1563 { 1564 assert(addr.sin_family == AddressFamily.INET, "Socket address is not of INET family."); 1565 sin = addr; 1566 } 1567 1568 /// Human readable string representing the IPv4 address in dotted-decimal form. 1569 override string toAddrString() @trusted const 1570 { 1571 return to!string(inet_ntoa(sin.sin_addr)); 1572 } 1573 1574 /// Human readable string representing the IPv4 port. 1575 override string toPortString() const 1576 { 1577 return std.conv.to!string(port); 1578 } 1579 1580 /** 1581 * Attempts to retrieve the host name as a fully qualified domain name. 1582 * 1583 * Returns: The FQDN corresponding to this `InternetAddress`, or 1584 * `null` if the host name did not resolve. 1585 * 1586 * Throws: `AddressException` on error. 1587 */ 1588 override string toHostNameString() const 1589 { 1590 // getnameinfo() is the recommended way to perform a reverse (name) 1591 // lookup on both Posix and Windows. However, it is only available 1592 // on Windows XP and above, and not included with the WinSock import 1593 // libraries shipped with DMD. Thus, we check for getnameinfo at 1594 // runtime in the shared module constructor, and fall back to the 1595 // deprecated getHostByAddr() if it could not be found. See also: 1596 // http://technet.microsoft.com/en-us/library/aa450403.aspx 1597 1598 if (getnameinfoPointer) 1599 return super.toHostNameString(); 1600 else 1601 { 1602 auto host = new InternetHost(); 1603 if (!host.getHostByAddr(ntohl(sin.sin_addr.s_addr))) 1604 return null; 1605 return host.name; 1606 } 1607 } 1608 1609 /** 1610 * Compares with another InternetAddress of same type for equality 1611 * Returns: true if the InternetAddresses share the same address and 1612 * port number. 1613 */ 1614 override bool opEquals(Object o) const 1615 { 1616 auto other = cast(InternetAddress) o; 1617 return other && this.sin.sin_addr.s_addr == other.sin.sin_addr.s_addr && 1618 this.sin.sin_port == other.sin.sin_port; 1619 } 1620 1621 /// 1622 @system unittest 1623 { 1624 auto addr1 = new InternetAddress("127.0.0.1", 80); 1625 auto addr2 = new InternetAddress("127.0.0.2", 80); 1626 1627 assert(addr1 == addr1); 1628 assert(addr1 != addr2); 1629 } 1630 1631 /** 1632 * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d) 1633 * and return the number. 1634 * Returns: If the string is not a legitimate IPv4 address, 1635 * `ADDR_NONE` is returned. 1636 */ 1637 static uint parse(scope const(char)[] addr) @trusted nothrow 1638 { 1639 return ntohl(inet_addr(addr.tempCString())); 1640 } 1641 1642 /** 1643 * Convert an IPv4 address number in host byte order to a human readable 1644 * string representing the IPv4 address in dotted-decimal form. 1645 */ 1646 static string addrToString(uint addr) @trusted nothrow 1647 { 1648 in_addr sin_addr; 1649 sin_addr.s_addr = htonl(addr); 1650 return to!string(inet_ntoa(sin_addr)); 1651 } 1652 } 1653 1654 1655 @safe unittest 1656 { 1657 softUnittest({ 1658 const InternetAddress ia = new InternetAddress("63.105.9.61", 80); 1659 assert(ia.toString() == "63.105.9.61:80"); 1660 }); 1661 1662 softUnittest({ 1663 // test construction from a sockaddr_in 1664 sockaddr_in sin; 1665 1666 sin.sin_addr.s_addr = htonl(0x7F_00_00_01); // 127.0.0.1 1667 sin.sin_family = AddressFamily.INET; 1668 sin.sin_port = htons(80); 1669 1670 const InternetAddress ia = new InternetAddress(sin); 1671 assert(ia.toString() == "127.0.0.1:80"); 1672 }); 1673 1674 softUnittest({ 1675 // test reverse lookup 1676 auto ih = new InternetHost; 1677 if (ih.getHostByName("digitalmars.com")) 1678 { 1679 const ia = new InternetAddress(ih.addrList[0], 80); 1680 assert(ia.toHostNameString() == "digitalmars.com"); 1681 1682 if (getnameinfoPointer) 1683 { 1684 // test reverse lookup, via gethostbyaddr 1685 auto getnameinfoPointerBackup = getnameinfoPointer; 1686 cast() getnameinfoPointer = null; 1687 scope(exit) cast() getnameinfoPointer = getnameinfoPointerBackup; 1688 1689 assert(ia.toHostNameString() == "digitalmars.com"); 1690 } 1691 } 1692 }); 1693 1694 debug (std_socket) 1695 softUnittest({ 1696 // test failing reverse lookup 1697 const InternetAddress ia = new InternetAddress("255.255.255.255", 80); 1698 assert(ia.toHostNameString() is null); 1699 1700 if (getnameinfoPointer) 1701 { 1702 // test failing reverse lookup, via gethostbyaddr 1703 auto getnameinfoPointerBackup = getnameinfoPointer; 1704 cast() getnameinfoPointer = null; 1705 scope(exit) cast() getnameinfoPointer = getnameinfoPointerBackup; 1706 1707 assert(ia.toHostNameString() is null); 1708 } 1709 }); 1710 } 1711 1712 1713 /** 1714 * `Internet6Address` encapsulates an IPv6 (Internet Protocol version 6) 1715 * socket address. 1716 * 1717 * Consider using `getAddress`, `parseAddress` and `Address` methods 1718 * instead of using this class directly. 1719 */ 1720 class Internet6Address: Address 1721 { 1722 protected: 1723 sockaddr_in6 sin6; 1724 1725 1726 this() pure nothrow @nogc 1727 { 1728 } 1729 1730 1731 public: 1732 override @property sockaddr* name() 1733 { 1734 return cast(sockaddr*)&sin6; 1735 } 1736 1737 override @property const(sockaddr)* name() const 1738 { 1739 return cast(const(sockaddr)*)&sin6; 1740 } 1741 1742 1743 override @property socklen_t nameLen() const 1744 { 1745 return cast(socklen_t) sin6.sizeof; 1746 } 1747 1748 1749 /// Any IPv6 host address. 1750 static @property ref const(ubyte)[16] ADDR_ANY() pure nothrow @nogc 1751 { 1752 static if (is(typeof(IN6ADDR_ANY))) 1753 { 1754 version (Windows) 1755 { 1756 static immutable addr = IN6ADDR_ANY.s6_addr; 1757 return addr; 1758 } 1759 else 1760 return IN6ADDR_ANY.s6_addr; 1761 } 1762 else static if (is(typeof(in6addr_any))) 1763 { 1764 return in6addr_any.s6_addr; 1765 } 1766 else 1767 static assert(0); 1768 } 1769 1770 /// Any IPv6 port number. 1771 enum ushort PORT_ANY = 0; 1772 1773 /// Returns the IPv6 port number. 1774 @property ushort port() const pure nothrow @nogc 1775 { 1776 return ntohs(sin6.sin6_port); 1777 } 1778 1779 /// Returns the IPv6 address. 1780 @property ubyte[16] addr() const pure nothrow @nogc 1781 { 1782 return sin6.sin6_addr.s6_addr; 1783 } 1784 1785 /** 1786 * Construct a new `Internet6Address`. 1787 * Params: 1788 * addr = an IPv6 host address string in the form described in RFC 2373, 1789 * or a host name which will be resolved using `getAddressInfo`. 1790 * service = (optional) service name. 1791 */ 1792 this(scope const(char)[] addr, scope const(char)[] service = null) @trusted 1793 { 1794 auto results = getAddressInfo(addr, service, AddressFamily.INET6); 1795 assert(results.length && results[0].family == AddressFamily.INET6); 1796 sin6 = *cast(sockaddr_in6*) results[0].address.name; 1797 } 1798 1799 /** 1800 * Construct a new `Internet6Address`. 1801 * Params: 1802 * addr = an IPv6 host address string in the form described in RFC 2373, 1803 * or a host name which will be resolved using `getAddressInfo`. 1804 * port = port number, may be `PORT_ANY`. 1805 */ 1806 this(scope const(char)[] addr, ushort port) 1807 { 1808 if (port == PORT_ANY) 1809 this(addr); 1810 else 1811 this(addr, to!string(port)); 1812 } 1813 1814 /** 1815 * Construct a new `Internet6Address`. 1816 * Params: 1817 * addr = (optional) an IPv6 host address in host byte order, or 1818 * `ADDR_ANY`. 1819 * port = port number, may be `PORT_ANY`. 1820 */ 1821 this(ubyte[16] addr, ushort port) pure nothrow @nogc 1822 { 1823 sin6.sin6_family = AddressFamily.INET6; 1824 sin6.sin6_addr.s6_addr = addr; 1825 sin6.sin6_port = htons(port); 1826 } 1827 1828 /// ditto 1829 this(ushort port) pure nothrow @nogc 1830 { 1831 sin6.sin6_family = AddressFamily.INET6; 1832 sin6.sin6_addr.s6_addr = ADDR_ANY; 1833 sin6.sin6_port = htons(port); 1834 } 1835 1836 /** 1837 * Construct a new `Internet6Address`. 1838 * Params: 1839 * addr = A sockaddr_in6 as obtained from lower-level API calls such as getifaddrs. 1840 */ 1841 this(sockaddr_in6 addr) pure nothrow @nogc 1842 { 1843 assert(addr.sin6_family == AddressFamily.INET6); 1844 sin6 = addr; 1845 } 1846 1847 /** 1848 * Parse an IPv6 host address string as described in RFC 2373, and return the 1849 * address. 1850 * Throws: `SocketException` on error. 1851 */ 1852 static ubyte[16] parse(scope const(char)[] addr) @trusted 1853 { 1854 // Although we could use inet_pton here, it's only available on Windows 1855 // versions starting with Vista, so use getAddressInfo with NUMERICHOST 1856 // instead. 1857 auto results = getAddressInfo(addr, AddressInfoFlags.NUMERICHOST); 1858 if (results.length && results[0].family == AddressFamily.INET6) 1859 return (cast(sockaddr_in6*) results[0].address.name).sin6_addr.s6_addr; 1860 throw new AddressException("Not an IPv6 address", 0); 1861 } 1862 } 1863 1864 1865 @safe unittest 1866 { 1867 softUnittest({ 1868 const Internet6Address ia = new Internet6Address("::1", 80); 1869 assert(ia.toString() == "[::1]:80"); 1870 }); 1871 1872 softUnittest({ 1873 // test construction from a sockaddr_in6 1874 sockaddr_in6 sin; 1875 1876 sin.sin6_addr.s6_addr = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // [::1] 1877 sin.sin6_family = AddressFamily.INET6; 1878 sin.sin6_port = htons(80); 1879 1880 const Internet6Address ia = new Internet6Address(sin); 1881 assert(ia.toString() == "[::1]:80"); 1882 }); 1883 } 1884 1885 1886 version (StdDdoc) 1887 { 1888 static if (!is(sockaddr_un)) 1889 { 1890 // This exists only to allow the constructor taking 1891 // a sockaddr_un to be compilable for documentation 1892 // on platforms that don't supply a sockaddr_un. 1893 struct sockaddr_un 1894 { 1895 } 1896 } 1897 1898 /** 1899 * `UnixAddress` encapsulates an address for a Unix domain socket 1900 * (`AF_UNIX`), i.e. a socket bound to a path name in the file system. 1901 * Available only on supported systems. 1902 * 1903 * Linux also supports an abstract address namespace, in which addresses 1904 * are independent of the file system. A socket address is abstract 1905 * iff `path` starts with a _null byte (`'\0'`). Null bytes in other 1906 * positions of an abstract address are allowed and have no special 1907 * meaning. 1908 * 1909 * Example: 1910 * --- 1911 * auto addr = new UnixAddress("/var/run/dbus/system_bus_socket"); 1912 * auto abstractAddr = new UnixAddress("\0/tmp/dbus-OtHLWmCLPR"); 1913 * --- 1914 * 1915 * See_Also: $(HTTP http://man7.org/linux/man-pages/man7/unix.7.html, UNIX(7)) 1916 */ 1917 class UnixAddress: Address 1918 { 1919 private this() pure nothrow @nogc {} 1920 1921 /// Construct a new `UnixAddress` from the specified path. 1922 this(scope const(char)[] path) { } 1923 1924 /** 1925 * Construct a new `UnixAddress`. 1926 * Params: 1927 * addr = A sockaddr_un as obtained from lower-level API calls. 1928 */ 1929 this(sockaddr_un addr) pure nothrow @nogc { } 1930 1931 /// Get the underlying _path. 1932 @property string path() const { return null; } 1933 1934 /// ditto 1935 override string toString() const { return null; } 1936 1937 override @property sockaddr* name() { return null; } 1938 override @property const(sockaddr)* name() const { return null; } 1939 override @property socklen_t nameLen() const { return 0; } 1940 } 1941 } 1942 else 1943 static if (is(sockaddr_un)) 1944 { 1945 class UnixAddress: Address 1946 { 1947 protected: 1948 socklen_t _nameLen; 1949 1950 struct 1951 { 1952 align (1): 1953 sockaddr_un sun; 1954 char unused = '\0'; // placeholder for a terminating '\0' 1955 } 1956 1957 this() pure nothrow @nogc 1958 { 1959 sun.sun_family = AddressFamily.UNIX; 1960 sun.sun_path = '?'; 1961 _nameLen = sun.sizeof; 1962 } 1963 1964 override void setNameLen(socklen_t len) @trusted 1965 { 1966 if (len > sun.sizeof) 1967 throw new SocketParameterException("Not enough socket address storage"); 1968 _nameLen = len; 1969 } 1970 1971 public: 1972 override @property sockaddr* name() 1973 { 1974 return cast(sockaddr*)&sun; 1975 } 1976 1977 override @property const(sockaddr)* name() const 1978 { 1979 return cast(const(sockaddr)*)&sun; 1980 } 1981 1982 override @property socklen_t nameLen() @trusted const 1983 { 1984 return _nameLen; 1985 } 1986 1987 this(scope const(char)[] path) @trusted pure 1988 { 1989 enforce(path.length <= sun.sun_path.sizeof, new SocketParameterException("Path too long")); 1990 sun.sun_family = AddressFamily.UNIX; 1991 sun.sun_path.ptr[0 .. path.length] = (cast(byte[]) path)[]; 1992 _nameLen = cast(socklen_t) 1993 { 1994 auto len = sockaddr_un.init.sun_path.offsetof + path.length; 1995 // Pathname socket address must be terminated with '\0' 1996 // which must be included in the address length. 1997 if (sun.sun_path.ptr[0]) 1998 { 1999 sun.sun_path.ptr[path.length] = 0; 2000 ++len; 2001 } 2002 return len; 2003 }(); 2004 } 2005 2006 this(sockaddr_un addr) pure nothrow @nogc 2007 { 2008 assert(addr.sun_family == AddressFamily.UNIX); 2009 sun = addr; 2010 } 2011 2012 @property string path() @trusted const pure 2013 { 2014 auto len = _nameLen - sockaddr_un.init.sun_path.offsetof; 2015 if (len == 0) 2016 return null; // An empty path may be returned from getpeername 2017 // For pathname socket address we need to strip off the terminating '\0' 2018 if (sun.sun_path.ptr[0]) 2019 --len; 2020 return (cast(const(char)*) sun.sun_path.ptr)[0 .. len].idup; 2021 } 2022 2023 override string toString() const pure 2024 { 2025 return path; 2026 } 2027 } 2028 2029 @safe unittest 2030 { 2031 import core.stdc.stdio : remove; 2032 2033 version (iOSDerived) 2034 { 2035 // Slightly different version of `std.file.deleteme` to reduce the path 2036 // length on iOS derived platforms. Due to the sandbox, the length 2037 // of paths can quickly become too long. 2038 static string deleteme() 2039 { 2040 import std.conv : text; 2041 import std.process : thisProcessID; 2042 import std.file : tempDir; 2043 2044 return text(tempDir, thisProcessID); 2045 } 2046 } 2047 2048 else 2049 import std.file : deleteme; 2050 2051 immutable ubyte[] data = [1, 2, 3, 4]; 2052 Socket[2] pair; 2053 2054 const basePath = deleteme; 2055 auto names = [ basePath ~ "-socket" ]; 2056 version (linux) 2057 names ~= "\0" ~ basePath ~ "-abstract\0unix\0socket"; 2058 2059 foreach (name; names) 2060 { 2061 auto address = new UnixAddress(name); 2062 2063 auto listener = new Socket(AddressFamily.UNIX, SocketType.STREAM); 2064 scope(exit) listener.close(); 2065 listener.bind(address); 2066 scope(exit) () @trusted { if (name[0]) remove(name.tempCString()); } (); 2067 assert(listener.localAddress.toString == name); 2068 2069 listener.listen(1); 2070 2071 pair[0] = new Socket(AddressFamily.UNIX, SocketType.STREAM); 2072 scope(exit) listener.close(); 2073 2074 pair[0].connect(address); 2075 scope(exit) pair[0].close(); 2076 2077 pair[1] = listener.accept(); 2078 scope(exit) pair[1].close(); 2079 2080 pair[0].send(data); 2081 2082 auto buf = new ubyte[data.length]; 2083 pair[1].receive(buf); 2084 assert(buf == data); 2085 2086 // getpeername is free to return an empty name for a unix 2087 // domain socket pair or unbound socket. Let's confirm it 2088 // returns successfully and doesn't throw anything. 2089 // See https://issues.dlang.org/show_bug.cgi?id=20544 2090 assertNotThrown(pair[1].remoteAddress().toString()); 2091 } 2092 } 2093 } 2094 2095 2096 /** 2097 * Class for exceptions thrown by `Socket.accept`. 2098 */ 2099 class SocketAcceptException: SocketOSException 2100 { 2101 mixin socketOSExceptionCtors; 2102 } 2103 2104 /// How a socket is shutdown: 2105 enum SocketShutdown: int 2106 { 2107 RECEIVE = SD_RECEIVE, /// socket receives are disallowed 2108 SEND = SD_SEND, /// socket sends are disallowed 2109 BOTH = SD_BOTH, /// both RECEIVE and SEND 2110 } 2111 2112 2113 /// Flags may be OR'ed together: 2114 enum SocketFlags: int 2115 { 2116 NONE = 0, /// no flags specified 2117 2118 OOB = MSG_OOB, /// out-of-band stream data 2119 PEEK = MSG_PEEK, /// peek at incoming data without removing it from the queue, only for receiving 2120 DONTROUTE = MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending 2121 } 2122 2123 2124 private mixin template FieldProxy(string target, string field) 2125 { 2126 mixin(` 2127 @property typeof(`~target~`) `~field~`() const pure nothrow @nogc 2128 { 2129 return `~target~`; 2130 } 2131 2132 /// ditto 2133 @property typeof(`~target~`) `~field~`(typeof(`~target~`) value) pure nothrow @nogc 2134 { 2135 return `~target~` = value; 2136 } 2137 `); 2138 } 2139 2140 2141 /// Duration timeout value. 2142 struct TimeVal 2143 { 2144 _ctimeval ctimeval; 2145 alias tv_sec_t = typeof(ctimeval.tv_sec); 2146 alias tv_usec_t = typeof(ctimeval.tv_usec); 2147 2148 version (StdDdoc) // no DDoc for string mixins, can't forward individual fields 2149 { 2150 tv_sec_t seconds; /// Number of _seconds. 2151 tv_usec_t microseconds; /// Number of additional _microseconds. 2152 } 2153 else 2154 { 2155 // D interface 2156 mixin FieldProxy!(`ctimeval.tv_sec`, `seconds`); 2157 mixin FieldProxy!(`ctimeval.tv_usec`, `microseconds`); 2158 } 2159 } 2160 2161 2162 /** 2163 * A collection of sockets for use with `Socket.select`. 2164 * 2165 * `SocketSet` wraps the platform `fd_set` type. However, unlike 2166 * `fd_set`, `SocketSet` is not statically limited to `FD_SETSIZE` 2167 * or any other limit, and grows as needed. 2168 */ 2169 class SocketSet 2170 { 2171 private: 2172 version (Windows) 2173 { 2174 // On Windows, fd_set is an array of socket handles, 2175 // following a word containing the fd_set instance size. 2176 // We use one dynamic array for everything, and use its first 2177 // element(s) for the count. 2178 2179 alias fd_set_count_type = typeof(fd_set.init.fd_count); 2180 alias fd_set_type = typeof(fd_set.init.fd_array[0]); 2181 static assert(fd_set_type.sizeof == socket_t.sizeof); 2182 2183 // Number of fd_set_type elements at the start of our array that are 2184 // used for the socket count and alignment 2185 2186 enum FD_SET_OFFSET = fd_set.fd_array.offsetof / fd_set_type.sizeof; 2187 static assert(FD_SET_OFFSET); 2188 static assert(fd_set.fd_count.offsetof % fd_set_type.sizeof == 0); 2189 2190 fd_set_type[] set; 2191 2192 void resize(size_t size) pure nothrow 2193 { 2194 set.length = FD_SET_OFFSET + size; 2195 } 2196 2197 ref inout(fd_set_count_type) count() @trusted @property inout pure nothrow @nogc 2198 { 2199 assert(set.length); 2200 return *cast(inout(fd_set_count_type)*)set.ptr; 2201 } 2202 2203 size_t capacity() @property const pure nothrow @nogc 2204 { 2205 return set.length - FD_SET_OFFSET; 2206 } 2207 2208 inout(socket_t)[] fds() @trusted inout @property pure nothrow @nogc 2209 { 2210 return cast(inout(socket_t)[])set[FD_SET_OFFSET .. FD_SET_OFFSET+count]; 2211 } 2212 } 2213 else 2214 version (Posix) 2215 { 2216 // On Posix, fd_set is a bit array. We assume that the fd_set 2217 // type (declared in core.sys.posix.sys.select) is a structure 2218 // containing a single field, a static array. 2219 2220 static assert(fd_set.tupleof.length == 1); 2221 2222 // This is the type used in the fd_set array. 2223 // Using the type of the correct size is important for big-endian 2224 // architectures. 2225 2226 alias fd_set_type = typeof(fd_set.init.tupleof[0][0]); 2227 2228 // Number of file descriptors represented by one fd_set_type 2229 2230 enum FD_NFDBITS = 8 * fd_set_type.sizeof; 2231 2232 static fd_set_type mask(uint n) pure nothrow @nogc 2233 { 2234 return (cast(fd_set_type) 1) << (n % FD_NFDBITS); 2235 } 2236 2237 // Array size to fit that many sockets 2238 2239 static size_t lengthFor(size_t size) pure nothrow @nogc 2240 { 2241 return (size + (FD_NFDBITS-1)) / FD_NFDBITS; 2242 } 2243 2244 fd_set_type[] set; 2245 2246 void resize(size_t size) pure nothrow 2247 { 2248 set.length = lengthFor(size); 2249 } 2250 2251 // Make sure we can fit that many sockets 2252 2253 void setMinCapacity(size_t size) pure nothrow 2254 { 2255 auto length = lengthFor(size); 2256 if (set.length < length) 2257 set.length = length; 2258 } 2259 2260 size_t capacity() @property const pure nothrow @nogc 2261 { 2262 return set.length * FD_NFDBITS; 2263 } 2264 2265 int maxfd; 2266 } 2267 else 2268 static assert(false, "Unknown platform"); 2269 2270 public: 2271 2272 /** 2273 * Create a SocketSet with a specific initial capacity (defaults to 2274 * `FD_SETSIZE`, the system's default capacity). 2275 */ 2276 this(size_t size = FD_SETSIZE) pure nothrow 2277 { 2278 resize(size); 2279 reset(); 2280 } 2281 2282 /// Reset the `SocketSet` so that there are 0 `Socket`s in the collection. 2283 void reset() pure nothrow @nogc 2284 { 2285 version (Windows) 2286 count = 0; 2287 else 2288 { 2289 set[] = 0; 2290 maxfd = -1; 2291 } 2292 } 2293 2294 2295 void add(socket_t s) @trusted pure nothrow 2296 { 2297 version (Windows) 2298 { 2299 if (count == capacity) 2300 { 2301 set.length *= 2; 2302 set.length = set.capacity; 2303 } 2304 ++count; 2305 fds[$-1] = s; 2306 } 2307 else 2308 { 2309 auto index = s / FD_NFDBITS; 2310 auto length = set.length; 2311 if (index >= length) 2312 { 2313 while (index >= length) 2314 length *= 2; 2315 set.length = length; 2316 set.length = set.capacity; 2317 } 2318 set[index] |= mask(s); 2319 if (maxfd < s) 2320 maxfd = s; 2321 } 2322 } 2323 2324 /** 2325 * Add a `Socket` to the collection. 2326 * The socket must not already be in the collection. 2327 */ 2328 void add(Socket s) pure nothrow 2329 { 2330 add(s.sock); 2331 } 2332 2333 void remove(socket_t s) pure nothrow 2334 { 2335 version (Windows) 2336 { 2337 import std.algorithm.searching : countUntil; 2338 auto fds = fds; 2339 auto p = fds.countUntil(s); 2340 if (p >= 0) 2341 fds[p] = fds[--count]; 2342 } 2343 else 2344 { 2345 auto index = s / FD_NFDBITS; 2346 if (index >= set.length) 2347 return; 2348 set[index] &= ~mask(s); 2349 // note: adjusting maxfd would require scanning the set, not worth it 2350 } 2351 } 2352 2353 2354 /** 2355 * Remove this `Socket` from the collection. 2356 * Does nothing if the socket is not in the collection already. 2357 */ 2358 void remove(Socket s) pure nothrow 2359 { 2360 remove(s.sock); 2361 } 2362 2363 int isSet(socket_t s) const pure nothrow @nogc 2364 { 2365 version (Windows) 2366 { 2367 import std.algorithm.searching : canFind; 2368 return fds.canFind(s) ? 1 : 0; 2369 } 2370 else 2371 { 2372 if (s > maxfd) 2373 return 0; 2374 auto index = s / FD_NFDBITS; 2375 return (set[index] & mask(s)) ? 1 : 0; 2376 } 2377 } 2378 2379 2380 /// Return nonzero if this `Socket` is in the collection. 2381 int isSet(Socket s) const pure nothrow @nogc 2382 { 2383 return isSet(s.sock); 2384 } 2385 2386 2387 /** 2388 * Returns: 2389 * The current capacity of this `SocketSet`. The exact 2390 * meaning of the return value varies from platform to platform. 2391 * 2392 * Note: 2393 * Since D 2.065, this value does not indicate a 2394 * restriction, and `SocketSet` will grow its capacity as 2395 * needed automatically. 2396 */ 2397 @property uint max() const pure nothrow @nogc 2398 { 2399 return cast(uint) capacity; 2400 } 2401 2402 2403 fd_set* toFd_set() @trusted pure nothrow @nogc 2404 { 2405 return cast(fd_set*) set.ptr; 2406 } 2407 2408 2409 int selectn() const pure nothrow @nogc 2410 { 2411 version (Windows) 2412 { 2413 return count; 2414 } 2415 else version (Posix) 2416 { 2417 return maxfd + 1; 2418 } 2419 } 2420 } 2421 2422 @safe unittest 2423 { 2424 auto fds = cast(socket_t[]) 2425 [cast(socket_t) 1, 2, 0, 1024, 17, 42, 1234, 77, 77+32, 77+64]; 2426 auto set = new SocketSet(); 2427 foreach (fd; fds) assert(!set.isSet(fd)); 2428 foreach (fd; fds) set.add(fd); 2429 foreach (fd; fds) assert(set.isSet(fd)); 2430 2431 // Make sure SocketSet reimplements fd_set correctly 2432 auto fdset = set.toFd_set(); 2433 foreach (fd; fds[0]..cast(socket_t)(fds[$-1]+1)) 2434 assert(cast(bool) set.isSet(fd) == cast(bool)(() @trusted => FD_ISSET(fd, fdset))()); 2435 2436 foreach (fd; fds) 2437 { 2438 assert(set.isSet(fd)); 2439 set.remove(fd); 2440 assert(!set.isSet(fd)); 2441 } 2442 } 2443 2444 @safe unittest 2445 { 2446 version (iOSDerived) 2447 { 2448 enum PAIRS = 256; 2449 enum LIMIT = 1024; 2450 } 2451 else 2452 { 2453 enum PAIRS = 768; 2454 enum LIMIT = 2048; 2455 } 2456 2457 softUnittest({ 2458 version (Posix) 2459 () @trusted 2460 { 2461 static assert(LIMIT > PAIRS*2); 2462 import core.sys.posix.sys.resource; 2463 rlimit fileLimit; 2464 getrlimit(RLIMIT_NOFILE, &fileLimit); 2465 assert(fileLimit.rlim_max > LIMIT, "Open file hard limit too low"); 2466 fileLimit.rlim_cur = LIMIT; 2467 setrlimit(RLIMIT_NOFILE, &fileLimit); 2468 } (); 2469 2470 Socket[2][PAIRS] pairs; 2471 foreach (ref pair; pairs) 2472 pair = socketPair(); 2473 scope(exit) 2474 { 2475 foreach (pair; pairs) 2476 { 2477 pair[0].close(); 2478 pair[1].close(); 2479 } 2480 } 2481 2482 import std.random; 2483 auto rng = Xorshift(42); 2484 pairs[].randomShuffle(rng); 2485 2486 auto readSet = new SocketSet(); 2487 auto writeSet = new SocketSet(); 2488 auto errorSet = new SocketSet(); 2489 2490 foreach (testPair; pairs) 2491 { 2492 void fillSets() 2493 { 2494 readSet.reset(); 2495 writeSet.reset(); 2496 errorSet.reset(); 2497 foreach (ref pair; pairs) 2498 foreach (s; pair[]) 2499 { 2500 readSet.add(s); 2501 writeSet.add(s); 2502 errorSet.add(s); 2503 } 2504 } 2505 2506 fillSets(); 2507 auto n = Socket.select(readSet, writeSet, errorSet); 2508 assert(n == PAIRS*2); // All in writeSet 2509 assert(writeSet.isSet(testPair[0])); 2510 assert(writeSet.isSet(testPair[1])); 2511 assert(!readSet.isSet(testPair[0])); 2512 assert(!readSet.isSet(testPair[1])); 2513 assert(!errorSet.isSet(testPair[0])); 2514 assert(!errorSet.isSet(testPair[1])); 2515 2516 ubyte[1] b; 2517 // Socket.send can't be marked with `scope` 2518 // -> @safe DIP1000 code can't use it - see https://github.com/dlang/phobos/pull/6204 2519 () @trusted { 2520 testPair[0].send(b[]); 2521 }(); 2522 fillSets(); 2523 n = Socket.select(readSet, null, null); 2524 assert(n == 1); // testPair[1] 2525 assert(readSet.isSet(testPair[1])); 2526 assert(!readSet.isSet(testPair[0])); 2527 // Socket.receive can't be marked with `scope` 2528 // -> @safe DIP1000 code can't use it - see https://github.com/dlang/phobos/pull/6204 2529 () @trusted { 2530 testPair[1].receive(b[]); 2531 }(); 2532 } 2533 }); 2534 } 2535 2536 // https://issues.dlang.org/show_bug.cgi?id=14012 2537 // https://issues.dlang.org/show_bug.cgi?id=14013 2538 @safe unittest 2539 { 2540 auto set = new SocketSet(1); 2541 assert(set.max >= 0); 2542 2543 enum LIMIT = 4096; 2544 foreach (n; 0 .. LIMIT) 2545 set.add(cast(socket_t) n); 2546 assert(set.max >= LIMIT); 2547 } 2548 2549 /// The level at which a socket option is defined: 2550 enum SocketOptionLevel: int 2551 { 2552 SOCKET = SOL_SOCKET, /// Socket level 2553 IP = ProtocolType.IP, /// Internet Protocol version 4 level 2554 ICMP = ProtocolType.ICMP, /// Internet Control Message Protocol level 2555 IGMP = ProtocolType.IGMP, /// Internet Group Management Protocol level 2556 GGP = ProtocolType.GGP, /// Gateway to Gateway Protocol level 2557 TCP = ProtocolType.TCP, /// Transmission Control Protocol level 2558 PUP = ProtocolType.PUP, /// PARC Universal Packet Protocol level 2559 UDP = ProtocolType.UDP, /// User Datagram Protocol level 2560 IDP = ProtocolType.IDP, /// Xerox NS protocol level 2561 RAW = ProtocolType.RAW, /// Raw IP packet level 2562 IPV6 = ProtocolType.IPV6, /// Internet Protocol version 6 level 2563 } 2564 2565 /// _Linger information for use with SocketOption.LINGER. 2566 struct Linger 2567 { 2568 _clinger clinger; 2569 2570 version (StdDdoc) // no DDoc for string mixins, can't forward individual fields 2571 { 2572 private alias l_onoff_t = typeof(_clinger.init.l_onoff ); 2573 private alias l_linger_t = typeof(_clinger.init.l_linger); 2574 l_onoff_t on; /// Nonzero for _on. 2575 l_linger_t time; /// Linger _time. 2576 } 2577 else 2578 { 2579 // D interface 2580 mixin FieldProxy!(`clinger.l_onoff`, `on`); 2581 mixin FieldProxy!(`clinger.l_linger`, `time`); 2582 } 2583 } 2584 2585 /// Specifies a socket option: 2586 enum SocketOption: int 2587 { 2588 DEBUG = SO_DEBUG, /// Record debugging information 2589 BROADCAST = SO_BROADCAST, /// Allow transmission of broadcast messages 2590 REUSEADDR = SO_REUSEADDR, /// Allow local reuse of address 2591 LINGER = SO_LINGER, /// Linger on close if unsent data is present 2592 OOBINLINE = SO_OOBINLINE, /// Receive out-of-band data in band 2593 SNDBUF = SO_SNDBUF, /// Send buffer size 2594 RCVBUF = SO_RCVBUF, /// Receive buffer size 2595 DONTROUTE = SO_DONTROUTE, /// Do not route 2596 SNDTIMEO = SO_SNDTIMEO, /// Send timeout 2597 RCVTIMEO = SO_RCVTIMEO, /// Receive timeout 2598 ERROR = SO_ERROR, /// Retrieve and clear error status 2599 KEEPALIVE = SO_KEEPALIVE, /// Enable keep-alive packets 2600 ACCEPTCONN = SO_ACCEPTCONN, /// Listen 2601 RCVLOWAT = SO_RCVLOWAT, /// Minimum number of input bytes to process 2602 SNDLOWAT = SO_SNDLOWAT, /// Minimum number of output bytes to process 2603 TYPE = SO_TYPE, /// Socket type 2604 2605 // SocketOptionLevel.TCP: 2606 TCP_NODELAY = .TCP_NODELAY, /// Disable the Nagle algorithm for send coalescing 2607 2608 // SocketOptionLevel.IPV6: 2609 IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, /// IP unicast hop limit 2610 IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, /// IP multicast interface 2611 IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, /// IP multicast loopback 2612 IPV6_MULTICAST_HOPS = .IPV6_MULTICAST_HOPS, /// IP multicast hops 2613 IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, /// Add an IP group membership 2614 IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, /// Drop an IP group membership 2615 IPV6_V6ONLY = .IPV6_V6ONLY, /// Treat wildcard bind as AF_INET6-only 2616 } 2617 2618 2619 /** 2620 * `Socket` is a class that creates a network communication endpoint using 2621 * the Berkeley sockets interface. 2622 */ 2623 class Socket 2624 { 2625 private: 2626 socket_t sock; 2627 AddressFamily _family; 2628 2629 version (Windows) 2630 bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking. 2631 2632 // The WinSock timeouts seem to be effectively skewed by a constant 2633 // offset of about half a second (value in milliseconds). This has 2634 // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7 2635 // and Windows Server 2008 R2 boxes. The unittest below tests this 2636 // behavior. 2637 enum WINSOCK_TIMEOUT_SKEW = 500; 2638 2639 @safe unittest 2640 { 2641 debug (std_socket) 2642 softUnittest({ 2643 import std.datetime.stopwatch; 2644 import std.typecons; 2645 2646 enum msecs = 1000; 2647 auto pair = socketPair(); 2648 auto sock = pair[0]; 2649 sock.setOption(SocketOptionLevel.SOCKET, 2650 SocketOption.RCVTIMEO, dur!"msecs"(msecs)); 2651 2652 auto sw = StopWatch(Yes.autoStart); 2653 ubyte[1] buf; 2654 sock.receive(buf); 2655 sw.stop(); 2656 2657 Duration readBack = void; 2658 sock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack); 2659 2660 assert(readBack.total!"msecs" == msecs); 2661 assert(sw.peek().total!"msecs" > msecs - 100 && sw.peek().total!"msecs" < msecs + 100); 2662 }); 2663 } 2664 2665 void setSock(socket_t handle) 2666 { 2667 assert(handle != socket_t.init); 2668 sock = handle; 2669 2670 // Set the option to disable SIGPIPE on send() if the platform 2671 // has it (e.g. on OS X). 2672 static if (is(typeof(SO_NOSIGPIPE))) 2673 { 2674 setOption(SocketOptionLevel.SOCKET, cast(SocketOption) SO_NOSIGPIPE, true); 2675 } 2676 } 2677 2678 2679 // For use with accepting(). 2680 protected this() pure nothrow @nogc 2681 { 2682 } 2683 2684 2685 public: 2686 2687 /** 2688 * Create a blocking socket. If a single protocol type exists to support 2689 * this socket type within the address family, the `ProtocolType` may be 2690 * omitted. 2691 */ 2692 this(AddressFamily af, SocketType type, ProtocolType protocol) @trusted 2693 { 2694 _family = af; 2695 auto handle = cast(socket_t) socket(af, type, protocol); 2696 if (handle == socket_t.init) 2697 throw new SocketOSException("Unable to create socket"); 2698 setSock(handle); 2699 } 2700 2701 /// ditto 2702 this(AddressFamily af, SocketType type) 2703 { 2704 /* A single protocol exists to support this socket type within the 2705 * protocol family, so the ProtocolType is assumed. 2706 */ 2707 this(af, type, cast(ProtocolType) 0); // Pseudo protocol number. 2708 } 2709 2710 2711 /// ditto 2712 this(AddressFamily af, SocketType type, scope const(char)[] protocolName) @trusted 2713 { 2714 protoent* proto; 2715 proto = getprotobyname(protocolName.tempCString()); 2716 if (!proto) 2717 throw new SocketOSException("Unable to find the protocol"); 2718 this(af, type, cast(ProtocolType) proto.p_proto); 2719 } 2720 2721 2722 /** 2723 * Create a blocking socket using the parameters from the specified 2724 * `AddressInfo` structure. 2725 */ 2726 this(const scope AddressInfo info) 2727 { 2728 this(info.family, info.type, info.protocol); 2729 } 2730 2731 /// Use an existing socket handle. 2732 this(socket_t sock, AddressFamily af) pure nothrow @nogc 2733 { 2734 assert(sock != socket_t.init); 2735 this.sock = sock; 2736 this._family = af; 2737 } 2738 2739 2740 ~this() nothrow @nogc 2741 { 2742 close(); 2743 } 2744 2745 2746 /// Get underlying socket handle. 2747 @property socket_t handle() const pure nothrow @nogc 2748 { 2749 return sock; 2750 } 2751 2752 /** 2753 * Get/set socket's blocking flag. 2754 * 2755 * When a socket is blocking, calls to receive(), accept(), and send() 2756 * will block and wait for data/action. 2757 * A non-blocking socket will immediately return instead of blocking. 2758 */ 2759 @property bool blocking() @trusted const nothrow @nogc 2760 { 2761 version (Windows) 2762 { 2763 return _blocking; 2764 } 2765 else version (Posix) 2766 { 2767 return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK); 2768 } 2769 } 2770 2771 /// ditto 2772 @property void blocking(bool byes) @trusted 2773 { 2774 version (Windows) 2775 { 2776 uint num = !byes; 2777 if (_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num)) 2778 goto err; 2779 _blocking = byes; 2780 } 2781 else version (Posix) 2782 { 2783 int x = fcntl(sock, F_GETFL, 0); 2784 if (-1 == x) 2785 goto err; 2786 if (byes) 2787 x &= ~O_NONBLOCK; 2788 else 2789 x |= O_NONBLOCK; 2790 if (-1 == fcntl(sock, F_SETFL, x)) 2791 goto err; 2792 } 2793 return; // Success. 2794 2795 err: 2796 throw new SocketOSException("Unable to set socket blocking"); 2797 } 2798 2799 2800 /// Get the socket's address family. 2801 @property AddressFamily addressFamily() 2802 { 2803 return _family; 2804 } 2805 2806 /// Property that indicates if this is a valid, alive socket. 2807 @property bool isAlive() @trusted const 2808 { 2809 int type; 2810 socklen_t typesize = cast(socklen_t) type.sizeof; 2811 return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize); 2812 } 2813 2814 /** 2815 * Associate a local address with this socket. 2816 * 2817 * Params: 2818 * addr = The $(LREF Address) to associate this socket with. 2819 * 2820 * Throws: $(LREF SocketOSException) when unable to bind the socket. 2821 */ 2822 void bind(Address addr) @trusted 2823 { 2824 if (_SOCKET_ERROR == .bind(sock, addr.name, addr.nameLen)) 2825 throw new SocketOSException("Unable to bind socket"); 2826 } 2827 2828 /** 2829 * Establish a connection. If the socket is blocking, connect waits for 2830 * the connection to be made. If the socket is nonblocking, connect 2831 * returns immediately and the connection attempt is still in progress. 2832 */ 2833 void connect(Address to) @trusted 2834 { 2835 if (_SOCKET_ERROR == .connect(sock, to.name, to.nameLen)) 2836 { 2837 int err; 2838 err = _lasterr(); 2839 2840 if (!blocking) 2841 { 2842 version (Windows) 2843 { 2844 if (WSAEWOULDBLOCK == err) 2845 return; 2846 } 2847 else version (Posix) 2848 { 2849 if (EINPROGRESS == err) 2850 return; 2851 } 2852 else 2853 { 2854 static assert(0); 2855 } 2856 } 2857 throw new SocketOSException("Unable to connect socket", err); 2858 } 2859 } 2860 2861 /** 2862 * Listen for an incoming connection. `bind` must be called before you 2863 * can `listen`. The `backlog` is a request of how many pending 2864 * incoming connections are queued until `accept`ed. 2865 */ 2866 void listen(int backlog) @trusted 2867 { 2868 if (_SOCKET_ERROR == .listen(sock, backlog)) 2869 throw new SocketOSException("Unable to listen on socket"); 2870 } 2871 2872 /** 2873 * Called by `accept` when a new `Socket` must be created for a new 2874 * connection. To use a derived class, override this method and return an 2875 * instance of your class. The returned `Socket`'s handle must not be 2876 * set; `Socket` has a protected constructor `this()` to use in this 2877 * situation. 2878 * 2879 * Override to use a derived class. 2880 * The returned socket's handle must not be set. 2881 */ 2882 protected Socket accepting() pure nothrow 2883 { 2884 return new Socket; 2885 } 2886 2887 /** 2888 * Accept an incoming connection. If the socket is blocking, `accept` 2889 * waits for a connection request. Throws `SocketAcceptException` if 2890 * unable to _accept. See `accepting` for use with derived classes. 2891 */ 2892 Socket accept() @trusted 2893 { 2894 auto newsock = cast(socket_t).accept(sock, null, null); 2895 if (socket_t.init == newsock) 2896 throw new SocketAcceptException("Unable to accept socket connection"); 2897 2898 Socket newSocket; 2899 try 2900 { 2901 newSocket = accepting(); 2902 assert(newSocket.sock == socket_t.init); 2903 2904 newSocket.setSock(newsock); 2905 version (Windows) 2906 newSocket._blocking = _blocking; //inherits blocking mode 2907 newSocket._family = _family; //same family 2908 } 2909 catch (Throwable o) 2910 { 2911 _close(newsock); 2912 throw o; 2913 } 2914 2915 return newSocket; 2916 } 2917 2918 /// Disables sends and/or receives. 2919 void shutdown(SocketShutdown how) @trusted nothrow @nogc 2920 { 2921 .shutdown(sock, cast(int) how); 2922 } 2923 2924 2925 private static void _close(socket_t sock) @system nothrow @nogc 2926 { 2927 version (Windows) 2928 { 2929 .closesocket(sock); 2930 } 2931 else version (Posix) 2932 { 2933 .close(sock); 2934 } 2935 } 2936 2937 2938 /** 2939 * Immediately drop any connections and release socket resources. 2940 * The `Socket` object is no longer usable after `close`. 2941 * Calling `shutdown` before `close` is recommended 2942 * for connection-oriented sockets. 2943 */ 2944 void close() @trusted nothrow @nogc 2945 { 2946 _close(sock); 2947 sock = socket_t.init; 2948 } 2949 2950 2951 /** 2952 * Returns: the local machine's host name 2953 */ 2954 static @property string hostName() @trusted // getter 2955 { 2956 char[256] result; // Host names are limited to 255 chars. 2957 if (_SOCKET_ERROR == .gethostname(result.ptr, result.length)) 2958 throw new SocketOSException("Unable to obtain host name"); 2959 return to!string(result.ptr); 2960 } 2961 2962 /// Remote endpoint `Address`. 2963 @property Address remoteAddress() @trusted 2964 { 2965 Address addr = createAddress(); 2966 socklen_t nameLen = addr.nameLen; 2967 if (_SOCKET_ERROR == .getpeername(sock, addr.name, &nameLen)) 2968 throw new SocketOSException("Unable to obtain remote socket address"); 2969 addr.setNameLen(nameLen); 2970 assert(addr.addressFamily == _family); 2971 return addr; 2972 } 2973 2974 /// Local endpoint `Address`. 2975 @property Address localAddress() @trusted 2976 { 2977 Address addr = createAddress(); 2978 socklen_t nameLen = addr.nameLen; 2979 if (_SOCKET_ERROR == .getsockname(sock, addr.name, &nameLen)) 2980 throw new SocketOSException("Unable to obtain local socket address"); 2981 addr.setNameLen(nameLen); 2982 assert(addr.addressFamily == _family); 2983 return addr; 2984 } 2985 2986 /** 2987 * Send or receive error code. See `wouldHaveBlocked`, 2988 * `lastSocketError` and `Socket.getErrorText` for obtaining more 2989 * information about the error. 2990 */ 2991 enum int ERROR = _SOCKET_ERROR; 2992 2993 private static int capToInt(size_t size) nothrow @nogc 2994 { 2995 // Windows uses int instead of size_t for length arguments. 2996 // Luckily, the send/recv functions make no guarantee that 2997 // all the data is sent, so we use that to send at most 2998 // int.max bytes. 2999 return size > size_t(int.max) ? int.max : cast(int) size; 3000 } 3001 3002 /** 3003 * Send data on the connection. If the socket is blocking and there is no 3004 * buffer space left, `send` waits. 3005 * Returns: The number of bytes actually sent, or `Socket.ERROR` on 3006 * failure. 3007 */ 3008 ptrdiff_t send(const(void)[] buf, SocketFlags flags) @trusted 3009 { 3010 static if (is(typeof(MSG_NOSIGNAL))) 3011 { 3012 flags = cast(SocketFlags)(flags | MSG_NOSIGNAL); 3013 } 3014 version (Windows) 3015 auto sent = .send(sock, buf.ptr, capToInt(buf.length), cast(int) flags); 3016 else 3017 auto sent = .send(sock, buf.ptr, buf.length, cast(int) flags); 3018 return sent; 3019 } 3020 3021 /// ditto 3022 ptrdiff_t send(const(void)[] buf) 3023 { 3024 return send(buf, SocketFlags.NONE); 3025 } 3026 3027 /** 3028 * Send data to a specific destination Address. If the destination address is 3029 * not specified, a connection must have been made and that address is used. 3030 * If the socket is blocking and there is no buffer space left, `sendTo` waits. 3031 * Returns: The number of bytes actually sent, or `Socket.ERROR` on 3032 * failure. 3033 */ 3034 ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to) @trusted 3035 { 3036 static if (is(typeof(MSG_NOSIGNAL))) 3037 { 3038 flags = cast(SocketFlags)(flags | MSG_NOSIGNAL); 3039 } 3040 version (Windows) 3041 return .sendto( 3042 sock, buf.ptr, capToInt(buf.length), 3043 cast(int) flags, to.name, to.nameLen 3044 ); 3045 else 3046 return .sendto(sock, buf.ptr, buf.length, cast(int) flags, to.name, to.nameLen); 3047 } 3048 3049 /// ditto 3050 ptrdiff_t sendTo(const(void)[] buf, Address to) 3051 { 3052 return sendTo(buf, SocketFlags.NONE, to); 3053 } 3054 3055 3056 //assumes you connect()ed 3057 /// ditto 3058 ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags) @trusted 3059 { 3060 static if (is(typeof(MSG_NOSIGNAL))) 3061 { 3062 flags = cast(SocketFlags)(flags | MSG_NOSIGNAL); 3063 } 3064 version (Windows) 3065 return .sendto(sock, buf.ptr, capToInt(buf.length), cast(int) flags, null, 0); 3066 else 3067 return .sendto(sock, buf.ptr, buf.length, cast(int) flags, null, 0); 3068 } 3069 3070 3071 //assumes you connect()ed 3072 /// ditto 3073 ptrdiff_t sendTo(const(void)[] buf) 3074 { 3075 return sendTo(buf, SocketFlags.NONE); 3076 } 3077 3078 3079 /** 3080 * Receive data on the connection. If the socket is blocking, `receive` 3081 * waits until there is data to be received. 3082 * Returns: The number of bytes actually received, `0` if the remote side 3083 * has closed the connection, or `Socket.ERROR` on failure. 3084 */ 3085 ptrdiff_t receive(void[] buf, SocketFlags flags) @trusted 3086 { 3087 version (Windows) // Does not use size_t 3088 { 3089 return buf.length 3090 ? .recv(sock, buf.ptr, capToInt(buf.length), cast(int) flags) 3091 : 0; 3092 } 3093 else 3094 { 3095 return buf.length 3096 ? .recv(sock, buf.ptr, buf.length, cast(int) flags) 3097 : 0; 3098 } 3099 } 3100 3101 /// ditto 3102 ptrdiff_t receive(void[] buf) 3103 { 3104 return receive(buf, SocketFlags.NONE); 3105 } 3106 3107 /** 3108 * Receive data and get the remote endpoint `Address`. 3109 * If the socket is blocking, `receiveFrom` waits until there is data to 3110 * be received. 3111 * Returns: The number of bytes actually received, `0` if the remote side 3112 * has closed the connection, or `Socket.ERROR` on failure. 3113 */ 3114 ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from) @trusted 3115 { 3116 if (!buf.length) //return 0 and don't think the connection closed 3117 return 0; 3118 if (from is null || from.addressFamily != _family) 3119 from = createAddress(); 3120 socklen_t nameLen = from.nameLen; 3121 version (Windows) 3122 { 3123 auto read = .recvfrom(sock, buf.ptr, capToInt(buf.length), cast(int) flags, from.name, &nameLen); 3124 from.setNameLen(nameLen); 3125 assert(from.addressFamily == _family); 3126 // if (!read) //connection closed 3127 return read; 3128 } 3129 else 3130 { 3131 auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int) flags, from.name, &nameLen); 3132 from.setNameLen(nameLen); 3133 assert(from.addressFamily == _family); 3134 // if (!read) //connection closed 3135 return read; 3136 } 3137 } 3138 3139 3140 /// ditto 3141 ptrdiff_t receiveFrom(void[] buf, ref Address from) 3142 { 3143 return receiveFrom(buf, SocketFlags.NONE, from); 3144 } 3145 3146 3147 //assumes you connect()ed 3148 /// ditto 3149 ptrdiff_t receiveFrom(void[] buf, SocketFlags flags) @trusted 3150 { 3151 if (!buf.length) //return 0 and don't think the connection closed 3152 return 0; 3153 version (Windows) 3154 { 3155 auto read = .recvfrom(sock, buf.ptr, capToInt(buf.length), cast(int) flags, null, null); 3156 // if (!read) //connection closed 3157 return read; 3158 } 3159 else 3160 { 3161 auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int) flags, null, null); 3162 // if (!read) //connection closed 3163 return read; 3164 } 3165 } 3166 3167 3168 //assumes you connect()ed 3169 /// ditto 3170 ptrdiff_t receiveFrom(void[] buf) 3171 { 3172 return receiveFrom(buf, SocketFlags.NONE); 3173 } 3174 3175 3176 /** 3177 * Get a socket option. 3178 * Returns: The number of bytes written to `result`. 3179 * The length, in bytes, of the actual result - very different from getsockopt() 3180 */ 3181 int getOption(SocketOptionLevel level, SocketOption option, void[] result) @trusted 3182 { 3183 socklen_t len = cast(socklen_t) result.length; 3184 if (_SOCKET_ERROR == .getsockopt(sock, cast(int) level, cast(int) option, result.ptr, &len)) 3185 throw new SocketOSException("Unable to get socket option"); 3186 return len; 3187 } 3188 3189 3190 /// Common case of getting integer and boolean options. 3191 int getOption(SocketOptionLevel level, SocketOption option, out int32_t result) @trusted 3192 { 3193 return getOption(level, option, (&result)[0 .. 1]); 3194 } 3195 3196 3197 /// Get the linger option. 3198 int getOption(SocketOptionLevel level, SocketOption option, out Linger result) @trusted 3199 { 3200 //return getOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]); 3201 return getOption(level, option, (&result.clinger)[0 .. 1]); 3202 } 3203 3204 /// Get a timeout (duration) option. 3205 void getOption(SocketOptionLevel level, SocketOption option, out Duration result) @trusted 3206 { 3207 enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO, 3208 new SocketParameterException("Not a valid timeout option: " ~ to!string(option))); 3209 // WinSock returns the timeout values as a milliseconds DWORD, 3210 // while Linux and BSD return a timeval struct. 3211 version (Windows) 3212 { 3213 int msecs; 3214 getOption(level, option, (&msecs)[0 .. 1]); 3215 if (option == SocketOption.RCVTIMEO) 3216 msecs += WINSOCK_TIMEOUT_SKEW; 3217 result = dur!"msecs"(msecs); 3218 } 3219 else version (Posix) 3220 { 3221 TimeVal tv; 3222 getOption(level, option, (&tv.ctimeval)[0 .. 1]); 3223 result = dur!"seconds"(tv.seconds) + dur!"usecs"(tv.microseconds); 3224 } 3225 else static assert(false); 3226 } 3227 3228 /// Set a socket option. 3229 void setOption(SocketOptionLevel level, SocketOption option, void[] value) @trusted 3230 { 3231 if (_SOCKET_ERROR == .setsockopt(sock, cast(int) level, 3232 cast(int) option, value.ptr, cast(uint) value.length)) 3233 throw new SocketOSException("Unable to set socket option"); 3234 } 3235 3236 3237 /// Common case for setting integer and boolean options. 3238 void setOption(SocketOptionLevel level, SocketOption option, int32_t value) @trusted 3239 { 3240 setOption(level, option, (&value)[0 .. 1]); 3241 } 3242 3243 3244 /// Set the linger option. 3245 void setOption(SocketOptionLevel level, SocketOption option, Linger value) @trusted 3246 { 3247 //setOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]); 3248 setOption(level, option, (&value.clinger)[0 .. 1]); 3249 } 3250 3251 /** 3252 * Sets a timeout (duration) option, i.e. `SocketOption.SNDTIMEO` or 3253 * `RCVTIMEO`. Zero indicates no timeout. 3254 * 3255 * In a typical application, you might also want to consider using 3256 * a non-blocking socket instead of setting a timeout on a blocking one. 3257 * 3258 * Note: While the receive timeout setting is generally quite accurate 3259 * on *nix systems even for smaller durations, there are two issues to 3260 * be aware of on Windows: First, although undocumented, the effective 3261 * timeout duration seems to be the one set on the socket plus half 3262 * a second. `setOption()` tries to compensate for that, but still, 3263 * timeouts under 500ms are not possible on Windows. Second, be aware 3264 * that the actual amount of time spent until a blocking call returns 3265 * randomly varies on the order of 10ms. 3266 * 3267 * Params: 3268 * level = The level at which a socket option is defined. 3269 * option = Either `SocketOption.SNDTIMEO` or `SocketOption.RCVTIMEO`. 3270 * value = The timeout duration to set. Must not be negative. 3271 * 3272 * Throws: `SocketException` if setting the options fails. 3273 * 3274 * Example: 3275 * --- 3276 * import std.datetime; 3277 * import std.typecons; 3278 * auto pair = socketPair(); 3279 * scope(exit) foreach (s; pair) s.close(); 3280 * 3281 * // Set a receive timeout, and then wait at one end of 3282 * // the socket pair, knowing that no data will arrive. 3283 * pair[0].setOption(SocketOptionLevel.SOCKET, 3284 * SocketOption.RCVTIMEO, dur!"seconds"(1)); 3285 * 3286 * auto sw = StopWatch(Yes.autoStart); 3287 * ubyte[1] buffer; 3288 * pair[0].receive(buffer); 3289 * writefln("Waited %s ms until the socket timed out.", 3290 * sw.peek.msecs); 3291 * --- 3292 */ 3293 void setOption(SocketOptionLevel level, SocketOption option, Duration value) @trusted 3294 { 3295 enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO, 3296 new SocketParameterException("Not a valid timeout option: " ~ to!string(option))); 3297 3298 enforce(value >= dur!"hnsecs"(0), new SocketParameterException( 3299 "Timeout duration must not be negative.")); 3300 3301 version (Windows) 3302 { 3303 import std.algorithm.comparison : max; 3304 3305 auto msecs = to!int(value.total!"msecs"); 3306 if (msecs != 0 && option == SocketOption.RCVTIMEO) 3307 msecs = max(1, msecs - WINSOCK_TIMEOUT_SKEW); 3308 setOption(level, option, msecs); 3309 } 3310 else version (Posix) 3311 { 3312 _ctimeval tv; 3313 value.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec); 3314 setOption(level, option, (&tv)[0 .. 1]); 3315 } 3316 else static assert(false); 3317 } 3318 3319 /** 3320 * Get a text description of this socket's error status, and clear the 3321 * socket's error status. 3322 */ 3323 string getErrorText() 3324 { 3325 int32_t error; 3326 getOption(SocketOptionLevel.SOCKET, SocketOption.ERROR, error); 3327 return formatSocketError(error); 3328 } 3329 3330 /** 3331 * Enables TCP keep-alive with the specified parameters. 3332 * 3333 * Params: 3334 * time = Number of seconds with no activity until the first 3335 * keep-alive packet is sent. 3336 * interval = Number of seconds between when successive keep-alive 3337 * packets are sent if no acknowledgement is received. 3338 * 3339 * Throws: `SocketOSException` if setting the options fails, or 3340 * `SocketFeatureException` if setting keep-alive parameters is 3341 * unsupported on the current platform. 3342 */ 3343 void setKeepAlive(int time, int interval) @trusted 3344 { 3345 version (Windows) 3346 { 3347 tcp_keepalive options; 3348 options.onoff = 1; 3349 options.keepalivetime = time * 1000; 3350 options.keepaliveinterval = interval * 1000; 3351 uint cbBytesReturned; 3352 enforce(WSAIoctl(sock, SIO_KEEPALIVE_VALS, 3353 &options, options.sizeof, 3354 null, 0, 3355 &cbBytesReturned, null, null) == 0, 3356 new SocketOSException("Error setting keep-alive")); 3357 } 3358 else 3359 static if (is(typeof(TCP_KEEPIDLE)) && is(typeof(TCP_KEEPINTVL))) 3360 { 3361 setOption(SocketOptionLevel.TCP, cast(SocketOption) TCP_KEEPIDLE, time); 3362 setOption(SocketOptionLevel.TCP, cast(SocketOption) TCP_KEEPINTVL, interval); 3363 setOption(SocketOptionLevel.SOCKET, SocketOption.KEEPALIVE, true); 3364 } 3365 else 3366 throw new SocketFeatureException("Setting keep-alive options " ~ 3367 "is not supported on this platform"); 3368 } 3369 3370 /** 3371 * Wait for a socket to change status. A wait timeout of $(REF Duration, core, time) or 3372 * `TimeVal`, may be specified; if a timeout is not specified or the 3373 * `TimeVal` is `null`, the maximum timeout is used. The `TimeVal` 3374 * timeout has an unspecified value when `select` returns. 3375 * Returns: The number of sockets with status changes, `0` on timeout, 3376 * or `-1` on interruption. If the return value is greater than `0`, 3377 * the `SocketSets` are updated to only contain the sockets having status 3378 * changes. For a connecting socket, a write status change means the 3379 * connection is established and it's able to send. For a listening socket, 3380 * a read status change means there is an incoming connection request and 3381 * it's able to accept. 3382 * 3383 * `SocketSet`'s updated to include only those sockets which an event occured. 3384 * For a `connect()`ing socket, writeability means connected. 3385 * For a `listen()`ing socket, readability means listening 3386 * `Winsock`; possibly internally limited to 64 sockets per set. 3387 * 3388 * Returns: 3389 * the number of events, 0 on timeout, or -1 on interruption 3390 */ 3391 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, Duration timeout) @trusted 3392 { 3393 auto vals = timeout.split!("seconds", "usecs")(); 3394 TimeVal tv; 3395 tv.seconds = cast(tv.tv_sec_t ) vals.seconds; 3396 tv.microseconds = cast(tv.tv_usec_t) vals.usecs; 3397 return select(checkRead, checkWrite, checkError, &tv); 3398 } 3399 3400 /// ditto 3401 //maximum timeout 3402 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError) 3403 { 3404 return select(checkRead, checkWrite, checkError, null); 3405 } 3406 3407 /// Ditto 3408 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeVal* timeout) @trusted 3409 in 3410 { 3411 //make sure none of the SocketSet's are the same object 3412 if (checkRead) 3413 { 3414 assert(checkRead !is checkWrite); 3415 assert(checkRead !is checkError); 3416 } 3417 if (checkWrite) 3418 { 3419 assert(checkWrite !is checkError); 3420 } 3421 } 3422 do 3423 { 3424 fd_set* fr, fw, fe; 3425 int n = 0; 3426 3427 version (Windows) 3428 { 3429 // Windows has a problem with empty fd_set`s that aren't null. 3430 fr = checkRead && checkRead.count ? checkRead.toFd_set() : null; 3431 fw = checkWrite && checkWrite.count ? checkWrite.toFd_set() : null; 3432 fe = checkError && checkError.count ? checkError.toFd_set() : null; 3433 } 3434 else 3435 { 3436 if (checkRead) 3437 { 3438 fr = checkRead.toFd_set(); 3439 n = checkRead.selectn(); 3440 } 3441 else 3442 { 3443 fr = null; 3444 } 3445 3446 if (checkWrite) 3447 { 3448 fw = checkWrite.toFd_set(); 3449 int _n; 3450 _n = checkWrite.selectn(); 3451 if (_n > n) 3452 n = _n; 3453 } 3454 else 3455 { 3456 fw = null; 3457 } 3458 3459 if (checkError) 3460 { 3461 fe = checkError.toFd_set(); 3462 int _n; 3463 _n = checkError.selectn(); 3464 if (_n > n) 3465 n = _n; 3466 } 3467 else 3468 { 3469 fe = null; 3470 } 3471 3472 // Make sure the sets' capacity matches, to avoid select reading 3473 // out of bounds just because one set was bigger than another 3474 if (checkRead ) checkRead .setMinCapacity(n); 3475 if (checkWrite) checkWrite.setMinCapacity(n); 3476 if (checkError) checkError.setMinCapacity(n); 3477 } 3478 3479 int result = .select(n, fr, fw, fe, &timeout.ctimeval); 3480 3481 version (Windows) 3482 { 3483 if (_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR) 3484 return -1; 3485 } 3486 else version (Posix) 3487 { 3488 if (_SOCKET_ERROR == result && errno == EINTR) 3489 return -1; 3490 } 3491 else 3492 { 3493 static assert(0); 3494 } 3495 3496 if (_SOCKET_ERROR == result) 3497 throw new SocketOSException("Socket select error"); 3498 3499 return result; 3500 } 3501 3502 3503 /** 3504 * Can be overridden to support other addresses. 3505 * Returns: a new `Address` object for the current address family. 3506 */ 3507 protected Address createAddress() pure nothrow 3508 { 3509 Address result; 3510 switch (_family) 3511 { 3512 static if (is(sockaddr_un)) 3513 { 3514 case AddressFamily.UNIX: 3515 result = new UnixAddress; 3516 break; 3517 } 3518 3519 case AddressFamily.INET: 3520 result = new InternetAddress; 3521 break; 3522 3523 case AddressFamily.INET6: 3524 result = new Internet6Address; 3525 break; 3526 3527 default: 3528 result = new UnknownAddress; 3529 } 3530 return result; 3531 } 3532 3533 } 3534 3535 3536 /// `TcpSocket` is a shortcut class for a TCP Socket. 3537 class TcpSocket: Socket 3538 { 3539 /// Constructs a blocking TCP Socket. 3540 this(AddressFamily family) 3541 { 3542 super(family, SocketType.STREAM, ProtocolType.TCP); 3543 } 3544 3545 /// Constructs a blocking IPv4 TCP Socket. 3546 this() 3547 { 3548 this(AddressFamily.INET); 3549 } 3550 3551 3552 //shortcut 3553 /// Constructs a blocking TCP Socket and connects to an `Address`. 3554 this(Address connectTo) 3555 { 3556 this(connectTo.addressFamily); 3557 connect(connectTo); 3558 } 3559 } 3560 3561 3562 /// `UdpSocket` is a shortcut class for a UDP Socket. 3563 class UdpSocket: Socket 3564 { 3565 /// Constructs a blocking UDP Socket. 3566 this(AddressFamily family) 3567 { 3568 super(family, SocketType.DGRAM, ProtocolType.UDP); 3569 } 3570 3571 3572 /// Constructs a blocking IPv4 UDP Socket. 3573 this() 3574 { 3575 this(AddressFamily.INET); 3576 } 3577 } 3578 3579 // https://issues.dlang.org/show_bug.cgi?id=16514 3580 @safe unittest 3581 { 3582 void checkAttributes(string attributes)() 3583 { 3584 mixin(attributes ~ q{ void function() fun = {};}); 3585 fun(); 3586 } 3587 3588 class TestSocket : Socket 3589 { 3590 override 3591 { 3592 @property pure nothrow @nogc @safe socket_t handle() const 3593 { 3594 checkAttributes!q{pure nothrow @nogc @safe}; assert(0); 3595 } 3596 @property nothrow @nogc @trusted bool blocking() const 3597 { 3598 checkAttributes!q{nothrow @nogc @trusted}; assert(0); 3599 } 3600 @property @trusted void blocking(bool byes) 3601 { 3602 checkAttributes!q{@trusted}; 3603 } 3604 @property @safe AddressFamily addressFamily() 3605 { 3606 checkAttributes!q{@safe}; assert(0); 3607 } 3608 @property @trusted bool isAlive() const 3609 { 3610 checkAttributes!q{@trusted}; assert(0); 3611 } 3612 @trusted void bind(Address addr) 3613 { 3614 checkAttributes!q{@trusted}; 3615 } 3616 @trusted void connect(Address to) 3617 { 3618 checkAttributes!q{@trusted}; 3619 } 3620 @trusted void listen(int backlog) 3621 { 3622 checkAttributes!q{@trusted}; 3623 } 3624 protected pure nothrow @safe Socket accepting() 3625 { 3626 checkAttributes!q{pure nothrow @safe}; assert(0); 3627 } 3628 @trusted Socket accept() 3629 { 3630 checkAttributes!q{@trusted}; assert(0); 3631 } 3632 nothrow @nogc @trusted void shutdown(SocketShutdown how) 3633 { 3634 checkAttributes!q{nothrow @nogc @trusted}; 3635 } 3636 nothrow @nogc @trusted void close() 3637 { 3638 checkAttributes!q{nothrow @nogc @trusted}; 3639 } 3640 @property @trusted Address remoteAddress() 3641 { 3642 checkAttributes!q{@trusted}; assert(0); 3643 } 3644 @property @trusted Address localAddress() 3645 { 3646 checkAttributes!q{@trusted}; assert(0); 3647 } 3648 @trusted ptrdiff_t send(const(void)[] buf, SocketFlags flags) 3649 { 3650 checkAttributes!q{@trusted}; assert(0); 3651 } 3652 @safe ptrdiff_t send(const(void)[] buf) 3653 { 3654 checkAttributes!q{@safe}; assert(0); 3655 } 3656 @trusted ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to) 3657 { 3658 checkAttributes!q{@trusted}; assert(0); 3659 } 3660 @safe ptrdiff_t sendTo(const(void)[] buf, Address to) 3661 { 3662 checkAttributes!q{@safe}; assert(0); 3663 } 3664 @trusted ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags) 3665 { 3666 checkAttributes!q{@trusted}; assert(0); 3667 } 3668 @safe ptrdiff_t sendTo(const(void)[] buf) 3669 { 3670 checkAttributes!q{@safe}; assert(0); 3671 } 3672 @trusted ptrdiff_t receive(void[] buf, SocketFlags flags) 3673 { 3674 checkAttributes!q{@trusted}; assert(0); 3675 } 3676 @safe ptrdiff_t receive(void[] buf) 3677 { 3678 checkAttributes!q{@safe}; assert(0); 3679 } 3680 @trusted ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from) 3681 { 3682 checkAttributes!q{@trusted}; assert(0); 3683 } 3684 @safe ptrdiff_t receiveFrom(void[] buf, ref Address from) 3685 { 3686 checkAttributes!q{@safe}; assert(0); 3687 } 3688 @trusted ptrdiff_t receiveFrom(void[] buf, SocketFlags flags) 3689 { 3690 checkAttributes!q{@trusted}; assert(0); 3691 } 3692 @safe ptrdiff_t receiveFrom(void[] buf) 3693 { 3694 checkAttributes!q{@safe}; assert(0); 3695 } 3696 @trusted int getOption(SocketOptionLevel level, SocketOption option, void[] result) 3697 { 3698 checkAttributes!q{@trusted}; assert(0); 3699 } 3700 @trusted int getOption(SocketOptionLevel level, SocketOption option, out int32_t result) 3701 { 3702 checkAttributes!q{@trusted}; assert(0); 3703 } 3704 @trusted int getOption(SocketOptionLevel level, SocketOption option, out Linger result) 3705 { 3706 checkAttributes!q{@trusted}; assert(0); 3707 } 3708 @trusted void getOption(SocketOptionLevel level, SocketOption option, out Duration result) 3709 { 3710 checkAttributes!q{@trusted}; 3711 } 3712 @trusted void setOption(SocketOptionLevel level, SocketOption option, void[] value) 3713 { 3714 checkAttributes!q{@trusted}; 3715 } 3716 @trusted void setOption(SocketOptionLevel level, SocketOption option, int32_t value) 3717 { 3718 checkAttributes!q{@trusted}; 3719 } 3720 @trusted void setOption(SocketOptionLevel level, SocketOption option, Linger value) 3721 { 3722 checkAttributes!q{@trusted}; 3723 } 3724 @trusted void setOption(SocketOptionLevel level, SocketOption option, Duration value) 3725 { 3726 checkAttributes!q{@trusted}; 3727 } 3728 @safe string getErrorText() 3729 { 3730 checkAttributes!q{@safe}; assert(0); 3731 } 3732 @trusted void setKeepAlive(int time, int interval) 3733 { 3734 checkAttributes!q{@trusted}; 3735 } 3736 protected pure nothrow @safe Address createAddress() 3737 { 3738 checkAttributes!q{pure nothrow @safe}; assert(0); 3739 } 3740 } 3741 } 3742 } 3743 3744 /** 3745 * Creates a pair of connected sockets. 3746 * 3747 * The two sockets are indistinguishable. 3748 * 3749 * Throws: `SocketException` if creation of the sockets fails. 3750 */ 3751 Socket[2] socketPair() @trusted 3752 { 3753 version (Posix) 3754 { 3755 int[2] socks; 3756 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1) 3757 throw new SocketOSException("Unable to create socket pair"); 3758 3759 Socket toSocket(size_t id) 3760 { 3761 auto s = new Socket; 3762 s.setSock(cast(socket_t) socks[id]); 3763 s._family = AddressFamily.UNIX; 3764 return s; 3765 } 3766 3767 return [toSocket(0), toSocket(1)]; 3768 } 3769 else version (Windows) 3770 { 3771 // We do not have socketpair() on Windows, just manually create a 3772 // pair of sockets connected over some localhost port. 3773 Socket[2] result; 3774 3775 auto listener = new TcpSocket(); 3776 listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); 3777 listener.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY)); 3778 auto addr = listener.localAddress; 3779 listener.listen(1); 3780 3781 result[0] = new TcpSocket(addr); 3782 result[1] = listener.accept(); 3783 3784 listener.close(); 3785 return result; 3786 } 3787 else 3788 static assert(false); 3789 } 3790 3791 /// 3792 @safe unittest 3793 { 3794 immutable ubyte[] data = [1, 2, 3, 4]; 3795 auto pair = socketPair(); 3796 scope(exit) foreach (s; pair) s.close(); 3797 3798 pair[0].send(data); 3799 3800 auto buf = new ubyte[data.length]; 3801 pair[1].receive(buf); 3802 assert(buf == data); 3803 }