PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/deps/uv/src/unix/tcp.c

https://gitlab.com/CORP-RESELLER/node
C | 362 lines | 232 code | 89 blank | 41 comment | 81 complexity | 97ab042ab8cfbfa1cf6da3ad9d9cb1d4 MD5 | raw file
  1. /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to
  5. * deal in the Software without restriction, including without limitation the
  6. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  7. * sell copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  18. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  19. * IN THE SOFTWARE.
  20. */
  21. #include "uv.h"
  22. #include "internal.h"
  23. #include <stdlib.h>
  24. #include <unistd.h>
  25. #include <assert.h>
  26. #include <errno.h>
  27. static int maybe_new_socket(uv_tcp_t* handle, int domain, int flags) {
  28. int sockfd;
  29. int err;
  30. if (domain == AF_UNSPEC || uv__stream_fd(handle) != -1) {
  31. handle->flags |= flags;
  32. return 0;
  33. }
  34. err = uv__socket(domain, SOCK_STREAM, 0);
  35. if (err < 0)
  36. return err;
  37. sockfd = err;
  38. err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
  39. if (err) {
  40. uv__close(sockfd);
  41. return err;
  42. }
  43. return 0;
  44. }
  45. int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
  46. int domain;
  47. /* Use the lower 8 bits for the domain */
  48. domain = flags & 0xFF;
  49. if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
  50. return -EINVAL;
  51. if (flags & ~0xFF)
  52. return -EINVAL;
  53. uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
  54. /* If anything fails beyond this point we need to remove the handle from
  55. * the handle queue, since it was added by uv__handle_init in uv_stream_init.
  56. */
  57. if (domain != AF_UNSPEC) {
  58. int err = maybe_new_socket(tcp, domain, 0);
  59. if (err) {
  60. QUEUE_REMOVE(&tcp->handle_queue);
  61. return err;
  62. }
  63. }
  64. return 0;
  65. }
  66. int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
  67. return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
  68. }
  69. int uv__tcp_bind(uv_tcp_t* tcp,
  70. const struct sockaddr* addr,
  71. unsigned int addrlen,
  72. unsigned int flags) {
  73. int err;
  74. int on;
  75. /* Cannot set IPv6-only mode on non-IPv6 socket. */
  76. if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
  77. return -EINVAL;
  78. err = maybe_new_socket(tcp,
  79. addr->sa_family,
  80. UV_STREAM_READABLE | UV_STREAM_WRITABLE);
  81. if (err)
  82. return err;
  83. on = 1;
  84. if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
  85. return -errno;
  86. #ifdef IPV6_V6ONLY
  87. if (addr->sa_family == AF_INET6) {
  88. on = (flags & UV_TCP_IPV6ONLY) != 0;
  89. if (setsockopt(tcp->io_watcher.fd,
  90. IPPROTO_IPV6,
  91. IPV6_V6ONLY,
  92. &on,
  93. sizeof on) == -1) {
  94. return -errno;
  95. }
  96. }
  97. #endif
  98. errno = 0;
  99. if (bind(tcp->io_watcher.fd, addr, addrlen) && errno != EADDRINUSE) {
  100. if (errno == EAFNOSUPPORT)
  101. /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
  102. * socket created with AF_INET to an AF_INET6 address or vice versa. */
  103. return -EINVAL;
  104. return -errno;
  105. }
  106. tcp->delayed_error = -errno;
  107. if (addr->sa_family == AF_INET6)
  108. tcp->flags |= UV_HANDLE_IPV6;
  109. return 0;
  110. }
  111. int uv__tcp_connect(uv_connect_t* req,
  112. uv_tcp_t* handle,
  113. const struct sockaddr* addr,
  114. unsigned int addrlen,
  115. uv_connect_cb cb) {
  116. int err;
  117. int r;
  118. assert(handle->type == UV_TCP);
  119. if (handle->connect_req != NULL)
  120. return -EALREADY; /* FIXME(bnoordhuis) -EINVAL or maybe -EBUSY. */
  121. err = maybe_new_socket(handle,
  122. addr->sa_family,
  123. UV_STREAM_READABLE | UV_STREAM_WRITABLE);
  124. if (err)
  125. return err;
  126. handle->delayed_error = 0;
  127. do
  128. r = connect(uv__stream_fd(handle), addr, addrlen);
  129. while (r == -1 && errno == EINTR);
  130. if (r == -1) {
  131. if (errno == EINPROGRESS)
  132. ; /* not an error */
  133. else if (errno == ECONNREFUSED)
  134. /* If we get a ECONNREFUSED wait until the next tick to report the
  135. * error. Solaris wants to report immediately--other unixes want to
  136. * wait.
  137. */
  138. handle->delayed_error = -errno;
  139. else
  140. return -errno;
  141. }
  142. uv__req_init(handle->loop, req, UV_CONNECT);
  143. req->cb = cb;
  144. req->handle = (uv_stream_t*) handle;
  145. QUEUE_INIT(&req->queue);
  146. handle->connect_req = req;
  147. uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
  148. if (handle->delayed_error)
  149. uv__io_feed(handle->loop, &handle->io_watcher);
  150. return 0;
  151. }
  152. int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
  153. int err;
  154. err = uv__nonblock(sock, 1);
  155. if (err)
  156. return err;
  157. return uv__stream_open((uv_stream_t*)handle,
  158. sock,
  159. UV_STREAM_READABLE | UV_STREAM_WRITABLE);
  160. }
  161. int uv_tcp_getsockname(const uv_tcp_t* handle,
  162. struct sockaddr* name,
  163. int* namelen) {
  164. socklen_t socklen;
  165. if (handle->delayed_error)
  166. return handle->delayed_error;
  167. if (uv__stream_fd(handle) < 0)
  168. return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
  169. /* sizeof(socklen_t) != sizeof(int) on some systems. */
  170. socklen = (socklen_t) *namelen;
  171. if (getsockname(uv__stream_fd(handle), name, &socklen))
  172. return -errno;
  173. *namelen = (int) socklen;
  174. return 0;
  175. }
  176. int uv_tcp_getpeername(const uv_tcp_t* handle,
  177. struct sockaddr* name,
  178. int* namelen) {
  179. socklen_t socklen;
  180. if (handle->delayed_error)
  181. return handle->delayed_error;
  182. if (uv__stream_fd(handle) < 0)
  183. return -EINVAL; /* FIXME(bnoordhuis) -EBADF */
  184. /* sizeof(socklen_t) != sizeof(int) on some systems. */
  185. socklen = (socklen_t) *namelen;
  186. if (getpeername(uv__stream_fd(handle), name, &socklen))
  187. return -errno;
  188. *namelen = (int) socklen;
  189. return 0;
  190. }
  191. int uv_tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
  192. static int single_accept = -1;
  193. int err;
  194. if (tcp->delayed_error)
  195. return tcp->delayed_error;
  196. if (single_accept == -1) {
  197. const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
  198. single_accept = (val != NULL && atoi(val) != 0); /* Off by default. */
  199. }
  200. if (single_accept)
  201. tcp->flags |= UV_TCP_SINGLE_ACCEPT;
  202. err = maybe_new_socket(tcp, AF_INET, UV_STREAM_READABLE);
  203. if (err)
  204. return err;
  205. if (listen(tcp->io_watcher.fd, backlog))
  206. return -errno;
  207. tcp->connection_cb = cb;
  208. /* Start listening for connections. */
  209. tcp->io_watcher.cb = uv__server_io;
  210. uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
  211. return 0;
  212. }
  213. int uv__tcp_nodelay(int fd, int on) {
  214. if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
  215. return -errno;
  216. return 0;
  217. }
  218. int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
  219. if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
  220. return -errno;
  221. #ifdef TCP_KEEPIDLE
  222. if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
  223. return -errno;
  224. #endif
  225. /* Solaris/SmartOS, if you don't support keep-alive,
  226. * then don't advertise it in your system headers...
  227. */
  228. /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
  229. #if defined(TCP_KEEPALIVE) && !defined(__sun)
  230. if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
  231. return -errno;
  232. #endif
  233. return 0;
  234. }
  235. int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
  236. int err;
  237. if (uv__stream_fd(handle) != -1) {
  238. err = uv__tcp_nodelay(uv__stream_fd(handle), on);
  239. if (err)
  240. return err;
  241. }
  242. if (on)
  243. handle->flags |= UV_TCP_NODELAY;
  244. else
  245. handle->flags &= ~UV_TCP_NODELAY;
  246. return 0;
  247. }
  248. int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
  249. int err;
  250. if (uv__stream_fd(handle) != -1) {
  251. err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
  252. if (err)
  253. return err;
  254. }
  255. if (on)
  256. handle->flags |= UV_TCP_KEEPALIVE;
  257. else
  258. handle->flags &= ~UV_TCP_KEEPALIVE;
  259. /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
  260. * uv_tcp_t with an int that's almost never used...
  261. */
  262. return 0;
  263. }
  264. int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
  265. if (enable)
  266. handle->flags &= ~UV_TCP_SINGLE_ACCEPT;
  267. else
  268. handle->flags |= UV_TCP_SINGLE_ACCEPT;
  269. return 0;
  270. }
  271. void uv__tcp_close(uv_tcp_t* handle) {
  272. uv__stream_close((uv_stream_t*)handle);
  273. }