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