1 // Written in the D programming language
2
3 /*
4 Copyright (C) 2004-2011 Christopher E. Miller
5
6 Boost Software License - Version 1.0 - August 17th, 2003
7
8 Permission is hereby granted, free of charge, to any person or organization
9 obtaining a copy of the software and accompanying documentation covered by
10 this license (the "Software") to use, reproduce, display, distribute,
11 execute, and transmit the Software, and to prepare derivative works of the
12 Software, and to permit third-parties to whom the Software is furnished to
13 do so, all subject to the following:
14
15 The copyright notices in the Software and this entire statement, including
16 the above license grant, this restriction and the following disclaimer,
17 must be included in all copies of the Software, in whole or in part, and
18 all derivative works of the Software, unless such copies or derivative
19 works are solely in the form of machine-executable object code generated by
20 a source language processor.
21
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 DEALINGS IN THE SOFTWARE.
29
30 socket.d 1.4
31 Jan 2011
32
33 Thanks to Benjamin Herr for his assistance.
34 */
35
36 /**
37 * Socket primitives.
38 * Example: See $(SAMPLESRC listener.d) and $(SAMPLESRC htmlget.d)
39 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
40 * Authors: Christopher E. Miller, $(HTTP klickverbot.at, David Nadlinger),
41 * $(HTTP thecybershadow.net, Vladimir Panteleev)
42 * Source: $(PHOBOSSRC std/_socket.d)
43 */
44
45 module std.socket;
46
47 import core.stdc.stdint, core.stdc.stdlib, core.stdc.string, std.conv, std.string;
48
49 import core.stdc.config;
50 import core.time : dur, Duration;
51 import std.exception;
52
53 import std.internal.cstring;
54
55
56 @safe:
57
version(Windows)58 version (Windows)
59 {
60 pragma (lib, "ws2_32.lib");
61 pragma (lib, "wsock32.lib");
62
63 import core.sys.windows.windows, std.windows.syserror;
64 public import core.sys.windows.winsock2;
65 private alias _ctimeval = core.sys.windows.winsock2.timeval;
66 private alias _clinger = core.sys.windows.winsock2.linger;
67
68 enum socket_t : SOCKET { INVALID_SOCKET }
69 private const int _SOCKET_ERROR = SOCKET_ERROR;
70
71
72 private int _lasterr() nothrow @nogc
73 {
74 return WSAGetLastError();
75 }
76 }
version(Posix)77 else version (Posix)
78 {
79 version (linux)
80 {
81 enum : int
82 {
83 TCP_KEEPIDLE = 4,
84 TCP_KEEPINTVL = 5
85 }
86 }
87
88 import core.sys.posix.arpa.inet;
89 import core.sys.posix.fcntl;
90 import core.sys.posix.netdb;
91 import core.sys.posix.netinet.in_;
92 import core.sys.posix.netinet.tcp;
93 import core.sys.posix.sys.select;
94 import core.sys.posix.sys.socket;
95 import core.sys.posix.sys.time;
96 import core.sys.posix.sys.un : sockaddr_un;
97 import core.sys.posix.unistd;
98 private alias _ctimeval = core.sys.posix.sys.time.timeval;
99 private alias _clinger = core.sys.posix.sys.socket.linger;
100
101 import core.stdc.errno;
102
103 enum socket_t : int32_t { init = -1 }
104 private const int _SOCKET_ERROR = -1;
105
106 private enum : int
107 {
108 SD_RECEIVE = SHUT_RD,
109 SD_SEND = SHUT_WR,
110 SD_BOTH = SHUT_RDWR
111 }
112
113 private int _lasterr() nothrow @nogc
114 {
115 return errno;
116 }
117 }
118 else
119 {
120 static assert(0); // No socket support yet.
121 }
122
123 version (unittest)
124 {
125 static assert(is(uint32_t == uint));
126 static assert(is(uint16_t == ushort));
127
128 import std.stdio : writefln;
129
130 // Print a message on exception instead of failing the unittest.
131 private void softUnittest(void delegate() @safe test, int line = __LINE__) @trusted
132 {
133 try
134 test();
135 catch (Throwable e)
136 {
137 writefln(" --- std.socket(%d) test fails depending on environment ---", line);
138 writefln(" (%s)", e);
139 }
140 }
141 }
142
143 /// Base exception thrown by $(D std.socket).
144 class SocketException: Exception
145 {
146 mixin basicExceptionCtors;
147 }
148
149
150 /*
151 * Needs to be public so that SocketOSException can be thrown outside of
152 * std.socket (since it uses it as a default argument), but it probably doesn't
153 * need to actually show up in the docs, since there's not really any public
154 * need for it outside of being a default argument.
155 */
156 string formatSocketError(int err) @trusted
157 {
158 version (Posix)
159 {
160 char[80] buf;
161 const(char)* cs;
162 version (CRuntime_Glibc)
163 {
164 cs = strerror_r(err, buf.ptr, buf.length);
165 }
166 else
167 {
168 auto errs = strerror_r(err, buf.ptr, buf.length);
169 if (errs == 0)
170 cs = buf.ptr;
171 else
172 return "Socket error " ~ to!string(err);
173 }
174
175 auto len = strlen(cs);
176
177 if (cs[len - 1] == '\n')
178 len--;
179 if (cs[len - 1] == '\r')
180 len--;
181 return cs[0 .. len].idup;
182 }
183 else
184 version (Windows)
185 {
186 return sysErrorString(err);
187 }
188 else
189 return "Socket error " ~ to!string(err);
190 }
191
192 /// Retrieve the error message for the most recently encountered network error.
193 @property string lastSocketError()
194 {
195 return formatSocketError(_lasterr());
196 }
197
198 /**
199 * Socket exceptions representing network errors reported by the operating
200 * system.
201 */
202 class SocketOSException: SocketException
203 {
204 int errorCode; /// Platform-specific error code.
205
206 ///
207 this(string msg,
208 string file = __FILE__,
209 size_t line = __LINE__,
210 Throwable next = null,
211 int err = _lasterr(),
212 string function(int) @trusted errorFormatter = &formatSocketError)
213 {
214 errorCode = err;
215
216 if (msg.length)
217 super(msg ~ ": " ~ errorFormatter(err), file, line, next);
218 else
219 super(errorFormatter(err), file, line, next);
220 }
221
222 ///
223 this(string msg,
224 Throwable next,
225 string file = __FILE__,
226 size_t line = __LINE__,
227 int err = _lasterr(),
228 string function(int) @trusted errorFormatter = &formatSocketError)
229 {
230 this(msg, file, line, next, err, errorFormatter);
231 }
232
233 ///
234 this(string msg,
235 int err,
236 string function(int) @trusted errorFormatter = &formatSocketError,
237 string file = __FILE__,
238 size_t line = __LINE__,
239 Throwable next = null)
240 {
241 this(msg, file, line, next, err, errorFormatter);
242 }
243 }
244
245 /// Socket exceptions representing invalid parameters specified by user code.
246 class SocketParameterException: SocketException
247 {
248 mixin basicExceptionCtors;
249 }
250
251 /**
252 * Socket exceptions representing attempts to use network capabilities not
253 * available on the current system.
254 */
255 class SocketFeatureException: SocketException
256 {
257 mixin basicExceptionCtors;
258 }
259
260
261 /**
262 * Returns:
263 * $(D true) if the last socket operation failed because the socket
264 * was in non-blocking mode and the operation would have blocked.
265 */
266 bool wouldHaveBlocked() nothrow @nogc
267 {
268 version (Windows)
269 return _lasterr() == WSAEWOULDBLOCK;
270 else version (Posix)
271 return _lasterr() == EAGAIN;
272 else
273 static assert(0);
274 }
275
276
277 private immutable
278 {
279 typeof(&getnameinfo) getnameinfoPointer;
280 typeof(&getaddrinfo) getaddrinfoPointer;
281 typeof(&freeaddrinfo) freeaddrinfoPointer;
282 }
283
284 shared static this() @system
285 {
286 version (Windows)
287 {
288 WSADATA wd;
289
290 // Winsock will still load if an older version is present.
291 // The version is just a request.
292 int val;
293 val = WSAStartup(0x2020, &wd);
294 if (val) // Request Winsock 2.2 for IPv6.
295 throw new SocketOSException("Unable to initialize socket library", val);
296
297 // These functions may not be present on older Windows versions.
298 // See the comment in InternetAddress.toHostNameString() for details.
299 auto ws2Lib = GetModuleHandleA("ws2_32.dll");
300 if (ws2Lib)
301 {
302 getnameinfoPointer = cast(typeof(getnameinfoPointer))
303 GetProcAddress(ws2Lib, "getnameinfo");
304 getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
305 GetProcAddress(ws2Lib, "getaddrinfo");
306 freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
307 GetProcAddress(ws2Lib, "freeaddrinfo");
308 }
309 }
310 else version (Posix)
311 {
312 getnameinfoPointer = &getnameinfo;
313 getaddrinfoPointer = &getaddrinfo;
314 freeaddrinfoPointer = &freeaddrinfo;
315 }
316 }
317
318
319 shared static ~this() @system nothrow @nogc
320 {
321 version (Windows)
322 {
323 WSACleanup();
324 }
325 }
326
327 /**
328 * The communication domain used to resolve an address.
329 */
330 enum AddressFamily: int
331 {
332 UNSPEC = AF_UNSPEC, /// Unspecified address family
333 UNIX = AF_UNIX, /// Local communication
334 INET = AF_INET, /// Internet Protocol version 4
335 IPX = AF_IPX, /// Novell IPX
336 APPLETALK = AF_APPLETALK, /// AppleTalk
337 INET6 = AF_INET6, /// Internet Protocol version 6
338 }
339
340
341 /**
342 * Communication semantics
343 */
344 enum SocketType: int
345 {
346 STREAM = SOCK_STREAM, /// Sequenced, reliable, two-way communication-based byte streams
347 DGRAM = SOCK_DGRAM, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
348 RAW = SOCK_RAW, /// Raw protocol access
349 RDM = SOCK_RDM, /// Reliably-delivered message datagrams
350 SEQPACKET = SOCK_SEQPACKET, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
351 }
352
353
354 /**
355 * Protocol
356 */
357 enum ProtocolType: int
358 {
359 IP = IPPROTO_IP, /// Internet Protocol version 4
360 ICMP = IPPROTO_ICMP, /// Internet Control Message Protocol
361 IGMP = IPPROTO_IGMP, /// Internet Group Management Protocol
362 GGP = IPPROTO_GGP, /// Gateway to Gateway Protocol
363 TCP = IPPROTO_TCP, /// Transmission Control Protocol
364 PUP = IPPROTO_PUP, /// PARC Universal Packet Protocol
365 UDP = IPPROTO_UDP, /// User Datagram Protocol
366 IDP = IPPROTO_IDP, /// Xerox NS protocol
367 RAW = IPPROTO_RAW, /// Raw IP packets
368 IPV6 = IPPROTO_IPV6, /// Internet Protocol version 6
369 }
370
371
372 /**
373 * $(D Protocol) is a class for retrieving protocol information.
374 *
375 * Example:
376 * ---
377 * auto proto = new Protocol;
378 * writeln("About protocol TCP:");
379 * if (proto.getProtocolByType(ProtocolType.TCP))
380 * {
381 * writefln(" Name: %s", proto.name);
382 * foreach (string s; proto.aliases)
383 * writefln(" Alias: %s", s);
384 * }
385 * else
386 * writeln(" No information found");
387 * ---
388 */
389 class Protocol
390 {
391 /// These members are populated when one of the following functions are called successfully:
392 ProtocolType type;
393 string name; /// ditto
394 string[] aliases; /// ditto
395
396
397 void populate(protoent* proto) @system pure nothrow
398 {
399 type = cast(ProtocolType) proto.p_proto;
400 name = to!string(proto.p_name);
401
402 int i;
403 for (i = 0;; i++)
404 {
405 if (!proto.p_aliases[i])
406 break;
407 }
408
409 if (i)
410 {
411 aliases = new string[i];
412 for (i = 0; i != aliases.length; i++)
413 {
414 aliases[i] =
415 to!string(proto.p_aliases[i]);
416 }
417 }
418 else
419 {
420 aliases = null;
421 }
422 }
423
424 /** Returns: false on failure */
425 bool getProtocolByName(in char[] name) @trusted nothrow
426 {
427 protoent* proto;
428 proto = getprotobyname(name.tempCString());
429 if (!proto)
430 return false;
431 populate(proto);
432 return true;
433 }
434
435
436 /** Returns: false on failure */
437 // Same as getprotobynumber().
438 bool getProtocolByType(ProtocolType type) @trusted nothrow
439 {
440 protoent* proto;
441 proto = getprotobynumber(type);
442 if (!proto)
443 return false;
444 populate(proto);
445 return true;
446 }
447 }
448
449
450 // Skip this test on Android because getprotobyname/number are
451 // unimplemented in bionic.
452 version (CRuntime_Bionic) {} else
453 @safe unittest
454 {
455 softUnittest({
456 Protocol proto = new Protocol;
457 assert(proto.getProtocolByType(ProtocolType.TCP));
458 //writeln("About protocol TCP:");
459 //writefln("\tName: %s", proto.name);
460 // foreach (string s; proto.aliases)
461 // {
462 // writefln("\tAlias: %s", s);
463 // }
464 assert(proto.name == "tcp");
465 assert(proto.aliases.length == 1 && proto.aliases[0] == "TCP");
466 });
467 }
468
469
470 /**
471 * $(D Service) is a class for retrieving service information.
472 *
473 * Example:
474 * ---
475 * auto serv = new Service;
476 * writeln("About service epmap:");
477 * if (serv.getServiceByName("epmap", "tcp"))
478 * {
479 * writefln(" Service: %s", serv.name);
480 * writefln(" Port: %d", serv.port);
481 * writefln(" Protocol: %s", serv.protocolName);
482 * foreach (string s; serv.aliases)
483 * writefln(" Alias: %s", s);
484 * }
485 * else
486 * writefln(" No service for epmap.");
487 * ---
488 */
489 class Service
490 {
491 /// These members are populated when one of the following functions are called successfully:
492 string name;
493 string[] aliases; /// ditto
494 ushort port; /// ditto
495 string protocolName; /// ditto
496
497
498 void populate(servent* serv) @system pure nothrow
499 {
500 name = to!string(serv.s_name);
501 port = ntohs(cast(ushort) serv.s_port);
502 protocolName = to!string(serv.s_proto);
503
504 int i;
505 for (i = 0;; i++)
506 {
507 if (!serv.s_aliases[i])
508 break;
509 }
510
511 if (i)
512 {
513 aliases = new string[i];
514 for (i = 0; i != aliases.length; i++)
515 {
516 aliases[i] =
517 to!string(serv.s_aliases[i]);
518 }
519 }
520 else
521 {
522 aliases = null;
523 }
524 }
525
526 /**
527 * If a protocol name is omitted, any protocol will be matched.
528 * Returns: false on failure.
529 */
530 bool getServiceByName(in char[] name, in char[] protocolName = null) @trusted nothrow
531 {
532 servent* serv;
533 serv = getservbyname(name.tempCString(), protocolName.tempCString());
534 if (!serv)
535 return false;
536 populate(serv);
537 return true;
538 }
539
540
541 /// ditto
542 bool getServiceByPort(ushort port, in char[] protocolName = null) @trusted nothrow
543 {
544 servent* serv;
545 serv = getservbyport(port, protocolName.tempCString());
546 if (!serv)
547 return false;
548 populate(serv);
549 return true;
550 }
551 }
552
553
554 @safe unittest
555 {
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
581 private 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 */
609 class 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 */
620 class 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 */
711 bool getHostByName(in char[] name) @trusted
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 */
761 bool getHostByAddr(in char[] addr) @trusted
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
800 /// Holds information about a socket _address retrieved by $(D getAddressInfo).
801 struct AddressInfo
802 {
803 AddressFamily family; /// Address _family
804 SocketType type; /// Socket _type
805 ProtocolType protocol; /// Protocol
806 Address address; /// Socket _address
807 string canonicalName; /// Canonical name, when $(D AddressInfoFlags.CANONNAME) is used.
808 }
809
810 /**
811 * A subset of flags supported on all platforms with getaddrinfo.
812 * Specifies option flags for $(D getAddressInfo).
813 */
814 enum AddressInfoFlags: int
815 {
816 /// The resulting addresses will be used in a call to $(D Socket.bind).
817 PASSIVE = AI_PASSIVE,
818
819 /// The canonical name is returned in $(D canonicalName) member in the first $(D AddressInfo).
820 CANONNAME = AI_CANONNAME,
821
822 /**
823 * The $(D node) parameter passed to $(D getAddressInfo) must be a numeric string.
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 */
834 private 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
850 * $(D getAddress) for compatibility with older systems.
851 *
852 * Returns: Array with one $(D AddressInfo) per socket address.
853 *
854 * Throws: $(D SocketOSException) on failure, or $(D SocketFeatureException)
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:
860 * $(UL $(LI $(D string) - service name or port number)
861 * $(LI $(D AddressInfoFlags) - option flags)
862 * $(LI $(D AddressFamily) - address family to filter by)
863 * $(LI $(D SocketType) - socket type to filter by)
864 * $(LI $(D ProtocolType) - protocol to filter by))
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 */
899 AddressInfo[] getAddressInfo(T...)(in char[] node, T options)
900 {
901 const(char)[] service = null;
902 addrinfo hints;
903 hints.ai_family = AF_UNSPEC;
904
905 foreach (option; options)
906 {
907 static if (is(typeof(option) : const(char)[]))
908 service = option;
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
944 private AddressInfo[] getAddressInfoImpl(in char[] node, in char[] service, addrinfo* hints) @system
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
1020 private ushort serviceToPort(in char[] service)
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
1037 * addresses. Uses $(D getAddressInfo) if the current system supports it,
1038 * and $(D InternetHost) otherwise.
1039 *
1040 * Returns: Array with one $(D Address) instance per socket address.
1041 *
1042 * Throws: $(D SocketOSException) on failure.
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 */
1057 Address[] getAddress(in char[] hostname, in char[] service = null)
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
1074 Address[] getAddress(in char[] hostname, ushort port)
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
1116 * attempt name resolution. Uses $(D getAddressInfo) with
1117 * $(D AddressInfoFlags.NUMERICHOST) if the current system supports it, and
1118 * $(D InternetAddress) otherwise.
1119 *
1120 * Returns: An $(D Address) instance representing specified address.
1121 *
1122 * Throws: $(D SocketException) on failure.
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 */
1151 Address parseAddress(in char[] hostaddr, in char[] service = null)
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
1160 Address parseAddress(in char[] hostaddr, ushort port)
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 /**
1197 * Class for exceptions thrown from an $(D Address).
1198 */
1199 class AddressException: SocketOSException
1200 {
1201 mixin socketOSExceptionCtors;
1202 }
1203
1204
1205 /**
1206 * $(D Address) is an abstract class for representing a socket addresses.
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 */
1229 abstract class Address
1230 {
1231 /// Returns pointer to underlying $(D sockaddr) structure.
1232 abstract @property sockaddr* name() pure nothrow @nogc;
1233 abstract @property const(sockaddr)* name() const pure nothrow @nogc; /// ditto
1234
1235 /// Returns actual size of underlying $(D sockaddr) structure.
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 *
1322 * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
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 *
1334 * Returns: The FQDN corresponding to this $(D Address), or $(D null) if
1335 * the host name did not resolve.
1336 *
1337 * Throws: $(D AddressException) on error, or $(D SocketFeatureException)
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 *
1349 * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
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 *
1361 * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
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 /**
1388 * $(D UnknownAddress) encapsulates an unknown socket address.
1389 */
1390 class UnknownAddress: Address
1391 {
1392 protected:
1393 sockaddr sa;
1394
1395
1396 public:
1397 override @property sockaddr* name()
1398 {
1399 return &sa;
1400 }
1401
1402 override @property const(sockaddr)* name() const
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 /**
1417 * $(D UnknownAddressReference) encapsulates a reference to an arbitrary
1418 * socket address.
1419 */
1420 class UnknownAddressReference: Address
1421 {
1422 protected:
1423 sockaddr* sa;
1424 socklen_t len;
1425
1426 public:
1427 /// Constructs an $(D Address) with a reference to the specified $(D sockaddr).
1428 this(sockaddr* sa, socklen_t len) pure nothrow @nogc
1429 {
1430 this.sa = sa;
1431 this.len = len;
1432 }
1433
1434 /// Constructs an $(D Address) with a copy of the specified $(D sockaddr).
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 /**
1460 * $(D InternetAddress) encapsulates an IPv4 (Internet Protocol version 4)
1461 * socket address.
1462 *
1463 * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
1464 * instead of using this class directly.
1465 */
1466 class InternetAddress: Address
1467 {
1468 protected:
1469 sockaddr_in sin;
1470
1471
1472 this() pure nothrow @nogc
1473 {
1474 }
1475
1476
1477 public:
1478 override @property sockaddr* name()
1479 {
1480 return cast(sockaddr*)&sin;
1481 }
1482
1483 override @property const(sockaddr)* name() const
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 /**
1512 * Construct a new $(D InternetAddress).
1513 * Params:
1514 * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
1515 * or a host name which will be resolved using an $(D InternetHost)
1516 * object.
1517 * port = port number, may be $(D PORT_ANY).
1518 */
1519 this(in char[] addr, ushort port)
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 /**
1537 * Construct a new $(D InternetAddress).
1538 * Params:
1539 * addr = (optional) an IPv4 address in host byte order, may be $(D ADDR_ANY).
1540 * port = port number, may be $(D PORT_ANY).
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 /**
1558 * Construct a new $(D InternetAddress).
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 {
1564 assert(addr.sin_family == AddressFamily.INET);
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 *
1583 * Returns: The FQDN corresponding to this $(D InternetAddress), or
1584 * $(D null) if the host name did not resolve.
1585 *
1586 * Throws: $(D AddressException) on error.
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,
1635 * $(D ADDR_NONE) is returned.
1636 */
1637 static uint parse(in char[] addr) @trusted nothrow
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
1694 version (SlowTests)
1695 softUnittest({
1696 // test failing reverse lookup
1697 const InternetAddress ia = new InternetAddress("127.114.111.120", 80);
1698 assert(ia.toHostNameString() is null);
1699
1700 if (getnameinfoPointer)
1701 {
1702 // test failing reverse lookup, via gethostbyaddr
1703 auto getnameinfoPointerBackup = getnameinfoPointer;
1704 getnameinfoPointer = null;
1705 scope(exit) getnameinfoPointer = getnameinfoPointerBackup;
1706
1707 assert(ia.toHostNameString() is null);
1708 }
1709 });
1710 }
1711
1712
1713 /**
1714 * $(D Internet6Address) encapsulates an IPv6 (Internet Protocol version 6)
1715 * socket address.
1716 *
1717 * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
1718 * instead of using this class directly.
1719 */
1720 class Internet6Address: Address
1721 {
1722 protected:
1723 sockaddr_in6 sin6;
1724
1725
1726 this() pure nothrow @nogc
1727 {
1728 }
1729
1730
1731 public:
1732 override @property sockaddr* name()
1733 {
1734 return cast(sockaddr*)&sin6;
1735 }
1736
1737 override @property const(sockaddr)* name() const
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 {
1752 const(ubyte)[16]* addr;
1753 static if (is(typeof(IN6ADDR_ANY)))
1754 {
1755 addr = &IN6ADDR_ANY.s6_addr;
1756 return *addr;
1757 }
1758 else static if (is(typeof(in6addr_any)))
1759 {
1760 addr = &in6addr_any.s6_addr;
1761 return *addr;
1762 }
1763 else
1764 static assert(0);
1765 }
1766
1767 /// Any IPv6 port number.
1768 enum ushort PORT_ANY = 0;
1769
1770 /// Returns the IPv6 port number.
1771 @property ushort port() const pure nothrow @nogc
1772 {
1773 return ntohs(sin6.sin6_port);
1774 }
1775
1776 /// Returns the IPv6 address.
1777 @property ubyte[16] addr() const pure nothrow @nogc
1778 {
1779 return sin6.sin6_addr.s6_addr;
1780 }
1781
1782 /**
1783 * Construct a new $(D Internet6Address).
1784 * Params:
1785 * addr = an IPv6 host address string in the form described in RFC 2373,
1786 * or a host name which will be resolved using $(D getAddressInfo).
1787 * service = (optional) service name.
1788 */
1789 this(in char[] addr, in char[] service = null) @trusted
1790 {
1791 auto results = getAddressInfo(addr, service, AddressFamily.INET6);
1792 assert(results.length && results[0].family == AddressFamily.INET6);
1793 sin6 = *cast(sockaddr_in6*) results[0].address.name;
1794 }
1795
1796 /**
1797 * Construct a new $(D Internet6Address).
1798 * Params:
1799 * addr = an IPv6 host address string in the form described in RFC 2373,
1800 * or a host name which will be resolved using $(D getAddressInfo).
1801 * port = port number, may be $(D PORT_ANY).
1802 */
1803 this(in char[] addr, ushort port)
1804 {
1805 if (port == PORT_ANY)
1806 this(addr);
1807 else
1808 this(addr, to!string(port));
1809 }
1810
1811 /**
1812 * Construct a new $(D Internet6Address).
1813 * Params:
1814 * addr = (optional) an IPv6 host address in host byte order, or
1815 * $(D ADDR_ANY).
1816 * port = port number, may be $(D PORT_ANY).
1817 */
1818 this(ubyte[16] addr, ushort port) pure nothrow @nogc
1819 {
1820 sin6.sin6_family = AddressFamily.INET6;
1821 sin6.sin6_addr.s6_addr = addr;
1822 sin6.sin6_port = htons(port);
1823 }
1824
1825 /// ditto
1826 this(ushort port) pure nothrow @nogc
1827 {
1828 sin6.sin6_family = AddressFamily.INET6;
1829 sin6.sin6_addr.s6_addr = ADDR_ANY;
1830 sin6.sin6_port = htons(port);
1831 }
1832
1833 /**
1834 * Construct a new $(D Internet6Address).
1835 * Params:
1836 * addr = A sockaddr_in6 as obtained from lower-level API calls such as getifaddrs.
1837 */
1838 this(sockaddr_in6 addr) pure nothrow @nogc
1839 {
1840 assert(addr.sin6_family == AddressFamily.INET6);
1841 sin6 = addr;
1842 }
1843
1844 /**
1845 * Parse an IPv6 host address string as described in RFC 2373, and return the
1846 * address.
1847 * Throws: $(D SocketException) on error.
1848 */
1849 static ubyte[16] parse(in char[] addr) @trusted
1850 {
1851 // Although we could use inet_pton here, it's only available on Windows
1852 // versions starting with Vista, so use getAddressInfo with NUMERICHOST
1853 // instead.
1854 auto results = getAddressInfo(addr, AddressInfoFlags.NUMERICHOST);
1855 if (results.length && results[0].family == AddressFamily.INET6)
1856 return (cast(sockaddr_in6*) results[0].address.name).sin6_addr.s6_addr;
1857 throw new AddressException("Not an IPv6 address", 0);
1858 }
1859 }
1860
1861
1862 @safe unittest
1863 {
1864 softUnittest({
1865 const Internet6Address ia = new Internet6Address("::1", 80);
1866 assert(ia.toString() == "[::1]:80");
1867 });
1868
1869 softUnittest({
1870 // test construction from a sockaddr_in6
1871 sockaddr_in6 sin;
1872
1873 sin.sin6_addr.s6_addr = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // [::1]
1874 sin.sin6_family = AddressFamily.INET6;
1875 sin.sin6_port = htons(80);
1876
1877 const Internet6Address ia = new Internet6Address(sin);
1878 assert(ia.toString() == "[::1]:80");
1879 });
1880 }
1881
1882
1883 version (StdDdoc)
1884 {
1885 static if (!is(sockaddr_un))
1886 {
1887 // This exists only to allow the constructor taking
1888 // a sockaddr_un to be compilable for documentation
1889 // on platforms that don't supply a sockaddr_un.
1890 struct sockaddr_un
1891 {
1892 }
1893 }
1894
1895 /**
1896 * $(D UnixAddress) encapsulates an address for a Unix domain socket
1897 * ($(D AF_UNIX)), i.e. a socket bound to a path name in the file system.
1898 * Available only on supported systems.
1899 *
1900 * Linux also supports an abstract address namespace, in which addresses
1901 * are independent of the file system. A socket address is abstract
1902 * iff `path` starts with a _null byte (`'\0'`). Null bytes in other
1903 * positions of an abstract address are allowed and have no special
1904 * meaning.
1905 *
1906 * Example:
1907 * ---
1908 * auto addr = new UnixAddress("/var/run/dbus/system_bus_socket");
1909 * auto abstractAddr = new UnixAddress("\0/tmp/dbus-OtHLWmCLPR");
1910 * ---
1911 *
1912 * See_Also: $(HTTP http://man7.org/linux/man-pages/man7/unix.7.html, UNIX(7))
1913 */
1914 class UnixAddress: Address
1915 {
1916 private this() pure nothrow @nogc {}
1917
1918 /// Construct a new $(D UnixAddress) from the specified path.
1919 this(in char[] path) { }
1920
1921 /**
1922 * Construct a new $(D UnixAddress).
1923 * Params:
1924 * addr = A sockaddr_un as obtained from lower-level API calls.
1925 */
1926 this(sockaddr_un addr) pure nothrow @nogc { }
1927
1928 /// Get the underlying _path.
1929 @property string path() const { return null; }
1930
1931 /// ditto
1932 override string toString() const { return null; }
1933
1934 override @property sockaddr* name() { return null; }
1935 override @property const(sockaddr)* name() const { return null; }
1936 override @property socklen_t nameLen() const { return 0; }
1937 }
1938 }
1939 else
1940 static if (is(sockaddr_un))
1941 {
1942 class UnixAddress: Address
1943 {
1944 protected:
1945 socklen_t _nameLen;
1946
1947 struct
1948 {
1949 align (1):
1950 sockaddr_un sun;
1951 char unused = '\0'; // placeholder for a terminating '\0'
1952 }
1953
1954 this() pure nothrow @nogc
1955 {
1956 sun.sun_family = AddressFamily.UNIX;
1957 sun.sun_path = '?';
1958 _nameLen = sun.sizeof;
1959 }
1960
1961 override void setNameLen(socklen_t len) @trusted
1962 {
1963 if (len > sun.sizeof)
1964 throw new SocketParameterException("Not enough socket address storage");
1965 _nameLen = len;
1966 }
1967
1968 public:
1969 override @property sockaddr* name()
1970 {
1971 return cast(sockaddr*)&sun;
1972 }
1973
1974 override @property const(sockaddr)* name() const
1975 {
1976 return cast(const(sockaddr)*)&sun;
1977 }
1978
1979 override @property socklen_t nameLen() @trusted const
1980 {
1981 return _nameLen;
1982 }
1983
1984 this(in char[] path) @trusted pure
1985 {
1986 enforce(path.length <= sun.sun_path.sizeof, new SocketParameterException("Path too long"));
1987 sun.sun_family = AddressFamily.UNIX;
1988 sun.sun_path.ptr[0 .. path.length] = (cast(byte[]) path)[];
1989 _nameLen = cast(socklen_t)
1990 {
1991 auto len = sockaddr_un.init.sun_path.offsetof + path.length;
1992 // Pathname socket address must be terminated with '\0'
1993 // which must be included in the address length.
1994 if (sun.sun_path.ptr[0])
1995 {
1996 sun.sun_path.ptr[path.length] = 0;
1997 ++len;
1998 }
1999 return len;
2000 }();
2001 }
2002
2003 this(sockaddr_un addr) pure nothrow @nogc
2004 {
2005 assert(addr.sun_family == AddressFamily.UNIX);
2006 sun = addr;
2007 }
2008
2009 @property string path() @trusted const pure
2010 {
2011 auto len = _nameLen - sockaddr_un.init.sun_path.offsetof;
2012 // For pathname socket address we need to strip off the terminating '\0'
2013 if (sun.sun_path.ptr[0])
2014 --len;
2015 return (cast(const(char)*) sun.sun_path.ptr)[0 .. len].idup;
2016 }
2017
2018 override string toString() const pure
2019 {
2020 return path;
2021 }
2022 }
2023
2024 @safe unittest
2025 {
2026 import core.stdc.stdio : remove;
2027 import std.file : deleteme;
2028
2029 immutable ubyte[] data = [1, 2, 3, 4];
2030 Socket[2] pair;
2031
2032 auto names = [ deleteme ~ "-unix-socket" ];
2033 version (linux)
2034 names ~= "\0" ~ deleteme ~ "-abstract\0unix\0socket";
2035 foreach (name; names)
2036 {
2037 auto address = new UnixAddress(name);
2038
2039 auto listener = new Socket(AddressFamily.UNIX, SocketType.STREAM);
2040 scope(exit) listener.close();
2041 listener.bind(address);
2042 scope(exit) () @trusted { if (name[0]) remove(name.tempCString()); } ();
2043 assert(listener.localAddress.toString == name);
2044
2045 listener.listen(1);
2046
2047 pair[0] = new Socket(AddressFamily.UNIX, SocketType.STREAM);
2048 scope(exit) listener.close();
2049
2050 pair[0].connect(address);
2051 scope(exit) pair[0].close();
2052
2053 pair[1] = listener.accept();
2054 scope(exit) pair[1].close();
2055
2056 pair[0].send(data);
2057
2058 auto buf = new ubyte[data.length];
2059 pair[1].receive(buf);
2060 assert(buf == data);
2061 }
2062 }
2063 }
2064
2065
2066 /**
2067 * Class for exceptions thrown by $(D Socket.accept).
2068 */
2069 class SocketAcceptException: SocketOSException
2070 {
2071 mixin socketOSExceptionCtors;
2072 }
2073
2074 /// How a socket is shutdown:
2075 enum SocketShutdown: int
2076 {
2077 RECEIVE = SD_RECEIVE, /// socket receives are disallowed
2078 SEND = SD_SEND, /// socket sends are disallowed
2079 BOTH = SD_BOTH, /// both RECEIVE and SEND
2080 }
2081
2082
2083 /// Flags may be OR'ed together:
2084 enum SocketFlags: int
2085 {
2086 NONE = 0, /// no flags specified
2087
2088 OOB = MSG_OOB, /// out-of-band stream data
2089 PEEK = MSG_PEEK, /// peek at incoming data without removing it from the queue, only for receiving
2090 DONTROUTE = MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending
2091 }
2092
2093
2094 private mixin template FieldProxy(string target, string field)
2095 {
2096 mixin(`
2097 @property typeof(`~target~`) `~field~`() const pure nothrow @nogc
2098 {
2099 return `~target~`;
2100 }
2101
2102 /// ditto
2103 @property typeof(`~target~`) `~field~`(typeof(`~target~`) value) pure nothrow @nogc
2104 {
2105 return `~target~` = value;
2106 }
2107 `);
2108 }
2109
2110
2111 /// Duration timeout value.
2112 struct TimeVal
2113 {
2114 _ctimeval ctimeval;
2115 alias tv_sec_t = typeof(ctimeval.tv_sec);
2116 alias tv_usec_t = typeof(ctimeval.tv_usec);
2117
2118 version (StdDdoc) // no DDoc for string mixins, can't forward individual fields
2119 {
2120 tv_sec_t seconds; /// Number of _seconds.
2121 tv_usec_t microseconds; /// Number of additional _microseconds.
2122 }
2123 else
2124 {
2125 // D interface
2126 mixin FieldProxy!(`ctimeval.tv_sec`, `seconds`);
2127 mixin FieldProxy!(`ctimeval.tv_usec`, `microseconds`);
2128 }
2129 }
2130
2131
2132 /**
2133 * A collection of sockets for use with $(D Socket.select).
2134 *
2135 * $(D SocketSet) wraps the platform $(D fd_set) type. However, unlike
2136 * $(D fd_set), $(D SocketSet) is not statically limited to $(D FD_SETSIZE)
2137 * or any other limit, and grows as needed.
2138 */
2139 class SocketSet
2140 {
2141 private:
2142 version (Windows)
2143 {
2144 // On Windows, fd_set is an array of socket handles,
2145 // following a word containing the fd_set instance size.
2146 // We use one dynamic array for everything, and use its first
2147 // element(s) for the count.
2148
2149 alias fd_set_count_type = typeof(fd_set.init.fd_count);
2150 alias fd_set_type = typeof(fd_set.init.fd_array[0]);
2151 static assert(fd_set_type.sizeof == socket_t.sizeof);
2152
2153 // Number of fd_set_type elements at the start of our array that are
2154 // used for the socket count and alignment
2155
2156 enum FD_SET_OFFSET = fd_set.fd_array.offsetof / fd_set_type.sizeof;
2157 static assert(FD_SET_OFFSET);
2158 static assert(fd_set.fd_count.offsetof % fd_set_type.sizeof == 0);
2159
2160 fd_set_type[] set;
2161
2162 void resize(size_t size) pure nothrow
2163 {
2164 set.length = FD_SET_OFFSET + size;
2165 }
2166
2167 ref inout(fd_set_count_type) count() @trusted @property inout pure nothrow @nogc
2168 {
2169 assert(set.length);
2170 return *cast(inout(fd_set_count_type)*)set.ptr;
2171 }
2172
2173 size_t capacity() @property const pure nothrow @nogc
2174 {
2175 return set.length - FD_SET_OFFSET;
2176 }
2177
2178 inout(socket_t)[] fds() @trusted inout @property pure nothrow @nogc
2179 {
2180 return cast(inout(socket_t)[])set[FD_SET_OFFSET .. FD_SET_OFFSET+count];
2181 }
2182 }
2183 else
2184 version (Posix)
2185 {
2186 // On Posix, fd_set is a bit array. We assume that the fd_set
2187 // type (declared in core.sys.posix.sys.select) is a structure
2188 // containing a single field, a static array.
2189
2190 static assert(fd_set.tupleof.length == 1);
2191
2192 // This is the type used in the fd_set array.
2193 // Using the type of the correct size is important for big-endian
2194 // architectures.
2195
2196 alias fd_set_type = typeof(fd_set.init.tupleof[0][0]);
2197
2198 // Number of file descriptors represented by one fd_set_type
2199
2200 enum FD_NFDBITS = 8 * fd_set_type.sizeof;
2201
2202 static fd_set_type mask(uint n) pure nothrow @nogc
2203 {
2204 return (cast(fd_set_type) 1) << (n % FD_NFDBITS);
2205 }
2206
2207 // Array size to fit that many sockets
2208
2209 static size_t lengthFor(size_t size) pure nothrow @nogc
2210 {
2211 return (size + (FD_NFDBITS-1)) / FD_NFDBITS;
2212 }
2213
2214 fd_set_type[] set;
2215
2216 void resize(size_t size) pure nothrow
2217 {
2218 set.length = lengthFor(size);
2219 }
2220
2221 // Make sure we can fit that many sockets
2222
2223 void setMinCapacity(size_t size) pure nothrow
2224 {
2225 auto length = lengthFor(size);
2226 if (set.length < length)
2227 set.length = length;
2228 }
2229
2230 size_t capacity() @property const pure nothrow @nogc
2231 {
2232 return set.length * FD_NFDBITS;
2233 }
2234
2235 int maxfd;
2236 }
2237 else
2238 static assert(false, "Unknown platform");
2239
2240 public:
2241
2242 /**
2243 * Create a SocketSet with a specific initial capacity (defaults to
2244 * $(D FD_SETSIZE), the system's default capacity).
2245 */
2246 this(size_t size = FD_SETSIZE) pure nothrow
2247 {
2248 resize(size);
2249 reset();
2250 }
2251
2252 /// Reset the $(D SocketSet) so that there are 0 $(D Socket)s in the collection.
2253 void reset() pure nothrow @nogc
2254 {
2255 version (Windows)
2256 count = 0;
2257 else
2258 {
2259 set[] = 0;
2260 maxfd = -1;
2261 }
2262 }
2263
2264
2265 void add(socket_t s) @trusted pure nothrow
2266 {
2267 version (Windows)
2268 {
2269 if (count == capacity)
2270 {
2271 set.length *= 2;
2272 set.length = set.capacity;
2273 }
2274 ++count;
2275 fds[$-1] = s;
2276 }
2277 else
2278 {
2279 auto index = s / FD_NFDBITS;
2280 auto length = set.length;
2281 if (index >= length)
2282 {
2283 while (index >= length)
2284 length *= 2;
2285 set.length = length;
2286 set.length = set.capacity;
2287 }
2288 set[index] |= mask(s);
2289 if (maxfd < s)
2290 maxfd = s;
2291 }
2292 }
2293
2294 /**
2295 * Add a $(D Socket) to the collection.
2296 * The socket must not already be in the collection.
2297 */
2298 void add(Socket s) pure nothrow
2299 {
2300 add(s.sock);
2301 }
2302
2303 void remove(socket_t s) pure nothrow
2304 {
2305 version (Windows)
2306 {
2307 import std.algorithm.searching : countUntil;
2308 auto fds = fds;
2309 auto p = fds.countUntil(s);
2310 if (p >= 0)
2311 fds[p] = fds[--count];
2312 }
2313 else
2314 {
2315 auto index = s / FD_NFDBITS;
2316 if (index >= set.length)
2317 return;
2318 set[index] &= ~mask(s);
2319 // note: adjusting maxfd would require scanning the set, not worth it
2320 }
2321 }
2322
2323
2324 /**
2325 * Remove this $(D Socket) from the collection.
2326 * Does nothing if the socket is not in the collection already.
2327 */
2328 void remove(Socket s) pure nothrow
2329 {
2330 remove(s.sock);
2331 }
2332
2333 int isSet(socket_t s) const pure nothrow @nogc
2334 {
2335 version (Windows)
2336 {
2337 import std.algorithm.searching : canFind;
2338 return fds.canFind(s) ? 1 : 0;
2339 }
2340 else
2341 {
2342 if (s > maxfd)
2343 return 0;
2344 auto index = s / FD_NFDBITS;
2345 return (set[index] & mask(s)) ? 1 : 0;
2346 }
2347 }
2348
2349
2350 /// Return nonzero if this $(D Socket) is in the collection.
2351 int isSet(Socket s) const pure nothrow @nogc
2352 {
2353 return isSet(s.sock);
2354 }
2355
2356
2357 /**
2358 * Returns:
2359 * The current capacity of this $(D SocketSet). The exact
2360 * meaning of the return value varies from platform to platform.
2361 *
2362 * Note:
2363 * Since D 2.065, this value does not indicate a
2364 * restriction, and $(D SocketSet) will grow its capacity as
2365 * needed automatically.
2366 */
2367 @property uint max() const pure nothrow @nogc
2368 {
2369 return cast(uint) capacity;
2370 }
2371
2372
2373 fd_set* toFd_set() @trusted pure nothrow @nogc
2374 {
2375 return cast(fd_set*) set.ptr;
2376 }
2377
2378
2379 int selectn() const pure nothrow @nogc
2380 {
2381 version (Windows)
2382 {
2383 return count;
2384 }
2385 else version (Posix)
2386 {
2387 return maxfd + 1;
2388 }
2389 }
2390 }
2391
2392 @safe unittest
2393 {
2394 auto fds = cast(socket_t[])
2395 [cast(socket_t) 1, 2, 0, 1024, 17, 42, 1234, 77, 77+32, 77+64];
2396 auto set = new SocketSet();
2397 foreach (fd; fds) assert(!set.isSet(fd));
2398 foreach (fd; fds) set.add(fd);
2399 foreach (fd; fds) assert(set.isSet(fd));
2400
2401 // Make sure SocketSet reimplements fd_set correctly
2402 auto fdset = set.toFd_set();
2403 foreach (fd; fds[0]..cast(socket_t)(fds[$-1]+1))
2404 assert(cast(bool) set.isSet(fd) == cast(bool)(() @trusted => FD_ISSET(fd, fdset))());
2405
2406 foreach (fd; fds)
2407 {
2408 assert(set.isSet(fd));
2409 set.remove(fd);
2410 assert(!set.isSet(fd));
2411 }
2412 }
2413
2414 @safe unittest
2415 {
2416 softUnittest({
2417 enum PAIRS = 768;
2418 version (Posix)
2419 () @trusted
2420 {
2421 enum LIMIT = 2048;
2422 static assert(LIMIT > PAIRS*2);
2423 import core.sys.posix.sys.resource;
2424 rlimit fileLimit;
2425 getrlimit(RLIMIT_NOFILE, &fileLimit);
2426 assert(fileLimit.rlim_max > LIMIT, "Open file hard limit too low");
2427 fileLimit.rlim_cur = LIMIT;
2428 setrlimit(RLIMIT_NOFILE, &fileLimit);
2429 } ();
2430
2431 Socket[2][PAIRS] pairs;
2432 foreach (ref pair; pairs)
2433 pair = socketPair();
2434 scope(exit)
2435 {
2436 foreach (pair; pairs)
2437 {
2438 pair[0].close();
2439 pair[1].close();
2440 }
2441 }
2442
2443 import std.random;
2444 auto rng = Xorshift(42);
2445 pairs[].randomShuffle(rng);
2446
2447 auto readSet = new SocketSet();
2448 auto writeSet = new SocketSet();
2449 auto errorSet = new SocketSet();
2450
2451 foreach (testPair; pairs)
2452 {
2453 void fillSets()
2454 {
2455 readSet.reset();
2456 writeSet.reset();
2457 errorSet.reset();
2458 foreach (ref pair; pairs)
2459 foreach (s; pair[])
2460 {
2461 readSet.add(s);
2462 writeSet.add(s);
2463 errorSet.add(s);
2464 }
2465 }
2466
2467 fillSets();
2468 auto n = Socket.select(readSet, writeSet, errorSet);
2469 assert(n == PAIRS*2); // All in writeSet
2470 assert(writeSet.isSet(testPair[0]));
2471 assert(writeSet.isSet(testPair[1]));
2472 assert(!readSet.isSet(testPair[0]));
2473 assert(!readSet.isSet(testPair[1]));
2474 assert(!errorSet.isSet(testPair[0]));
2475 assert(!errorSet.isSet(testPair[1]));
2476
2477 ubyte[1] b;
2478 testPair[0].send(b[]);
2479 fillSets();
2480 n = Socket.select(readSet, null, null);
2481 assert(n == 1); // testPair[1]
2482 assert(readSet.isSet(testPair[1]));
2483 assert(!readSet.isSet(testPair[0]));
2484 testPair[1].receive(b[]);
2485 }
2486 });
2487 }
2488
2489 @safe unittest // Issue 14012, 14013
2490 {
2491 auto set = new SocketSet(1);
2492 assert(set.max >= 0);
2493
2494 enum LIMIT = 4096;
2495 foreach (n; 0 .. LIMIT)
2496 set.add(cast(socket_t) n);
2497 assert(set.max >= LIMIT);
2498 }
2499
2500 /// The level at which a socket option is defined:
2501 enum SocketOptionLevel: int
2502 {
2503 SOCKET = SOL_SOCKET, /// Socket level
2504 IP = ProtocolType.IP, /// Internet Protocol version 4 level
2505 ICMP = ProtocolType.ICMP, /// Internet Control Message Protocol level
2506 IGMP = ProtocolType.IGMP, /// Internet Group Management Protocol level
2507 GGP = ProtocolType.GGP, /// Gateway to Gateway Protocol level
2508 TCP = ProtocolType.TCP, /// Transmission Control Protocol level
2509 PUP = ProtocolType.PUP, /// PARC Universal Packet Protocol level
2510 UDP = ProtocolType.UDP, /// User Datagram Protocol level
2511 IDP = ProtocolType.IDP, /// Xerox NS protocol level
2512 RAW = ProtocolType.RAW, /// Raw IP packet level
2513 IPV6 = ProtocolType.IPV6, /// Internet Protocol version 6 level
2514 }
2515
2516 /// _Linger information for use with SocketOption.LINGER.
2517 struct Linger
2518 {
2519 _clinger clinger;
2520
2521 version (StdDdoc) // no DDoc for string mixins, can't forward individual fields
2522 {
2523 private alias l_onoff_t = typeof(_clinger.init.l_onoff );
2524 private alias l_linger_t = typeof(_clinger.init.l_linger);
2525 l_onoff_t on; /// Nonzero for _on.
2526 l_linger_t time; /// Linger _time.
2527 }
2528 else
2529 {
2530 // D interface
2531 mixin FieldProxy!(`clinger.l_onoff`, `on`);
2532 mixin FieldProxy!(`clinger.l_linger`, `time`);
2533 }
2534 }
2535
2536 /// Specifies a socket option:
2537 enum SocketOption: int
2538 {
2539 DEBUG = SO_DEBUG, /// Record debugging information
2540 BROADCAST = SO_BROADCAST, /// Allow transmission of broadcast messages
2541 REUSEADDR = SO_REUSEADDR, /// Allow local reuse of address
2542 LINGER = SO_LINGER, /// Linger on close if unsent data is present
2543 OOBINLINE = SO_OOBINLINE, /// Receive out-of-band data in band
2544 SNDBUF = SO_SNDBUF, /// Send buffer size
2545 RCVBUF = SO_RCVBUF, /// Receive buffer size
2546 DONTROUTE = SO_DONTROUTE, /// Do not route
2547 SNDTIMEO = SO_SNDTIMEO, /// Send timeout
2548 RCVTIMEO = SO_RCVTIMEO, /// Receive timeout
2549 ERROR = SO_ERROR, /// Retrieve and clear error status
2550 KEEPALIVE = SO_KEEPALIVE, /// Enable keep-alive packets
2551 ACCEPTCONN = SO_ACCEPTCONN, /// Listen
2552 RCVLOWAT = SO_RCVLOWAT, /// Minimum number of input bytes to process
2553 SNDLOWAT = SO_SNDLOWAT, /// Minimum number of output bytes to process
2554 TYPE = SO_TYPE, /// Socket type
2555
2556 // SocketOptionLevel.TCP:
2557 TCP_NODELAY = .TCP_NODELAY, /// Disable the Nagle algorithm for send coalescing
2558
2559 // SocketOptionLevel.IPV6:
2560 IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, /// IP unicast hop limit
2561 IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, /// IP multicast interface
2562 IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, /// IP multicast loopback
2563 IPV6_MULTICAST_HOPS = .IPV6_MULTICAST_HOPS, /// IP multicast hops
2564 IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, /// Add an IP group membership
2565 IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, /// Drop an IP group membership
2566 IPV6_V6ONLY = .IPV6_V6ONLY, /// Treat wildcard bind as AF_INET6-only
2567 }
2568
2569
2570 /**
2571 * $(D Socket) is a class that creates a network communication endpoint using
2572 * the Berkeley sockets interface.
2573 */
2574 class Socket
2575 {
2576 private:
2577 socket_t sock;
2578 AddressFamily _family;
2579
2580 version (Windows)
2581 bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking.
2582
2583 // The WinSock timeouts seem to be effectively skewed by a constant
2584 // offset of about half a second (value in milliseconds). This has
2585 // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7
2586 // and Windows Server 2008 R2 boxes. The unittest below tests this
2587 // behavior.
2588 enum WINSOCK_TIMEOUT_SKEW = 500;
2589
2590 @safe unittest
2591 {
2592 version (SlowTests)
2593 softUnittest({
2594 import std.datetime;
2595 import std.typecons;
2596
2597 enum msecs = 1000;
2598 auto pair = socketPair();
2599 auto sock = pair[0];
2600 sock.setOption(SocketOptionLevel.SOCKET,
2601 SocketOption.RCVTIMEO, dur!"msecs"(msecs));
2602
2603 auto sw = StopWatch(Yes.autoStart);
2604 ubyte[1] buf;
2605 sock.receive(buf);
2606 sw.stop();
2607
2608 Duration readBack = void;
2609 sock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack);
2610
2611 assert(readBack.total!"msecs" == msecs);
2612 assert(sw.peek().msecs > msecs-100 && sw.peek().msecs < msecs+100);
2613 });
2614 }
2615
2616 void setSock(socket_t handle)
2617 {
2618 assert(handle != socket_t.init);
2619 sock = handle;
2620
2621 // Set the option to disable SIGPIPE on send() if the platform
2622 // has it (e.g. on OS X).
2623 static if (is(typeof(SO_NOSIGPIPE)))
2624 {
2625 setOption(SocketOptionLevel.SOCKET, cast(SocketOption) SO_NOSIGPIPE, true);
2626 }
2627 }
2628
2629
2630 // For use with accepting().
2631 protected this() pure nothrow @nogc
2632 {
2633 }
2634
2635
2636 public:
2637
2638 /**
2639 * Create a blocking socket. If a single protocol type exists to support
2640 * this socket type within the address family, the $(D ProtocolType) may be
2641 * omitted.
2642 */
2643 this(AddressFamily af, SocketType type, ProtocolType protocol) @trusted
2644 {
2645 _family = af;
2646 auto handle = cast(socket_t) socket(af, type, protocol);
2647 if (handle == socket_t.init)
2648 throw new SocketOSException("Unable to create socket");
2649 setSock(handle);
2650 }
2651
2652 /// ditto
2653 this(AddressFamily af, SocketType type)
2654 {
2655 /* A single protocol exists to support this socket type within the
2656 * protocol family, so the ProtocolType is assumed.
2657 */
2658 this(af, type, cast(ProtocolType) 0); // Pseudo protocol number.
2659 }
2660
2661
2662 /// ditto
2663 this(AddressFamily af, SocketType type, in char[] protocolName) @trusted
2664 {
2665 protoent* proto;
2666 proto = getprotobyname(protocolName.tempCString());
2667 if (!proto)
2668 throw new SocketOSException("Unable to find the protocol");
2669 this(af, type, cast(ProtocolType) proto.p_proto);
2670 }
2671
2672
2673 /**
2674 * Create a blocking socket using the parameters from the specified
2675 * $(D AddressInfo) structure.
2676 */
2677 this(in AddressInfo info)
2678 {
2679 this(info.family, info.type, info.protocol);
2680 }
2681
2682 /// Use an existing socket handle.
2683 this(socket_t sock, AddressFamily af) pure nothrow @nogc
2684 {
2685 assert(sock != socket_t.init);
2686 this.sock = sock;
2687 this._family = af;
2688 }
2689
2690
2691 ~this() nothrow @nogc
2692 {
2693 close();
2694 }
2695
2696
2697 /// Get underlying socket handle.
2698 @property socket_t handle() const pure nothrow @nogc
2699 {
2700 return sock;
2701 }
2702
2703 /**
2704 * Get/set socket's blocking flag.
2705 *
2706 * When a socket is blocking, calls to receive(), accept(), and send()
2707 * will block and wait for data/action.
2708 * A non-blocking socket will immediately return instead of blocking.
2709 */
2710 @property bool blocking() @trusted const nothrow @nogc
2711 {
2712 version (Windows)
2713 {
2714 return _blocking;
2715 }
2716 else version (Posix)
2717 {
2718 return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK);
2719 }
2720 }
2721
2722 /// ditto
2723 @property void blocking(bool byes) @trusted
2724 {
2725 version (Windows)
2726 {
2727 uint num = !byes;
2728 if (_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
2729 goto err;
2730 _blocking = byes;
2731 }
2732 else version (Posix)
2733 {
2734 int x = fcntl(sock, F_GETFL, 0);
2735 if (-1 == x)
2736 goto err;
2737 if (byes)
2738 x &= ~O_NONBLOCK;
2739 else
2740 x |= O_NONBLOCK;
2741 if (-1 == fcntl(sock, F_SETFL, x))
2742 goto err;
2743 }
2744 return; // Success.
2745
2746 err:
2747 throw new SocketOSException("Unable to set socket blocking");
2748 }
2749
2750
2751 /// Get the socket's address family.
2752 @property AddressFamily addressFamily()
2753 {
2754 return _family;
2755 }
2756
2757 /// Property that indicates if this is a valid, alive socket.
2758 @property bool isAlive() @trusted const
2759 {
2760 int type;
2761 socklen_t typesize = cast(socklen_t) type.sizeof;
2762 return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
2763 }
2764
2765 /// Associate a local address with this socket.
2766 void bind(Address addr) @trusted
2767 {
2768 if (_SOCKET_ERROR == .bind(sock, addr.name, addr.nameLen))
2769 throw new SocketOSException("Unable to bind socket");
2770 }
2771
2772 /**
2773 * Establish a connection. If the socket is blocking, connect waits for
2774 * the connection to be made. If the socket is nonblocking, connect
2775 * returns immediately and the connection attempt is still in progress.
2776 */
2777 void connect(Address to) @trusted
2778 {
2779 if (_SOCKET_ERROR == .connect(sock, to.name, to.nameLen))
2780 {
2781 int err;
2782 err = _lasterr();
2783
2784 if (!blocking)
2785 {
2786 version (Windows)
2787 {
2788 if (WSAEWOULDBLOCK == err)
2789 return;
2790 }
2791 else version (Posix)
2792 {
2793 if (EINPROGRESS == err)
2794 return;
2795 }
2796 else
2797 {
2798 static assert(0);
2799 }
2800 }
2801 throw new SocketOSException("Unable to connect socket", err);
2802 }
2803 }
2804
2805 /**
2806 * Listen for an incoming connection. $(D bind) must be called before you
2807 * can $(D listen). The $(D backlog) is a request of how many pending
2808 * incoming connections are queued until $(D accept)ed.
2809 */
2810 void listen(int backlog) @trusted
2811 {
2812 if (_SOCKET_ERROR == .listen(sock, backlog))
2813 throw new SocketOSException("Unable to listen on socket");
2814 }
2815
2816 /**
2817 * Called by $(D accept) when a new $(D Socket) must be created for a new
2818 * connection. To use a derived class, override this method and return an
2819 * instance of your class. The returned $(D Socket)'s handle must not be
2820 * set; $(D Socket) has a protected constructor $(D this()) to use in this
2821 * situation.
2822 *
2823 * Override to use a derived class.
2824 * The returned socket's handle must not be set.
2825 */
2826 protected Socket accepting() pure nothrow
2827 {
2828 return new Socket;
2829 }
2830
2831 /**
2832 * Accept an incoming connection. If the socket is blocking, $(D accept)
2833 * waits for a connection request. Throws $(D SocketAcceptException) if
2834 * unable to _accept. See $(D accepting) for use with derived classes.
2835 */
2836 Socket accept() @trusted
2837 {
2838 auto newsock = cast(socket_t).accept(sock, null, null);
2839 if (socket_t.init == newsock)
2840 throw new SocketAcceptException("Unable to accept socket connection");
2841
2842 Socket newSocket;
2843 try
2844 {
2845 newSocket = accepting();
2846 assert(newSocket.sock == socket_t.init);
2847
2848 newSocket.setSock(newsock);
2849 version (Windows)
2850 newSocket._blocking = _blocking; //inherits blocking mode
2851 newSocket._family = _family; //same family
2852 }
2853 catch (Throwable o)
2854 {
2855 _close(newsock);
2856 throw o;
2857 }
2858
2859 return newSocket;
2860 }
2861
2862 /// Disables sends and/or receives.
2863 void shutdown(SocketShutdown how) @trusted nothrow @nogc
2864 {
2865 .shutdown(sock, cast(int) how);
2866 }
2867
2868
2869 private static void _close(socket_t sock) @system nothrow @nogc
2870 {
2871 version (Windows)
2872 {
2873 .closesocket(sock);
2874 }
2875 else version (Posix)
2876 {
2877 .close(sock);
2878 }
2879 }
2880
2881
2882 /**
2883 * Immediately drop any connections and release socket resources.
2884 * Calling $(D shutdown) before $(D close) is recommended for
2885 * connection-oriented sockets. The $(D Socket) object is no longer
2886 * usable after $(D close).
2887 * Calling shutdown() before this is recommended
2888 * for connection-oriented sockets.
2889 */
2890 void close() @trusted nothrow @nogc
2891 {
2892 _close(sock);
2893 sock = socket_t.init;
2894 }
2895
2896
2897 /**
2898 * Returns: the local machine's host name
2899 */
2900 static @property string hostName() @trusted // getter
2901 {
2902 char[256] result; // Host names are limited to 255 chars.
2903 if (_SOCKET_ERROR == .gethostname(result.ptr, result.length))
2904 throw new SocketOSException("Unable to obtain host name");
2905 return to!string(result.ptr);
2906 }
2907
2908 /// Remote endpoint $(D Address).
2909 @property Address remoteAddress() @trusted
2910 {
2911 Address addr = createAddress();
2912 socklen_t nameLen = addr.nameLen;
2913 if (_SOCKET_ERROR == .getpeername(sock, addr.name, &nameLen))
2914 throw new SocketOSException("Unable to obtain remote socket address");
2915 addr.setNameLen(nameLen);
2916 assert(addr.addressFamily == _family);
2917 return addr;
2918 }
2919
2920 /// Local endpoint $(D Address).
2921 @property Address localAddress() @trusted
2922 {
2923 Address addr = createAddress();
2924 socklen_t nameLen = addr.nameLen;
2925 if (_SOCKET_ERROR == .getsockname(sock, addr.name, &nameLen))
2926 throw new SocketOSException("Unable to obtain local socket address");
2927 addr.setNameLen(nameLen);
2928 assert(addr.addressFamily == _family);
2929 return addr;
2930 }
2931
2932 /**
2933 * Send or receive error code. See $(D wouldHaveBlocked),
2934 * $(D lastSocketError) and $(D Socket.getErrorText) for obtaining more
2935 * information about the error.
2936 */
2937 enum int ERROR = _SOCKET_ERROR;
2938
2939 private static int capToInt(size_t size) nothrow @nogc
2940 {
2941 // Windows uses int instead of size_t for length arguments.
2942 // Luckily, the send/recv functions make no guarantee that
2943 // all the data is sent, so we use that to send at most
2944 // int.max bytes.
2945 return size > size_t(int.max) ? int.max : cast(int) size;
2946 }
2947
2948 /**
2949 * Send data on the connection. If the socket is blocking and there is no
2950 * buffer space left, $(D send) waits.
2951 * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on
2952 * failure.
2953 */
2954 ptrdiff_t send(const(void)[] buf, SocketFlags flags) @trusted
2955 {
2956 static if (is(typeof(MSG_NOSIGNAL)))
2957 {
2958 flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
2959 }
2960 version (Windows)
2961 auto sent = .send(sock, buf.ptr, capToInt(buf.length), cast(int) flags);
2962 else
2963 auto sent = .send(sock, buf.ptr, buf.length, cast(int) flags);
2964 return sent;
2965 }
2966
2967 /// ditto
2968 ptrdiff_t send(const(void)[] buf)
2969 {
2970 return send(buf, SocketFlags.NONE);
2971 }
2972
2973 /**
2974 * Send data to a specific destination Address. If the destination address is
2975 * not specified, a connection must have been made and that address is used.
2976 * If the socket is blocking and there is no buffer space left, $(D sendTo) waits.
2977 * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on
2978 * failure.
2979 */
2980 ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to) @trusted
2981 {
2982 static if (is(typeof(MSG_NOSIGNAL)))
2983 {
2984 flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
2985 }
2986 version (Windows)
2987 return .sendto(
2988 sock, buf.ptr, capToInt(buf.length),
2989 cast(int) flags, to.name, to.nameLen
2990 );
2991 else
2992 return .sendto(sock, buf.ptr, buf.length, cast(int) flags, to.name, to.nameLen);
2993 }
2994
2995 /// ditto
2996 ptrdiff_t sendTo(const(void)[] buf, Address to)
2997 {
2998 return sendTo(buf, SocketFlags.NONE, to);
2999 }
3000
3001
3002 //assumes you connect()ed
3003 /// ditto
3004 ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags) @trusted
3005 {
3006 static if (is(typeof(MSG_NOSIGNAL)))
3007 {
3008 flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
3009 }
3010 version (Windows)
3011 return .sendto(sock, buf.ptr, capToInt(buf.length), cast(int) flags, null, 0);
3012 else
3013 return .sendto(sock, buf.ptr, buf.length, cast(int) flags, null, 0);
3014 }
3015
3016
3017 //assumes you connect()ed
3018 /// ditto
3019 ptrdiff_t sendTo(const(void)[] buf)
3020 {
3021 return sendTo(buf, SocketFlags.NONE);
3022 }
3023
3024
3025 /**
3026 * Receive data on the connection. If the socket is blocking, $(D receive)
3027 * waits until there is data to be received.
3028 * Returns: The number of bytes actually received, $(D 0) if the remote side
3029 * has closed the connection, or $(D Socket.ERROR) on failure.
3030 */
3031 ptrdiff_t receive(void[] buf, SocketFlags flags) @trusted
3032 {
3033 version (Windows) // Does not use size_t
3034 {
3035 return buf.length
3036 ? .recv(sock, buf.ptr, capToInt(buf.length), cast(int) flags)
3037 : 0;
3038 }
3039 else
3040 {
3041 return buf.length
3042 ? .recv(sock, buf.ptr, buf.length, cast(int) flags)
3043 : 0;
3044 }
3045 }
3046
3047 /// ditto
3048 ptrdiff_t receive(void[] buf)
3049 {
3050 return receive(buf, SocketFlags.NONE);
3051 }
3052
3053 /**
3054 * Receive data and get the remote endpoint $(D Address).
3055 * If the socket is blocking, $(D receiveFrom) waits until there is data to
3056 * be received.
3057 * Returns: The number of bytes actually received, $(D 0) if the remote side
3058 * has closed the connection, or $(D Socket.ERROR) on failure.
3059 */
3060 ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from) @trusted
3061 {
3062 if (!buf.length) //return 0 and don't think the connection closed
3063 return 0;
3064 if (from is null || from.addressFamily != _family)
3065 from = createAddress();
3066 socklen_t nameLen = from.nameLen;
3067 version (Windows)
3068 {
3069 auto read = .recvfrom(sock, buf.ptr, capToInt(buf.length), cast(int) flags, from.name, &nameLen);
3070 from.setNameLen(nameLen);
3071 assert(from.addressFamily == _family);
3072 // if (!read) //connection closed
3073 return read;
3074 }
3075 else
3076 {
3077 auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int) flags, from.name, &nameLen);
3078 from.setNameLen(nameLen);
3079 assert(from.addressFamily == _family);
3080 // if (!read) //connection closed
3081 return read;
3082 }
3083 }
3084
3085
3086 /// ditto
3087 ptrdiff_t receiveFrom(void[] buf, ref Address from)
3088 {
3089 return receiveFrom(buf, SocketFlags.NONE, from);
3090 }
3091
3092
3093 //assumes you connect()ed
3094 /// ditto
3095 ptrdiff_t receiveFrom(void[] buf, SocketFlags flags) @trusted
3096 {
3097 if (!buf.length) //return 0 and don't think the connection closed
3098 return 0;
3099 version (Windows)
3100 {
3101 auto read = .recvfrom(sock, buf.ptr, capToInt(buf.length), cast(int) flags, null, null);
3102 // if (!read) //connection closed
3103 return read;
3104 }
3105 else
3106 {
3107 auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int) flags, null, null);
3108 // if (!read) //connection closed
3109 return read;
3110 }
3111 }
3112
3113
3114 //assumes you connect()ed
3115 /// ditto
3116 ptrdiff_t receiveFrom(void[] buf)
3117 {
3118 return receiveFrom(buf, SocketFlags.NONE);
3119 }
3120
3121
3122 /**
3123 * Get a socket option.
3124 * Returns: The number of bytes written to $(D result).
3125 * The length, in bytes, of the actual result - very different from getsockopt()
3126 */
3127 int getOption(SocketOptionLevel level, SocketOption option, void[] result) @trusted
3128 {
3129 socklen_t len = cast(socklen_t) result.length;
3130 if (_SOCKET_ERROR == .getsockopt(sock, cast(int) level, cast(int) option, result.ptr, &len))
3131 throw new SocketOSException("Unable to get socket option");
3132 return len;
3133 }
3134
3135
3136 /// Common case of getting integer and boolean options.
3137 int getOption(SocketOptionLevel level, SocketOption option, out int32_t result) @trusted
3138 {
3139 return getOption(level, option, (&result)[0 .. 1]);
3140 }
3141
3142
3143 /// Get the linger option.
3144 int getOption(SocketOptionLevel level, SocketOption option, out Linger result) @trusted
3145 {
3146 //return getOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
3147 return getOption(level, option, (&result.clinger)[0 .. 1]);
3148 }
3149
3150 /// Get a timeout (duration) option.
3151 void getOption(SocketOptionLevel level, SocketOption option, out Duration result) @trusted
3152 {
3153 enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO,
3154 new SocketParameterException("Not a valid timeout option: " ~ to!string(option)));
3155 // WinSock returns the timeout values as a milliseconds DWORD,
3156 // while Linux and BSD return a timeval struct.
3157 version (Windows)
3158 {
3159 int msecs;
3160 getOption(level, option, (&msecs)[0 .. 1]);
3161 if (option == SocketOption.RCVTIMEO)
3162 msecs += WINSOCK_TIMEOUT_SKEW;
3163 result = dur!"msecs"(msecs);
3164 }
3165 else version (Posix)
3166 {
3167 TimeVal tv;
3168 getOption(level, option, (&tv.ctimeval)[0 .. 1]);
3169 result = dur!"seconds"(tv.seconds) + dur!"usecs"(tv.microseconds);
3170 }
3171 else static assert(false);
3172 }
3173
3174 /// Set a socket option.
3175 void setOption(SocketOptionLevel level, SocketOption option, void[] value) @trusted
3176 {
3177 if (_SOCKET_ERROR == .setsockopt(sock, cast(int) level,
3178 cast(int) option, value.ptr, cast(uint) value.length))
3179 throw new SocketOSException("Unable to set socket option");
3180 }
3181
3182
3183 /// Common case for setting integer and boolean options.
3184 void setOption(SocketOptionLevel level, SocketOption option, int32_t value) @trusted
3185 {
3186 setOption(level, option, (&value)[0 .. 1]);
3187 }
3188
3189
3190 /// Set the linger option.
3191 void setOption(SocketOptionLevel level, SocketOption option, Linger value) @trusted
3192 {
3193 //setOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
3194 setOption(level, option, (&value.clinger)[0 .. 1]);
3195 }
3196
3197 /**
3198 * Sets a timeout (duration) option, i.e. $(D SocketOption.SNDTIMEO) or
3199 * $(D RCVTIMEO). Zero indicates no timeout.
3200 *
3201 * In a typical application, you might also want to consider using
3202 * a non-blocking socket instead of setting a timeout on a blocking one.
3203 *
3204 * Note: While the receive timeout setting is generally quite accurate
3205 * on *nix systems even for smaller durations, there are two issues to
3206 * be aware of on Windows: First, although undocumented, the effective
3207 * timeout duration seems to be the one set on the socket plus half
3208 * a second. $(D setOption()) tries to compensate for that, but still,
3209 * timeouts under 500ms are not possible on Windows. Second, be aware
3210 * that the actual amount of time spent until a blocking call returns
3211 * randomly varies on the order of 10ms.
3212 *
3213 * Params:
3214 * level = The level at which a socket option is defined.
3215 * option = Either $(D SocketOption.SNDTIMEO) or $(D SocketOption.RCVTIMEO).
3216 * value = The timeout duration to set. Must not be negative.
3217 *
3218 * Throws: $(D SocketException) if setting the options fails.
3219 *
3220 * Example:
3221 * ---
3222 * import std.datetime;
3223 * import std.typecons;
3224 * auto pair = socketPair();
3225 * scope(exit) foreach (s; pair) s.close();
3226 *
3227 * // Set a receive timeout, and then wait at one end of
3228 * // the socket pair, knowing that no data will arrive.
3229 * pair[0].setOption(SocketOptionLevel.SOCKET,
3230 * SocketOption.RCVTIMEO, dur!"seconds"(1));
3231 *
3232 * auto sw = StopWatch(Yes.autoStart);
3233 * ubyte[1] buffer;
3234 * pair[0].receive(buffer);
3235 * writefln("Waited %s ms until the socket timed out.",
3236 * sw.peek.msecs);
3237 * ---
3238 */
3239 void setOption(SocketOptionLevel level, SocketOption option, Duration value) @trusted
3240 {
3241 enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO,
3242 new SocketParameterException("Not a valid timeout option: " ~ to!string(option)));
3243
3244 enforce(value >= dur!"hnsecs"(0), new SocketParameterException(
3245 "Timeout duration must not be negative."));
3246
3247 version (Windows)
3248 {
3249 import std.algorithm.comparison : max;
3250
3251 auto msecs = to!int(value.total!"msecs");
3252 if (msecs != 0 && option == SocketOption.RCVTIMEO)
3253 msecs = max(1, msecs - WINSOCK_TIMEOUT_SKEW);
3254 setOption(level, option, msecs);
3255 }
3256 else version (Posix)
3257 {
3258 _ctimeval tv;
3259 value.split!("seconds", "usecs")(tv.tv_sec, tv.tv_usec);
3260 setOption(level, option, (&tv)[0 .. 1]);
3261 }
3262 else static assert(false);
3263 }
3264
3265 /**
3266 * Get a text description of this socket's error status, and clear the
3267 * socket's error status.
3268 */
3269 string getErrorText()
3270 {
3271 int32_t error;
3272 getOption(SocketOptionLevel.SOCKET, SocketOption.ERROR, error);
3273 return formatSocketError(error);
3274 }
3275
3276 /**
3277 * Enables TCP keep-alive with the specified parameters.
3278 *
3279 * Params:
3280 * time = Number of seconds with no activity until the first
3281 * keep-alive packet is sent.
3282 * interval = Number of seconds between when successive keep-alive
3283 * packets are sent if no acknowledgement is received.
3284 *
3285 * Throws: $(D SocketOSException) if setting the options fails, or
3286 * $(D SocketFeatureException) if setting keep-alive parameters is
3287 * unsupported on the current platform.
3288 */
3289 void setKeepAlive(int time, int interval) @trusted
3290 {
3291 version (Windows)
3292 {
3293 tcp_keepalive options;
3294 options.onoff = 1;
3295 options.keepalivetime = time * 1000;
3296 options.keepaliveinterval = interval * 1000;
3297 uint cbBytesReturned;
3298 enforce(WSAIoctl(sock, SIO_KEEPALIVE_VALS,
3299 &options, options.sizeof,
3300 null, 0,
3301 &cbBytesReturned, null, null) == 0,
3302 new SocketOSException("Error setting keep-alive"));
3303 }
3304 else
3305 static if (is(typeof(TCP_KEEPIDLE)) && is(typeof(TCP_KEEPINTVL)))
3306 {
3307 setOption(SocketOptionLevel.TCP, cast(SocketOption) TCP_KEEPIDLE, time);
3308 setOption(SocketOptionLevel.TCP, cast(SocketOption) TCP_KEEPINTVL, interval);
3309 setOption(SocketOptionLevel.SOCKET, SocketOption.KEEPALIVE, true);
3310 }
3311 else
3312 throw new SocketFeatureException("Setting keep-alive options " ~
3313 "is not supported on this platform");
3314 }
3315
3316 /**
3317 * Wait for a socket to change status. A wait timeout of $(REF Duration, core, time) or
3318 * $(D TimeVal), may be specified; if a timeout is not specified or the
3319 * $(D TimeVal) is $(D null), the maximum timeout is used. The $(D TimeVal)
3320 * timeout has an unspecified value when $(D select) returns.
3321 * Returns: The number of sockets with status changes, $(D 0) on timeout,
3322 * or $(D -1) on interruption. If the return value is greater than $(D 0),
3323 * the $(D SocketSets) are updated to only contain the sockets having status
3324 * changes. For a connecting socket, a write status change means the
3325 * connection is established and it's able to send. For a listening socket,
3326 * a read status change means there is an incoming connection request and
3327 * it's able to accept.
3328 *
3329 * `SocketSet`'s updated to include only those sockets which an event occured.
3330 * For a `connect()`ing socket, writeability means connected.
3331 * For a `listen()`ing socket, readability means listening
3332 * `Winsock`; possibly internally limited to 64 sockets per set.
3333 *
3334 * Returns:
3335 * the number of events, 0 on timeout, or -1 on interruption
3336 */
3337 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, Duration timeout) @trusted
3338 {
3339 auto vals = timeout.split!("seconds", "usecs")();
3340 TimeVal tv;
3341 tv.seconds = cast(tv.tv_sec_t ) vals.seconds;
3342 tv.microseconds = cast(tv.tv_usec_t) vals.usecs;
3343 return select(checkRead, checkWrite, checkError, &tv);
3344 }
3345
3346 /// ditto
3347 //maximum timeout
3348 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
3349 {
3350 return select(checkRead, checkWrite, checkError, null);
3351 }
3352
3353 /// Ditto
3354 static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeVal* timeout) @trusted
3355 in
3356 {
3357 //make sure none of the SocketSet's are the same object
3358 if (checkRead)
3359 {
3360 assert(checkRead !is checkWrite);
3361 assert(checkRead !is checkError);
3362 }
3363 if (checkWrite)
3364 {
3365 assert(checkWrite !is checkError);
3366 }
3367 }
3368 body
3369 {
3370 fd_set* fr, fw, fe;
3371 int n = 0;
3372
3373 version (Windows)
3374 {
3375 // Windows has a problem with empty fd_set`s that aren't null.
3376 fr = checkRead && checkRead.count ? checkRead.toFd_set() : null;
3377 fw = checkWrite && checkWrite.count ? checkWrite.toFd_set() : null;
3378 fe = checkError && checkError.count ? checkError.toFd_set() : null;
3379 }
3380 else
3381 {
3382 if (checkRead)
3383 {
3384 fr = checkRead.toFd_set();
3385 n = checkRead.selectn();
3386 }
3387 else
3388 {
3389 fr = null;
3390 }
3391
3392 if (checkWrite)
3393 {
3394 fw = checkWrite.toFd_set();
3395 int _n;
3396 _n = checkWrite.selectn();
3397 if (_n > n)
3398 n = _n;
3399 }
3400 else
3401 {
3402 fw = null;
3403 }
3404
3405 if (checkError)
3406 {
3407 fe = checkError.toFd_set();
3408 int _n;
3409 _n = checkError.selectn();
3410 if (_n > n)
3411 n = _n;
3412 }
3413 else
3414 {
3415 fe = null;
3416 }
3417
3418 // Make sure the sets' capacity matches, to avoid select reading
3419 // out of bounds just because one set was bigger than another
3420 if (checkRead ) checkRead .setMinCapacity(n);
3421 if (checkWrite) checkWrite.setMinCapacity(n);
3422 if (checkError) checkError.setMinCapacity(n);
3423 }
3424
3425 int result = .select(n, fr, fw, fe, &timeout.ctimeval);
3426
3427 version (Windows)
3428 {
3429 if (_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR)
3430 return -1;
3431 }
3432 else version (Posix)
3433 {
3434 if (_SOCKET_ERROR == result && errno == EINTR)
3435 return -1;
3436 }
3437 else
3438 {
3439 static assert(0);
3440 }
3441
3442 if (_SOCKET_ERROR == result)
3443 throw new SocketOSException("Socket select error");
3444
3445 return result;
3446 }
3447
3448
3449 /**
3450 * Can be overridden to support other addresses.
3451 * Returns: a new `Address` object for the current address family.
3452 */
3453 protected Address createAddress() pure nothrow
3454 {
3455 Address result;
3456 switch (_family)
3457 {
3458 static if (is(sockaddr_un))
3459 {
3460 case AddressFamily.UNIX:
3461 result = new UnixAddress;
3462 break;
3463 }
3464
3465 case AddressFamily.INET:
3466 result = new InternetAddress;
3467 break;
3468
3469 case AddressFamily.INET6:
3470 result = new Internet6Address;
3471 break;
3472
3473 default:
3474 result = new UnknownAddress;
3475 }
3476 return result;
3477 }
3478
3479 }
3480
3481
3482 /// $(D TcpSocket) is a shortcut class for a TCP Socket.
3483 class TcpSocket: Socket
3484 {
3485 /// Constructs a blocking TCP Socket.
3486 this(AddressFamily family)
3487 {
3488 super(family, SocketType.STREAM, ProtocolType.TCP);
3489 }
3490
3491 /// Constructs a blocking IPv4 TCP Socket.
3492 this()
3493 {
3494 this(AddressFamily.INET);
3495 }
3496
3497
3498 //shortcut
3499 /// Constructs a blocking TCP Socket and connects to an $(D Address).
3500 this(Address connectTo)
3501 {
3502 this(connectTo.addressFamily);
3503 connect(connectTo);
3504 }
3505 }
3506
3507
3508 /// $(D UdpSocket) is a shortcut class for a UDP Socket.
3509 class UdpSocket: Socket
3510 {
3511 /// Constructs a blocking UDP Socket.
3512 this(AddressFamily family)
3513 {
3514 super(family, SocketType.DGRAM, ProtocolType.UDP);
3515 }
3516
3517
3518 /// Constructs a blocking IPv4 UDP Socket.
3519 this()
3520 {
3521 this(AddressFamily.INET);
3522 }
3523 }
3524
3525 // Issue 16514
3526 @safe unittest
3527 {
3528 class TestSocket : Socket
3529 {
3530 override
3531 {
3532 const pure nothrow @nogc @property @safe socket_t handle() { assert(0); }
3533 const nothrow @nogc @property @trusted bool blocking() { assert(0); }
3534 @property @trusted void blocking(bool byes) { assert(0); }
3535 @property @safe AddressFamily addressFamily() { assert(0); }
3536 const @property @trusted bool isAlive() { assert(0); }
3537 @trusted void bind(Address addr) { assert(0); }
3538 @trusted void connect(Address to) { assert(0); }
3539 @trusted void listen(int backlog) { assert(0); }
3540 protected pure nothrow @safe Socket accepting() { assert(0); }
3541 @trusted Socket accept() { assert(0); }
3542 nothrow @nogc @trusted void shutdown(SocketShutdown how) { assert(0); }
3543 nothrow @nogc @trusted void close() { assert(0); }
3544 @property @trusted Address remoteAddress() { assert(0); }
3545 @property @trusted Address localAddress() { assert(0); }
3546 @trusted ptrdiff_t send(const(void)[] buf, SocketFlags flags) { assert(0); }
3547 @safe ptrdiff_t send(const(void)[] buf) { assert(0); }
3548 @trusted ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to) { assert(0); }
3549 @safe ptrdiff_t sendTo(const(void)[] buf, Address to) { assert(0); }
3550 @trusted ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags) { assert(0); }
3551 @safe ptrdiff_t sendTo(const(void)[] buf) { assert(0); }
3552 @trusted ptrdiff_t receive(void[] buf, SocketFlags flags) { assert(0); }
3553 @safe ptrdiff_t receive(void[] buf) { assert(0); }
3554 @trusted ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from) { assert(0); }
3555 @safe ptrdiff_t receiveFrom(void[] buf, ref Address from) { assert(0); }
3556 @trusted ptrdiff_t receiveFrom(void[] buf, SocketFlags flags) { assert(0); }
3557 @safe ptrdiff_t receiveFrom(void[] buf) { assert(0); }
3558 @trusted int getOption(SocketOptionLevel level, SocketOption option, void[] result) { assert(0); }
3559 @trusted int getOption(SocketOptionLevel level, SocketOption option, out int32_t result) { assert(0); }
3560 @trusted int getOption(SocketOptionLevel level, SocketOption option, out Linger result) { assert(0); }
3561 @trusted void getOption(SocketOptionLevel level, SocketOption option, out Duration result) { assert(0); }
3562 @trusted void setOption(SocketOptionLevel level, SocketOption option, void[] value) { assert(0); }
3563 @trusted void setOption(SocketOptionLevel level, SocketOption option, int32_t value) { assert(0); }
3564 @trusted void setOption(SocketOptionLevel level, SocketOption option, Linger value) { assert(0); }
3565 @trusted void setOption(SocketOptionLevel level, SocketOption option, Duration value) { assert(0); }
3566 @safe string getErrorText() { assert(0); }
3567 @trusted void setKeepAlive(int time, int interval) { assert(0); }
3568 protected pure nothrow @safe Address createAddress() { assert(0); }
3569 }
3570 }
3571 }
3572
3573 /**
3574 * Creates a pair of connected sockets.
3575 *
3576 * The two sockets are indistinguishable.
3577 *
3578 * Throws: $(D SocketException) if creation of the sockets fails.
3579 */
3580 Socket[2] socketPair() @trusted
3581 {
3582 version (Posix)
3583 {
3584 int[2] socks;
3585 if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1)
3586 throw new SocketOSException("Unable to create socket pair");
3587
3588 Socket toSocket(size_t id)
3589 {
3590 auto s = new Socket;
3591 s.setSock(cast(socket_t) socks[id]);
3592 s._family = AddressFamily.UNIX;
3593 return s;
3594 }
3595
3596 return [toSocket(0), toSocket(1)];
3597 }
3598 else version (Windows)
3599 {
3600 // We do not have socketpair() on Windows, just manually create a
3601 // pair of sockets connected over some localhost port.
3602 Socket[2] result;
3603
3604 auto listener = new TcpSocket();
3605 listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
3606 listener.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY));
3607 auto addr = listener.localAddress;
3608 listener.listen(1);
3609
3610 result[0] = new TcpSocket(addr);
3611 result[1] = listener.accept();
3612
3613 listener.close();
3614 return result;
3615 }
3616 else
3617 static assert(false);
3618 }
3619
3620 ///
3621 @safe unittest
3622 {
3623 immutable ubyte[] data = [1, 2, 3, 4];
3624 auto pair = socketPair();
3625 scope(exit) foreach (s; pair) s.close();
3626
3627 pair[0].send(data);
3628
3629 auto buf = new ubyte[data.length];
3630 pair[1].receive(buf);
3631 assert(buf == data);
3632 }
3633