PageRenderTime 27ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/tango/net/device/Berkeley.d

http://github.com/SiegeLord/Tango-D2
D | 2412 lines | 1396 code | 377 blank | 639 comment | 135 complexity | 8f0d84adfdab271ae6dbaa0bcc941d1b MD5 | raw file

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

  1. module tango.net.device.Berkeley;
  2. private import tango.sys.Common;
  3. private import tango.core.Exception;
  4. import consts=tango.sys.consts.socket;
  5. private import tango.stdc.string : strlen;
  6. private import tango.stdc.stringz;
  7. /*******************************************************************************
  8. *******************************************************************************/
  9. enum {SOCKET_ERROR = consts.SOCKET_ERROR}
  10. /*******************************************************************************
  11. *******************************************************************************/
  12. enum SocketOption
  13. {
  14. DEBUG = consts.SO_DEBUG , /* turn on debugging info recording */
  15. BROADCAST = consts.SO_BROADCAST , /* permit sending of broadcast msgs */
  16. REUSEADDR = consts.SO_REUSEADDR , /* allow local address reuse */
  17. LINGER = consts.SO_LINGER , /* linger on close if data present */
  18. DONTLINGER = ~(consts.SO_LINGER),
  19. OOBINLINE = consts.SO_OOBINLINE , /* leave received OOB data in line */
  20. ACCEPTCONN = consts.SO_ACCEPTCONN, /* socket has had listen() */
  21. KEEPALIVE = consts.SO_KEEPALIVE , /* keep connections alive */
  22. DONTROUTE = consts.SO_DONTROUTE , /* just use interface addresses */
  23. TYPE = consts.SO_TYPE , /* get socket type */
  24. /*
  25. * Additional options, not kept in so_options.
  26. */
  27. SNDBUF = consts.SO_SNDBUF, /* send buffer size */
  28. RCVBUF = consts.SO_RCVBUF, /* receive buffer size */
  29. ERROR = consts.SO_ERROR , /* get error status and clear */
  30. // OptionLevel.IP settings
  31. MULTICAST_TTL = consts.IP_MULTICAST_TTL ,
  32. MULTICAST_LOOP = consts.IP_MULTICAST_LOOP ,
  33. ADD_MEMBERSHIP = consts.IP_ADD_MEMBERSHIP ,
  34. DROP_MEMBERSHIP = consts.IP_DROP_MEMBERSHIP,
  35. // OptionLevel.TCP settings
  36. TCP_NODELAY = consts.TCP_NODELAY ,
  37. // Windows specifics
  38. WIN_UPDATE_ACCEPT_CONTEXT = 0x700B,
  39. WIN_CONNECT_TIME = 0x700C,
  40. WIN_UPDATE_CONNECT_CONTEXT = 0x7010,
  41. }
  42. /*******************************************************************************
  43. *******************************************************************************/
  44. enum SocketOptionLevel
  45. {
  46. SOCKET = consts.SOL_SOCKET ,
  47. IP = consts.IPPROTO_IP ,
  48. TCP = consts.IPPROTO_TCP ,
  49. UDP = consts.IPPROTO_UDP ,
  50. }
  51. /*******************************************************************************
  52. *******************************************************************************/
  53. enum SocketType
  54. {
  55. STREAM = consts.SOCK_STREAM , /++ sequential, reliable +/
  56. DGRAM = consts.SOCK_DGRAM , /++ connectionless unreliable, max length +/
  57. SEQPACKET = consts.SOCK_SEQPACKET, /++ sequential, reliable, max length +/
  58. }
  59. /*******************************************************************************
  60. *******************************************************************************/
  61. enum ProtocolType
  62. {
  63. IP = consts.IPPROTO_IP , /// default internet protocol (probably 4 for compatibility)
  64. IPV4 = consts.IPPROTO_IP , /// internet protocol version 4
  65. IPV6 = consts.IPPROTO_IPV6 , /// internet protocol version 6
  66. ICMP = consts.IPPROTO_ICMP , /// internet control message protocol
  67. IGMP = consts.IPPROTO_IGMP , /// internet group management protocol
  68. TCP = consts.IPPROTO_TCP , /// transmission control protocol
  69. PUP = consts.IPPROTO_PUP , /// PARC universal packet protocol
  70. UDP = consts.IPPROTO_UDP , /// user datagram protocol
  71. IDP = consts.IPPROTO_IDP , /// Xerox NS protocol
  72. }
  73. /*******************************************************************************
  74. *******************************************************************************/
  75. enum AddressFamily
  76. {
  77. UNSPEC = consts.AF_UNSPEC ,
  78. UNIX = consts.AF_UNIX ,
  79. INET = consts.AF_INET ,
  80. IPX = consts.AF_IPX ,
  81. APPLETALK = consts.AF_APPLETALK,
  82. INET6 = consts.AF_INET6 ,
  83. }
  84. /*******************************************************************************
  85. *******************************************************************************/
  86. enum SocketShutdown
  87. {
  88. RECEIVE = consts.SHUT_RD,
  89. SEND = consts.SHUT_WR,
  90. BOTH = consts.SHUT_RDWR,
  91. }
  92. /*******************************************************************************
  93. *******************************************************************************/
  94. enum SocketFlags
  95. {
  96. NONE = 0,
  97. OOB = consts.MSG_OOB, /// out of band
  98. PEEK = consts.MSG_PEEK, /// only for receiving
  99. DONTROUTE = consts.MSG_DONTROUTE, /// only for sending
  100. NOSIGNAL = 0x4000, /// inhibit signals
  101. }
  102. enum AIFlags: int
  103. {
  104. PASSIVE = consts.AI_PASSIVE, /// get address to use bind()
  105. CANONNAME = consts.AI_CANONNAME, /// fill ai_canonname
  106. NUMERICHOST = consts.AI_NUMERICHOST, /// prevent host name resolution
  107. NUMERICSERV = consts.AI_NUMERICSERV, /// prevent service name resolution valid
  108. /// flags for addrinfo (not a standard def,
  109. /// apps should not use it)
  110. ALL = consts.AI_ALL, /// IPv6 and IPv4-mapped (with AI_V4MAPPED)
  111. ADDRCONFIG = consts.AI_ADDRCONFIG, /// only if any address is assigned
  112. V4MAPPED = consts.AI_V4MAPPED, /// accept IPv4-mapped IPv6 address special
  113. /// recommended flags for getipnodebyname
  114. MASK = consts.AI_MASK,
  115. DEFAULT = consts.AI_DEFAULT,
  116. }
  117. enum AIError
  118. {
  119. BADFLAGS = consts.EAI_BADFLAGS, /// Invalid value for `ai_flags' field.
  120. NONAME = consts.EAI_NONAME, /// NAME or SERVICE is unknown.
  121. AGAIN = consts.EAI_AGAIN, /// Temporary failure in name resolution.
  122. FAIL = consts.EAI_FAIL, /// Non-recoverable failure in name res.
  123. NODATA = consts.EAI_NODATA, /// No address associated with NAME.
  124. FAMILY = consts.EAI_FAMILY, /// `ai_family' not supported.
  125. SOCKTYPE = consts.EAI_SOCKTYPE, /// `ai_socktype' not supported.
  126. SERVICE = consts.EAI_SERVICE, /// SERVICE not supported for `ai_socktype'.
  127. MEMORY = consts.EAI_MEMORY, /// Memory allocation failure.
  128. }
  129. enum NIFlags: int
  130. {
  131. MAXHOST = consts.NI_MAXHOST,
  132. MAXSERV = consts.NI_MAXSERV,
  133. NUMERICHOST = consts.NI_NUMERICHOST, /// Don't try to look up hostname.
  134. NUMERICSERV = consts.NI_NUMERICSERV, /// Don't convert port number to name.
  135. NOFQDN = consts.NI_NOFQDN, /// Only return nodename portion.
  136. NAMEREQD = consts.NI_NAMEREQD, /// Don't return numeric addresses.
  137. DGRAM = consts.NI_DGRAM, /// Look up UDP service rather than TCP.
  138. }
  139. /*******************************************************************************
  140. conversions for network byte-order
  141. *******************************************************************************/
  142. version(BigEndian)
  143. {
  144. private ushort htons (ushort x)
  145. {
  146. return x;
  147. }
  148. private uint htonl (uint x)
  149. {
  150. return x;
  151. }
  152. }
  153. else
  154. {
  155. private import tango.core.BitManip;
  156. private ushort htons (ushort x)
  157. {
  158. return cast(ushort) ((x >> 8) | (x << 8));
  159. }
  160. private uint htonl (uint x)
  161. {
  162. return bswap(x);
  163. }
  164. }
  165. /*******************************************************************************
  166. *******************************************************************************/
  167. version (Win32)
  168. {
  169. pragma (lib, "ws2_32.lib");
  170. private import tango.sys.win32.WsaSock;
  171. enum socket_t: int
  172. {
  173. init = ~0
  174. }
  175. package extern (Windows)
  176. {
  177. alias closesocket close;
  178. socket_t socket(int af, int type, int protocol);
  179. int ioctlsocket(socket_t s, int cmd, uint* argp);
  180. uint inet_addr(const(char)* cp);
  181. int bind(socket_t s, Address.sockaddr* name, int namelen);
  182. int connect(socket_t s, Address.sockaddr* name, int namelen);
  183. int listen(socket_t s, int backlog);
  184. socket_t accept(socket_t s, Address.sockaddr* addr, int* addrlen);
  185. int closesocket(socket_t s);
  186. int shutdown(socket_t s, int how);
  187. int getpeername(socket_t s, Address.sockaddr* name, int* namelen);
  188. int getsockname(socket_t s, Address.sockaddr* name, int* namelen);
  189. int send(socket_t s, const(void)* buf, int len, int flags);
  190. int sendto(socket_t s, const(void)* buf, int len, int flags, Address.sockaddr* to, int tolen);
  191. int recv(socket_t s, void* buf, int len, int flags);
  192. int recvfrom(socket_t s, void* buf, int len, int flags, Address.sockaddr* from, int* fromlen);
  193. int select(int nfds, SocketSet.fd* readfds, SocketSet.fd* writefds, SocketSet.fd* errorfds, SocketSet.timeval* timeout);
  194. int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
  195. int setsockopt(socket_t s, int level, int optname, const(void)* optval, int optlen);
  196. int gethostname(void* namebuffer, int buflen);
  197. char* inet_ntoa(uint ina);
  198. NetHost.hostent* gethostbyname(const(char)* name);
  199. NetHost.hostent* gethostbyaddr(const(void)* addr, int len, int type);
  200. /**
  201. The gai_strerror function translates error codes of getaddrinfo,
  202. freeaddrinfo and getnameinfo to a human readable string, suitable
  203. for error reporting. (C) MAN
  204. */
  205. //char* gai_strerror(int errcode);
  206. /**
  207. Given node and service, which identify an Internet host and a service,
  208. getaddrinfo() returns one or more addrinfo structures, each of which
  209. contains an Internet address that can be specified in a call to bind
  210. or connect. The getaddrinfo() function combines the functionality
  211. provided by the getservbyname and getservbyport functions into a single
  212. interface, but unlike the latter functions, getaddrinfo() is reentrant
  213. and allows programs to eliminate IPv4-versus-IPv6 dependencies.(C) MAN
  214. */
  215. int function(const(char)* node, const(char)* service, Address.addrinfo* hints, Address.addrinfo** res) getaddrinfo;
  216. /**
  217. The freeaddrinfo() function frees the memory that was allocated for the
  218. dynamically allocated linked list res. (C) MAN
  219. */
  220. void function(Address.addrinfo *res) freeaddrinfo;
  221. /**
  222. The getnameinfo() function is the inverse of getaddrinfo: it converts
  223. a socket address to a corresponding host and service, in a protocol-
  224. independent manner. It combines the functionality of gethostbyaddr and
  225. getservbyport, but unlike those functions, getaddrinfo is reentrant and
  226. allows programs to eliminate IPv4-versus-IPv6 dependencies. (C) MAN
  227. */
  228. int function(Address.sockaddr* sa, int salen, char* host, int hostlen, char* serv, int servlen, int flags) getnameinfo;
  229. bool function (socket_t, uint, void*, DWORD, DWORD, DWORD, DWORD*, OVERLAPPED*) AcceptEx;
  230. bool function (socket_t, HANDLE, DWORD, DWORD, OVERLAPPED*, void*, DWORD) TransmitFile;
  231. bool function (socket_t, void*, int, void*, DWORD, DWORD*, OVERLAPPED*) ConnectEx;
  232. //char* inet_ntop(int af, void *src, char *dst, int len);
  233. }
  234. private __gshared HMODULE lib;
  235. shared static this()
  236. {
  237. lib = LoadLibraryA ("Ws2_32.dll");
  238. getnameinfo = cast(typeof(getnameinfo)) GetProcAddress(lib, "getnameinfo");
  239. if (!getnameinfo)
  240. {
  241. FreeLibrary (lib);
  242. lib = LoadLibraryA ("Wship6.dll");
  243. }
  244. getnameinfo = cast(typeof(getnameinfo)) GetProcAddress(lib, "getnameinfo");
  245. getaddrinfo = cast(typeof(getaddrinfo)) GetProcAddress(lib, "getaddrinfo");
  246. freeaddrinfo = cast(typeof(freeaddrinfo)) GetProcAddress(lib, "freeaddrinfo");
  247. if (!getnameinfo)
  248. {
  249. FreeLibrary (lib);
  250. lib = null;
  251. }
  252. WSADATA wd = void;
  253. if (WSAStartup (0x0202, &wd))
  254. throw new SocketException("version of socket library is too old");
  255. DWORD result;
  256. Guid acceptG = {0xb5367df1, 0xcbac, 0x11cf, [0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
  257. Guid connectG = {0x25a207b9, 0xddf3, 0x4660, [0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e]};
  258. Guid transmitG = {0xb5367df0, 0xcbac, 0x11cf, [0x95,0xca,0x00,0x80,0x5f,0x48,0xa1,0x92]};
  259. auto s = cast(HANDLE) socket (AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP);
  260. assert (s != cast(HANDLE) -1);
  261. WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
  262. &connectG, connectG.sizeof, &ConnectEx,
  263. ConnectEx.sizeof, &result, null, null);
  264. WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
  265. &acceptG, acceptG.sizeof, &AcceptEx,
  266. AcceptEx.sizeof, &result, null, null);
  267. WSAIoctl (s, SIO_GET_EXTENSION_FUNCTION_POINTER,
  268. &transmitG, transmitG.sizeof, &TransmitFile,
  269. TransmitFile.sizeof, &result, null, null);
  270. closesocket (cast(socket_t)(cast(int)s));
  271. }
  272. shared static ~this()
  273. {
  274. if (lib)
  275. FreeLibrary (lib);
  276. WSACleanup();
  277. }
  278. }
  279. else
  280. {
  281. private import tango.stdc.errno;
  282. //private alias int socket_t = -1;
  283. enum socket_t: int
  284. {
  285. init = -1
  286. }
  287. package extern (C)
  288. {
  289. socket_t socket(int af, int type, int protocol);
  290. int fcntl(socket_t s, int f, ...);
  291. uint inet_addr(const(char)* cp);
  292. int bind(socket_t s, const(Address.sockaddr)* name, int namelen);
  293. int connect(socket_t s, const(Address.sockaddr)* name, int namelen);
  294. int listen(socket_t s, int backlog);
  295. socket_t accept(socket_t s, Address.sockaddr* addr, int* addrlen);
  296. int close(socket_t s);
  297. int shutdown(socket_t s, int how);
  298. int getpeername(socket_t s, Address.sockaddr* name, int* namelen);
  299. int getsockname(socket_t s, Address.sockaddr* name, int* namelen);
  300. int send(socket_t s, const(void)* buf, size_t len, int flags);
  301. int sendto(socket_t s, const(void)* buf, size_t len, int flags, Address.sockaddr* to, int tolen);
  302. int recv(socket_t s, void* buf, size_t len, int flags);
  303. int recvfrom(socket_t s, void* buf, size_t len, int flags, Address.sockaddr* from, int* fromlen);
  304. int select(int nfds, SocketSet.fd* readfds, SocketSet.fd* writefds, SocketSet.fd* errorfds, SocketSet.timeval* timeout);
  305. int getsockopt(socket_t s, int level, int optname, void* optval, int* optlen);
  306. int setsockopt(socket_t s, int level, int optname, const(void)* optval, int optlen);
  307. int gethostname(void* namebuffer, int buflen);
  308. char* inet_ntoa(uint ina);
  309. NetHost.hostent* gethostbyname(const(char)* name);
  310. NetHost.hostent* gethostbyaddr(const(void)* addr, int len, int type);
  311. /**
  312. Given node and service, which identify an Internet host and a service,
  313. getaddrinfo() returns one or more addrinfo structures, each of which
  314. contains an Internet address that can be specified in a call to bind or
  315. connect. The getaddrinfo() function combines the functionality provided
  316. by the getservbyname and getservbyport functions into a single interface,
  317. but unlike the latter functions, getaddrinfo() is reentrant and allows
  318. programs to eliminate IPv4-versus-IPv6 dependencies. (C) MAN
  319. */
  320. int getaddrinfo(const(char)* node, const(char)* service, Address.addrinfo* hints, Address.addrinfo** res);
  321. /**
  322. The freeaddrinfo() function frees the memory that was allocated for the
  323. dynamically allocated linked list res. (C) MAN
  324. */
  325. void freeaddrinfo(Address.addrinfo *res);
  326. /**
  327. The getnameinfo() function is the inverse of getaddrinfo: it converts a socket
  328. address to a corresponding host and service, in a protocol-independent manner.
  329. It combines the functionality of gethostbyaddr and getservbyport, but unlike
  330. those functions, getaddrinfo is reentrant and allows programs to eliminate
  331. IPv4-versus-IPv6 dependencies. (C) MAN
  332. */
  333. int getnameinfo(Address.sockaddr* sa, int salen, char* host, int hostlen, char* serv, int servlen, int flags);
  334. /**
  335. The gai_strerror function translates error codes of getaddrinfo, freeaddrinfo
  336. and getnameinfo to a human readable string, suitable for error reporting. (C) MAN
  337. */
  338. const(char)* gai_strerror(int errcode);
  339. const(char)* inet_ntop(int af, const(void) *src, char *dst, int len);
  340. }
  341. }
  342. /*******************************************************************************
  343. *******************************************************************************/
  344. public struct Berkeley
  345. {
  346. socket_t sock;
  347. SocketType type;
  348. AddressFamily family;
  349. ProtocolType protocol;
  350. version (Windows)
  351. bool synchronous;
  352. enum INVALID_SOCKET = socket_t.init;
  353. enum
  354. {
  355. Error = -1
  356. }
  357. alias Error ERROR; // backward compatibility
  358. alias noDelay setNoDelay; // backward compatibility
  359. alias addressReuse setAddressReuse; // backward compatibility
  360. /***********************************************************************
  361. Configure this instance
  362. ***********************************************************************/
  363. void open (AddressFamily family, SocketType type, ProtocolType protocol, bool create=true)
  364. {
  365. this.type = type;
  366. this.family = family;
  367. this.protocol = protocol;
  368. if (create)
  369. reopen();
  370. }
  371. /***********************************************************************
  372. Open/reopen a native socket for this instance
  373. ***********************************************************************/
  374. void reopen (socket_t sock = sock.init)
  375. {
  376. if (this.sock != sock.init)
  377. this.detach();
  378. if (sock is sock.init)
  379. {
  380. sock = cast(socket_t) socket (family, type, protocol);
  381. if (sock is sock.init)
  382. exception ("Unable to create socket: ");
  383. }
  384. this.sock = sock;
  385. }
  386. /***********************************************************************
  387. calling shutdown() before this is recommended for connection-
  388. oriented sockets
  389. ***********************************************************************/
  390. void detach ()
  391. {
  392. if (sock != sock.init)
  393. .close (sock);
  394. sock = sock.init;
  395. }
  396. /***********************************************************************
  397. Return the underlying OS handle of this Conduit
  398. ***********************************************************************/
  399. @property const socket_t handle ()
  400. {
  401. return sock;
  402. }
  403. /***********************************************************************
  404. Return socket error status
  405. ***********************************************************************/
  406. @property const int error ()
  407. {
  408. int errcode;
  409. getOption (SocketOptionLevel.SOCKET, SocketOption.ERROR, (&errcode)[0..1]);
  410. return errcode;
  411. }
  412. /***********************************************************************
  413. Return the last error
  414. ***********************************************************************/
  415. @property static int lastError ()
  416. {
  417. version (Win32)
  418. return WSAGetLastError();
  419. else
  420. return errno;
  421. }
  422. /***********************************************************************
  423. Is this socket still alive? A closed socket is considered to
  424. be dead, but a shutdown socket is still alive.
  425. ***********************************************************************/
  426. @property const bool isAlive ()
  427. {
  428. int type, typesize = type.sizeof;
  429. return getsockopt (sock, SocketOptionLevel.SOCKET,
  430. SocketOption.TYPE, cast(char*) &type,
  431. &typesize) != Error;
  432. }
  433. /***********************************************************************
  434. ***********************************************************************/
  435. @property AddressFamily addressFamily ()
  436. {
  437. return family;
  438. }
  439. /***********************************************************************
  440. ***********************************************************************/
  441. Berkeley* bind (Address addr)
  442. {
  443. if(Error == .bind (sock, addr.name, addr.nameLen))
  444. exception ("Unable to bind socket: ");
  445. return &this;
  446. }
  447. /***********************************************************************
  448. ***********************************************************************/
  449. Berkeley* connect (Address to)
  450. {
  451. if (Error == .connect (sock, to.name, to.nameLen))
  452. {
  453. if (! blocking)
  454. {
  455. auto err = lastError;
  456. version (Windows)
  457. {
  458. if (err is WSAEWOULDBLOCK)
  459. return &this;
  460. }
  461. else
  462. {
  463. if (err is EINPROGRESS)
  464. return &this;
  465. }
  466. }
  467. exception ("Unable to connect socket: ");
  468. }
  469. return &this;
  470. }
  471. /***********************************************************************
  472. need to bind() first
  473. ***********************************************************************/
  474. Berkeley* listen (int backlog)
  475. {
  476. if (Error == .listen (sock, backlog))
  477. exception ("Unable to listen on socket: ");
  478. return &this;
  479. }
  480. /***********************************************************************
  481. need to bind() first
  482. ***********************************************************************/
  483. void accept (ref Berkeley target)
  484. {
  485. auto newsock = .accept (sock, null, null);
  486. if (socket_t.init is newsock)
  487. exception ("Unable to accept socket connection: ");
  488. target.reopen (newsock);
  489. target.protocol = protocol; //same protocol
  490. target.family = family; //same family
  491. target.type = type; //same type
  492. }
  493. /***********************************************************************
  494. The shutdown function shuts down the connection of the socket.
  495. Depending on the argument value, it will:
  496. - stop receiving data for this socket. If further data
  497. arrives, it is rejected.
  498. - stop trying to transmit data from this socket. Also
  499. discards any data waiting to be sent. Stop looking for
  500. acknowledgement of data already sent; don't retransmit
  501. if any data is lost.
  502. ***********************************************************************/
  503. Berkeley* shutdown (SocketShutdown how)
  504. {
  505. .shutdown (sock, how);
  506. return &this;
  507. }
  508. /***********************************************************************
  509. set linger timeout
  510. ***********************************************************************/
  511. @property Berkeley* linger (int period)
  512. {
  513. version (Win32)
  514. alias ushort attr;
  515. else
  516. alias uint attr;
  517. union linger
  518. {
  519. struct {
  520. attr l_onoff; // option on/off
  521. attr l_linger; // linger time
  522. };
  523. attr[2] array; // combined
  524. }
  525. linger l;
  526. l.l_onoff = 1; // option on/off
  527. l.l_linger = cast(ushort) period; // linger time
  528. return setOption (SocketOptionLevel.SOCKET, SocketOption.LINGER, l.array);
  529. }
  530. /***********************************************************************
  531. enable/disable address reuse
  532. ***********************************************************************/
  533. @property Berkeley* addressReuse (bool enabled)
  534. {
  535. int[1] x = enabled;
  536. return setOption (SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, x);
  537. }
  538. /***********************************************************************
  539. enable/disable noDelay option (nagle)
  540. ***********************************************************************/
  541. @property Berkeley* noDelay (bool enabled)
  542. {
  543. int[1] x = enabled;
  544. return setOption (SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, x);
  545. }
  546. /***********************************************************************
  547. Helper function to handle the adding and dropping of group
  548. membership.
  549. ***********************************************************************/
  550. void joinGroup (IPv4Address address, bool onOff)
  551. {
  552. assert (address, "Socket.joinGroup :: invalid null address");
  553. struct ip_mreq
  554. {
  555. uint imr_multiaddr; /* IP multicast address of group */
  556. uint imr_interface; /* local IP address of interface */
  557. }
  558. ip_mreq mrq;
  559. auto option = (onOff) ? SocketOption.ADD_MEMBERSHIP : SocketOption.DROP_MEMBERSHIP;
  560. mrq.imr_interface = 0;
  561. mrq.imr_multiaddr = address.sin.sin_addr;
  562. if (.setsockopt(sock, SocketOptionLevel.IP, option, &mrq, mrq.sizeof) == Error)
  563. exception ("Unable to perform multicast join: ");
  564. }
  565. /***********************************************************************
  566. ***********************************************************************/
  567. const Address newFamilyObject ()
  568. {
  569. if (family is AddressFamily.INET)
  570. return new IPv4Address;
  571. if (family is AddressFamily.INET6)
  572. return new IPv6Address;
  573. return new UnknownAddress;
  574. }
  575. /***********************************************************************
  576. return the hostname
  577. ***********************************************************************/
  578. @property static char[] hostName ()
  579. {
  580. char[64] name;
  581. if(Error == .gethostname (name.ptr, name.length))
  582. exception ("Unable to obtain host name: ");
  583. return name [0 .. strlen(name.ptr)].dup;
  584. }
  585. /***********************************************************************
  586. return the default host address (IPv4)
  587. ***********************************************************************/
  588. @property static uint hostAddress ()
  589. {
  590. auto ih = new NetHost;
  591. ih.getHostByName (hostName);
  592. assert (ih.addrList.length);
  593. return ih.addrList[0];
  594. }
  595. /***********************************************************************
  596. return the remote address of the current connection (IPv4)
  597. ***********************************************************************/
  598. @property const Address remoteAddress ()
  599. {
  600. auto addr = newFamilyObject();
  601. auto nameLen = addr.nameLen;
  602. if(Error == .getpeername (sock, addr.name, &nameLen))
  603. exception ("Unable to obtain remote socket address: ");
  604. assert (addr.addressFamily is family);
  605. return addr;
  606. }
  607. /***********************************************************************
  608. return the local address of the current connection (IPv4)
  609. ***********************************************************************/
  610. @property const Address localAddress ()
  611. {
  612. auto addr = newFamilyObject();
  613. auto nameLen = addr.nameLen;
  614. if(Error == .getsockname (sock, addr.name, &nameLen))
  615. exception ("Unable to obtain local socket address: ");
  616. assert (addr.addressFamily is family);
  617. return addr;
  618. }
  619. /***********************************************************************
  620. Send data on the connection. Returns the number of bytes
  621. actually sent, or ERROR on failure. If the socket is blocking
  622. and there is no buffer space left, send waits.
  623. Returns number of bytes actually sent, or -1 on error
  624. ***********************************************************************/
  625. const int send (const(void)[] buf, SocketFlags flags=SocketFlags.NONE)
  626. {
  627. if (buf.length is 0)
  628. return 0;
  629. version (Posix)
  630. {
  631. auto ret = .send (sock, buf.ptr, buf.length,
  632. SocketFlags.NOSIGNAL + cast(int) flags);
  633. if (errno is EPIPE)
  634. ret = -1;
  635. return ret;
  636. }
  637. else
  638. return .send (sock, buf.ptr, buf.length, cast(int) flags);
  639. }
  640. /***********************************************************************
  641. Send data to a specific destination Address. If the
  642. destination address is not specified, a connection
  643. must have been made and that address is used. If the
  644. socket is blocking and there is no buffer space left,
  645. sendTo waits.
  646. ***********************************************************************/
  647. const int sendTo (const(void)[] buf, SocketFlags flags, Address to)
  648. {
  649. return sendTo (buf, cast(int) flags, to.name, to.nameLen);
  650. }
  651. /***********************************************************************
  652. ditto
  653. ***********************************************************************/
  654. const int sendTo (const(void)[] buf, Address to)
  655. {
  656. return sendTo (buf, SocketFlags.NONE, to);
  657. }
  658. /***********************************************************************
  659. ditto - assumes you connect()ed
  660. ***********************************************************************/
  661. const int sendTo (const(void)[] buf, SocketFlags flags=SocketFlags.NONE)
  662. {
  663. return sendTo (buf, cast(int) flags, null, 0);
  664. }
  665. /***********************************************************************
  666. Send data to a specific destination Address. If the
  667. destination address is not specified, a connection
  668. must have been made and that address is used. If the
  669. socket is blocking and there is no buffer space left,
  670. sendTo waits.
  671. ***********************************************************************/
  672. private const int sendTo (const(void)[] buf, int flags, Address.sockaddr* to, int len)
  673. {
  674. if (buf.length is 0)
  675. return 0;
  676. version (Posix)
  677. {
  678. auto ret = .sendto (sock, buf.ptr, buf.length,
  679. flags | SocketFlags.NOSIGNAL, to, len);
  680. if (errno is EPIPE)
  681. ret = -1;
  682. return ret;
  683. }
  684. else
  685. return .sendto (sock, buf.ptr, buf.length, flags, to, len);
  686. }
  687. /***********************************************************************
  688. Receive data on the connection. Returns the number of
  689. bytes actually received, 0 if the remote side has closed
  690. the connection, or ERROR on failure. If the socket is blocking,
  691. receive waits until there is data to be received.
  692. Returns number of bytes actually received, 0 on connection
  693. closure, or -1 on error
  694. ***********************************************************************/
  695. const int receive (void[] buf, SocketFlags flags=SocketFlags.NONE)
  696. {
  697. if (!buf.length)
  698. badArg ("Socket.receive :: target buffer has 0 length");
  699. return .recv(sock, buf.ptr, buf.length, cast(int)flags);
  700. }
  701. /***********************************************************************
  702. Receive data and get the remote endpoint Address. Returns
  703. the number of bytes actually received, 0 if the remote side
  704. has closed the connection, or ERROR on failure. If the socket
  705. is blocking, receiveFrom waits until there is data to be
  706. received.
  707. ***********************************************************************/
  708. const int receiveFrom (void[] buf, SocketFlags flags, Address from)
  709. {
  710. if (!buf.length)
  711. badArg ("Socket.receiveFrom :: target buffer has 0 length");
  712. assert(from.addressFamily() == family);
  713. int nameLen = from.nameLen();
  714. return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, from.name(), &nameLen);
  715. }
  716. /***********************************************************************
  717. ditto
  718. ***********************************************************************/
  719. const int receiveFrom (void[] buf, Address from)
  720. {
  721. return receiveFrom(buf, SocketFlags.NONE, from);
  722. }
  723. /***********************************************************************
  724. ditto - assumes you connect()ed
  725. ***********************************************************************/
  726. const int receiveFrom (void[] buf, SocketFlags flags = SocketFlags.NONE)
  727. {
  728. if (!buf.length)
  729. badArg ("Socket.receiveFrom :: target buffer has 0 length");
  730. return .recvfrom(sock, buf.ptr, buf.length, cast(int)flags, null, null);
  731. }
  732. /***********************************************************************
  733. returns the length, in bytes, of the actual result - very
  734. different from getsockopt()
  735. ***********************************************************************/
  736. const int getOption (SocketOptionLevel level, SocketOption option, void[] result)
  737. {
  738. int len = cast(int) result.length;
  739. if(Error == .getsockopt (sock, cast(int)level, cast(int)option, result.ptr, &len))
  740. exception ("Unable to get socket option: ");
  741. return len;
  742. }
  743. /***********************************************************************
  744. ***********************************************************************/
  745. Berkeley* setOption (SocketOptionLevel level, SocketOption option, const(void)[] value)
  746. {
  747. if(Error == .setsockopt (sock, cast(int)level, cast(int)option, value.ptr, cast(int) value.length))
  748. exception ("Unable to set socket option: ");
  749. return &this;
  750. }
  751. /***********************************************************************
  752. getter
  753. ***********************************************************************/
  754. @property const bool blocking()
  755. {
  756. version (Windows)
  757. return synchronous;
  758. else
  759. return !(fcntl(sock, F_GETFL, 0) & O_NONBLOCK);
  760. }
  761. /***********************************************************************
  762. setter
  763. ***********************************************************************/
  764. @property void blocking(bool yes)
  765. {
  766. version (Windows)
  767. {
  768. uint num = !yes;
  769. if(ioctlsocket(sock, consts.FIONBIO, &num) is ERROR)
  770. exception("Unable to set socket blocking: ");
  771. synchronous = yes;
  772. }
  773. else
  774. {
  775. int x = fcntl(sock, F_GETFL, 0);
  776. if(yes)
  777. x &= ~O_NONBLOCK;
  778. else
  779. x |= O_NONBLOCK;
  780. if(fcntl(sock, F_SETFL, x) is ERROR)
  781. exception("Unable to set socket blocking: ");
  782. }
  783. return;
  784. }
  785. /***********************************************************************
  786. ***********************************************************************/
  787. static void exception (immutable(char)[] msg)
  788. {
  789. throw new SocketException (msg ~ SysError.lookup(lastError).idup);
  790. }
  791. /***********************************************************************
  792. ***********************************************************************/
  793. protected static void badArg (immutable(char)[] msg)
  794. {
  795. throw new IllegalArgumentException (msg);
  796. }
  797. }
  798. /*******************************************************************************
  799. *******************************************************************************/
  800. public abstract class Address
  801. {
  802. public struct sockaddr
  803. {
  804. ushort sa_family;
  805. char[14] sa_data = 0;
  806. }
  807. struct addrinfo
  808. {
  809. int ai_flags;
  810. int ai_family;
  811. int ai_socktype;
  812. int ai_protocol;
  813. uint ai_addrlen;
  814. version (FreeBSD)
  815. {
  816. char* ai_canonname;
  817. sockaddr* ai_addr;
  818. }
  819. else
  820. {
  821. sockaddr* ai_addr;
  822. char* ai_canonname;
  823. }
  824. addrinfo* ai_next;
  825. }
  826. @property abstract sockaddr* name();
  827. @property abstract const int nameLen();
  828. /***********************************************************************
  829. Internal usage
  830. ***********************************************************************/
  831. private static ushort ntohs (ushort x)
  832. {
  833. return htons(x);
  834. }
  835. /***********************************************************************
  836. Internal usage
  837. ***********************************************************************/
  838. private static uint ntohl (uint x)
  839. {
  840. return htonl(x);
  841. }
  842. /***********************************************************************
  843. Internal usage
  844. ***********************************************************************/
  845. private static char[] fromInt (char[] tmp, int i)
  846. {
  847. size_t j = tmp.length;
  848. do {
  849. tmp[--j] = cast(char)(i % 10 + '0');
  850. } while (i /= 10);
  851. return tmp [j .. $];
  852. }
  853. /***********************************************************************
  854. Internal usage
  855. ***********************************************************************/
  856. private static int toInt (const(char)[] s)
  857. {
  858. uint value;
  859. foreach (c; s)
  860. if (c >= '0' && c <= '9')
  861. value = value * 10 + (c - '0');
  862. else
  863. break;
  864. return value;
  865. }
  866. /***********************************************************************
  867. Tango: added this common function
  868. ***********************************************************************/
  869. static void exception (immutable(char)[] msg)
  870. {
  871. throw new SocketException (msg);
  872. }
  873. /***********************************************************************
  874. Address factory
  875. ***********************************************************************/
  876. static Address create (sockaddr* sa)
  877. {
  878. switch (sa.sa_family)
  879. {
  880. case AddressFamily.INET:
  881. return new IPv4Address(sa);
  882. case AddressFamily.INET6:
  883. return new IPv6Address(sa);
  884. default:
  885. return null;
  886. }
  887. }
  888. /***********************************************************************
  889. ***********************************************************************/
  890. static Address resolve (const(char)[] host, const(char)[] service = null,
  891. AddressFamily af = AddressFamily.UNSPEC,
  892. AIFlags flags = cast(AIFlags)0)
  893. {
  894. return resolveAll (host, service, af, flags)[0];
  895. }
  896. /***********************************************************************
  897. ***********************************************************************/
  898. static Address resolve (const(char)[] host, ushort port,
  899. AddressFamily af = AddressFamily.UNSPEC,
  900. AIFlags flags = cast(AIFlags)0)
  901. {
  902. return resolveAll (host, port, af, flags)[0];
  903. }
  904. /***********************************************************************
  905. ***********************************************************************/
  906. static Address[] resolveAll (const(char)[] host, const(char)[] service = null,
  907. AddressFamily af = AddressFamily.UNSPEC,
  908. AIFlags flags = cast(AIFlags)0)
  909. {
  910. Address[] retVal;
  911. version (Win32)
  912. {
  913. if (!getaddrinfo)
  914. { // *old* windows, let's fall back to NetHost
  915. uint port = toInt(service);
  916. if (flags & AIFlags.PASSIVE && host is null)
  917. return [new IPv4Address(0, cast(ushort)port)];
  918. auto nh = new NetHost;
  919. if (!nh.getHostByName(host))
  920. throw new AddressException("couldn't resolve " ~ host.idup);
  921. retVal.length = nh.addrList.length;
  922. foreach (i, addr; nh.addrList)
  923. retVal[i] = new IPv4Address(addr, cast(ushort)port);
  924. return retVal;
  925. }
  926. }
  927. addrinfo* info;
  928. addrinfo hints;
  929. hints.ai_flags = flags;
  930. hints.ai_family = (flags & AIFlags.PASSIVE && af == AddressFamily.UNSPEC) ? AddressFamily.INET6 : af;
  931. hints.ai_socktype = SocketType.STREAM;
  932. int error = getaddrinfo(toStringz(host), service.length == 0 ? null : toStringz(service), &hints, &info);
  933. if (error != 0)
  934. throw new AddressException("couldn't resolve " ~ host.idup);
  935. retVal.length = 16;
  936. retVal.length = 0;
  937. while (info)
  938. {
  939. if (auto addr = create(info.ai_addr))
  940. retVal ~= addr;
  941. info = info.ai_next;
  942. }
  943. freeaddrinfo (info);
  944. return retVal;
  945. }
  946. /***********************************************************************
  947. ***********************************************************************/
  948. static Address[] resolveAll (const(char)[] host, ushort port,
  949. AddressFamily af = AddressFamily.UNSPEC,
  950. AIFlags flags = cast(AIFlags)0)
  951. {
  952. char[16] buf;
  953. return resolveAll (host, fromInt(buf, port), af, flags);
  954. }
  955. /***********************************************************************
  956. ***********************************************************************/
  957. static Address passive (const(char)[] service,
  958. AddressFamily af = AddressFamily.UNSPEC,
  959. AIFlags flags = cast(AIFlags)0)
  960. {
  961. return resolve (null, service, af, flags | AIFlags.PASSIVE);
  962. }
  963. /***********************************************************************
  964. ***********************************************************************/
  965. static Address passive (ushort port, AddressFamily af = AddressFamily.UNSPEC,
  966. AIFlags flags = cast(AIFlags)0)
  967. {
  968. return resolve (null, port, af, flags | AIFlags.PASSIVE);
  969. }
  970. /***********************************************************************
  971. ***********************************************************************/
  972. @property char[] toAddrString()
  973. {
  974. char[1025] host = void;
  975. // Getting name info. Don't look up hostname, returns
  976. // numeric name. (NIFlags.NUMERICHOST)
  977. getnameinfo (name, nameLen, host.ptr, host.length, null, 0, NIFlags.NUMERICHOST);
  978. return fromStringz (host.ptr).dup;
  979. }
  980. /***********************************************************************
  981. ***********************************************************************/
  982. @property char[] toPortString()

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