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