PageRenderTime 55ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/d/phobos2/std/socket.d

https://bitbucket.org/alexrp/gdc
D | 2033 lines | 1351 code | 275 blank | 407 comment | 170 complexity | 376fa37c23da3d5eb41bbcdfb2afc013 MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0

Large files files are truncated, but you can click here to view the full file

  1. // Written in the D programming language
  2. /*
  3. Copyright (C) 2004-2005 Christopher E. Miller
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not
  15. be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. socket.d 1.3
  19. Jan 2005
  20. Thanks to Benjamin Herr for his assistance.
  21. */
  22. /**
  23. * Notes: For Win32 systems, link with ws2_32.lib.
  24. * Example: See /dmd/samples/d/listener.d.
  25. * Authors: Christopher E. Miller, $(WEB klickverbot.at, David Nadlinger)
  26. * Source: $(PHOBOSSRC std/_socket.d)
  27. * Macros:
  28. * WIKI=Phobos/StdSocket
  29. */
  30. module std.socket;
  31. import core.stdc.stdint, std.string, std.c.string, std.c.stdlib, std.conv,
  32. std.traits;
  33. import core.stdc.config;
  34. import core.time : dur, Duration;
  35. import std.algorithm : max;
  36. import std.exception : assumeUnique, enforce;
  37. version(unittest)
  38. {
  39. private import std.c.stdio : printf;
  40. }
  41. version(Posix)
  42. {
  43. version = BsdSockets;
  44. }
  45. version(Win32)
  46. {
  47. pragma (lib, "ws2_32.lib");
  48. pragma (lib, "wsock32.lib");
  49. private import std.c.windows.windows, std.c.windows.winsock;
  50. private alias std.c.windows.winsock.timeval _ctimeval;
  51. enum socket_t : SOCKET { INVALID_SOCKET };
  52. private const int _SOCKET_ERROR = SOCKET_ERROR;
  53. private int _lasterr()
  54. {
  55. return WSAGetLastError();
  56. }
  57. }
  58. else version(BsdSockets)
  59. {
  60. version(Posix)
  61. {
  62. version(linux)
  63. import std.c.linux.socket : AF_IPX, AF_APPLETALK, SOCK_RDM,
  64. IPPROTO_IGMP, IPPROTO_GGP, IPPROTO_PUP, IPPROTO_IDP,
  65. SD_RECEIVE, SD_SEND, SD_BOTH, MSG_NOSIGNAL, INADDR_NONE;
  66. else version(OSX)
  67. private import std.c.osx.socket;
  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. private import core.sys.posix.fcntl;
  81. private import core.sys.posix.unistd;
  82. private import core.sys.posix.arpa.inet;
  83. private import core.sys.posix.netinet.tcp;
  84. private import core.sys.posix.netinet.in_;
  85. private import core.sys.posix.sys.time;
  86. //private import core.sys.posix.sys.select;
  87. private import core.sys.posix.sys.socket;
  88. private alias core.sys.posix.sys.time.timeval _ctimeval;
  89. }
  90. private import core.stdc.errno;
  91. enum socket_t : int32_t { init = -1 }
  92. private const int _SOCKET_ERROR = -1;
  93. private int _lasterr()
  94. {
  95. return errno;
  96. }
  97. }
  98. else
  99. {
  100. static assert(0); // No socket support yet.
  101. }
  102. /// Base exception thrown from a Socket.
  103. class SocketException: Exception
  104. {
  105. int errorCode; /// Platform-specific error code.
  106. this(string msg, int err = 0)
  107. {
  108. errorCode = err;
  109. version(Posix)
  110. {
  111. if(errorCode > 0)
  112. {
  113. char[80] buf;
  114. const(char)* cs;
  115. version (linux)
  116. {
  117. cs = strerror_r(errorCode, buf.ptr, buf.length);
  118. }
  119. else version (OSX)
  120. {
  121. auto errs = strerror_r(errorCode, buf.ptr, buf.length);
  122. if (errs == 0)
  123. cs = buf.ptr;
  124. else
  125. {
  126. cs = "Unknown error";
  127. }
  128. }
  129. else version (FreeBSD)
  130. {
  131. auto errs = strerror_r(errorCode, buf.ptr, buf.length);
  132. if (errs == 0)
  133. cs = buf.ptr;
  134. else
  135. {
  136. cs = "Unknown error";
  137. }
  138. }
  139. else
  140. {
  141. static assert(0);
  142. }
  143. auto len = strlen(cs);
  144. if(cs[len - 1] == '\n')
  145. len--;
  146. if(cs[len - 1] == '\r')
  147. len--;
  148. msg = cast(string) (msg ~ ": " ~ cs[0 .. len]);
  149. }
  150. }
  151. super(msg);
  152. }
  153. }
  154. private __gshared typeof(&getnameinfo) getnameinfoPointer;
  155. shared static this()
  156. {
  157. version(Win32)
  158. {
  159. WSADATA wd;
  160. // Winsock will still load if an older version is present.
  161. // The version is just a request.
  162. int val;
  163. val = WSAStartup(0x2020, &wd);
  164. if(val) // Request Winsock 2.2 for IPv6.
  165. throw new SocketException("Unable to initialize socket library", val);
  166. // See the comment in InternetAddress.toHostNameString() for
  167. // details on the getnameinfo() issue.
  168. auto ws2Lib = GetModuleHandleA("ws2_32.dll");
  169. if (ws2Lib)
  170. {
  171. getnameinfoPointer = cast(typeof(getnameinfoPointer))
  172. GetProcAddress(ws2Lib, "getnameinfo");
  173. }
  174. }
  175. else version(Posix)
  176. {
  177. getnameinfoPointer = &getnameinfo;
  178. }
  179. }
  180. shared static ~this()
  181. {
  182. version(Win32)
  183. {
  184. WSACleanup();
  185. }
  186. }
  187. /**
  188. * The communication domain used to resolve an address.
  189. */
  190. enum AddressFamily: int
  191. {
  192. UNSPEC = AF_UNSPEC, ///
  193. UNIX = AF_UNIX, /// local communication
  194. INET = AF_INET, /// internet protocol version 4
  195. IPX = AF_IPX, /// novell IPX
  196. APPLETALK = AF_APPLETALK, /// appletalk
  197. INET6 = AF_INET6, // internet protocol version 6
  198. }
  199. /**
  200. * Communication semantics
  201. */
  202. enum SocketType: int
  203. {
  204. STREAM = SOCK_STREAM, /// sequenced, reliable, two-way communication-based byte streams
  205. DGRAM = SOCK_DGRAM, /// connectionless, unreliable datagrams with a fixed maximum length; data may be lost or arrive out of order
  206. RAW = SOCK_RAW, /// raw protocol access
  207. RDM = SOCK_RDM, /// reliably-delivered message datagrams
  208. SEQPACKET = SOCK_SEQPACKET, /// sequenced, reliable, two-way connection-based datagrams with a fixed maximum length
  209. }
  210. /**
  211. * Protocol
  212. */
  213. enum ProtocolType: int
  214. {
  215. IP = IPPROTO_IP, /// internet protocol version 4
  216. ICMP = IPPROTO_ICMP, /// internet control message protocol
  217. IGMP = IPPROTO_IGMP, /// internet group management protocol
  218. GGP = IPPROTO_GGP, /// gateway to gateway protocol
  219. TCP = IPPROTO_TCP, /// transmission control protocol
  220. PUP = IPPROTO_PUP, /// PARC universal packet protocol
  221. UDP = IPPROTO_UDP, /// user datagram protocol
  222. IDP = IPPROTO_IDP, /// Xerox NS protocol
  223. IPV6 = IPPROTO_IPV6, /// internet protocol version 6
  224. }
  225. /**
  226. * Protocol is a class for retrieving protocol information.
  227. */
  228. class Protocol
  229. {
  230. ProtocolType type; /// These members are populated when one of the following functions are called without failure:
  231. string name; /// ditto
  232. string[] aliases; /// ditto
  233. void populate(protoent* proto)
  234. {
  235. type = cast(ProtocolType)proto.p_proto;
  236. name = to!string(proto.p_name).idup;
  237. int i;
  238. for(i = 0;; i++)
  239. {
  240. if(!proto.p_aliases[i])
  241. break;
  242. }
  243. if(i)
  244. {
  245. aliases = new string[i];
  246. for(i = 0; i != aliases.length; i++)
  247. {
  248. aliases[i] =
  249. to!string(proto.p_aliases[i]).idup;
  250. }
  251. }
  252. else
  253. {
  254. aliases = null;
  255. }
  256. }
  257. /** Returns false on failure */
  258. bool getProtocolByName(string name)
  259. {
  260. protoent* proto;
  261. proto = getprotobyname(toStringz(name));
  262. if(!proto)
  263. return false;
  264. populate(proto);
  265. return true;
  266. }
  267. /** Returns false on failure */
  268. // Same as getprotobynumber().
  269. bool getProtocolByType(ProtocolType type)
  270. {
  271. protoent* proto;
  272. proto = getprotobynumber(type);
  273. if(!proto)
  274. return false;
  275. populate(proto);
  276. return true;
  277. }
  278. }
  279. unittest
  280. {
  281. Protocol proto = new Protocol;
  282. version (Windows)
  283. {
  284. // These fail, don't know why
  285. pragma(msg, " --- std.socket(" ~ __LINE__.stringof ~ ") broken test ---");
  286. }
  287. else
  288. {
  289. assert(proto.getProtocolByType(ProtocolType.TCP));
  290. //printf("About protocol TCP:\n\tName: %.*s\n", proto.name);
  291. // foreach(string s; proto.aliases)
  292. // {
  293. // printf("\tAlias: %.*s\n", s);
  294. // }
  295. assert(proto.name == "tcp");
  296. assert(proto.aliases.length == 1 && proto.aliases[0] == "TCP");
  297. }
  298. }
  299. /**
  300. * Service is a class for retrieving service information.
  301. */
  302. class Service
  303. {
  304. /** These members are populated when one of the following functions are called without failure: */
  305. string name;
  306. string[] aliases; /// ditto
  307. ushort port; /// ditto
  308. string protocolName; /// ditto
  309. void populate(servent* serv)
  310. {
  311. name = to!string(serv.s_name);
  312. port = ntohs(cast(ushort)serv.s_port);
  313. protocolName = to!string(serv.s_proto);
  314. int i;
  315. for(i = 0;; i++)
  316. {
  317. if(!serv.s_aliases[i])
  318. break;
  319. }
  320. if(i)
  321. {
  322. aliases = new string[i];
  323. for(i = 0; i != aliases.length; i++)
  324. {
  325. aliases[i] =
  326. to!string(serv.s_aliases[i]).idup;
  327. }
  328. }
  329. else
  330. {
  331. aliases = null;
  332. }
  333. }
  334. /**
  335. * If a protocol name is omitted, any protocol will be matched.
  336. * Returns: false on failure.
  337. */
  338. bool getServiceByName(string name, string protocolName)
  339. {
  340. servent* serv;
  341. serv = getservbyname(toStringz(name), toStringz(protocolName));
  342. if(!serv)
  343. return false;
  344. populate(serv);
  345. return true;
  346. }
  347. // Any protocol name will be matched.
  348. /// ditto
  349. bool getServiceByName(string name)
  350. {
  351. servent* serv;
  352. serv = getservbyname(toStringz(name), null);
  353. if(!serv)
  354. return false;
  355. populate(serv);
  356. return true;
  357. }
  358. /// ditto
  359. bool getServiceByPort(ushort port, string protocolName)
  360. {
  361. servent* serv;
  362. serv = getservbyport(port, toStringz(protocolName));
  363. if(!serv)
  364. return false;
  365. populate(serv);
  366. return true;
  367. }
  368. // Any protocol name will be matched.
  369. /// ditto
  370. bool getServiceByPort(ushort port)
  371. {
  372. servent* serv;
  373. serv = getservbyport(port, null);
  374. if(!serv)
  375. return false;
  376. populate(serv);
  377. return true;
  378. }
  379. }
  380. unittest
  381. {
  382. Service serv = new Service;
  383. if(serv.getServiceByName("epmap", "tcp"))
  384. {
  385. // printf("About service epmap:\n\tService: %.*s\n"
  386. // "\tPort: %d\n\tProtocol: %.*s\n",
  387. // serv.name, serv.port, serv.protocolName);
  388. // foreach(string s; serv.aliases)
  389. // {
  390. // printf("\tAlias: %.*s\n", s);
  391. // }
  392. // For reasons unknown this is loc-srv on Wine and epmap on Windows
  393. assert(serv.name == "loc-srv" || serv.name == "epmap", serv.name);
  394. assert(serv.port == 135);
  395. assert(serv.protocolName == "tcp");
  396. // This assert used to pass, don't know why it fails now
  397. //assert(serv.aliases.length == 1 && serv.aliases[0] == "epmap");
  398. }
  399. else
  400. {
  401. printf("No service for epmap.\n");
  402. }
  403. }
  404. /**
  405. * Base exception thrown from an InternetHost.
  406. */
  407. class HostException: Exception
  408. {
  409. int errorCode; /// Platform-specific error code.
  410. this(string msg, int err = 0)
  411. {
  412. errorCode = err;
  413. super(msg);
  414. }
  415. }
  416. /**
  417. * InternetHost is a class for resolving IPv4 addresses.
  418. */
  419. class InternetHost
  420. {
  421. /** These members are populated when one of the following functions are called without failure: */
  422. string name;
  423. string[] aliases; /// ditto
  424. uint32_t[] addrList; /// ditto
  425. void validHostent(hostent* he)
  426. {
  427. if(he.h_addrtype != cast(int)AddressFamily.INET || he.h_length != 4)
  428. throw new HostException("Address family mismatch", _lasterr());
  429. }
  430. void populate(hostent* he)
  431. {
  432. int i;
  433. char* p;
  434. name = to!string(he.h_name).idup;
  435. for(i = 0;; i++)
  436. {
  437. p = he.h_aliases[i];
  438. if(!p)
  439. break;
  440. }
  441. if(i)
  442. {
  443. aliases = new string[i];
  444. for(i = 0; i != aliases.length; i++)
  445. {
  446. aliases[i] =
  447. to!string(he.h_aliases[i]).idup;
  448. }
  449. }
  450. else
  451. {
  452. aliases = null;
  453. }
  454. for(i = 0;; i++)
  455. {
  456. p = he.h_addr_list[i];
  457. if(!p)
  458. break;
  459. }
  460. if(i)
  461. {
  462. addrList = new uint32_t[i];
  463. for(i = 0; i != addrList.length; i++)
  464. {
  465. addrList[i] = ntohl(*(cast(uint32_t*)he.h_addr_list[i]));
  466. }
  467. }
  468. else
  469. {
  470. addrList = null;
  471. }
  472. }
  473. /**
  474. * Resolve host name. Returns false if unable to resolve.
  475. */
  476. bool getHostByName(string name)
  477. {
  478. version(Windows)
  479. {
  480. // TODO gethostbyname is deprecated in windows, use getaddrinfo
  481. auto he = gethostbyname(toStringz(name));
  482. if(!he)
  483. return false;
  484. validHostent(he);
  485. populate(he);
  486. }
  487. else
  488. {
  489. // posix systems use global state for return value, so we
  490. // must synchronize across all threads
  491. synchronized(this.classinfo)
  492. {
  493. auto he = gethostbyname(toStringz(name));
  494. if(!he)
  495. return false;
  496. validHostent(he);
  497. populate(he);
  498. }
  499. }
  500. return true;
  501. }
  502. /**
  503. * Resolve IPv4 address number. Returns false if unable to resolve.
  504. *
  505. * Params:
  506. * addr = The IPv4 address to resolve, in network byte order.
  507. */
  508. bool getHostByAddr(uint addr)
  509. {
  510. uint x = htonl(addr);
  511. version(Windows)
  512. {
  513. // TODO gethostbyaddr is deprecated in windows, use getnameinfo
  514. auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
  515. if(!he)
  516. return false;
  517. validHostent(he);
  518. populate(he);
  519. }
  520. else
  521. {
  522. // posix systems use global state for return value, so we
  523. // must synchronize across all threads
  524. synchronized(this.classinfo)
  525. {
  526. auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
  527. if(!he)
  528. return false;
  529. validHostent(he);
  530. populate(he);
  531. }
  532. }
  533. return true;
  534. }
  535. /**
  536. * Same as previous, but addr is an IPv4 address string in the
  537. * dotted-decimal form $(I a.b.c.d).
  538. * Returns false if unable to resolve.
  539. */
  540. bool getHostByAddr(string addr)
  541. {
  542. uint x = inet_addr(std.string.toStringz(addr));
  543. version(Windows)
  544. {
  545. // TODO gethostbyaddr is deprecated in windows, use getnameinfo
  546. auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
  547. if(!he)
  548. return false;
  549. validHostent(he);
  550. populate(he);
  551. }
  552. else
  553. {
  554. // posix systems use global state for return value, so we
  555. // must synchronize across all threads
  556. synchronized(this.classinfo)
  557. {
  558. auto he = gethostbyaddr(&x, 4, cast(int)AddressFamily.INET);
  559. if(!he)
  560. return false;
  561. validHostent(he);
  562. populate(he);
  563. }
  564. }
  565. return true;
  566. }
  567. }
  568. unittest
  569. {
  570. try
  571. {
  572. InternetHost ih = new InternetHost;
  573. if (!ih.getHostByName("www.digitalmars.com"))
  574. return; // don't fail if not connected to internet
  575. //printf("addrList.length = %d\n", ih.addrList.length);
  576. assert(ih.addrList.length);
  577. InternetAddress ia = new InternetAddress(ih.addrList[0], InternetAddress.PORT_ANY);
  578. assert(ih.name == "www.digitalmars.com" || ih.name == "digitalmars.com",
  579. ih.name);
  580. // printf("IP address = %.*s\nname = %.*s\n", ia.toAddrString(), ih.name);
  581. // foreach(int i, string s; ih.aliases)
  582. // {
  583. // printf("aliases[%d] = %.*s\n", i, s);
  584. // }
  585. // printf("---\n");
  586. assert(ih.getHostByAddr(ih.addrList[0]));
  587. // printf("name = %.*s\n", ih.name);
  588. // foreach(int i, string s; ih.aliases)
  589. // {
  590. // printf("aliases[%d] = %.*s\n", i, s);
  591. // }
  592. }
  593. catch (Throwable e)
  594. {
  595. // Test fails or succeeds depending on environment!
  596. printf(" --- std.socket(%u) broken test ---\n", __LINE__);
  597. printf(" (%.*s)\n", e.toString());
  598. }
  599. }
  600. /**
  601. * Base exception thrown from an Address.
  602. */
  603. class AddressException: Exception
  604. {
  605. this(string msg)
  606. {
  607. super(msg);
  608. }
  609. }
  610. /**
  611. * Address is an abstract class for representing a network addresses.
  612. */
  613. abstract class Address
  614. {
  615. protected sockaddr* name();
  616. protected int nameLen();
  617. AddressFamily addressFamily(); /// Family of this address.
  618. override string toString(); /// Human readable string representing this address.
  619. }
  620. /**
  621. *
  622. */
  623. class UnknownAddress: Address
  624. {
  625. protected:
  626. sockaddr sa;
  627. override sockaddr* name()
  628. {
  629. return &sa;
  630. }
  631. override int nameLen()
  632. {
  633. return sa.sizeof;
  634. }
  635. public:
  636. override AddressFamily addressFamily()
  637. {
  638. return cast(AddressFamily)sa.sa_family;
  639. }
  640. override string toString()
  641. {
  642. return "Unknown";
  643. }
  644. }
  645. /**
  646. * InternetAddress is a class that represents an IPv4 (internet protocol version
  647. * 4) address and port.
  648. */
  649. class InternetAddress: Address
  650. {
  651. protected:
  652. sockaddr_in sin;
  653. override sockaddr* name()
  654. {
  655. return cast(sockaddr*)&sin;
  656. }
  657. override int nameLen()
  658. {
  659. return sin.sizeof;
  660. }
  661. this()
  662. {
  663. }
  664. public:
  665. enum uint ADDR_ANY = INADDR_ANY; /// Any IPv4 address number.
  666. enum uint ADDR_NONE = INADDR_NONE; /// An invalid IPv4 address number.
  667. enum ushort PORT_ANY = 0; /// Any IPv4 port number.
  668. /// Overridden to return AddressFamily.INET.
  669. override AddressFamily addressFamily()
  670. {
  671. return cast(AddressFamily)AddressFamily.INET;
  672. }
  673. /// Returns the IPv4 port number.
  674. ushort port()
  675. {
  676. return ntohs(sin.sin_port);
  677. }
  678. /// Returns the IPv4 address number.
  679. uint addr()
  680. {
  681. return ntohl(sin.sin_addr.s_addr);
  682. }
  683. /**
  684. * Params:
  685. * addr = an IPv4 address string in the dotted-decimal form a.b.c.d,
  686. * or a host name that will be resolved using an InternetHost
  687. * object.
  688. * port = may be PORT_ANY as stated below.
  689. */
  690. this(string addr, ushort port)
  691. {
  692. uint uiaddr = parse(addr);
  693. if(ADDR_NONE == uiaddr)
  694. {
  695. InternetHost ih = new InternetHost;
  696. if(!ih.getHostByName(addr))
  697. //throw new AddressException("Invalid internet address");
  698. throw new AddressException(
  699. "Unable to resolve host '" ~ addr ~ "'");
  700. uiaddr = ih.addrList[0];
  701. }
  702. sin.sin_family = AddressFamily.INET;
  703. sin.sin_addr.s_addr = htonl(uiaddr);
  704. sin.sin_port = htons(port);
  705. }
  706. /**
  707. * Construct a new Address. addr may be ADDR_ANY (default) and port may
  708. * be PORT_ANY, and the actual numbers may not be known until a connection
  709. * is made.
  710. */
  711. this(uint addr, ushort port)
  712. {
  713. sin.sin_family = AddressFamily.INET;
  714. sin.sin_addr.s_addr = htonl(addr);
  715. sin.sin_port = htons(port);
  716. }
  717. /// ditto
  718. this(ushort port)
  719. {
  720. sin.sin_family = AddressFamily.INET;
  721. sin.sin_addr.s_addr = 0; //any, "0.0.0.0"
  722. sin.sin_port = htons(port);
  723. }
  724. /// Human readable string representing the IPv4 address in dotted-decimal form.
  725. string toAddrString()
  726. {
  727. return to!string(inet_ntoa(sin.sin_addr)).idup;
  728. }
  729. /// Human readable string representing the IPv4 port.
  730. string toPortString()
  731. {
  732. return std.conv.to!string(port());
  733. }
  734. /*
  735. * Returns the host name as a fully qualified domain name, if
  736. * available, or the IP address in dotted-decimal notation otherwise.
  737. */
  738. string toHostNameString()
  739. {
  740. // getnameinfo() is the recommended way to perform a reverse (name)
  741. // lookup on both Posix and Windows. However, it is only available
  742. // on Windows XP and above, and not included with the WinSock import
  743. // libraries shipped with DMD. Thus, we check for getnameinfo at
  744. // runtime in the shared module constructor, and fall back to the
  745. // deprecated getHostByAddr() if it could not be found. See also:
  746. // http://technet.microsoft.com/en-us/library/aa450403.aspx
  747. if (getnameinfoPointer is null)
  748. {
  749. auto host = new InternetHost();
  750. enforce(host.getHostByAddr(sin.sin_addr.s_addr),
  751. new SocketException("Could not get host name."));
  752. return host.name;
  753. }
  754. auto buf = new char[NI_MAXHOST];
  755. auto rc = getnameinfoPointer(cast(sockaddr*)&sin, sin.sizeof,
  756. buf.ptr, cast(uint)buf.length, null, 0, 0);
  757. enforce(rc == 0, new SocketException(
  758. "Could not get host name", _lasterr()));
  759. return assumeUnique(buf[0 .. strlen(buf.ptr)]);
  760. }
  761. /// Human readable string representing the IPv4 address and port in the form $(I a.b.c.d:e).
  762. override string toString()
  763. {
  764. return toAddrString() ~ ":" ~ toPortString();
  765. }
  766. /**
  767. * Parse an IPv4 address string in the dotted-decimal form $(I a.b.c.d)
  768. * and return the number.
  769. * If the string is not a legitimate IPv4 address,
  770. * ADDR_NONE is returned.
  771. */
  772. static uint parse(string addr)
  773. {
  774. return ntohl(inet_addr(std.string.toStringz(addr)));
  775. }
  776. }
  777. unittest
  778. {
  779. try
  780. {
  781. InternetAddress ia = new InternetAddress("63.105.9.61", 80);
  782. assert(ia.toString() == "63.105.9.61:80");
  783. }
  784. catch (Throwable e)
  785. {
  786. printf(" --- std.socket(%u) broken test ---\n", __LINE__);
  787. printf(" (%.*s)\n", e.toString());
  788. }
  789. }
  790. /** */
  791. class SocketAcceptException: SocketException
  792. {
  793. this(string msg, int err = 0)
  794. {
  795. super(msg, err);
  796. }
  797. }
  798. /// How a socket is shutdown:
  799. enum SocketShutdown: int
  800. {
  801. RECEIVE = SD_RECEIVE, /// socket receives are disallowed
  802. SEND = SD_SEND, /// socket sends are disallowed
  803. BOTH = SD_BOTH, /// both RECEIVE and SEND
  804. }
  805. /// Flags may be OR'ed together:
  806. enum SocketFlags: int
  807. {
  808. NONE = 0, /// no flags specified
  809. OOB = MSG_OOB, /// out-of-band stream data
  810. PEEK = MSG_PEEK, /// peek at incoming data without removing it from the queue, only for receiving
  811. DONTROUTE = MSG_DONTROUTE, /// data should not be subject to routing; this flag may be ignored. Only for sending
  812. }
  813. /// Duration timeout value.
  814. extern(C) struct timeval
  815. {
  816. // D interface
  817. c_long seconds; /// Number of seconds.
  818. c_long microseconds; /// Number of additional microseconds.
  819. // C interface
  820. deprecated
  821. {
  822. alias seconds tv_sec;
  823. alias microseconds tv_usec;
  824. }
  825. }
  826. /// A collection of sockets for use with Socket.select.
  827. class SocketSet
  828. {
  829. private:
  830. uint maxsockets; /// max desired sockets, the fd_set might be capable of holding more
  831. fd_set set;
  832. version(Win32)
  833. {
  834. uint count()
  835. {
  836. return set.fd_count;
  837. }
  838. }
  839. else version(BsdSockets)
  840. {
  841. int maxfd;
  842. uint count;
  843. }
  844. public:
  845. /// Set the maximum amount of sockets that may be added.
  846. this(uint max)
  847. {
  848. maxsockets = max;
  849. reset();
  850. }
  851. /// Uses the default maximum for the system.
  852. this()
  853. {
  854. this(FD_SETSIZE);
  855. }
  856. /// Reset the SocketSet so that there are 0 Sockets in the collection.
  857. void reset()
  858. {
  859. FD_ZERO(&set);
  860. version(BsdSockets)
  861. {
  862. maxfd = -1;
  863. count = 0;
  864. }
  865. }
  866. void add(socket_t s)
  867. in
  868. {
  869. // Make sure too many sockets don't get added.
  870. assert(count < maxsockets);
  871. }
  872. body
  873. {
  874. FD_SET(s, &set);
  875. version(BsdSockets)
  876. {
  877. ++count;
  878. if(s > maxfd)
  879. maxfd = s;
  880. }
  881. }
  882. /// Add a Socket to the collection. Adding more than the maximum has dangerous side affects.
  883. void add(Socket s)
  884. {
  885. add(s.sock);
  886. }
  887. void remove(socket_t s)
  888. {
  889. FD_CLR(s, &set);
  890. version(BsdSockets)
  891. {
  892. --count;
  893. // note: adjusting maxfd would require scanning the set, not worth it
  894. }
  895. }
  896. /// Remove this Socket from the collection.
  897. void remove(Socket s)
  898. {
  899. remove(s.sock);
  900. }
  901. int isSet(socket_t s)
  902. {
  903. return FD_ISSET(s, &set);
  904. }
  905. /// Returns nonzero if this Socket is in the collection.
  906. int isSet(Socket s)
  907. {
  908. return isSet(s.sock);
  909. }
  910. /// Return maximum amount of sockets that can be added, like FD_SETSIZE.
  911. uint max()
  912. {
  913. return maxsockets;
  914. }
  915. fd_set* toFd_set()
  916. {
  917. return &set;
  918. }
  919. int selectn()
  920. {
  921. version(Win32)
  922. {
  923. return count;
  924. }
  925. else version(BsdSockets)
  926. {
  927. return maxfd + 1;
  928. }
  929. }
  930. }
  931. /// The level at which a socket option is defined:
  932. enum SocketOptionLevel: int
  933. {
  934. SOCKET = SOL_SOCKET, /// socket level
  935. IP = ProtocolType.IP, /// internet protocol version 4 level
  936. ICMP = ProtocolType.ICMP, ///
  937. IGMP = ProtocolType.IGMP, ///
  938. GGP = ProtocolType.GGP, ///
  939. TCP = ProtocolType.TCP, /// transmission control protocol level
  940. PUP = ProtocolType.PUP, ///
  941. UDP = ProtocolType.UDP, /// user datagram protocol level
  942. IDP = ProtocolType.IDP, ///
  943. IPV6 = ProtocolType.IPV6, /// internet protocol version 6 level
  944. }
  945. /// Linger information for use with SocketOption.LINGER.
  946. extern(C) struct linger
  947. {
  948. // D interface
  949. version(Win32)
  950. {
  951. uint16_t on; /// Nonzero for on.
  952. uint16_t time; /// Linger time.
  953. }
  954. else version(BsdSockets)
  955. {
  956. int32_t on;
  957. int32_t time;
  958. }
  959. // C interface
  960. deprecated
  961. {
  962. alias on l_onoff;
  963. alias time l_linger;
  964. }
  965. }
  966. /// Specifies a socket option:
  967. enum SocketOption: int
  968. {
  969. DEBUG = SO_DEBUG, /// record debugging information
  970. BROADCAST = SO_BROADCAST, /// allow transmission of broadcast messages
  971. REUSEADDR = SO_REUSEADDR, /// allow local reuse of address
  972. LINGER = SO_LINGER, /// linger on close if unsent data is present
  973. OOBINLINE = SO_OOBINLINE, /// receive out-of-band data in band
  974. SNDBUF = SO_SNDBUF, /// send buffer size
  975. RCVBUF = SO_RCVBUF, /// receive buffer size
  976. DONTROUTE = SO_DONTROUTE, /// do not route
  977. SNDTIMEO = SO_SNDTIMEO, /// send timeout
  978. RCVTIMEO = SO_RCVTIMEO, /// receive timeout
  979. // SocketOptionLevel.TCP:
  980. TCP_NODELAY = .TCP_NODELAY, /// disable the Nagle algorithm for send coalescing
  981. // SocketOptionLevel.IPV6:
  982. IPV6_UNICAST_HOPS = .IPV6_UNICAST_HOPS, ///
  983. IPV6_MULTICAST_IF = .IPV6_MULTICAST_IF, ///
  984. IPV6_MULTICAST_LOOP = .IPV6_MULTICAST_LOOP, ///
  985. IPV6_JOIN_GROUP = .IPV6_JOIN_GROUP, ///
  986. IPV6_LEAVE_GROUP = .IPV6_LEAVE_GROUP, ///
  987. }
  988. /**
  989. * Socket is a class that creates a network communication endpoint using the
  990. * Berkeley sockets interface.
  991. */
  992. class Socket
  993. {
  994. private:
  995. socket_t sock;
  996. AddressFamily _family;
  997. version(Win32)
  998. bool _blocking = false; /// Property to get or set whether the socket is blocking or nonblocking.
  999. // The WinSock timeouts seem to be effectively skewed by a constant
  1000. // offset of about half a second (value in milliseconds). This has
  1001. // been confirmed on updated (as of Jun 2011) Windows XP, Windows 7
  1002. // and Windows Server 2008 R2 boxes.
  1003. enum WINSOCK_TIMEOUT_SKEW = 500;
  1004. void setSock(socket_t handle)
  1005. {
  1006. assert(handle != socket_t.init);
  1007. sock = handle;
  1008. // Set the option to disable SIGPIPE on send() if the platform
  1009. // has it (e.g. on OS X).
  1010. static if (is(typeof(SO_NOSIGPIPE)))
  1011. {
  1012. setOption(SocketOptionLevel.SOCKET, cast(SocketOption)SO_NOSIGPIPE, true);
  1013. }
  1014. }
  1015. // For use with accepting().
  1016. protected this()
  1017. {
  1018. }
  1019. public:
  1020. /**
  1021. * Create a blocking socket. If a single protocol type exists to support
  1022. * this socket type within the address family, the ProtocolType may be
  1023. * omitted.
  1024. */
  1025. this(AddressFamily af, SocketType type, ProtocolType protocol)
  1026. {
  1027. _family = af;
  1028. auto handle = cast(socket_t) socket(af, type, protocol);
  1029. if(handle == socket_t.init)
  1030. throw new SocketException("Unable to create socket", _lasterr());
  1031. setSock(handle);
  1032. }
  1033. // A single protocol exists to support this socket type within the
  1034. // protocol family, so the ProtocolType is assumed.
  1035. /// ditto
  1036. this(AddressFamily af, SocketType type)
  1037. {
  1038. this(af, type, cast(ProtocolType)0); // Pseudo protocol number.
  1039. }
  1040. /// ditto
  1041. this(AddressFamily af, SocketType type, string protocolName)
  1042. {
  1043. protoent* proto;
  1044. proto = getprotobyname(toStringz(protocolName));
  1045. if(!proto)
  1046. throw new SocketException("Unable to find the protocol", _lasterr());
  1047. this(af, type, cast(ProtocolType)proto.p_proto);
  1048. }
  1049. ~this()
  1050. {
  1051. close();
  1052. }
  1053. /// Get underlying socket handle.
  1054. socket_t handle()
  1055. {
  1056. return sock;
  1057. }
  1058. /**
  1059. * Get/set socket's blocking flag.
  1060. *
  1061. * When a socket is blocking, calls to receive(), accept(), and send()
  1062. * will block and wait for data/action.
  1063. * A non-blocking socket will immediately return instead of blocking.
  1064. */
  1065. bool blocking()
  1066. {
  1067. version(Win32)
  1068. {
  1069. return _blocking;
  1070. }
  1071. else version(BsdSockets)
  1072. {
  1073. return !(fcntl(handle, F_GETFL, 0) & O_NONBLOCK);
  1074. }
  1075. }
  1076. /// ditto
  1077. void blocking(bool byes)
  1078. {
  1079. version(Win32)
  1080. {
  1081. uint num = !byes;
  1082. if(_SOCKET_ERROR == ioctlsocket(sock, FIONBIO, &num))
  1083. goto err;
  1084. _blocking = byes;
  1085. }
  1086. else version(BsdSockets)
  1087. {
  1088. int x = fcntl(sock, F_GETFL, 0);
  1089. if(-1 == x)
  1090. goto err;
  1091. if(byes)
  1092. x &= ~O_NONBLOCK;
  1093. else
  1094. x |= O_NONBLOCK;
  1095. if(-1 == fcntl(sock, F_SETFL, x))
  1096. goto err;
  1097. }
  1098. return; // Success.
  1099. err:
  1100. throw new SocketException("Unable to set socket blocking", _lasterr());
  1101. }
  1102. /// Get the socket's address family.
  1103. AddressFamily addressFamily() // getter
  1104. {
  1105. return _family;
  1106. }
  1107. /// Property that indicates if this is a valid, alive socket.
  1108. bool isAlive() // getter
  1109. {
  1110. int type;
  1111. socklen_t typesize = cast(socklen_t) type.sizeof;
  1112. return !getsockopt(sock, SOL_SOCKET, SO_TYPE, cast(char*)&type, &typesize);
  1113. }
  1114. /// Associate a local address with this socket.
  1115. void bind(Address addr)
  1116. {
  1117. if(_SOCKET_ERROR == .bind(sock, addr.name(), addr.nameLen()))
  1118. throw new SocketException("Unable to bind socket", _lasterr());
  1119. }
  1120. /**
  1121. * Establish a connection. If the socket is blocking, connect waits for
  1122. * the connection to be made. If the socket is nonblocking, connect
  1123. * returns immediately and the connection attempt is still in progress.
  1124. */
  1125. void connect(Address to)
  1126. {
  1127. if(_SOCKET_ERROR == .connect(sock, to.name(), to.nameLen()))
  1128. {
  1129. int err;
  1130. err = _lasterr();
  1131. if(!blocking)
  1132. {
  1133. version(Win32)
  1134. {
  1135. if(WSAEWOULDBLOCK == err)
  1136. return;
  1137. }
  1138. else version(Posix)
  1139. {
  1140. if(EINPROGRESS == err)
  1141. return;
  1142. }
  1143. else
  1144. {
  1145. static assert(0);
  1146. }
  1147. }
  1148. throw new SocketException("Unable to connect socket", err);
  1149. }
  1150. }
  1151. /**
  1152. * Listen for an incoming connection. bind must be called before you can
  1153. * listen. The backlog is a request of how many pending incoming
  1154. * connections are queued until accept'ed.
  1155. */
  1156. void listen(int backlog)
  1157. {
  1158. if(_SOCKET_ERROR == .listen(sock, backlog))
  1159. throw new SocketException("Unable to listen on socket", _lasterr());
  1160. }
  1161. /**
  1162. * Called by accept when a new Socket must be created for a new
  1163. * connection. To use a derived class, override this method and return an
  1164. * instance of your class. The returned Socket's handle must not be set;
  1165. * Socket has a protected constructor this() to use in this situation.
  1166. */
  1167. // Override to use a derived class.
  1168. // The returned socket's handle must not be set.
  1169. protected Socket accepting()
  1170. {
  1171. return new Socket;
  1172. }
  1173. /**
  1174. * Accept an incoming connection. If the socket is blocking, accept
  1175. * waits for a connection request. Throws SocketAcceptException if unable
  1176. * to accept. See accepting for use with derived classes.
  1177. */
  1178. Socket accept()
  1179. {
  1180. auto newsock = cast(socket_t).accept(sock, null, null);
  1181. if(socket_t.init == newsock)
  1182. throw new SocketAcceptException("Unable to accept socket connection", _lasterr());
  1183. Socket newSocket;
  1184. try
  1185. {
  1186. newSocket = accepting();
  1187. assert(newSocket.sock == socket_t.init);
  1188. newSocket.setSock(newsock);
  1189. version(Win32)
  1190. newSocket._blocking = _blocking; //inherits blocking mode
  1191. newSocket._family = _family; //same family
  1192. }
  1193. catch(Throwable o)
  1194. {
  1195. _close(newsock);
  1196. throw o;
  1197. }
  1198. return newSocket;
  1199. }
  1200. /// Disables sends and/or receives.
  1201. void shutdown(SocketShutdown how)
  1202. {
  1203. .shutdown(sock, cast(int)how);
  1204. }
  1205. private static void _close(socket_t sock)
  1206. {
  1207. version(Win32)
  1208. {
  1209. .closesocket(sock);
  1210. }
  1211. else version(BsdSockets)
  1212. {
  1213. .close(sock);
  1214. }
  1215. }
  1216. /**
  1217. * Immediately drop any connections and release socket resources.
  1218. * Calling shutdown before close is recommended for connection-oriented
  1219. * sockets. The Socket object is no longer usable after close.
  1220. */
  1221. //calling shutdown() before this is recommended
  1222. //for connection-oriented sockets
  1223. void close()
  1224. {
  1225. _close(sock);
  1226. sock = socket_t.init;
  1227. }
  1228. private Address newFamilyObject()
  1229. {
  1230. Address result;
  1231. switch(_family)
  1232. {
  1233. case cast(AddressFamily)AddressFamily.INET:
  1234. result = new InternetAddress;
  1235. break;
  1236. default:
  1237. result = new UnknownAddress;
  1238. }
  1239. return result;
  1240. }
  1241. /// Returns the local machine's host name. Idea from mango.
  1242. static string hostName() // getter
  1243. {
  1244. char[256] result; // Host names are limited to 255 chars.
  1245. if(_SOCKET_ERROR == .gethostname(result.ptr, result.length))
  1246. throw new SocketException("Unable to obtain host name", _lasterr());
  1247. return to!string(cast(char*)result).idup;
  1248. }
  1249. /// Remote endpoint Address.
  1250. Address remoteAddress()
  1251. {
  1252. Address addr = newFamilyObject();
  1253. socklen_t nameLen = cast(socklen_t) addr.nameLen();
  1254. if(_SOCKET_ERROR == .getpeername(sock, addr.name(), &nameLen))
  1255. throw new SocketException("Unable to obtain remote socket address", _lasterr());
  1256. assert(addr.addressFamily() == _family);
  1257. return addr;
  1258. }
  1259. /// Local endpoint Address.
  1260. Address localAddress()
  1261. {
  1262. Address addr = newFamilyObject();
  1263. socklen_t nameLen = cast(socklen_t) addr.nameLen();
  1264. if(_SOCKET_ERROR == .getsockname(sock, addr.name(), &nameLen))
  1265. throw new SocketException("Unable to obtain local socket address", _lasterr());
  1266. assert(addr.addressFamily() == _family);
  1267. return addr;
  1268. }
  1269. /// Send or receive error code.
  1270. enum int ERROR = _SOCKET_ERROR;
  1271. /**
  1272. * Send data on the connection. Returns the number of bytes actually
  1273. * sent, or ERROR on failure. If the socket is blocking and there is no
  1274. * buffer space left, send waits.
  1275. */
  1276. //returns number of bytes actually sent, or -1 on error
  1277. Select!(size_t.sizeof > 4, long, int)
  1278. send(const(void)[] buf, SocketFlags flags)
  1279. {
  1280. static if (is(typeof(MSG_NOSIGNAL)))
  1281. {
  1282. flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
  1283. }
  1284. version( Windows )
  1285. auto sent = .send(sock, buf.ptr, to!int(buf.length), cast(int)flags);
  1286. else
  1287. auto sent = .send(sock, buf.ptr, buf.length, cast(int)flags);
  1288. return sent;
  1289. }
  1290. /// ditto
  1291. Select!(size_t.sizeof > 4, long, int) send(const(void)[] buf)
  1292. {
  1293. return send(buf, SocketFlags.NONE);
  1294. }
  1295. /**
  1296. * Send data to a specific destination Address. If the destination address is not specified, a connection must have been made and that address is used. If the socket is blocking and there is no buffer space left, sendTo waits.
  1297. */
  1298. Select!(size_t.sizeof > 4, long, int)
  1299. sendTo(const(void)[] buf, SocketFlags flags, Address to)
  1300. {
  1301. static if (is(typeof(MSG_NOSIGNAL)))
  1302. {
  1303. flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
  1304. }
  1305. version( Windows )
  1306. return .sendto(
  1307. sock, buf.ptr, std.conv.to!int(buf.length),
  1308. cast(int)flags, to.name(), to.nameLen()
  1309. );
  1310. else
  1311. return .sendto(sock, buf.ptr, buf.length, cast(int)flags, to.name(), to.nameLen());
  1312. }
  1313. /// ditto
  1314. Select!(size_t.sizeof > 4, long, int) sendTo(const(void)[] buf, Address to)
  1315. {
  1316. return sendTo(buf, SocketFlags.NONE, to);
  1317. }
  1318. //assumes you connect()ed
  1319. /// ditto
  1320. Select!(size_t.sizeof > 4, long, int) sendTo(const(void)[] buf, SocketFlags flags)
  1321. {
  1322. static if (is(typeof(MSG_NOSIGNAL)))
  1323. {
  1324. flags = cast(SocketFlags)(flags | MSG_NOSIGNAL);
  1325. }
  1326. version(Windows)
  1327. return .sendto(sock, buf.ptr, to!int(buf.length), cast(int)flags, null, 0);
  1328. else
  1329. return .sendto(sock, buf.ptr, buf.length, cast(int)flags, null, 0);
  1330. }
  1331. //assumes you connect()ed
  1332. /// ditto
  1333. Select!(size_t.sizeof > 4, long, int) sendTo(const(void)[] buf)
  1334. {
  1335. return sendTo(buf, SocketFlags.NONE);
  1336. }
  1337. /**
  1338. * Receive data on the connection. Returns the number of bytes actually
  1339. * received, 0 if the remote side has closed the connection, or ERROR on
  1340. * failure. If the socket is blocking, receive waits until there is data
  1341. * to be received.
  1342. */
  1343. //returns number of bytes actually received, 0 on connection closure, or -1 on error
  1344. ptrdiff_t receive(void[] buf, SocketFlags flags)
  1345. {
  1346. version(Win32) // Does not use size_t
  1347. {
  1348. return buf.length
  1349. ? .recv(sock, buf.ptr, to!int(buf.length), cast(int)flags)
  1350. : 0;
  1351. } else {
  1352. return buf.length
  1353. ? .recv(sock, buf.ptr, buf.length, cast(int)flags)
  1354. : 0;
  1355. }
  1356. }
  1357. /// ditto
  1358. ptrdiff_t receive(void[] buf)
  1359. {
  1360. return receive(buf, SocketFlags.NONE);
  1361. }
  1362. /**
  1363. * Receive data and get the remote endpoint Address.
  1364. * If the socket is blocking, receiveFrom waits until there is data to
  1365. * be received.
  1366. * Returns: the number of bytes actually received,
  1367. * 0 if the remote side has closed the connection, or ERROR on failure.
  1368. */
  1369. Select!(size_t.sizeof > 4, long, int)
  1370. receiveFrom(void[] buf, SocketFlags flags, out Address from)
  1371. {
  1372. if(!buf.length) //return 0 and don't think the connection closed
  1373. return 0;
  1374. from = newFamilyObject();
  1375. socklen_t nameLen = cast(socklen_t) from.nameLen();
  1376. version(Win32)
  1377. {
  1378. auto read = .recvfrom(sock, buf.ptr, to!int(buf.length), cast(int)flags, from.name(), &nameLen);
  1379. assert(from.addressFamily() == _family);
  1380. // if(!read) //connection closed
  1381. return read;
  1382. } else {
  1383. auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
  1384. assert(from.addressFamily() == _family);
  1385. // if(!read) //connection closed
  1386. return read;
  1387. }
  1388. }
  1389. /// ditto
  1390. ptrdiff_t receiveFrom(void[] buf, out Address from)
  1391. {
  1392. return receiveFrom(buf, SocketFlags.NONE, from);
  1393. }
  1394. //assumes you connect()ed
  1395. /// ditto
  1396. Select!(size_t.sizeof > 4, long, int)
  1397. receiveFrom(void[] buf, SocketFlags flags)
  1398. {
  1399. if(!buf.length) //return 0 and don't think the connection closed
  1400. return 0;
  1401. version(Win32)
  1402. {
  1403. auto read = .recvfrom(sock, buf.ptr, to!int(buf.length), cast(int)flags, null, null);
  1404. // if(!read) //connection closed
  1405. return read;
  1406. } else {
  1407. auto read = .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
  1408. // if(!read) //connection closed
  1409. return read;
  1410. }
  1411. }
  1412. //assumes you connect()ed
  1413. /// ditto
  1414. ptrdiff_t receiveFrom(void[] buf)
  1415. {
  1416. return receiveFrom(buf, SocketFlags.NONE);
  1417. }
  1418. /// Get a socket option. Returns the number of bytes written to result.
  1419. //returns the length, in bytes, of the actual result - very different from getsockopt()
  1420. int getOption(SocketOptionLevel level, SocketOption option, void[] result)
  1421. {
  1422. socklen_t len = cast(socklen_t) result.length;
  1423. if(_SOCKET_ERROR == .getsockopt(sock, cast(int)level, cast(int)option, result.ptr, &len))
  1424. throw new SocketException("Unable to get socket option", _lasterr());
  1425. return len;
  1426. }
  1427. /// Common case of getting integer and boolean options.
  1428. int getOption(SocketOptionLevel level, SocketOption option, out int32_t result)
  1429. {
  1430. return getOption(level, option, (&result)[0 .. 1]);
  1431. }
  1432. /// Get the linger option.
  1433. int getOption(SocketOptionLevel level, SocketOption option, out linger result)
  1434. {
  1435. //return getOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&result)[0 .. 1]);
  1436. return getOption(level, option, (&result)[0 .. 1]);
  1437. }
  1438. /// Get a timeout (duration) option.
  1439. void getOption(SocketOptionLevel level, SocketOption option, out Duration result)
  1440. {
  1441. enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO,
  1442. new SocketException("Not a valid timeout option: " ~ to!string(option)));
  1443. // WinSock returns the timeout values as a milliseconds DWORD,
  1444. // while Linux and BSD return a timeval struct.
  1445. version (Win32)
  1446. {
  1447. int msecs;
  1448. getOption(level, option, (&msecs)[0 .. 1]);
  1449. if (option == SocketOption.RCVTIMEO)
  1450. msecs += WINSOCK_TIMEOUT_SKEW;
  1451. result = dur!"msecs"(msecs);
  1452. }
  1453. else version (BsdSockets)
  1454. {
  1455. timeval tv;
  1456. getOption(level, option, (&tv)[0..1]);
  1457. result = dur!"seconds"(tv.seconds) + dur!"usecs"(tv.microseconds);
  1458. }
  1459. else static assert(false);
  1460. }
  1461. // Set a socket option.
  1462. void setOption(SocketOptionLevel level, SocketOption option, void[] value)
  1463. {
  1464. if(_SOCKET_ERROR == .setsockopt(sock, cast(int)level,
  1465. cast(int)option, value.ptr, cast(uint) value.length))
  1466. throw new SocketException("Unable to set socket option", _lasterr());
  1467. }
  1468. /// Common case for setting integer and boolean options.
  1469. void setOption(SocketOptionLevel level, SocketOption option, int32_t value)
  1470. {
  1471. setOption(level, option, (&value)[0 .. 1]);
  1472. }
  1473. /// Set the linger option.
  1474. void setOption(SocketOptionLevel level, SocketOption option, linger value)
  1475. {
  1476. //setOption(cast(SocketOptionLevel)SocketOptionLevel.SOCKET, SocketOption.LINGER, (&value)[0 .. 1]);
  1477. setOption(level, option, (&value)[0 .. 1]);
  1478. }
  1479. /**
  1480. * Sets a timeout (duration) option, i.e. SocketOption.SNDTIMEO or
  1481. * RCVTIMEO. Zero indicates no timeout.
  1482. *
  1483. * In a typical application, you might also want to consider using
  1484. * a non-blocking socket instead of setting a timeout on a blocking one.
  1485. *
  1486. * Note: While the receive timeout setting is generally quite accurate
  1487. * on *nix systems even for smaller durations, there are two issues to
  1488. * be aware of on Windows: First, although undocumented, the effective
  1489. * timeout duration seems to be the one set on the socket plus half
  1490. * a second. setOption() tries to compensate for that, but still,
  1491. * timeouts under 500ms are not possible on Windows. Second, be aware
  1492. * that the actual amount of time spent until a blocking call returns
  1493. * randomly varies on the order of 10ms.
  1494. *
  1495. * Params:
  1496. * value = The timeout duration to set. Must not be negative.
  1497. *
  1498. * Throws: SocketException if setting the options fails.
  1499. *
  1500. * Example:
  1501. * ---
  1502. * import std.datetime;
  1503. * auto pair = socketPair();
  1504. * scope(exit) foreach (s; pair) s.close();
  1505. *
  1506. * // Set a receive timeout, and then wait at one end of
  1507. * // the socket pair, knowing that no data will arrive.
  1508. * pair[0].setOption(SocketOptionLevel.SOCKET,
  1509. * SocketOption.RCVTIMEO, dur!"seconds"(1));
  1510. *
  1511. * auto sw = StopWatch(AutoStart.yes);
  1512. * ubyte[1] buffer;
  1513. * pair[0].receive(buffer);
  1514. * writefln("Waited %s ms until the socket timed out.",
  1515. * sw.peek.msecs);
  1516. * ---
  1517. */
  1518. void setOption(SocketOptionLevel level, SocketOption option, Duration value)
  1519. {
  1520. enforce(option == SocketOption.SNDTIMEO || option == SocketOption.RCVTIMEO,
  1521. new SocketException("Not a valid timeout option: " ~ to!string(option)));
  1522. enforce(value >= dur!"hnsecs"(0), new SocketException(
  1523. "Timeout duration must not be negative."));
  1524. version (Win32)
  1525. {
  1526. auto msecs = cast(int)value.total!"msecs"();
  1527. if (msecs == 0 || option != SocketOption.RCVTIMEO)
  1528. {
  1529. setOption(level, option, msecs);
  1530. }
  1531. else
  1532. {
  1533. setOption(level, option, cast(int)
  1534. max(1, msecs - WINSOCK_TIMEOUT_SKEW));
  1535. }
  1536. }
  1537. else version (BsdSockets)
  1538. {
  1539. timeval tv = { seconds: cast(int)value.total!"seconds"(),
  1540. microseconds: value.fracSec.usecs };
  1541. setOption(level, option, (&tv)[0 .. 1]);
  1542. }
  1543. else static assert(false);
  1544. }
  1545. /**
  1546. * Wait for a socket to change status. A wait timeout timeval or int microseconds may be specified; if a ti…

Large files files are truncated, but you can click here to view the full file