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