1 // Written in the D programming language
4 Copyright (C) 2004-2011 Christopher E. Miller
6 Boost Software License - Version 1.0 - August 17th, 2003
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:
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.
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.
33 Thanks to Benjamin Herr for his assistance.
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)
47 import core
.stdc
.stdint
, core
.stdc
.stdlib
, core
.stdc
.string
, std
.conv
, std
.string
;
49 import core
.stdc
.config
;
50 import core
.time
: dur
, Duration
;
53 import std
.internal
.cstring
;
63 pragma (lib
, "ws2_32.lib");
64 pragma (lib
, "wsock32.lib");
67 import core
.sys
.windows
.windows
, std
.windows
.syserror
;
68 public import core
.sys
.windows
.winsock2
;
69 private alias _ctimeval
= core
.sys
.windows
.winsock2
.timeval
;
70 private alias _clinger
= core
.sys
.windows
.winsock2
.linger
;
72 enum socket_t
: SOCKET
{ INVALID_SOCKET
}
73 private const int _SOCKET_ERROR
= SOCKET_ERROR
;
76 private int _lasterr() nothrow @nogc
78 return WSAGetLastError();
92 import core
.sys
.posix
.arpa
.inet
;
93 import core
.sys
.posix
.fcntl
;
94 import core
.sys
.posix
.netdb
;
95 import core
.sys
.posix
.netinet
.in_
;
96 import core
.sys
.posix
.netinet
.tcp
;
97 import core
.sys
.posix
.sys
.select
;
98 import core
.sys
.posix
.sys
.socket
;
99 import core
.sys
.posix
.sys
.time
;
100 import core
.sys
.posix
.sys
.un
: sockaddr_un
;
101 import core
.sys
.posix
.unistd
;
102 private alias _ctimeval
= core
.sys
.posix
.sys
.time
.timeval
;
103 private alias _clinger
= core
.sys
.posix
.sys
.socket
.linger
;
105 import core
.stdc
.errno
;
107 enum socket_t
: int32_t
{ init
= -1 }
108 private const int _SOCKET_ERROR
= -1;
112 SD_RECEIVE
= SHUT_RD
,
117 private int _lasterr() nothrow @nogc
124 static assert(0); // No socket support yet.
129 static assert(is(uint32_t
== uint));
130 static assert(is(uint16_t
== ushort));
132 import std
.stdio
: writefln
;
134 // Print a message on exception instead of failing the unittest.
135 private void softUnittest(void delegate() @safe test, int line
= __LINE__
) @trusted
141 writefln(" --- std.socket(%d) test fails depending on environment ---", line
);
142 writefln(" (%s)", e
);
147 /// Base exception thrown by $(D std.socket).
148 class SocketException
: Exception
150 mixin basicExceptionCtors
;
155 * Needs to be public so that SocketOSException can be thrown outside of
156 * std.socket (since it uses it as a default argument), but it probably doesn't
157 * need to actually show up in the docs, since there's not really any public
158 * need for it outside of being a default argument.
160 string
formatSocketError(int err
) @trusted
166 version (CRuntime_Glibc
)
168 cs
= strerror_r(err
, buf
.ptr
, buf
.length
);
172 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
176 return "Socket error " ~ to
!string(err
);
178 else version (FreeBSD
)
180 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
184 return "Socket error " ~ to
!string(err
);
186 else version (NetBSD
)
188 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
192 return "Socket error " ~ to
!string(err
);
194 else version (Solaris
)
196 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
200 return "Socket error " ~ to
!string(err
);
202 else version (CRuntime_Bionic
)
204 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
208 return "Socket error " ~ to
!string(err
);
213 auto len
= strlen(cs
);
215 if (cs
[len
- 1] == '\n')
217 if (cs
[len
- 1] == '\r')
219 return cs
[0 .. len
].idup
;
224 return sysErrorString(err
);
227 return "Socket error " ~ to
!string(err
);
230 /// Retrieve the error message for the most recently encountered network error.
231 @property string
lastSocketError()
233 return formatSocketError(_lasterr());
237 * Socket exceptions representing network errors reported by the operating
240 class SocketOSException
: SocketException
242 int errorCode
; /// Platform-specific error code.
246 string file
= __FILE__
,
247 size_t line
= __LINE__
,
248 Throwable next
= null,
249 int err
= _lasterr(),
250 string
function(int) @trusted errorFormatter
= &formatSocketError
)
255 super(msg
~ ": " ~ errorFormatter(err
), file
, line
, next
);
257 super(errorFormatter(err
), file
, line
, next
);
263 string file
= __FILE__
,
264 size_t line
= __LINE__
,
265 int err
= _lasterr(),
266 string
function(int) @trusted errorFormatter
= &formatSocketError
)
268 this(msg
, file
, line
, next
, err
, errorFormatter
);
274 string
function(int) @trusted errorFormatter
= &formatSocketError
,
275 string file
= __FILE__
,
276 size_t line
= __LINE__
,
277 Throwable next
= null)
279 this(msg
, file
, line
, next
, err
, errorFormatter
);
283 /// Socket exceptions representing invalid parameters specified by user code.
284 class SocketParameterException
: SocketException
286 mixin basicExceptionCtors
;
290 * Socket exceptions representing attempts to use network capabilities not
291 * available on the current system.
293 class SocketFeatureException
: SocketException
295 mixin basicExceptionCtors
;
301 * $(D true) if the last socket operation failed because the socket
302 * was in non-blocking mode and the operation would have blocked.
304 bool wouldHaveBlocked() nothrow @nogc
307 return _lasterr() == WSAEWOULDBLOCK
;
309 return _lasterr() == EAGAIN
;
317 typeof(&getnameinfo
) getnameinfoPointer
;
318 typeof(&getaddrinfo
) getaddrinfoPointer
;
319 typeof(&freeaddrinfo
) freeaddrinfoPointer
;
322 shared static this() @system
328 // Winsock will still load if an older version is present.
329 // The version is just a request.
331 val
= WSAStartup(0x2020, &wd
);
332 if (val
) // Request Winsock 2.2 for IPv6.
333 throw new SocketOSException("Unable to initialize socket library", val
);
335 // These functions may not be present on older Windows versions.
336 // See the comment in InternetAddress.toHostNameString() for details.
337 auto ws2Lib
= GetModuleHandleA("ws2_32.dll");
340 getnameinfoPointer
= cast(typeof(getnameinfoPointer
))
341 GetProcAddress(ws2Lib
, "getnameinfo");
342 getaddrinfoPointer
= cast(typeof(getaddrinfoPointer
))
343 GetProcAddress(ws2Lib
, "getaddrinfo");
344 freeaddrinfoPointer
= cast(typeof(freeaddrinfoPointer
))
345 GetProcAddress(ws2Lib
, "freeaddrinfo");
350 getnameinfoPointer
= &getnameinfo
;
351 getaddrinfoPointer
= &getaddrinfo
;
352 freeaddrinfoPointer
= &freeaddrinfo
;
357 shared static ~this() @system nothrow @nogc
366 * The communication domain used to resolve an address.
368 enum AddressFamily
: int
370 UNSPEC
= AF_UNSPEC
, /// Unspecified address family
371 UNIX
= AF_UNIX
, /// Local communication
372 INET
= AF_INET
, /// Internet Protocol version 4
373 IPX
= AF_IPX
, /// Novell IPX
374 APPLETALK
= AF_APPLETALK
, /// AppleTalk
375 INET6
= AF_INET6
, /// Internet Protocol version 6
380 * Communication semantics
384 STREAM
= SOCK_STREAM
, /// Sequenced, reliable, two-way communication-based byte streams
385 DGRAM
= SOCK_DGRAM
, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
386 RAW
= SOCK_RAW
, /// Raw protocol access
387 RDM
= SOCK_RDM
, /// Reliably-delivered message datagrams
388 SEQPACKET
= SOCK_SEQPACKET
, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
395 enum ProtocolType
: int
397 IP
= IPPROTO_IP
, /// Internet Protocol version 4
398 ICMP
= IPPROTO_ICMP
, /// Internet Control Message Protocol
399 IGMP
= IPPROTO_IGMP
, /// Internet Group Management Protocol
400 GGP
= IPPROTO_GGP
, /// Gateway to Gateway Protocol
401 TCP
= IPPROTO_TCP
, /// Transmission Control Protocol
402 PUP
= IPPROTO_PUP
, /// PARC Universal Packet Protocol
403 UDP
= IPPROTO_UDP
, /// User Datagram Protocol
404 IDP
= IPPROTO_IDP
, /// Xerox NS protocol
405 RAW
= IPPROTO_RAW
, /// Raw IP packets
406 IPV6
= IPPROTO_IPV6
, /// Internet Protocol version 6
411 * $(D Protocol) is a class for retrieving protocol information.
415 * auto proto = new Protocol;
416 * writeln("About protocol TCP:");
417 * if (proto.getProtocolByType(ProtocolType.TCP))
419 * writefln(" Name: %s", proto.name);
420 * foreach (string s; proto.aliases)
421 * writefln(" Alias: %s", s);
424 * writeln(" No information found");
429 /// These members are populated when one of the following functions are called successfully:
431 string name
; /// ditto
432 string
[] aliases
; /// ditto
435 void populate(protoent
* proto
) @system pure nothrow
437 type
= cast(ProtocolType
) proto
.p_proto
;
438 name
= to
!string(proto
.p_name
);
443 if (!proto
.p_aliases
[i
])
449 aliases
= new string
[i
];
450 for (i
= 0; i
!= aliases
.length
; i
++)
453 to
!string(proto
.p_aliases
[i
]);
462 /** Returns: false on failure */
463 bool getProtocolByName(in char[] name
) @trusted nothrow
466 proto
= getprotobyname(name
.tempCString());
474 /** Returns: false on failure */
475 // Same as getprotobynumber().
476 bool getProtocolByType(ProtocolType type
) @trusted nothrow
479 proto
= getprotobynumber(type
);
488 // Skip this test on Android because getprotobyname/number are
489 // unimplemented in bionic.
490 version (CRuntime_Bionic
) {} else
494 Protocol proto
= new Protocol
;
495 assert(proto
.getProtocolByType(ProtocolType
.TCP
));
496 //writeln("About protocol TCP:");
497 //writefln("\tName: %s", proto.name);
498 // foreach (string s; proto.aliases)
500 // writefln("\tAlias: %s", s);
502 assert(proto
.name
== "tcp");
503 assert(proto
.aliases
.length
== 1 && proto
.aliases
[0] == "TCP");
509 * $(D Service) is a class for retrieving service information.
513 * auto serv = new Service;
514 * writeln("About service epmap:");
515 * if (serv.getServiceByName("epmap", "tcp"))
517 * writefln(" Service: %s", serv.name);
518 * writefln(" Port: %d", serv.port);
519 * writefln(" Protocol: %s", serv.protocolName);
520 * foreach (string s; serv.aliases)
521 * writefln(" Alias: %s", s);
524 * writefln(" No service for epmap.");
529 /// These members are populated when one of the following functions are called successfully:
531 string
[] aliases
; /// ditto
532 ushort port
; /// ditto
533 string protocolName
; /// ditto
536 void populate(servent
* serv
) @system pure nothrow
538 name
= to
!string(serv
.s_name
);
539 port
= ntohs(cast(ushort) serv
.s_port
);
540 protocolName
= to
!string(serv
.s_proto
);
545 if (!serv
.s_aliases
[i
])
551 aliases
= new string
[i
];
552 for (i
= 0; i
!= aliases
.length
; i
++)
555 to
!string(serv
.s_aliases
[i
]);
565 * If a protocol name is omitted, any protocol will be matched.
566 * Returns: false on failure.
568 bool getServiceByName(in char[] name
, in char[] protocolName
= null) @trusted nothrow
571 serv
= getservbyname(name
.tempCString(), protocolName
.tempCString());
580 bool getServiceByPort(ushort port
, in char[] protocolName
= null) @trusted nothrow
583 serv
= getservbyport(port
, protocolName
.tempCString());
595 Service serv
= new Service
;
596 if (serv
.getServiceByName("epmap", "tcp"))
598 // writefln("About service epmap:");
599 // writefln("\tService: %s", serv.name);
600 // writefln("\tPort: %d", serv.port);
601 // writefln("\tProtocol: %s", serv.protocolName);
602 // foreach (string s; serv.aliases)
604 // writefln("\tAlias: %s", s);
606 // For reasons unknown this is loc-srv on Wine and epmap on Windows
607 assert(serv
.name
== "loc-srv" || serv
.name
== "epmap", serv
.name
);
608 assert(serv
.port
== 135);
609 assert(serv
.protocolName
== "tcp");
613 writefln("No service for epmap.");
619 private mixin template socketOSExceptionCtors()
622 this(string msg
, string file
= __FILE__
, size_t line
= __LINE__
,
623 Throwable next
= null, int err
= _lasterr())
625 super(msg
, file
, line
, next
, err
);
629 this(string msg
, Throwable next
, string file
= __FILE__
,
630 size_t line
= __LINE__
, int err
= _lasterr())
632 super(msg
, next
, file
, line
, err
);
636 this(string msg
, int err
, string file
= __FILE__
, size_t line
= __LINE__
,
637 Throwable next
= null)
639 super(msg
, next
, file
, line
, err
);
645 * Class for exceptions thrown from an `InternetHost`.
647 class HostException
: SocketOSException
649 mixin socketOSExceptionCtors
;
653 * `InternetHost` is a class for resolving IPv4 addresses.
655 * Consider using `getAddress`, `parseAddress` and `Address` methods
656 * instead of using this class directly.
660 /// These members are populated when one of the following functions are called successfully:
662 string
[] aliases
; /// ditto
663 uint[] addrList
; /// ditto
666 void validHostent(in hostent
* he
)
668 if (he
.h_addrtype
!= cast(int) AddressFamily
.INET || he
.h_length
!= 4)
669 throw new HostException("Address family mismatch");
673 void populate(hostent
* he
) @system pure nothrow
678 name
= to
!string(he
.h_name
);
689 aliases
= new string
[i
];
690 for (i
= 0; i
!= aliases
.length
; i
++)
693 to
!string(he
.h_aliases
[i
]);
703 p
= he
.h_addr_list
[i
];
710 addrList
= new uint[i
];
711 for (i
= 0; i
!= addrList
.length
; i
++)
713 addrList
[i
] = ntohl(*(cast(uint*) he
.h_addr_list
[i
]));
722 private bool getHostNoSync(string opMixin
, T
)(T param
) @system
733 alias getHost
= getHostNoSync
;
736 // posix systems use global state for return value, so we
737 // must synchronize across all threads
738 private bool getHost(string opMixin
, T
)(T param
) @system
740 synchronized(this.classinfo
)
741 return getHostNoSync
!(opMixin
, T
)(param
);
747 * Returns: false if unable to resolve.
749 bool getHostByName(in char[] name
) @trusted
751 static if (is(typeof(gethostbyname_r
)))
753 return getHostNoSync
!q
{
756 ubyte[256] buffer_v
= void;
757 auto buffer
= buffer_v
[];
758 auto param_zTmp
= param
.tempCString();
763 if (gethostbyname_r(param_zTmp
, he
, buffer
.ptr
, buffer
.length
, &he
, &errno
) == ERANGE
)
764 buffer
.length
= buffer
.length
* 2;
773 auto he
= gethostbyname(param
.tempCString());
779 * Resolve IPv4 address number.
782 * addr = The IPv4 address to resolve, in host byte order.
784 * false if unable to resolve.
786 bool getHostByAddr(uint addr
) @trusted
789 auto x
= htonl(param
);
790 auto he
= gethostbyaddr(&x
, 4, cast(int) AddressFamily
.INET
);
795 * Same as previous, but addr is an IPv4 address string in the
796 * dotted-decimal form $(I a.b.c.d).
797 * Returns: false if unable to resolve.
799 bool getHostByAddr(in char[] addr
) @trusted
802 auto x
= inet_addr(param
.tempCString());
803 enforce(x
!= INADDR_NONE
,
804 new SocketParameterException("Invalid IPv4 address"));
805 auto he
= gethostbyaddr(&x
, 4, cast(int) AddressFamily
.INET
);
813 InternetHost ih
= new InternetHost
;
815 ih
.getHostByAddr(0x7F_00_00_01);
816 assert(ih
.addrList
[0] == 0x7F_00_00_01);
817 ih
.getHostByAddr("127.0.0.1");
818 assert(ih
.addrList
[0] == 0x7F_00_00_01);
820 if (!ih
.getHostByName("www.digitalmars.com"))
821 return; // don't fail if not connected to internet
823 assert(ih
.addrList
.length
);
824 InternetAddress ia
= new InternetAddress(ih
.addrList
[0], InternetAddress
.PORT_ANY
);
825 assert(ih
.name
== "www.digitalmars.com" || ih
.name
== "digitalmars.com",
828 assert(ih
.getHostByAddr(ih
.addrList
[0]));
829 string getHostNameFromInt
= ih
.name
.dup
;
831 assert(ih
.getHostByAddr(ia
.toAddrString()));
832 string getHostNameFromStr
= ih
.name
.dup
;
834 assert(getHostNameFromInt
== getHostNameFromStr
);
838 /// Holds information about a socket _address retrieved by $(D getAddressInfo).
841 AddressFamily family
; /// Address _family
842 SocketType type
; /// Socket _type
843 ProtocolType protocol
; /// Protocol
844 Address address
; /// Socket _address
845 string canonicalName
; /// Canonical name, when $(D AddressInfoFlags.CANONNAME) is used.
849 * A subset of flags supported on all platforms with getaddrinfo.
850 * Specifies option flags for $(D getAddressInfo).
852 enum AddressInfoFlags
: int
854 /// The resulting addresses will be used in a call to $(D Socket.bind).
855 PASSIVE
= AI_PASSIVE
,
857 /// The canonical name is returned in $(D canonicalName) member in the first $(D AddressInfo).
858 CANONNAME
= AI_CANONNAME
,
861 * The $(D node) parameter passed to $(D getAddressInfo) must be a numeric string.
862 * This will suppress any potentially lengthy network host address lookups.
864 NUMERICHOST
= AI_NUMERICHOST
,
869 * On POSIX, getaddrinfo uses its own error codes, and thus has its own
870 * formatting function.
872 private string
formatGaiError(int err
) @trusted
876 return sysErrorString(err
);
881 return to
!string(gai_strerror(err
));
886 * Provides _protocol-independent translation from host names to socket
887 * addresses. If advanced functionality is not required, consider using
888 * $(D getAddress) for compatibility with older systems.
890 * Returns: Array with one $(D AddressInfo) per socket address.
892 * Throws: $(D SocketOSException) on failure, or $(D SocketFeatureException)
893 * if this functionality is not available on the current system.
896 * node = string containing host name or numeric address
897 * options = optional additional parameters, identified by type:
898 * $(UL $(LI $(D string) - service name or port number)
899 * $(LI $(D AddressInfoFlags) - option flags)
900 * $(LI $(D AddressFamily) - address family to filter by)
901 * $(LI $(D SocketType) - socket type to filter by)
902 * $(LI $(D ProtocolType) - protocol to filter by))
906 * // Roundtrip DNS resolution
907 * auto results = getAddressInfo("www.digitalmars.com");
908 * assert(results[0].address.toHostNameString() ==
909 * "digitalmars.com");
912 * results = getAddressInfo("www.digitalmars.com",
913 * AddressInfoFlags.CANONNAME);
914 * assert(results[0].canonicalName == "digitalmars.com");
917 * results = getAddressInfo("ipv6.google.com");
918 * assert(results[0].family == AddressFamily.INET6);
920 * // Multihomed resolution
921 * results = getAddressInfo("google.com");
922 * assert(results.length > 1);
925 * results = getAddressInfo("127.0.0.1",
926 * AddressInfoFlags.NUMERICHOST);
927 * assert(results.length && results[0].family ==
928 * AddressFamily.INET);
931 * results = getAddressInfo("::1",
932 * AddressInfoFlags.NUMERICHOST);
933 * assert(results.length && results[0].family ==
934 * AddressFamily.INET6);
937 AddressInfo
[] getAddressInfo(T
...)(in char[] node
, T options
)
939 const(char)[] service
= null;
941 hints
.ai_family
= AF_UNSPEC
;
943 foreach (option
; options
)
945 static if (is(typeof(option
) : const(char)[]))
948 static if (is(typeof(option
) == AddressInfoFlags
))
949 hints
.ai_flags |
= option
;
951 static if (is(typeof(option
) == AddressFamily
))
952 hints
.ai_family
= option
;
954 static if (is(typeof(option
) == SocketType
))
955 hints
.ai_socktype
= option
;
957 static if (is(typeof(option
) == ProtocolType
))
958 hints
.ai_protocol
= option
;
960 static assert(0, "Unknown getAddressInfo option type: " ~ typeof(option
).stringof
);
963 return () @trusted { return getAddressInfoImpl(node
, service
, &hints
); }();
970 const(char[]) breakSafety()
972 *cast(int*) 0xcafebabe = 0xdeadbeef;
975 alias breakSafety
this;
977 assert(!__traits(compiles
, () {
978 getAddressInfo("", Oops
.init
);
979 }), "getAddressInfo breaks @safe");
982 private AddressInfo
[] getAddressInfoImpl(in char[] node
, in char[] service
, addrinfo
* hints
) @system
984 import std
.array
: appender
;
986 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
990 int ret = getaddrinfoPointer(
992 service
.tempCString(),
994 enforce(ret == 0, new SocketOSException("getaddrinfo error", ret, &formatGaiError
));
995 scope(exit
) freeaddrinfoPointer(ai_res
);
997 auto result
= appender
!(AddressInfo
[])();
999 // Use const to force UnknownAddressReference to copy the sockaddr.
1000 for (const(addrinfo
)* ai
= ai_res
; ai
; ai
= ai
.ai_next
)
1001 result
~= AddressInfo(
1002 cast(AddressFamily
) ai
.ai_family
,
1003 cast(SocketType
) ai
.ai_socktype
,
1004 cast(ProtocolType
) ai
.ai_protocol
,
1005 new UnknownAddressReference(ai
.ai_addr
, cast(socklen_t
) ai
.ai_addrlen
),
1006 ai
.ai_canonname ? to
!string(ai
.ai_canonname
) : null);
1008 assert(result
.data
.length
> 0);
1012 throw new SocketFeatureException("Address info lookup is not available " ~
1020 if (getaddrinfoPointer
)
1022 // Roundtrip DNS resolution
1023 auto results
= getAddressInfo("www.digitalmars.com");
1024 assert(results
[0].address
.toHostNameString() == "digitalmars.com");
1027 results
= getAddressInfo("www.digitalmars.com",
1028 AddressInfoFlags
.CANONNAME
);
1029 assert(results
[0].canonicalName
== "digitalmars.com");
1032 //results = getAddressInfo("ipv6.google.com");
1033 //assert(results[0].family == AddressFamily.INET6);
1035 // Multihomed resolution
1036 //results = getAddressInfo("google.com");
1037 //assert(results.length > 1);
1040 results
= getAddressInfo("127.0.0.1", AddressInfoFlags
.NUMERICHOST
);
1041 assert(results
.length
&& results
[0].family
== AddressFamily
.INET
);
1044 results
= getAddressInfo("::1", AddressInfoFlags
.NUMERICHOST
);
1045 assert(results
.length
&& results
[0].family
== AddressFamily
.INET6
);
1049 if (getaddrinfoPointer
)
1051 auto results
= getAddressInfo(null, "1234", AddressInfoFlags
.PASSIVE
,
1052 SocketType
.STREAM
, ProtocolType
.TCP
, AddressFamily
.INET
);
1053 assert(results
.length
== 1 && results
[0].address
.toString() == "0.0.0.0:1234");
1058 private ushort serviceToPort(in char[] service
)
1061 return InternetAddress
.PORT_ANY
;
1063 if (isNumeric(service
))
1064 return to
!ushort(service
);
1067 auto s
= new Service();
1068 s
.getServiceByName(service
);
1074 * Provides _protocol-independent translation from host names to socket
1075 * addresses. Uses $(D getAddressInfo) if the current system supports it,
1076 * and $(D InternetHost) otherwise.
1078 * Returns: Array with one $(D Address) instance per socket address.
1080 * Throws: $(D SocketOSException) on failure.
1084 * writeln("Resolving www.digitalmars.com:");
1087 * auto addresses = getAddress("www.digitalmars.com");
1088 * foreach (address; addresses)
1089 * writefln(" IP: %s", address.toAddrString());
1091 * catch (SocketException e)
1092 * writefln(" Lookup failed: %s", e.msg);
1095 Address
[] getAddress(in char[] hostname
, in char[] service
= null)
1097 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1099 // use getAddressInfo
1100 auto infos
= getAddressInfo(hostname
, service
);
1102 results
.length
= infos
.length
;
1103 foreach (i
, ref result
; results
)
1104 result
= infos
[i
].address
;
1108 return getAddress(hostname
, serviceToPort(service
));
1112 Address
[] getAddress(in char[] hostname
, ushort port
)
1114 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1115 return getAddress(hostname
, to
!string(port
));
1118 // use getHostByName
1119 auto ih
= new InternetHost
;
1120 if (!ih
.getHostByName(hostname
))
1121 throw new AddressException(
1122 text("Unable to resolve host '", hostname
, "'"));
1125 foreach (uint addr
; ih
.addrList
)
1126 results
~= new InternetAddress(addr
, port
);
1135 auto addresses
= getAddress("63.105.9.61");
1136 assert(addresses
.length
&& addresses
[0].toAddrString() == "63.105.9.61");
1138 if (getaddrinfoPointer
)
1140 // test via gethostbyname
1141 auto getaddrinfoPointerBackup
= getaddrinfoPointer
;
1142 cast() getaddrinfoPointer
= null;
1143 scope(exit
) cast() getaddrinfoPointer
= getaddrinfoPointerBackup
;
1145 addresses
= getAddress("63.105.9.61");
1146 assert(addresses
.length
&& addresses
[0].toAddrString() == "63.105.9.61");
1153 * Provides _protocol-independent parsing of network addresses. Does not
1154 * attempt name resolution. Uses $(D getAddressInfo) with
1155 * $(D AddressInfoFlags.NUMERICHOST) if the current system supports it, and
1156 * $(D InternetAddress) otherwise.
1158 * Returns: An $(D Address) instance representing specified address.
1160 * Throws: $(D SocketException) on failure.
1164 * writeln("Enter IP address:");
1165 * string ip = readln().chomp();
1168 * Address address = parseAddress(ip);
1169 * writefln("Looking up reverse of %s:",
1170 * address.toAddrString());
1173 * string reverse = address.toHostNameString();
1175 * writefln(" Reverse name: %s", reverse);
1177 * writeln(" Reverse hostname not found.");
1179 * catch (SocketException e)
1180 * writefln(" Lookup error: %s", e.msg);
1182 * catch (SocketException e)
1184 * writefln(" %s is not a valid IP address: %s",
1189 Address
parseAddress(in char[] hostaddr
, in char[] service
= null)
1191 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1192 return getAddressInfo(hostaddr
, service
, AddressInfoFlags
.NUMERICHOST
)[0].address
;
1194 return parseAddress(hostaddr
, serviceToPort(service
));
1198 Address
parseAddress(in char[] hostaddr
, ushort port
)
1200 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1201 return parseAddress(hostaddr
, to
!string(port
));
1204 auto in4_addr
= InternetAddress
.parse(hostaddr
);
1205 enforce(in4_addr
!= InternetAddress
.ADDR_NONE
,
1206 new SocketParameterException("Invalid IP address"));
1207 return new InternetAddress(in4_addr
, port
);
1215 auto address
= parseAddress("63.105.9.61");
1216 assert(address
.toAddrString() == "63.105.9.61");
1218 if (getaddrinfoPointer
)
1220 // test via inet_addr
1221 auto getaddrinfoPointerBackup
= getaddrinfoPointer
;
1222 cast() getaddrinfoPointer
= null;
1223 scope(exit
) cast() getaddrinfoPointer
= getaddrinfoPointerBackup
;
1225 address
= parseAddress("63.105.9.61");
1226 assert(address
.toAddrString() == "63.105.9.61");
1229 assert(collectException
!SocketException(parseAddress("Invalid IP address")));
1235 * Class for exceptions thrown from an $(D Address).
1237 class AddressException
: SocketOSException
1239 mixin socketOSExceptionCtors
;
1244 * $(D Address) is an abstract class for representing a socket addresses.
1248 * writeln("About www.google.com port 80:");
1251 * Address[] addresses = getAddress("www.google.com", 80);
1252 * writefln(" %d addresses found.", addresses.length);
1253 * foreach (int i, Address a; addresses)
1255 * writefln(" Address %d:", i+1);
1256 * writefln(" IP address: %s", a.toAddrString());
1257 * writefln(" Hostname: %s", a.toHostNameString());
1258 * writefln(" Port: %s", a.toPortString());
1259 * writefln(" Service name: %s",
1260 * a.toServiceNameString());
1263 * catch (SocketException e)
1264 * writefln(" Lookup error: %s", e.msg);
1267 abstract class Address
1269 /// Returns pointer to underlying $(D sockaddr) structure.
1270 abstract @property sockaddr
* name() pure nothrow @nogc;
1271 abstract @property const(sockaddr
)* name() const pure nothrow @nogc; /// ditto
1273 /// Returns actual size of underlying $(D sockaddr) structure.
1274 abstract @property socklen_t
nameLen() const pure nothrow @nogc;
1276 // Socket.remoteAddress, Socket.localAddress, and Socket.receiveFrom
1277 // use setNameLen to set the actual size of the address as returned by
1278 // getsockname, getpeername, and recvfrom, respectively.
1279 // The following implementation is sufficient for fixed-length addresses,
1280 // and ensures that the length is not changed.
1281 // Must be overridden for variable-length addresses.
1282 protected void setNameLen(socklen_t len
)
1284 if (len
!= this.nameLen
)
1285 throw new AddressException(
1286 format("%s expects address of length %d, not %d", typeid(this),
1287 this.nameLen
, len
), 0);
1290 /// Family of this address.
1291 @property AddressFamily
addressFamily() const pure nothrow @nogc
1293 return cast(AddressFamily
) name
.sa_family
;
1296 // Common code for toAddrString and toHostNameString
1297 private string
toHostString(bool numeric
) @trusted const
1299 // getnameinfo() is the recommended way to perform a reverse (name)
1300 // lookup on both Posix and Windows. However, it is only available
1301 // on Windows XP and above, and not included with the WinSock import
1302 // libraries shipped with DMD. Thus, we check for getnameinfo at
1303 // runtime in the shared module constructor, and use it if it's
1304 // available in the base class method. Classes for specific network
1305 // families (e.g. InternetHost) override this method and use a
1306 // deprecated, albeit commonly-available method when getnameinfo()
1307 // is not available.
1308 // http://technet.microsoft.com/en-us/library/aa450403.aspx
1309 if (getnameinfoPointer
)
1311 auto buf
= new char[NI_MAXHOST
];
1312 auto ret = getnameinfoPointer(
1314 buf
.ptr
, cast(uint) buf
.length
,
1316 numeric ? NI_NUMERICHOST
: NI_NAMEREQD
);
1320 if (ret == EAI_NONAME
)
1323 if (ret == WSANO_DATA
)
1327 enforce(ret == 0, new AddressException("Could not get " ~
1328 (numeric ?
"host address" : "host name")));
1329 return assumeUnique(buf
[0 .. strlen(buf
.ptr
)]);
1332 throw new SocketFeatureException((numeric ?
"Host address" : "Host name") ~
1333 " lookup for this address family is not available on this system.");
1336 // Common code for toPortString and toServiceNameString
1337 private string
toServiceString(bool numeric
) @trusted const
1339 // See toHostNameString() for details about getnameinfo().
1340 if (getnameinfoPointer
)
1342 auto buf
= new char[NI_MAXSERV
];
1343 enforce(getnameinfoPointer(
1346 buf
.ptr
, cast(uint) buf
.length
,
1347 numeric ? NI_NUMERICSERV
: NI_NAMEREQD
1348 ) == 0, new AddressException("Could not get " ~
1349 (numeric ?
"port number" : "service name")));
1350 return assumeUnique(buf
[0 .. strlen(buf
.ptr
)]);
1353 throw new SocketFeatureException((numeric ?
"Port number" : "Service name") ~
1354 " lookup for this address family is not available on this system.");
1358 * Attempts to retrieve the host address as a human-readable string.
1360 * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
1361 * if address retrieval for this address family is not available on the
1364 string
toAddrString() const
1366 return toHostString(true);
1370 * Attempts to retrieve the host name as a fully qualified domain name.
1372 * Returns: The FQDN corresponding to this $(D Address), or $(D null) if
1373 * the host name did not resolve.
1375 * Throws: $(D AddressException) on error, or $(D SocketFeatureException)
1376 * if host name lookup for this address family is not available on the
1379 string
toHostNameString() const
1381 return toHostString(false);
1385 * Attempts to retrieve the numeric port number as a string.
1387 * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
1388 * if port number retrieval for this address family is not available on the
1391 string
toPortString() const
1393 return toServiceString(true);
1397 * Attempts to retrieve the service name as a string.
1399 * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
1400 * if service name lookup for this address family is not available on the
1403 string
toServiceNameString() const
1405 return toServiceString(false);
1408 /// Human readable string representing this address.
1409 override string
toString() const
1413 string host
= toAddrString();
1414 string port
= toPortString();
1415 if (host
.indexOf(':') >= 0)
1416 return "[" ~ host
~ "]:" ~ port
;
1418 return host
~ ":" ~ port
;
1420 catch (SocketException
)
1426 * $(D UnknownAddress) encapsulates an unknown socket address.
1428 class UnknownAddress
: Address
1435 override @property sockaddr
* name()
1440 override @property const(sockaddr
)* name() const
1446 override @property socklen_t
nameLen() const
1448 return cast(socklen_t
) sa
.sizeof
;
1455 * $(D UnknownAddressReference) encapsulates a reference to an arbitrary
1458 class UnknownAddressReference
: Address
1465 /// Constructs an $(D Address) with a reference to the specified $(D sockaddr).
1466 this(sockaddr
* sa
, socklen_t len
) pure nothrow @nogc
1472 /// Constructs an $(D Address) with a copy of the specified $(D sockaddr).
1473 this(const(sockaddr
)* sa
, socklen_t len
) @system pure nothrow
1475 this.sa
= cast(sockaddr
*) (cast(ubyte*) sa
)[0 .. len
].dup
.ptr
;
1479 override @property sockaddr
* name()
1484 override @property const(sockaddr
)* name() const
1490 override @property socklen_t
nameLen() const
1492 return cast(socklen_t
) len
;
1498 * $(D InternetAddress) encapsulates an IPv4 (Internet Protocol version 4)
1501 * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
1502 * instead of using this class directly.
1504 class InternetAddress
: Address
1510 this() pure nothrow @nogc
1516 override @property sockaddr
* name()
1518 return cast(sockaddr
*)&sin
;
1521 override @property const(sockaddr
)* name() const
1523 return cast(const(sockaddr
)*)&sin
;
1527 override @property socklen_t
nameLen() const
1529 return cast(socklen_t
) sin
.sizeof
;
1533 enum uint ADDR_ANY
= INADDR_ANY
; /// Any IPv4 host address.
1534 enum uint ADDR_NONE
= INADDR_NONE
; /// An invalid IPv4 host address.
1535 enum ushort PORT_ANY
= 0; /// Any IPv4 port number.
1537 /// Returns the IPv4 _port number (in host byte order).
1538 @property ushort port() const pure nothrow @nogc
1540 return ntohs(sin
.sin_port
);
1543 /// Returns the IPv4 address number (in host byte order).
1544 @property uint addr() const pure nothrow @nogc
1546 return ntohl(sin
.sin_addr
.s_addr
);
1550 * Construct a new $(D InternetAddress).
1552 * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
1553 * or a host name which will be resolved using an $(D InternetHost)
1555 * port = port number, may be $(D PORT_ANY).
1557 this(in char[] addr
, ushort port
)
1559 uint uiaddr
= parse(addr
);
1560 if (ADDR_NONE
== uiaddr
)
1562 InternetHost ih
= new InternetHost
;
1563 if (!ih
.getHostByName(addr
))
1564 //throw new AddressException("Invalid internet address");
1565 throw new AddressException(
1566 text("Unable to resolve host '", addr
, "'"));
1567 uiaddr
= ih
.addrList
[0];
1569 sin
.sin_family
= AddressFamily
.INET
;
1570 sin
.sin_addr
.s_addr
= htonl(uiaddr
);
1571 sin
.sin_port
= htons(port
);
1575 * Construct a new $(D InternetAddress).
1577 * addr = (optional) an IPv4 address in host byte order, may be $(D ADDR_ANY).
1578 * port = port number, may be $(D PORT_ANY).
1580 this(uint addr
, ushort port
) pure nothrow @nogc
1582 sin
.sin_family
= AddressFamily
.INET
;
1583 sin
.sin_addr
.s_addr
= htonl(addr
);
1584 sin
.sin_port
= htons(port
);
1588 this(ushort port
) pure nothrow @nogc
1590 sin
.sin_family
= AddressFamily
.INET
;
1591 sin
.sin_addr
.s_addr
= ADDR_ANY
;
1592 sin
.sin_port
= htons(port
);
1596 * Construct a new $(D InternetAddress).
1598 * addr = A sockaddr_in as obtained from lower-level API calls such as getifaddrs.
1600 this(sockaddr_in addr
) pure nothrow @nogc
1602 assert(addr
.sin_family
== AddressFamily
.INET
);
1606 /// Human readable string representing the IPv4 address in dotted-decimal form.
1607 override string
toAddrString() @trusted const
1609 return to
!string(inet_ntoa(sin
.sin_addr
));
1612 /// Human readable string representing the IPv4 port.
1613 override string
toPortString() const
1615 return std
.conv
.to
!string(port
);
1619 * Attempts to retrieve the host name as a fully qualified domain name.
1621 * Returns: The FQDN corresponding to this $(D InternetAddress), or
1622 * $(D null) if the host name did not resolve.
1624 * Throws: $(D AddressException) on error.
1626 override string
toHostNameString() const
1628 // getnameinfo() is the recommended way to perform a reverse (name)
1629 // lookup on both Posix and Windows. However, it is only available
1630 // on Windows XP and above, and not included with the WinSock import
1631 // libraries shipped with DMD. Thus, we check for getnameinfo at
1632 // runtime in the shared module constructor, and fall back to the
1633 // deprecated getHostByAddr() if it could not be found. See also:
1634 // http://technet.microsoft.com/en-us/library/aa450403.aspx
1636 if (getnameinfoPointer
)
1637 return super.toHostNameString();
1640 auto host
= new InternetHost();
1641 if (!host
.getHostByAddr(ntohl(sin
.sin_addr
.s_addr
)))
1648 * Compares with another InternetAddress of same type for equality
1649 * Returns: true if the InternetAddresses share the same address and
1652 override bool opEquals(Object o
) const
1654 auto other
= cast(InternetAddress
) o
;
1655 return other
&& this.sin
.sin_addr
.s_addr
== other
.sin
.sin_addr
.s_addr
&&
1656 this.sin
.sin_port
== other
.sin
.sin_port
;
1662 auto addr1
= new InternetAddress("127.0.0.1", 80);
1663 auto addr2
= new InternetAddress("127.0.0.2", 80);
1665 assert(addr1
== addr1
);
1666 assert(addr1
!= addr2
);
1670 * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
1671 * and return the number.
1672 * Returns: If the string is not a legitimate IPv4 address,
1673 * $(D ADDR_NONE) is returned.
1675 static uint parse(in char[] addr
) @trusted nothrow
1677 return ntohl(inet_addr(addr
.tempCString()));
1681 * Convert an IPv4 address number in host byte order to a human readable
1682 * string representing the IPv4 address in dotted-decimal form.
1684 static string
addrToString(uint addr
) @trusted nothrow
1687 sin_addr
.s_addr
= htonl(addr
);
1688 return to
!string(inet_ntoa(sin_addr
));
1696 const InternetAddress ia
= new InternetAddress("63.105.9.61", 80);
1697 assert(ia
.toString() == "63.105.9.61:80");
1701 // test construction from a sockaddr_in
1704 sin
.sin_addr
.s_addr
= htonl(0x7F_00_00_01); // 127.0.0.1
1705 sin
.sin_family
= AddressFamily
.INET
;
1706 sin
.sin_port
= htons(80);
1708 const InternetAddress ia
= new InternetAddress(sin
);
1709 assert(ia
.toString() == "127.0.0.1:80");
1713 // test reverse lookup
1714 auto ih
= new InternetHost
;
1715 if (ih
.getHostByName("digitalmars.com"))
1717 const ia
= new InternetAddress(ih
.addrList
[0], 80);
1718 assert(ia
.toHostNameString() == "digitalmars.com");
1720 if (getnameinfoPointer
)
1722 // test reverse lookup, via gethostbyaddr
1723 auto getnameinfoPointerBackup
= getnameinfoPointer
;
1724 cast() getnameinfoPointer
= null;
1725 scope(exit
) cast() getnameinfoPointer
= getnameinfoPointerBackup
;
1727 assert(ia
.toHostNameString() == "digitalmars.com");
1734 // test failing reverse lookup
1735 const InternetAddress ia
= new InternetAddress("127.114.111.120", 80);
1736 assert(ia
.toHostNameString() is null);
1738 if (getnameinfoPointer
)
1740 // test failing reverse lookup, via gethostbyaddr
1741 auto getnameinfoPointerBackup
= getnameinfoPointer
;
1742 getnameinfoPointer
= null;
1743 scope(exit
) getnameinfoPointer
= getnameinfoPointerBackup
;
1745 assert(ia
.toHostNameString() is null);
1752 * $(D Internet6Address) encapsulates an IPv6 (Internet Protocol version 6)
1755 * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
1756 * instead of using this class directly.
1758 class Internet6Address
: Address
1764 this() pure nothrow @nogc
1770 override @property sockaddr
* name()
1772 return cast(sockaddr
*)&sin6
;
1775 override @property const(sockaddr
)* name() const
1777 return cast(const(sockaddr
)*)&sin6
;
1781 override @property socklen_t
nameLen() const
1783 return cast(socklen_t
) sin6
.sizeof
;
1787 /// Any IPv6 host address.
1788 static @property ref const(ubyte)[16] ADDR_ANY() pure nothrow @nogc
1790 const(ubyte)[16]* addr
;
1791 static if (is(typeof(IN6ADDR_ANY
)))
1793 addr
= &IN6ADDR_ANY
.s6_addr
;
1796 else static if (is(typeof(in6addr_any
)))
1798 addr
= &in6addr_any
.s6_addr
;
1805 /// Any IPv6 port number.
1806 enum ushort PORT_ANY
= 0;
1808 /// Returns the IPv6 port number.
1809 @property ushort port() const pure nothrow @nogc
1811 return ntohs(sin6
.sin6_port
);
1814 /// Returns the IPv6 address.
1815 @property ubyte[16] addr() const pure nothrow @nogc
1817 return sin6
.sin6_addr
.s6_addr
;
1821 * Construct a new $(D Internet6Address).
1823 * addr = an IPv6 host address string in the form described in RFC 2373,
1824 * or a host name which will be resolved using $(D getAddressInfo).
1825 * service = (optional) service name.
1827 this(in char[] addr
, in char[] service
= null) @trusted
1829 auto results
= getAddressInfo(addr
, service
, AddressFamily
.INET6
);
1830 assert(results
.length
&& results
[0].family
== AddressFamily
.INET6
);
1831 sin6
= *cast(sockaddr_in6
*) results
[0].address
.name
;
1835 * Construct a new $(D Internet6Address).
1837 * addr = an IPv6 host address string in the form described in RFC 2373,
1838 * or a host name which will be resolved using $(D getAddressInfo).
1839 * port = port number, may be $(D PORT_ANY).
1841 this(in char[] addr
, ushort port
)
1843 if (port
== PORT_ANY
)
1846 this(addr
, to
!string(port
));
1850 * Construct a new $(D Internet6Address).
1852 * addr = (optional) an IPv6 host address in host byte order, or
1854 * port = port number, may be $(D PORT_ANY).
1856 this(ubyte[16] addr
, ushort port
) pure nothrow @nogc
1858 sin6
.sin6_family
= AddressFamily
.INET6
;
1859 sin6
.sin6_addr
.s6_addr
= addr
;
1860 sin6
.sin6_port
= htons(port
);
1864 this(ushort port
) pure nothrow @nogc
1866 sin6
.sin6_family
= AddressFamily
.INET6
;
1867 sin6
.sin6_addr
.s6_addr
= ADDR_ANY
;
1868 sin6
.sin6_port
= htons(port
);
1872 * Construct a new $(D Internet6Address).
1874 * addr = A sockaddr_in6 as obtained from lower-level API calls such as getifaddrs.
1876 this(sockaddr_in6 addr
) pure nothrow @nogc
1878 assert(addr
.sin6_family
== AddressFamily
.INET6
);
1883 * Parse an IPv6 host address string as described in RFC 2373, and return the
1885 * Throws: $(D SocketException) on error.
1887 static ubyte[16] parse(in char[] addr
) @trusted
1889 // Although we could use inet_pton here, it's only available on Windows
1890 // versions starting with Vista, so use getAddressInfo with NUMERICHOST
1892 auto results
= getAddressInfo(addr
, AddressInfoFlags
.NUMERICHOST
);
1893 if (results
.length
&& results
[0].family
== AddressFamily
.INET6
)
1894 return (cast(sockaddr_in6
*) results
[0].address
.name
).sin6_addr
.s6_addr
;
1895 throw new AddressException("Not an IPv6 address", 0);
1903 const Internet6Address ia
= new Internet6Address("::1", 80);
1904 assert(ia
.toString() == "[::1]:80");
1908 // test construction from a sockaddr_in6
1911 sin
.sin6_addr
.s6_addr
= [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // [::1]
1912 sin
.sin6_family
= AddressFamily
.INET6
;
1913 sin
.sin6_port
= htons(80);
1915 const Internet6Address ia
= new Internet6Address(sin
);
1916 assert(ia
.toString() == "[::1]:80");
1923 static if (!is(sockaddr_un
))
1925 // This exists only to allow the constructor taking
1926 // a sockaddr_un to be compilable for documentation
1927 // on platforms that don't supply a sockaddr_un.
1934 * $(D UnixAddress) encapsulates an address for a Unix domain socket
1935 * ($(D AF_UNIX)), i.e. a socket bound to a path name in the file system.
1936 * Available only on supported systems.
1938 * Linux also supports an abstract address namespace, in which addresses
1939 * are independent of the file system. A socket address is abstract
1940 * iff `path` starts with a _null byte (`'\0'`). Null bytes in other
1941 * positions of an abstract address are allowed and have no special
1946 * auto addr = new UnixAddress("/var/run/dbus/system_bus_socket");
1947 * auto abstractAddr = new UnixAddress("\0/tmp/dbus-OtHLWmCLPR");
1950 * See_Also: $(HTTP http://man7.org/linux/man-pages/man7/unix.7.html, UNIX(7))
1952 class UnixAddress
: Address
1954 private this() pure nothrow @nogc {}
1956 /// Construct a new $(D UnixAddress) from the specified path.
1957 this(in char[] path
) { }
1960 * Construct a new $(D UnixAddress).
1962 * addr = A sockaddr_un as obtained from lower-level API calls.
1964 this(sockaddr_un addr
) pure nothrow @nogc { }
1966 /// Get the underlying _path.
1967 @property string
path() const { return null; }
1970 override string
toString() const { return null; }
1972 override @property sockaddr
* name() { return null; }
1973 override @property const(sockaddr
)* name() const { return null; }
1974 override @property socklen_t
nameLen() const { return 0; }
1978 static if (is(sockaddr_un
))
1980 class UnixAddress
: Address
1989 char unused
= '\0'; // placeholder for a terminating '\0'
1992 this() pure nothrow @nogc
1994 sun
.sun_family
= AddressFamily
.UNIX
;
1996 _nameLen
= sun
.sizeof
;
1999 override void setNameLen(socklen_t len
) @trusted
2001 if (len
> sun
.sizeof
)
2002 throw new SocketParameterException("Not enough socket address storage");
2007 override @property sockaddr
* name()
2009 return cast(sockaddr
*)&sun
;
2012 override @property const(sockaddr
)* name() const
2014 return cast(const(sockaddr
)*)&sun
;
2017 override @property socklen_t
nameLen() @trusted const
2022 this(in char[] path
) @trusted pure
2024 enforce(path
.length
<= sun
.sun_path
.sizeof
, new SocketParameterException("Path too long"));
2025 sun
.sun_family
= AddressFamily
.UNIX
;
2026 sun
.sun_path
.ptr
[0 .. path
.length
] = (cast(byte[]) path
)[];
2027 _nameLen
= cast(socklen_t
)
2029 auto len
= sockaddr_un
.init
.sun_path
.offsetof
+ path
.length
;
2030 // Pathname socket address must be terminated with '\0'
2031 // which must be included in the address length.
2032 if (sun
.sun_path
.ptr
[0])
2034 sun
.sun_path
.ptr
[path
.length
] = 0;
2041 this(sockaddr_un addr
) pure nothrow @nogc
2043 assert(addr
.sun_family
== AddressFamily
.UNIX
);
2047 @property string
path() @trusted const pure
2049 auto len
= _nameLen
- sockaddr_un
.init
.sun_path
.offsetof
;
2050 // For pathname socket address we need to strip off the terminating '\0'
2051 if (sun
.sun_path
.ptr
[0])
2053 return (cast(const(char)*) sun
.sun_path
.ptr
)[0 .. len
].idup
;
2056 override string
toString() const pure
2064 import core
.stdc
.stdio
: remove
;
2065 import std
.file
: deleteme
;
2067 immutable ubyte[] data
= [1, 2, 3, 4];
2070 auto names
= [ deleteme
~ "-unix-socket" ];
2072 names
~= "\0" ~ deleteme
~ "-abstract\0unix\0socket";
2073 foreach (name
; names
)
2075 auto address
= new UnixAddress(name
);
2077 auto listener
= new Socket(AddressFamily
.UNIX
, SocketType
.STREAM
);
2078 scope(exit
) listener
.close();
2079 listener
.bind(address
);
2080 scope(exit
) () @trusted { if (name
[0]) remove(name
.tempCString()); } ();
2081 assert(listener
.localAddress
.toString
== name
);
2085 pair
[0] = new Socket(AddressFamily
.UNIX
, SocketType
.STREAM
);
2086 scope(exit
) listener
.close();
2088 pair
[0].connect(address
);
2089 scope(exit
) pair
[0].close();
2091 pair
[1] = listener
.accept();
2092 scope(exit
) pair
[1].close();
2096 auto buf
= new ubyte[data
.length
];
2097 pair
[1].receive(buf
);
2098 assert(buf
== data
);
2105 * Class for exceptions thrown by $(D Socket.accept).
2107 class SocketAcceptException
: SocketOSException
2109 mixin socketOSExceptionCtors
;
2112 /// How a socket is shutdown:
2113 enum SocketShutdown
: int
2115 RECEIVE
= SD_RECEIVE
, /// socket receives are disallowed
2116 SEND
= SD_SEND
, /// socket sends are disallowed
2117 BOTH
= SD_BOTH
, /// both RECEIVE and SEND
2121 /// Flags may be OR'ed together:
2122 enum SocketFlags
: int
2124 NONE
= 0, /// no flags specified
2126 OOB
= MSG_OOB
, /// out-of-band stream data
2127 PEEK
= MSG_PEEK
, /// peek at incoming data without removing it from the queue, only for receiving
2128 DONTROUTE
= MSG_DONTROUTE
, /// data should not be subject to routing; this flag may be ignored. Only for sending
2132 private mixin template FieldProxy(string target
, string field
)
2135 @property typeof(`~target
~`) `~field
~`() const pure nothrow @nogc
2141 @property typeof(`~target
~`) `~field
~`(typeof(`~target
~`) value) pure nothrow @nogc
2143 return `~target
~` = value;
2149 /// Duration timeout value.
2153 alias tv_sec_t
= typeof(ctimeval
.tv_sec
);
2154 alias tv_usec_t
= typeof(ctimeval
.tv_usec
);
2156 version (StdDdoc
) // no DDoc for string mixins, can't forward individual fields
2158 tv_sec_t seconds
; /// Number of _seconds.
2159 tv_usec_t microseconds
; /// Number of additional _microseconds.
2164 mixin FieldProxy
!(`ctimeval.tv_sec`, `seconds`);
2165 mixin FieldProxy
!(`ctimeval.tv_usec`, `microseconds`);
2171 * A collection of sockets for use with $(D Socket.select).
2173 * $(D SocketSet) wraps the platform $(D fd_set) type. However, unlike
2174 * $(D fd_set), $(D SocketSet) is not statically limited to $(D FD_SETSIZE)
2175 * or any other limit, and grows as needed.
2182 // On Windows, fd_set is an array of socket handles,
2183 // following a word containing the fd_set instance size.
2184 // We use one dynamic array for everything, and use its first
2185 // element(s) for the count.
2187 alias fd_set_count_type
= typeof(fd_set
.init
.fd_count
);
2188 alias fd_set_type
= typeof(fd_set
.init
.fd_array
[0]);
2189 static assert(fd_set_type
.sizeof
== socket_t
.sizeof
);
2191 // Number of fd_set_type elements at the start of our array that are
2192 // used for the socket count and alignment
2194 enum FD_SET_OFFSET
= fd_set
.fd_array
.offsetof
/ fd_set_type
.sizeof
;
2195 static assert(FD_SET_OFFSET
);
2196 static assert(fd_set
.fd_count
.offsetof
% fd_set_type
.sizeof
== 0);
2200 void resize(size_t size
) pure nothrow
2202 set
.length
= FD_SET_OFFSET
+ size
;
2205 ref inout(fd_set_count_type
) count() @trusted @property inout pure nothrow @nogc
2208 return *cast(inout(fd_set_count_type
)*)set
.ptr
;
2211 size_t
capacity() @property const pure nothrow @nogc
2213 return set
.length
- FD_SET_OFFSET
;
2216 inout(socket_t
)[] fds() @trusted inout @property pure nothrow @nogc
2218 return cast(inout(socket_t
)[])set
[FD_SET_OFFSET
.. FD_SET_OFFSET
+count
];
2224 // On Posix, fd_set is a bit array. We assume that the fd_set
2225 // type (declared in core.sys.posix.sys.select) is a structure
2226 // containing a single field, a static array.
2228 static assert(fd_set
.tupleof
.length
== 1);
2230 // This is the type used in the fd_set array.
2231 // Using the type of the correct size is important for big-endian
2234 alias fd_set_type
= typeof(fd_set
.init
.tupleof
[0][0]);
2236 // Number of file descriptors represented by one fd_set_type
2238 enum FD_NFDBITS
= 8 * fd_set_type
.sizeof
;
2240 static fd_set_type
mask(uint n
) pure nothrow @nogc
2242 return (cast(fd_set_type
) 1) << (n
% FD_NFDBITS
);
2245 // Array size to fit that many sockets
2247 static size_t
lengthFor(size_t size
) pure nothrow @nogc
2249 return (size
+ (FD_NFDBITS
-1)) / FD_NFDBITS
;
2254 void resize(size_t size
) pure nothrow
2256 set
.length
= lengthFor(size
);
2259 // Make sure we can fit that many sockets
2261 void setMinCapacity(size_t size
) pure nothrow
2263 auto length
= lengthFor(size
);
2264 if (set
.length
< length
)
2265 set
.length
= length
;
2268 size_t
capacity() @property const pure nothrow @nogc
2270 return set
.length
* FD_NFDBITS
;
2276 static assert(false, "Unknown platform");
2281 * Create a SocketSet with a specific initial capacity (defaults to
2282 * $(D FD_SETSIZE), the system's default capacity).
2284 this(size_t size
= FD_SETSIZE
) pure nothrow
2290 /// Reset the $(D SocketSet) so that there are 0 $(D Socket)s in the collection.
2291 void reset() pure nothrow @nogc
2303 void add(socket_t s
) @trusted pure nothrow
2307 if (count
== capacity
)
2310 set
.length
= set
.capacity
;
2317 auto index
= s
/ FD_NFDBITS
;
2318 auto length
= set
.length
;
2319 if (index
>= length
)
2321 while (index
>= length
)
2323 set
.length
= length
;
2324 set
.length
= set
.capacity
;
2326 set
[index
] |
= mask(s
);
2333 * Add a $(D Socket) to the collection.
2334 * The socket must not already be in the collection.
2336 void add(Socket s
) pure nothrow
2341 void remove(socket_t s
) pure nothrow
2345 import std
.algorithm
.searching
: countUntil
;
2347 auto p
= fds
.countUntil(s
);
2349 fds
[p
] = fds
[--count
];
2353 auto index
= s
/ FD_NFDBITS
;
2354 if (index
>= set
.length
)
2356 set
[index
] &= ~mask(s
);
2357 // note: adjusting maxfd would require scanning the set, not worth it
2363 * Remove this $(D Socket) from the collection.
2364 * Does nothing if the socket is not in the collection already.
2366 void remove(Socket s
) pure nothrow
2371 int isSet(socket_t s
) const pure nothrow @nogc
2375 import std
.algorithm
.searching
: canFind
;
2376 return fds
.canFind(s
) ?
1 : 0;
2382 auto index
= s
/ FD_NFDBITS
;
2383 return (set
[index
] & mask(s
)) ?
1 : 0;
2388 /// Return nonzero if this $(D Socket) is in the collection.
2389 int isSet(Socket s
) const pure nothrow @nogc
2391 return isSet(s
.sock
);
2397 * The current capacity of this $(D SocketSet). The exact
2398 * meaning of the return value varies from platform to platform.
2401 * Since D 2.065, this value does not indicate a
2402 * restriction, and $(D SocketSet) will grow its capacity as
2403 * needed automatically.
2405 @property uint max() const pure nothrow @nogc
2407 return cast(uint) capacity
;
2411 fd_set
* toFd_set() @trusted pure nothrow @nogc
2413 return cast(fd_set
*) set
.ptr
;
2417 int selectn() const pure nothrow @nogc
2423 else version (Posix
)
2432 auto fds
= cast(socket_t
[])
2433 [cast(socket_t
) 1, 2, 0, 1024, 17, 42, 1234, 77, 77+32, 77+64];
2434 auto set
= new SocketSet();
2435 foreach (fd
; fds
) assert(!set
.isSet(fd
));
2436 foreach (fd
; fds
) set
.add(fd
);
2437 foreach (fd
; fds
) assert(set
.isSet(fd
));
2439 // Make sure SocketSet reimplements fd_set correctly
2440 auto fdset
= set
.toFd_set();
2441 foreach (fd
; fds
[0]..cast(socket_t
)(fds
[$-1]+1))
2442 assert(cast(bool) set
.isSet(fd
) == cast(bool)(() @trusted => FD_ISSET(fd
, fdset
))());
2446 assert(set
.isSet(fd
));
2448 assert(!set
.isSet(fd
));
2460 static assert(LIMIT
> PAIRS
*2);
2461 import core
.sys
.posix
.sys
.resource
;
2463 getrlimit(RLIMIT_NOFILE
, &fileLimit
);
2464 assert(fileLimit
.rlim_max
> LIMIT
, "Open file hard limit too low");
2465 fileLimit
.rlim_cur
= LIMIT
;
2466 setrlimit(RLIMIT_NOFILE
, &fileLimit
);
2469 Socket
[2][PAIRS
] pairs
;
2470 foreach (ref pair
; pairs
)
2471 pair
= socketPair();
2474 foreach (pair
; pairs
)
2482 auto rng
= Xorshift(42);
2483 pairs
[].randomShuffle(rng
);
2485 auto readSet
= new SocketSet();
2486 auto writeSet
= new SocketSet();
2487 auto errorSet
= new SocketSet();
2489 foreach (testPair
; pairs
)
2496 foreach (ref pair
; pairs
)
2506 auto n
= Socket
.select(readSet
, writeSet
, errorSet
);
2507 assert(n
== PAIRS
*2); // All in writeSet
2508 assert(writeSet
.isSet(testPair
[0]));
2509 assert(writeSet
.isSet(testPair
[1]));
2510 assert(!readSet
.isSet(testPair
[0]));
2511 assert(!readSet
.isSet(testPair
[1]));
2512 assert(!errorSet
.isSet(testPair
[0]));
2513 assert(!errorSet
.isSet(testPair
[1]));
2516 testPair
[0].send(b
[]);
2518 n
= Socket
.select(readSet
, null, null);
2519 assert(n
== 1); // testPair[1]
2520 assert(readSet
.isSet(testPair
[1]));
2521 assert(!readSet
.isSet(testPair
[0]));
2522 testPair
[1].receive(b
[]);
2527 @safe unittest // Issue 14012, 14013
2529 auto set
= new SocketSet(1);
2530 assert(set
.max
>= 0);
2533 foreach (n
; 0 .. LIMIT
)
2534 set
.add(cast(socket_t
) n
);
2535 assert(set
.max
>= LIMIT
);
2538 /// The level at which a socket option is defined:
2539 enum SocketOptionLevel
: int
2541 SOCKET
= SOL_SOCKET
, /// Socket level
2542 IP
= ProtocolType
.IP
, /// Internet Protocol version 4 level
2543 ICMP
= ProtocolType
.ICMP
, /// Internet Control Message Protocol level
2544 IGMP
= ProtocolType
.IGMP
, /// Internet Group Management Protocol level
2545 GGP
= ProtocolType
.GGP
, /// Gateway to Gateway Protocol level
2546 TCP
= ProtocolType
.TCP
, /// Transmission Control Protocol level
2547 PUP
= ProtocolType
.PUP
, /// PARC Universal Packet Protocol level
2548 UDP
= ProtocolType
.UDP
, /// User Datagram Protocol level
2549 IDP
= ProtocolType
.IDP
, /// Xerox NS protocol level
2550 RAW
= ProtocolType
.RAW
, /// Raw IP packet level
2551 IPV6
= ProtocolType
.IPV6
, /// Internet Protocol version 6 level
2554 /// _Linger information for use with SocketOption.LINGER.
2559 version (StdDdoc
) // no DDoc for string mixins, can't forward individual fields
2561 private alias l_onoff_t
= typeof(_clinger
.init
.l_onoff
);
2562 private alias l_linger_t
= typeof(_clinger
.init
.l_linger
);
2563 l_onoff_t on
; /// Nonzero for _on.
2564 l_linger_t time
; /// Linger _time.
2569 mixin FieldProxy
!(`clinger.l_onoff`, `on`);
2570 mixin FieldProxy
!(`clinger.l_linger`, `time`);
2574 /// Specifies a socket option:
2575 enum SocketOption
: int
2577 DEBUG
= SO_DEBUG
, /// Record debugging information
2578 BROADCAST
= SO_BROADCAST
, /// Allow transmission of broadcast messages
2579 REUSEADDR
= SO_REUSEADDR
, /// Allow local reuse of address
2580 LINGER
= SO_LINGER
, /// Linger on close if unsent data is present
2581 OOBINLINE
= SO_OOBINLINE
, /// Receive out-of-band data in band
2582 SNDBUF
= SO_SNDBUF
, /// Send buffer size
2583 RCVBUF
= SO_RCVBUF
, /// Receive buffer size
2584 DONTROUTE
= SO_DONTROUTE
, /// Do not route
2585 SNDTIMEO
= SO_SNDTIMEO
, /// Send timeout
2586 RCVTIMEO
= SO_RCVTIMEO
, /// Receive timeout
2587 ERROR
= SO_ERROR
, /// Retrieve and clear error status
2588 KEEPALIVE
= SO_KEEPALIVE
, /// Enable keep-alive packets
2589 ACCEPTCONN
= SO_ACCEPTCONN
, /// Listen
2590 RCVLOWAT
= SO_RCVLOWAT
, /// Minimum number of input bytes to process
2591 SNDLOWAT
= SO_SNDLOWAT
, /// Minimum number of output bytes to process
2592 TYPE
= SO_TYPE
, /// Socket type
2594 // SocketOptionLevel.TCP:
2595 TCP_NODELAY
= .TCP_NODELAY
, /// Disable the Nagle algorithm for send coalescing
2597 // SocketOptionLevel.IPV6:
2598 IPV6_UNICAST_HOPS
= .IPV6_UNICAST_HOPS
, /// IP unicast hop limit
2599 IPV6_MULTICAST_IF
= .IPV6_MULTICAST_IF
, /// IP multicast interface
2600 IPV6_MULTICAST_LOOP
= .IPV6_MULTICAST_LOOP
, /// IP multicast loopback
2601 IPV6_MULTICAST_HOPS
= .IPV6_MULTICAST_HOPS
, /// IP multicast hops
2602 IPV6_JOIN_GROUP
= .IPV6_JOIN_GROUP
, /// Add an IP group membership
2603 IPV6_LEAVE_GROUP
= .IPV6_LEAVE_GROUP
, /// Drop an IP group membership
2604 IPV6_V6ONLY
= .IPV6_V6ONLY
, /// Treat wildcard bind as AF_INET6-only
2609 * $(D Socket) is a class that creates a network communication endpoint using
2610 * the Berkeley sockets interface.
2616 AddressFamily _family
;
2619 bool _blocking
= false; /// Property to get or set whether the socket is blocking or nonblocking.
2621 // The WinSock timeouts seem to be effectively skewed by a constant
2622 // offset of about half a second (value in milliseconds). This has
2623 // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7
2624 // and Windows Server 2008 R2 boxes. The unittest below tests this
2626 enum WINSOCK_TIMEOUT_SKEW
= 500;
2632 import std
.datetime
;
2633 import std
.typecons
;
2636 auto pair
= socketPair();
2637 auto sock
= pair
[0];
2638 sock
.setOption(SocketOptionLevel
.SOCKET
,
2639 SocketOption
.RCVTIMEO
, dur
!"msecs"(msecs
));
2641 auto sw
= StopWatch(Yes
.autoStart
);
2646 Duration readBack
= void;
2647 sock
.getOption(SocketOptionLevel
.SOCKET
, SocketOption
.RCVTIMEO
, readBack
);
2649 assert(readBack
.total
!"msecs" == msecs
);
2650 assert(sw
.peek().msecs
> msecs
-100 && sw
.peek().msecs
< msecs
+100);
2654 void setSock(socket_t handle
)
2656 assert(handle
!= socket_t
.init
);
2659 // Set the option to disable SIGPIPE on send() if the platform
2660 // has it (e.g. on OS X).
2661 static if (is(typeof(SO_NOSIGPIPE
)))
2663 setOption(SocketOptionLevel
.SOCKET
, cast(SocketOption
) SO_NOSIGPIPE
, true);
2668 // For use with accepting().
2669 protected this() pure nothrow @nogc
2677 * Create a blocking socket. If a single protocol type exists to support
2678 * this socket type within the address family, the $(D ProtocolType) may be
2681 this(AddressFamily af
, SocketType type
, ProtocolType protocol
) @trusted
2684 auto handle
= cast(socket_t
) socket(af
, type
, protocol
);
2685 if (handle
== socket_t
.init
)
2686 throw new SocketOSException("Unable to create socket");
2691 this(AddressFamily af
, SocketType type
)
2693 /* A single protocol exists to support this socket type within the
2694 * protocol family, so the ProtocolType is assumed.
2696 this(af
, type
, cast(ProtocolType
) 0); // Pseudo protocol number.
2701 this(AddressFamily af
, SocketType type
, in char[] protocolName
) @trusted
2704 proto
= getprotobyname(protocolName
.tempCString());
2706 throw new SocketOSException("Unable to find the protocol");
2707 this(af
, type
, cast(ProtocolType
) proto
.p_proto
);
2712 * Create a blocking socket using the parameters from the specified
2713 * $(D AddressInfo) structure.
2715 this(in AddressInfo info
)
2717 this(info
.family
, info
.type
, info
.protocol
);
2720 /// Use an existing socket handle.
2721 this(socket_t sock
, AddressFamily af
) pure nothrow @nogc
2723 assert(sock
!= socket_t
.init
);
2729 ~this() nothrow @nogc
2735 /// Get underlying socket handle.
2736 @property socket_t
handle() const pure nothrow @nogc
2742 * Get/set socket's blocking flag.
2744 * When a socket is blocking, calls to receive(), accept(), and send()
2745 * will block and wait for data/action.
2746 * A non-blocking socket will immediately return instead of blocking.
2748 @property bool blocking() @trusted const nothrow @nogc
2754 else version (Posix
)
2756 return !(fcntl(handle
, F_GETFL
, 0) & O_NONBLOCK
);
2761 @property void blocking(bool byes
) @trusted
2766 if (_SOCKET_ERROR
== ioctlsocket(sock
, FIONBIO
, &num
))
2770 else version (Posix
)
2772 int x
= fcntl(sock
, F_GETFL
, 0);
2779 if (-1 == fcntl(sock
, F_SETFL
, x
))
2785 throw new SocketOSException("Unable to set socket blocking");
2789 /// Get the socket's address family.
2790 @property AddressFamily
addressFamily()
2795 /// Property that indicates if this is a valid, alive socket.
2796 @property bool isAlive() @trusted const
2799 socklen_t typesize
= cast(socklen_t
) type
.sizeof
;
2800 return !getsockopt(sock
, SOL_SOCKET
, SO_TYPE
, cast(char*)&type
, &typesize
);
2803 /// Associate a local address with this socket.
2804 void bind(Address addr
) @trusted
2806 if (_SOCKET_ERROR
== .bind(sock
, addr
.name
, addr
.nameLen
))
2807 throw new SocketOSException("Unable to bind socket");
2811 * Establish a connection. If the socket is blocking, connect waits for
2812 * the connection to be made. If the socket is nonblocking, connect
2813 * returns immediately and the connection attempt is still in progress.
2815 void connect(Address to
) @trusted
2817 if (_SOCKET_ERROR
== .connect(sock
, to
.name
, to
.nameLen
))
2826 if (WSAEWOULDBLOCK
== err
)
2829 else version (Posix
)
2831 if (EINPROGRESS
== err
)
2839 throw new SocketOSException("Unable to connect socket", err
);
2844 * Listen for an incoming connection. $(D bind) must be called before you
2845 * can $(D listen). The $(D backlog) is a request of how many pending
2846 * incoming connections are queued until $(D accept)ed.
2848 void listen(int backlog
) @trusted
2850 if (_SOCKET_ERROR
== .listen(sock
, backlog
))
2851 throw new SocketOSException("Unable to listen on socket");
2855 * Called by $(D accept) when a new $(D Socket) must be created for a new
2856 * connection. To use a derived class, override this method and return an
2857 * instance of your class. The returned $(D Socket)'s handle must not be
2858 * set; $(D Socket) has a protected constructor $(D this()) to use in this
2861 * Override to use a derived class.
2862 * The returned socket's handle must not be set.
2864 protected Socket
accepting() pure nothrow
2870 * Accept an incoming connection. If the socket is blocking, $(D accept)
2871 * waits for a connection request. Throws $(D SocketAcceptException) if
2872 * unable to _accept. See $(D accepting) for use with derived classes.
2874 Socket
accept() @trusted
2876 auto newsock
= cast(socket_t
).accept(sock
, null, null);
2877 if (socket_t
.init
== newsock
)
2878 throw new SocketAcceptException("Unable to accept socket connection");
2883 newSocket
= accepting();
2884 assert(newSocket
.sock
== socket_t
.init
);
2886 newSocket
.setSock(newsock
);
2888 newSocket
._blocking
= _blocking
; //inherits blocking mode
2889 newSocket
._family
= _family
; //same family
2900 /// Disables sends and/or receives.
2901 void shutdown(SocketShutdown how
) @trusted nothrow @nogc
2903 .shutdown(sock
, cast(int) how
);
2907 private static void _close(socket_t sock
) @system nothrow @nogc
2913 else version (Posix
)
2921 * Immediately drop any connections and release socket resources.
2922 * Calling $(D shutdown) before $(D close) is recommended for
2923 * connection-oriented sockets. The $(D Socket) object is no longer
2924 * usable after $(D close).
2925 * Calling shutdown() before this is recommended
2926 * for connection-oriented sockets.
2928 void close() @trusted nothrow @nogc
2931 sock
= socket_t
.init
;
2936 * Returns: the local machine's host name
2938 static @property string
hostName() @trusted // getter
2940 char[256] result
; // Host names are limited to 255 chars.
2941 if (_SOCKET_ERROR
== .gethostname(result
.ptr
, result
.length
))
2942 throw new SocketOSException("Unable to obtain host name");
2943 return to
!string(result
.ptr
);
2946 /// Remote endpoint $(D Address).
2947 @property Address
remoteAddress() @trusted
2949 Address addr
= createAddress();
2950 socklen_t nameLen
= addr
.nameLen
;
2951 if (_SOCKET_ERROR
== .getpeername(sock
, addr
.name
, &nameLen
))
2952 throw new SocketOSException("Unable to obtain remote socket address");
2953 addr
.setNameLen(nameLen
);
2954 assert(addr
.addressFamily
== _family
);
2958 /// Local endpoint $(D Address).
2959 @property Address
localAddress() @trusted
2961 Address addr
= createAddress();
2962 socklen_t nameLen
= addr
.nameLen
;
2963 if (_SOCKET_ERROR
== .getsockname(sock
, addr
.name
, &nameLen
))
2964 throw new SocketOSException("Unable to obtain local socket address");
2965 addr
.setNameLen(nameLen
);
2966 assert(addr
.addressFamily
== _family
);
2971 * Send or receive error code. See $(D wouldHaveBlocked),
2972 * $(D lastSocketError) and $(D Socket.getErrorText) for obtaining more
2973 * information about the error.
2975 enum int ERROR
= _SOCKET_ERROR
;
2977 private static int capToInt(size_t size
) nothrow @nogc
2979 // Windows uses int instead of size_t for length arguments.
2980 // Luckily, the send/recv functions make no guarantee that
2981 // all the data is sent, so we use that to send at most
2983 return size
> size_t(int.max
) ?
int.max
: cast(int) size
;
2987 * Send data on the connection. If the socket is blocking and there is no
2988 * buffer space left, $(D send) waits.
2989 * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on
2992 ptrdiff_t
send(const(void)[] buf
, SocketFlags flags
) @trusted
2994 static if (is(typeof(MSG_NOSIGNAL
)))
2996 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
2999 auto sent
= .send(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
);
3001 auto sent
= .send(sock
, buf
.ptr
, buf
.length
, cast(int) flags
);
3006 ptrdiff_t
send(const(void)[] buf
)
3008 return send(buf
, SocketFlags
.NONE
);
3012 * Send data to a specific destination Address. If the destination address is
3013 * not specified, a connection must have been made and that address is used.
3014 * If the socket is blocking and there is no buffer space left, $(D sendTo) waits.
3015 * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on
3018 ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
, Address to
) @trusted
3020 static if (is(typeof(MSG_NOSIGNAL
)))
3022 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3026 sock
, buf
.ptr
, capToInt(buf
.length
),
3027 cast(int) flags
, to
.name
, to
.nameLen
3030 return .sendto(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, to
.name
, to
.nameLen
);
3034 ptrdiff_t
sendTo(const(void)[] buf
, Address to
)
3036 return sendTo(buf
, SocketFlags
.NONE
, to
);
3040 //assumes you connect()ed
3042 ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
) @trusted
3044 static if (is(typeof(MSG_NOSIGNAL
)))
3046 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3049 return .sendto(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, null, 0);
3051 return .sendto(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, null, 0);
3055 //assumes you connect()ed
3057 ptrdiff_t
sendTo(const(void)[] buf
)
3059 return sendTo(buf
, SocketFlags
.NONE
);
3064 * Receive data on the connection. If the socket is blocking, $(D receive)
3065 * waits until there is data to be received.
3066 * Returns: The number of bytes actually received, $(D 0) if the remote side
3067 * has closed the connection, or $(D Socket.ERROR) on failure.
3069 ptrdiff_t
receive(void[] buf
, SocketFlags flags
) @trusted
3071 version (Windows
) // Does not use size_t
3074 ?
.recv(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
)
3080 ?
.recv(sock
, buf
.ptr
, buf
.length
, cast(int) flags
)
3086 ptrdiff_t
receive(void[] buf
)
3088 return receive(buf
, SocketFlags
.NONE
);
3092 * Receive data and get the remote endpoint $(D Address).
3093 * If the socket is blocking, $(D receiveFrom) waits until there is data to
3095 * Returns: The number of bytes actually received, $(D 0) if the remote side
3096 * has closed the connection, or $(D Socket.ERROR) on failure.
3098 ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
, ref Address from
) @trusted
3100 if (!buf
.length
) //return 0 and don't think the connection closed
3102 if (from
is null || from
.addressFamily
!= _family
)
3103 from
= createAddress();
3104 socklen_t nameLen
= from
.nameLen
;
3107 auto read
= .recvfrom(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, from
.name
, &nameLen
);
3108 from
.setNameLen(nameLen
);
3109 assert(from
.addressFamily
== _family
);
3110 // if (!read) //connection closed
3115 auto read
= .recvfrom(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, from
.name
, &nameLen
);
3116 from
.setNameLen(nameLen
);
3117 assert(from
.addressFamily
== _family
);
3118 // if (!read) //connection closed
3125 ptrdiff_t
receiveFrom(void[] buf
, ref Address from
)
3127 return receiveFrom(buf
, SocketFlags
.NONE
, from
);
3131 //assumes you connect()ed
3133 ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
) @trusted
3135 if (!buf
.length
) //return 0 and don't think the connection closed
3139 auto read
= .recvfrom(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, null, null);
3140 // if (!read) //connection closed
3145 auto read
= .recvfrom(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, null, null);
3146 // if (!read) //connection closed
3152 //assumes you connect()ed
3154 ptrdiff_t
receiveFrom(void[] buf
)
3156 return receiveFrom(buf
, SocketFlags
.NONE
);
3161 * Get a socket option.
3162 * Returns: The number of bytes written to $(D result).
3163 * The length, in bytes, of the actual result - very different from getsockopt()
3165 int getOption(SocketOptionLevel level
, SocketOption option
, void[] result
) @trusted
3167 socklen_t len
= cast(socklen_t
) result
.length
;
3168 if (_SOCKET_ERROR
== .getsockopt(sock
, cast(int) level
, cast(int) option
, result
.ptr
, &len
))
3169 throw new SocketOSException("Unable to get socket option");
3174 /// Common case of getting integer and boolean options.
3175 int getOption(SocketOptionLevel level
, SocketOption option
, out int32_t result
) @trusted
3177 return getOption(level
, option
, (&result
)[0 .. 1]);
3181 /// Get the linger option.
3182 int getOption(SocketOptionLevel level
, SocketOption option
, out Linger result
) @trusted
3184 //return getOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
3185 return getOption(level
, option
, (&result
.clinger
)[0 .. 1]);
3188 /// Get a timeout (duration) option.
3189 void getOption(SocketOptionLevel level
, SocketOption option
, out Duration result
) @trusted
3191 enforce(option
== SocketOption
.SNDTIMEO || option
== SocketOption
.RCVTIMEO
,
3192 new SocketParameterException("Not a valid timeout option: " ~ to
!string(option
)));
3193 // WinSock returns the timeout values as a milliseconds DWORD,
3194 // while Linux and BSD return a timeval struct.
3198 getOption(level
, option
, (&msecs
)[0 .. 1]);
3199 if (option
== SocketOption
.RCVTIMEO
)
3200 msecs
+= WINSOCK_TIMEOUT_SKEW
;
3201 result
= dur
!"msecs"(msecs
);
3203 else version (Posix
)
3206 getOption(level
, option
, (&tv
.ctimeval
)[0 .. 1]);
3207 result
= dur
!"seconds"(tv
.seconds
) + dur
!"usecs"(tv
.microseconds
);
3209 else static assert(false);
3212 /// Set a socket option.
3213 void setOption(SocketOptionLevel level
, SocketOption option
, void[] value
) @trusted
3215 if (_SOCKET_ERROR
== .setsockopt(sock
, cast(int) level
,
3216 cast(int) option
, value
.ptr
, cast(uint) value
.length
))
3217 throw new SocketOSException("Unable to set socket option");
3221 /// Common case for setting integer and boolean options.
3222 void setOption(SocketOptionLevel level
, SocketOption option
, int32_t value
) @trusted
3224 setOption(level
, option
, (&value
)[0 .. 1]);
3228 /// Set the linger option.
3229 void setOption(SocketOptionLevel level
, SocketOption option
, Linger value
) @trusted
3231 //setOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
3232 setOption(level
, option
, (&value
.clinger
)[0 .. 1]);
3236 * Sets a timeout (duration) option, i.e. $(D SocketOption.SNDTIMEO) or
3237 * $(D RCVTIMEO). Zero indicates no timeout.
3239 * In a typical application, you might also want to consider using
3240 * a non-blocking socket instead of setting a timeout on a blocking one.
3242 * Note: While the receive timeout setting is generally quite accurate
3243 * on *nix systems even for smaller durations, there are two issues to
3244 * be aware of on Windows: First, although undocumented, the effective
3245 * timeout duration seems to be the one set on the socket plus half
3246 * a second. $(D setOption()) tries to compensate for that, but still,
3247 * timeouts under 500ms are not possible on Windows. Second, be aware
3248 * that the actual amount of time spent until a blocking call returns
3249 * randomly varies on the order of 10ms.
3252 * level = The level at which a socket option is defined.
3253 * option = Either $(D SocketOption.SNDTIMEO) or $(D SocketOption.RCVTIMEO).
3254 * value = The timeout duration to set. Must not be negative.
3256 * Throws: $(D SocketException) if setting the options fails.
3260 * import std.datetime;
3261 * import std.typecons;
3262 * auto pair = socketPair();
3263 * scope(exit) foreach (s; pair) s.close();
3265 * // Set a receive timeout, and then wait at one end of
3266 * // the socket pair, knowing that no data will arrive.
3267 * pair[0].setOption(SocketOptionLevel.SOCKET,
3268 * SocketOption.RCVTIMEO, dur!"seconds"(1));
3270 * auto sw = StopWatch(Yes.autoStart);
3272 * pair[0].receive(buffer);
3273 * writefln("Waited %s ms until the socket timed out.",
3277 void setOption(SocketOptionLevel level
, SocketOption option
, Duration value
) @trusted
3279 enforce(option
== SocketOption
.SNDTIMEO || option
== SocketOption
.RCVTIMEO
,
3280 new SocketParameterException("Not a valid timeout option: " ~ to
!string(option
)));
3282 enforce(value
>= dur
!"hnsecs"(0), new SocketParameterException(
3283 "Timeout duration must not be negative."));
3287 import std
.algorithm
.comparison
: max
;
3289 auto msecs
= to
!int(value
.total
!"msecs");
3290 if (msecs
!= 0 && option
== SocketOption
.RCVTIMEO
)
3291 msecs
= max(1, msecs
- WINSOCK_TIMEOUT_SKEW
);
3292 setOption(level
, option
, msecs
);
3294 else version (Posix
)
3297 value
.split
!("seconds", "usecs")(tv
.tv_sec
, tv
.tv_usec
);
3298 setOption(level
, option
, (&tv
)[0 .. 1]);
3300 else static assert(false);
3304 * Get a text description of this socket's error status, and clear the
3305 * socket's error status.
3307 string
getErrorText()
3310 getOption(SocketOptionLevel
.SOCKET
, SocketOption
.ERROR
, error
);
3311 return formatSocketError(error
);
3315 * Enables TCP keep-alive with the specified parameters.
3318 * time = Number of seconds with no activity until the first
3319 * keep-alive packet is sent.
3320 * interval = Number of seconds between when successive keep-alive
3321 * packets are sent if no acknowledgement is received.
3323 * Throws: $(D SocketOSException) if setting the options fails, or
3324 * $(D SocketFeatureException) if setting keep-alive parameters is
3325 * unsupported on the current platform.
3327 void setKeepAlive(int time
, int interval
) @trusted
3331 tcp_keepalive options
;
3333 options
.keepalivetime
= time
* 1000;
3334 options
.keepaliveinterval
= interval
* 1000;
3335 uint cbBytesReturned
;
3336 enforce(WSAIoctl(sock
, SIO_KEEPALIVE_VALS
,
3337 &options
, options
.sizeof
,
3339 &cbBytesReturned
, null, null) == 0,
3340 new SocketOSException("Error setting keep-alive"));
3343 static if (is(typeof(TCP_KEEPIDLE
)) && is(typeof(TCP_KEEPINTVL
)))
3345 setOption(SocketOptionLevel
.TCP
, cast(SocketOption
) TCP_KEEPIDLE
, time
);
3346 setOption(SocketOptionLevel
.TCP
, cast(SocketOption
) TCP_KEEPINTVL
, interval
);
3347 setOption(SocketOptionLevel
.SOCKET
, SocketOption
.KEEPALIVE
, true);
3350 throw new SocketFeatureException("Setting keep-alive options " ~
3351 "is not supported on this platform");
3355 * Wait for a socket to change status. A wait timeout of $(REF Duration, core, time) or
3356 * $(D TimeVal), may be specified; if a timeout is not specified or the
3357 * $(D TimeVal) is $(D null), the maximum timeout is used. The $(D TimeVal)
3358 * timeout has an unspecified value when $(D select) returns.
3359 * Returns: The number of sockets with status changes, $(D 0) on timeout,
3360 * or $(D -1) on interruption. If the return value is greater than $(D 0),
3361 * the $(D SocketSets) are updated to only contain the sockets having status
3362 * changes. For a connecting socket, a write status change means the
3363 * connection is established and it's able to send. For a listening socket,
3364 * a read status change means there is an incoming connection request and
3365 * it's able to accept.
3367 * `SocketSet`'s updated to include only those sockets which an event occured.
3368 * For a `connect()`ing socket, writeability means connected.
3369 * For a `listen()`ing socket, readability means listening
3370 * `Winsock`; possibly internally limited to 64 sockets per set.
3373 * the number of events, 0 on timeout, or -1 on interruption
3375 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
, Duration timeout
) @trusted
3377 auto vals
= timeout
.split
!("seconds", "usecs")();
3379 tv
.seconds
= cast(tv
.tv_sec_t
) vals
.seconds
;
3380 tv
.microseconds
= cast(tv
.tv_usec_t
) vals
.usecs
;
3381 return select(checkRead
, checkWrite
, checkError
, &tv
);
3386 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
)
3388 return select(checkRead
, checkWrite
, checkError
, null);
3392 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
, TimeVal
* timeout
) @trusted
3395 //make sure none of the SocketSet's are the same object
3398 assert(checkRead
!is checkWrite
);
3399 assert(checkRead
!is checkError
);
3403 assert(checkWrite
!is checkError
);
3413 // Windows has a problem with empty fd_set`s that aren't null.
3414 fr
= checkRead
&& checkRead
.count ? checkRead
.toFd_set() : null;
3415 fw
= checkWrite
&& checkWrite
.count ? checkWrite
.toFd_set() : null;
3416 fe
= checkError
&& checkError
.count ? checkError
.toFd_set() : null;
3422 fr
= checkRead
.toFd_set();
3423 n
= checkRead
.selectn();
3432 fw
= checkWrite
.toFd_set();
3434 _n
= checkWrite
.selectn();
3445 fe
= checkError
.toFd_set();
3447 _n
= checkError
.selectn();
3456 // Make sure the sets' capacity matches, to avoid select reading
3457 // out of bounds just because one set was bigger than another
3458 if (checkRead
) checkRead
.setMinCapacity(n
);
3459 if (checkWrite
) checkWrite
.setMinCapacity(n
);
3460 if (checkError
) checkError
.setMinCapacity(n
);
3463 int result
= .select(n
, fr
, fw
, fe
, &timeout
.ctimeval
);
3467 if (_SOCKET_ERROR
== result
&& WSAGetLastError() == WSAEINTR
)
3470 else version (Posix
)
3472 if (_SOCKET_ERROR
== result
&& errno
== EINTR
)
3480 if (_SOCKET_ERROR
== result
)
3481 throw new SocketOSException("Socket select error");
3488 * Can be overridden to support other addresses.
3489 * Returns: a new `Address` object for the current address family.
3491 protected Address
createAddress() pure nothrow
3496 static if (is(sockaddr_un
))
3498 case AddressFamily
.UNIX
:
3499 result
= new UnixAddress
;
3503 case AddressFamily
.INET
:
3504 result
= new InternetAddress
;
3507 case AddressFamily
.INET6
:
3508 result
= new Internet6Address
;
3512 result
= new UnknownAddress
;
3520 /// $(D TcpSocket) is a shortcut class for a TCP Socket.
3521 class TcpSocket
: Socket
3523 /// Constructs a blocking TCP Socket.
3524 this(AddressFamily family
)
3526 super(family
, SocketType
.STREAM
, ProtocolType
.TCP
);
3529 /// Constructs a blocking IPv4 TCP Socket.
3532 this(AddressFamily
.INET
);
3537 /// Constructs a blocking TCP Socket and connects to an $(D Address).
3538 this(Address connectTo
)
3540 this(connectTo
.addressFamily
);
3546 /// $(D UdpSocket) is a shortcut class for a UDP Socket.
3547 class UdpSocket
: Socket
3549 /// Constructs a blocking UDP Socket.
3550 this(AddressFamily family
)
3552 super(family
, SocketType
.DGRAM
, ProtocolType
.UDP
);
3556 /// Constructs a blocking IPv4 UDP Socket.
3559 this(AddressFamily
.INET
);
3566 class TestSocket
: Socket
3570 const pure nothrow @nogc @property @safe socket_t
handle() { assert(0); }
3571 const nothrow @nogc @property @trusted bool blocking() { assert(0); }
3572 @property @trusted void blocking(bool byes
) { assert(0); }
3573 @property @safe AddressFamily
addressFamily() { assert(0); }
3574 const @property @trusted bool isAlive() { assert(0); }
3575 @trusted void bind(Address addr
) { assert(0); }
3576 @trusted void connect(Address to
) { assert(0); }
3577 @trusted void listen(int backlog
) { assert(0); }
3578 protected pure nothrow @safe Socket
accepting() { assert(0); }
3579 @trusted Socket
accept() { assert(0); }
3580 nothrow @nogc @trusted void shutdown(SocketShutdown how
) { assert(0); }
3581 nothrow @nogc @trusted void close() { assert(0); }
3582 @property @trusted Address
remoteAddress() { assert(0); }
3583 @property @trusted Address
localAddress() { assert(0); }
3584 @trusted ptrdiff_t
send(const(void)[] buf
, SocketFlags flags
) { assert(0); }
3585 @safe ptrdiff_t
send(const(void)[] buf
) { assert(0); }
3586 @trusted ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
, Address to
) { assert(0); }
3587 @safe ptrdiff_t
sendTo(const(void)[] buf
, Address to
) { assert(0); }
3588 @trusted ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
) { assert(0); }
3589 @safe ptrdiff_t
sendTo(const(void)[] buf
) { assert(0); }
3590 @trusted ptrdiff_t
receive(void[] buf
, SocketFlags flags
) { assert(0); }
3591 @safe ptrdiff_t
receive(void[] buf
) { assert(0); }
3592 @trusted ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
, ref Address from
) { assert(0); }
3593 @safe ptrdiff_t
receiveFrom(void[] buf
, ref Address from
) { assert(0); }
3594 @trusted ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
) { assert(0); }
3595 @safe ptrdiff_t
receiveFrom(void[] buf
) { assert(0); }
3596 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, void[] result
) { assert(0); }
3597 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, out int32_t result
) { assert(0); }
3598 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, out Linger result
) { assert(0); }
3599 @trusted void getOption(SocketOptionLevel level
, SocketOption option
, out Duration result
) { assert(0); }
3600 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, void[] value
) { assert(0); }
3601 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, int32_t value
) { assert(0); }
3602 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, Linger value
) { assert(0); }
3603 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, Duration value
) { assert(0); }
3604 @safe string
getErrorText() { assert(0); }
3605 @trusted void setKeepAlive(int time
, int interval
) { assert(0); }
3606 protected pure nothrow @safe Address
createAddress() { assert(0); }
3612 * Creates a pair of connected sockets.
3614 * The two sockets are indistinguishable.
3616 * Throws: $(D SocketException) if creation of the sockets fails.
3618 Socket
[2] socketPair() @trusted
3623 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, socks
) == -1)
3624 throw new SocketOSException("Unable to create socket pair");
3626 Socket
toSocket(size_t id
)
3628 auto s
= new Socket
;
3629 s
.setSock(cast(socket_t
) socks
[id
]);
3630 s
._family
= AddressFamily
.UNIX
;
3634 return [toSocket(0), toSocket(1)];
3636 else version (Windows
)
3638 // We do not have socketpair() on Windows, just manually create a
3639 // pair of sockets connected over some localhost port.
3642 auto listener
= new TcpSocket();
3643 listener
.setOption(SocketOptionLevel
.SOCKET
, SocketOption
.REUSEADDR
, true);
3644 listener
.bind(new InternetAddress(INADDR_LOOPBACK
, InternetAddress
.PORT_ANY
));
3645 auto addr
= listener
.localAddress
;
3648 result
[0] = new TcpSocket(addr
);
3649 result
[1] = listener
.accept();
3655 static assert(false);
3661 immutable ubyte[] data
= [1, 2, 3, 4];
3662 auto pair
= socketPair();
3663 scope(exit
) foreach (s
; pair
) s
.close();
3667 auto buf
= new ubyte[data
.length
];
3668 pair
[1].receive(buf
);
3669 assert(buf
== data
);