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