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