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