|
160
|
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
|
|
|
22 #include "uv.h"
|
|
|
23 #include "internal.h"
|
|
|
24
|
|
|
25 #include <stdlib.h>
|
|
|
26 #include <unistd.h>
|
|
|
27 #include <assert.h>
|
|
|
28 #include <errno.h>
|
|
|
29
|
|
|
30 #include <sys/types.h>
|
|
|
31 #include <sys/socket.h>
|
|
|
32
|
|
|
33 /* ifaddrs is not implemented on AIX and IBM i PASE */
|
|
|
34 #if !defined(_AIX)
|
|
|
35 #include <ifaddrs.h>
|
|
|
36 #endif
|
|
|
37
|
|
|
38 static int maybe_bind_socket(int fd) {
|
|
|
39 union uv__sockaddr s;
|
|
|
40 socklen_t slen;
|
|
|
41
|
|
|
42 slen = sizeof(s);
|
|
|
43 memset(&s, 0, sizeof(s));
|
|
|
44
|
|
|
45 if (getsockname(fd, &s.addr, &slen))
|
|
|
46 return UV__ERR(errno);
|
|
|
47
|
|
|
48 if (s.addr.sa_family == AF_INET)
|
|
|
49 if (s.in.sin_port != 0)
|
|
|
50 return 0; /* Already bound to a port. */
|
|
|
51
|
|
|
52 if (s.addr.sa_family == AF_INET6)
|
|
|
53 if (s.in6.sin6_port != 0)
|
|
|
54 return 0; /* Already bound to a port. */
|
|
|
55
|
|
|
56 /* Bind to an arbitrary port. */
|
|
|
57 if (bind(fd, &s.addr, slen))
|
|
|
58 return UV__ERR(errno);
|
|
|
59
|
|
|
60 return 0;
|
|
|
61 }
|
|
|
62
|
|
|
63
|
|
|
64 static int new_socket(uv_tcp_t* handle, int domain, unsigned int flags) {
|
|
|
65 int sockfd;
|
|
|
66 int err;
|
|
|
67
|
|
|
68 sockfd = uv__socket(domain, SOCK_STREAM, 0);
|
|
|
69 if (sockfd < 0)
|
|
|
70 return sockfd;
|
|
|
71
|
|
|
72 err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
|
|
|
73 if (err) {
|
|
|
74 uv__close(sockfd);
|
|
|
75 return err;
|
|
|
76 }
|
|
|
77
|
|
|
78 if (flags & UV_HANDLE_BOUND)
|
|
|
79 return maybe_bind_socket(sockfd);
|
|
|
80
|
|
|
81 return 0;
|
|
|
82 }
|
|
|
83
|
|
|
84
|
|
|
85 static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned int flags) {
|
|
|
86 int sockfd;
|
|
|
87 int err;
|
|
|
88
|
|
|
89 if (domain == AF_UNSPEC)
|
|
|
90 goto out;
|
|
|
91
|
|
|
92 sockfd = uv__stream_fd(handle);
|
|
|
93 if (sockfd == -1)
|
|
|
94 return new_socket(handle, domain, flags);
|
|
|
95
|
|
|
96 if (!(flags & UV_HANDLE_BOUND))
|
|
|
97 goto out;
|
|
|
98
|
|
|
99 if (handle->flags & UV_HANDLE_BOUND)
|
|
|
100 goto out; /* Already bound to a port. */
|
|
|
101
|
|
|
102 err = maybe_bind_socket(sockfd);
|
|
|
103 if (err)
|
|
|
104 return err;
|
|
|
105
|
|
|
106 out:
|
|
|
107
|
|
|
108 handle->flags |= flags;
|
|
|
109 return 0;
|
|
|
110 }
|
|
|
111
|
|
|
112
|
|
|
113 int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
|
|
|
114 int domain;
|
|
|
115 int err;
|
|
|
116
|
|
|
117 /* Use the lower 8 bits for the domain */
|
|
|
118 domain = flags & 0xFF;
|
|
|
119 if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
|
|
|
120 return UV_EINVAL;
|
|
|
121
|
|
|
122 if (flags & ~0xFF)
|
|
|
123 return UV_EINVAL;
|
|
|
124
|
|
|
125 uv__stream_init(loop, (uv_stream_t*)tcp, UV_TCP);
|
|
|
126
|
|
|
127 /* If anything fails beyond this point we need to remove the handle from
|
|
|
128 * the handle queue, since it was added by uv__handle_init in uv_stream_init.
|
|
|
129 */
|
|
|
130
|
|
|
131 if (domain != AF_UNSPEC) {
|
|
|
132 err = new_socket(tcp, domain, 0);
|
|
|
133 if (err) {
|
|
|
134 uv__queue_remove(&tcp->handle_queue);
|
|
|
135 if (tcp->io_watcher.fd != -1)
|
|
|
136 uv__close(tcp->io_watcher.fd);
|
|
|
137 tcp->io_watcher.fd = -1;
|
|
|
138 return err;
|
|
|
139 }
|
|
|
140 }
|
|
|
141
|
|
|
142 return 0;
|
|
|
143 }
|
|
|
144
|
|
|
145
|
|
|
146 int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
|
|
|
147 return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
|
|
|
148 }
|
|
|
149
|
|
|
150
|
|
|
151 int uv__tcp_bind(uv_tcp_t* tcp,
|
|
|
152 const struct sockaddr* addr,
|
|
|
153 unsigned int addrlen,
|
|
|
154 unsigned int flags) {
|
|
|
155 int err;
|
|
|
156 int on;
|
|
|
157
|
|
|
158 /* Cannot set IPv6-only mode on non-IPv6 socket. */
|
|
|
159 if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
|
|
|
160 return UV_EINVAL;
|
|
|
161
|
|
|
162 err = maybe_new_socket(tcp, addr->sa_family, 0);
|
|
|
163 if (err)
|
|
|
164 return err;
|
|
|
165
|
|
|
166 on = 1;
|
|
|
167 if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
|
|
|
168 return UV__ERR(errno);
|
|
|
169
|
|
|
170 if (flags & UV_TCP_REUSEPORT) {
|
|
|
171 err = uv__sock_reuseport(tcp->io_watcher.fd);
|
|
|
172 if (err)
|
|
|
173 return err;
|
|
|
174 }
|
|
|
175
|
|
|
176 #ifndef __OpenBSD__
|
|
|
177 #ifdef IPV6_V6ONLY
|
|
|
178 if (addr->sa_family == AF_INET6) {
|
|
|
179 on = (flags & UV_TCP_IPV6ONLY) != 0;
|
|
|
180 if (setsockopt(tcp->io_watcher.fd,
|
|
|
181 IPPROTO_IPV6,
|
|
|
182 IPV6_V6ONLY,
|
|
|
183 &on,
|
|
|
184 sizeof on) == -1) {
|
|
|
185 #if defined(__MVS__)
|
|
|
186 if (errno == EOPNOTSUPP)
|
|
|
187 return UV_EINVAL;
|
|
|
188 #endif
|
|
|
189 return UV__ERR(errno);
|
|
|
190 }
|
|
|
191 }
|
|
|
192 #endif
|
|
|
193 #endif
|
|
|
194
|
|
|
195 errno = 0;
|
|
|
196 err = bind(tcp->io_watcher.fd, addr, addrlen);
|
|
|
197 if (err == -1 && errno != EADDRINUSE) {
|
|
|
198 if (errno == EAFNOSUPPORT)
|
|
|
199 /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
|
|
|
200 * socket created with AF_INET to an AF_INET6 address or vice versa. */
|
|
|
201 return UV_EINVAL;
|
|
|
202 return UV__ERR(errno);
|
|
|
203 }
|
|
|
204 tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0;
|
|
|
205
|
|
|
206 tcp->flags |= UV_HANDLE_BOUND;
|
|
|
207 if (addr->sa_family == AF_INET6)
|
|
|
208 tcp->flags |= UV_HANDLE_IPV6;
|
|
|
209
|
|
|
210 return 0;
|
|
|
211 }
|
|
|
212
|
|
|
213
|
|
|
214 static int uv__is_ipv6_link_local(const struct sockaddr* addr) {
|
|
|
215 const struct sockaddr_in6* a6;
|
|
|
216 uint8_t b[2];
|
|
|
217
|
|
|
218 if (addr->sa_family != AF_INET6)
|
|
|
219 return 0;
|
|
|
220
|
|
|
221 a6 = (const struct sockaddr_in6*) addr;
|
|
|
222 memcpy(b, &a6->sin6_addr, sizeof(b));
|
|
|
223
|
|
|
224 return b[0] == 0xFE && b[1] == 0x80;
|
|
|
225 }
|
|
|
226
|
|
|
227
|
|
|
228 static int uv__ipv6_link_local_scope_id(void) {
|
|
|
229 struct sockaddr_in6* a6;
|
|
|
230 int rv;
|
|
|
231 #if defined(_AIX)
|
|
|
232 /* AIX & IBM i do not have ifaddrs
|
|
|
233 * so fallback to use uv_interface_addresses */
|
|
|
234 uv_interface_address_t* interfaces;
|
|
|
235 uv_interface_address_t* ifa;
|
|
|
236 int count, i;
|
|
|
237
|
|
|
238 if (uv_interface_addresses(&interfaces, &count))
|
|
|
239 return 0;
|
|
|
240
|
|
|
241 rv = 0;
|
|
|
242
|
|
|
243 for (ifa = interfaces; ifa != &interfaces[count]; ifa++) {
|
|
|
244 if (uv__is_ipv6_link_local((struct sockaddr*) &ifa->address)) {
|
|
|
245 rv = ifa->address.address6.sin6_scope_id;
|
|
|
246 break;
|
|
|
247 }
|
|
|
248 }
|
|
|
249
|
|
|
250 uv_free_interface_addresses(interfaces, count);
|
|
|
251
|
|
|
252 #else
|
|
|
253 struct ifaddrs* ifa;
|
|
|
254 struct ifaddrs* p;
|
|
|
255
|
|
|
256 if (getifaddrs(&ifa))
|
|
|
257 return 0;
|
|
|
258
|
|
|
259 for (p = ifa; p != NULL; p = p->ifa_next)
|
|
|
260 if (p->ifa_addr != NULL)
|
|
|
261 if (uv__is_ipv6_link_local(p->ifa_addr))
|
|
|
262 break;
|
|
|
263
|
|
|
264 rv = 0;
|
|
|
265 if (p != NULL) {
|
|
|
266 a6 = (struct sockaddr_in6*) p->ifa_addr;
|
|
|
267 rv = a6->sin6_scope_id;
|
|
|
268 }
|
|
|
269
|
|
|
270 freeifaddrs(ifa);
|
|
|
271 #endif /* defined(_AIX) */
|
|
|
272
|
|
|
273 return rv;
|
|
|
274 }
|
|
|
275
|
|
|
276
|
|
|
277 int uv__tcp_connect(uv_connect_t* req,
|
|
|
278 uv_tcp_t* handle,
|
|
|
279 const struct sockaddr* addr,
|
|
|
280 unsigned int addrlen,
|
|
|
281 uv_connect_cb cb) {
|
|
|
282 struct sockaddr_in6 tmp6;
|
|
|
283 int err;
|
|
|
284 int r;
|
|
|
285
|
|
|
286 assert(handle->type == UV_TCP);
|
|
|
287
|
|
|
288 if (handle->connect_req != NULL)
|
|
|
289 return UV_EALREADY; /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
|
|
|
290
|
|
|
291 if (handle->delayed_error != 0)
|
|
|
292 goto out;
|
|
|
293
|
|
|
294 err = maybe_new_socket(handle,
|
|
|
295 addr->sa_family,
|
|
|
296 UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
|
|
297 if (err)
|
|
|
298 return err;
|
|
|
299
|
|
|
300 if (uv__is_ipv6_link_local(addr)) {
|
|
|
301 memcpy(&tmp6, addr, sizeof(tmp6));
|
|
|
302 if (tmp6.sin6_scope_id == 0) {
|
|
|
303 tmp6.sin6_scope_id = uv__ipv6_link_local_scope_id();
|
|
|
304 addr = (void*) &tmp6;
|
|
|
305 }
|
|
|
306 }
|
|
|
307
|
|
|
308 do {
|
|
|
309 errno = 0;
|
|
|
310 r = connect(uv__stream_fd(handle), addr, addrlen);
|
|
|
311 } while (r == -1 && errno == EINTR);
|
|
|
312
|
|
|
313 /* We not only check the return value, but also check the errno != 0.
|
|
|
314 * Because in rare cases connect() will return -1 but the errno
|
|
|
315 * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
|
|
|
316 * and actually the tcp three-way handshake is completed.
|
|
|
317 */
|
|
|
318 if (r == -1 && errno != 0) {
|
|
|
319 if (errno == EINPROGRESS)
|
|
|
320 ; /* not an error */
|
|
|
321 else if (errno == ECONNREFUSED
|
|
|
322 #if defined(__OpenBSD__)
|
|
|
323 || errno == EINVAL
|
|
|
324 #endif
|
|
|
325 )
|
|
|
326 /* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
|
|
|
327 * next tick to report the error. Solaris and OpenBSD wants to report
|
|
|
328 * immediately -- other unixes want to wait.
|
|
|
329 */
|
|
|
330 handle->delayed_error = UV__ERR(ECONNREFUSED);
|
|
|
331 else
|
|
|
332 return UV__ERR(errno);
|
|
|
333 }
|
|
|
334
|
|
|
335 out:
|
|
|
336
|
|
|
337 uv__req_init(handle->loop, req, UV_CONNECT);
|
|
|
338 req->cb = cb;
|
|
|
339 req->handle = (uv_stream_t*) handle;
|
|
|
340 uv__queue_init(&req->queue);
|
|
|
341 handle->connect_req = req;
|
|
|
342
|
|
|
343 uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
|
|
|
344
|
|
|
345 if (handle->delayed_error)
|
|
|
346 uv__io_feed(handle->loop, &handle->io_watcher);
|
|
|
347
|
|
|
348 return 0;
|
|
|
349 }
|
|
|
350
|
|
|
351
|
|
|
352 int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
|
|
|
353 int err;
|
|
|
354
|
|
|
355 if (uv__fd_exists(handle->loop, sock))
|
|
|
356 return UV_EEXIST;
|
|
|
357
|
|
|
358 err = uv__nonblock(sock, 1);
|
|
|
359 if (err)
|
|
|
360 return err;
|
|
|
361
|
|
|
362 return uv__stream_open((uv_stream_t*)handle,
|
|
|
363 sock,
|
|
|
364 UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
|
|
|
365 }
|
|
|
366
|
|
|
367
|
|
|
368 int uv_tcp_getsockname(const uv_tcp_t* handle,
|
|
|
369 struct sockaddr* name,
|
|
|
370 int* namelen) {
|
|
|
371
|
|
|
372 if (handle->delayed_error)
|
|
|
373 return handle->delayed_error;
|
|
|
374
|
|
|
375 return uv__getsockpeername((const uv_handle_t*) handle,
|
|
|
376 getsockname,
|
|
|
377 name,
|
|
|
378 namelen);
|
|
|
379 }
|
|
|
380
|
|
|
381
|
|
|
382 int uv_tcp_getpeername(const uv_tcp_t* handle,
|
|
|
383 struct sockaddr* name,
|
|
|
384 int* namelen) {
|
|
|
385
|
|
|
386 if (handle->delayed_error)
|
|
|
387 return handle->delayed_error;
|
|
|
388
|
|
|
389 return uv__getsockpeername((const uv_handle_t*) handle,
|
|
|
390 getpeername,
|
|
|
391 name,
|
|
|
392 namelen);
|
|
|
393 }
|
|
|
394
|
|
|
395
|
|
|
396 int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
|
|
|
397 int fd;
|
|
|
398 struct linger l = { 1, 0 };
|
|
|
399
|
|
|
400 /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
|
|
|
401 if (uv__is_stream_shutting(handle))
|
|
|
402 return UV_EINVAL;
|
|
|
403
|
|
|
404 fd = uv__stream_fd(handle);
|
|
|
405 if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) {
|
|
|
406 if (errno == EINVAL) {
|
|
|
407 /* Open Group Specifications Issue 7, 2018 edition states that
|
|
|
408 * EINVAL may mean the socket has been shut down already.
|
|
|
409 * Behavior observed on Solaris, illumos and macOS. */
|
|
|
410 errno = 0;
|
|
|
411 } else {
|
|
|
412 return UV__ERR(errno);
|
|
|
413 }
|
|
|
414 }
|
|
|
415
|
|
|
416 uv_close((uv_handle_t*) handle, close_cb);
|
|
|
417 return 0;
|
|
|
418 }
|
|
|
419
|
|
|
420
|
|
|
421 int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
|
|
|
422 unsigned int flags;
|
|
|
423 int err;
|
|
|
424
|
|
|
425 if (tcp->delayed_error)
|
|
|
426 return tcp->delayed_error;
|
|
|
427
|
|
|
428 flags = 0;
|
|
|
429 #if defined(__MVS__)
|
|
|
430 /* on zOS the listen call does not bind automatically
|
|
|
431 if the socket is unbound. Hence the manual binding to
|
|
|
432 an arbitrary port is required to be done manually
|
|
|
433 */
|
|
|
434 flags |= UV_HANDLE_BOUND;
|
|
|
435 #endif
|
|
|
436 err = maybe_new_socket(tcp, AF_INET, flags);
|
|
|
437 if (err)
|
|
|
438 return err;
|
|
|
439
|
|
|
440 if (listen(tcp->io_watcher.fd, backlog))
|
|
|
441 return UV__ERR(errno);
|
|
|
442
|
|
|
443 tcp->connection_cb = cb;
|
|
|
444 tcp->flags |= UV_HANDLE_BOUND;
|
|
|
445
|
|
|
446 /* Start listening for connections. */
|
|
|
447 tcp->io_watcher.cb = uv__server_io;
|
|
|
448 uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
|
|
|
449
|
|
|
450 return 0;
|
|
|
451 }
|
|
|
452
|
|
|
453
|
|
|
454 int uv__tcp_nodelay(int fd, int on) {
|
|
|
455 if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
|
|
|
456 return UV__ERR(errno);
|
|
|
457 return 0;
|
|
|
458 }
|
|
|
459
|
|
|
460
|
|
|
461 #if (defined(UV__SOLARIS_11_4) && !UV__SOLARIS_11_4) || \
|
|
|
462 (defined(__DragonFly__) && __DragonFly_version < 500702)
|
|
|
463 /* DragonFlyBSD <500702 and Solaris <11.4 require millisecond units
|
|
|
464 * for TCP keepalive options. */
|
|
|
465 #define UV_KEEPALIVE_FACTOR(x) (x *= 1000)
|
|
|
466 #else
|
|
|
467 #define UV_KEEPALIVE_FACTOR(x)
|
|
|
468 #endif
|
|
|
469 int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
|
|
|
470 int idle;
|
|
|
471 int intvl;
|
|
|
472 int cnt;
|
|
|
473
|
|
|
474 (void) &idle;
|
|
|
475 (void) &intvl;
|
|
|
476 (void) &cnt;
|
|
|
477
|
|
|
478 if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
|
|
|
479 return UV__ERR(errno);
|
|
|
480
|
|
|
481 if (!on)
|
|
|
482 return 0;
|
|
|
483
|
|
|
484 if (delay < 1)
|
|
|
485 return UV_EINVAL;
|
|
|
486
|
|
|
487 #ifdef __sun
|
|
|
488 /* The implementation of TCP keep-alive on Solaris/SmartOS is a bit unusual
|
|
|
489 * compared to other Unix-like systems.
|
|
|
490 * Thus, we need to specialize it on Solaris.
|
|
|
491 *
|
|
|
492 * There are two keep-alive mechanisms on Solaris:
|
|
|
493 * - By default, the first keep-alive probe is sent out after a TCP connection is idle for two hours.
|
|
|
494 * If the peer does not respond to the probe within eight minutes, the TCP connection is aborted.
|
|
|
495 * You can alter the interval for sending out the first probe using the socket option TCP_KEEPALIVE_THRESHOLD
|
|
|
496 * in milliseconds or TCP_KEEPIDLE in seconds.
|
|
|
497 * The system default is controlled by the TCP ndd parameter tcp_keepalive_interval. The minimum value is ten seconds.
|
|
|
498 * The maximum is ten days, while the default is two hours. If you receive no response to the probe,
|
|
|
499 * you can use the TCP_KEEPALIVE_ABORT_THRESHOLD socket option to change the time threshold for aborting a TCP connection.
|
|
|
500 * The option value is an unsigned integer in milliseconds. The value zero indicates that TCP should never time out and
|
|
|
501 * abort the connection when probing. The system default is controlled by the TCP ndd parameter tcp_keepalive_abort_interval.
|
|
|
502 * The default is eight minutes.
|
|
|
503 *
|
|
|
504 * - The second implementation is activated if socket option TCP_KEEPINTVL and/or TCP_KEEPCNT are set.
|
|
|
505 * The time between each consequent probes is set by TCP_KEEPINTVL in seconds.
|
|
|
506 * The minimum value is ten seconds. The maximum is ten days, while the default is two hours.
|
|
|
507 * The TCP connection will be aborted after certain amount of probes, which is set by TCP_KEEPCNT, without receiving response.
|
|
|
508 */
|
|
|
509
|
|
|
510 idle = delay;
|
|
|
511 /* Kernel expects at least 10 seconds. */
|
|
|
512 if (idle < 10)
|
|
|
513 idle = 10;
|
|
|
514 /* Kernel expects at most 10 days. */
|
|
|
515 if (idle > 10*24*60*60)
|
|
|
516 idle = 10*24*60*60;
|
|
|
517
|
|
|
518 UV_KEEPALIVE_FACTOR(idle);
|
|
|
519
|
|
|
520 /* `TCP_KEEPIDLE`, `TCP_KEEPINTVL`, and `TCP_KEEPCNT` were not available on Solaris
|
|
|
521 * until version 11.4, but let's take a chance here. */
|
|
|
522 #if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
|
|
|
523 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
|
|
524 return UV__ERR(errno);
|
|
|
525
|
|
|
526 intvl = 10; /* required at least 10 seconds */
|
|
|
527 UV_KEEPALIVE_FACTOR(intvl);
|
|
|
528 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
|
|
529 return UV__ERR(errno);
|
|
|
530
|
|
|
531 cnt = 1; /* 1 retry, ensure (TCP_KEEPINTVL * TCP_KEEPCNT) is 10 seconds */
|
|
|
532 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
|
|
533 return UV__ERR(errno);
|
|
|
534 #else
|
|
|
535 /* Fall back to the first implementation of tcp-alive mechanism for older Solaris,
|
|
|
536 * simulate the tcp-alive mechanism on other platforms via `TCP_KEEPALIVE_THRESHOLD` + `TCP_KEEPALIVE_ABORT_THRESHOLD`.
|
|
|
537 */
|
|
|
538 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD, &idle, sizeof(idle)))
|
|
|
539 return UV__ERR(errno);
|
|
|
540
|
|
|
541 /* Note that the consequent probes will not be sent at equal intervals on Solaris,
|
|
|
542 * but will be sent using the exponential backoff algorithm. */
|
|
|
543 int time_to_abort = 10; /* 10 seconds */
|
|
|
544 UV_KEEPALIVE_FACTOR(time_to_abort);
|
|
|
545 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD, &time_to_abort, sizeof(time_to_abort)))
|
|
|
546 return UV__ERR(errno);
|
|
|
547 #endif
|
|
|
548
|
|
|
549 #else /* !defined(__sun) */
|
|
|
550
|
|
|
551 idle = delay;
|
|
|
552 UV_KEEPALIVE_FACTOR(idle);
|
|
|
553 #ifdef TCP_KEEPIDLE
|
|
|
554 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)))
|
|
|
555 return UV__ERR(errno);
|
|
|
556 #elif defined(TCP_KEEPALIVE)
|
|
|
557 /* Darwin/macOS uses TCP_KEEPALIVE in place of TCP_KEEPIDLE. */
|
|
|
558 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &idle, sizeof(idle)))
|
|
|
559 return UV__ERR(errno);
|
|
|
560 #endif
|
|
|
561
|
|
|
562 #ifdef TCP_KEEPINTVL
|
|
|
563 intvl = 1; /* 1 second; same as default on Win32 */
|
|
|
564 UV_KEEPALIVE_FACTOR(intvl);
|
|
|
565 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
|
|
|
566 return UV__ERR(errno);
|
|
|
567 #endif
|
|
|
568
|
|
|
569 #ifdef TCP_KEEPCNT
|
|
|
570 cnt = 10; /* 10 retries; same as hardcoded on Win32 */
|
|
|
571 if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
|
|
|
572 return UV__ERR(errno);
|
|
|
573 #endif
|
|
|
574
|
|
|
575 #endif /* !defined(__sun) */
|
|
|
576 return 0;
|
|
|
577 }
|
|
|
578
|
|
|
579
|
|
|
580 int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
|
|
|
581 int err;
|
|
|
582
|
|
|
583 if (uv__stream_fd(handle) != -1) {
|
|
|
584 err = uv__tcp_nodelay(uv__stream_fd(handle), on);
|
|
|
585 if (err)
|
|
|
586 return err;
|
|
|
587 }
|
|
|
588
|
|
|
589 if (on)
|
|
|
590 handle->flags |= UV_HANDLE_TCP_NODELAY;
|
|
|
591 else
|
|
|
592 handle->flags &= ~UV_HANDLE_TCP_NODELAY;
|
|
|
593
|
|
|
594 return 0;
|
|
|
595 }
|
|
|
596
|
|
|
597
|
|
|
598 int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
|
|
|
599 int err;
|
|
|
600
|
|
|
601 if (uv__stream_fd(handle) != -1) {
|
|
|
602 err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
|
|
|
603 if (err)
|
|
|
604 return err;
|
|
|
605 }
|
|
|
606
|
|
|
607 if (on)
|
|
|
608 handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
|
|
|
609 else
|
|
|
610 handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
|
|
|
611
|
|
|
612 /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
|
|
|
613 * uv_tcp_t with an int that's almost never used...
|
|
|
614 */
|
|
|
615
|
|
|
616 return 0;
|
|
|
617 }
|
|
|
618
|
|
|
619
|
|
|
620 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
|
|
|
621 return 0;
|
|
|
622 }
|
|
|
623
|
|
|
624
|
|
|
625 void uv__tcp_close(uv_tcp_t* handle) {
|
|
|
626 uv__stream_close((uv_stream_t*)handle);
|
|
|
627 }
|
|
|
628
|
|
|
629
|
|
|
630 int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
|
|
|
631 uv_os_sock_t temp[2];
|
|
|
632 int err;
|
|
|
633 #if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC)
|
|
|
634 int flags;
|
|
|
635
|
|
|
636 flags = type | SOCK_CLOEXEC;
|
|
|
637 if ((flags0 & UV_NONBLOCK_PIPE) && (flags1 & UV_NONBLOCK_PIPE))
|
|
|
638 flags |= SOCK_NONBLOCK;
|
|
|
639
|
|
|
640 if (socketpair(AF_UNIX, flags, protocol, temp))
|
|
|
641 return UV__ERR(errno);
|
|
|
642
|
|
|
643 if (flags & UV_FS_O_NONBLOCK) {
|
|
|
644 fds[0] = temp[0];
|
|
|
645 fds[1] = temp[1];
|
|
|
646 return 0;
|
|
|
647 }
|
|
|
648 #else
|
|
|
649 if (socketpair(AF_UNIX, type, protocol, temp))
|
|
|
650 return UV__ERR(errno);
|
|
|
651
|
|
|
652 if ((err = uv__cloexec(temp[0], 1)))
|
|
|
653 goto fail;
|
|
|
654 if ((err = uv__cloexec(temp[1], 1)))
|
|
|
655 goto fail;
|
|
|
656 #endif
|
|
|
657
|
|
|
658 if (flags0 & UV_NONBLOCK_PIPE)
|
|
|
659 if ((err = uv__nonblock(temp[0], 1)))
|
|
|
660 goto fail;
|
|
|
661 if (flags1 & UV_NONBLOCK_PIPE)
|
|
|
662 if ((err = uv__nonblock(temp[1], 1)))
|
|
|
663 goto fail;
|
|
|
664
|
|
|
665 fds[0] = temp[0];
|
|
|
666 fds[1] = temp[1];
|
|
|
667 return 0;
|
|
|
668
|
|
|
669 fail:
|
|
|
670 uv__close(temp[0]);
|
|
|
671 uv__close(temp[1]);
|
|
|
672 return err;
|
|
|
673 }
|