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