xref: /libuv/src/unix/tcp.c (revision fedfa989)
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 
maybe_bind_socket(int fd)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 
new_socket(uv_tcp_t * handle,int domain,unsigned int flags)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 
maybe_new_socket(uv_tcp_t * handle,int domain,unsigned int flags)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 
uv_tcp_init_ex(uv_loop_t * loop,uv_tcp_t * tcp,unsigned int flags)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 
uv_tcp_init(uv_loop_t * loop,uv_tcp_t * tcp)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 
uv__tcp_bind(uv_tcp_t * tcp,const struct sockaddr * addr,unsigned int addrlen,unsigned int flags)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 
uv__is_ipv6_link_local(const struct sockaddr * addr)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 
uv__ipv6_link_local_scope_id(void)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 
uv__tcp_connect(uv_connect_t * req,uv_tcp_t * handle,const struct sockaddr * addr,unsigned int addrlen,uv_connect_cb cb)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 
uv_tcp_open(uv_tcp_t * handle,uv_os_sock_t sock)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 
uv_tcp_getsockname(const uv_tcp_t * handle,struct sockaddr * name,int * namelen)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 
uv_tcp_getpeername(const uv_tcp_t * handle,struct sockaddr * name,int * namelen)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 
uv_tcp_close_reset(uv_tcp_t * handle,uv_close_cb close_cb)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 
uv__tcp_listen(uv_tcp_t * tcp,int backlog,uv_connection_cb cb)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 
uv__tcp_nodelay(int fd,int on)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
uv__tcp_keepalive(int fd,int on,unsigned int delay)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 
uv_tcp_nodelay(uv_tcp_t * handle,int on)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 
uv_tcp_keepalive(uv_tcp_t * handle,int on,unsigned int delay)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 
uv_tcp_simultaneous_accepts(uv_tcp_t * handle,int enable)620 int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
621   return 0;
622 }
623 
624 
uv__tcp_close(uv_tcp_t * handle)625 void uv__tcp_close(uv_tcp_t* handle) {
626   uv__stream_close((uv_stream_t*)handle);
627 }
628 
629 
uv_socketpair(int type,int protocol,uv_os_sock_t fds[2],int flags0,int flags1)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 }
674