/std/socket.d

http://github.com/jcd/phobos · D · 3276 lines · 2021 code · 414 blank · 841 comment · 255 complexity · 02a5746ae79a3ff545995366b2eb4268 MD5 · raw file

  1. // Written in the D programming language
  2. /*
  3. Copyright (C) 2004-2011 Christopher E. Miller
  4. Boost Software License - Version 1.0 - August 17th, 2003
  5. Permission is hereby granted, free of charge, to any person or organization
  6. obtaining a copy of the software and accompanying documentation covered by
  7. this license (the "Software") to use, reproduce, display, distribute,
  8. execute, and transmit the Software, and to prepare derivative works of the
  9. Software, and to permit third-parties to whom the Software is furnished to
  10. do so, all subject to the following:
  11. The copyright notices in the Software and this entire statement, including
  12. the above license grant, this restriction and the following disclaimer,
  13. must be included in all copies of the Software, in whole or in part, and
  14. all derivative works of the Software, unless such copies or derivative
  15. works are solely in the form of machine-executable object code generated by
  16. a source language processor.
  17. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  20. SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  21. FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  22. ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. DEALINGS IN THE SOFTWARE.
  24. socket.d 1.4
  25. Jan 2011
  26. Thanks to Benjamin Herr for his assistance.
  27. */
  28. /**
  29. * Example: See $(SAMPLESRC listener.d) and $(SAMPLESRC htmlget.d)
  30. * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
  31. * Authors: Christopher E. Miller, $(WEB klickverbot.at, David Nadlinger),
  32. * $(WEB thecybershadow.net, Vladimir Panteleev)
  33. * Source: $(PHOBOSSRC std/_socket.d)
  34. * Macros:
  35. * WIKI=Phobos/StdSocket
  36. */
  37. module std.socket;
  38. import core.stdc.stdint, std.string, std.c.string, std.c.stdlib, std.conv;
  39. import core.stdc.config;
  40. import core.time : dur, Duration;
  41. import std.algorithm : max;
  42. import std.exception : assumeUnique, enforce, collectException;
  43. version(Windows)
  44. {
  45. pragma (lib, "ws2_32.lib");
  46. pragma (lib, "wsock32.lib");
  47. private import std.c.windows.windows, std.c.windows.winsock, std.windows.syserror;
  48. private alias std.c.windows.winsock.timeval _ctimeval;
  49. private alias std.c.windows.winsock.linger _clinger;
  50. enum socket_t : SOCKET { INVALID_SOCKET }
  51. private const int _SOCKET_ERROR = SOCKET_ERROR;
  52. private int _lasterr()
  53. {
  54. return WSAGetLastError();
  55. }
  56. }
  57. else version(Posix)
  58. {
  59. version(linux)
  60. import std.c.linux.socket : AF_IPX, AF_APPLETALK, SOCK_RDM,
  61. IPPROTO_IGMP, IPPROTO_GGP, IPPROTO_PUP, IPPROTO_IDP,
  62. SD_RECEIVE, SD_SEND, SD_BOTH, MSG_NOSIGNAL, INADDR_NONE,
  63. TCP_KEEPIDLE, TCP_KEEPINTVL;
  64. else version(OSX)
  65. import std.c.osx.socket : AF_IPX, AF_APPLETALK, SOCK_RDM,
  66. IPPROTO_IGMP, IPPROTO_GGP, IPPROTO_PUP, IPPROTO_IDP,
  67. SD_RECEIVE, SD_SEND, SD_BOTH, INADDR_NONE;
  68. else version(FreeBSD)
  69. {
  70. import core.sys.posix.sys.socket;
  71. import core.sys.posix.sys.select;
  72. import std.c.freebsd.socket;
  73. private enum SD_RECEIVE = SHUT_RD;
  74. private enum SD_SEND = SHUT_WR;
  75. private enum SD_BOTH = SHUT_RDWR;
  76. }
  77. else
  78. static assert(false);
  79. import core.sys.posix.netdb;
  80. import core.sys.posix.sys.un : sockaddr_un;
  81. private import core.sys.posix.fcntl;
  82. private import core.sys.posix.unistd;
  83. private import core.sys.posix.arpa.inet;
  84. private import core.sys.posix.netinet.tcp;
  85. private import core.sys.posix.netinet.in_;
  86. private import core.sys.posix.sys.time;
  87. //private import core.sys.posix.sys.select;
  88. private import core.sys.posix.sys.socket;
  89. private alias core.sys.posix.sys.time.timeval _ctimeval;
  90. private alias core.sys.posix.sys.socket.linger _clinger;
  91. private import core.stdc.errno;
  92. enum socket_t : int32_t { init = -1 }
  93. private const int _SOCKET_ERROR = -1;
  94. private int _lasterr()
  95. {
  96. return errno;
  97. }
  98. }
  99. else
  100. {
  101. static assert(0); // No socket support yet.
  102. }
  103. version(unittest)
  104. {
  105. static assert(is(uint32_t == uint));
  106. static assert(is(uint16_t == ushort));
  107. private import std.stdio : writefln;
  108. // Print a message on exception instead of failing the unittest.
  109. private void softUnittest(void delegate() test, int line = __LINE__)
  110. {
  111. try
  112. test();
  113. catch (Throwable e)
  114. {
  115. writefln(" --- std.socket(%d) test fails depending on environment ---", line);
  116. writefln(" (%s)", e);
  117. }
  118. }
  119. }
  120. /// Base exception thrown by $(D std.socket).
  121. class SocketException: Exception
  122. {
  123. ///
  124. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  125. {
  126. super(msg, file, line, next);
  127. }
  128. ///
  129. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  130. {
  131. super(msg, next, file, line);
  132. }
  133. }
  134. // Needs to be public so that SocketOSException can be thrown outside of
  135. // std.socket (since it uses it as a default argument), but it probably doesn't
  136. // need to actually show up in the docs, since there's not really any public
  137. // need for it outside of being a default argument.
  138. string formatSocketError(int err)
  139. {
  140. version(Posix)
  141. {
  142. char[80] buf;
  143. const(char)* cs;
  144. version (linux)
  145. {
  146. cs = strerror_r(err, buf.ptr, buf.length);
  147. }
  148. else version (OSX)
  149. {
  150. auto errs = strerror_r(err, buf.ptr, buf.length);
  151. if (errs == 0)
  152. cs = buf.ptr;
  153. else
  154. return "Socket error " ~ to!string(err);
  155. }
  156. else version (FreeBSD)
  157. {
  158. auto errs = strerror_r(err, buf.ptr, buf.length);
  159. if (errs == 0)
  160. cs = buf.ptr;
  161. else
  162. return "Socket error " ~ to!string(err);
  163. }
  164. else
  165. static assert(0);
  166. auto len = strlen(cs);
  167. if(cs[len - 1] == '\n')
  168. len--;
  169. if(cs[len - 1] == '\r')
  170. len--;
  171. return cs[0 .. len].idup;
  172. }
  173. else
  174. version(Windows)
  175. {
  176. return sysErrorString(err);
  177. }
  178. else
  179. return "Socket error " ~ to!string(err);
  180. }
  181. /// Retrieve the error message for the most recently encountered network error.
  182. @property string lastSocketError()
  183. {
  184. return formatSocketError(_lasterr());
  185. }
  186. /// Socket exceptions representing network errors reported by the operating
  187. /// system.
  188. class SocketOSException: SocketException
  189. {
  190. int errorCode; /// Platform-specific error code.
  191. ///
  192. this(string msg,
  193. string file = __FILE__,
  194. size_t line = __LINE__,
  195. Throwable next = null,
  196. int err = _lasterr(),
  197. string function(int) errorFormatter = &formatSocketError)
  198. {
  199. errorCode = err;
  200. if (msg.length)
  201. super(msg ~ ": " ~ errorFormatter(err), file, line, next);
  202. else
  203. super(errorFormatter(err), file, line, next);
  204. }
  205. ///
  206. this(string msg,
  207. Throwable next,
  208. string file = __FILE__,
  209. size_t line = __LINE__,
  210. int err = _lasterr(),
  211. string function(int) errorFormatter = &formatSocketError)
  212. {
  213. this(msg, file, line, next, err, errorFormatter);
  214. }
  215. ///
  216. this(string msg,
  217. int err,
  218. string function(int) errorFormatter = &formatSocketError,
  219. string file = __FILE__,
  220. size_t line = __LINE__,
  221. Throwable next = null)
  222. {
  223. this(msg, file, line, next, err, errorFormatter);
  224. }
  225. }
  226. /// Socket exceptions representing invalid parameters specified by user code.
  227. class SocketParameterException: SocketException
  228. {
  229. ///
  230. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  231. {
  232. super(msg, file, line, next);
  233. }
  234. ///
  235. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  236. {
  237. super(msg, next, file, line);
  238. }
  239. }
  240. /// Socket exceptions representing attempts to use network capabilities not
  241. /// available on the current system.
  242. class SocketFeatureException: SocketException
  243. {
  244. ///
  245. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  246. {
  247. super(msg, file, line, next);
  248. }
  249. ///
  250. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__)
  251. {
  252. super(msg, next, file, line);
  253. }
  254. }
  255. /// Return $(D true) if the last socket operation failed because the socket
  256. /// was in non-blocking mode and the operation would have blocked.
  257. bool wouldHaveBlocked()
  258. {
  259. version(Windows)
  260. return _lasterr() == WSAEWOULDBLOCK;
  261. else version(Posix)
  262. return _lasterr() == EAGAIN;
  263. else
  264. static assert(0);
  265. }
  266. private __gshared typeof(&getnameinfo) getnameinfoPointer;
  267. private __gshared typeof(&getaddrinfo) getaddrinfoPointer;
  268. private __gshared typeof(&freeaddrinfo) freeaddrinfoPointer;
  269. shared static this()
  270. {
  271. version(Windows)
  272. {
  273. WSADATA wd;
  274. // Winsock will still load if an older version is present.
  275. // The version is just a request.
  276. int val;
  277. val = WSAStartup(0x2020, &wd);
  278. if(val) // Request Winsock 2.2 for IPv6.
  279. throw new SocketOSException("Unable to initialize socket library", val);
  280. // These functions may not be present on older Windows versions.
  281. // See the comment in InternetAddress.toHostNameString() for details.
  282. auto ws2Lib = GetModuleHandleA("ws2_32.dll");
  283. if (ws2Lib)
  284. {
  285. getnameinfoPointer = cast(typeof(getnameinfoPointer))
  286. GetProcAddress(ws2Lib, "getnameinfo");
  287. getaddrinfoPointer = cast(typeof(getaddrinfoPointer))
  288. GetProcAddress(ws2Lib, "getaddrinfo");
  289. freeaddrinfoPointer = cast(typeof(freeaddrinfoPointer))
  290. GetProcAddress(ws2Lib, "freeaddrinfo");
  291. }
  292. }
  293. else version(Posix)
  294. {
  295. getnameinfoPointer = &getnameinfo;
  296. getaddrinfoPointer = &getaddrinfo;
  297. freeaddrinfoPointer = &freeaddrinfo;
  298. }
  299. }
  300. shared static ~this()
  301. {
  302. version(Windows)
  303. {
  304. WSACleanup();
  305. }
  306. }
  307. /**
  308. * The communication domain used to resolve an address.
  309. */
  310. enum AddressFamily: int
  311. {
  312. UNSPEC = AF_UNSPEC, /// Unspecified address family
  313. UNIX = AF_UNIX, /// Local communication
  314. INET = AF_INET, /// Internet Protocol version 4
  315. IPX = AF_IPX, /// Novell IPX
  316. APPLETALK = AF_APPLETALK, /// AppleTalk
  317. INET6 = AF_INET6, /// Internet Protocol version 6
  318. }
  319. /**
  320. * Communication semantics
  321. */
  322. enum SocketType: int
  323. {
  324. STREAM = SOCK_STREAM, /// Sequenced, reliable, two-way communication-based byte streams
  325. DGRAM = SOCK_DGRAM, /// Connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
  326. RAW = SOCK_RAW, /// Raw protocol access
  327. RDM = SOCK_RDM, /// Reliably-delivered message datagrams
  328. SEQPACKET = SOCK_SEQPACKET, /// Sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
  329. }
  330. /**
  331. * Protocol
  332. */
  333. enum ProtocolType: int
  334. {
  335. IP = IPPROTO_IP, /// Internet Protocol version 4
  336. ICMP = IPPROTO_ICMP, /// Internet Control Message Protocol
  337. IGMP = IPPROTO_IGMP, /// Internet Group Management Protocol
  338. GGP = IPPROTO_GGP, /// Gateway to Gateway Protocol
  339. TCP = IPPROTO_TCP, /// Transmission Control Protocol
  340. PUP = IPPROTO_PUP, /// PARC Universal Packet Protocol
  341. UDP = IPPROTO_UDP, /// User Datagram Protocol
  342. IDP = IPPROTO_IDP, /// Xerox NS protocol
  343. RAW = IPPROTO_RAW, /// Raw IP packets
  344. IPV6 = IPPROTO_IPV6, /// Internet Protocol version 6
  345. }
  346. /**
  347. * $(D Protocol) is a class for retrieving protocol information.
  348. *
  349. * Example:
  350. * ---
  351. * auto proto = new Protocol;
  352. * writeln("About protocol TCP:");
  353. * if (proto.getProtocolByType(ProtocolType.TCP))
  354. * {
  355. * writefln(" Name: %s", proto.name);
  356. * foreach(string s; proto.aliases)
  357. * writefln(" Alias: %s", s);
  358. * }
  359. * else
  360. * writeln(" No information found");
  361. * ---
  362. */
  363. class Protocol
  364. {
  365. /// These members are populated when one of the following functions are called successfully:
  366. ProtocolType type;
  367. string name; /// ditto
  368. string[] aliases; /// ditto
  369. void populate(protoent* proto)
  370. {
  371. type = cast(ProtocolType)proto.p_proto;
  372. name = to!string(proto.p_name);
  373. int i;
  374. for(i = 0;; i++)
  375. {
  376. if(!proto.p_aliases[i])
  377. break;
  378. }
  379. if(i)
  380. {
  381. aliases = new string[i];
  382. for(i = 0; i != aliases.length; i++)
  383. {
  384. aliases[i] =
  385. to!string(proto.p_aliases[i]);
  386. }
  387. }
  388. else
  389. {
  390. aliases = null;
  391. }
  392. }
  393. /** Returns: false on failure */
  394. bool getProtocolByName(in char[] name)
  395. {
  396. protoent* proto;
  397. proto = getprotobyname(toStringz(name));
  398. if(!proto)
  399. return false;
  400. populate(proto);
  401. return true;
  402. }
  403. /** Returns: false on failure */
  404. // Same as getprotobynumber().
  405. bool getProtocolByType(ProtocolType type)
  406. {
  407. protoent* proto;
  408. proto = getprotobynumber(type);
  409. if(!proto)
  410. return false;
  411. populate(proto);
  412. return true;
  413. }
  414. }
  415. unittest
  416. {
  417. softUnittest({
  418. Protocol proto = new Protocol;
  419. assert(proto.getProtocolByType(ProtocolType.TCP));
  420. //writeln("About protocol TCP:");
  421. //writefln("\tName: %s", proto.name);
  422. // foreach(string s; proto.aliases)
  423. // {
  424. // writefln("\tAlias: %s", s);
  425. // }
  426. assert(proto.name == "tcp");
  427. assert(proto.aliases.length == 1 && proto.aliases[0] == "TCP");
  428. });
  429. }
  430. /**
  431. * $(D Service) is a class for retrieving service information.
  432. *
  433. * Example:
  434. * ---
  435. * auto serv = new Service;
  436. * writeln("About service epmap:");
  437. * if (serv.getServiceByName("epmap", "tcp"))
  438. * {
  439. * writefln(" Service: %s", serv.name);
  440. * writefln(" Port: %d", serv.port);
  441. * writefln(" Protocol: %s", serv.protocolName);
  442. * foreach (string s; serv.aliases)
  443. * writefln(" Alias: %s", s);
  444. * }
  445. * else
  446. * writefln(" No service for epmap.");
  447. * ---
  448. */
  449. class Service
  450. {
  451. /// These members are populated when one of the following functions are called successfully:
  452. string name;
  453. string[] aliases; /// ditto
  454. ushort port; /// ditto
  455. string protocolName; /// ditto
  456. void populate(servent* serv)
  457. {
  458. name = to!string(serv.s_name);
  459. port = ntohs(cast(ushort)serv.s_port);
  460. protocolName = to!string(serv.s_proto);
  461. int i;
  462. for(i = 0;; i++)
  463. {
  464. if(!serv.s_aliases[i])
  465. break;
  466. }
  467. if(i)
  468. {
  469. aliases = new string[i];
  470. for(i = 0; i != aliases.length; i++)
  471. {
  472. aliases[i] =
  473. to!string(serv.s_aliases[i]);
  474. }
  475. }
  476. else
  477. {
  478. aliases = null;
  479. }
  480. }
  481. /**
  482. * If a protocol name is omitted, any protocol will be matched.
  483. * Returns: false on failure.
  484. */
  485. bool getServiceByName(in char[] name, in char[] protocolName = null)
  486. {
  487. servent* serv;
  488. serv = getservbyname(toStringz(name), protocolName !is null ? toStringz(protocolName) : null);
  489. if(!serv)
  490. return false;
  491. populate(serv);
  492. return true;
  493. }
  494. /// ditto
  495. bool getServiceByPort(ushort port, in char[] protocolName = null)
  496. {
  497. servent* serv;
  498. serv = getservbyport(port, protocolName !is null ? toStringz(protocolName) : null);
  499. if(!serv)
  500. return false;
  501. populate(serv);
  502. return true;
  503. }
  504. }
  505. unittest
  506. {
  507. softUnittest({
  508. Service serv = new Service;
  509. if(serv.getServiceByName("epmap", "tcp"))
  510. {
  511. // writefln("About service epmap:");
  512. // writefln("\tService: %s", serv.name);
  513. // writefln("\tPort: %d", serv.port);
  514. // writefln("\tProtocol: %s", serv.protocolName);
  515. // foreach(string s; serv.aliases)
  516. // {
  517. // writefln("\tAlias: %s", s);
  518. // }
  519. // For reasons unknown this is loc-srv on Wine and epmap on Windows
  520. assert(serv.name == "loc-srv" || serv.name == "epmap", serv.name);
  521. assert(serv.port == 135);
  522. assert(serv.protocolName == "tcp");
  523. }
  524. else
  525. {
  526. writefln("No service for epmap.");
  527. }
  528. });
  529. }
  530. /**
  531. * Class for exceptions thrown from an $(D InternetHost).
  532. */
  533. class HostException: SocketOSException
  534. {
  535. ///
  536. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr())
  537. {
  538. super(msg, file, line, next, err);
  539. }
  540. ///
  541. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr())
  542. {
  543. super(msg, next, file, line, err);
  544. }
  545. ///
  546. this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  547. {
  548. super(msg, next, file, line, err);
  549. }
  550. }
  551. /**
  552. * $(D InternetHost) is a class for resolving IPv4 addresses.
  553. *
  554. * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
  555. * instead of using this class directly.
  556. *
  557. * Example:
  558. * ---
  559. * auto ih = new InternetHost;
  560. *
  561. * // Forward lookup
  562. * writeln("About www.digitalmars.com:");
  563. * if (ih.getHostByName("www.digitalmars.com"))
  564. * {
  565. * writefln(" Name: %s", ih.name);
  566. * auto ip = InternetAddress.addrToString(ih.addrList[0]);
  567. * writefln(" IP address: %s", ip);
  568. * foreach (string s; ih.aliases)
  569. * writefln(" Alias: %s", s);
  570. * writeln("---");
  571. *
  572. * // Reverse lookup
  573. * writefln("About IP %s:", ip);
  574. * if (ih.getHostByAddr(ih.addrList[0]))
  575. * {
  576. * writefln(" Name: %s", ih.name);
  577. * foreach (string s; ih.aliases)
  578. * writefln(" Alias: %s", s);
  579. * }
  580. * else
  581. * writeln(" Reverse lookup failed");
  582. * }
  583. * else
  584. * writeln(" Can't resolve www.digitalmars.com");
  585. * ---
  586. */
  587. class InternetHost
  588. {
  589. /// These members are populated when one of the following functions are called successfully:
  590. string name;
  591. string[] aliases; /// ditto
  592. uint[] addrList; /// ditto
  593. void validHostent(hostent* he)
  594. {
  595. if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4)
  596. throw new HostException("Address family mismatch");
  597. }
  598. void populate(hostent* he)
  599. {
  600. int i;
  601. char* p;
  602. name = to!string(he.h_name);
  603. for(i = 0;; i++)
  604. {
  605. p = he.h_aliases[i];
  606. if(!p)
  607. break;
  608. }
  609. if(i)
  610. {
  611. aliases = new string[i];
  612. for(i = 0; i != aliases.length; i++)
  613. {
  614. aliases[i] =
  615. to!string(he.h_aliases[i]);
  616. }
  617. }
  618. else
  619. {
  620. aliases = null;
  621. }
  622. for(i = 0;; i++)
  623. {
  624. p = he.h_addr_list[i];
  625. if(!p)
  626. break;
  627. }
  628. if(i)
  629. {
  630. addrList = new uint[i];
  631. for(i = 0; i != addrList.length; i++)
  632. {
  633. addrList[i] = ntohl(*(cast(uint*)he.h_addr_list[i]));
  634. }
  635. }
  636. else
  637. {
  638. addrList = null;
  639. }
  640. }
  641. private bool getHostNoSync(string opMixin, T)(T param)
  642. {
  643. mixin(opMixin);
  644. if (!he)
  645. return false;
  646. validHostent(he);
  647. populate(he);
  648. return true;
  649. }
  650. version(Windows)
  651. alias getHostNoSync getHost;
  652. else
  653. {
  654. // posix systems use global state for return value, so we
  655. // must synchronize across all threads
  656. private bool getHost(string opMixin, T)(T param)
  657. {
  658. synchronized(this.classinfo)
  659. return getHostNoSync!(opMixin, T)(param);
  660. }
  661. }
  662. /**
  663. * Resolve host name.
  664. * Returns: false if unable to resolve.
  665. */
  666. bool getHostByName(in char[] name)
  667. {
  668. static if (is(typeof(gethostbyname_r)))
  669. {
  670. return getHostNoSync!q{
  671. hostent he_v;
  672. hostent* he;
  673. ubyte[256] buffer_v = void;
  674. auto buffer = buffer_v[];
  675. auto param_z = std.string.toStringz(param);
  676. while (true)
  677. {
  678. he = &he_v;
  679. int errno;
  680. if (gethostbyname_r(param_z, he, buffer.ptr, buffer.length, &he, &errno) == ERANGE)
  681. buffer.length = buffer.length * 2;
  682. else
  683. break;
  684. }
  685. }(name);
  686. }
  687. else
  688. {
  689. return getHost!q{
  690. auto he = gethostbyname(toStringz(param));
  691. }(name);
  692. }
  693. }
  694. /**
  695. * Resolve IPv4 address number.
  696. *
  697. * Params:
  698. * addr = The IPv4 address to resolve, in host byte order.
  699. * Returns:
  700. * false if unable to resolve.
  701. */
  702. bool getHostByAddr(uint addr)
  703. {
  704. return getHost!q{
  705. auto x = htonl(param);
  706. auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
  707. }(addr);
  708. }
  709. /**
  710. * Same as previous, but addr is an IPv4 address string in the
  711. * dotted-decimal form $(I a.b.c.d).
  712. * Returns: false if unable to resolve.
  713. */
  714. bool getHostByAddr(in char[] addr)
  715. {
  716. return getHost!q{
  717. auto x = inet_addr(std.string.toStringz(param));
  718. enforce(x != INADDR_NONE,
  719. new SocketParameterException("Invalid IPv4 address"));
  720. auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
  721. }(addr);
  722. }
  723. }
  724. unittest
  725. {
  726. InternetHost ih = new InternetHost;
  727. ih.getHostByAddr(0x7F_00_00_01);
  728. assert(ih.addrList[0] == 0x7F_00_00_01);
  729. ih.getHostByAddr("127.0.0.1");
  730. assert(ih.addrList[0] == 0x7F_00_00_01);
  731. softUnittest({
  732. if (!ih.getHostByName("www.digitalmars.com"))
  733. return; // don't fail if not connected to internet
  734. //writefln("addrList.length = %d", ih.addrList.length);
  735. assert(ih.addrList.length);
  736. InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY);
  737. assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com",
  738. ih.name);
  739. // writefln("IP address = %s", ia.toAddrString());
  740. // writefln("name = %s", ih.name);
  741. // foreach(int i, string s; ih.aliases)
  742. // {
  743. // writefln("aliases[%d] = %s", i, s);
  744. // }
  745. // writefln("---");
  746. //assert(ih.getHostByAddr(ih.addrList[0]));
  747. // writefln("name = %s", ih.name);
  748. // foreach(int i, string s; ih.aliases)
  749. // {
  750. // writefln("aliases[%d] = %s", i, s);
  751. // }
  752. });
  753. }
  754. /// Holds information about a socket _address retrieved by $(D getAddressInfo).
  755. struct AddressInfo
  756. {
  757. AddressFamily family; /// Address _family
  758. SocketType type; /// Socket _type
  759. ProtocolType protocol; /// Protocol
  760. Address address; /// Socket _address
  761. string canonicalName; /// Canonical name, when $(D AddressInfoFlags.CANONNAME) is used.
  762. }
  763. // A subset of flags supported on all platforms with getaddrinfo.
  764. /// Specifies option flags for $(D getAddressInfo).
  765. enum AddressInfoFlags: int
  766. {
  767. /// The resulting addresses will be used in a call to $(D Socket.bind).
  768. PASSIVE = AI_PASSIVE,
  769. /// The canonical name is returned in $(D canonicalName) member in the first $(D AddressInfo).
  770. CANONNAME = AI_CANONNAME,
  771. /// The $(D node) parameter passed to $(D getAddressInfo) must be a numeric string.
  772. /// This will suppress any potentially lengthy network host address lookups.
  773. NUMERICHOST = AI_NUMERICHOST,
  774. }
  775. /// On POSIX, getaddrinfo uses its own error codes, and thus has its own
  776. /// formatting function.
  777. private string formatGaiError(int err)
  778. {
  779. version(Windows)
  780. {
  781. return sysErrorString(err);
  782. }
  783. else
  784. {
  785. synchronized
  786. return to!string(gai_strerror(err));
  787. }
  788. }
  789. /**
  790. * Provides _protocol-independent translation from host names to socket
  791. * addresses. If advanced functionality is not required, consider using
  792. * $(D getAddress) for compatibility with older systems.
  793. *
  794. * Returns: Array with one $(D AddressInfo) per socket address.
  795. *
  796. * Throws: $(D SocketOSException) on failure, or $(D SocketFeatureException)
  797. * if this functionality is not available on the current system.
  798. *
  799. * Params:
  800. * node = string containing host name or numeric address
  801. * options = optional additional parameters, identified by type:
  802. * $(UL $(LI $(D string) - service name or port number)
  803. * $(LI $(D AddressInfoFlags) - option flags)
  804. * $(LI $(D AddressFamily) - address family to filter by)
  805. * $(LI $(D SocketType) - socket type to filter by)
  806. * $(LI $(D ProtocolType) - protocol to filter by))
  807. *
  808. * Example:
  809. * ---
  810. * // Roundtrip DNS resolution
  811. * auto results = getAddressInfo("www.digitalmars.com");
  812. * assert(results[0].address.toHostNameString() ==
  813. * "digitalmars.com");
  814. *
  815. * // Canonical name
  816. * results = getAddressInfo("www.digitalmars.com",
  817. * AddressInfoFlags.CANONNAME);
  818. * assert(results[0].canonicalName == "digitalmars.com");
  819. *
  820. * // IPv6 resolution
  821. * results = getAddressInfo("ipv6.google.com");
  822. * assert(results[0].family == AddressFamily.INET6);
  823. *
  824. * // Multihomed resolution
  825. * results = getAddressInfo("google.com");
  826. * assert(results.length > 1);
  827. *
  828. * // Parsing IPv4
  829. * results = getAddressInfo("127.0.0.1",
  830. * AddressInfoFlags.NUMERICHOST);
  831. * assert(results.length && results[0].family ==
  832. * AddressFamily.INET);
  833. *
  834. * // Parsing IPv6
  835. * results = getAddressInfo("::1",
  836. * AddressInfoFlags.NUMERICHOST);
  837. * assert(results.length && results[0].family ==
  838. * AddressFamily.INET6);
  839. * ---
  840. */
  841. AddressInfo[] getAddressInfo(T...)(in char[] node, T options)
  842. {
  843. const(char)[] service = null;
  844. addrinfo hints;
  845. hints.ai_family = AF_UNSPEC;
  846. foreach (option; options)
  847. {
  848. static if (is(typeof(option) : const(char)[]))
  849. service = option;
  850. else
  851. static if (is(typeof(option) == AddressInfoFlags))
  852. hints.ai_flags |= option;
  853. else
  854. static if (is(typeof(option) == AddressFamily))
  855. hints.ai_family = option;
  856. else
  857. static if (is(typeof(option) == SocketType))
  858. hints.ai_socktype = option;
  859. else
  860. static if (is(typeof(option) == ProtocolType))
  861. hints.ai_protocol = option;
  862. else
  863. static assert(0, "Unknown getAddressInfo option type: " ~ typeof(option).stringof);
  864. }
  865. return getAddressInfoImpl(node, service, &hints);
  866. }
  867. private AddressInfo[] getAddressInfoImpl(in char[] node, in char[] service, addrinfo* hints)
  868. {
  869. if (getaddrinfoPointer && freeaddrinfoPointer)
  870. {
  871. addrinfo* ai_res;
  872. int ret = getaddrinfoPointer(
  873. node is null ? null : std.string.toStringz(node),
  874. service is null ? null : std.string.toStringz(service),
  875. hints, &ai_res);
  876. scope(exit) if (ai_res) freeaddrinfoPointer(ai_res);
  877. enforce(ret == 0, new SocketOSException("getaddrinfo error", ret, &formatGaiError));
  878. AddressInfo[] result;
  879. // Use const to force UnknownAddressReference to copy the sockaddr.
  880. for (const(addrinfo)* ai = ai_res; ai; ai = ai.ai_next)
  881. result ~= AddressInfo(
  882. cast(AddressFamily) ai.ai_family,
  883. cast(SocketType ) ai.ai_socktype,
  884. cast(ProtocolType ) ai.ai_protocol,
  885. new UnknownAddressReference(ai.ai_addr, cast(socklen_t) ai.ai_addrlen),
  886. ai.ai_canonname ? to!string(ai.ai_canonname) : null);
  887. assert(result.length > 0);
  888. return result;
  889. }
  890. throw new SocketFeatureException("Address info lookup is not available " ~
  891. "on this system.");
  892. }
  893. unittest
  894. {
  895. softUnittest({
  896. if (getaddrinfoPointer)
  897. {
  898. // Roundtrip DNS resolution
  899. auto results = getAddressInfo("www.digitalmars.com");
  900. assert(results[0].address.toHostNameString() == "digitalmars.com");
  901. // Canonical name
  902. results = getAddressInfo("www.digitalmars.com",
  903. AddressInfoFlags.CANONNAME);
  904. assert(results[0].canonicalName == "digitalmars.com");
  905. // IPv6 resolution
  906. //results = getAddressInfo("ipv6.google.com");
  907. //assert(results[0].family == AddressFamily.INET6);
  908. // Multihomed resolution
  909. //results = getAddressInfo("google.com");
  910. //assert(results.length > 1);
  911. // Parsing IPv4
  912. results = getAddressInfo("127.0.0.1", AddressInfoFlags.NUMERICHOST);
  913. assert(results.length && results[0].family == AddressFamily.INET);
  914. // Parsing IPv6
  915. results = getAddressInfo("::1", AddressInfoFlags.NUMERICHOST);
  916. assert(results.length && results[0].family == AddressFamily.INET6);
  917. }
  918. });
  919. }
  920. private ushort serviceToPort(in char[] service)
  921. {
  922. if (service == "")
  923. return InternetAddress.PORT_ANY;
  924. else
  925. if (isNumeric(service))
  926. return to!ushort(service);
  927. else
  928. {
  929. auto s = new Service();
  930. s.getServiceByName(service);
  931. return s.port;
  932. }
  933. }
  934. /**
  935. * Provides _protocol-independent translation from host names to socket
  936. * addresses. Uses $(D getAddressInfo) if the current system supports it,
  937. * and $(D InternetHost) otherwise.
  938. *
  939. * Returns: Array with one $(D Address) instance per socket address.
  940. *
  941. * Throws: $(D SocketOSException) on failure.
  942. *
  943. * Example:
  944. * ---
  945. * writeln("Resolving www.digitalmars.com:");
  946. * try
  947. * {
  948. * auto addresses = getAddress("www.digitalmars.com");
  949. * foreach (address; addresses)
  950. * writefln(" IP: %s", address.toAddrString());
  951. * }
  952. * catch (SocketException e)
  953. * writefln(" Lookup failed: %s", e.msg);
  954. * ---
  955. */
  956. Address[] getAddress(in char[] hostname, in char[] service = null)
  957. {
  958. if (getaddrinfoPointer && freeaddrinfoPointer)
  959. {
  960. // use getAddressInfo
  961. Address[] results;
  962. auto infos = getAddressInfo(hostname, service);
  963. foreach (ref info; infos)
  964. results ~= info.address;
  965. return results;
  966. }
  967. else
  968. return getAddress(hostname, serviceToPort(service));
  969. }
  970. /// ditto
  971. Address[] getAddress(in char[] hostname, ushort port)
  972. {
  973. if (getaddrinfoPointer && freeaddrinfoPointer)
  974. return getAddress(hostname, to!string(port));
  975. else
  976. {
  977. // use getHostByName
  978. auto ih = new InternetHost;
  979. if (!ih.getHostByName(hostname))
  980. throw new AddressException(
  981. text("Unable to resolve host '", hostname, "'"));
  982. Address[] results;
  983. foreach (uint addr; ih.addrList)
  984. results ~= new InternetAddress(addr, port);
  985. return results;
  986. }
  987. }
  988. unittest
  989. {
  990. softUnittest({
  991. auto addresses = getAddress("63.105.9.61");
  992. assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61");
  993. if (getaddrinfoPointer)
  994. {
  995. // test via gethostbyname
  996. auto getaddrinfoPointerBackup = getaddrinfoPointer;
  997. getaddrinfoPointer = null;
  998. scope(exit) getaddrinfoPointer = getaddrinfoPointerBackup;
  999. addresses = getAddress("63.105.9.61");
  1000. assert(addresses.length && addresses[0].toAddrString() == "63.105.9.61");
  1001. }
  1002. });
  1003. }
  1004. /**
  1005. * Provides _protocol-independent parsing of network addresses. Does not
  1006. * attempt name resolution. Uses $(D getAddressInfo) with
  1007. * $(D AddressInfoFlags.NUMERICHOST) if the current system supports it, and
  1008. * $(D InternetAddress) otherwise.
  1009. *
  1010. * Returns: An $(D Address) instance representing specified address.
  1011. *
  1012. * Throws: $(D SocketException) on failure.
  1013. *
  1014. * Example:
  1015. * ---
  1016. * writeln("Enter IP address:");
  1017. * string ip = readln().chomp();
  1018. * try
  1019. * {
  1020. * Address address = parseAddress(ip);
  1021. * writefln("Looking up reverse of %s:",
  1022. * address.toAddrString());
  1023. * try
  1024. * {
  1025. * string reverse = address.toHostNameString();
  1026. * if (reverse)
  1027. * writefln(" Reverse name: %s", reverse);
  1028. * else
  1029. * writeln(" Reverse hostname not found.");
  1030. * }
  1031. * catch (SocketException e)
  1032. * writefln(" Lookup error: %s", e.msg);
  1033. * }
  1034. * catch (SocketException e)
  1035. * {
  1036. * writefln(" %s is not a valid IP address: %s",
  1037. * ip, e.msg);
  1038. * }
  1039. * ---
  1040. */
  1041. Address parseAddress(in char[] hostaddr, in char[] service = null)
  1042. {
  1043. if (getaddrinfoPointer && freeaddrinfoPointer)
  1044. return getAddressInfo(hostaddr, service, AddressInfoFlags.NUMERICHOST)[0].address;
  1045. else
  1046. return parseAddress(hostaddr, serviceToPort(service));
  1047. }
  1048. /// ditto
  1049. Address parseAddress(in char[] hostaddr, ushort port)
  1050. {
  1051. if (getaddrinfoPointer && freeaddrinfoPointer)
  1052. return parseAddress(hostaddr, to!string(port));
  1053. else
  1054. {
  1055. auto in4_addr = InternetAddress.parse(hostaddr);
  1056. enforce(in4_addr != InternetAddress.ADDR_NONE,
  1057. new SocketParameterException("Invalid IP address"));
  1058. return new InternetAddress(in4_addr, port);
  1059. }
  1060. }
  1061. unittest
  1062. {
  1063. softUnittest({
  1064. auto address = parseAddress("63.105.9.61");
  1065. assert(address.toAddrString() == "63.105.9.61");
  1066. if (getaddrinfoPointer)
  1067. {
  1068. // test via inet_addr
  1069. auto getaddrinfoPointerBackup = getaddrinfoPointer;
  1070. getaddrinfoPointer = null;
  1071. scope(exit) getaddrinfoPointer = getaddrinfoPointerBackup;
  1072. address = parseAddress("63.105.9.61");
  1073. assert(address.toAddrString() == "63.105.9.61");
  1074. }
  1075. assert(collectException!SocketException(parseAddress("Invalid IP address")));
  1076. });
  1077. }
  1078. /**
  1079. * Class for exceptions thrown from an $(D Address).
  1080. */
  1081. class AddressException: SocketOSException
  1082. {
  1083. ///
  1084. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr())
  1085. {
  1086. super(msg, file, line, next, err);
  1087. }
  1088. ///
  1089. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr())
  1090. {
  1091. super(msg, next, file, line, err);
  1092. }
  1093. ///
  1094. this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  1095. {
  1096. super(msg, next, file, line, err);
  1097. }
  1098. }
  1099. /**
  1100. * $(D Address) is an abstract class for representing a socket addresses.
  1101. *
  1102. * Example:
  1103. * ---
  1104. * writeln("About www.google.com port 80:");
  1105. * try
  1106. * {
  1107. * Address[] addresses = getAddress("www.google.com", 80);
  1108. * writefln(" %d addresses found.", addresses.length);
  1109. * foreach (int i, Address a; addresses)
  1110. * {
  1111. * writefln(" Address %d:", i+1);
  1112. * writefln(" IP address: %s", a.toAddrString());
  1113. * writefln(" Hostname: %s", a.toHostNameString());
  1114. * writefln(" Port: %s", a.toPortString());
  1115. * writefln(" Service name: %s",
  1116. * a.toServiceNameString());
  1117. * }
  1118. * }
  1119. * catch (SocketException e)
  1120. * writefln(" Lookup error: %s", e.msg);
  1121. * ---
  1122. */
  1123. abstract class Address
  1124. {
  1125. /// Returns pointer to underlying $(D sockaddr) structure.
  1126. abstract @property sockaddr* name();
  1127. abstract @property const(sockaddr)* name() const; /// ditto
  1128. /// Returns actual size of underlying $(D sockaddr) structure.
  1129. abstract @property socklen_t nameLen() const;
  1130. /// Family of this address.
  1131. @property AddressFamily addressFamily() const
  1132. {
  1133. return cast(AddressFamily) name.sa_family;
  1134. }
  1135. // Common code for toAddrString and toHostNameString
  1136. private final string toHostString(bool numeric) const
  1137. {
  1138. // getnameinfo() is the recommended way to perform a reverse (name)
  1139. // lookup on both Posix and Windows. However, it is only available
  1140. // on Windows XP and above, and not included with the WinSock import
  1141. // libraries shipped with DMD. Thus, we check for getnameinfo at
  1142. // runtime in the shared module constructor, and use it if it's
  1143. // available in the base class method. Classes for specific network
  1144. // families (e.g. InternetHost) override this method and use a
  1145. // deprecated, albeit commonly-available method when getnameinfo()
  1146. // is not available.
  1147. // http://technet.microsoft.com/en-us/library/aa450403.aspx
  1148. if (getnameinfoPointer)
  1149. {
  1150. auto buf = new char[NI_MAXHOST];
  1151. auto ret = getnameinfoPointer(
  1152. name, nameLen,
  1153. buf.ptr, cast(uint)buf.length,
  1154. null, 0,
  1155. numeric ? NI_NUMERICHOST : NI_NAMEREQD);
  1156. if (!numeric)
  1157. {
  1158. if (ret==EAI_NONAME)
  1159. return null;
  1160. version(Windows)
  1161. if (ret==WSANO_DATA)
  1162. return null;
  1163. }
  1164. enforce(ret == 0, new AddressException("Could not get " ~
  1165. (numeric ? "host address" : "host name")));
  1166. return assumeUnique(buf[0 .. strlen(buf.ptr)]);
  1167. }
  1168. throw new SocketFeatureException((numeric ? "Host address" : "Host name") ~
  1169. " lookup for this address family is not available on this system.");
  1170. }
  1171. // Common code for toPortString and toServiceNameString
  1172. private final string toServiceString(bool numeric) const
  1173. {
  1174. // See toHostNameString() for details about getnameinfo().
  1175. if (getnameinfoPointer)
  1176. {
  1177. auto buf = new char[NI_MAXSERV];
  1178. enforce(getnameinfoPointer(
  1179. name, nameLen,
  1180. null, 0,
  1181. buf.ptr, cast(uint)buf.length,
  1182. numeric ? NI_NUMERICSERV : NI_NAMEREQD
  1183. ) == 0, new AddressException("Could not get " ~
  1184. (numeric ? "port number" : "service name")));
  1185. return assumeUnique(buf[0 .. strlen(buf.ptr)]);
  1186. }
  1187. throw new SocketFeatureException((numeric ? "Port number" : "Service name") ~
  1188. " lookup for this address family is not available on this system.");
  1189. }
  1190. /**
  1191. * Attempts to retrieve the host address as a human-readable string.
  1192. *
  1193. * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
  1194. * if address retrieval for this address family is not available on the
  1195. * current system.
  1196. */
  1197. string toAddrString() const
  1198. {
  1199. return toHostString(true);
  1200. }
  1201. /**
  1202. * Attempts to retrieve the host name as a fully qualified domain name.
  1203. *
  1204. * Returns: The FQDN corresponding to this $(D Address), or $(D null) if
  1205. * the host name did not resolve.
  1206. *
  1207. * Throws: $(D AddressException) on error, or $(D SocketFeatureException)
  1208. * if host name lookup for this address family is not available on the
  1209. * current system.
  1210. */
  1211. string toHostNameString() const
  1212. {
  1213. return toHostString(false);
  1214. }
  1215. /**
  1216. * Attempts to retrieve the numeric port number as a string.
  1217. *
  1218. * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
  1219. * if port number retrieval for this address family is not available on the
  1220. * current system.
  1221. */
  1222. string toPortString() const
  1223. {
  1224. return toServiceString(true);
  1225. }
  1226. /**
  1227. * Attempts to retrieve the service name as a string.
  1228. *
  1229. * Throws: $(D AddressException) on failure, or $(D SocketFeatureException)
  1230. * if service name lookup for this address family is not available on the
  1231. * current system.
  1232. */
  1233. string toServiceNameString() const
  1234. {
  1235. return toServiceString(false);
  1236. }
  1237. /// Human readable string representing this address.
  1238. override string toString() const
  1239. {
  1240. try
  1241. {
  1242. string host = toAddrString();
  1243. string port = toPortString();
  1244. if (host.indexOf(':') >= 0)
  1245. return "[" ~ host ~ "]:" ~ port;
  1246. else
  1247. return host ~ ":" ~ port;
  1248. }
  1249. catch (SocketException)
  1250. return "Unknown";
  1251. }
  1252. }
  1253. /**
  1254. * $(D UnknownAddress) encapsulates an unknown socket address.
  1255. */
  1256. class UnknownAddress: Address
  1257. {
  1258. protected:
  1259. sockaddr sa;
  1260. public:
  1261. override @property sockaddr* name()
  1262. {
  1263. return &sa;
  1264. }
  1265. override @property const(sockaddr)* name() const
  1266. {
  1267. return &sa;
  1268. }
  1269. override @property socklen_t nameLen() const
  1270. {
  1271. return cast(socklen_t) sa.sizeof;
  1272. }
  1273. }
  1274. /**
  1275. * $(D UnknownAddressReference) encapsulates a reference to an arbitrary
  1276. * socket address.
  1277. */
  1278. class UnknownAddressReference: Address
  1279. {
  1280. protected:
  1281. sockaddr* sa;
  1282. socklen_t len;
  1283. public:
  1284. /// Constructs an $(D Address) with a reference to the specified $(D sockaddr).
  1285. this(sockaddr* sa, socklen_t len)
  1286. {
  1287. this.sa = sa;
  1288. this.len = len;
  1289. }
  1290. /// Constructs an $(D Address) with a copy of the specified $(D sockaddr).
  1291. this(const(sockaddr)* sa, socklen_t len)
  1292. {
  1293. this.sa = cast(sockaddr*) (cast(ubyte*)sa)[0..len].dup.ptr;
  1294. this.len = len;
  1295. }
  1296. override @property sockaddr* name()
  1297. {
  1298. return sa;
  1299. }
  1300. override @property const(sockaddr)* name() const
  1301. {
  1302. return sa;
  1303. }
  1304. override @property socklen_t nameLen() const
  1305. {
  1306. return cast(socklen_t) len;
  1307. }
  1308. }
  1309. /**
  1310. * $(D InternetAddress) encapsulates an IPv4 (Internet Protocol version 4)
  1311. * socket address.
  1312. *
  1313. * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
  1314. * instead of using this class directly.
  1315. */
  1316. class InternetAddress: Address
  1317. {
  1318. protected:
  1319. sockaddr_in sin;
  1320. this()
  1321. {
  1322. }
  1323. public:
  1324. override @property sockaddr* name()
  1325. {
  1326. return cast(sockaddr*)&sin;
  1327. }
  1328. override @property const(sockaddr)* name() const
  1329. {
  1330. return cast(const(sockaddr)*)&sin;
  1331. }
  1332. override @property socklen_t nameLen() const
  1333. {
  1334. return cast(socklen_t) sin.sizeof;
  1335. }
  1336. enum uint ADDR_ANY = INADDR_ANY; /// Any IPv4 host address.
  1337. enum uint ADDR_NONE = INADDR_NONE; /// An invalid IPv4 host address.
  1338. enum ushort PORT_ANY = 0; /// Any IPv4 port number.
  1339. /// Returns the IPv4 _port number (in host byte order).
  1340. @property ushort port() const
  1341. {
  1342. return ntohs(sin.sin_port);
  1343. }
  1344. /// Returns the IPv4 address number (in host byte order).
  1345. @property uint addr() const
  1346. {
  1347. return ntohl(sin.sin_addr.s_addr);
  1348. }
  1349. /**
  1350. * Construct a new $(D InternetAddress).
  1351. * Params:
  1352. * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
  1353. * or a host name which will be resolved using an $(D InternetHost)
  1354. * object.
  1355. * port = port number, may be $(D PORT_ANY).
  1356. */
  1357. this(in char[] addr, ushort port)
  1358. {
  1359. uint uiaddr = parse(addr);
  1360. if(ADDR_NONE == uiaddr)
  1361. {
  1362. InternetHost ih = new InternetHost;
  1363. if(!ih.getHostByName(addr))
  1364. //throw new AddressException("Invalid internet address");
  1365. throw new AddressException(
  1366. text("Unable to resolve host '", addr, "'"));
  1367. uiaddr = ih.addrList[0];
  1368. }
  1369. sin.sin_family = AddressFamily.INET;
  1370. sin.sin_addr.s_addr = htonl(uiaddr);
  1371. sin.sin_port = htons(port);
  1372. }
  1373. /**
  1374. * Construct a new $(D InternetAddress).
  1375. * Params:
  1376. * addr = (optional) an IPv4 address in host byte order, may be $(D ADDR_ANY).
  1377. * port = port number, may be $(D PORT_ANY).
  1378. */
  1379. this(uint addr, ushort port)
  1380. {
  1381. sin.sin_family = AddressFamily.INET;
  1382. sin.sin_addr.s_addr = htonl(addr);
  1383. sin.sin_port = htons(port);
  1384. }
  1385. /// ditto
  1386. this(ushort port)
  1387. {
  1388. sin.sin_family = AddressFamily.INET;
  1389. sin.sin_addr.s_addr = ADDR_ANY;
  1390. sin.sin_port = htons(port);
  1391. }
  1392. /// Human readable string representing the IPv4 address in dotted-decimal form.
  1393. override string toAddrString() const
  1394. {
  1395. return to!string(inet_ntoa(sin.sin_addr));
  1396. }
  1397. /// Human readable string representing the IPv4 port.
  1398. override string toPortString() const
  1399. {
  1400. return std.conv.to!string(port);
  1401. }
  1402. /**
  1403. * Attempts to retrieve the host name as a fully qualified domain name.
  1404. *
  1405. * Returns: The FQDN corresponding to this $(D InternetAddress), or
  1406. * $(D null) if the host name did not resolve.
  1407. *
  1408. * Throws: $(D AddressException) on error.
  1409. */
  1410. override string toHostNameString() const
  1411. {
  1412. // getnameinfo() is the recommended way to perform a reverse (name)
  1413. // lookup on both Posix and Windows. However, it is only available
  1414. // on Windows XP and above, and not included with the WinSock import
  1415. // libraries shipped with DMD. Thus, we check for getnameinfo at
  1416. // runtime in the shared module constructor, and fall back to the
  1417. // deprecated getHostByAddr() if it could not be found. See also:
  1418. // http://technet.microsoft.com/en-us/library/aa450403.aspx
  1419. if (getnameinfoPointer)
  1420. return super.toHostNameString();
  1421. else
  1422. {
  1423. auto host = new InternetHost();
  1424. if (!host.getHostByAddr(ntohl(sin.sin_addr.s_addr)))
  1425. return null;
  1426. return host.name;
  1427. }
  1428. }
  1429. /**
  1430. * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
  1431. * and return the number.
  1432. * Returns: If the string is not a legitimate IPv4 address,
  1433. * $(D ADDR_NONE) is returned.
  1434. */
  1435. static uint parse(in char[] addr)
  1436. {
  1437. return ntohl(inet_addr(std.string.toStringz(addr)));
  1438. }
  1439. /**
  1440. * Convert an IPv4 address number in host byte order to a human readable
  1441. * string representing the IPv4 address in dotted-decimal form.
  1442. */
  1443. static string addrToString(uint addr)
  1444. {
  1445. in_addr sin_addr;
  1446. sin_addr.s_addr = htonl(addr);
  1447. return to!string(inet_ntoa(sin_addr));
  1448. }
  1449. }
  1450. unittest
  1451. {
  1452. softUnittest({
  1453. const InternetAddress ia = new InternetAddress("63.105.9.61", 80);
  1454. assert(ia.toString() == "63.105.9.61:80");
  1455. });
  1456. softUnittest({
  1457. // test reverse lookup
  1458. auto ih = new InternetHost;
  1459. if (ih.getHostByName("digitalmars.com"))
  1460. {
  1461. const ia = new InternetAddress(ih.addrList[0], 80);
  1462. assert(ia.toHostNameString() == "digitalmars.com");
  1463. if (getnameinfoPointer)
  1464. {
  1465. // test reverse lookup, via gethostbyaddr
  1466. auto getnameinfoPointerBackup = getnameinfoPointer;
  1467. getnameinfoPointer = null;
  1468. scope(exit) getnameinfoPointer = getnameinfoPointerBackup;
  1469. assert(ia.toHostNameString() == "digitalmars.com");
  1470. }
  1471. }
  1472. });
  1473. version (SlowTests)
  1474. softUnittest({
  1475. // test failing reverse lookup
  1476. const InternetAddress ia = new InternetAddress("127.114.111.120", 80);
  1477. assert(ia.toHostNameString() is null);
  1478. if (getnameinfoPointer)
  1479. {
  1480. // test failing reverse lookup, via gethostbyaddr
  1481. auto getnameinfoPointerBackup = getnameinfoPointer;
  1482. getnameinfoPointer = null;
  1483. scope(exit) getnameinfoPointer = getnameinfoPointerBackup;
  1484. assert(ia.toHostNameString() is null);
  1485. }
  1486. });
  1487. }
  1488. /**
  1489. * $(D Internet6Address) encapsulates an IPv6 (Internet Protocol version 6)
  1490. * socket address.
  1491. *
  1492. * Consider using $(D getAddress), $(D parseAddress) and $(D Address) methods
  1493. * instead of using this class directly.
  1494. */
  1495. class Internet6Address: Address
  1496. {
  1497. protected:
  1498. sockaddr_in6 sin6;
  1499. this()
  1500. {
  1501. }
  1502. public:
  1503. override @property sockaddr* name()
  1504. {
  1505. return cast(sockaddr*)&sin6;
  1506. }
  1507. override @property const(sockaddr)* name() const
  1508. {
  1509. return cast(const(sockaddr)*)&sin6;
  1510. }
  1511. override @property socklen_t nameLen() const
  1512. {
  1513. return cast(socklen_t) sin6.sizeof;
  1514. }
  1515. /// Any IPv6 host address.
  1516. static @property ref const(ubyte)[16] ADDR_ANY()
  1517. {
  1518. const(ubyte)[16]* addr;
  1519. static if (is(typeof(IN6ADDR_ANY)))
  1520. return addr = &IN6ADDR_ANY.s6_addr, *addr;
  1521. else
  1522. static if (is(typeof(in6addr_any)))
  1523. return addr = &in6addr_any.s6_addr, *addr;
  1524. else
  1525. static assert(0);
  1526. }
  1527. /// Any IPv6 port number.
  1528. enum ushort PORT_ANY = 0;
  1529. /// Returns the IPv6 port number.
  1530. @property ushort port() const
  1531. {
  1532. return ntohs(sin6.sin6_port);
  1533. }
  1534. /// Returns the IPv6 address.
  1535. @property ubyte[16] addr() const
  1536. {
  1537. return sin6.sin6_addr.s6_addr;
  1538. }
  1539. /**
  1540. * Construct a new $(D Internet6Address).
  1541. * Params:
  1542. * addr = an IPv6 host address string in the form described in RFC 2373,
  1543. * or a host name which will be resolved using $(D getAddressInfo).
  1544. * service = (optional) service name.
  1545. */
  1546. this(in char[] addr, in char[] service = null)
  1547. {
  1548. auto results = getAddressInfo(addr, service, AddressFamily.INET6);
  1549. assert(results.length && results[0].family == AddressFamily.INET6);
  1550. sin6 = *cast(sockaddr_in6*)results[0].address.name;
  1551. }
  1552. /**
  1553. * Construct a new $(D Internet6Address).
  1554. * Params:
  1555. * addr = an IPv6 host address string in the form described in RFC 2373,
  1556. * or a host name which will be resolved using $(D getAddressInfo).
  1557. * port = port number, may be $(D PORT_ANY).
  1558. */
  1559. this(in char[] addr, ushort port)
  1560. {
  1561. if (port == PORT_ANY)
  1562. this(addr);
  1563. else
  1564. this(addr, to!string(port));
  1565. }
  1566. /**
  1567. * Construct a new $(D Internet6Address).
  1568. * Params:
  1569. * addr = (optional) an IPv6 host address in host byte order, or
  1570. * $(D ADDR_ANY).
  1571. * port = port number, may be $(D PORT_ANY).
  1572. */
  1573. this(ubyte[16] addr, ushort port)
  1574. {
  1575. sin6.sin6_family = AddressFamily.INET6;
  1576. sin6.sin6_addr.s6_addr = addr;
  1577. sin6.sin6_port = htons(port);
  1578. }
  1579. /// ditto
  1580. this(ushort port)
  1581. {
  1582. sin6.sin6_family = AddressFamily.INET6;
  1583. sin6.sin6_addr.s6_addr = ADDR_ANY;
  1584. sin6.sin6_port = htons(port);
  1585. }
  1586. /**
  1587. * Parse an IPv6 host address string as described in RFC 2373, and return the
  1588. * address.
  1589. * Throws: $(D SocketException) on error.
  1590. */
  1591. static ubyte[16] parse(in char[] addr)
  1592. {
  1593. // Although we could use inet_pton here, it's only available on Windows
  1594. // versions starting with Vista, so use getAddressInfo with NUMERICHOST
  1595. // instead.
  1596. auto results = getAddressInfo(addr, AddressInfoFlags.NUMERICHOST);
  1597. if (results.length && results[0].family == AddressFamily.INET6)
  1598. return (cast(sockaddr_in6*)results[0].address.name).sin6_addr.s6_addr;
  1599. throw new AddressException("Not an IPv6 address", 0);
  1600. }
  1601. }
  1602. unittest
  1603. {
  1604. softUnittest({
  1605. const Internet6Address ia = new Internet6Address("::1", 80);
  1606. assert(ia.toString() == "[::1]:80");
  1607. });
  1608. }
  1609. version(StdDdoc)
  1610. {
  1611. /**
  1612. * $(D UnixAddress) encapsulates an address for a Unix domain socket
  1613. * ($(D AF_UNIX)). Available only on supported systems.
  1614. */
  1615. class UnixAddress: Address
  1616. {
  1617. /// Construct a new $(D UnixAddress) from the specified path.
  1618. this(in char[] path);
  1619. /// Get the underlying _path.
  1620. @property string path() const;
  1621. /// ditto
  1622. override string toString() const;
  1623. }
  1624. }
  1625. else
  1626. static if (is(sockaddr_un))
  1627. {
  1628. class UnixAddress: Address
  1629. {
  1630. protected:
  1631. sockaddr_un* sun;
  1632. socklen_t len;
  1633. this()
  1634. {
  1635. }
  1636. public:
  1637. override @property sockaddr* name()
  1638. {
  1639. return cast(sockaddr*)sun;
  1640. }
  1641. override @property const(sockaddr)* name() const
  1642. {
  1643. return cast(const(sockaddr)*)sun;
  1644. }
  1645. override @property socklen_t nameLen() const
  1646. {
  1647. return len;
  1648. }
  1649. this(in char[] path)
  1650. {
  1651. len = cast(socklen_t)(sockaddr_un.init.sun_path.offsetof + path.length + 1);
  1652. sun = cast(sockaddr_un*) (new ubyte[len]).ptr;
  1653. sun.sun_family = AF_UNIX;
  1654. sun.sun_path.ptr[0..path.length] = (cast(byte[]) path)[];
  1655. sun.sun_path.ptr[path.length] = 0;
  1656. }
  1657. @property string path() const
  1658. {
  1659. return to!string(sun.sun_path.ptr);
  1660. }
  1661. override string toString() const
  1662. {
  1663. return path;
  1664. }
  1665. }
  1666. unittest
  1667. {
  1668. import core.stdc.stdio : remove;
  1669. immutable ubyte[] data = [1, 2, 3, 4];
  1670. Socket[2] pair;
  1671. auto name = "unix-address-family-unittest-socket-name";
  1672. auto address = new UnixAddress(name);
  1673. auto listener = new Socket(AddressFamily.UNIX, SocketType.STREAM);
  1674. scope(exit) listener.close();
  1675. listener.bind(address);
  1676. scope(exit) remove(toStringz(name));
  1677. listener.listen(1);
  1678. pair[0] = new Socket(AddressFamily.UNIX, SocketType.STREAM);
  1679. scope(exit) listener.close();
  1680. pair[0].connect(address);
  1681. scope(exit) pair[0].close();
  1682. pair[1] = listener.accept();
  1683. scope(exit) pair[1].close();
  1684. pair[0].send(data);
  1685. auto buf = new ubyte[data.length];
  1686. pair[1].receive(buf);
  1687. assert(buf == data);
  1688. }
  1689. }
  1690. /**
  1691. * Class for exceptions thrown by $(D Socket.accept).
  1692. */
  1693. class SocketAcceptException: SocketOSException
  1694. {
  1695. ///
  1696. this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null, int err = _lasterr())
  1697. {
  1698. super(msg, file, line, next, err);
  1699. }
  1700. ///
  1701. this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__, int err = _lasterr())
  1702. {
  1703. super(msg, next, file, line, err);
  1704. }
  1705. ///
  1706. this(string msg, int err, string file = __FILE__, size_t line = __LINE__, Throwable next = null)
  1707. {
  1708. super(msg, next, file, line, err);
  1709. }
  1710. }
  1711. /// How a socket is shutdown:
  1712. enum SocketShutdown: int
  1713. {
  1714. RECEIVE = SD_RECEIVE, /// socket receives are disallowed
  1715. SEND = SD_SEND, /// socket sends are disallowed
  1716. BOTH = SD_BOTH, /// both RECEIVE and SEND
  1717. }
  1718. /// Flags may be OR'ed together:
  1719. enum SocketFlags: int
  1720. {
  1721. NONE = 0, /// no flags specified
  1722. OOB = MSG_OOB, /// out-of-band stream data
  1723. PEEK = MSG_PEEK, /// peek at incoming data without removing it from the queue, only for receiving
  1724. DONTROUTE = MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending
  1725. }
  1726. private mixin template FieldProxy(string target, string field)
  1727. {
  1728. mixin(`
  1729. @property typeof(`~target~`) `~field~`() const
  1730. {
  1731. return `~target~`;
  1732. }
  1733. /// ditto
  1734. @property typeof(`~target~`) `~field~`(typeof(`~target~`) value)
  1735. {
  1736. return `~target~` = value;
  1737. }
  1738. `);
  1739. }
  1740. /// Duration timeout value.
  1741. struct TimeVal
  1742. {
  1743. _ctimeval ctimeval;
  1744. alias typeof(ctimeval.tv_sec) tv_sec_t;
  1745. alias typeof(ctimeval.tv_usec) tv_usec_t;
  1746. version (StdDdoc) // no DDoc for string mixins, can't forward individual fields
  1747. {
  1748. tv_sec_t seconds; /// Number of _seconds.
  1749. tv_usec_t microseconds; /// Number of additional _microseconds.
  1750. }
  1751. else
  1752. {
  1753. // D interface
  1754. mixin FieldProxy!(`ctimeval.tv_sec`, `seconds`);
  1755. mixin FieldProxy!(`ctimeval.tv_usec`, `microseconds`);
  1756. }
  1757. }
  1758. /**
  1759. * A collection of sockets for use with $(D Socket.select).
  1760. *
  1761. * $(D SocketSet) allows specifying the capacity of the underlying
  1762. * $(D fd_set), however users should be aware that the exact meaning of this
  1763. * value varies depending on the current platform:
  1764. * $(UL $(LI On POSIX, $(D fd_set) is a bit array of file descriptors. The
  1765. * $(D SocketSet) capacity specifies the highest file descriptor which can be
  1766. * stored in the set.)
  1767. * $(LI on Windows, $(D fd_set) is an array of socket handles. Capacity
  1768. * indicates the actual number of sockets that can be stored in the set.))
  1769. */
  1770. class SocketSet
  1771. {
  1772. private:
  1773. version(Windows)
  1774. {
  1775. // the maximum number of sockets the allocated fd_set can hold
  1776. uint fdsetCapacity;
  1777. fd_set* set;
  1778. @property uint count() const { return set.fd_count; }
  1779. }
  1780. else version(Posix)
  1781. {
  1782. int fdsetMax;
  1783. fd_set setData;
  1784. final @property fd_set* set() { return &setData; }
  1785. final @property const(fd_set)* set() const { return &setData; }
  1786. int maxfd;
  1787. uint count;
  1788. }
  1789. public:
  1790. /**
  1791. * Set the capacity of this $(D SocketSet). The exact meaning of the
  1792. * $(D max) parameter varies from platform to platform.
  1793. * Throws: $(D SocketParameterException) if $(D max) exceeds this
  1794. * platform's maximum socket set size.
  1795. */
  1796. this(uint max)
  1797. {
  1798. version(Windows)
  1799. {
  1800. fdsetCapacity = max;
  1801. set = FD_CREATE(max);
  1802. }
  1803. else version(Posix)
  1804. {
  1805. // TODO (needs druntime changes)
  1806. enforce(max <= FD_SETSIZE, new SocketParameterException(
  1807. "Maximum socket set size exceeded for this platform"));
  1808. fdsetMax = max;
  1809. }
  1810. reset();
  1811. }
  1812. /// Uses the default capacity for the system.
  1813. this()
  1814. {
  1815. this(FD_SETSIZE);
  1816. }
  1817. /// Reset the $(D SocketSet) so that there are 0 $(D Socket)s in the collection.
  1818. void reset()
  1819. {
  1820. FD_ZERO(set);
  1821. version(Posix)
  1822. {
  1823. maxfd = -1;
  1824. count = 0;
  1825. }
  1826. }
  1827. void add(socket_t s)
  1828. {
  1829. // Make sure too many sockets don't get added.
  1830. version(Windows)
  1831. {
  1832. enforce(count < fdsetCapacity, new SocketParameterException(
  1833. "SocketSet capacity exceeded"));
  1834. }
  1835. else version(Posix)
  1836. {
  1837. enforce(s < fdsetMax, new SocketParameterException(
  1838. "Socket descriptor index exceeds SocketSet capacity"));
  1839. }
  1840. FD_SET(s, set);
  1841. version(Posix)
  1842. {
  1843. ++count;
  1844. if(s > maxfd)
  1845. maxfd = s;
  1846. }
  1847. }
  1848. /// Add a $(D Socket) to the collection.
  1849. /// Throws: $(D SocketParameterException) if the capacity of this
  1850. /// $(D SocketSet) has been exceeded.
  1851. void add(Socket s)
  1852. {
  1853. add(s.sock);
  1854. }
  1855. void remove(socket_t s)
  1856. {
  1857. version(Posix)
  1858. {
  1859. enforce(s < fdsetMax, new SocketParameterException(
  1860. "Socket descriptor index exceeds SocketSet capacity"));
  1861. }
  1862. FD_CLR(s, set);
  1863. version(Posix)
  1864. {
  1865. --count;
  1866. // note: adjusting maxfd would require scanning the set, not worth it
  1867. }
  1868. }
  1869. /// Remove this $(D Socket) from the collection.
  1870. void remove(Socket s)
  1871. {
  1872. remove(s.sock);
  1873. }
  1874. int isSet(socket_t s) const
  1875. {
  1876. version(Posix)
  1877. {
  1878. enforce(s < fdsetMax, new SocketParameterException(
  1879. "Socket descriptor index exceeds SocketSet capacity"));
  1880. }
  1881. return FD_ISSET(s, set);
  1882. }
  1883. /// Returns nonzero if this $(D Socket) is in the collection.
  1884. int isSet(Socket s) const
  1885. {
  1886. return isSet(s.sock);
  1887. }
  1888. /// Return the capacity of this $(D SocketSet). The exact meaning of the
  1889. /// return value varies from platform to platform.
  1890. @property uint max() const
  1891. {
  1892. version(Windows)
  1893. {
  1894. return fdsetCapacity;
  1895. }
  1896. else version(Posix)
  1897. {
  1898. return fdsetMax;
  1899. }
  1900. }
  1901. fd_set* toFd_set()
  1902. {
  1903. return set;
  1904. }
  1905. int selectn() const
  1906. {
  1907. version(Windows)
  1908. {
  1909. return count;
  1910. }
  1911. else version(Posix)
  1912. {
  1913. return maxfd + 1;
  1914. }
  1915. }
  1916. }
  1917. /// The level at which a socket option is defined:
  1918. enum SocketOptionLevel: int
  1919. {
  1920. SOCKET = SOL_SOCKET, /// Socket level
  1921. IP = ProtocolType.IP, /// Internet Protocol version 4 level
  1922. ICMP = ProtocolType.ICMP, /// Internet Control Message Protocol level
  1923. IGMP = ProtocolType.IGMP, /// Internet Group Management Protocol level
  1924. GGP = ProtocolType.GGP, /// Gateway to Gateway Protocol level
  1925. TCP = ProtocolType.TCP, /// Transmission Control Protocol level
  1926. PUP = ProtocolType.PUP, /// PARC Universal Packet Protocol level
  1927. UDP = ProtocolType.UDP, /// User Datagram Protocol level
  1928. IDP = ProtocolType.IDP, /// Xerox NS protocol level
  1929. RAW = ProtocolType.RAW, /// Raw IP packet level
  1930. IPV6 = ProtocolType.IPV6, /// Internet Protocol version 6 level
  1931. }
  1932. /// _Linger information for use with SocketOption.LINGER.
  1933. struct Linger
  1934. {
  1935. _clinger clinger;
  1936. version (StdDdoc) // no DDoc for string mixins, can't forward individual fields
  1937. {
  1938. private alias typeof(_clinger.init.l_onoff ) l_onoff_t;
  1939. private alias typeof(_clinger.init.l_linger) l_linger_t;
  1940. l_onoff_t on; /// Nonzero for _on.
  1941. l_linger_t time; /// Linger _time.
  1942. }
  1943. else
  1944. {
  1945. // D interface
  1946. mixin FieldProxy!(`clinger.l_onoff`, `on`);
  1947. mixin FieldProxy!(`clinger.l_linger`, `time`);
  1948. }
  1949. }
  1950. /// Specifies a socket option:
  1951. enum SocketOption: int
  1952. {
  1953. DEBUG = SO_DEBUG, /// Record debugging information
  1954. BROADCAST = SO_BROADCAST, /// Allow transmission of broadcast messages
  1955. REUSEADDR = SO_REUSEADDR, /// Allow local reuse of address
  1956. LINGER = SO_LINGER, /// Linger on close if unsent data is present
  1957. OOBINLINE = SO_OOBINLINE, /// Receive out-of-band data in band
  1958. SNDBUF = SO_SNDBUF, /// Send buffer size
  1959. RCVBUF = SO_RCVBUF, /// Receive buffer size
  1960. DONTROUTE = SO_DONTROUTE, /// Do not route
  1961. SNDTIMEO = SO_SNDTIMEO, /// Send timeout
  1962. RCVTIMEO = SO_RCVTIMEO, /// Receive timeout
  1963. ERROR = SO_ERROR, /// Retrieve and clear error status
  1964. KEEPALIVE = SO_KEEPALIVE, /// Enable keep-alive packets
  1965. ACCEPTCONN = SO_ACCEPTCONN, /// Listen
  1966. RCVLOWAT = SO_RCVLOWAT, /// Minimum number of input bytes to process
  1967. SNDLOWAT = SO_SNDLOWAT, /// Minimum number of output bytes to process
  1968. TYPE = SO_TYPE, /// Socket type
  1969. // SocketOptionLevel.TCP:
  1970. TCP_NODELAY = .TCP_NODELAY, /// Disable the Nagle algorithm for send coalescing
  1971. // SocketOptionLevel.IPV6:
  1972. IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, /// IP unicast hop limit
  1973. IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, /// IP multicast interface
  1974. IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, /// IP multicast loopback
  1975. IPV6_MULTICAST_HOPS = .IPV6_MULTICAST_HOPS, /// IP multicast hops
  1976. IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, /// Add an IP group membership
  1977. IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, /// Drop an IP group membership
  1978. IPV6_V6ONLY = .IPV6_V6ONLY, /// Treat wildcard bind as AF_INET6-only
  1979. }
  1980. /**
  1981. * $(D Socket) is a class that creates a network communication endpoint using
  1982. * the Berkeley sockets interface.
  1983. */
  1984. class Socket
  1985. {
  1986. private:
  1987. socket_t sock;
  1988. AddressFamily _family;
  1989. version(Windows)
  1990. bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking.
  1991. // The WinSock timeouts seem to be effectively skewed by a constant
  1992. // offset of about half a second (value in milliseconds). This has
  1993. // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7
  1994. // and Windows Server 2008 R2 boxes. The unittest below tests this
  1995. // behavior.
  1996. enum WINSOCK_TIMEOUT_SKEW = 500;
  1997. unittest
  1998. {
  1999. version(SlowTests)
  2000. softUnittest({
  2001. import std.datetime;
  2002. enum msecs = 1000;
  2003. auto pair = socketPair();
  2004. auto sock = pair[0];
  2005. sock.setOption(SocketOptionLevel.SOCKET,
  2006. SocketOption.RCVTIMEO, dur!"msecs"(msecs));
  2007. auto sw = StopWatch(AutoStart.yes);
  2008. ubyte[1] buf;
  2009. sock.receive(buf);
  2010. sw.stop();
  2011. Duration readBack = void;
  2012. sock.getOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, readBack);
  2013. assert(readBack.total!"msecs" == msecs);
  2014. assert(sw.peek().msecs > msecs-100 && sw.peek().msecs < msecs+100);
  2015. });
  2016. }
  2017. void setSock(socket_t handle)
  2018. {
  2019. assert(handle != socket_t.init);
  2020. sock = handle;
  2021. // Set the option to disable SIGPIPE on send() if the platform
  2022. // has it (e.g. on OS X).
  2023. static if (is(typeof(SO_NOSIGPIPE)))
  2024. {
  2025. setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_NOSIGPIPE, true);
  2026. }
  2027. }
  2028. // For use with accepting().
  2029. protected this()
  2030. {
  2031. }
  2032. public:
  2033. /**
  2034. * Create a blocking socket. If a single protocol type exists to support
  2035. * this socket type within the address family, the $(D ProtocolType) may be
  2036. * omitted.
  2037. */
  2038. this(AddressFamily af, SocketType type, ProtocolType protocol)
  2039. {
  2040. _family = af;
  2041. auto handle = cast(socket_t) socket(af, type, protocol);
  2042. if(handle == socket_t.init)
  2043. throw new SocketOSException("Unable to create socket");
  2044. setSock(handle);
  2045. }
  2046. // A single protocol exists to support this socket type within the
  2047. // protocol family, so the ProtocolType is assumed.
  2048. /// ditto
  2049. this(AddressFamily af, SocketType type)
  2050. {
  2051. this(af, type, cast(ProtocolType)0); // Pseudo protocol number.
  2052. }
  2053. /// ditto
  2054. this(AddressFamily af, SocketType type, in char[] protocolName)
  2055. {
  2056. protoent* proto;
  2057. proto = getprotobyname(toStringz(protocolName));
  2058. if(!proto)
  2059. throw new SocketOSException("Unable to find the protocol");
  2060. this(af, type, cast(ProtocolType)proto.p_proto);
  2061. }
  2062. /**
  2063. * Create a blocking socket using the parameters from the specified
  2064. * $(D AddressInfo) structure.
  2065. */
  2066. this(in AddressInfo info)
  2067. {
  2068. this(info.family, info.type, info.protocol);
  2069. }
  2070. /// Use an existing socket handle.
  2071. this(socket_t sock, AddressFamily af)
  2072. {
  2073. assert(sock != socket_t.init);
  2074. this.sock = sock;
  2075. this._family = af;
  2076. }
  2077. ~this()
  2078. {
  2079. close();
  2080. }
  2081. /// Get underlying socket handle.
  2082. @property socket_t handle() const
  2083. {
  2084. return sock;
  2085. }
  2086. /**
  2087. * Get/set socket's blocking flag.
  2088. *
  2089. * When a socket is blocking, calls to receive(), accept(), and send()
  2090. * will block and wait for data/action.
  2091. * A non-blocking socket will immediately return instead of blocking.
  2092. */
  2093. @property bool blocking() const
  2094. {
  2095. version(Windows)
  2096. {
  2097. return _blocking;
  2098. }
  2099. else version(Posix)
  2100. {
  2101. return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK);
  2102. }
  2103. }
  2104. /// ditto
  2105. @property void blocking(bool byes)
  2106. {
  2107. version(Windows)
  2108. {
  2109. uint num = !byes;
  2110. if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
  2111. goto err;
  2112. _blocking = byes;
  2113. }
  2114. else version(Posix)
  2115. {
  2116. int x = fcntl(sock, F_GETFL, 0);
  2117. if(-1 == x)
  2118. goto err;
  2119. if(byes)
  2120. x &= ~O_NONBLOCK;
  2121. else
  2122. x |= O_NONBLOCK;
  2123. if(-1 == fcntl(sock, F_SETFL, x))
  2124. goto err;
  2125. }
  2126. return; // Success.
  2127. err:
  2128. throw new SocketOSException("Unable to set socket blocking");
  2129. }
  2130. /// Get the socket's address family.
  2131. @property AddressFamily addressFamily()
  2132. {
  2133. return _family;
  2134. }
  2135. /// Property that indicates if this is a valid, alive socket.
  2136. @property bool isAlive() const
  2137. {
  2138. int type;
  2139. socklen_t typesize = cast(socklen_t) type.sizeof;
  2140. return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
  2141. }
  2142. /// Associate a local address with this socket.
  2143. void bind(Address addr)
  2144. {
  2145. if(_SOCKET_ERROR == .bind(sock, addr.name, addr.nameLen))
  2146. throw new SocketOSException("Unable to bind socket");
  2147. }
  2148. /**
  2149. * Establish a connection. If the socket is blocking, connect waits for
  2150. * the connection to be made. If the socket is nonblocking, connect
  2151. * returns immediately and the connection attempt is still in progress.
  2152. */
  2153. void connect(Address to)
  2154. {
  2155. if(_SOCKET_ERROR == .connect(sock, to.name, to.nameLen))
  2156. {
  2157. int err;
  2158. err = _lasterr();
  2159. if(!blocking)
  2160. {
  2161. version(Windows)
  2162. {
  2163. if(WSAEWOULDBLOCK == err)
  2164. return;
  2165. }
  2166. else version(Posix)
  2167. {
  2168. if(EINPROGRESS == err)
  2169. return;
  2170. }
  2171. else
  2172. {
  2173. static assert(0);
  2174. }
  2175. }
  2176. throw new SocketOSException("Unable to connect socket", err);
  2177. }
  2178. }
  2179. /**
  2180. * Listen for an incoming connection. $(D bind) must be called before you
  2181. * can $(D listen). The $(D backlog) is a request of how many pending
  2182. * incoming connections are queued until $(D accept)ed.
  2183. */
  2184. void listen(int backlog)
  2185. {
  2186. if(_SOCKET_ERROR == .listen(sock, backlog))
  2187. throw new SocketOSException("Unable to listen on socket");
  2188. }
  2189. /**
  2190. * Called by $(D accept) when a new $(D Socket) must be created for a new
  2191. * connection. To use a derived class, override this method and return an
  2192. * instance of your class. The returned $(D Socket)'s handle must not be
  2193. * set; $(D Socket) has a protected constructor $(D this()) to use in this
  2194. * situation.
  2195. */
  2196. // Override to use a derived class.
  2197. // The returned socket's handle must not be set.
  2198. protected Socket accepting()
  2199. {
  2200. return new Socket;
  2201. }
  2202. /**
  2203. * Accept an incoming connection. If the socket is blocking, $(D accept)
  2204. * waits for a connection request. Throws $(D SocketAcceptException) if
  2205. * unable to _accept. See $(D accepting) for use with derived classes.
  2206. */
  2207. Socket accept()
  2208. {
  2209. auto newsock = cast(socket_t).accept(sock, null, null);
  2210. if(socket_t.init == newsock)
  2211. throw new SocketAcceptException("Unable to accept socket connection");
  2212. Socket newSocket;
  2213. try
  2214. {
  2215. newSocket = accepting();
  2216. assert(newSocket.sock == socket_t.init);
  2217. newSocket.setSock(newsock);
  2218. version(Windows)
  2219. newSocket._blocking = _blocking; //inherits blocking mode
  2220. newSocket._family = _family; //same family
  2221. }
  2222. catch(Throwable o)
  2223. {
  2224. _close(newsock);
  2225. throw o;
  2226. }
  2227. return newSocket;
  2228. }
  2229. /// Disables sends and/or receives.
  2230. void shutdown(SocketShutdown how)
  2231. {
  2232. .shutdown(sock, cast(int)how);
  2233. }
  2234. private static void _close(socket_t sock)
  2235. {
  2236. version(Windows)
  2237. {
  2238. .closesocket(sock);
  2239. }
  2240. else version(Posix)
  2241. {
  2242. .close(sock);
  2243. }
  2244. }
  2245. /**
  2246. * Immediately drop any connections and release socket resources.
  2247. * Calling $(D shutdown) before $(D close) is recommended for
  2248. * connection-oriented sockets. The $(D Socket) object is no longer
  2249. * usable after $(D close).
  2250. */
  2251. //calling shutdown() before this is recommended
  2252. //for connection-oriented sockets
  2253. void close()
  2254. {
  2255. _close(sock);
  2256. sock = socket_t.init;
  2257. }
  2258. /// Returns the local machine's host name.
  2259. // Idea from mango.
  2260. static @property string hostName() // getter
  2261. {
  2262. char[256] result; // Host names are limited to 255 chars.
  2263. if(_SOCKET_ERROR == .gethostname(result.ptr, result.length))
  2264. throw new SocketOSException("Unable to obtain host name");
  2265. return to!string(result.ptr);
  2266. }
  2267. /// Remote endpoint $(D Address).
  2268. @property Address remoteAddress()
  2269. {
  2270. Address addr = createAddress();
  2271. socklen_t nameLen = addr.nameLen;
  2272. if(_SOCKET_ERROR == .getpeername(sock, addr.name, &nameLen))
  2273. throw new SocketOSException("Unable to obtain remote socket address");
  2274. if(nameLen > addr.nameLen)
  2275. throw new SocketParameterException("Not enough socket address storage");
  2276. assert(addr.addressFamily == _family);
  2277. return addr;
  2278. }
  2279. /// Local endpoint $(D Address).
  2280. @property Address localAddress()
  2281. {
  2282. Address addr = createAddress();
  2283. socklen_t nameLen = addr.nameLen;
  2284. if(_SOCKET_ERROR == .getsockname(sock, addr.name, &nameLen))
  2285. throw new SocketOSException("Unable to obtain local socket address");
  2286. if(nameLen > addr.nameLen)
  2287. throw new SocketParameterException("Not enough socket address storage");
  2288. assert(addr.addressFamily == _family);
  2289. return addr;
  2290. }
  2291. /**
  2292. * Send or receive error code. See $(D wouldHaveBlocked),
  2293. * $(D lastSocketError) and $(D Socket.getErrorText) for obtaining more
  2294. * information about the error.
  2295. */
  2296. enum int ERROR = _SOCKET_ERROR;
  2297. /**
  2298. * Send data on the connection. If the socket is blocking and there is no
  2299. * buffer space left, $(D send) waits.
  2300. * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on
  2301. * failure.
  2302. */
  2303. //returns number of bytes actually sent, or -1 on error
  2304. ptrdiff_t send(const(void)[] buf, SocketFlags flags)
  2305. {
  2306. static if (is(typeof(MSG_NOSIGNAL)))
  2307. {
  2308. flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
  2309. }
  2310. version( Windows )
  2311. auto sent = .send(sock, buf.ptr, to!int(buf.length), cast(int)flags);
  2312. else
  2313. auto sent = .send(sock, buf.ptr, buf.length, cast(int)flags);
  2314. return sent;
  2315. }
  2316. /// ditto
  2317. ptrdiff_t send(const(void)[] buf)
  2318. {
  2319. return send(buf, SocketFlags.NONE);
  2320. }
  2321. /**
  2322. * Send data to a specific destination Address. If the destination address is
  2323. * not specified, a connection must have been made and that address is used.
  2324. * If the socket is blocking and there is no buffer space left, $(D sendTo) waits.
  2325. * Returns: The number of bytes actually sent, or $(D Socket.ERROR) on
  2326. * failure.
  2327. */
  2328. ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags, Address to)
  2329. {
  2330. static if (is(typeof(MSG_NOSIGNAL)))
  2331. {
  2332. flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
  2333. }
  2334. version( Windows )
  2335. return .sendto(
  2336. sock, buf.ptr, std.conv.to!int(buf.length),
  2337. cast(int)flags, to.name, to.nameLen
  2338. );
  2339. else
  2340. return .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name, to.nameLen);
  2341. }
  2342. /// ditto
  2343. ptrdiff_t sendTo(const(void)[] buf, Address to)
  2344. {
  2345. return sendTo(buf, SocketFlags.NONE, to);
  2346. }
  2347. //assumes you connect()ed
  2348. /// ditto
  2349. ptrdiff_t sendTo(const(void)[] buf, SocketFlags flags)
  2350. {
  2351. static if (is(typeof(MSG_NOSIGNAL)))
  2352. {
  2353. flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
  2354. }
  2355. version(Windows)
  2356. return .sendto(sock, buf.ptr, to!int(buf.length), cast(int)flags, null, 0);
  2357. else
  2358. return .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
  2359. }
  2360. //assumes you connect()ed
  2361. /// ditto
  2362. ptrdiff_t sendTo(const(void)[] buf)
  2363. {
  2364. return sendTo(buf, SocketFlags.NONE);
  2365. }
  2366. /**
  2367. * Receive data on the connection. If the socket is blocking, $(D receive)
  2368. * waits until there is data to be received.
  2369. * Returns: The number of bytes actually received, $(D 0) if the remote side
  2370. * has closed the connection, or $(D Socket.ERROR) on failure.
  2371. */
  2372. //returns number of bytes actually received, 0 on connection closure, or -1 on error
  2373. ptrdiff_t receive(void[] buf, SocketFlags flags)
  2374. {
  2375. version(Windows) // Does not use size_t
  2376. {
  2377. return buf.length
  2378. ? .recv(sock, buf.ptr, to!int(buf.length), cast(int)flags)
  2379. : 0;
  2380. } else {
  2381. return buf.length
  2382. ? .recv(sock, buf.ptr, buf.length, cast(int)flags)
  2383. : 0;
  2384. }
  2385. }
  2386. /// ditto
  2387. ptrdiff_t receive(void[] buf)
  2388. {
  2389. return receive(buf, SocketFlags.NONE);
  2390. }
  2391. /**
  2392. * Receive data and get the remote endpoint $(D Address).
  2393. * If the socket is blocking, $(D receiveFrom) waits until there is data to
  2394. * be received.
  2395. * Returns: The number of bytes actually received, $(D 0) if the remote side
  2396. * has closed the connection, or $(D Socket.ERROR) on failure.
  2397. */
  2398. ptrdiff_t receiveFrom(void[] buf, SocketFlags flags, ref Address from)
  2399. {
  2400. if(!buf.length) //return 0 and don't think the connection closed
  2401. return 0;
  2402. if (from is null || from.addressFamily != _family)
  2403. from = createAddress();
  2404. socklen_t nameLen = from.nameLen;
  2405. version(Windows)
  2406. {
  2407. auto read = .recvfrom(sock, buf.ptr, to!int(buf.length), cast(int)flags, from.name, &nameLen);
  2408. assert(from.addressFamily == _family);
  2409. // if(!read) //connection closed
  2410. return read;
  2411. } else {
  2412. auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name, &nameLen);
  2413. assert(from.addressFamily == _family);
  2414. // if(!read) //connection closed
  2415. return read;
  2416. }
  2417. }
  2418. /// ditto
  2419. ptrdiff_t receiveFrom(void[] buf, ref Address from)
  2420. {
  2421. return receiveFrom(buf, SocketFlags.NONE, from);
  2422. }
  2423. //assumes you connect()ed
  2424. /// ditto
  2425. ptrdiff_t receiveFrom(void[] buf, SocketFlags flags)
  2426. {
  2427. if(!buf.length) //return 0 and don't think the connection closed
  2428. return 0;
  2429. version(Windows)
  2430. {
  2431. auto read = .recvfrom(sock, buf.ptr, to!int(buf.length), cast(int)flags, null, null);
  2432. // if(!read) //connection closed
  2433. return read;
  2434. } else {
  2435. auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
  2436. // if(!read) //connection closed
  2437. return read;
  2438. }
  2439. }
  2440. //assumes you connect()ed
  2441. /// ditto
  2442. ptrdiff_t receiveFrom(void[] buf)
  2443. {
  2444. return receiveFrom(buf, SocketFlags.NONE);
  2445. }
  2446. /// Get a socket option.
  2447. /// Returns: The number of bytes written to $(D result).
  2448. //returns the length, in bytes, of the actual result - very different from getsockopt()
  2449. int getOption(SocketOptionLevel level, SocketOption option, void[] result)
  2450. {
  2451. socklen_t len = cast(socklen_t) result.length;
  2452. if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result.ptr, &len))
  2453. throw new SocketOSException("Unable to get socket option");
  2454. return len;
  2455. }
  2456. /// Common case of getting integer and boolean options.
  2457. int getOption(SocketOptionLevel level, SocketOption option, out int32_t result)
  2458. {
  2459. return getOption(level, option, (&result)[0 .. 1]);
  2460. }
  2461. /// Get the linger option.
  2462. int getOption(SocketOptionLevel level, SocketOption option, out Linger result)
  2463. {
  2464. //return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
  2465. return getOption(level, option, (&result.clinger)[0 .. 1]);
  2466. }
  2467. /// Get a timeout (duration) option.
  2468. void getOption(SocketOptionLevel level, SocketOption option, out Duration result)
  2469. {
  2470. enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO,
  2471. new SocketParameterException("Not a valid timeout option: " ~ to!string(option)));
  2472. // WinSock returns the timeout values as a milliseconds DWORD,
  2473. // while Linux and BSD return a timeval struct.
  2474. version (Windows)
  2475. {
  2476. int msecs;
  2477. getOption(level, option, (&msecs)[0 .. 1]);
  2478. if (option == SocketOption.RCVTIMEO)
  2479. msecs += WINSOCK_TIMEOUT_SKEW;
  2480. result = dur!"msecs"(msecs);
  2481. }
  2482. else version (Posix)
  2483. {
  2484. TimeVal tv;
  2485. getOption(level, option, (&tv.ctimeval)[0..1]);
  2486. result = dur!"seconds"(tv.seconds) + dur!"usecs"(tv.microseconds);
  2487. }
  2488. else static assert(false);
  2489. }
  2490. // Set a socket option.
  2491. void setOption(SocketOptionLevel level, SocketOption option, void[] value)
  2492. {
  2493. if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level,
  2494. cast(int)option, value.ptr, cast(uint) value.length))
  2495. throw new SocketOSException("Unable to set socket option");
  2496. }
  2497. /// Common case for setting integer and boolean options.
  2498. void setOption(SocketOptionLevel level, SocketOption option, int32_t value)
  2499. {
  2500. setOption(level, option, (&value)[0 .. 1]);
  2501. }
  2502. /// Set the linger option.
  2503. void setOption(SocketOptionLevel level, SocketOption option, Linger value)
  2504. {
  2505. //setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
  2506. setOption(level, option, (&value.clinger)[0 .. 1]);
  2507. }
  2508. /**
  2509. * Sets a timeout (duration) option, i.e. $(D SocketOption.SNDTIMEO) or
  2510. * $(D RCVTIMEO). Zero indicates no timeout.
  2511. *
  2512. * In a typical application, you might also want to consider using
  2513. * a non-blocking socket instead of setting a timeout on a blocking one.
  2514. *
  2515. * Note: While the receive timeout setting is generally quite accurate
  2516. * on *nix systems even for smaller durations, there are two issues to
  2517. * be aware of on Windows: First, although undocumented, the effective
  2518. * timeout duration seems to be the one set on the socket plus half
  2519. * a second. $(D setOption()) tries to compensate for that, but still,
  2520. * timeouts under 500ms are not possible on Windows. Second, be aware
  2521. * that the actual amount of time spent until a blocking call returns
  2522. * randomly varies on the order of 10ms.
  2523. *
  2524. * Params:
  2525. * level = The level at which a socket option is defined.
  2526. * option = Either $(D SocketOption.SNDTIMEO) or $(D SocketOption.RCVTIMEO).
  2527. * value = The timeout duration to set. Must not be negative.
  2528. *
  2529. * Throws: $(D SocketException) if setting the options fails.
  2530. *
  2531. * Example:
  2532. * ---
  2533. * import std.datetime;
  2534. * auto pair = socketPair();
  2535. * scope(exit) foreach (s; pair) s.close();
  2536. *
  2537. * // Set a receive timeout, and then wait at one end of
  2538. * // the socket pair, knowing that no data will arrive.
  2539. * pair[0].setOption(SocketOptionLevel.SOCKET,
  2540. * SocketOption.RCVTIMEO, dur!"seconds"(1));
  2541. *
  2542. * auto sw = StopWatch(AutoStart.yes);
  2543. * ubyte[1] buffer;
  2544. * pair[0].receive(buffer);
  2545. * writefln("Waited %s ms until the socket timed out.",
  2546. * sw.peek.msecs);
  2547. * ---
  2548. */
  2549. void setOption(SocketOptionLevel level, SocketOption option, Duration value)
  2550. {
  2551. enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO,
  2552. new SocketParameterException("Not a valid timeout option: " ~ to!string(option)));
  2553. enforce(value >= dur!"hnsecs"(0), new SocketParameterException(
  2554. "Timeout duration must not be negative."));
  2555. version (Windows)
  2556. {
  2557. auto msecs = to!int(value.total!"msecs");
  2558. if (msecs != 0 && option == SocketOption.RCVTIMEO)
  2559. msecs = max(1, msecs - WINSOCK_TIMEOUT_SKEW);
  2560. setOption(level, option, msecs);
  2561. }
  2562. else version (Posix)
  2563. {
  2564. _ctimeval tv;
  2565. tv.tv_sec = to!(typeof(tv.tv_sec ))(value.total!"seconds");
  2566. tv.tv_usec = to!(typeof(tv.tv_usec))(value.fracSec.usecs);
  2567. setOption(level, option, (&tv)[0 .. 1]);
  2568. }
  2569. else static assert(false);
  2570. }
  2571. /// Get a text description of this socket's error status, and clear the
  2572. /// socket's error status.
  2573. string getErrorText()
  2574. {
  2575. int32_t error;
  2576. getOption(SocketOptionLevel.SOCKET, SocketOption.ERROR, error);
  2577. return formatSocketError(error);
  2578. }
  2579. /**
  2580. * Enables TCP keep-alive with the specified parameters.
  2581. *
  2582. * Params:
  2583. * time = Number of seconds with no activity until the first
  2584. * keep-alive packet is sent.
  2585. * interval = Number of seconds between when successive keep-alive
  2586. * packets are sent if no acknowledgement is received.
  2587. *
  2588. * Throws: $(D SocketOSException) if setting the options fails, or
  2589. * $(D SocketFeatureException) if setting keep-alive parameters is
  2590. * unsupported on the current platform.
  2591. */
  2592. void setKeepAlive(int time, int interval)
  2593. {
  2594. version(Windows)
  2595. {
  2596. tcp_keepalive options;
  2597. options.onoff = 1;
  2598. options.keepalivetime = time * 1000;
  2599. options.keepaliveinterval = interval * 1000;
  2600. uint cbBytesReturned;
  2601. enforce(WSAIoctl(sock, SIO_KEEPALIVE_VALS,
  2602. &options, options.sizeof,
  2603. null, 0,
  2604. &cbBytesReturned, null, null) == 0,
  2605. new SocketOSException("Error setting keep-alive"));
  2606. }
  2607. else
  2608. static if (is(typeof(TCP_KEEPIDLE)) && is(typeof(TCP_KEEPINTVL)))
  2609. {
  2610. setOption(SocketOptionLevel.TCP, cast(SocketOption)TCP_KEEPIDLE, time);
  2611. setOption(SocketOptionLevel.TCP, cast(SocketOption)TCP_KEEPINTVL, interval);
  2612. setOption(SocketOptionLevel.SOCKET, SocketOption.KEEPALIVE, true);
  2613. }
  2614. else
  2615. throw new SocketFeatureException("Setting keep-alive options " ~
  2616. "is not supported on this platform");
  2617. }
  2618. /**
  2619. * Wait for a socket to change status. A wait timeout of $(Duration) or
  2620. * $(D TimeVal), may be specified; if a timeout is not specified or the
  2621. * $(D TimeVal) is $(D null), the maximum timeout is used. The $(D TimeVal)
  2622. * timeout has an unspecified value when $(D select) returns.
  2623. * Returns: The number of sockets with status changes, $(D 0) on timeout,
  2624. * or $(D -1) on interruption. If the return value is greater than $(D 0),
  2625. * the $(D SocketSets) are updated to only contain the sockets having status
  2626. * changes. For a connecting socket, a write status change means the
  2627. * connection is established and it's able to send. For a listening socket,
  2628. * a read status change means there is an incoming connection request and
  2629. * it's able to accept.
  2630. */
  2631. //SocketSet's updated to include only those sockets which an event occured
  2632. //returns the number of events, 0 on timeout, or -1 on interruption
  2633. //for a connect()ing socket, writeability means connected
  2634. //for a listen()ing socket, readability means listening
  2635. //Winsock: possibly internally limited to 64 sockets per set
  2636. static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, Duration timeout)
  2637. {
  2638. TimeVal tv;
  2639. tv.seconds = to!(tv.tv_sec_t )(timeout.total!"seconds");
  2640. tv.microseconds = to!(tv.tv_usec_t)(timeout.fracSec.usecs);
  2641. return select(checkRead, checkWrite, checkError, &tv);
  2642. }
  2643. /// ditto
  2644. //maximum timeout
  2645. static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError)
  2646. {
  2647. return select(checkRead, checkWrite, checkError, null);
  2648. }
  2649. /// Ditto
  2650. static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, TimeVal* timeout)
  2651. in
  2652. {
  2653. //make sure none of the SocketSet's are the same object
  2654. if(checkRead)
  2655. {
  2656. assert(checkRead !is checkWrite);
  2657. assert(checkRead !is checkError);
  2658. }
  2659. if(checkWrite)
  2660. {
  2661. assert(checkWrite !is checkError);
  2662. }
  2663. }
  2664. body
  2665. {
  2666. fd_set* fr, fw, fe;
  2667. int n = 0;
  2668. version(Windows)
  2669. {
  2670. // Windows has a problem with empty fd_set`s that aren't null.
  2671. fr = checkRead && checkRead.count ? checkRead.toFd_set() : null;
  2672. fw = checkWrite && checkWrite.count ? checkWrite.toFd_set() : null;
  2673. fe = checkError && checkError.count ? checkError.toFd_set() : null;
  2674. }
  2675. else
  2676. {
  2677. if(checkRead)
  2678. {
  2679. fr = checkRead.toFd_set();
  2680. n = checkRead.selectn();
  2681. }
  2682. else
  2683. {
  2684. fr = null;
  2685. }
  2686. if(checkWrite)
  2687. {
  2688. fw = checkWrite.toFd_set();
  2689. int _n;
  2690. _n = checkWrite.selectn();
  2691. if(_n > n)
  2692. n = _n;
  2693. }
  2694. else
  2695. {
  2696. fw = null;
  2697. }
  2698. if(checkError)
  2699. {
  2700. fe = checkError.toFd_set();
  2701. int _n;
  2702. _n = checkError.selectn();
  2703. if(_n > n)
  2704. n = _n;
  2705. }
  2706. else
  2707. {
  2708. fe = null;
  2709. }
  2710. }
  2711. int result = .select(n, fr, fw, fe, &timeout.ctimeval);
  2712. version(Windows)
  2713. {
  2714. if(_SOCKET_ERROR == result && WSAGetLastError() == WSAEINTR)
  2715. return -1;
  2716. }
  2717. else version(Posix)
  2718. {
  2719. if(_SOCKET_ERROR == result && errno == EINTR)
  2720. return -1;
  2721. }
  2722. else
  2723. {
  2724. static assert(0);
  2725. }
  2726. if(_SOCKET_ERROR == result)
  2727. throw new SocketOSException("Socket select error");
  2728. return result;
  2729. }
  2730. // Explicitly undocumented. It will be removed in December 2014.
  2731. deprecated("Please use the overload of select which takes a Duration instead.")
  2732. static int select(SocketSet checkRead, SocketSet checkWrite, SocketSet checkError, long microseconds)
  2733. {
  2734. TimeVal tv;
  2735. tv.seconds = to!(tv.tv_sec_t )(microseconds / 1_000_000);
  2736. tv.microseconds = to!(tv.tv_usec_t)(microseconds % 1_000_000);
  2737. return select(checkRead, checkWrite, checkError, &tv);
  2738. }
  2739. /// Returns a new Address object for the current address family.
  2740. /// Can be overridden to support other addresses.
  2741. protected Address createAddress()
  2742. {
  2743. Address result;
  2744. switch(_family)
  2745. {
  2746. case AddressFamily.INET:
  2747. result = new InternetAddress;
  2748. break;
  2749. case AddressFamily.INET6:
  2750. result = new Internet6Address;
  2751. break;
  2752. default:
  2753. result = new UnknownAddress;
  2754. }
  2755. return result;
  2756. }
  2757. }
  2758. /// $(D TcpSocket) is a shortcut class for a TCP Socket.
  2759. class TcpSocket: Socket
  2760. {
  2761. /// Constructs a blocking TCP Socket.
  2762. this(AddressFamily family)
  2763. {
  2764. super(family, SocketType.STREAM, ProtocolType.TCP);
  2765. }
  2766. /// Constructs a blocking IPv4 TCP Socket.
  2767. this()
  2768. {
  2769. this(AddressFamily.INET);
  2770. }
  2771. //shortcut
  2772. /// Constructs a blocking TCP Socket and connects to an $(D Address).
  2773. this(Address connectTo)
  2774. {
  2775. this(connectTo.addressFamily);
  2776. connect(connectTo);
  2777. }
  2778. }
  2779. /// $(D UdpSocket) is a shortcut class for a UDP Socket.
  2780. class UdpSocket: Socket
  2781. {
  2782. /// Constructs a blocking UDP Socket.
  2783. this(AddressFamily family)
  2784. {
  2785. super(family, SocketType.DGRAM, ProtocolType.UDP);
  2786. }
  2787. /// Constructs a blocking IPv4 UDP Socket.
  2788. this()
  2789. {
  2790. this(AddressFamily.INET);
  2791. }
  2792. }
  2793. /**
  2794. * Creates a pair of connected sockets.
  2795. *
  2796. * The two sockets are indistinguishable.
  2797. *
  2798. * Throws: $(D SocketException) if creation of the sockets fails.
  2799. *
  2800. * Example:
  2801. * ---
  2802. * immutable ubyte[] data = [1, 2, 3, 4];
  2803. * auto pair = socketPair();
  2804. * scope(exit) foreach (s; pair) s.close();
  2805. *
  2806. * pair[0].send(data);
  2807. *
  2808. * auto buf = new ubyte[data.length];
  2809. * pair[1].receive(buf);
  2810. * assert(buf == data);
  2811. * ---
  2812. */
  2813. Socket[2] socketPair()
  2814. {
  2815. version(Posix)
  2816. {
  2817. int[2] socks;
  2818. if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == -1)
  2819. throw new SocketOSException("Unable to create socket pair");
  2820. Socket toSocket(size_t id)
  2821. {
  2822. auto s = new Socket;
  2823. s.setSock(cast(socket_t)socks[id]);
  2824. s._family = AddressFamily.UNIX;
  2825. return s;
  2826. }
  2827. return [toSocket(0), toSocket(1)];
  2828. }
  2829. else version(Windows)
  2830. {
  2831. // We do not have socketpair() on Windows, just manually create a
  2832. // pair of sockets connected over some localhost port.
  2833. Socket[2] result;
  2834. auto listener = new TcpSocket();
  2835. listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
  2836. listener.bind(new InternetAddress(INADDR_LOOPBACK, InternetAddress.PORT_ANY));
  2837. auto addr = listener.localAddress;
  2838. listener.listen(1);
  2839. result[0] = new TcpSocket(addr);
  2840. result[1] = listener.accept();
  2841. listener.close();
  2842. return result;
  2843. }
  2844. else
  2845. static assert(false);
  2846. }
  2847. unittest
  2848. {
  2849. immutable ubyte[] data = [1, 2, 3, 4];
  2850. auto pair = socketPair();
  2851. scope(exit) foreach (s; pair) s.close();
  2852. pair[0].send(data);
  2853. auto buf = new ubyte[data.length];
  2854. pair[1].receive(buf);
  2855. assert(buf == data);
  2856. }