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