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