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