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
);
126 // Without debug=std_socket, still compile the slow tests, just don't run them.
128 private enum runSlowTests
= true;
130 private enum runSlowTests
= false;
133 /// Base exception thrown by `std.socket`.
134 class SocketException
: Exception
136 mixin basicExceptionCtors
;
139 version (CRuntime_Glibc
) version = GNU_STRERROR
;
140 version (CRuntime_UClibc
) version = GNU_STRERROR
;
143 * Needs to be public so that SocketOSException can be thrown outside of
144 * std.socket (since it uses it as a default argument), but it probably doesn't
145 * need to actually show up in the docs, since there's not really any public
146 * need for it outside of being a default argument.
148 string
formatSocketError(int err
) @trusted
154 version (GNU_STRERROR
)
156 cs
= strerror_r(err
, buf
.ptr
, buf
.length
);
160 auto errs
= strerror_r(err
, buf
.ptr
, buf
.length
);
164 return "Socket error " ~ to
!string(err
);
167 auto len
= strlen(cs
);
169 if (cs
[len
- 1] == '\n')
171 if (cs
[len
- 1] == '\r')
173 return cs
[0 .. len
].idup
;
178 return generateSysErrorMsg(err
);
181 return "Socket error " ~ to
!string(err
);
184 /// Returns the error message of the most recently encountered network error.
185 @property string
lastSocketError()
187 return formatSocketError(_lasterr());
190 /// Socket exception representing network errors reported by the operating system.
191 class SocketOSException
: SocketException
193 int errorCode
; /// Platform-specific error code.
197 string file
= __FILE__
,
198 size_t line
= __LINE__
,
199 Throwable next
= null,
200 int err
= _lasterr(),
201 string
function(int) @trusted errorFormatter
= &formatSocketError
)
206 super(msg
~ ": " ~ errorFormatter(err
), file
, line
, next
);
208 super(errorFormatter(err
), file
, line
, next
);
214 string file
= __FILE__
,
215 size_t line
= __LINE__
,
216 int err
= _lasterr(),
217 string
function(int) @trusted errorFormatter
= &formatSocketError
)
219 this(msg
, file
, line
, next
, err
, errorFormatter
);
225 string
function(int) @trusted errorFormatter
= &formatSocketError
,
226 string file
= __FILE__
,
227 size_t line
= __LINE__
,
228 Throwable next
= null)
230 this(msg
, file
, line
, next
, err
, errorFormatter
);
234 /// Socket exception representing invalid parameters specified by user code.
235 class SocketParameterException
: SocketException
237 mixin basicExceptionCtors
;
241 * Socket exception representing attempts to use network capabilities not
242 * available on the current system.
244 class SocketFeatureException
: SocketException
246 mixin basicExceptionCtors
;
252 * `true` if the last socket operation failed because the socket
253 * was in non-blocking mode and the operation would have blocked,
254 * or if the socket is in blocking mode and set a `SNDTIMEO` or `RCVTIMEO`,
255 * and the operation timed out.
257 bool wouldHaveBlocked() nothrow @nogc
260 return _lasterr() == WSAEWOULDBLOCK ||
_lasterr() == WSAETIMEDOUT
;
262 return _lasterr() == EAGAIN
;
264 static assert(0, "No socket support for this platform yet.");
269 auto sockets
= socketPair();
271 s
.setOption(SocketOptionLevel
.SOCKET
, SocketOption
.RCVTIMEO
, dur
!"msecs"(10));
272 ubyte[] buffer
= new ubyte[](16);
273 auto rec
= s
.receive(buffer
);
274 assert(rec
== -1 && wouldHaveBlocked());
280 typeof(&getnameinfo
) getnameinfoPointer
;
281 typeof(&getaddrinfo
) getaddrinfoPointer
;
282 typeof(&freeaddrinfo
) freeaddrinfoPointer
;
285 shared static this() @system
291 // Winsock will still load if an older version is present.
292 // The version is just a request.
294 val
= WSAStartup(0x2020, &wd
);
295 if (val
) // Request Winsock 2.2 for IPv6.
296 throw new SocketOSException("Unable to initialize socket library", val
);
298 // These functions may not be present on older Windows versions.
299 // See the comment in InternetAddress.toHostNameString() for details.
300 auto ws2Lib
= GetModuleHandleA("ws2_32.dll");
303 getnameinfoPointer
= cast(typeof(getnameinfoPointer
))
304 GetProcAddress(ws2Lib
, "getnameinfo");
305 getaddrinfoPointer
= cast(typeof(getaddrinfoPointer
))
306 GetProcAddress(ws2Lib
, "getaddrinfo");
307 freeaddrinfoPointer
= cast(typeof(freeaddrinfoPointer
))
308 GetProcAddress(ws2Lib
, "freeaddrinfo");
313 getnameinfoPointer
= &getnameinfo
;
314 getaddrinfoPointer
= &getaddrinfo
;
315 freeaddrinfoPointer
= &freeaddrinfo
;
320 shared static ~this() @system nothrow @nogc
329 * The communication domain used to resolve an address.
331 enum AddressFamily
: ushort
333 UNSPEC
= AF_UNSPEC
, /// Unspecified address family
334 UNIX
= AF_UNIX
, /// Local communication (Unix socket)
335 INET
= AF_INET
, /// Internet Protocol version 4
336 IPX
= AF_IPX
, /// Novell IPX
337 APPLETALK
= AF_APPLETALK
, /// AppleTalk
338 INET6
= AF_INET6
, /// Internet Protocol version 6
343 * Communication semantics
347 STREAM
= SOCK_STREAM
, /// Sequenced, reliable, two-way communication-based byte streams
348 DGRAM
= SOCK_DGRAM
, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
349 RAW
= SOCK_RAW
, /// Raw protocol access
350 RDM
= SOCK_RDM
, /// Reliably-delivered message datagrams
351 SEQPACKET
= SOCK_SEQPACKET
, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
358 enum ProtocolType
: int
360 IP
= IPPROTO_IP
, /// Internet Protocol version 4
361 ICMP
= IPPROTO_ICMP
, /// Internet Control Message Protocol
362 IGMP
= IPPROTO_IGMP
, /// Internet Group Management Protocol
363 GGP
= IPPROTO_GGP
, /// Gateway to Gateway Protocol
364 TCP
= IPPROTO_TCP
, /// Transmission Control Protocol
365 PUP
= IPPROTO_PUP
, /// PARC Universal Packet Protocol
366 UDP
= IPPROTO_UDP
, /// User Datagram Protocol
367 IDP
= IPPROTO_IDP
, /// Xerox NS protocol
368 RAW
= IPPROTO_RAW
, /// Raw IP packets
369 IPV6
= IPPROTO_IPV6
, /// Internet Protocol version 6
374 * Class for retrieving protocol information.
378 * auto proto = new Protocol;
379 * writeln("About protocol TCP:");
380 * if (proto.getProtocolByType(ProtocolType.TCP))
382 * writefln(" Name: %s", proto.name);
383 * foreach (string s; proto.aliases)
384 * writefln(" Alias: %s", s);
387 * writeln(" No information found");
392 /// These members are populated when one of the following functions are called successfully:
394 string name
; /// ditto
395 string
[] aliases
; /// ditto
398 void populate(protoent
* proto
) @system pure nothrow
400 type
= cast(ProtocolType
) proto
.p_proto
;
401 name
= to
!string(proto
.p_name
);
406 if (!proto
.p_aliases
[i
])
412 aliases
= new string
[i
];
413 for (i
= 0; i
!= aliases
.length
; i
++)
416 to
!string(proto
.p_aliases
[i
]);
425 /** Returns: false on failure */
426 bool getProtocolByName(scope const(char)[] name
) @trusted nothrow
429 proto
= getprotobyname(name
.tempCString());
437 /** Returns: false on failure */
438 // Same as getprotobynumber().
439 bool getProtocolByType(ProtocolType type
) @trusted nothrow
442 proto
= getprotobynumber(type
);
451 // Skip this test on Android because getprotobyname/number are
452 // unimplemented in bionic.
453 version (CRuntime_Bionic
) {} else
456 // import std.stdio : writefln;
458 Protocol proto
= new Protocol
;
459 assert(proto
.getProtocolByType(ProtocolType
.TCP
));
460 //writeln("About protocol TCP:");
461 //writefln("\tName: %s", proto.name);
462 // foreach (string s; proto.aliases)
464 // writefln("\tAlias: %s", s);
466 assert(proto
.name
== "tcp");
467 assert(proto
.aliases
.length
== 1 && proto
.aliases
[0] == "TCP");
473 * Class for retrieving service information.
477 * auto serv = new Service;
478 * writeln("About service epmap:");
479 * if (serv.getServiceByName("epmap", "tcp"))
481 * writefln(" Service: %s", serv.name);
482 * writefln(" Port: %d", serv.port);
483 * writefln(" Protocol: %s", serv.protocolName);
484 * foreach (string s; serv.aliases)
485 * writefln(" Alias: %s", s);
488 * writefln(" No service for epmap.");
493 /// These members are populated when one of the following functions are called successfully:
495 string
[] aliases
; /// ditto
496 ushort port
; /// ditto
497 string protocolName
; /// ditto
500 void populate(servent
* serv
) @system pure nothrow
502 name
= to
!string(serv
.s_name
);
503 port
= ntohs(cast(ushort) serv
.s_port
);
504 protocolName
= to
!string(serv
.s_proto
);
509 if (!serv
.s_aliases
[i
])
515 aliases
= new string
[i
];
516 for (i
= 0; i
!= aliases
.length
; i
++)
519 to
!string(serv
.s_aliases
[i
]);
529 * If a protocol name is omitted, any protocol will be matched.
530 * Returns: false on failure.
532 bool getServiceByName(scope const(char)[] name
, scope const(char)[] protocolName
= null) @trusted nothrow
535 serv
= getservbyname(name
.tempCString(), protocolName
.tempCString());
544 bool getServiceByPort(ushort port
, scope const(char)[] protocolName
= null) @trusted nothrow
547 serv
= getservbyport(port
, protocolName
.tempCString());
558 import std
.stdio
: writefln
;
560 Service serv
= new Service
;
561 if (serv
.getServiceByName("epmap", "tcp"))
563 // writefln("About service epmap:");
564 // writefln("\tService: %s", serv.name);
565 // writefln("\tPort: %d", serv.port);
566 // writefln("\tProtocol: %s", serv.protocolName);
567 // foreach (string s; serv.aliases)
569 // writefln("\tAlias: %s", s);
571 // For reasons unknown this is loc-srv on Wine and epmap on Windows
572 assert(serv
.name
== "loc-srv" || serv
.name
== "epmap", serv
.name
);
573 assert(serv
.port
== 135);
574 assert(serv
.protocolName
== "tcp");
578 writefln("No service for epmap.");
584 private mixin template socketOSExceptionCtors()
587 this(string msg
, string file
= __FILE__
, size_t line
= __LINE__
,
588 Throwable next
= null, int err
= _lasterr())
590 super(msg
, file
, line
, next
, err
);
594 this(string msg
, Throwable next
, string file
= __FILE__
,
595 size_t line
= __LINE__
, int err
= _lasterr())
597 super(msg
, next
, file
, line
, err
);
601 this(string msg
, int err
, string file
= __FILE__
, size_t line
= __LINE__
,
602 Throwable next
= null)
604 super(msg
, next
, file
, line
, err
);
610 * Class for exceptions thrown from an `InternetHost`.
612 class HostException
: SocketOSException
614 mixin socketOSExceptionCtors
;
618 * Class for resolving IPv4 addresses.
620 * Consider using `getAddress`, `parseAddress` and `Address` methods
621 * instead of using this class directly.
625 /// These members are populated when one of the following functions are called successfully:
627 string
[] aliases
; /// ditto
628 uint[] addrList
; /// ditto
631 void validHostent(in hostent
* he
)
633 if (he
.h_addrtype
!= cast(int) AddressFamily
.INET || he
.h_length
!= 4)
634 throw new HostException("Address family mismatch");
638 void populate(hostent
* he
) @system pure nothrow
643 name
= to
!string(he
.h_name
);
654 aliases
= new string
[i
];
655 for (i
= 0; i
!= aliases
.length
; i
++)
658 to
!string(he
.h_aliases
[i
]);
668 p
= he
.h_addr_list
[i
];
675 addrList
= new uint[i
];
676 for (i
= 0; i
!= addrList
.length
; i
++)
678 addrList
[i
] = ntohl(*(cast(uint*) he
.h_addr_list
[i
]));
687 private bool getHostNoSync(string opMixin
, T
)(T param
) @system
698 alias getHost
= getHostNoSync
;
701 // posix systems use global state for return value, so we
702 // must synchronize across all threads
703 private bool getHost(string opMixin
, T
)(T param
) @system
705 synchronized(this.classinfo
)
706 return getHostNoSync
!(opMixin
, T
)(param
);
712 * Returns: false if unable to resolve.
714 bool getHostByName(scope const(char)[] name
) @trusted
716 static if (is(typeof(gethostbyname_r
)))
718 return getHostNoSync
!q
{
721 ubyte[256] buffer_v
= void;
722 auto buffer
= buffer_v
[];
723 auto param_zTmp
= param
.tempCString();
728 if (gethostbyname_r(param_zTmp
, he
, buffer
.ptr
, buffer
.length
, &he
, &errno
) == ERANGE
)
729 buffer
.length
= buffer
.length
* 2;
738 auto he
= gethostbyname(param
.tempCString());
744 * Resolve IPv4 address number.
747 * addr = The IPv4 address to resolve, in host byte order.
749 * false if unable to resolve.
751 bool getHostByAddr(uint addr
) @trusted
754 auto x
= htonl(param
);
755 auto he
= gethostbyaddr(&x
, 4, cast(int) AddressFamily
.INET
);
760 * Same as previous, but addr is an IPv4 address string in the
761 * dotted-decimal form $(I a.b.c.d).
762 * Returns: false if unable to resolve.
764 bool getHostByAddr(scope const(char)[] addr
) @trusted
767 auto x
= inet_addr(param
.tempCString());
768 enforce(x
!= INADDR_NONE
,
769 new SocketParameterException("Invalid IPv4 address"));
770 auto he
= gethostbyaddr(&x
, 4, cast(int) AddressFamily
.INET
);
778 InternetHost ih
= new InternetHost
;
780 ih
.getHostByAddr(0x7F_00_00_01);
781 assert(ih
.addrList
[0] == 0x7F_00_00_01);
782 ih
.getHostByAddr("127.0.0.1");
783 assert(ih
.addrList
[0] == 0x7F_00_00_01);
785 if (!ih
.getHostByName("www.digitalmars.com"))
786 return; // don't fail if not connected to internet
788 assert(ih
.addrList
.length
);
789 InternetAddress ia
= new InternetAddress(ih
.addrList
[0], InternetAddress
.PORT_ANY
);
790 assert(ih
.name
== "www.digitalmars.com" || ih
.name
== "digitalmars.com",
793 /* The following assert randomly fails in the test suite.
794 * https://issues.dlang.org/show_bug.cgi?id=22791
795 * So just ignore it when it fails.
797 //assert(ih.getHostByAddr(ih.addrList[0]));
798 if (ih
.getHostByAddr(ih
.addrList
[0]))
800 string getHostNameFromInt
= ih
.name
.dup
;
802 // This randomly fails in the compiler test suite
803 //assert(ih.getHostByAddr(ia.toAddrString()));
805 if (ih
.getHostByAddr(ia
.toAddrString()))
807 string getHostNameFromStr
= ih
.name
.dup
;
808 assert(getHostNameFromInt
== getHostNameFromStr
);
814 /// Holds information about a socket _address retrieved by `getAddressInfo`.
817 AddressFamily family
; /// Address _family
818 SocketType type
; /// Socket _type
819 ProtocolType protocol
; /// Protocol
820 Address address
; /// Socket _address
821 string canonicalName
; /// Canonical name, when `AddressInfoFlags.CANONNAME` is used.
825 * A subset of flags supported on all platforms with getaddrinfo.
826 * Specifies option flags for `getAddressInfo`.
828 enum AddressInfoFlags
: int
830 /// The resulting addresses will be used in a call to `Socket.bind`.
831 PASSIVE
= AI_PASSIVE
,
833 /// The canonical name is returned in `canonicalName` member in the first `AddressInfo`.
834 CANONNAME
= AI_CANONNAME
,
837 * The `node` parameter passed to `getAddressInfo` must be a numeric string.
838 * This will suppress any potentially lengthy network host address lookups.
840 NUMERICHOST
= AI_NUMERICHOST
,
845 * On POSIX, getaddrinfo uses its own error codes, and thus has its own
846 * formatting function.
848 private string
formatGaiError(int err
) @trusted
852 return generateSysErrorMsg(err
);
857 return to
!string(gai_strerror(err
));
862 * Provides _protocol-independent translation from host names to socket
863 * addresses. If advanced functionality is not required, consider using
864 * `getAddress` for compatibility with older systems.
866 * Returns: Array with one `AddressInfo` per socket address.
868 * Throws: `SocketOSException` on failure, or `SocketFeatureException`
869 * if this functionality is not available on the current system.
872 * node = string containing host name or numeric address
873 * options = optional additional parameters, identified by type:
874 * $(UL $(LI `string` - service name or port number)
875 * $(LI `AddressInfoFlags` - option flags)
876 * $(LI `AddressFamily` - address family to filter by)
877 * $(LI `SocketType` - socket type to filter by)
878 * $(LI `ProtocolType` - protocol to filter by))
882 * // Roundtrip DNS resolution
883 * auto results = getAddressInfo("www.digitalmars.com");
884 * assert(results[0].address.toHostNameString() ==
885 * "digitalmars.com");
888 * results = getAddressInfo("www.digitalmars.com",
889 * AddressInfoFlags.CANONNAME);
890 * assert(results[0].canonicalName == "digitalmars.com");
893 * results = getAddressInfo("ipv6.google.com");
894 * assert(results[0].family == AddressFamily.INET6);
896 * // Multihomed resolution
897 * results = getAddressInfo("google.com");
898 * assert(results.length > 1);
901 * results = getAddressInfo("127.0.0.1",
902 * AddressInfoFlags.NUMERICHOST);
903 * assert(results.length && results[0].family ==
904 * AddressFamily.INET);
907 * results = getAddressInfo("::1",
908 * AddressInfoFlags.NUMERICHOST);
909 * assert(results.length && results[0].family ==
910 * AddressFamily.INET6);
913 AddressInfo
[] getAddressInfo(T
...)(scope const(char)[] node
, scope T options
)
915 const(char)[] service
= null;
917 hints
.ai_family
= AF_UNSPEC
;
919 foreach (i
, option
; options
)
921 static if (is(typeof(option
) : const(char)[]))
922 service
= options
[i
];
924 static if (is(typeof(option
) == AddressInfoFlags
))
925 hints
.ai_flags |
= option
;
927 static if (is(typeof(option
) == AddressFamily
))
928 hints
.ai_family
= option
;
930 static if (is(typeof(option
) == SocketType
))
931 hints
.ai_socktype
= option
;
933 static if (is(typeof(option
) == ProtocolType
))
934 hints
.ai_protocol
= option
;
936 static assert(0, "Unknown getAddressInfo option type: " ~ typeof(option
).stringof
);
939 return () @trusted { return getAddressInfoImpl(node
, service
, &hints
); }();
946 const(char[]) breakSafety()
948 *cast(int*) 0xcafebabe = 0xdeadbeef;
951 alias breakSafety
this;
953 assert(!__traits(compiles
, () {
954 getAddressInfo("", Oops
.init
);
955 }), "getAddressInfo breaks @safe");
958 private AddressInfo
[] getAddressInfoImpl(scope const(char)[] node
, scope const(char)[] service
, addrinfo
* hints
) @system
960 import std
.array
: appender
;
962 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
966 int ret = getaddrinfoPointer(
968 service
.tempCString(),
970 enforce(ret == 0, new SocketOSException("getaddrinfo error", ret, &formatGaiError
));
971 scope(exit
) freeaddrinfoPointer(ai_res
);
973 auto result
= appender
!(AddressInfo
[])();
975 // Use const to force UnknownAddressReference to copy the sockaddr.
976 for (const(addrinfo
)* ai
= ai_res
; ai
; ai
= ai
.ai_next
)
977 result
~= AddressInfo(
978 cast(AddressFamily
) ai
.ai_family
,
979 cast(SocketType
) ai
.ai_socktype
,
980 cast(ProtocolType
) ai
.ai_protocol
,
981 new UnknownAddressReference(ai
.ai_addr
, cast(socklen_t
) ai
.ai_addrlen
),
982 ai
.ai_canonname ? to
!string(ai
.ai_canonname
) : null);
984 assert(result
.data
.length
> 0);
988 throw new SocketFeatureException("Address info lookup is not available " ~
996 if (getaddrinfoPointer
)
998 // Roundtrip DNS resolution
999 auto results
= getAddressInfo("www.digitalmars.com");
1000 assert(results
[0].address
.toHostNameString() == "digitalmars.com");
1003 results
= getAddressInfo("www.digitalmars.com",
1004 AddressInfoFlags
.CANONNAME
);
1005 assert(results
[0].canonicalName
== "digitalmars.com");
1008 //results = getAddressInfo("ipv6.google.com");
1009 //assert(results[0].family == AddressFamily.INET6);
1011 // Multihomed resolution
1012 //results = getAddressInfo("google.com");
1013 //assert(results.length > 1);
1016 results
= getAddressInfo("127.0.0.1", AddressInfoFlags
.NUMERICHOST
);
1017 assert(results
.length
&& results
[0].family
== AddressFamily
.INET
);
1020 results
= getAddressInfo("::1", AddressInfoFlags
.NUMERICHOST
);
1021 assert(results
.length
&& results
[0].family
== AddressFamily
.INET6
);
1025 if (getaddrinfoPointer
)
1027 auto results
= getAddressInfo(null, "1234", AddressInfoFlags
.PASSIVE
,
1028 SocketType
.STREAM
, ProtocolType
.TCP
, AddressFamily
.INET
);
1029 assert(results
.length
== 1 && results
[0].address
.toString() == "0.0.0.0:1234");
1034 private ushort serviceToPort(scope const(char)[] service
)
1037 return InternetAddress
.PORT_ANY
;
1039 if (isNumeric(service
))
1040 return to
!ushort(service
);
1043 auto s
= new Service();
1044 s
.getServiceByName(service
);
1050 * Provides _protocol-independent translation from host names to socket
1051 * addresses. Uses `getAddressInfo` if the current system supports it,
1052 * and `InternetHost` otherwise.
1054 * Returns: Array with one `Address` instance per socket address.
1056 * Throws: `SocketOSException` on failure.
1060 * writeln("Resolving www.digitalmars.com:");
1063 * auto addresses = getAddress("www.digitalmars.com");
1064 * foreach (address; addresses)
1065 * writefln(" IP: %s", address.toAddrString());
1067 * catch (SocketException e)
1068 * writefln(" Lookup failed: %s", e.msg);
1071 Address
[] getAddress(scope const(char)[] hostname
, scope const(char)[] service
= null)
1073 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1075 // use getAddressInfo
1076 auto infos
= getAddressInfo(hostname
, service
);
1078 results
.length
= infos
.length
;
1079 foreach (i
, ref result
; results
)
1080 result
= infos
[i
].address
;
1084 return getAddress(hostname
, serviceToPort(service
));
1088 Address
[] getAddress(scope const(char)[] hostname
, ushort port
)
1090 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1091 return getAddress(hostname
, to
!string(port
));
1094 // use getHostByName
1095 auto ih
= new InternetHost
;
1096 if (!ih
.getHostByName(hostname
))
1097 throw new AddressException(
1098 text("Unable to resolve host '", hostname
, "'"));
1101 foreach (uint addr
; ih
.addrList
)
1102 results
~= new InternetAddress(addr
, port
);
1111 auto addresses
= getAddress("63.105.9.61");
1112 assert(addresses
.length
&& addresses
[0].toAddrString() == "63.105.9.61");
1114 if (getaddrinfoPointer
)
1116 // test via gethostbyname
1117 auto getaddrinfoPointerBackup
= getaddrinfoPointer
;
1118 cast() getaddrinfoPointer
= null;
1119 scope(exit
) cast() getaddrinfoPointer
= getaddrinfoPointerBackup
;
1121 addresses
= getAddress("63.105.9.61");
1122 assert(addresses
.length
&& addresses
[0].toAddrString() == "63.105.9.61");
1129 * Provides _protocol-independent parsing of network addresses. Does not
1130 * attempt name resolution. Uses `getAddressInfo` with
1131 * `AddressInfoFlags.NUMERICHOST` if the current system supports it, and
1132 * `InternetAddress` otherwise.
1134 * Returns: An `Address` instance representing specified address.
1136 * Throws: `SocketException` on failure.
1140 * writeln("Enter IP address:");
1141 * string ip = readln().chomp();
1144 * Address address = parseAddress(ip);
1145 * writefln("Looking up reverse of %s:",
1146 * address.toAddrString());
1149 * string reverse = address.toHostNameString();
1151 * writefln(" Reverse name: %s", reverse);
1153 * writeln(" Reverse hostname not found.");
1155 * catch (SocketException e)
1156 * writefln(" Lookup error: %s", e.msg);
1158 * catch (SocketException e)
1160 * writefln(" %s is not a valid IP address: %s",
1165 Address
parseAddress(scope const(char)[] hostaddr
, scope const(char)[] service
= null)
1167 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1168 return getAddressInfo(hostaddr
, service
, AddressInfoFlags
.NUMERICHOST
)[0].address
;
1170 return parseAddress(hostaddr
, serviceToPort(service
));
1174 Address
parseAddress(scope const(char)[] hostaddr
, ushort port
)
1176 if (getaddrinfoPointer
&& freeaddrinfoPointer
)
1177 return parseAddress(hostaddr
, to
!string(port
));
1180 auto in4_addr
= InternetAddress
.parse(hostaddr
);
1181 enforce(in4_addr
!= InternetAddress
.ADDR_NONE
,
1182 new SocketParameterException("Invalid IP address"));
1183 return new InternetAddress(in4_addr
, port
);
1191 auto address
= parseAddress("63.105.9.61");
1192 assert(address
.toAddrString() == "63.105.9.61");
1194 if (getaddrinfoPointer
)
1196 // test via inet_addr
1197 auto getaddrinfoPointerBackup
= getaddrinfoPointer
;
1198 cast() getaddrinfoPointer
= null;
1199 scope(exit
) cast() getaddrinfoPointer
= getaddrinfoPointerBackup
;
1201 address
= parseAddress("63.105.9.61");
1202 assert(address
.toAddrString() == "63.105.9.61");
1205 assert(collectException
!SocketException(parseAddress("Invalid IP address")));
1211 * Class for exceptions thrown from an `Address`.
1213 class AddressException
: SocketOSException
1215 mixin socketOSExceptionCtors
;
1220 * Abstract class for representing a socket address.
1224 * writeln("About www.google.com port 80:");
1227 * Address[] addresses = getAddress("www.google.com", 80);
1228 * writefln(" %d addresses found.", addresses.length);
1229 * foreach (int i, Address a; addresses)
1231 * writefln(" Address %d:", i+1);
1232 * writefln(" IP address: %s", a.toAddrString());
1233 * writefln(" Hostname: %s", a.toHostNameString());
1234 * writefln(" Port: %s", a.toPortString());
1235 * writefln(" Service name: %s",
1236 * a.toServiceNameString());
1239 * catch (SocketException e)
1240 * writefln(" Lookup error: %s", e.msg);
1243 abstract class Address
1245 /// Returns pointer to underlying `sockaddr` structure.
1246 abstract @property sockaddr
* name() pure nothrow @nogc;
1247 abstract @property const(sockaddr
)* name() const pure nothrow @nogc; /// ditto
1249 /// Returns actual size of underlying `sockaddr` structure.
1250 abstract @property socklen_t
nameLen() const pure nothrow @nogc;
1252 // Socket.remoteAddress, Socket.localAddress, and Socket.receiveFrom
1253 // use setNameLen to set the actual size of the address as returned by
1254 // getsockname, getpeername, and recvfrom, respectively.
1255 // The following implementation is sufficient for fixed-length addresses,
1256 // and ensures that the length is not changed.
1257 // Must be overridden for variable-length addresses.
1258 protected void setNameLen(socklen_t len
)
1260 if (len
!= this.nameLen
)
1261 throw new AddressException(
1262 format("%s expects address of length %d, not %d", typeid(this),
1263 this.nameLen
, len
), 0);
1266 /// Family of this address.
1267 @property AddressFamily
addressFamily() const pure nothrow @nogc
1269 return cast(AddressFamily
) name
.sa_family
;
1272 // Common code for toAddrString and toHostNameString
1273 private string
toHostString(bool numeric
) @trusted const
1275 // getnameinfo() is the recommended way to perform a reverse (name)
1276 // lookup on both Posix and Windows. However, it is only available
1277 // on Windows XP and above, and not included with the WinSock import
1278 // libraries shipped with DMD. Thus, we check for getnameinfo at
1279 // runtime in the shared module constructor, and use it if it's
1280 // available in the base class method. Classes for specific network
1281 // families (e.g. InternetHost) override this method and use a
1282 // deprecated, albeit commonly-available method when getnameinfo()
1283 // is not available.
1284 // http://technet.microsoft.com/en-us/library/aa450403.aspx
1285 if (getnameinfoPointer
)
1287 auto buf
= new char[NI_MAXHOST
];
1288 auto ret = getnameinfoPointer(
1290 buf
.ptr
, cast(uint) buf
.length
,
1292 numeric ? NI_NUMERICHOST
: NI_NAMEREQD
);
1296 if (ret == EAI_NONAME
)
1299 if (ret == WSANO_DATA
)
1303 enforce(ret == 0, new AddressException("Could not get " ~
1304 (numeric ?
"host address" : "host name")));
1305 return assumeUnique(buf
[0 .. strlen(buf
.ptr
)]);
1308 throw new SocketFeatureException((numeric ?
"Host address" : "Host name") ~
1309 " lookup for this address family is not available on this system.");
1312 // Common code for toPortString and toServiceNameString
1313 private string
toServiceString(bool numeric
) @trusted const
1315 // See toHostNameString() for details about getnameinfo().
1316 if (getnameinfoPointer
)
1318 auto buf
= new char[NI_MAXSERV
];
1319 enforce(getnameinfoPointer(
1322 buf
.ptr
, cast(uint) buf
.length
,
1323 numeric ? NI_NUMERICSERV
: NI_NAMEREQD
1324 ) == 0, new AddressException("Could not get " ~
1325 (numeric ?
"port number" : "service name")));
1326 return assumeUnique(buf
[0 .. strlen(buf
.ptr
)]);
1329 throw new SocketFeatureException((numeric ?
"Port number" : "Service name") ~
1330 " lookup for this address family is not available on this system.");
1334 * Attempts to retrieve the host address as a human-readable string.
1336 * Throws: `AddressException` on failure, or `SocketFeatureException`
1337 * if address retrieval for this address family is not available on the
1340 string
toAddrString() const
1342 return toHostString(true);
1346 * Attempts to retrieve the host name as a fully qualified domain name.
1348 * Returns: The FQDN corresponding to this `Address`, or `null` if
1349 * the host name did not resolve.
1351 * Throws: `AddressException` on error, or `SocketFeatureException`
1352 * if host name lookup for this address family is not available on the
1355 string
toHostNameString() const
1357 return toHostString(false);
1361 * Attempts to retrieve the numeric port number as a string.
1363 * Throws: `AddressException` on failure, or `SocketFeatureException`
1364 * if port number retrieval for this address family is not available on the
1367 string
toPortString() const
1369 return toServiceString(true);
1373 * Attempts to retrieve the service name as a string.
1375 * Throws: `AddressException` on failure, or `SocketFeatureException`
1376 * if service name lookup for this address family is not available on the
1379 string
toServiceNameString() const
1381 return toServiceString(false);
1384 /// Human readable string representing this address.
1385 override string
toString() const
1389 string host
= toAddrString();
1390 string port
= toPortString();
1391 if (host
.indexOf(':') >= 0)
1392 return "[" ~ host
~ "]:" ~ port
;
1394 return host
~ ":" ~ port
;
1396 catch (SocketException
)
1402 * Encapsulates an unknown socket address.
1404 class UnknownAddress
: Address
1411 override @property sockaddr
* name() return
1416 override @property const(sockaddr
)* name() const return
1422 override @property socklen_t
nameLen() const
1424 return cast(socklen_t
) sa
.sizeof
;
1431 * Encapsulates a reference to an arbitrary
1434 class UnknownAddressReference
: Address
1441 /// Constructs an `Address` with a reference to the specified `sockaddr`.
1442 this(sockaddr
* sa
, socklen_t len
) pure nothrow @nogc
1448 /// Constructs an `Address` with a copy of the specified `sockaddr`.
1449 this(const(sockaddr
)* sa
, socklen_t len
) @system pure nothrow
1451 this.sa
= cast(sockaddr
*) (cast(ubyte*) sa
)[0 .. len
].dup
.ptr
;
1455 override @property sockaddr
* name()
1460 override @property const(sockaddr
)* name() const
1466 override @property socklen_t
nameLen() const
1468 return cast(socklen_t
) len
;
1474 * Encapsulates an IPv4 (Internet Protocol version 4) socket address.
1476 * Consider using `getAddress`, `parseAddress` and `Address` methods
1477 * instead of using this class directly.
1479 class InternetAddress
: Address
1485 this() pure nothrow @nogc
1491 override @property sockaddr
* name() return
1493 return cast(sockaddr
*)&sin
;
1496 override @property const(sockaddr
)* name() const return
1498 return cast(const(sockaddr
)*)&sin
;
1502 override @property socklen_t
nameLen() const
1504 return cast(socklen_t
) sin
.sizeof
;
1508 enum uint ADDR_ANY
= INADDR_ANY
; /// Any IPv4 host address.
1509 enum uint ADDR_NONE
= INADDR_NONE
; /// An invalid IPv4 host address.
1510 enum ushort PORT_ANY
= 0; /// Any IPv4 port number.
1512 /// Returns the IPv4 _port number (in host byte order).
1513 @property ushort port() const pure nothrow @nogc
1515 return ntohs(sin
.sin_port
);
1518 /// Returns the IPv4 address number (in host byte order).
1519 @property uint addr() const pure nothrow @nogc
1521 return ntohl(sin
.sin_addr
.s_addr
);
1525 * Construct a new `InternetAddress`.
1527 * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
1528 * or a host name which will be resolved using an `InternetHost`
1530 * port = port number, may be `PORT_ANY`.
1532 this(scope const(char)[] addr
, ushort port
)
1534 uint uiaddr
= parse(addr
);
1535 if (ADDR_NONE
== uiaddr
)
1537 InternetHost ih
= new InternetHost
;
1538 if (!ih
.getHostByName(addr
))
1539 //throw new AddressException("Invalid internet address");
1540 throw new AddressException(
1541 text("Unable to resolve host '", addr
, "'"));
1542 uiaddr
= ih
.addrList
[0];
1544 sin
.sin_family
= AddressFamily
.INET
;
1545 sin
.sin_addr
.s_addr
= htonl(uiaddr
);
1546 sin
.sin_port
= htons(port
);
1550 * Construct a new `InternetAddress`.
1552 * addr = (optional) an IPv4 address in host byte order, may be `ADDR_ANY`.
1553 * port = port number, may be `PORT_ANY`.
1555 this(uint addr
, ushort port
) pure nothrow @nogc
1557 sin
.sin_family
= AddressFamily
.INET
;
1558 sin
.sin_addr
.s_addr
= htonl(addr
);
1559 sin
.sin_port
= htons(port
);
1563 this(ushort port
) pure nothrow @nogc
1565 sin
.sin_family
= AddressFamily
.INET
;
1566 sin
.sin_addr
.s_addr
= ADDR_ANY
;
1567 sin
.sin_port
= htons(port
);
1571 * Construct a new `InternetAddress`.
1573 * addr = A sockaddr_in as obtained from lower-level API calls such as getifaddrs.
1575 this(sockaddr_in addr
) pure nothrow @nogc
1577 assert(addr
.sin_family
== AddressFamily
.INET
, "Socket address is not of INET family.");
1581 /// Human readable string representing the IPv4 address in dotted-decimal form.
1582 override string
toAddrString() @trusted const
1584 return to
!string(inet_ntoa(sin
.sin_addr
));
1587 /// Human readable string representing the IPv4 port.
1588 override string
toPortString() const
1590 return std
.conv
.to
!string(port
);
1594 * Attempts to retrieve the host name as a fully qualified domain name.
1596 * Returns: The FQDN corresponding to this `InternetAddress`, or
1597 * `null` if the host name did not resolve.
1599 * Throws: `AddressException` on error.
1601 override string
toHostNameString() const
1603 // getnameinfo() is the recommended way to perform a reverse (name)
1604 // lookup on both Posix and Windows. However, it is only available
1605 // on Windows XP and above, and not included with the WinSock import
1606 // libraries shipped with DMD. Thus, we check for getnameinfo at
1607 // runtime in the shared module constructor, and fall back to the
1608 // deprecated getHostByAddr() if it could not be found. See also:
1609 // http://technet.microsoft.com/en-us/library/aa450403.aspx
1611 if (getnameinfoPointer
)
1612 return super.toHostNameString();
1615 auto host
= new InternetHost();
1616 if (!host
.getHostByAddr(ntohl(sin
.sin_addr
.s_addr
)))
1623 * Provides support for comparing equality with another
1624 * InternetAddress of the same type.
1625 * Returns: true if the InternetAddresses share the same address and
1628 override bool opEquals(Object o
) const
1630 auto other
= cast(InternetAddress
) o
;
1631 return other
&& this.sin
.sin_addr
.s_addr
== other
.sin
.sin_addr
.s_addr
&&
1632 this.sin
.sin_port
== other
.sin
.sin_port
;
1638 auto addr1
= new InternetAddress("127.0.0.1", 80);
1639 auto addr2
= new InternetAddress("127.0.0.2", 80);
1641 assert(addr1
== addr1
);
1642 assert(addr1
!= addr2
);
1646 * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
1647 * and return the number.
1648 * Returns: If the string is not a legitimate IPv4 address,
1649 * `ADDR_NONE` is returned.
1651 static uint parse(scope const(char)[] addr
) @trusted nothrow
1653 return ntohl(inet_addr(addr
.tempCString()));
1657 * Convert an IPv4 address number in host byte order to a human readable
1658 * string representing the IPv4 address in dotted-decimal form.
1660 static string
addrToString(uint addr
) @trusted nothrow
1663 sin_addr
.s_addr
= htonl(addr
);
1664 return to
!string(inet_ntoa(sin_addr
));
1672 const InternetAddress ia
= new InternetAddress("63.105.9.61", 80);
1673 assert(ia
.toString() == "63.105.9.61:80");
1677 // test construction from a sockaddr_in
1680 sin
.sin_addr
.s_addr
= htonl(0x7F_00_00_01); // 127.0.0.1
1681 sin
.sin_family
= AddressFamily
.INET
;
1682 sin
.sin_port
= htons(80);
1684 const InternetAddress ia
= new InternetAddress(sin
);
1685 assert(ia
.toString() == "127.0.0.1:80");
1689 // test reverse lookup
1690 auto ih
= new InternetHost
;
1691 if (ih
.getHostByName("digitalmars.com"))
1693 const ia
= new InternetAddress(ih
.addrList
[0], 80);
1694 assert(ia
.toHostNameString() == "digitalmars.com");
1696 if (getnameinfoPointer
)
1698 // test reverse lookup, via gethostbyaddr
1699 auto getnameinfoPointerBackup
= getnameinfoPointer
;
1700 cast() getnameinfoPointer
= null;
1701 scope(exit
) cast() getnameinfoPointer
= getnameinfoPointerBackup
;
1703 assert(ia
.toHostNameString() == "digitalmars.com");
1710 // test failing reverse lookup
1711 const InternetAddress ia
= new InternetAddress("255.255.255.255", 80);
1712 assert(ia
.toHostNameString() is null);
1714 if (getnameinfoPointer
)
1716 // test failing reverse lookup, via gethostbyaddr
1717 auto getnameinfoPointerBackup
= getnameinfoPointer
;
1718 cast() getnameinfoPointer
= null;
1719 scope(exit
) cast() getnameinfoPointer
= getnameinfoPointerBackup
;
1721 assert(ia
.toHostNameString() is null);
1728 * Encapsulates an IPv6 (Internet Protocol version 6) socket address.
1730 * Consider using `getAddress`, `parseAddress` and `Address` methods
1731 * instead of using this class directly.
1733 class Internet6Address
: Address
1739 this() pure nothrow @nogc
1745 override @property sockaddr
* name() return
1747 return cast(sockaddr
*)&sin6
;
1750 override @property const(sockaddr
)* name() const return
1752 return cast(const(sockaddr
)*)&sin6
;
1756 override @property socklen_t
nameLen() const
1758 return cast(socklen_t
) sin6
.sizeof
;
1762 /// Any IPv6 host address.
1763 static @property ref const(ubyte)[16] ADDR_ANY() pure nothrow @nogc
1765 static if (is(typeof(IN6ADDR_ANY
)))
1769 static immutable addr
= IN6ADDR_ANY
.s6_addr
;
1773 return IN6ADDR_ANY
.s6_addr
;
1775 else static if (is(typeof(in6addr_any
)))
1777 return in6addr_any
.s6_addr
;
1783 /// Any IPv6 port number.
1784 enum ushort PORT_ANY
= 0;
1786 /// Returns the IPv6 port number.
1787 @property ushort port() const pure nothrow @nogc
1789 return ntohs(sin6
.sin6_port
);
1792 /// Returns the IPv6 address.
1793 @property ubyte[16] addr() const pure nothrow @nogc
1795 return sin6
.sin6_addr
.s6_addr
;
1799 * Construct a new `Internet6Address`.
1801 * addr = an IPv6 host address string in the form described in RFC 2373,
1802 * or a host name which will be resolved using `getAddressInfo`.
1803 * service = (optional) service name.
1805 this(scope const(char)[] addr
, scope const(char)[] service
= null) @trusted
1807 auto results
= getAddressInfo(addr
, service
, AddressFamily
.INET6
);
1808 assert(results
.length
&& results
[0].family
== AddressFamily
.INET6
);
1809 sin6
= *cast(sockaddr_in6
*) results
[0].address
.name
;
1813 * Construct a new `Internet6Address`.
1815 * addr = an IPv6 host address string in the form described in RFC 2373,
1816 * or a host name which will be resolved using `getAddressInfo`.
1817 * port = port number, may be `PORT_ANY`.
1819 this(scope const(char)[] addr
, ushort port
)
1821 if (port
== PORT_ANY
)
1824 this(addr
, to
!string(port
));
1828 * Construct a new `Internet6Address`.
1830 * addr = (optional) an IPv6 host address in host byte order, or
1832 * port = port number, may be `PORT_ANY`.
1834 this(ubyte[16] addr
, ushort port
) pure nothrow @nogc
1836 sin6
.sin6_family
= AddressFamily
.INET6
;
1837 sin6
.sin6_addr
.s6_addr
= addr
;
1838 sin6
.sin6_port
= htons(port
);
1842 this(ushort port
) pure nothrow @nogc
1844 sin6
.sin6_family
= AddressFamily
.INET6
;
1845 sin6
.sin6_addr
.s6_addr
= ADDR_ANY
;
1846 sin6
.sin6_port
= htons(port
);
1850 * Construct a new `Internet6Address`.
1852 * addr = A sockaddr_in6 as obtained from lower-level API calls such as getifaddrs.
1854 this(sockaddr_in6 addr
) pure nothrow @nogc
1856 assert(addr
.sin6_family
== AddressFamily
.INET6
);
1861 * Parse an IPv6 host address string as described in RFC 2373, and return the
1863 * Throws: `SocketException` on error.
1865 static ubyte[16] parse(scope const(char)[] addr
) @trusted
1867 // Although we could use inet_pton here, it's only available on Windows
1868 // versions starting with Vista, so use getAddressInfo with NUMERICHOST
1870 auto results
= getAddressInfo(addr
, AddressInfoFlags
.NUMERICHOST
);
1871 if (results
.length
&& results
[0].family
== AddressFamily
.INET6
)
1872 return (cast(sockaddr_in6
*) results
[0].address
.name
).sin6_addr
.s6_addr
;
1873 throw new AddressException("Not an IPv6 address", 0);
1881 const Internet6Address ia
= new Internet6Address("::1", 80);
1882 assert(ia
.toString() == "[::1]:80");
1886 // test construction from a sockaddr_in6
1889 sin
.sin6_addr
.s6_addr
= [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]; // [::1]
1890 sin
.sin6_family
= AddressFamily
.INET6
;
1891 sin
.sin6_port
= htons(80);
1893 const Internet6Address ia
= new Internet6Address(sin
);
1894 assert(ia
.toString() == "[::1]:80");
1901 static if (!is(sockaddr_un
))
1903 // This exists only to allow the constructor taking
1904 // a sockaddr_un to be compilable for documentation
1905 // on platforms that don't supply a sockaddr_un.
1912 * Encapsulates an address for a Unix domain socket (`AF_UNIX`),
1913 * i.e. a socket bound to a path name in the file system.
1914 * Available only on supported systems.
1916 * Linux also supports an abstract address namespace, in which addresses
1917 * are independent of the file system. A socket address is abstract
1918 * iff `path` starts with a _null byte (`'\0'`). Null bytes in other
1919 * positions of an abstract address are allowed and have no special
1924 * auto addr = new UnixAddress("/var/run/dbus/system_bus_socket");
1925 * auto abstractAddr = new UnixAddress("\0/tmp/dbus-OtHLWmCLPR");
1928 * See_Also: $(HTTP http://man7.org/linux/man-pages/man7/unix.7.html, UNIX(7))
1930 class UnixAddress
: Address
1932 private this() pure nothrow @nogc {}
1934 /// Construct a new `UnixAddress` from the specified path.
1935 this(scope const(char)[] path
) { }
1938 * Construct a new `UnixAddress`.
1940 * addr = A sockaddr_un as obtained from lower-level API calls.
1942 this(sockaddr_un addr
) pure nothrow @nogc { }
1944 /// Get the underlying _path.
1945 @property string
path() const { return null; }
1948 override string
toString() const { return null; }
1950 override @property sockaddr
* name() { return null; }
1951 override @property const(sockaddr
)* name() const { return null; }
1952 override @property socklen_t
nameLen() const { return 0; }
1956 static if (is(sockaddr_un
))
1958 class UnixAddress
: Address
1967 char unused
= '\0'; // placeholder for a terminating '\0'
1970 this() pure nothrow @nogc
1972 sun
.sun_family
= AddressFamily
.UNIX
;
1974 _nameLen
= sun
.sizeof
;
1977 override void setNameLen(socklen_t len
) @trusted
1979 if (len
> sun
.sizeof
)
1980 throw new SocketParameterException("Not enough socket address storage");
1985 override @property sockaddr
* name() return
1987 return cast(sockaddr
*)&sun
;
1990 override @property const(sockaddr
)* name() const return
1992 return cast(const(sockaddr
)*)&sun
;
1995 override @property socklen_t
nameLen() @trusted const
2000 this(scope const(char)[] path
) @trusted pure
2002 enforce(path
.length
<= sun
.sun_path
.sizeof
, new SocketParameterException("Path too long"));
2003 sun
.sun_family
= AddressFamily
.UNIX
;
2004 sun
.sun_path
.ptr
[0 .. path
.length
] = (cast(byte[]) path
)[];
2005 _nameLen
= cast(socklen_t
)
2007 auto len
= sockaddr_un
.init
.sun_path
.offsetof
+ path
.length
;
2008 // Pathname socket address must be terminated with '\0'
2009 // which must be included in the address length.
2010 if (sun
.sun_path
.ptr
[0])
2012 sun
.sun_path
.ptr
[path
.length
] = 0;
2019 this(sockaddr_un addr
) pure nothrow @nogc
2021 assert(addr
.sun_family
== AddressFamily
.UNIX
);
2025 @property string
path() @trusted const pure
2027 auto len
= _nameLen
- sockaddr_un
.init
.sun_path
.offsetof
;
2029 return null; // An empty path may be returned from getpeername
2030 // For pathname socket address we need to strip off the terminating '\0'
2031 if (sun
.sun_path
.ptr
[0])
2033 return (cast(const(char)*) sun
.sun_path
.ptr
)[0 .. len
].idup
;
2036 override string
toString() const pure
2044 import core
.stdc
.stdio
: remove
;
2046 version (iOSDerived
)
2048 // Slightly different version of `std.file.deleteme` to reduce the path
2049 // length on iOS derived platforms. Due to the sandbox, the length
2050 // of paths can quickly become too long.
2051 static string
deleteme()
2053 import std
.conv
: text
;
2054 import std
.process
: thisProcessID
;
2055 import std
.file
: tempDir
;
2057 return text(tempDir
, thisProcessID
);
2062 import std
.file
: deleteme
;
2064 immutable ubyte[] data
= [1, 2, 3, 4];
2067 const basePath
= deleteme
;
2068 auto names
= [ basePath
~ "-socket" ];
2070 names
~= "\0" ~ basePath
~ "-abstract\0unix\0socket";
2072 foreach (name
; names
)
2074 auto address
= new UnixAddress(name
);
2076 auto listener
= new Socket(AddressFamily
.UNIX
, SocketType
.STREAM
);
2077 scope(exit
) listener
.close();
2078 listener
.bind(address
);
2079 scope(exit
) () @trusted { if (name
[0]) remove(name
.tempCString()); } ();
2080 assert(listener
.localAddress
.toString
== name
);
2084 pair
[0] = new Socket(AddressFamily
.UNIX
, SocketType
.STREAM
);
2085 scope(exit
) listener
.close();
2087 pair
[0].connect(address
);
2088 scope(exit
) pair
[0].close();
2090 pair
[1] = listener
.accept();
2091 scope(exit
) pair
[1].close();
2095 auto buf
= new ubyte[data
.length
];
2096 pair
[1].receive(buf
);
2097 assert(buf
== data
);
2099 // getpeername is free to return an empty name for a unix
2100 // domain socket pair or unbound socket. Let's confirm it
2101 // returns successfully and doesn't throw anything.
2102 // See https://issues.dlang.org/show_bug.cgi?id=20544
2103 assertNotThrown(pair
[1].remoteAddress().toString());
2110 * Exception thrown by `Socket.accept`.
2112 class SocketAcceptException
: SocketOSException
2114 mixin socketOSExceptionCtors
;
2117 /// How a socket is shutdown:
2118 enum SocketShutdown
: int
2120 RECEIVE
= SD_RECEIVE
, /// socket receives are disallowed
2121 SEND
= SD_SEND
, /// socket sends are disallowed
2122 BOTH
= SD_BOTH
, /// both RECEIVE and SEND
2126 /// Socket flags that may be OR'ed together:
2127 enum SocketFlags
: int
2129 NONE
= 0, /// no flags specified
2131 OOB
= MSG_OOB
, /// out-of-band stream data
2132 PEEK
= MSG_PEEK
, /// peek at incoming data without removing it from the queue, only for receiving
2133 DONTROUTE
= MSG_DONTROUTE
, /// data should not be subject to routing; this flag may be ignored. Only for sending
2137 /// Duration timeout value.
2141 alias tv_sec_t
= typeof(ctimeval
.tv_sec
);
2142 alias tv_usec_t
= typeof(ctimeval
.tv_usec
);
2144 /// Number of _seconds.
2145 pure nothrow @nogc @property
2146 ref inout(tv_sec_t
) seconds() inout return
2148 return ctimeval
.tv_sec
;
2151 /// Number of additional _microseconds.
2152 pure nothrow @nogc @property
2153 ref inout(tv_usec_t
) microseconds() inout return
2155 return ctimeval
.tv_usec
;
2161 * A collection of sockets for use with `Socket.select`.
2163 * `SocketSet` wraps the platform `fd_set` type. However, unlike
2164 * `fd_set`, `SocketSet` is not statically limited to `FD_SETSIZE`
2165 * or any other limit, and grows as needed.
2172 // On Windows, fd_set is an array of socket handles,
2173 // following a word containing the fd_set instance size.
2174 // We use one dynamic array for everything, and use its first
2175 // element(s) for the count.
2177 alias fd_set_count_type
= typeof(fd_set
.init
.fd_count
);
2178 alias fd_set_type
= typeof(fd_set
.init
.fd_array
[0]);
2179 static assert(fd_set_type
.sizeof
== socket_t
.sizeof
);
2181 // Number of fd_set_type elements at the start of our array that are
2182 // used for the socket count and alignment
2184 enum FD_SET_OFFSET
= fd_set
.fd_array
.offsetof
/ fd_set_type
.sizeof
;
2185 static assert(FD_SET_OFFSET
);
2186 static assert(fd_set
.fd_count
.offsetof
% fd_set_type
.sizeof
== 0);
2190 void resize(size_t size
) pure nothrow
2192 set
.length
= FD_SET_OFFSET
+ size
;
2195 ref inout(fd_set_count_type
) count() @trusted @property inout pure nothrow @nogc
2198 return *cast(inout(fd_set_count_type
)*)set
.ptr
;
2201 size_t
capacity() @property const pure nothrow @nogc
2203 return set
.length
- FD_SET_OFFSET
;
2206 inout(socket_t
)[] fds() @trusted inout @property pure nothrow @nogc
2208 return cast(inout(socket_t
)[])set
[FD_SET_OFFSET
.. FD_SET_OFFSET
+count
];
2214 // On Posix, fd_set is a bit array. We assume that the fd_set
2215 // type (declared in core.sys.posix.sys.select) is a structure
2216 // containing a single field, a static array.
2218 static assert(fd_set
.tupleof
.length
== 1);
2220 // This is the type used in the fd_set array.
2221 // Using the type of the correct size is important for big-endian
2224 alias fd_set_type
= typeof(fd_set
.init
.tupleof
[0][0]);
2226 // Number of file descriptors represented by one fd_set_type
2228 enum FD_NFDBITS
= 8 * fd_set_type
.sizeof
;
2230 static fd_set_type
mask(uint n
) pure nothrow @nogc
2232 return (cast(fd_set_type
) 1) << (n
% FD_NFDBITS
);
2235 // Array size to fit that many sockets
2237 static size_t
lengthFor(size_t size
) pure nothrow @nogc
2239 return (size
+ (FD_NFDBITS
-1)) / FD_NFDBITS
;
2244 void resize(size_t size
) pure nothrow
2246 set
.length
= lengthFor(size
);
2249 // Make sure we can fit that many sockets
2251 void setMinCapacity(size_t size
) pure nothrow
2253 auto length
= lengthFor(size
);
2254 if (set
.length
< length
)
2255 set
.length
= length
;
2258 size_t
capacity() @property const pure nothrow @nogc
2260 return set
.length
* FD_NFDBITS
;
2266 static assert(false, "Unknown platform");
2271 * Create a SocketSet with a specific initial capacity (defaults to
2272 * `FD_SETSIZE`, the system's default capacity).
2274 this(size_t size
= FD_SETSIZE
) pure nothrow
2280 /// Reset the `SocketSet` so that there are 0 `Socket`s in the collection.
2281 void reset() pure nothrow @nogc
2293 void add(socket_t s
) @trusted pure nothrow
2297 if (count
== capacity
)
2300 set
.length
= set
.capacity
;
2307 auto index
= s
/ FD_NFDBITS
;
2308 auto length
= set
.length
;
2309 if (index
>= length
)
2311 while (index
>= length
)
2313 set
.length
= length
;
2314 set
.length
= set
.capacity
;
2316 set
[index
] |
= mask(s
);
2323 * Add a `Socket` to the collection.
2324 * The socket must not already be in the collection.
2326 void add(Socket s
) pure nothrow
2331 void remove(socket_t s
) pure nothrow
2335 import std
.algorithm
.searching
: countUntil
;
2337 auto p
= fds
.countUntil(s
);
2339 fds
[p
] = fds
[--count
];
2343 auto index
= s
/ FD_NFDBITS
;
2344 if (index
>= set
.length
)
2346 set
[index
] &= ~mask(s
);
2347 // note: adjusting maxfd would require scanning the set, not worth it
2353 * Remove this `Socket` from the collection.
2354 * Does nothing if the socket is not in the collection already.
2356 void remove(Socket s
) pure nothrow
2361 int isSet(socket_t s
) const pure nothrow @nogc
2365 import std
.algorithm
.searching
: canFind
;
2366 return fds
.canFind(s
) ?
1 : 0;
2372 auto index
= s
/ FD_NFDBITS
;
2373 return (set
[index
] & mask(s
)) ?
1 : 0;
2378 /// Return nonzero if this `Socket` is in the collection.
2379 int isSet(Socket s
) const pure nothrow @nogc
2381 return isSet(s
.sock
);
2387 * The current capacity of this `SocketSet`. The exact
2388 * meaning of the return value varies from platform to platform.
2391 * Since D 2.065, this value does not indicate a
2392 * restriction, and `SocketSet` will grow its capacity as
2393 * needed automatically.
2395 @property uint max() const pure nothrow @nogc
2397 return cast(uint) capacity
;
2401 fd_set
* toFd_set() @trusted pure nothrow @nogc
2403 return cast(fd_set
*) set
.ptr
;
2407 int selectn() const pure nothrow @nogc
2413 else version (Posix
)
2422 auto fds
= cast(socket_t
[])
2423 [cast(socket_t
) 1, 2, 0, 1024, 17, 42, 1234, 77, 77+32, 77+64];
2424 auto set
= new SocketSet();
2425 foreach (fd
; fds
) assert(!set
.isSet(fd
));
2426 foreach (fd
; fds
) set
.add(fd
);
2427 foreach (fd
; fds
) assert(set
.isSet(fd
));
2429 // Make sure SocketSet reimplements fd_set correctly
2430 auto fdset
= set
.toFd_set();
2431 foreach (fd
; fds
[0]..cast(socket_t
)(fds
[$-1]+1))
2432 assert(cast(bool) set
.isSet(fd
) == cast(bool)(() @trusted => FD_ISSET(fd
, fdset
))());
2436 assert(set
.isSet(fd
));
2438 assert(!set
.isSet(fd
));
2444 version (iOSDerived
)
2459 static assert(LIMIT
> PAIRS
*2);
2460 import core
.sys
.posix
.sys
.resource
;
2462 getrlimit(RLIMIT_NOFILE
, &fileLimit
);
2463 assert(fileLimit
.rlim_max
> LIMIT
, "Open file hard limit too low");
2464 fileLimit
.rlim_cur
= LIMIT
;
2465 setrlimit(RLIMIT_NOFILE
, &fileLimit
);
2468 Socket
[2][PAIRS
] pairs
;
2469 foreach (ref pair
; pairs
)
2470 pair
= socketPair();
2473 foreach (pair
; pairs
)
2481 auto rng
= Xorshift(42);
2482 pairs
[].randomShuffle(rng
);
2484 auto readSet
= new SocketSet();
2485 auto writeSet
= new SocketSet();
2486 auto errorSet
= new SocketSet();
2488 foreach (testPair
; pairs
)
2495 foreach (ref pair
; pairs
)
2505 auto n
= Socket
.select(readSet
, writeSet
, errorSet
);
2506 assert(n
== PAIRS
*2); // All in writeSet
2507 assert(writeSet
.isSet(testPair
[0]));
2508 assert(writeSet
.isSet(testPair
[1]));
2509 assert(!readSet
.isSet(testPair
[0]));
2510 assert(!readSet
.isSet(testPair
[1]));
2511 assert(!errorSet
.isSet(testPair
[0]));
2512 assert(!errorSet
.isSet(testPair
[1]));
2515 // Socket.send can't be marked with `scope`
2516 // -> @safe DIP1000 code can't use it - see https://github.com/dlang/phobos/pull/6204
2518 testPair
[0].send(b
[]);
2521 n
= Socket
.select(readSet
, null, null);
2522 assert(n
== 1); // testPair[1]
2523 assert(readSet
.isSet(testPair
[1]));
2524 assert(!readSet
.isSet(testPair
[0]));
2525 // Socket.receive can't be marked with `scope`
2526 // -> @safe DIP1000 code can't use it - see https://github.com/dlang/phobos/pull/6204
2528 testPair
[1].receive(b
[]);
2534 // https://issues.dlang.org/show_bug.cgi?id=14012
2535 // https://issues.dlang.org/show_bug.cgi?id=14013
2538 auto set
= new SocketSet(1);
2539 assert(set
.max
>= 0);
2542 foreach (n
; 0 .. LIMIT
)
2543 set
.add(cast(socket_t
) n
);
2544 assert(set
.max
>= LIMIT
);
2547 /// The level at which a socket option is defined:
2548 enum SocketOptionLevel
: int
2550 SOCKET
= SOL_SOCKET
, /// Socket level
2551 IP
= ProtocolType
.IP
, /// Internet Protocol version 4 level
2552 ICMP
= ProtocolType
.ICMP
, /// Internet Control Message Protocol level
2553 IGMP
= ProtocolType
.IGMP
, /// Internet Group Management Protocol level
2554 GGP
= ProtocolType
.GGP
, /// Gateway to Gateway Protocol level
2555 TCP
= ProtocolType
.TCP
, /// Transmission Control Protocol level
2556 PUP
= ProtocolType
.PUP
, /// PARC Universal Packet Protocol level
2557 UDP
= ProtocolType
.UDP
, /// User Datagram Protocol level
2558 IDP
= ProtocolType
.IDP
, /// Xerox NS protocol level
2559 RAW
= ProtocolType
.RAW
, /// Raw IP packet level
2560 IPV6
= ProtocolType
.IPV6
, /// Internet Protocol version 6 level
2563 /// _Linger information for use with SocketOption.LINGER.
2568 private alias l_onoff_t
= typeof(_clinger
.init
.l_onoff
);
2569 private alias l_linger_t
= typeof(_clinger
.init
.l_linger
);
2571 /// Nonzero for _on.
2572 pure nothrow @nogc @property
2573 ref inout(l_onoff_t
) on() inout return
2575 return clinger
.l_onoff
;
2579 pure nothrow @nogc @property
2580 ref inout(l_linger_t
) time() inout return
2582 return clinger
.l_linger
;
2586 /// Specifies a socket option:
2587 enum SocketOption
: int
2589 DEBUG
= SO_DEBUG
, /// Record debugging information
2590 BROADCAST
= SO_BROADCAST
, /// Allow transmission of broadcast messages
2591 REUSEADDR
= SO_REUSEADDR
, /// Allow local reuse of address
2592 LINGER
= SO_LINGER
, /// Linger on close if unsent data is present
2593 OOBINLINE
= SO_OOBINLINE
, /// Receive out-of-band data in band
2594 SNDBUF
= SO_SNDBUF
, /// Send buffer size
2595 RCVBUF
= SO_RCVBUF
, /// Receive buffer size
2596 DONTROUTE
= SO_DONTROUTE
, /// Do not route
2597 SNDTIMEO
= SO_SNDTIMEO
, /// Send timeout
2598 RCVTIMEO
= SO_RCVTIMEO
, /// Receive timeout
2599 ERROR
= SO_ERROR
, /// Retrieve and clear error status
2600 KEEPALIVE
= SO_KEEPALIVE
, /// Enable keep-alive packets
2601 ACCEPTCONN
= SO_ACCEPTCONN
, /// Listen
2602 RCVLOWAT
= SO_RCVLOWAT
, /// Minimum number of input bytes to process
2603 SNDLOWAT
= SO_SNDLOWAT
, /// Minimum number of output bytes to process
2604 TYPE
= SO_TYPE
, /// Socket type
2606 // SocketOptionLevel.TCP:
2607 TCP_NODELAY
= .TCP_NODELAY
, /// Disable the Nagle algorithm for send coalescing
2609 // SocketOptionLevel.IPV6:
2610 IPV6_UNICAST_HOPS
= .IPV6_UNICAST_HOPS
, /// IP unicast hop limit
2611 IPV6_MULTICAST_IF
= .IPV6_MULTICAST_IF
, /// IP multicast interface
2612 IPV6_MULTICAST_LOOP
= .IPV6_MULTICAST_LOOP
, /// IP multicast loopback
2613 IPV6_MULTICAST_HOPS
= .IPV6_MULTICAST_HOPS
, /// IP multicast hops
2614 IPV6_JOIN_GROUP
= .IPV6_JOIN_GROUP
, /// Add an IP group membership
2615 IPV6_LEAVE_GROUP
= .IPV6_LEAVE_GROUP
, /// Drop an IP group membership
2616 IPV6_V6ONLY
= .IPV6_V6ONLY
, /// Treat wildcard bind as AF_INET6-only
2621 * Class that creates a network communication endpoint using
2622 * the Berkeley sockets interface.
2628 AddressFamily _family
;
2631 bool _blocking
= true; /// Property to get or set whether the socket is blocking or nonblocking.
2633 // The WinSock timeouts seem to be effectively skewed by a constant
2634 // offset of about half a second (value in milliseconds). This has
2635 // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7
2636 // and Windows Server 2008 R2 boxes. The unittest below tests this
2638 enum WINSOCK_TIMEOUT_SKEW
= 500;
2644 import std
.datetime
.stopwatch
: StopWatch
;
2645 import std
.typecons
: Yes
;
2648 auto pair
= socketPair();
2649 auto testSock
= pair
[0];
2650 testSock
.setOption(SocketOptionLevel
.SOCKET
,
2651 SocketOption
.RCVTIMEO
, dur
!"msecs"(msecs
));
2653 auto sw
= StopWatch(Yes
.autoStart
);
2655 testSock
.receive(buf
);
2658 Duration readBack
= void;
2659 testSock
.getOption(SocketOptionLevel
.SOCKET
, SocketOption
.RCVTIMEO
, readBack
);
2661 assert(readBack
.total
!"msecs" == msecs
);
2662 assert(sw
.peek().total
!"msecs" > msecs
- 100 && sw
.peek().total
!"msecs" < msecs
+ 100);
2666 void setSock(socket_t handle
)
2668 assert(handle
!= socket_t
.init
);
2671 // Set the option to disable SIGPIPE on send() if the platform
2672 // has it (e.g. on OS X).
2673 static if (is(typeof(SO_NOSIGPIPE
)))
2675 setOption(SocketOptionLevel
.SOCKET
, cast(SocketOption
) SO_NOSIGPIPE
, true);
2680 // For use with accepting().
2681 protected this() pure nothrow @nogc
2689 * Create a blocking socket. If a single protocol type exists to support
2690 * this socket type within the address family, the `ProtocolType` may be
2693 this(AddressFamily af
, SocketType type
, ProtocolType protocol
) @trusted
2696 auto handle
= cast(socket_t
) socket(af
, type
, protocol
);
2697 if (handle
== socket_t
.init
)
2698 throw new SocketOSException("Unable to create socket");
2703 this(AddressFamily af
, SocketType type
)
2705 /* A single protocol exists to support this socket type within the
2706 * protocol family, so the ProtocolType is assumed.
2708 this(af
, type
, cast(ProtocolType
) 0); // Pseudo protocol number.
2713 this(AddressFamily af
, SocketType type
, scope const(char)[] protocolName
) @trusted
2716 proto
= getprotobyname(protocolName
.tempCString());
2718 throw new SocketOSException("Unable to find the protocol");
2719 this(af
, type
, cast(ProtocolType
) proto
.p_proto
);
2724 * Create a blocking socket using the parameters from the specified
2725 * `AddressInfo` structure.
2727 this(const scope AddressInfo info
)
2729 this(info
.family
, info
.type
, info
.protocol
);
2732 /// Use an existing socket handle.
2733 this(socket_t sock
, AddressFamily af
) pure nothrow @nogc
2735 assert(sock
!= socket_t
.init
);
2741 ~this() nothrow @nogc
2747 /// Get underlying socket handle.
2748 @property socket_t
handle() const pure nothrow @nogc
2754 * Releases the underlying socket handle from the Socket object. Once it
2755 * is released, you cannot use the Socket object's methods anymore. This
2756 * also means the Socket destructor will no longer close the socket - it
2757 * becomes your responsibility.
2759 * To get the handle without releasing it, use the `handle` property.
2761 @property socket_t
release() pure nothrow @nogc
2764 this.sock
= socket_t
.init
;
2769 * Get/set socket's blocking flag.
2771 * When a socket is blocking, calls to receive(), accept(), and send()
2772 * will block and wait for data/action.
2773 * A non-blocking socket will immediately return instead of blocking.
2775 @property bool blocking() @trusted const nothrow @nogc
2781 else version (Posix
)
2783 return !(fcntl(handle
, F_GETFL
, 0) & O_NONBLOCK
);
2788 @property void blocking(bool byes
) @trusted
2793 if (_SOCKET_ERROR
== ioctlsocket(sock
, FIONBIO
, &num
))
2797 else version (Posix
)
2799 int x
= fcntl(sock
, F_GETFL
, 0);
2806 if (-1 == fcntl(sock
, F_SETFL
, x
))
2812 throw new SocketOSException("Unable to set socket blocking");
2816 /// Get the socket's address family.
2817 @property AddressFamily
addressFamily()
2822 /// Property that indicates if this is a valid, alive socket.
2823 @property bool isAlive() @trusted const
2826 socklen_t typesize
= cast(socklen_t
) type
.sizeof
;
2827 return !getsockopt(sock
, SOL_SOCKET
, SO_TYPE
, cast(char*)&type
, &typesize
);
2831 * Associate a local address with this socket.
2834 * addr = The $(LREF Address) to associate this socket with.
2836 * Throws: $(LREF SocketOSException) when unable to bind the socket.
2838 void bind(Address addr
) @trusted
2840 if (_SOCKET_ERROR
== .bind(sock
, addr
.name
, addr
.nameLen
))
2841 throw new SocketOSException("Unable to bind socket");
2845 * Establish a connection. If the socket is blocking, connect waits for
2846 * the connection to be made. If the socket is nonblocking, connect
2847 * returns immediately and the connection attempt is still in progress.
2849 void connect(Address to
) @trusted
2851 if (_SOCKET_ERROR
== .connect(sock
, to
.name
, to
.nameLen
))
2860 if (WSAEWOULDBLOCK
== err
)
2863 else version (Posix
)
2865 if (EINPROGRESS
== err
)
2873 throw new SocketOSException("Unable to connect socket", err
);
2878 * Listen for an incoming connection. `bind` must be called before you
2879 * can `listen`. The `backlog` is a request of how many pending
2880 * incoming connections are queued until `accept`ed.
2882 void listen(int backlog
) @trusted
2884 if (_SOCKET_ERROR
== .listen(sock
, backlog
))
2885 throw new SocketOSException("Unable to listen on socket");
2889 * Called by `accept` when a new `Socket` must be created for a new
2890 * connection. To use a derived class, override this method and return an
2891 * instance of your class. The returned `Socket`'s handle must not be
2892 * set; `Socket` has a protected constructor `this()` to use in this
2895 * Override to use a derived class.
2896 * The returned socket's handle must not be set.
2898 protected Socket
accepting() pure nothrow
2904 * Accept an incoming connection. If the socket is blocking, `accept`
2905 * waits for a connection request. Throws `SocketAcceptException` if
2906 * unable to _accept. See `accepting` for use with derived classes.
2908 Socket
accept() @trusted
2910 auto newsock
= cast(socket_t
).accept(sock
, null, null);
2911 if (socket_t
.init
== newsock
)
2912 throw new SocketAcceptException("Unable to accept socket connection");
2917 newSocket
= accepting();
2918 assert(newSocket
.sock
== socket_t
.init
);
2920 newSocket
.setSock(newsock
);
2922 newSocket
._blocking
= _blocking
; //inherits blocking mode
2923 newSocket
._family
= _family
; //same family
2934 /// Disables sends and/or receives.
2935 void shutdown(SocketShutdown how
) @trusted nothrow @nogc
2937 .shutdown(sock
, cast(int) how
);
2941 private static void _close(socket_t sock
) @system nothrow @nogc
2947 else version (Posix
)
2955 * Immediately drop any connections and release socket resources.
2956 * The `Socket` object is no longer usable after `close`.
2957 * Calling `shutdown` before `close` is recommended
2958 * for connection-oriented sockets.
2960 void close() scope @trusted nothrow @nogc
2963 sock
= socket_t
.init
;
2968 * Returns: The local machine's host name
2970 static @property string
hostName() @trusted // getter
2972 char[256] result
; // Host names are limited to 255 chars.
2973 if (_SOCKET_ERROR
== .gethostname(result
.ptr
, result
.length
))
2974 throw new SocketOSException("Unable to obtain host name");
2975 return to
!string(result
.ptr
);
2978 /// Remote endpoint `Address`.
2979 @property Address
remoteAddress() @trusted
2981 Address addr
= createAddress();
2982 socklen_t nameLen
= addr
.nameLen
;
2983 if (_SOCKET_ERROR
== .getpeername(sock
, addr
.name
, &nameLen
))
2984 throw new SocketOSException("Unable to obtain remote socket address");
2985 addr
.setNameLen(nameLen
);
2986 assert(addr
.addressFamily
== _family
);
2990 /// Local endpoint `Address`.
2991 @property Address
localAddress() @trusted
2993 Address addr
= createAddress();
2994 socklen_t nameLen
= addr
.nameLen
;
2995 if (_SOCKET_ERROR
== .getsockname(sock
, addr
.name
, &nameLen
))
2996 throw new SocketOSException("Unable to obtain local socket address");
2997 addr
.setNameLen(nameLen
);
2998 assert(addr
.addressFamily
== _family
);
3003 * Send or receive error code. See `wouldHaveBlocked`,
3004 * `lastSocketError` and `Socket.getErrorText` for obtaining more
3005 * information about the error.
3007 enum int ERROR
= _SOCKET_ERROR
;
3009 private static int capToInt(size_t size
) nothrow @nogc
3011 // Windows uses int instead of size_t for length arguments.
3012 // Luckily, the send/recv functions make no guarantee that
3013 // all the data is sent, so we use that to send at most
3015 return size
> size_t(int.max
) ?
int.max
: cast(int) size
;
3019 * Send data on the connection. If the socket is blocking and there is no
3020 * buffer space left, `send` waits.
3021 * Returns: The number of bytes actually sent, or `Socket.ERROR` on
3024 ptrdiff_t
send(scope const(void)[] buf
, SocketFlags flags
) @trusted
3026 static if (is(typeof(MSG_NOSIGNAL
)))
3028 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3031 auto sent
= .send(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
);
3033 auto sent
= .send(sock
, buf
.ptr
, buf
.length
, cast(int) flags
);
3038 ptrdiff_t
send(scope const(void)[] buf
)
3040 return send(buf
, SocketFlags
.NONE
);
3044 * Send data to a specific destination Address. If the destination address is
3045 * not specified, a connection must have been made and that address is used.
3046 * If the socket is blocking and there is no buffer space left, `sendTo` waits.
3047 * Returns: The number of bytes actually sent, or `Socket.ERROR` on
3050 ptrdiff_t
sendTo(scope const(void)[] buf
, SocketFlags flags
, Address to
) @trusted
3052 static if (is(typeof(MSG_NOSIGNAL
)))
3054 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3058 sock
, buf
.ptr
, capToInt(buf
.length
),
3059 cast(int) flags
, to
.name
, to
.nameLen
3062 return .sendto(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, to
.name
, to
.nameLen
);
3066 ptrdiff_t
sendTo(scope const(void)[] buf
, Address to
)
3068 return sendTo(buf
, SocketFlags
.NONE
, to
);
3072 //assumes you connect()ed
3074 ptrdiff_t
sendTo(scope const(void)[] buf
, SocketFlags flags
) @trusted
3076 static if (is(typeof(MSG_NOSIGNAL
)))
3078 flags
= cast(SocketFlags
)(flags | MSG_NOSIGNAL
);
3081 return .sendto(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, null, 0);
3083 return .sendto(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, null, 0);
3087 //assumes you connect()ed
3089 ptrdiff_t
sendTo(scope const(void)[] buf
)
3091 return sendTo(buf
, SocketFlags
.NONE
);
3096 * Receive data on the connection. If the socket is blocking, `receive`
3097 * waits until there is data to be received.
3098 * Returns: The number of bytes actually received, `0` if the remote side
3099 * has closed the connection, or `Socket.ERROR` on failure.
3101 ptrdiff_t
receive(scope void[] buf
, SocketFlags flags
) @trusted
3103 version (Windows
) // Does not use size_t
3106 ?
.recv(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
)
3112 ?
.recv(sock
, buf
.ptr
, buf
.length
, cast(int) flags
)
3118 ptrdiff_t
receive(scope void[] buf
)
3120 return receive(buf
, SocketFlags
.NONE
);
3124 * Receive data and get the remote endpoint `Address`.
3125 * If the socket is blocking, `receiveFrom` waits until there is data to
3127 * Returns: The number of bytes actually received, `0` if the remote side
3128 * has closed the connection, or `Socket.ERROR` on failure.
3130 ptrdiff_t
receiveFrom(scope void[] buf
, SocketFlags flags
, ref Address from
) @trusted
3132 if (!buf
.length
) //return 0 and don't think the connection closed
3134 if (from
is null || from
.addressFamily
!= _family
)
3135 from
= createAddress();
3136 socklen_t nameLen
= from
.nameLen
;
3138 auto read
= .recvfrom(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, from
.name
, &nameLen
);
3141 auto read
= .recvfrom(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, from
.name
, &nameLen
);
3145 from
.setNameLen(nameLen
);
3146 assert(from
.addressFamily
== _family
);
3153 ptrdiff_t
receiveFrom(scope void[] buf
, ref Address from
)
3155 return receiveFrom(buf
, SocketFlags
.NONE
, from
);
3159 //assumes you connect()ed
3161 ptrdiff_t
receiveFrom(scope void[] buf
, SocketFlags flags
) @trusted
3163 if (!buf
.length
) //return 0 and don't think the connection closed
3167 auto read
= .recvfrom(sock
, buf
.ptr
, capToInt(buf
.length
), cast(int) flags
, null, null);
3168 // if (!read) //connection closed
3173 auto read
= .recvfrom(sock
, buf
.ptr
, buf
.length
, cast(int) flags
, null, null);
3174 // if (!read) //connection closed
3180 //assumes you connect()ed
3182 ptrdiff_t
receiveFrom(scope void[] buf
)
3184 return receiveFrom(buf
, SocketFlags
.NONE
);
3189 * Get a socket option.
3190 * Returns: The number of bytes written to `result`.
3191 * The length, in bytes, of the actual result - very different from getsockopt()
3193 int getOption(SocketOptionLevel level
, SocketOption option
, scope void[] result
) @trusted
3195 socklen_t len
= cast(socklen_t
) result
.length
;
3196 if (_SOCKET_ERROR
== .getsockopt(sock
, cast(int) level
, cast(int) option
, result
.ptr
, &len
))
3197 throw new SocketOSException("Unable to get socket option");
3202 /// Common case of getting integer and boolean options.
3203 int getOption(SocketOptionLevel level
, SocketOption option
, out int32_t result
) @trusted
3205 return getOption(level
, option
, (&result
)[0 .. 1]);
3209 /// Get the linger option.
3210 int getOption(SocketOptionLevel level
, SocketOption option
, out Linger result
) @trusted
3212 //return getOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
3213 return getOption(level
, option
, (&result
.clinger
)[0 .. 1]);
3216 /// Get a timeout (duration) option.
3217 void getOption(SocketOptionLevel level
, SocketOption option
, out Duration result
) @trusted
3219 enforce(option
== SocketOption
.SNDTIMEO || option
== SocketOption
.RCVTIMEO
,
3220 new SocketParameterException("Not a valid timeout option: " ~ to
!string(option
)));
3221 // WinSock returns the timeout values as a milliseconds DWORD,
3222 // while Linux and BSD return a timeval struct.
3226 getOption(level
, option
, (&msecs
)[0 .. 1]);
3227 if (option
== SocketOption
.RCVTIMEO
)
3228 msecs
+= WINSOCK_TIMEOUT_SKEW
;
3229 result
= dur
!"msecs"(msecs
);
3231 else version (Posix
)
3234 getOption(level
, option
, (&tv
.ctimeval
)[0 .. 1]);
3235 result
= dur
!"seconds"(tv
.seconds
) + dur
!"usecs"(tv
.microseconds
);
3237 else static assert(false);
3240 /// Set a socket option.
3241 void setOption(SocketOptionLevel level
, SocketOption option
, scope void[] value
) @trusted
3243 if (_SOCKET_ERROR
== .setsockopt(sock
, cast(int) level
,
3244 cast(int) option
, value
.ptr
, cast(uint) value
.length
))
3245 throw new SocketOSException("Unable to set socket option");
3249 /// Common case for setting integer and boolean options.
3250 void setOption(SocketOptionLevel level
, SocketOption option
, int32_t value
) @trusted
3252 setOption(level
, option
, (&value
)[0 .. 1]);
3256 /// Set the linger option.
3257 void setOption(SocketOptionLevel level
, SocketOption option
, Linger value
) @trusted
3259 //setOption(cast(SocketOptionLevel) SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
3260 setOption(level
, option
, (&value
.clinger
)[0 .. 1]);
3264 * Sets a timeout (duration) option, i.e. `SocketOption.SNDTIMEO` or
3265 * `RCVTIMEO`. Zero indicates no timeout.
3267 * In a typical application, you might also want to consider using
3268 * a non-blocking socket instead of setting a timeout on a blocking one.
3270 * Note: While the receive timeout setting is generally quite accurate
3271 * on *nix systems even for smaller durations, there are two issues to
3272 * be aware of on Windows: First, although undocumented, the effective
3273 * timeout duration seems to be the one set on the socket plus half
3274 * a second. `setOption()` tries to compensate for that, but still,
3275 * timeouts under 500ms are not possible on Windows. Second, be aware
3276 * that the actual amount of time spent until a blocking call returns
3277 * randomly varies on the order of 10ms.
3280 * level = The level at which a socket option is defined.
3281 * option = Either `SocketOption.SNDTIMEO` or `SocketOption.RCVTIMEO`.
3282 * value = The timeout duration to set. Must not be negative.
3284 * Throws: `SocketException` if setting the options fails.
3288 * import std.datetime;
3289 * import std.typecons;
3290 * auto pair = socketPair();
3291 * scope(exit) foreach (s; pair) s.close();
3293 * // Set a receive timeout, and then wait at one end of
3294 * // the socket pair, knowing that no data will arrive.
3295 * pair[0].setOption(SocketOptionLevel.SOCKET,
3296 * SocketOption.RCVTIMEO, dur!"seconds"(1));
3298 * auto sw = StopWatch(Yes.autoStart);
3300 * pair[0].receive(buffer);
3301 * writefln("Waited %s ms until the socket timed out.",
3305 void setOption(SocketOptionLevel level
, SocketOption option
, Duration value
) @trusted
3307 enforce(option
== SocketOption
.SNDTIMEO || option
== SocketOption
.RCVTIMEO
,
3308 new SocketParameterException("Not a valid timeout option: " ~ to
!string(option
)));
3310 enforce(value
>= dur
!"hnsecs"(0), new SocketParameterException(
3311 "Timeout duration must not be negative."));
3315 import std
.algorithm
.comparison
: max
;
3317 auto msecs
= to
!int(value
.total
!"msecs");
3318 if (msecs
!= 0 && option
== SocketOption
.RCVTIMEO
)
3319 msecs
= max(1, msecs
- WINSOCK_TIMEOUT_SKEW
);
3320 setOption(level
, option
, msecs
);
3322 else version (Posix
)
3325 value
.split
!("seconds", "usecs")(tv
.tv_sec
, tv
.tv_usec
);
3326 setOption(level
, option
, (&tv
)[0 .. 1]);
3328 else static assert(false);
3332 * Get a text description of this socket's error status, and clear the
3333 * socket's error status.
3335 string
getErrorText()
3338 getOption(SocketOptionLevel
.SOCKET
, SocketOption
.ERROR
, error
);
3339 return formatSocketError(error
);
3343 * Enables TCP keep-alive with the specified parameters.
3346 * time = Number of seconds with no activity until the first
3347 * keep-alive packet is sent.
3348 * interval = Number of seconds between when successive keep-alive
3349 * packets are sent if no acknowledgement is received.
3351 * Throws: `SocketOSException` if setting the options fails, or
3352 * `SocketFeatureException` if setting keep-alive parameters is
3353 * unsupported on the current platform.
3355 void setKeepAlive(int time
, int interval
) @trusted
3359 tcp_keepalive options
;
3361 options
.keepalivetime
= time
* 1000;
3362 options
.keepaliveinterval
= interval
* 1000;
3363 uint cbBytesReturned
;
3364 enforce(WSAIoctl(sock
, SIO_KEEPALIVE_VALS
,
3365 &options
, options
.sizeof
,
3367 &cbBytesReturned
, null, null) == 0,
3368 new SocketOSException("Error setting keep-alive"));
3371 static if (is(typeof(TCP_KEEPIDLE
)) && is(typeof(TCP_KEEPINTVL
)))
3373 setOption(SocketOptionLevel
.TCP
, cast(SocketOption
) TCP_KEEPIDLE
, time
);
3374 setOption(SocketOptionLevel
.TCP
, cast(SocketOption
) TCP_KEEPINTVL
, interval
);
3375 setOption(SocketOptionLevel
.SOCKET
, SocketOption
.KEEPALIVE
, true);
3378 throw new SocketFeatureException("Setting keep-alive options " ~
3379 "is not supported on this platform");
3383 * Wait for a socket to change status. A wait timeout of $(REF Duration, core, time) or
3384 * `TimeVal`, may be specified; if a timeout is not specified or the
3385 * `TimeVal` is `null`, the maximum timeout is used. The `TimeVal`
3386 * timeout has an unspecified value when `select` returns.
3387 * Returns: The number of sockets with status changes, `0` on timeout,
3388 * or `-1` on interruption. If the return value is greater than `0`,
3389 * the `SocketSets` are updated to only contain the sockets having status
3390 * changes. For a connecting socket, a write status change means the
3391 * connection is established and it's able to send. For a listening socket,
3392 * a read status change means there is an incoming connection request and
3393 * it's able to accept.
3395 * `SocketSet`'s updated to include only those sockets which an event occured.
3396 * For a `connect()`ing socket, writeability means connected.
3397 * For a `listen()`ing socket, readability means listening
3398 * `Winsock`; possibly internally limited to 64 sockets per set.
3401 * the number of events, 0 on timeout, or -1 on interruption
3403 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
, Duration timeout
) @trusted
3405 auto vals
= timeout
.split
!("seconds", "usecs")();
3407 tv
.seconds
= cast(tv
.tv_sec_t
) vals
.seconds
;
3408 tv
.microseconds
= cast(tv
.tv_usec_t
) vals
.usecs
;
3409 return select(checkRead
, checkWrite
, checkError
, &tv
);
3414 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
)
3416 return select(checkRead
, checkWrite
, checkError
, null);
3420 static int select(SocketSet checkRead
, SocketSet checkWrite
, SocketSet checkError
, TimeVal
* timeout
) @trusted
3423 //make sure none of the SocketSet's are the same object
3426 assert(checkRead
!is checkWrite
);
3427 assert(checkRead
!is checkError
);
3431 assert(checkWrite
!is checkError
);
3441 // Windows has a problem with empty fd_set`s that aren't null.
3442 fr
= checkRead
&& checkRead
.count ? checkRead
.toFd_set() : null;
3443 fw
= checkWrite
&& checkWrite
.count ? checkWrite
.toFd_set() : null;
3444 fe
= checkError
&& checkError
.count ? checkError
.toFd_set() : null;
3450 fr
= checkRead
.toFd_set();
3451 n
= checkRead
.selectn();
3460 fw
= checkWrite
.toFd_set();
3462 _n
= checkWrite
.selectn();
3473 fe
= checkError
.toFd_set();
3475 _n
= checkError
.selectn();
3484 // Make sure the sets' capacity matches, to avoid select reading
3485 // out of bounds just because one set was bigger than another
3486 if (checkRead
) checkRead
.setMinCapacity(n
);
3487 if (checkWrite
) checkWrite
.setMinCapacity(n
);
3488 if (checkError
) checkError
.setMinCapacity(n
);
3491 int result
= .select(n
, fr
, fw
, fe
, &timeout
.ctimeval
);
3495 if (_SOCKET_ERROR
== result
&& WSAGetLastError() == WSAEINTR
)
3498 else version (Posix
)
3500 if (_SOCKET_ERROR
== result
&& errno
== EINTR
)
3508 if (_SOCKET_ERROR
== result
)
3509 throw new SocketOSException("Socket select error");
3516 * Can be overridden to support other addresses.
3517 * Returns: A new `Address` object for the current address family.
3519 protected Address
createAddress() pure nothrow
3524 static if (is(sockaddr_un
))
3526 case AddressFamily
.UNIX
:
3527 result
= new UnixAddress
;
3531 case AddressFamily
.INET
:
3532 result
= new InternetAddress
;
3535 case AddressFamily
.INET6
:
3536 result
= new Internet6Address
;
3540 result
= new UnknownAddress
;
3548 /// Shortcut class for a TCP Socket.
3549 class TcpSocket
: Socket
3551 /// Constructs a blocking TCP Socket.
3552 this(AddressFamily family
)
3554 super(family
, SocketType
.STREAM
, ProtocolType
.TCP
);
3557 /// Constructs a blocking IPv4 TCP Socket.
3560 this(AddressFamily
.INET
);
3565 /// Constructs a blocking TCP Socket and connects to the given `Address`.
3566 this(Address connectTo
)
3568 this(connectTo
.addressFamily
);
3574 /// Shortcut class for a UDP Socket.
3575 class UdpSocket
: Socket
3577 /// Constructs a blocking UDP Socket.
3578 this(AddressFamily family
)
3580 super(family
, SocketType
.DGRAM
, ProtocolType
.UDP
);
3584 /// Constructs a blocking IPv4 UDP Socket.
3587 this(AddressFamily
.INET
);
3596 auto s
= new UdpSocket
;
3598 s
.bind(new InternetAddress(InternetAddress
.PORT_ANY
));
3599 s
.receiveFrom(buf
, addr
);
3602 // https://issues.dlang.org/show_bug.cgi?id=16514
3605 void checkAttributes(string attributes
)()
3607 mixin(attributes
~ q
{ void function() fun
= {};});
3611 class TestSocket
: Socket
3615 @property pure nothrow @nogc @safe socket_t
handle() const
3617 checkAttributes
!q
{pure nothrow @nogc @safe}; assert(0);
3619 @property nothrow @nogc @trusted bool blocking() const
3621 checkAttributes
!q
{nothrow @nogc @trusted}; assert(0);
3623 @property @trusted void blocking(bool byes
)
3625 checkAttributes
!q
{@trusted};
3627 @property @safe AddressFamily
addressFamily()
3629 checkAttributes
!q
{@safe}; assert(0);
3631 @property @trusted bool isAlive() const
3633 checkAttributes
!q
{@trusted}; assert(0);
3635 @trusted void bind(Address addr
)
3637 checkAttributes
!q
{@trusted};
3639 @trusted void connect(Address to
)
3641 checkAttributes
!q
{@trusted};
3643 @trusted void listen(int backlog
)
3645 checkAttributes
!q
{@trusted};
3647 protected pure nothrow @safe Socket
accepting()
3649 checkAttributes
!q
{pure nothrow @safe}; assert(0);
3651 @trusted Socket
accept()
3653 checkAttributes
!q
{@trusted}; assert(0);
3655 nothrow @nogc @trusted void shutdown(SocketShutdown how
)
3657 checkAttributes
!q
{nothrow @nogc @trusted};
3659 nothrow @nogc @trusted scope void close()
3661 checkAttributes
!q
{nothrow @nogc @trusted};
3663 @property @trusted Address
remoteAddress()
3665 checkAttributes
!q
{@trusted}; assert(0);
3667 @property @trusted Address
localAddress()
3669 checkAttributes
!q
{@trusted}; assert(0);
3671 @trusted ptrdiff_t
send(scope const(void)[] buf
, SocketFlags flags
)
3673 checkAttributes
!q
{@trusted}; assert(0);
3675 @safe ptrdiff_t
send(scope const(void)[] buf
)
3677 checkAttributes
!q
{@safe}; assert(0);
3679 @trusted ptrdiff_t
sendTo(scope const(void)[] buf
, SocketFlags flags
, Address to
)
3681 checkAttributes
!q
{@trusted}; assert(0);
3683 @safe ptrdiff_t
sendTo(scope const(void)[] buf
, Address to
)
3685 checkAttributes
!q
{@safe}; assert(0);
3687 @trusted ptrdiff_t
sendTo(scope const(void)[] buf
, SocketFlags flags
)
3689 checkAttributes
!q
{@trusted}; assert(0);
3691 @safe ptrdiff_t
sendTo(scope const(void)[] buf
)
3693 checkAttributes
!q
{@safe}; assert(0);
3695 @trusted ptrdiff_t
receive(scope void[] buf
, SocketFlags flags
)
3697 checkAttributes
!q
{@trusted}; assert(0);
3699 @safe ptrdiff_t
receive(scope void[] buf
)
3701 checkAttributes
!q
{@safe}; assert(0);
3703 @trusted ptrdiff_t
receiveFrom(scope void[] buf
, SocketFlags flags
, ref Address from
)
3705 checkAttributes
!q
{@trusted}; assert(0);
3707 @safe ptrdiff_t
receiveFrom(scope void[] buf
, ref Address from
)
3709 checkAttributes
!q
{@safe}; assert(0);
3711 @trusted ptrdiff_t
receiveFrom(scope void[] buf
, SocketFlags flags
)
3713 checkAttributes
!q
{@trusted}; assert(0);
3715 @safe ptrdiff_t
receiveFrom(scope void[] buf
)
3717 checkAttributes
!q
{@safe}; assert(0);
3719 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, scope void[] result
)
3721 checkAttributes
!q
{@trusted}; assert(0);
3723 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, out int32_t result
)
3725 checkAttributes
!q
{@trusted}; assert(0);
3727 @trusted int getOption(SocketOptionLevel level
, SocketOption option
, out Linger result
)
3729 checkAttributes
!q
{@trusted}; assert(0);
3731 @trusted void getOption(SocketOptionLevel level
, SocketOption option
, out Duration result
)
3733 checkAttributes
!q
{@trusted};
3735 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, scope void[] value
)
3737 checkAttributes
!q
{@trusted};
3739 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, int32_t value
)
3741 checkAttributes
!q
{@trusted};
3743 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, Linger value
)
3745 checkAttributes
!q
{@trusted};
3747 @trusted void setOption(SocketOptionLevel level
, SocketOption option
, Duration value
)
3749 checkAttributes
!q
{@trusted};
3751 @safe string
getErrorText()
3753 checkAttributes
!q
{@safe}; assert(0);
3755 @trusted void setKeepAlive(int time
, int interval
)
3757 checkAttributes
!q
{@trusted};
3759 protected pure nothrow @safe Address
createAddress()
3761 checkAttributes
!q
{pure nothrow @safe}; assert(0);
3768 * Creates a pair of connected sockets.
3770 * The two sockets are indistinguishable.
3772 * Throws: `SocketException` if creation of the sockets fails.
3774 Socket
[2] socketPair() @trusted
3779 if (socketpair(AF_UNIX
, SOCK_STREAM
, 0, socks
) == -1)
3780 throw new SocketOSException("Unable to create socket pair");
3782 Socket
toSocket(size_t id
)
3784 auto s
= new Socket
;
3785 s
.setSock(cast(socket_t
) socks
[id
]);
3786 s
._family
= AddressFamily
.UNIX
;
3790 return [toSocket(0), toSocket(1)];
3792 else version (Windows
)
3794 // We do not have socketpair() on Windows, just manually create a
3795 // pair of sockets connected over some localhost port.
3798 auto listener
= new TcpSocket();
3799 listener
.setOption(SocketOptionLevel
.SOCKET
, SocketOption
.REUSEADDR
, true);
3800 listener
.bind(new InternetAddress(INADDR_LOOPBACK
, InternetAddress
.PORT_ANY
));
3801 auto addr
= listener
.localAddress
;
3804 result
[0] = new TcpSocket(addr
);
3805 result
[1] = listener
.accept();
3811 static assert(false);
3817 immutable ubyte[4] data
= [1, 2, 3, 4];
3818 auto pair
= socketPair();
3819 scope(exit
) foreach (s
; pair
) s
.close();
3821 pair
[0].send(data
[]);
3823 auto buf
= new ubyte[data
.length
];
3824 pair
[1].receive(buf
);
3825 assert(buf
== data
);