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