1 // Written in the D programming language
3 // NOTE: When working on this module, be sure to run tests with -debug=std_socket
4 // E.g.: dmd -version=StdUnittest -debug=std_socket -unittest -main -run socket
5 // This will enable some tests which are too slow or flaky to run as part of CI.
8 Copyright (C) 2004-2011 Christopher E. Miller
13 Thanks to Benjamin Herr for his assistance.
18 * Example: See $(SAMPLESRC listener.d) and $(SAMPLESRC htmlget.d)
19 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
20 * Authors: Christopher E. Miller, $(HTTP klickverbot.at, David Nadlinger),
21 * $(HTTP thecybershadow.net, Vladimir Panteleev)
22 * Source: $(PHOBOSSRC std/socket.d)
27 import core
.stdc
.stdint
, core
.stdc
.stdlib
, core
.stdc
.string
, std
.conv
, std
.string
;
29 import core
.stdc
.config
;
30 import core
.time
: dur
, Duration
;
33 import std
.internal
.cstring
;
39 else version (WatchOS
)
46 pragma (lib
, "ws2_32.lib");
47 pragma (lib
, "wsock32.lib");
49 import core
.sys
.windows
.winbase
, std
.windows
.syserror
;
50 public import core
.sys
.windows
.winsock2
;
51 private alias _ctimeval
= core
.sys
.windows
.winsock2
.timeval
;
52 private alias _clinger
= core
.sys
.windows
.winsock2
.linger
;
54 enum socket_t
: SOCKET
{ INVALID_SOCKET
}
55 private const int _SOCKET_ERROR
= SOCKET_ERROR
;
58 private int _lasterr() nothrow @nogc
60 return WSAGetLastError();
74 public import core
.sys
.posix
.netinet
.in_
;
75 import core
.sys
.posix
.arpa
.inet
;
76 import core
.sys
.posix
.fcntl
;
77 import core
.sys
.posix
.netdb
;
78 import core
.sys
.posix
.netinet
.tcp
;
79 import core
.sys
.posix
.sys
.select
;
80 import core
.sys
.posix
.sys
.socket
;
81 import core
.sys
.posix
.sys
.time
;
82 import core
.sys
.posix
.sys
.un
: sockaddr_un
;
83 import core
.sys
.posix
.unistd
;
84 private alias _ctimeval
= core
.sys
.posix
.sys
.time
.timeval
;
85 private alias _clinger
= core
.sys
.posix
.sys
.socket
.linger
;
87 import core
.stdc
.errno
;
89 enum socket_t
: int32_t
{ _init
= -1 }
90 private const int _SOCKET_ERROR
= -1;
99 private int _lasterr() nothrow @nogc
106 static assert(0, "No socket support for this platform yet.");
109 version (StdUnittest
)
111 // Print a message on exception instead of failing the unittest.
112 private void softUnittest(void delegate() @safe test, int line
= __LINE__
) @trusted
118 import std
.stdio
: writefln
;
122 writefln("Ignoring std.socket(%d) test failure (likely caused by flaky environment): %s", line
, e
.msg
);
127 /// Base exception thrown by `std.socket`.
128 class SocketException
: Exception
130 mixin basicExceptionCtors
;
133 version (CRuntime_Glibc
) version = GNU_STRERROR
;
134 version (CRuntime_UClibc
) version = GNU_STRERROR
;
137 * Needs to be public so that SocketOSException can be thrown outside of
138 * std.socket (since it uses it as a default argument), but it probably doesn't
139 * need to actually show up in the docs, since there's not really any public
140 * need for it outside of being a default argument.
142 string
formatSocketError(int err
) @trusted
148 version (GNU_STRERROR
)
150 cs
= strerror_r(err
, buf
.ptr
, buf
.length
);
154 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
158 return "Socket error " ~ to
!string(err
);
161 auto len
= strlen(cs
);
163 if (cs
[len
- 1] == '\n')
165 if (cs
[len
- 1] == '\r')
167 return cs
[0 .. len
].idup
;
172 return generateSysErrorMsg(err
);
175 return "Socket error " ~ to
!string(err
);
178 /// Retrieve the error message for the most recently encountered network error.
179 @property string
lastSocketError()
181 return formatSocketError(_lasterr());
185 * Socket exceptions representing network errors reported by the operating
188 class SocketOSException
: SocketException
190 int errorCode
; /// Platform-specific error code.
194 string file
= __FILE__
,
195 size_t line
= __LINE__
,
196 Throwable next
= null,
197 int err
= _lasterr(),
198 string
function(int) @trusted errorFormatter
= &formatSocketError
)
203 super(msg
~ ": " ~ errorFormatter(err
), file
, line
, next
);
205 super(errorFormatter(err
), file
, line
, next
);
211 string file
= __FILE__
,
212 size_t line
= __LINE__
,
213 int err
= _lasterr(),
214 string
function(int) @trusted errorFormatter
= &formatSocketError
)
216 this(msg
, file
, line
, next
, err
, errorFormatter
);
222 string
function(int) @trusted errorFormatter
= &formatSocketError
,
223 string file
= __FILE__
,
224 size_t line
= __LINE__
,
225 Throwable next
= null)
227 this(msg
, file
, line
, next
, err
, errorFormatter
);
231 /// Socket exceptions representing invalid parameters specified by user code.
232 class SocketParameterException
: SocketException
234 mixin basicExceptionCtors
;
238 * Socket exceptions representing attempts to use network capabilities not
239 * available on the current system.
241 class SocketFeatureException
: SocketException
243 mixin basicExceptionCtors
;
249 * `true` if the last socket operation failed because the socket
250 * was in non-blocking mode and the operation would have blocked,
251 * or if the socket is in blocking mode and set a SNDTIMEO or RCVTIMEO,
252 * and the operation timed out.
254 bool wouldHaveBlocked() nothrow @nogc
257 return _lasterr() == WSAEWOULDBLOCK ||
_lasterr() == WSAETIMEDOUT
;
259 return _lasterr() == EAGAIN
;
261 static assert(0, "No socket support for this platform yet.");
266 auto sockets
= socketPair();
268 s
.setOption(SocketOptionLevel
.SOCKET
, SocketOption
.RCVTIMEO
, dur
!"msecs"(10));
269 ubyte[] buffer
= new ubyte[](16);
270 auto rec
= s
.receive(buffer
);
271 assert(rec
== -1 && wouldHaveBlocked());
277 typeof(&getnameinfo
) getnameinfoPointer
;
278 typeof(&getaddrinfo
) getaddrinfoPointer
;
279 typeof(&freeaddrinfo
) freeaddrinfoPointer
;
282 shared static this() @system
288 // Winsock will still load if an older version is present.
289 // The version is just a request.
291 val
= WSAStartup(0x2020, &wd
);
292 if (val
) // Request Winsock 2.2 for IPv6.
293 throw new SocketOSException("Unable to initialize socket library", val
);
295 // These functions may not be present on older Windows versions.
296 // See the comment in InternetAddress.toHostNameString() for details.
297 auto ws2Lib
= GetModuleHandleA("ws2_32.dll");
300 getnameinfoPointer
= cast(typeof(getnameinfoPointer
))
301 GetProcAddress(ws2Lib
, "getnameinfo");
302 getaddrinfoPointer
= cast(typeof(getaddrinfoPointer
))
303 GetProcAddress(ws2Lib
, "getaddrinfo");
304 freeaddrinfoPointer
= cast(typeof(freeaddrinfoPointer
))
305 GetProcAddress(ws2Lib
, "freeaddrinfo");
310 getnameinfoPointer
= &getnameinfo
;
311 getaddrinfoPointer
= &getaddrinfo
;
312 freeaddrinfoPointer
= &freeaddrinfo
;
317 shared static ~this() @system nothrow @nogc
326 * The communication domain used to resolve an address.
328 enum AddressFamily
: ushort
330 UNSPEC
= AF_UNSPEC
, /// Unspecified address family
331 UNIX
= AF_UNIX
, /// Local communication
332 INET
= AF_INET
, /// Internet Protocol version 4
333 IPX
= AF_IPX
, /// Novell IPX
334 APPLETALK
= AF_APPLETALK
, /// AppleTalk
335 INET6
= AF_INET6
, /// Internet Protocol version 6
340 * Communication semantics
344 STREAM
= SOCK_STREAM
, /// Sequenced, reliable, two-way communication-based byte streams
345 DGRAM
= SOCK_DGRAM
, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
346 RAW
= SOCK_RAW
, /// Raw protocol access
347 RDM
= SOCK_RDM
, /// Reliably-delivered message datagrams
348 SEQPACKET
= SOCK_SEQPACKET
, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
355 enum ProtocolType
: int
357 IP
= IPPROTO_IP
, /// Internet Protocol version 4
358 ICMP
= IPPROTO_ICMP
, /// Internet Control Message Protocol
359 IGMP
= IPPROTO_IGMP
, /// Internet Group Management Protocol
360 GGP
= IPPROTO_GGP
, /// Gateway to Gateway Protocol
361 TCP
= IPPROTO_TCP
, /// Transmission Control Protocol
362 PUP
= IPPROTO_PUP
, /// PARC Universal Packet Protocol
363 UDP
= IPPROTO_UDP
, /// User Datagram Protocol
364 IDP
= IPPROTO_IDP
, /// Xerox NS protocol
365 RAW
= IPPROTO_RAW
, /// Raw IP packets
366 IPV6
= IPPROTO_IPV6
, /// Internet Protocol version 6
371 * `Protocol` is a class for retrieving protocol information.
375 * auto proto = new Protocol;
376 * writeln("About protocol TCP:");
377 * if (proto.getProtocolByType(ProtocolType.TCP))
379 * writefln(" Name: %s", proto.name);
380 * foreach (string s; proto.aliases)
381 * writefln(" Alias: %s", s);
384 * writeln(" No information found");
389 /// These members are populated when one of the following functions are called successfully:
391 string name
; /// ditto
392 string
[] aliases
; /// ditto
395 void populate(protoent
* proto
) @system pure nothrow
397 type
= cast(ProtocolType
) proto
.p_proto
;
398 name
= to
!string(proto
.p_name
);
403 if (!proto
.p_aliases
[i
])
409 aliases
= new string
[i
];
410 for (i
= 0; i
!= aliases
.length
; i
++)
413 to
!string(proto
.p_aliases
[i
]);
422 /** Returns: false on failure */
423 bool getProtocolByName(scope const(char)[] name
) @trusted nothrow
426 proto
= getprotobyname(name
.tempCString());
434 /** Returns: false on failure */
435 // Same as getprotobynumber().
436 bool getProtocolByType(ProtocolType type
) @trusted nothrow
439 proto
= getprotobynumber(type
);
448 // Skip this test on Android because getprotobyname/number are
449 // unimplemented in bionic.
450 version (CRuntime_Bionic
) {} else
453 // import std.stdio : writefln;
455 Protocol proto
= new Protocol
;
456 assert(proto
.getProtocolByType(ProtocolType
.TCP
));
457 //writeln("About protocol TCP:");
458 //writefln("\tName: %s", proto.name);
459 // foreach (string s; proto.aliases)
461 // writefln("\tAlias: %s", s);
463 assert(proto
.name
== "tcp");
464 assert(proto
.aliases
.length
== 1 && proto
.aliases
[0] == "TCP");
470 * `Service` is a class for retrieving service information.
474 * auto serv = new Service;
475 * writeln("About service epmap:");
476 * if (serv.getServiceByName("epmap", "tcp"))
478 * writefln(" Service: %s", serv.name);
479 * writefln(" Port: %d", serv.port);
480 * writefln(" Protocol: %s", serv.protocolName);
481 * foreach (string s; serv.aliases)
482 * writefln(" Alias: %s", s);
485 * writefln(" No service for epmap.");
490 /// These members are populated when one of the following functions are called successfully:
492 string
[] aliases
; /// ditto
493 ushort port
; /// ditto
494 string protocolName
; /// ditto
497 void populate(servent
* serv
) @system pure nothrow
499 name
= to
!string(serv
.s_name
);
500 port
= ntohs(cast(ushort) serv
.s_port
);
501 protocolName
= to
!string(serv
.s_proto
);
506 if (!serv
.s_aliases
[i
])
512 aliases
= new string
[i
];
513 for (i
= 0; i
!= aliases
.length
; i
++)
516 to
!string(serv
.s_aliases
[i
]);
526 * If a protocol name is omitted, any protocol will be matched.
527 * Returns: false on failure.
529 bool getServiceByName(scope const(char)[] name
, scope const(char)[] protocolName
= null) @trusted nothrow
532 serv
= getservbyname(name
.tempCString(), protocolName
.tempCString());
541 bool getServiceByPort(ushort port
, scope const(char)[] protocolName
= null) @trusted nothrow
544 serv
= getservbyport(port
, protocolName
.tempCString());
555 import std
.stdio
: writefln
;
557 Service serv
= new Service
;
558 if (serv
.getServiceByName("epmap", "tcp"))
560 // writefln("About service epmap:");
561 // writefln("\tService: %s", serv.name);
562 // writefln("\tPort: %d", serv.port);
563 // writefln("\tProtocol: %s", serv.protocolName);
564 // foreach (string s; serv.aliases)
566 // writefln("\tAlias: %s", s);
568 // For reasons unknown this is loc-srv on Wine and epmap on Windows
569 assert(serv
.name
== "loc-srv" || serv
.name
== "epmap", serv
.name
);
570 assert(serv
.port
== 135);
571 assert(serv
.protocolName
== "tcp");
575 writefln("No service for epmap.");
581 private mixin template socketOSExceptionCtors()
584 this(string msg
, string file
= __FILE__
, size_t line
= __LINE__
,
585 Throwable next
= null, int err
= _lasterr())
587 super(msg
, file
, line
, next
, err
);
591 this(string msg
, Throwable next
, string file
= __FILE__
,
592 size_t line
= __LINE__
, int err
= _lasterr())
594 super(msg
, next
, file
, line
, err
);
598 this(string msg
, int err
, string file
= __FILE__
, size_t line
= __LINE__
,
599 Throwable next
= null)
601 super(msg
, next
, file
, line
, err
);
607 * Class for exceptions thrown from an `InternetHost`.
609 class HostException
: SocketOSException
611 mixin socketOSExceptionCtors
;
615 * `InternetHost` is a class for resolving IPv4 addresses.
617 * Consider using `getAddress`, `parseAddress` and `Address` methods
618 * instead of using this class directly.
622 /// These members are populated when one of the following functions are called successfully:
624 string
[] aliases
; /// ditto
625 uint[] addrList
; /// ditto
628 void validHostent(in hostent
* he
)
630 if (he
.h_addrtype
!= cast(int) AddressFamily
.INET || he
.h_length
!= 4)
631 throw new HostException("Address family mismatch");
635 void populate(hostent
* he
) @system pure nothrow
640 name
= to
!string(he
.h_name
);
651 aliases
= new string
[i
];
652 for (i
= 0; i
!= aliases
.length
; i
++)
655 to
!string(he
.h_aliases
[i
]);
665 p
= he
.h_addr_list
[i
];
672 addrList
= new uint[i
];
673 for (i
= 0; i
!= addrList
.length
; i
++)
675 addrList
[i
] = ntohl(*(cast(uint*) he
.h_addr_list
[i
]));
684 private bool getHostNoSync(string opMixin
, T
)(T param
) @system
695 alias getHost
= getHostNoSync
;
698 // posix systems use global state for return value, so we
699 // must synchronize across all threads
700 private bool getHost(string opMixin
, T
)(T param
) @system
702 synchronized(this.classinfo
)
703 return getHostNoSync
!(opMixin
, T
)(param
);
709 * Returns: false if unable to resolve.
711 bool getHostByName(scope const(char)[] name
) @trusted
713 static if (is(typeof(gethostbyname_r
)))
715 return getHostNoSync
!q
{
718 ubyte[256] buffer_v
= void;
719 auto buffer
= buffer_v
[];
720 auto param_zTmp
= param
.tempCString();
725 if (gethostbyname_r(param_zTmp
, he
, buffer
.ptr
, buffer
.length
, &he
, &errno
) == ERANGE
)
726 buffer
.length
= buffer
.length
* 2;
735 auto he
= gethostbyname(param
.tempCString());
741 * Resolve IPv4 address number.
744 * addr = The IPv4 address to resolve, in host byte order.
746 * false if unable to resolve.
748 bool getHostByAddr(uint addr
) @trusted
751 auto x
= htonl(param
);
752 auto he
= gethostbyaddr(&x
, 4, cast(int) AddressFamily
.INET
);
757 * Same as previous, but addr is an IPv4 address string in the
758 * dotted-decimal form $(I a.b.c.d).
759 * Returns: false if unable to resolve.
761 bool getHostByAddr(scope const(char)[] addr
) @trusted
764 auto x
= inet_addr(param
.tempCString());
765 enforce(x
!= INADDR_NONE
,
766 new SocketParameterException("Invalid IPv4 address"));
767 auto he
= gethostbyaddr(&x
, 4, cast(int) AddressFamily
.INET
);
775 InternetHost ih
= new InternetHost
;
777 ih
.getHostByAddr(0x7F_00_00_01);
778 assert(ih
.addrList
[0] == 0x7F_00_00_01);
779 ih
.getHostByAddr("127.0.0.1");
780 assert(ih
.addrList
[0] == 0x7F_00_00_01);
782 if (!ih
.getHostByName("www.digitalmars.com"))
783 return; // don't fail if not connected to internet
785 assert(ih
.addrList
.length
);
786 InternetAddress ia
= new InternetAddress(ih
.addrList
[0], InternetAddress
.PORT_ANY
);
787 assert(ih
.name
== "www.digitalmars.com" || ih
.name
== "digitalmars.com",
790 /* The following assert randomly fails in the test suite.
791 * https://issues.dlang.org/show_bug.cgi?id=22791
792 * So just ignore it when it fails.
794 //assert(ih.getHostByAddr(ih.addrList[0]));
795 if (ih
.getHostByAddr(ih
.addrList
[0]))
797 string getHostNameFromInt
= ih
.name
.dup
;
799 assert(ih
.getHostByAddr(ia
.toAddrString()));
800 string getHostNameFromStr
= ih
.name
.dup
;
802 assert(getHostNameFromInt
== getHostNameFromStr
);
807 /// Holds information about a socket _address retrieved by `getAddressInfo`.
810 AddressFamily family
; /// Address _family
811 SocketType type
; /// Socket _type
812 ProtocolType protocol
; /// Protocol
813 Address address
; /// Socket _address
814 string canonicalName
; /// Canonical name, when `AddressInfoFlags.CANONNAME` is used.
818 * A subset of flags supported on all platforms with getaddrinfo.
819 * Specifies option flags for `getAddressInfo`.
821 enum AddressInfoFlags
: int
823 /// The resulting addresses will be used in a call to `Socket.bind`.
824 PASSIVE
= AI_PASSIVE
,
826 /// The canonical name is returned in `canonicalName` member in the first `AddressInfo`.
827 CANONNAME
= AI_CANONNAME
,
830 * The `node` parameter passed to `getAddressInfo` must be a numeric string.
831 * This will suppress any potentially lengthy network host address lookups.
833 NUMERICHOST
= AI_NUMERICHOST
,
838 * On POSIX, getaddrinfo uses its own error codes, and thus has its own
839 * formatting function.
841 private string
formatGaiError(int err
) @trusted
845 return generateSysErrorMsg(err
);
850 return to
!string(gai_strerror(err
));
855 * Provides _protocol-independent translation from host names to socket
856 * addresses. If advanced functionality is not required, consider using
857 * `getAddress` for compatibility with older systems.
859 * Returns: Array with one `AddressInfo` per socket address.
861 * Throws: `SocketOSException` on failure, or `SocketFeatureException`
862 * if this functionality is not available on the current system.
865 * node = string containing host name or numeric address
866 * options = optional additional parameters, identified by type:
867 * $(UL $(LI `string` - service name or port number)
868 * $(LI `AddressInfoFlags` - option flags)
869 * $(LI `AddressFamily` - address family to filter by)
870 * $(LI `SocketType` - socket type to filter by)
871 * $(LI `ProtocolType` - protocol to filter by))
875 * // Roundtrip DNS resolution
876 * auto results = getAddressInfo("www.digitalmars.com");
877 * assert(results[0].address.toHostNameString() ==
878 * "digitalmars.com");
881 * results = getAddressInfo("www.digitalmars.com",
882 * AddressInfoFlags.CANONNAME);
883 * assert(results[0].canonicalName == "digitalmars.com");
886 * results = getAddressInfo("ipv6.google.com");
887 * assert(results[0].family == AddressFamily.INET6);
889 * // Multihomed resolution
890 * results = getAddressInfo("google.com");
891 * assert(results.length > 1);
894 * results = getAddressInfo("127.0.0.1",
895 * AddressInfoFlags.NUMERICHOST);
896 * assert(results.length && results[0].family ==
897 * AddressFamily.INET);
900 * results = getAddressInfo("::1",
901 * AddressInfoFlags.NUMERICHOST);
902 * assert(results.length && results[0].family ==
903 * AddressFamily.INET6);
906 AddressInfo
[] getAddressInfo(T
...)(scope const(char)[] node
, scope T options
)
908 const(char)[] service
= null;
910 hints
.ai_family
= AF_UNSPEC
;
912 foreach (i
, option
; options
)
914 static if (is(typeof(option
) : const(char)[]))
915 service
= options
[i
];
917 static if (is(typeof(option
) == AddressInfoFlags
))
918 hints
.ai_flags |
= option
;
920 static if (is(typeof(option
) == AddressFamily
))
921 hints
.ai_family
= option
;
923 static if (is(typeof(option
) == SocketType
))
924 hints
.ai_socktype
= option
;
926 static if (is(typeof(option
) == ProtocolType
))
927 hints
.ai_protocol
= option
;
929 static assert(0, "Unknown getAddressInfo option type: " ~ typeof(option
).stringof
);
932 return () @trusted { return getAddressInfoImpl(node
, service
, &hints
); }();
939 const(char[]) breakSafety()
941 *cast(int*) 0xcafebabe = 0xdeadbeef;
944 alias breakSafety
this;
946 assert(!__traits(compiles
, () {
947 getAddressInfo("", Oops
.init
);
948 }), "getAddressInfo breaks @safe");
951 private AddressInfo
[] getAddressInfoImpl(scope const(char)[] node
, scope const(char)[] service
, addrinfo
* hints
) @system
953 import std
.array
: appender
;
955 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
959 int ret = getaddrinfoPointer(
961 service
.tempCString(),
963 enforce(ret == 0, new SocketOSException("getaddrinfo error", ret, &formatGaiError
));
964 scope(exit
) freeaddrinfoPointer(ai_res
);
966 auto result
= appender
!(AddressInfo
[])();
968 // Use const to force UnknownAddressReference to copy the sockaddr.
969 for (const(addrinfo
)* ai
= ai_res
; ai
; ai
= ai
.ai_next
)
970 result
~= AddressInfo(
971 cast(AddressFamily
) ai
.ai_family
,
972 cast(SocketType
) ai
.ai_socktype
,
973 cast(ProtocolType
) ai
.ai_protocol
,
974 new UnknownAddressReference(ai
.ai_addr
, cast(socklen_t
) ai
.ai_addrlen
),
975 ai
.ai_canonname ? to
!string(ai
.ai_canonname
) : null);
977 assert(result
.data
.length
> 0);
981 throw new SocketFeatureException("Address info lookup is not available " ~
989 if (getaddrinfoPointer
)
991 // Roundtrip DNS resolution
992 auto results
= getAddressInfo("www.digitalmars.com");
993 assert(results
[0].address
.toHostNameString() == "digitalmars.com");
996 results
= getAddressInfo("www.digitalmars.com",
997 AddressInfoFlags
.CANONNAME
);
998 assert(results
[0].canonicalName
== "digitalmars.com");
1001 //results = getAddressInfo("ipv6.google.com");
1002 //assert(results[0].family == AddressFamily.INET6);
1004 // Multihomed resolution
1005 //results = getAddressInfo("google.com");
1006 //assert(results.length > 1);
1009 results
= getAddressInfo("127.0.0.1", AddressInfoFlags
.NUMERICHOST
);
1010 assert(results
.length
&& results
[0].family
== AddressFamily
.INET
);
1013 results
= getAddressInfo("::1", AddressInfoFlags
.NUMERICHOST
);
1014 assert(results
.length
&& results
[0].family
== AddressFamily
.INET6
);
1018 if (getaddrinfoPointer
)
1020 auto results
= getAddressInfo(null, "1234", AddressInfoFlags
.PASSIVE
,
1021 SocketType
.STREAM
, ProtocolType
.TCP
, AddressFamily
.INET
);
1022 assert(results
.length
== 1 && results
[0].address
.toString() == "0.0.0.0:1234");
1027 private ushort serviceToPort(scope const(char)[] service
)
1030 return InternetAddress
.PORT_ANY
;
1032 if (isNumeric(service
))
1033 return to
!ushort(service
);
1036 auto s
= new Service();
1037 s
.getServiceByName(service
);
1043 * Provides _protocol-independent translation from host names to socket
1044 * addresses. Uses `getAddressInfo` if the current system supports it,
1045 * and `InternetHost` otherwise.
1047 * Returns: Array with one `Address` instance per socket address.
1049 * Throws: `SocketOSException` on failure.
1053 * writeln("Resolving www.digitalmars.com:");
1056 * auto addresses = getAddress("www.digitalmars.com");
1057 * foreach (address; addresses)
1058 * writefln(" IP: %s", address.toAddrString());
1060 * catch (SocketException e)
1061 * writefln(" Lookup failed: %s", e.msg);
1064 Address
[] getAddress(scope const(char)[] hostname
, scope const(char)[] service
= null)
1066 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1068 // use getAddressInfo
1069 auto infos
= getAddressInfo(hostname
, service
);
1071 results
.length
= infos
.length
;
1072 foreach (i
, ref result
; results
)
1073 result
= infos
[i
].address
;
1077 return getAddress(hostname
, serviceToPort(service
));
1081 Address
[] getAddress(scope const(char)[] hostname
, ushort port
)
1083 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1084 return getAddress(hostname
, to
!string(port
));
1087 // use getHostByName
1088 auto ih
= new InternetHost
;
1089 if (!ih
.getHostByName(hostname
))
1090 throw new AddressException(
1091 text("Unable to resolve host '", hostname
, "'"));
1094 foreach (uint addr
; ih
.addrList
)
1095 results
~= new InternetAddress(addr
, port
);
1104 auto addresses
= getAddress("63.105.9.61");
1105 assert(addresses
.length
&& addresses
[0].toAddrString() == "63.105.9.61");
1107 if (getaddrinfoPointer
)
1109 // test via gethostbyname
1110 auto getaddrinfoPointerBackup
= getaddrinfoPointer
;
1111 cast() getaddrinfoPointer
= null;
1112 scope(exit
) cast() getaddrinfoPointer
= getaddrinfoPointerBackup
;
1114 addresses
= getAddress("63.105.9.61");
1115 assert(addresses
.length
&& addresses
[0].toAddrString() == "63.105.9.61");
1122 * Provides _protocol-independent parsing of network addresses. Does not
1123 * attempt name resolution. Uses `getAddressInfo` with
1124 * `AddressInfoFlags.NUMERICHOST` if the current system supports it, and
1125 * `InternetAddress` otherwise.
1127 * Returns: An `Address` instance representing specified address.
1129 * Throws: `SocketException` on failure.
1133 * writeln("Enter IP address:");
1134 * string ip = readln().chomp();
1137 * Address address = parseAddress(ip);
1138 * writefln("Looking up reverse of %s:",
1139 * address.toAddrString());
1142 * string reverse = address.toHostNameString();
1144 * writefln(" Reverse name: %s", reverse);
1146 * writeln(" Reverse hostname not found.");
1148 * catch (SocketException e)
1149 * writefln(" Lookup error: %s", e.msg);
1151 * catch (SocketException e)
1153 * writefln(" %s is not a valid IP address: %s",
1158 Address
parseAddress(scope const(char)[] hostaddr
, scope const(char)[] service
= null)
1160 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1161 return getAddressInfo(hostaddr
, service
, AddressInfoFlags
.NUMERICHOST
)[0].address
;
1163 return parseAddress(hostaddr
, serviceToPort(service
));
1167 Address
parseAddress(scope const(char)[] hostaddr
, ushort port
)
1169 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1170 return parseAddress(hostaddr
, to
!string(port
));
1173 auto in4_addr
= InternetAddress
.parse(hostaddr
);
1174 enforce(in4_addr
!= InternetAddress
.ADDR_NONE
,
1175 new SocketParameterException("Invalid IP address"));
1176 return new InternetAddress(in4_addr
, port
);
1184 auto address
= parseAddress("63.105.9.61");
1185 assert(address
.toAddrString() == "63.105.9.61");
1187 if (getaddrinfoPointer
)
1189 // test via inet_addr
1190 auto getaddrinfoPointerBackup
= getaddrinfoPointer
;
1191 cast() getaddrinfoPointer
= null;
1192 scope(exit
) cast() getaddrinfoPointer
= getaddrinfoPointerBackup
;
1194 address
= parseAddress("63.105.9.61");
1195 assert(address
.toAddrString() == "63.105.9.61");
1198 assert(collectException
!SocketException(parseAddress("Invalid IP address")));
1204 * Class for exceptions thrown from an `Address`.
1206 class AddressException
: SocketOSException
1208 mixin socketOSExceptionCtors
;
1213 * `Address` is an abstract class for representing a socket addresses.
1217 * writeln("About www.google.com port 80:");
1220 * Address[] addresses = getAddress("www.google.com", 80);
1221 * writefln(" %d addresses found.", addresses.length);
1222 * foreach (int i, Address a; addresses)
1224 * writefln(" Address %d:", i+1);
1225 * writefln(" IP address: %s", a.toAddrString());
1226 * writefln(" Hostname: %s", a.toHostNameString());
1227 * writefln(" Port: %s", a.toPortString());
1228 * writefln(" Service name: %s",
1229 * a.toServiceNameString());
1232 * catch (SocketException e)
1233 * writefln(" Lookup error: %s", e.msg);
1236 abstract class Address
1238 /// Returns pointer to underlying `sockaddr` structure.
1239 abstract @property sockaddr
* name() pure nothrow @nogc;
1240 abstract @property const(sockaddr
)* name() const pure nothrow @nogc; /// ditto
1242 /// Returns actual size of underlying `sockaddr` structure.
1243 abstract @property socklen_t
nameLen() const pure nothrow @nogc;
1245 // Socket.remoteAddress, Socket.localAddress, and Socket.receiveFrom
1246 // use setNameLen to set the actual size of the address as returned by
1247 // getsockname, getpeername, and recvfrom, respectively.
1248 // The following implementation is sufficient for fixed-length addresses,
1249 // and ensures that the length is not changed.
1250 // Must be overridden for variable-length addresses.
1251 protected void setNameLen(socklen_t len
)
1253 if (len
!= this.nameLen
)
1254 throw new AddressException(
1255 format("%s expects address of length %d, not %d", typeid(this),
1256 this.nameLen
, len
), 0);
1259 /// Family of this address.
1260 @property AddressFamily
addressFamily() const pure nothrow @nogc
1262 return cast(AddressFamily
) name
.sa_family
;
1265 // Common code for toAddrString and toHostNameString
1266 private string
toHostString(bool numeric
) @trusted const
1268 // getnameinfo() is the recommended way to perform a reverse (name)
1269 // lookup on both Posix and Windows. However, it is only available
1270 // on Windows XP and above, and not included with the WinSock import
1271 // libraries shipped with DMD. Thus, we check for getnameinfo at
1272 // runtime in the shared module constructor, and use it if it's
1273 // available in the base class method. Classes for specific network
1274 // families (e.g. InternetHost) override this method and use a
1275 // deprecated, albeit commonly-available method when getnameinfo()
1276 // is not available.
1277 // http://technet.microsoft.com/en-us/library/aa450403.aspx
1278 if (getnameinfoPointer
)
1280 auto buf
= new char[NI_MAXHOST
];
1281 auto ret = getnameinfoPointer(
1283 buf
.ptr
, cast(uint) buf
.length
,
1285 numeric ? NI_NUMERICHOST
: NI_NAMEREQD
);
1289 if (ret == EAI_NONAME
)
1292 if (ret == WSANO_DATA
)
1296 enforce(ret == 0, new AddressException("Could not get " ~
1297 (numeric ?
"host address" : "host name")));
1298 return assumeUnique(buf
[0 .. strlen(buf
.ptr
)]);
1301 throw new SocketFeatureException((numeric ?
"Host address" : "Host name") ~
1302 " lookup for this address family is not available on this system.");
1305 // Common code for toPortString and toServiceNameString
1306 private string
toServiceString(bool numeric
) @trusted const
1308 // See toHostNameString() for details about getnameinfo().
1309 if (getnameinfoPointer
)
1311 auto buf
= new char[NI_MAXSERV
];
1312 enforce(getnameinfoPointer(
1315 buf
.ptr
, cast(uint) buf
.length
,
1316 numeric ? NI_NUMERICSERV
: NI_NAMEREQD
1317 ) == 0, new AddressException("Could not get " ~
1318 (numeric ?
"port number" : "service name")));
1319 return assumeUnique(buf
[0 .. strlen(buf
.ptr
)]);
1322 throw new SocketFeatureException((numeric ?
"Port number" : "Service name") ~
1323 " lookup for this address family is not available on this system.");
1327 * Attempts to retrieve the host address as a human-readable string.
1329 * Throws: `AddressException` on failure, or `SocketFeatureException`
1330 * if address retrieval for this address family is not available on the
1333 string
toAddrString() const
1335 return toHostString(true);
1339 * Attempts to retrieve the host name as a fully qualified domain name.
1341 * Returns: The FQDN corresponding to this `Address`, or `null` if
1342 * the host name did not resolve.
1344 * Throws: `AddressException` on error, or `SocketFeatureException`
1345 * if host name lookup for this address family is not available on the
1348 string
toHostNameString() const
1350 return toHostString(false);
1354 * Attempts to retrieve the numeric port number as a string.
1356 * Throws: `AddressException` on failure, or `SocketFeatureException`
1357 * if port number retrieval for this address family is not available on the
1360 string
toPortString() const
1362 return toServiceString(true);
1366 * Attempts to retrieve the service name as a string.
1368 * Throws: `AddressException` on failure, or `SocketFeatureException`
1369 * if service name lookup for this address family is not available on the
1372 string
toServiceNameString() const
1374 return toServiceString(false);
1377 /// Human readable string representing this address.
1378 override string
toString() const
1382 string host
= toAddrString();
1383 string port
= toPortString();
1384 if (host
.indexOf(':') >= 0)
1385 return "[" ~ host
~ "]:" ~ port
;
1387 return host
~ ":" ~ port
;
1389 catch (SocketException
)
1395 * `UnknownAddress` encapsulates an unknown socket address.
1397 class UnknownAddress
: Address
1404 override @property sockaddr
* name() return
1409 override @property const(sockaddr
)* name() const return
1415 override @property socklen_t
nameLen() const
1417 return cast(socklen_t
) sa
.sizeof
;
1424 * `UnknownAddressReference` encapsulates a reference to an arbitrary
1427 class UnknownAddressReference
: Address
1434 /// Constructs an `Address` with a reference to the specified `sockaddr`.
1435 this(sockaddr
* sa
, socklen_t len
) pure nothrow @nogc
1441 /// Constructs an `Address` with a copy of the specified `sockaddr`.
1442 this(const(sockaddr
)* sa
, socklen_t len
) @system pure nothrow
1444 this.sa
= cast(sockaddr
*) (cast(ubyte*) sa
)[0 .. len
].dup
.ptr
;
1448 override @property sockaddr
* name()
1453 override @property const(sockaddr
)* name() const
1459 override @property socklen_t
nameLen() const
1461 return cast(socklen_t
) len
;
1467 * `InternetAddress` encapsulates an IPv4 (Internet Protocol version 4)
1470 * Consider using `getAddress`, `parseAddress` and `Address` methods
1471 * instead of using this class directly.
1473 class InternetAddress
: Address
1479 this() pure nothrow @nogc
1485 override @property sockaddr
* name() return
1487 return cast(sockaddr
*)&sin
;
1490 override @property const(sockaddr
)* name() const return
1492 return cast(const(sockaddr
)*)&sin
;
1496 override @property socklen_t
nameLen() const
1498 return cast(socklen_t
) sin
.sizeof
;
1502 enum uint ADDR_ANY
= INADDR_ANY
; /// Any IPv4 host address.
1503 enum uint ADDR_NONE
= INADDR_NONE
; /// An invalid IPv4 host address.
1504 enum ushort PORT_ANY
= 0; /// Any IPv4 port number.
1506 /// Returns the IPv4 _port number (in host byte order).
1507 @property ushort port() const pure nothrow @nogc
1509 return ntohs(sin
.sin_port
);
1512 /// Returns the IPv4 address number (in host byte order).
1513 @property uint addr() const pure nothrow @nogc
1515 return ntohl(sin
.sin_addr
.s_addr
);
1519 * Construct a new `InternetAddress`.
1521 * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
1522 * or a host name which will be resolved using an `InternetHost`
1524 * port = port number, may be `PORT_ANY`.
1526 this(scope const(char)[] addr
, ushort port
)
1528 uint uiaddr
= parse(addr
);
1529 if (ADDR_NONE
== uiaddr
)
1531 InternetHost ih
= new InternetHost
;
1532 if (!ih
.getHostByName(addr
))
1533 //throw new AddressException("Invalid internet address");
1534 throw new AddressException(
1535 text("Unable to resolve host '", addr
, "'"));
1536 uiaddr
= ih
.addrList
[0];
1538 sin
.sin_family
= AddressFamily
.INET
;
1539 sin
.sin_addr
.s_addr
= htonl(uiaddr
);
1540 sin
.sin_port
= htons(port
);
1544 * Construct a new `InternetAddress`.
1546 * addr = (optional) an IPv4 address in host byte order, may be `ADDR_ANY`.
1547 * port = port number, may be `PORT_ANY`.
1549 this(uint addr
, ushort port
) pure nothrow @nogc
1551 sin
.sin_family
= AddressFamily
.INET
;
1552 sin
.sin_addr
.s_addr
= htonl(addr
);
1553 sin
.sin_port
= htons(port
);
1557 this(ushort port
) pure nothrow @nogc
1559 sin
.sin_family
= AddressFamily
.INET
;
1560 sin
.sin_addr
.s_addr
= ADDR_ANY
;
1561 sin
.sin_port
= htons(port
);
1565 * Construct a new `InternetAddress`.
1567 * addr = A sockaddr_in as obtained from lower-level API calls such as getifaddrs.
1569 this(sockaddr_in addr
) pure nothrow @nogc
1571 assert(addr
.sin_family
== AddressFamily
.INET
, "Socket address is not of INET family.");
1575 /// Human readable string representing the IPv4 address in dotted-decimal form.
1576 override string
toAddrString() @trusted const
1578 return to
!string(inet_ntoa(sin
.sin_addr
));
1581 /// Human readable string representing the IPv4 port.
1582 override string
toPortString() const
1584 return std
.conv
.to
!string(port
);
1588 * Attempts to retrieve the host name as a fully qualified domain name.
1590 * Returns: The FQDN corresponding to this `InternetAddress`, or
1591 * `null` if the host name did not resolve.
1593 * Throws: `AddressException` on error.
1595 override string
toHostNameString() const
1597 // getnameinfo() is the recommended way to perform a reverse (name)
1598 // lookup on both Posix and Windows. However, it is only available
1599 // on Windows XP and above, and not included with the WinSock import
1600 // libraries shipped with DMD. Thus, we check for getnameinfo at
1601 // runtime in the shared module constructor, and fall back to the
1602 // deprecated getHostByAddr() if it could not be found. See also:
1603 // http://technet.microsoft.com/en-us/library/aa450403.aspx
1605 if (getnameinfoPointer
)
1606 return super.toHostNameString();
1609 auto host
= new InternetHost();
1610 if (!host
.getHostByAddr(ntohl(sin
.sin_addr
.s_addr
)))
1617 * Compares with another InternetAddress of same type for equality
1618 * Returns: true if the InternetAddresses share the same address and
1621 override bool opEquals(Object o
) const
1623 auto other
= cast(InternetAddress
) o
;
1624 return other
&& this.sin
.sin_addr
.s_addr
== other
.sin
.sin_addr
.s_addr
&&
1625 this.sin
.sin_port
== other
.sin
.sin_port
;
1631 auto addr1
= new InternetAddress("127.0.0.1", 80);
1632 auto addr2
= new InternetAddress("127.0.0.2", 80);
1634 assert(addr1
== addr1
);
1635 assert(addr1
!= addr2
);
1639 * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
1640 * and return the number.
1641 * Returns: If the string is not a legitimate IPv4 address,
1642 * `ADDR_NONE` is returned.
1644 static uint parse(scope const(char)[] addr
) @trusted nothrow
1646 return ntohl(inet_addr(addr
.tempCString()));
1650 * Convert an IPv4 address number in host byte order to a human readable
1651 * string representing the IPv4 address in dotted-decimal form.
1653 static string
addrToString(uint addr
) @trusted nothrow
1656 sin_addr
.s_addr
= htonl(addr
);
1657 return to
!string(inet_ntoa(sin_addr
));
1665 const InternetAddress ia
= new InternetAddress("63.105.9.61", 80);
1666 assert(ia
.toString() == "63.105.9.61:80");
1670 // test construction from a sockaddr_in
1673 sin
.sin_addr
.s_addr
= htonl(0x7F_00_00_01); // 127.0.0.1
1674 sin
.sin_family
= AddressFamily
.INET
;
1675 sin
.sin_port
= htons(80);
1677 const InternetAddress ia
= new InternetAddress(sin
);
1678 assert(ia
.toString() == "127.0.0.1:80");
1682 // test reverse lookup
1683 auto ih
= new InternetHost
;
1684 if (ih
.getHostByName("digitalmars.com"))
1686 const ia
= new InternetAddress(ih
.addrList
[0], 80);
1687 assert(ia
.toHostNameString() == "digitalmars.com");
1689 if (getnameinfoPointer
)
1691 // test reverse lookup, via gethostbyaddr
1692 auto getnameinfoPointerBackup
= getnameinfoPointer
;
1693 cast() getnameinfoPointer
= null;
1694 scope(exit
) cast() getnameinfoPointer
= getnameinfoPointerBackup
;
1696 assert(ia
.toHostNameString() == "digitalmars.com");
1703 // test failing reverse lookup
1704 const InternetAddress ia
= new InternetAddress("255.255.255.255", 80);
1705 assert(ia
.toHostNameString() is null);
1707 if (getnameinfoPointer
)
1709 // test failing reverse lookup, via gethostbyaddr
1710 auto getnameinfoPointerBackup
= getnameinfoPointer
;
1711 cast() getnameinfoPointer
= null;
1712 scope(exit
) cast() getnameinfoPointer
= getnameinfoPointerBackup
;
1714 assert(ia
.toHostNameString() is null);
1721 * `Internet6Address` encapsulates an IPv6 (Internet Protocol version 6)
1724 * Consider using `getAddress`, `parseAddress` and `Address` methods
1725 * instead of using this class directly.
1727 class Internet6Address
: Address
1733 this() pure nothrow @nogc
1739 override @property sockaddr
* name() return
1741 return cast(sockaddr
*)&sin6
;
1744 override @property const(sockaddr
)* name() const return
1746 return cast(const(sockaddr
)*)&sin6
;
1750 override @property socklen_t
nameLen() const
1752 return cast(socklen_t
) sin6
.sizeof
;
1756 /// Any IPv6 host address.
1757 static @property ref const(ubyte)[16] ADDR_ANY() pure nothrow @nogc
1759 static if (is(typeof(IN6ADDR_ANY
)))
1763 static immutable addr
= IN6ADDR_ANY
.s6_addr
;
1767 return IN6ADDR_ANY
.s6_addr
;
1769 else static if (is(typeof(in6addr_any
)))
1771 return in6addr_any
.s6_addr
;
1777 /// Any IPv6 port number.
1778 enum ushort PORT_ANY
= 0;
1780 /// Returns the IPv6 port number.
1781 @property ushort port() const pure nothrow @nogc
1783 return ntohs(sin6
.sin6_port
);
1786 /// Returns the IPv6 address.
1787 @property ubyte[16] addr() const pure nothrow @nogc
1789 return sin6
.sin6_addr
.s6_addr
;
1793 * Construct a new `Internet6Address`.
1795 * addr = an IPv6 host address string in the form described in RFC 2373,
1796 * or a host name which will be resolved using `getAddressInfo`.
1797 * service = (optional) service name.
1799 this(scope const(char)[] addr
, scope const(char)[] service
= null) @trusted
1801 auto results
= getAddressInfo(addr
, service
, AddressFamily
.INET6
);
1802 assert(results
.length
&& results
[0].family
== AddressFamily
.INET6
);
1803 sin6
= *cast(sockaddr_in6
*) results
[0].address
.name
;
1807 * Construct a new `Internet6Address`.
1809 * addr = an IPv6 host address string in the form described in RFC 2373,
1810 * or a host name which will be resolved using `getAddressInfo`.
1811 * port = port number, may be `PORT_ANY`.
1813 this(scope const(char)[] addr
, ushort port
)
1815 if (port
== PORT_ANY
)
1818 this(addr
, to
!string(port
));
1822 * Construct a new `Internet6Address`.
1824 * addr = (optional) an IPv6 host address in host byte order, or
1826 * port = port number, may be `PORT_ANY`.
1828 this(ubyte[16] addr
, ushort port
) pure nothrow @nogc
1830 sin6
.sin6_family
= AddressFamily
.INET6
;
1831 sin6
.sin6_addr
.s6_addr
= addr
;
1832 sin6
.sin6_port
= htons(port
);
1836 this(ushort port
) pure nothrow @nogc
1838 sin6
.sin6_family
= AddressFamily
.INET6
;
1839 sin6
.sin6_addr
.s6_addr
= ADDR_ANY
;
1840 sin6
.sin6_port
= htons(port
);
1844 * Construct a new `Internet6Address`.
1846 * addr = A sockaddr_in6 as obtained from lower-level API calls such as getifaddrs.
1848 this(sockaddr_in6 addr
) pure nothrow @nogc
1850 assert(addr
.sin6_family
== AddressFamily
.INET6
);
1855 * Parse an IPv6 host address string as described in RFC 2373, and return the
1857 * Throws: `SocketException` on error.
1859 static ubyte[16] parse(scope const(char)[] addr
) @trusted
1861 // Although we could use inet_pton here, it's only available on Windows
1862 // versions starting with Vista, so use getAddressInfo with NUMERICHOST
1864 auto results
= getAddressInfo(addr
, AddressInfoFlags
.NUMERICHOST
);
1865 if (results
.length
&& results
[0].family
== AddressFamily
.INET6
)
1866 return (cast(sockaddr_in6
*) results
[0].address
.name
).sin6_addr
.s6_addr
;
1867 throw new AddressException("Not an IPv6 address", 0);
1875 const Internet6Address ia
= new Internet6Address("::1", 80);
1876 assert(ia
.toString() == "[::1]:80");
1880 // test construction from a sockaddr_in6
1883 sin
.sin6_addr
.s6_addr
= [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // [::1]
1884 sin
.sin6_family
= AddressFamily
.INET6
;
1885 sin
.sin6_port
= htons(80);
1887 const Internet6Address ia
= new Internet6Address(sin
);
1888 assert(ia
.toString() == "[::1]:80");
1895 static if (!is(sockaddr_un
))
1897 // This exists only to allow the constructor taking
1898 // a sockaddr_un to be compilable for documentation
1899 // on platforms that don't supply a sockaddr_un.
1906 * `UnixAddress` encapsulates an address for a Unix domain socket
1907 * (`AF_UNIX`), i.e. a socket bound to a path name in the file system.
1908 * Available only on supported systems.
1910 * Linux also supports an abstract address namespace, in which addresses
1911 * are independent of the file system. A socket address is abstract
1912 * iff `path` starts with a _null byte (`'\0'`). Null bytes in other
1913 * positions of an abstract address are allowed and have no special
1918 * auto addr = new UnixAddress("/var/run/dbus/system_bus_socket");
1919 * auto abstractAddr = new UnixAddress("\0/tmp/dbus-OtHLWmCLPR");
1922 * See_Also: $(HTTP http://man7.org/linux/man-pages/man7/unix.7.html, UNIX(7))
1924 class UnixAddress
: Address
1926 private this() pure nothrow @nogc {}
1928 /// Construct a new `UnixAddress` from the specified path.
1929 this(scope const(char)[] path
) { }
1932 * Construct a new `UnixAddress`.
1934 * addr = A sockaddr_un as obtained from lower-level API calls.
1936 this(sockaddr_un addr
) pure nothrow @nogc { }
1938 /// Get the underlying _path.
1939 @property string
path() const { return null; }
1942 override string
toString() const { return null; }
1944 override @property sockaddr
* name() { return null; }
1945 override @property const(sockaddr
)* name() const { return null; }
1946 override @property socklen_t
nameLen() const { return 0; }
1950 static if (is(sockaddr_un
))
1952 class UnixAddress
: Address
1961 char unused
= '\0'; // placeholder for a terminating '\0'
1964 this() pure nothrow @nogc
1966 sun
.sun_family
= AddressFamily
.UNIX
;
1968 _nameLen
= sun
.sizeof
;
1971 override void setNameLen(socklen_t len
) @trusted
1973 if (len
> sun
.sizeof
)
1974 throw new SocketParameterException("Not enough socket address storage");
1979 override @property sockaddr
* name() return
1981 return cast(sockaddr
*)&sun
;
1984 override @property const(sockaddr
)* name() const return
1986 return cast(const(sockaddr
)*)&sun
;
1989 override @property socklen_t
nameLen() @trusted const
1994 this(scope const(char)[] path
) @trusted pure
1996 enforce(path
.length
<= sun
.sun_path
.sizeof
, new SocketParameterException("Path too long"));
1997 sun
.sun_family
= AddressFamily
.UNIX
;
1998 sun
.sun_path
.ptr
[0 .. path
.length
] = (cast(byte[]) path
)[];
1999 _nameLen
= cast(socklen_t
)
2001 auto len
= sockaddr_un
.init
.sun_path
.offsetof
+ path
.length
;
2002 // Pathname socket address must be terminated with '\0'
2003 // which must be included in the address length.
2004 if (sun
.sun_path
.ptr
[0])
2006 sun
.sun_path
.ptr
[path
.length
] = 0;
2013 this(sockaddr_un addr
) pure nothrow @nogc
2015 assert(addr
.sun_family
== AddressFamily
.UNIX
);
2019 @property string
path() @trusted const pure
2021 auto len
= _nameLen
- sockaddr_un
.init
.sun_path
.offsetof
;
2023 return null; // An empty path may be returned from getpeername
2024 // For pathname socket address we need to strip off the terminating '\0'
2025 if (sun
.sun_path
.ptr
[0])
2027 return (cast(const(char)*) sun
.sun_path
.ptr
)[0 .. len
].idup
;
2030 override string
toString() const pure
2038 import core
.stdc
.stdio
: remove
;
2040 version (iOSDerived
)
2042 // Slightly different version of `std.file.deleteme` to reduce the path
2043 // length on iOS derived platforms. Due to the sandbox, the length
2044 // of paths can quickly become too long.
2045 static string
deleteme()
2047 import std
.conv
: text
;
2048 import std
.process
: thisProcessID
;
2049 import std
.file
: tempDir
;
2051 return text(tempDir
, thisProcessID
);
2056 import std
.file
: deleteme
;
2058 immutable ubyte[] data
= [1, 2, 3, 4];
2061 const basePath
= deleteme
;
2062 auto names
= [ basePath
~ "-socket" ];
2064 names
~= "\0" ~ basePath
~ "-abstract\0unix\0socket";
2066 foreach (name
; names
)
2068 auto address
= new UnixAddress(name
);
2070 auto listener
= new Socket(AddressFamily
.UNIX
, SocketType
.STREAM
);
2071 scope(exit
) listener
.close();
2072 listener
.bind(address
);
2073 scope(exit
) () @trusted { if (name
[0]) remove(name
.tempCString()); } ();
2074 assert(listener
.localAddress
.toString
== name
);
2078 pair
[0] = new Socket(AddressFamily
.UNIX
, SocketType
.STREAM
);
2079 scope(exit
) listener
.close();
2081 pair
[0].connect(address
);
2082 scope(exit
) pair
[0].close();
2084 pair
[1] = listener
.accept();
2085 scope(exit
) pair
[1].close();
2089 auto buf
= new ubyte[data
.length
];
2090 pair
[1].receive(buf
);
2091 assert(buf
== data
);
2093 // getpeername is free to return an empty name for a unix
2094 // domain socket pair or unbound socket. Let's confirm it
2095 // returns successfully and doesn't throw anything.
2096 // See https://issues.dlang.org/show_bug.cgi?id=20544
2097 assertNotThrown(pair
[1].remoteAddress().toString());
2104 * Class for exceptions thrown by `Socket.accept`.
2106 class SocketAcceptException
: SocketOSException
2108 mixin socketOSExceptionCtors
;
2111 /// How a socket is shutdown:
2112 enum SocketShutdown
: int
2114 RECEIVE
= SD_RECEIVE
, /// socket receives are disallowed
2115 SEND
= SD_SEND
, /// socket sends are disallowed
2116 BOTH
= SD_BOTH
, /// both RECEIVE and SEND
2120 /// Flags may be OR'ed together:
2121 enum SocketFlags
: int
2123 NONE
= 0, /// no flags specified
2125 OOB
= MSG_OOB
, /// out-of-band stream data
2126 PEEK
= MSG_PEEK
, /// peek at incoming data without removing it from the queue, only for receiving
2127 DONTROUTE
= MSG_DONTROUTE
, /// data should not be subject to routing; this flag may be ignored. Only for sending
2131 /// Duration timeout value.
2135 alias tv_sec_t
= typeof(ctimeval
.tv_sec
);
2136 alias tv_usec_t
= typeof(ctimeval
.tv_usec
);
2138 /// Number of _seconds.
2139 pure nothrow @nogc @property
2140 ref inout(tv_sec_t
) seconds() inout return
2142 return ctimeval
.tv_sec
;
2145 /// Number of additional _microseconds.
2146 pure nothrow @nogc @property
2147 ref inout(tv_usec_t
) microseconds() inout return
2149 return ctimeval
.tv_usec
;
2155 * A collection of sockets for use with `Socket.select`.
2157 * `SocketSet` wraps the platform `fd_set` type. However, unlike
2158 * `fd_set`, `SocketSet` is not statically limited to `FD_SETSIZE`
2159 * or any other limit, and grows as needed.
2166 // On Windows, fd_set is an array of socket handles,
2167 // following a word containing the fd_set instance size.
2168 // We use one dynamic array for everything, and use its first
2169 // element(s) for the count.
2171 alias fd_set_count_type
= typeof(fd_set
.init
.fd_count
);
2172 alias fd_set_type
= typeof(fd_set
.init
.fd_array
[0]);
2173 static assert(fd_set_type
.sizeof
== socket_t
.sizeof
);
2175 // Number of fd_set_type elements at the start of our array that are
2176 // used for the socket count and alignment
2178 enum FD_SET_OFFSET
= fd_set
.fd_array
.offsetof
/ fd_set_type
.sizeof
;
2179 static assert(FD_SET_OFFSET
);
2180 static assert(fd_set
.fd_count
.offsetof
% fd_set_type
.sizeof
== 0);
2184 void resize(size_t size
) pure nothrow
2186 set
.length
= FD_SET_OFFSET
+ size
;
2189 ref inout(fd_set_count_type
) count() @trusted @property inout pure nothrow @nogc
2192 return *cast(inout(fd_set_count_type
)*)set
.ptr
;
2195 size_t
capacity() @property const pure nothrow @nogc
2197 return set
.length
- FD_SET_OFFSET
;
2200 inout(socket_t
)[] fds() @trusted inout @property pure nothrow @nogc
2202 return cast(inout(socket_t
)[])set
[FD_SET_OFFSET
.. FD_SET_OFFSET
+count
];
2208 // On Posix, fd_set is a bit array. We assume that the fd_set
2209 // type (declared in core.sys.posix.sys.select) is a structure
2210 // containing a single field, a static array.
2212 static assert(fd_set
.tupleof
.length
== 1);
2214 // This is the type used in the fd_set array.
2215 // Using the type of the correct size is important for big-endian
2218 alias fd_set_type
= typeof(fd_set
.init
.tupleof
[0][0]);
2220 // Number of file descriptors represented by one fd_set_type
2222 enum FD_NFDBITS
= 8 * fd_set_type
.sizeof
;
2224 static fd_set_type
mask(uint n
) pure nothrow @nogc
2226 return (cast(fd_set_type
) 1) << (n
% FD_NFDBITS
);
2229 // Array size to fit that many sockets
2231 static size_t
lengthFor(size_t size
) pure nothrow @nogc
2233 return (size
+ (FD_NFDBITS
-1)) / FD_NFDBITS
;
2238 void resize(size_t size
) pure nothrow
2240 set
.length
= lengthFor(size
);
2243 // Make sure we can fit that many sockets
2245 void setMinCapacity(size_t size
) pure nothrow
2247 auto length
= lengthFor(size
);
2248 if (set
.length
< length
)
2249 set
.length
= length
;
2252 size_t
capacity() @property const pure nothrow @nogc
2254 return set
.length
* FD_NFDBITS
;
2260 static assert(false, "Unknown platform");
2265 * Create a SocketSet with a specific initial capacity (defaults to
2266 * `FD_SETSIZE`, the system's default capacity).
2268 this(size_t size
= FD_SETSIZE
) pure nothrow
2274 /// Reset the `SocketSet` so that there are 0 `Socket`s in the collection.
2275 void reset() pure nothrow @nogc
2287 void add(socket_t s
) @trusted pure nothrow
2291 if (count
== capacity
)
2294 set
.length
= set
.capacity
;
2301 auto index
= s
/ FD_NFDBITS
;
2302 auto length
= set
.length
;
2303 if (index
>= length
)
2305 while (index
>= length
)
2307 set
.length
= length
;
2308 set
.length
= set
.capacity
;
2310 set
[index
] |
= mask(s
);
2317 * Add a `Socket` to the collection.
2318 * The socket must not already be in the collection.
2320 void add(Socket s
) pure nothrow
2325 void remove(socket_t s
) pure nothrow
2329 import std
.algorithm
.searching
: countUntil
;
2331 auto p
= fds
.countUntil(s
);
2333 fds
[p
] = fds
[--count
];
2337 auto index
= s
/ FD_NFDBITS
;
2338 if (index
>= set
.length
)
2340 set
[index
] &= ~mask(s
);
2341 // note: adjusting maxfd would require scanning the set, not worth it
2347 * Remove this `Socket` from the collection.
2348 * Does nothing if the socket is not in the collection already.
2350 void remove(Socket s
) pure nothrow
2355 int isSet(socket_t s
) const pure nothrow @nogc
2359 import std
.algorithm
.searching
: canFind
;
2360 return fds
.canFind(s
) ?
1 : 0;
2366 auto index
= s
/ FD_NFDBITS
;
2367 return (set
[index
] & mask(s
)) ?
1 : 0;
2372 /// Return nonzero if this `Socket` is in the collection.
2373 int isSet(Socket s
) const pure nothrow @nogc
2375 return isSet(s
.sock
);
2381 * The current capacity of this `SocketSet`. The exact
2382 * meaning of the return value varies from platform to platform.
2385 * Since D 2.065, this value does not indicate a
2386 * restriction, and `SocketSet` will grow its capacity as
2387 * needed automatically.
2389 @property uint max() const pure nothrow @nogc
2391 return cast(uint) capacity
;
2395 fd_set
* toFd_set() @trusted pure nothrow @nogc
2397 return cast(fd_set
*) set
.ptr
;
2401 int selectn() const pure nothrow @nogc
2407 else version (Posix
)
2416 auto fds
= cast(socket_t
[])
2417 [cast(socket_t
) 1, 2, 0, 1024, 17, 42, 1234, 77, 77+32, 77+64];
2418 auto set
= new SocketSet();
2419 foreach (fd
; fds
) assert(!set
.isSet(fd
));
2420 foreach (fd
; fds
) set
.add(fd
);
2421 foreach (fd
; fds
) assert(set
.isSet(fd
));
2423 // Make sure SocketSet reimplements fd_set correctly
2424 auto fdset
= set
.toFd_set();
2425 foreach (fd
; fds
[0]..cast(socket_t
)(fds
[$-1]+1))
2426 assert(cast(bool) set
.isSet(fd
) == cast(bool)(() @trusted => FD_ISSET(fd
, fdset
))());
2430 assert(set
.isSet(fd
));
2432 assert(!set
.isSet(fd
));
2438 version (iOSDerived
)
2453 static assert(LIMIT
> PAIRS
*2);
2454 import core
.sys
.posix
.sys
.resource
;
2456 getrlimit(RLIMIT_NOFILE
, &fileLimit
);
2457 assert(fileLimit
.rlim_max
> LIMIT
, "Open file hard limit too low");
2458 fileLimit
.rlim_cur
= LIMIT
;
2459 setrlimit(RLIMIT_NOFILE
, &fileLimit
);
2462 Socket
[2][PAIRS
] pairs
;
2463 foreach (ref pair
; pairs
)
2464 pair
= socketPair();
2467 foreach (pair
; pairs
)
2475 auto rng
= Xorshift(42);
2476 pairs
[].randomShuffle(rng
);
2478 auto readSet
= new SocketSet();
2479 auto writeSet
= new SocketSet();
2480 auto errorSet
= new SocketSet();
2482 foreach (testPair
; pairs
)
2489 foreach (ref pair
; pairs
)
2499 auto n
= Socket
.select(readSet
, writeSet
, errorSet
);
2500 assert(n
== PAIRS
*2); // All in writeSet
2501 assert(writeSet
.isSet(testPair
[0]));
2502 assert(writeSet
.isSet(testPair
[1]));
2503 assert(!readSet
.isSet(testPair
[0]));
2504 assert(!readSet
.isSet(testPair
[1]));
2505 assert(!errorSet
.isSet(testPair
[0]));
2506 assert(!errorSet
.isSet(testPair
[1]));
2509 // Socket.send can't be marked with `scope`
2510 // -> @safe DIP1000 code can't use it - see https://github.com/dlang/phobos/pull/6204
2512 testPair
[0].send(b
[]);
2515 n
= Socket
.select(readSet
, null, null);
2516 assert(n
== 1); // testPair[1]
2517 assert(readSet
.isSet(testPair
[1]));
2518 assert(!readSet
.isSet(testPair
[0]));
2519 // Socket.receive can't be marked with `scope`
2520 // -> @safe DIP1000 code can't use it - see https://github.com/dlang/phobos/pull/6204
2522 testPair
[1].receive(b
[]);
2528 // https://issues.dlang.org/show_bug.cgi?id=14012
2529 // https://issues.dlang.org/show_bug.cgi?id=14013
2532 auto set
= new SocketSet(1);
2533 assert(set
.max
>= 0);
2536 foreach (n
; 0 .. LIMIT
)
2537 set
.add(cast(socket_t
) n
);
2538 assert(set
.max
>= LIMIT
);
2541 /// The level at which a socket option is defined:
2542 enum SocketOptionLevel
: int
2544 SOCKET
= SOL_SOCKET
, /// Socket level
2545 IP
= ProtocolType
.IP
, /// Internet Protocol version 4 level
2546 ICMP
= ProtocolType
.ICMP
, /// Internet Control Message Protocol level
2547 IGMP
= ProtocolType
.IGMP
, /// Internet Group Management Protocol level
2548 GGP
= ProtocolType
.GGP
, /// Gateway to Gateway Protocol level
2549 TCP
= ProtocolType
.TCP
, /// Transmission Control Protocol level
2550 PUP
= ProtocolType
.PUP
, /// PARC Universal Packet Protocol level
2551 UDP
= ProtocolType
.UDP
, /// User Datagram Protocol level
2552 IDP
= ProtocolType
.IDP
, /// Xerox NS protocol level
2553 RAW
= ProtocolType
.RAW
, /// Raw IP packet level
2554 IPV6
= ProtocolType
.IPV6
, /// Internet Protocol version 6 level
2557 /// _Linger information for use with SocketOption.LINGER.
2562 private alias l_onoff_t
= typeof(_clinger
.init
.l_onoff
);
2563 private alias l_linger_t
= typeof(_clinger
.init
.l_linger
);
2565 /// Nonzero for _on.
2566 pure nothrow @nogc @property
2567 ref inout(l_onoff_t
) on() inout return
2569 return clinger
.l_onoff
;
2573 pure nothrow @nogc @property
2574 ref inout(l_linger_t
) time() inout return
2576 return clinger
.l_linger
;
2580 /// Specifies a socket option:
2581 enum SocketOption
: int
2583 DEBUG
= SO_DEBUG
, /// Record debugging information
2584 BROADCAST
= SO_BROADCAST
, /// Allow transmission of broadcast messages
2585 REUSEADDR
= SO_REUSEADDR
, /// Allow local reuse of address
2586 LINGER
= SO_LINGER
, /// Linger on close if unsent data is present
2587 OOBINLINE
= SO_OOBINLINE
, /// Receive out-of-band data in band
2588 SNDBUF
= SO_SNDBUF
, /// Send buffer size
2589 RCVBUF
= SO_RCVBUF
, /// Receive buffer size
2590 DONTROUTE
= SO_DONTROUTE
, /// Do not route
2591 SNDTIMEO
= SO_SNDTIMEO
, /// Send timeout
2592 RCVTIMEO
= SO_RCVTIMEO
, /// Receive timeout
2593 ERROR
= SO_ERROR
, /// Retrieve and clear error status
2594 KEEPALIVE
= SO_KEEPALIVE
, /// Enable keep-alive packets
2595 ACCEPTCONN
= SO_ACCEPTCONN
, /// Listen
2596 RCVLOWAT
= SO_RCVLOWAT
, /// Minimum number of input bytes to process
2597 SNDLOWAT
= SO_SNDLOWAT
, /// Minimum number of output bytes to process
2598 TYPE
= SO_TYPE
, /// Socket type
2600 // SocketOptionLevel.TCP:
2601 TCP_NODELAY
= .TCP_NODELAY
, /// Disable the Nagle algorithm for send coalescing
2603 // SocketOptionLevel.IPV6:
2604 IPV6_UNICAST_HOPS
= .IPV6_UNICAST_HOPS
, /// IP unicast hop limit
2605 IPV6_MULTICAST_IF
= .IPV6_MULTICAST_IF
, /// IP multicast interface
2606 IPV6_MULTICAST_LOOP
= .IPV6_MULTICAST_LOOP
, /// IP multicast loopback
2607 IPV6_MULTICAST_HOPS
= .IPV6_MULTICAST_HOPS
, /// IP multicast hops
2608 IPV6_JOIN_GROUP
= .IPV6_JOIN_GROUP
, /// Add an IP group membership
2609 IPV6_LEAVE_GROUP
= .IPV6_LEAVE_GROUP
, /// Drop an IP group membership
2610 IPV6_V6ONLY
= .IPV6_V6ONLY
, /// Treat wildcard bind as AF_INET6-only
2615 * `Socket` is a class that creates a network communication endpoint using
2616 * the Berkeley sockets interface.
2622 AddressFamily _family
;
2625 bool _blocking
= false; /// Property to get or set whether the socket is blocking or nonblocking.
2627 // The WinSock timeouts seem to be effectively skewed by a constant
2628 // offset of about half a second (value in milliseconds). This has
2629 // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7
2630 // and Windows Server 2008 R2 boxes. The unittest below tests this
2632 enum WINSOCK_TIMEOUT_SKEW
= 500;
2638 import std
.datetime
.stopwatch
;
2639 import std
.typecons
;
2642 auto pair
= socketPair();
2643 auto sock
= pair
[0];
2644 sock
.setOption(SocketOptionLevel
.SOCKET
,
2645 SocketOption
.RCVTIMEO
, dur
!"msecs"(msecs
));
2647 auto sw
= StopWatch(Yes
.autoStart
);
2652 Duration readBack
= void;
2653 sock
.getOption(SocketOptionLevel
.SOCKET
, SocketOption
.RCVTIMEO
, readBack
);
2655 assert(readBack
.total
!"msecs" == msecs
);
2656 assert(sw
.peek().total
!"msecs" > msecs
- 100 && sw
.peek().total
!"msecs" < msecs
+ 100);
2660 void setSock(socket_t handle
)
2662 assert(handle
!= socket_t
.init
);
2665 // Set the option to disable SIGPIPE on send() if the platform
2666 // has it (e.g. on OS X).
2667 static if (is(typeof(SO_NOSIGPIPE
)))
2669 setOption(SocketOptionLevel
.SOCKET
, cast(SocketOption
) SO_NOSIGPIPE
, true);
2674 // For use with accepting().
2675 protected this() pure nothrow @nogc
2683 * Create a blocking socket. If a single protocol type exists to support
2684 * this socket type within the address family, the `ProtocolType` may be
2687 this(AddressFamily af
, SocketType type
, ProtocolType protocol
) @trusted
2690 auto handle
= cast(socket_t
) socket(af
, type
, protocol
);
2691 if (handle
== socket_t
.init
)
2692 throw new SocketOSException("Unable to create socket");
2697 this(AddressFamily af
, SocketType type
)
2699 /* A single protocol exists to support this socket type within the
2700 * protocol family, so the ProtocolType is assumed.
2702 this(af
, type
, cast(ProtocolType
) 0); // Pseudo protocol number.
2707 this(AddressFamily af
, SocketType type
, scope const(char)[] protocolName
) @trusted
2710 proto
= getprotobyname(protocolName
.tempCString());
2712 throw new SocketOSException("Unable to find the protocol");
2713 this(af
, type
, cast(ProtocolType
) proto
.p_proto
);
2718 * Create a blocking socket using the parameters from the specified
2719 * `AddressInfo` structure.
2721 this(const scope AddressInfo info
)
2723 this(info
.family
, info
.type
, info
.protocol
);
2726 /// Use an existing socket handle.
2727 this(socket_t sock
, AddressFamily af
) pure nothrow @nogc
2729 assert(sock
!= socket_t
.init
);
2735 ~this() nothrow @nogc
2741 /// Get underlying socket handle.
2742 @property socket_t
handle() const pure nothrow @nogc
2748 * Get/set socket's blocking flag.
2750 * When a socket is blocking, calls to receive(), accept(), and send()
2751 * will block and wait for data/action.
2752 * A non-blocking socket will immediately return instead of blocking.
2754 @property bool blocking() @trusted const nothrow @nogc
2760 else version (Posix
)
2762 return !(fcntl(handle
, F_GETFL
, 0) & O_NONBLOCK
);
2767 @property void blocking(bool byes
) @trusted
2772 if (_SOCKET_ERROR
== ioctlsocket(sock
, FIONBIO
, &num
))
2776 else version (Posix
)
2778 int x
= fcntl(sock
, F_GETFL
, 0);
2785 if (-1 == fcntl(sock
, F_SETFL
, x
))
2791 throw new SocketOSException("Unable to set socket blocking");
2795 /// Get the socket's address family.
2796 @property AddressFamily
addressFamily()
2801 /// Property that indicates if this is a valid, alive socket.
2802 @property bool isAlive() @trusted const
2805 socklen_t typesize
= cast(socklen_t
) type
.sizeof
;
2806 return !getsockopt(sock
, SOL_SOCKET
, SO_TYPE
, cast(char*)&type
, &typesize
);
2810 * Associate a local address with this socket.
2813 * addr = The $(LREF Address) to associate this socket with.
2815 * Throws: $(LREF SocketOSException) when unable to bind the socket.
2817 void bind(Address addr
) @trusted
2819 if (_SOCKET_ERROR
== .bind(sock
, addr
.name
, addr
.nameLen
))
2820 throw new SocketOSException("Unable to bind socket");
2824 * Establish a connection. If the socket is blocking, connect waits for
2825 * the connection to be made. If the socket is nonblocking, connect
2826 * returns immediately and the connection attempt is still in progress.
2828 void connect(Address to
) @trusted
2830 if (_SOCKET_ERROR
== .connect(sock
, to
.name
, to
.nameLen
))
2839 if (WSAEWOULDBLOCK
== err
)
2842 else version (Posix
)
2844 if (EINPROGRESS
== err
)
2852 throw new SocketOSException("Unable to connect socket", err
);
2857 * Listen for an incoming connection. `bind` must be called before you
2858 * can `listen`. The `backlog` is a request of how many pending
2859 * incoming connections are queued until `accept`ed.
2861 void listen(int backlog
) @trusted
2863 if (_SOCKET_ERROR
== .listen(sock
, backlog
))
2864 throw new SocketOSException("Unable to listen on socket");
2868 * Called by `accept` when a new `Socket` must be created for a new
2869 * connection. To use a derived class, override this method and return an
2870 * instance of your class. The returned `Socket`'s handle must not be
2871 * set; `Socket` has a protected constructor `this()` to use in this
2874 * Override to use a derived class.
2875 * The returned socket's handle must not be set.
2877 protected Socket
accepting() pure nothrow
2883 * Accept an incoming connection. If the socket is blocking, `accept`
2884 * waits for a connection request. Throws `SocketAcceptException` if
2885 * unable to _accept. See `accepting` for use with derived classes.
2887 Socket
accept() @trusted
2889 auto newsock
= cast(socket_t
).accept(sock
, null, null);
2890 if (socket_t
.init
== newsock
)
2891 throw new SocketAcceptException("Unable to accept socket connection");
2896 newSocket
= accepting();
2897 assert(newSocket
.sock
== socket_t
.init
);
2899 newSocket
.setSock(newsock
);
2901 newSocket
._blocking
= _blocking
; //inherits blocking mode
2902 newSocket
._family
= _family
; //same family
2913 /// Disables sends and/or receives.
2914 void shutdown(SocketShutdown how
) @trusted nothrow @nogc
2916 .shutdown(sock
, cast(int) how
);
2920 private static void _close(socket_t sock
) @system nothrow @nogc
2926 else version (Posix
)
2934 * Immediately drop any connections and release socket resources.
2935 * The `Socket` object is no longer usable after `close`.
2936 * Calling `shutdown` before `close` is recommended
2937 * for connection-oriented sockets.
2939 void close() @trusted nothrow @nogc
2942 sock
= socket_t
.init
;
2947 * Returns: the local machine's host name
2949 static @property string
hostName() @trusted // getter
2951 char[256] result
; // Host names are limited to 255 chars.
2952 if (_SOCKET_ERROR
== .gethostname(result
.ptr
, result
.length
))
2953 throw new SocketOSException("Unable to obtain host name");
2954 return to
!string(result
.ptr
);
2957 /// Remote endpoint `Address`.
2958 @property Address
remoteAddress() @trusted
2960 Address addr
= createAddress();
2961 socklen_t nameLen
= addr
.nameLen
;
2962 if (_SOCKET_ERROR
== .getpeername(sock
, addr
.name
, &nameLen
))
2963 throw new SocketOSException("Unable to obtain remote socket address");
2964 addr
.setNameLen(nameLen
);
2965 assert(addr
.addressFamily
== _family
);
2969 /// Local endpoint `Address`.
2970 @property Address
localAddress() @trusted
2972 Address addr
= createAddress();
2973 socklen_t nameLen
= addr
.nameLen
;
2974 if (_SOCKET_ERROR
== .getsockname(sock
, addr
.name
, &nameLen
))
2975 throw new SocketOSException("Unable to obtain local socket address");
2976 addr
.setNameLen(nameLen
);
2977 assert(addr
.addressFamily
== _family
);
2982 * Send or receive error code. See `wouldHaveBlocked`,
2983 * `lastSocketError` and `Socket.getErrorText` for obtaining more
2984 * information about the error.
2986 enum int ERROR
= _SOCKET_ERROR
;
2988 private static int capToInt(size_t size
) nothrow @nogc
2990 // Windows uses int instead of size_t for length arguments.
2991 // Luckily, the send/recv functions make no guarantee that
2992 // all the data is sent, so we use that to send at most
2994 return size
> size_t(int.max
) ?
int.max
: cast(int) size
;
2998 * Send data on the connection. If the socket is blocking and there is no
2999 * buffer space left, `send` waits.
3000 * Returns: The number of bytes actually sent, or `Socket.ERROR` on
3003 ptrdiff_t
send(const(void)[] buf
, SocketFlags flags
) @trusted
3005 static if (is(typeof(MSG_NOSIGNAL
)))
3007 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3010 auto sent
= .send(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
);
3012 auto sent
= .send(sock
, buf
.ptr
, buf
.length
, cast(int) flags
);
3017 ptrdiff_t
send(const(void)[] buf
)
3019 return send(buf
, SocketFlags
.NONE
);
3023 * Send data to a specific destination Address. If the destination address is
3024 * not specified, a connection must have been made and that address is used.
3025 * If the socket is blocking and there is no buffer space left, `sendTo` waits.
3026 * Returns: The number of bytes actually sent, or `Socket.ERROR` on
3029 ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
, Address to
) @trusted
3031 static if (is(typeof(MSG_NOSIGNAL
)))
3033 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3037 sock
, buf
.ptr
, capToInt(buf
.length
),
3038 cast(int) flags
, to
.name
, to
.nameLen
3041 return .sendto(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, to
.name
, to
.nameLen
);
3045 ptrdiff_t
sendTo(const(void)[] buf
, Address to
)
3047 return sendTo(buf
, SocketFlags
.NONE
, to
);
3051 //assumes you connect()ed
3053 ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
) @trusted
3055 static if (is(typeof(MSG_NOSIGNAL
)))
3057 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3060 return .sendto(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, null, 0);
3062 return .sendto(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, null, 0);
3066 //assumes you connect()ed
3068 ptrdiff_t
sendTo(const(void)[] buf
)
3070 return sendTo(buf
, SocketFlags
.NONE
);
3075 * Receive data on the connection. If the socket is blocking, `receive`
3076 * waits until there is data to be received.
3077 * Returns: The number of bytes actually received, `0` if the remote side
3078 * has closed the connection, or `Socket.ERROR` on failure.
3080 ptrdiff_t
receive(void[] buf
, SocketFlags flags
) @trusted
3082 version (Windows
) // Does not use size_t
3085 ?
.recv(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
)
3091 ?
.recv(sock
, buf
.ptr
, buf
.length
, cast(int) flags
)
3097 ptrdiff_t
receive(void[] buf
)
3099 return receive(buf
, SocketFlags
.NONE
);
3103 * Receive data and get the remote endpoint `Address`.
3104 * If the socket is blocking, `receiveFrom` waits until there is data to
3106 * Returns: The number of bytes actually received, `0` if the remote side
3107 * has closed the connection, or `Socket.ERROR` on failure.
3109 ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
, ref Address from
) @trusted
3111 if (!buf
.length
) //return 0 and don't think the connection closed
3113 if (from
is null || from
.addressFamily
!= _family
)
3114 from
= createAddress();
3115 socklen_t nameLen
= from
.nameLen
;
3117 auto read
= .recvfrom(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, from
.name
, &nameLen
);
3120 auto read
= .recvfrom(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, from
.name
, &nameLen
);
3124 from
.setNameLen(nameLen
);
3125 assert(from
.addressFamily
== _family
);
3132 ptrdiff_t
receiveFrom(void[] buf
, ref Address from
)
3134 return receiveFrom(buf
, SocketFlags
.NONE
, from
);
3138 //assumes you connect()ed
3140 ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
) @trusted
3142 if (!buf
.length
) //return 0 and don't think the connection closed
3146 auto read
= .recvfrom(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, null, null);
3147 // if (!read) //connection closed
3152 auto read
= .recvfrom(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, null, null);
3153 // if (!read) //connection closed
3159 //assumes you connect()ed
3161 ptrdiff_t
receiveFrom(void[] buf
)
3163 return receiveFrom(buf
, SocketFlags
.NONE
);
3168 * Get a socket option.
3169 * Returns: The number of bytes written to `result`.
3170 * The length, in bytes, of the actual result - very different from getsockopt()
3172 int getOption(SocketOptionLevel level
, SocketOption option
, void[] result
) @trusted
3174 socklen_t len
= cast(socklen_t
) result
.length
;
3175 if (_SOCKET_ERROR
== .getsockopt(sock
, cast(int) level
, cast(int) option
, result
.ptr
, &len
))
3176 throw new SocketOSException("Unable to get socket option");
3181 /// Common case of getting integer and boolean options.
3182 int getOption(SocketOptionLevel level
, SocketOption option
, out int32_t result
) @trusted
3184 return getOption(level
, option
, (&result
)[0 .. 1]);
3188 /// Get the linger option.
3189 int getOption(SocketOptionLevel level
, SocketOption option
, out Linger result
) @trusted
3191 //return getOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
3192 return getOption(level
, option
, (&result
.clinger
)[0 .. 1]);
3195 /// Get a timeout (duration) option.
3196 void getOption(SocketOptionLevel level
, SocketOption option
, out Duration result
) @trusted
3198 enforce(option
== SocketOption
.SNDTIMEO || option
== SocketOption
.RCVTIMEO
,
3199 new SocketParameterException("Not a valid timeout option: " ~ to
!string(option
)));
3200 // WinSock returns the timeout values as a milliseconds DWORD,
3201 // while Linux and BSD return a timeval struct.
3205 getOption(level
, option
, (&msecs
)[0 .. 1]);
3206 if (option
== SocketOption
.RCVTIMEO
)
3207 msecs
+= WINSOCK_TIMEOUT_SKEW
;
3208 result
= dur
!"msecs"(msecs
);
3210 else version (Posix
)
3213 getOption(level
, option
, (&tv
.ctimeval
)[0 .. 1]);
3214 result
= dur
!"seconds"(tv
.seconds
) + dur
!"usecs"(tv
.microseconds
);
3216 else static assert(false);
3219 /// Set a socket option.
3220 void setOption(SocketOptionLevel level
, SocketOption option
, void[] value
) @trusted
3222 if (_SOCKET_ERROR
== .setsockopt(sock
, cast(int) level
,
3223 cast(int) option
, value
.ptr
, cast(uint) value
.length
))
3224 throw new SocketOSException("Unable to set socket option");
3228 /// Common case for setting integer and boolean options.
3229 void setOption(SocketOptionLevel level
, SocketOption option
, int32_t value
) @trusted
3231 setOption(level
, option
, (&value
)[0 .. 1]);
3235 /// Set the linger option.
3236 void setOption(SocketOptionLevel level
, SocketOption option
, Linger value
) @trusted
3238 //setOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
3239 setOption(level
, option
, (&value
.clinger
)[0 .. 1]);
3243 * Sets a timeout (duration) option, i.e. `SocketOption.SNDTIMEO` or
3244 * `RCVTIMEO`. Zero indicates no timeout.
3246 * In a typical application, you might also want to consider using
3247 * a non-blocking socket instead of setting a timeout on a blocking one.
3249 * Note: While the receive timeout setting is generally quite accurate
3250 * on *nix systems even for smaller durations, there are two issues to
3251 * be aware of on Windows: First, although undocumented, the effective
3252 * timeout duration seems to be the one set on the socket plus half
3253 * a second. `setOption()` tries to compensate for that, but still,
3254 * timeouts under 500ms are not possible on Windows. Second, be aware
3255 * that the actual amount of time spent until a blocking call returns
3256 * randomly varies on the order of 10ms.
3259 * level = The level at which a socket option is defined.
3260 * option = Either `SocketOption.SNDTIMEO` or `SocketOption.RCVTIMEO`.
3261 * value = The timeout duration to set. Must not be negative.
3263 * Throws: `SocketException` if setting the options fails.
3267 * import std.datetime;
3268 * import std.typecons;
3269 * auto pair = socketPair();
3270 * scope(exit) foreach (s; pair) s.close();
3272 * // Set a receive timeout, and then wait at one end of
3273 * // the socket pair, knowing that no data will arrive.
3274 * pair[0].setOption(SocketOptionLevel.SOCKET,
3275 * SocketOption.RCVTIMEO, dur!"seconds"(1));
3277 * auto sw = StopWatch(Yes.autoStart);
3279 * pair[0].receive(buffer);
3280 * writefln("Waited %s ms until the socket timed out.",
3284 void setOption(SocketOptionLevel level
, SocketOption option
, Duration value
) @trusted
3286 enforce(option
== SocketOption
.SNDTIMEO || option
== SocketOption
.RCVTIMEO
,
3287 new SocketParameterException("Not a valid timeout option: " ~ to
!string(option
)));
3289 enforce(value
>= dur
!"hnsecs"(0), new SocketParameterException(
3290 "Timeout duration must not be negative."));
3294 import std
.algorithm
.comparison
: max
;
3296 auto msecs
= to
!int(value
.total
!"msecs");
3297 if (msecs
!= 0 && option
== SocketOption
.RCVTIMEO
)
3298 msecs
= max(1, msecs
- WINSOCK_TIMEOUT_SKEW
);
3299 setOption(level
, option
, msecs
);
3301 else version (Posix
)
3304 value
.split
!("seconds", "usecs")(tv
.tv_sec
, tv
.tv_usec
);
3305 setOption(level
, option
, (&tv
)[0 .. 1]);
3307 else static assert(false);
3311 * Get a text description of this socket's error status, and clear the
3312 * socket's error status.
3314 string
getErrorText()
3317 getOption(SocketOptionLevel
.SOCKET
, SocketOption
.ERROR
, error
);
3318 return formatSocketError(error
);
3322 * Enables TCP keep-alive with the specified parameters.
3325 * time = Number of seconds with no activity until the first
3326 * keep-alive packet is sent.
3327 * interval = Number of seconds between when successive keep-alive
3328 * packets are sent if no acknowledgement is received.
3330 * Throws: `SocketOSException` if setting the options fails, or
3331 * `SocketFeatureException` if setting keep-alive parameters is
3332 * unsupported on the current platform.
3334 void setKeepAlive(int time
, int interval
) @trusted
3338 tcp_keepalive options
;
3340 options
.keepalivetime
= time
* 1000;
3341 options
.keepaliveinterval
= interval
* 1000;
3342 uint cbBytesReturned
;
3343 enforce(WSAIoctl(sock
, SIO_KEEPALIVE_VALS
,
3344 &options
, options
.sizeof
,
3346 &cbBytesReturned
, null, null) == 0,
3347 new SocketOSException("Error setting keep-alive"));
3350 static if (is(typeof(TCP_KEEPIDLE
)) && is(typeof(TCP_KEEPINTVL
)))
3352 setOption(SocketOptionLevel
.TCP
, cast(SocketOption
) TCP_KEEPIDLE
, time
);
3353 setOption(SocketOptionLevel
.TCP
, cast(SocketOption
) TCP_KEEPINTVL
, interval
);
3354 setOption(SocketOptionLevel
.SOCKET
, SocketOption
.KEEPALIVE
, true);
3357 throw new SocketFeatureException("Setting keep-alive options " ~
3358 "is not supported on this platform");
3362 * Wait for a socket to change status. A wait timeout of $(REF Duration, core, time) or
3363 * `TimeVal`, may be specified; if a timeout is not specified or the
3364 * `TimeVal` is `null`, the maximum timeout is used. The `TimeVal`
3365 * timeout has an unspecified value when `select` returns.
3366 * Returns: The number of sockets with status changes, `0` on timeout,
3367 * or `-1` on interruption. If the return value is greater than `0`,
3368 * the `SocketSets` are updated to only contain the sockets having status
3369 * changes. For a connecting socket, a write status change means the
3370 * connection is established and it's able to send. For a listening socket,
3371 * a read status change means there is an incoming connection request and
3372 * it's able to accept.
3374 * `SocketSet`'s updated to include only those sockets which an event occured.
3375 * For a `connect()`ing socket, writeability means connected.
3376 * For a `listen()`ing socket, readability means listening
3377 * `Winsock`; possibly internally limited to 64 sockets per set.
3380 * the number of events, 0 on timeout, or -1 on interruption
3382 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
, Duration timeout
) @trusted
3384 auto vals
= timeout
.split
!("seconds", "usecs")();
3386 tv
.seconds
= cast(tv
.tv_sec_t
) vals
.seconds
;
3387 tv
.microseconds
= cast(tv
.tv_usec_t
) vals
.usecs
;
3388 return select(checkRead
, checkWrite
, checkError
, &tv
);
3393 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
)
3395 return select(checkRead
, checkWrite
, checkError
, null);
3399 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
, TimeVal
* timeout
) @trusted
3402 //make sure none of the SocketSet's are the same object
3405 assert(checkRead
!is checkWrite
);
3406 assert(checkRead
!is checkError
);
3410 assert(checkWrite
!is checkError
);
3420 // Windows has a problem with empty fd_set`s that aren't null.
3421 fr
= checkRead
&& checkRead
.count ? checkRead
.toFd_set() : null;
3422 fw
= checkWrite
&& checkWrite
.count ? checkWrite
.toFd_set() : null;
3423 fe
= checkError
&& checkError
.count ? checkError
.toFd_set() : null;
3429 fr
= checkRead
.toFd_set();
3430 n
= checkRead
.selectn();
3439 fw
= checkWrite
.toFd_set();
3441 _n
= checkWrite
.selectn();
3452 fe
= checkError
.toFd_set();
3454 _n
= checkError
.selectn();
3463 // Make sure the sets' capacity matches, to avoid select reading
3464 // out of bounds just because one set was bigger than another
3465 if (checkRead
) checkRead
.setMinCapacity(n
);
3466 if (checkWrite
) checkWrite
.setMinCapacity(n
);
3467 if (checkError
) checkError
.setMinCapacity(n
);
3470 int result
= .select(n
, fr
, fw
, fe
, &timeout
.ctimeval
);
3474 if (_SOCKET_ERROR
== result
&& WSAGetLastError() == WSAEINTR
)
3477 else version (Posix
)
3479 if (_SOCKET_ERROR
== result
&& errno
== EINTR
)
3487 if (_SOCKET_ERROR
== result
)
3488 throw new SocketOSException("Socket select error");
3495 * Can be overridden to support other addresses.
3496 * Returns: a new `Address` object for the current address family.
3498 protected Address
createAddress() pure nothrow
3503 static if (is(sockaddr_un
))
3505 case AddressFamily
.UNIX
:
3506 result
= new UnixAddress
;
3510 case AddressFamily
.INET
:
3511 result
= new InternetAddress
;
3514 case AddressFamily
.INET6
:
3515 result
= new Internet6Address
;
3519 result
= new UnknownAddress
;
3527 /// `TcpSocket` is a shortcut class for a TCP Socket.
3528 class TcpSocket
: Socket
3530 /// Constructs a blocking TCP Socket.
3531 this(AddressFamily family
)
3533 super(family
, SocketType
.STREAM
, ProtocolType
.TCP
);
3536 /// Constructs a blocking IPv4 TCP Socket.
3539 this(AddressFamily
.INET
);
3544 /// Constructs a blocking TCP Socket and connects to an `Address`.
3545 this(Address connectTo
)
3547 this(connectTo
.addressFamily
);
3553 /// `UdpSocket` is a shortcut class for a UDP Socket.
3554 class UdpSocket
: Socket
3556 /// Constructs a blocking UDP Socket.
3557 this(AddressFamily family
)
3559 super(family
, SocketType
.DGRAM
, ProtocolType
.UDP
);
3563 /// Constructs a blocking IPv4 UDP Socket.
3566 this(AddressFamily
.INET
);
3575 auto s
= new UdpSocket
;
3577 s
.bind(new InternetAddress(InternetAddress
.PORT_ANY
));
3578 s
.receiveFrom(buf
, addr
);
3581 // https://issues.dlang.org/show_bug.cgi?id=16514
3584 void checkAttributes(string attributes
)()
3586 mixin(attributes
~ q
{ void function() fun
= {};});
3590 class TestSocket
: Socket
3594 @property pure nothrow @nogc @safe socket_t
handle() const
3596 checkAttributes
!q
{pure nothrow @nogc @safe}; assert(0);
3598 @property nothrow @nogc @trusted bool blocking() const
3600 checkAttributes
!q
{nothrow @nogc @trusted}; assert(0);
3602 @property @trusted void blocking(bool byes
)
3604 checkAttributes
!q
{@trusted};
3606 @property @safe AddressFamily
addressFamily()
3608 checkAttributes
!q
{@safe}; assert(0);
3610 @property @trusted bool isAlive() const
3612 checkAttributes
!q
{@trusted}; assert(0);
3614 @trusted void bind(Address addr
)
3616 checkAttributes
!q
{@trusted};
3618 @trusted void connect(Address to
)
3620 checkAttributes
!q
{@trusted};
3622 @trusted void listen(int backlog
)
3624 checkAttributes
!q
{@trusted};
3626 protected pure nothrow @safe Socket
accepting()
3628 checkAttributes
!q
{pure nothrow @safe}; assert(0);
3630 @trusted Socket
accept()
3632 checkAttributes
!q
{@trusted}; assert(0);
3634 nothrow @nogc @trusted void shutdown(SocketShutdown how
)
3636 checkAttributes
!q
{nothrow @nogc @trusted};
3638 nothrow @nogc @trusted void close()
3640 checkAttributes
!q
{nothrow @nogc @trusted};
3642 @property @trusted Address
remoteAddress()
3644 checkAttributes
!q
{@trusted}; assert(0);
3646 @property @trusted Address
localAddress()
3648 checkAttributes
!q
{@trusted}; assert(0);
3650 @trusted ptrdiff_t
send(const(void)[] buf
, SocketFlags flags
)
3652 checkAttributes
!q
{@trusted}; assert(0);
3654 @safe ptrdiff_t
send(const(void)[] buf
)
3656 checkAttributes
!q
{@safe}; assert(0);
3658 @trusted ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
, Address to
)
3660 checkAttributes
!q
{@trusted}; assert(0);
3662 @safe ptrdiff_t
sendTo(const(void)[] buf
, Address to
)
3664 checkAttributes
!q
{@safe}; assert(0);
3666 @trusted ptrdiff_t
sendTo(const(void)[] buf
, SocketFlags flags
)
3668 checkAttributes
!q
{@trusted}; assert(0);
3670 @safe ptrdiff_t
sendTo(const(void)[] buf
)
3672 checkAttributes
!q
{@safe}; assert(0);
3674 @trusted ptrdiff_t
receive(void[] buf
, SocketFlags flags
)
3676 checkAttributes
!q
{@trusted}; assert(0);
3678 @safe ptrdiff_t
receive(void[] buf
)
3680 checkAttributes
!q
{@safe}; assert(0);
3682 @trusted ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
, ref Address from
)
3684 checkAttributes
!q
{@trusted}; assert(0);
3686 @safe ptrdiff_t
receiveFrom(void[] buf
, ref Address from
)
3688 checkAttributes
!q
{@safe}; assert(0);
3690 @trusted ptrdiff_t
receiveFrom(void[] buf
, SocketFlags flags
)
3692 checkAttributes
!q
{@trusted}; assert(0);
3694 @safe ptrdiff_t
receiveFrom(void[] buf
)
3696 checkAttributes
!q
{@safe}; assert(0);
3698 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, void[] result
)
3700 checkAttributes
!q
{@trusted}; assert(0);
3702 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, out int32_t result
)
3704 checkAttributes
!q
{@trusted}; assert(0);
3706 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, out Linger result
)
3708 checkAttributes
!q
{@trusted}; assert(0);
3710 @trusted void getOption(SocketOptionLevel level
, SocketOption option
, out Duration result
)
3712 checkAttributes
!q
{@trusted};
3714 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, void[] value
)
3716 checkAttributes
!q
{@trusted};
3718 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, int32_t value
)
3720 checkAttributes
!q
{@trusted};
3722 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, Linger value
)
3724 checkAttributes
!q
{@trusted};
3726 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, Duration value
)
3728 checkAttributes
!q
{@trusted};
3730 @safe string
getErrorText()
3732 checkAttributes
!q
{@safe}; assert(0);
3734 @trusted void setKeepAlive(int time
, int interval
)
3736 checkAttributes
!q
{@trusted};
3738 protected pure nothrow @safe Address
createAddress()
3740 checkAttributes
!q
{pure nothrow @safe}; assert(0);
3747 * Creates a pair of connected sockets.
3749 * The two sockets are indistinguishable.
3751 * Throws: `SocketException` if creation of the sockets fails.
3753 Socket
[2] socketPair() @trusted
3758 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, socks
) == -1)
3759 throw new SocketOSException("Unable to create socket pair");
3761 Socket
toSocket(size_t id
)
3763 auto s
= new Socket
;
3764 s
.setSock(cast(socket_t
) socks
[id
]);
3765 s
._family
= AddressFamily
.UNIX
;
3769 return [toSocket(0), toSocket(1)];
3771 else version (Windows
)
3773 // We do not have socketpair() on Windows, just manually create a
3774 // pair of sockets connected over some localhost port.
3777 auto listener
= new TcpSocket();
3778 listener
.setOption(SocketOptionLevel
.SOCKET
, SocketOption
.REUSEADDR
, true);
3779 listener
.bind(new InternetAddress(INADDR_LOOPBACK
, InternetAddress
.PORT_ANY
));
3780 auto addr
= listener
.localAddress
;
3783 result
[0] = new TcpSocket(addr
);
3784 result
[1] = listener
.accept();
3790 static assert(false);
3796 immutable ubyte[] data
= [1, 2, 3, 4];
3797 auto pair
= socketPair();
3798 scope(exit
) foreach (s
; pair
) s
.close();
3802 auto buf
= new ubyte[data
.length
];
3803 pair
[1].receive(buf
);
3804 assert(buf
== data
);