Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Utilities/cmlibuv/src/unix/tcp.c
Line
Count
Source
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
31
0
static int new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
32
0
  struct sockaddr_storage saddr;
33
0
  socklen_t slen;
34
0
  int sockfd;
35
0
  int err;
36
37
0
  err = uv__socket(domain, SOCK_STREAM, 0);
38
0
  if (err < 0)
39
0
    return err;
40
0
  sockfd = err;
41
42
0
  err = uv__stream_open((uv_stream_t*) handle, sockfd, flags);
43
0
  if (err) {
44
0
    uv__close(sockfd);
45
0
    return err;
46
0
  }
47
48
0
  if (flags & UV_HANDLE_BOUND) {
49
    /* Bind this new socket to an arbitrary port */
50
0
    slen = sizeof(saddr);
51
0
    memset(&saddr, 0, sizeof(saddr));
52
0
    if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen)) {
53
0
      uv__close(sockfd);
54
0
      return UV__ERR(errno);
55
0
    }
56
57
0
    if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen)) {
58
0
      uv__close(sockfd);
59
0
      return UV__ERR(errno);
60
0
    }
61
0
  }
62
63
0
  return 0;
64
0
}
65
66
67
0
static int maybe_new_socket(uv_tcp_t* handle, int domain, unsigned long flags) {
68
0
  struct sockaddr_storage saddr;
69
0
  socklen_t slen;
70
71
0
  if (domain == AF_UNSPEC) {
72
0
    handle->flags |= flags;
73
0
    return 0;
74
0
  }
75
76
0
  if (uv__stream_fd(handle) != -1) {
77
78
0
    if (flags & UV_HANDLE_BOUND) {
79
80
0
      if (handle->flags & UV_HANDLE_BOUND) {
81
        /* It is already bound to a port. */
82
0
        handle->flags |= flags;
83
0
        return 0;
84
0
      }
85
86
      /* Query to see if tcp socket is bound. */
87
0
      slen = sizeof(saddr);
88
0
      memset(&saddr, 0, sizeof(saddr));
89
0
      if (getsockname(uv__stream_fd(handle), (struct sockaddr*) &saddr, &slen))
90
0
        return UV__ERR(errno);
91
92
0
      if ((saddr.ss_family == AF_INET6 &&
93
0
          ((struct sockaddr_in6*) &saddr)->sin6_port != 0) ||
94
0
          (saddr.ss_family == AF_INET &&
95
0
          ((struct sockaddr_in*) &saddr)->sin_port != 0)) {
96
        /* Handle is already bound to a port. */
97
0
        handle->flags |= flags;
98
0
        return 0;
99
0
      }
100
101
      /* Bind to arbitrary port */
102
0
      if (bind(uv__stream_fd(handle), (struct sockaddr*) &saddr, slen))
103
0
        return UV__ERR(errno);
104
0
    }
105
106
0
    handle->flags |= flags;
107
0
    return 0;
108
0
  }
109
110
0
  return new_socket(handle, domain, flags);
111
0
}
112
113
114
0
int uv_tcp_init_ex(uv_loop_t* loop, uv_tcp_t* tcp, unsigned int flags) {
115
0
  int domain;
116
117
  /* Use the lower 8 bits for the domain */
118
0
  domain = flags & 0xFF;
119
0
  if (domain != AF_INET && domain != AF_INET6 && domain != AF_UNSPEC)
120
0
    return UV_EINVAL;
121
122
0
  if (flags & ~0xFF)
123
0
    return UV_EINVAL;
124
125
0
  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
0
  if (domain != AF_UNSPEC) {
132
0
    int err = maybe_new_socket(tcp, domain, 0);
133
0
    if (err) {
134
0
      QUEUE_REMOVE(&tcp->handle_queue);
135
0
      return err;
136
0
    }
137
0
  }
138
139
0
  return 0;
140
0
}
141
142
143
0
int uv_tcp_init(uv_loop_t* loop, uv_tcp_t* tcp) {
144
0
  return uv_tcp_init_ex(loop, tcp, AF_UNSPEC);
145
0
}
146
147
148
int uv__tcp_bind(uv_tcp_t* tcp,
149
                 const struct sockaddr* addr,
150
                 unsigned int addrlen,
151
0
                 unsigned int flags) {
152
0
  int err;
153
0
  int on;
154
155
  /* Cannot set IPv6-only mode on non-IPv6 socket. */
156
0
  if ((flags & UV_TCP_IPV6ONLY) && addr->sa_family != AF_INET6)
157
0
    return UV_EINVAL;
158
159
0
  err = maybe_new_socket(tcp, addr->sa_family, 0);
160
0
  if (err)
161
0
    return err;
162
163
0
  on = 1;
164
0
  if (setsockopt(tcp->io_watcher.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)))
165
0
    return UV__ERR(errno);
166
167
0
#ifndef __OpenBSD__
168
0
#ifdef IPV6_V6ONLY
169
0
  if (addr->sa_family == AF_INET6) {
170
0
    on = (flags & UV_TCP_IPV6ONLY) != 0;
171
0
    if (setsockopt(tcp->io_watcher.fd,
172
0
                   IPPROTO_IPV6,
173
0
                   IPV6_V6ONLY,
174
0
                   &on,
175
0
                   sizeof on) == -1) {
176
#if defined(__MVS__)
177
      if (errno == EOPNOTSUPP)
178
        return UV_EINVAL;
179
#endif
180
0
      return UV__ERR(errno);
181
0
    }
182
0
  }
183
0
#endif
184
0
#endif
185
186
0
  errno = 0;
187
0
  err = bind(tcp->io_watcher.fd, addr, addrlen);
188
0
  if (err == -1 && errno != EADDRINUSE) {
189
0
    if (errno == EAFNOSUPPORT)
190
      /* OSX, other BSDs and SunoS fail with EAFNOSUPPORT when binding a
191
       * socket created with AF_INET to an AF_INET6 address or vice versa. */
192
0
      return UV_EINVAL;
193
0
    return UV__ERR(errno);
194
0
  }
195
0
  tcp->delayed_error = (err == -1) ? UV__ERR(errno) : 0;
196
197
0
  tcp->flags |= UV_HANDLE_BOUND;
198
0
  if (addr->sa_family == AF_INET6)
199
0
    tcp->flags |= UV_HANDLE_IPV6;
200
201
0
  return 0;
202
0
}
203
204
205
int uv__tcp_connect(uv_connect_t* req,
206
                    uv_tcp_t* handle,
207
                    const struct sockaddr* addr,
208
                    unsigned int addrlen,
209
0
                    uv_connect_cb cb) {
210
0
  int err;
211
0
  int r;
212
213
0
  assert(handle->type == UV_TCP);
214
215
0
  if (handle->connect_req != NULL)
216
0
    return UV_EALREADY;  /* FIXME(bnoordhuis) UV_EINVAL or maybe UV_EBUSY. */
217
218
0
  if (handle->delayed_error != 0)
219
0
    goto out;
220
221
0
  err = maybe_new_socket(handle,
222
0
                         addr->sa_family,
223
0
                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
224
0
  if (err)
225
0
    return err;
226
227
0
  do {
228
0
    errno = 0;
229
0
    r = connect(uv__stream_fd(handle), addr, addrlen);
230
0
  } while (r == -1 && errno == EINTR);
231
232
  /* We not only check the return value, but also check the errno != 0.
233
   * Because in rare cases connect() will return -1 but the errno
234
   * is 0 (for example, on Android 4.3, OnePlus phone A0001_12_150227)
235
   * and actually the tcp three-way handshake is completed.
236
   */
237
0
  if (r == -1 && errno != 0) {
238
0
    if (errno == EINPROGRESS)
239
0
      ; /* not an error */
240
0
    else if (errno == ECONNREFUSED
241
#if defined(__OpenBSD__)
242
      || errno == EINVAL
243
#endif
244
0
      )
245
    /* If we get ECONNREFUSED (Solaris) or EINVAL (OpenBSD) wait until the
246
     * next tick to report the error. Solaris and OpenBSD wants to report
247
     * immediately -- other unixes want to wait.
248
     */
249
0
      handle->delayed_error = UV__ERR(ECONNREFUSED);
250
0
    else
251
0
      return UV__ERR(errno);
252
0
  }
253
254
0
out:
255
256
0
  uv__req_init(handle->loop, req, UV_CONNECT);
257
0
  req->cb = cb;
258
0
  req->handle = (uv_stream_t*) handle;
259
0
  QUEUE_INIT(&req->queue);
260
0
  handle->connect_req = req;
261
262
0
  uv__io_start(handle->loop, &handle->io_watcher, POLLOUT);
263
264
0
  if (handle->delayed_error)
265
0
    uv__io_feed(handle->loop, &handle->io_watcher);
266
267
0
  return 0;
268
0
}
269
270
271
0
int uv_tcp_open(uv_tcp_t* handle, uv_os_sock_t sock) {
272
0
  int err;
273
274
0
  if (uv__fd_exists(handle->loop, sock))
275
0
    return UV_EEXIST;
276
277
0
  err = uv__nonblock(sock, 1);
278
0
  if (err)
279
0
    return err;
280
281
0
  return uv__stream_open((uv_stream_t*)handle,
282
0
                         sock,
283
0
                         UV_HANDLE_READABLE | UV_HANDLE_WRITABLE);
284
0
}
285
286
287
int uv_tcp_getsockname(const uv_tcp_t* handle,
288
                       struct sockaddr* name,
289
0
                       int* namelen) {
290
291
0
  if (handle->delayed_error)
292
0
    return handle->delayed_error;
293
294
0
  return uv__getsockpeername((const uv_handle_t*) handle,
295
0
                             getsockname,
296
0
                             name,
297
0
                             namelen);
298
0
}
299
300
301
int uv_tcp_getpeername(const uv_tcp_t* handle,
302
                       struct sockaddr* name,
303
0
                       int* namelen) {
304
305
0
  if (handle->delayed_error)
306
0
    return handle->delayed_error;
307
308
0
  return uv__getsockpeername((const uv_handle_t*) handle,
309
0
                             getpeername,
310
0
                             name,
311
0
                             namelen);
312
0
}
313
314
315
0
int uv_tcp_close_reset(uv_tcp_t* handle, uv_close_cb close_cb) {
316
0
  int fd;
317
0
  struct linger l = { 1, 0 };
318
319
  /* Disallow setting SO_LINGER to zero due to some platform inconsistencies */
320
0
  if (handle->flags & UV_HANDLE_SHUTTING)
321
0
    return UV_EINVAL;
322
323
0
  fd = uv__stream_fd(handle);
324
0
  if (0 != setsockopt(fd, SOL_SOCKET, SO_LINGER, &l, sizeof(l))) {
325
0
    if (errno == EINVAL) {
326
      /* Open Group Specifications Issue 7, 2018 edition states that
327
       * EINVAL may mean the socket has been shut down already.
328
       * Behavior observed on Solaris, illumos and macOS. */
329
0
      errno = 0;
330
0
    } else {
331
0
      return UV__ERR(errno);
332
0
    }
333
0
  }
334
335
0
  uv_close((uv_handle_t*) handle, close_cb);
336
0
  return 0;
337
0
}
338
339
340
0
int uv__tcp_listen(uv_tcp_t* tcp, int backlog, uv_connection_cb cb) {
341
0
  static int single_accept_cached = -1;
342
0
  unsigned long flags;
343
0
  int single_accept;
344
0
  int err;
345
346
0
  if (tcp->delayed_error)
347
0
    return tcp->delayed_error;
348
349
0
  single_accept = uv__load_relaxed(&single_accept_cached);
350
0
  if (single_accept == -1) {
351
0
    const char* val = getenv("UV_TCP_SINGLE_ACCEPT");
352
0
    single_accept = (val != NULL && atoi(val) != 0);  /* Off by default. */
353
0
    uv__store_relaxed(&single_accept_cached, single_accept);
354
0
  }
355
356
0
  if (single_accept)
357
0
    tcp->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
358
359
0
  flags = 0;
360
#if defined(__MVS__)
361
  /* on zOS the listen call does not bind automatically
362
     if the socket is unbound. Hence the manual binding to
363
     an arbitrary port is required to be done manually
364
  */
365
  flags |= UV_HANDLE_BOUND;
366
#endif
367
0
  err = maybe_new_socket(tcp, AF_INET, flags);
368
0
  if (err)
369
0
    return err;
370
371
0
  if (listen(tcp->io_watcher.fd, backlog))
372
0
    return UV__ERR(errno);
373
374
0
  tcp->connection_cb = cb;
375
0
  tcp->flags |= UV_HANDLE_BOUND;
376
377
  /* Start listening for connections. */
378
0
  tcp->io_watcher.cb = uv__server_io;
379
0
  uv__io_start(tcp->loop, &tcp->io_watcher, POLLIN);
380
381
0
  return 0;
382
0
}
383
384
385
0
int uv__tcp_nodelay(int fd, int on) {
386
0
  if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on)))
387
0
    return UV__ERR(errno);
388
0
  return 0;
389
0
}
390
391
392
0
int uv__tcp_keepalive(int fd, int on, unsigned int delay) {
393
0
  if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)))
394
0
    return UV__ERR(errno);
395
396
0
#ifdef TCP_KEEPIDLE
397
0
  if (on) {
398
0
    int intvl = 1;  /*  1 second; same as default on Win32 */
399
0
    int cnt = 10;  /* 10 retries; same as hardcoded on Win32 */
400
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &delay, sizeof(delay)))
401
0
      return UV__ERR(errno);
402
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &intvl, sizeof(intvl)))
403
0
      return UV__ERR(errno);
404
0
    if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)))
405
0
      return UV__ERR(errno);
406
0
  }
407
0
#endif
408
409
  /* Solaris/SmartOS, if you don't support keep-alive,
410
   * then don't advertise it in your system headers...
411
   */
412
  /* FIXME(bnoordhuis) That's possibly because sizeof(delay) should be 1. */
413
#if defined(TCP_KEEPALIVE) && !defined(__sun)
414
  if (on && setsockopt(fd, IPPROTO_TCP, TCP_KEEPALIVE, &delay, sizeof(delay)))
415
    return UV__ERR(errno);
416
#endif
417
418
0
  return 0;
419
0
}
420
421
422
0
int uv_tcp_nodelay(uv_tcp_t* handle, int on) {
423
0
  int err;
424
425
0
  if (uv__stream_fd(handle) != -1) {
426
0
    err = uv__tcp_nodelay(uv__stream_fd(handle), on);
427
0
    if (err)
428
0
      return err;
429
0
  }
430
431
0
  if (on)
432
0
    handle->flags |= UV_HANDLE_TCP_NODELAY;
433
0
  else
434
0
    handle->flags &= ~UV_HANDLE_TCP_NODELAY;
435
436
0
  return 0;
437
0
}
438
439
440
0
int uv_tcp_keepalive(uv_tcp_t* handle, int on, unsigned int delay) {
441
0
  int err;
442
443
0
  if (uv__stream_fd(handle) != -1) {
444
0
    err =uv__tcp_keepalive(uv__stream_fd(handle), on, delay);
445
0
    if (err)
446
0
      return err;
447
0
  }
448
449
0
  if (on)
450
0
    handle->flags |= UV_HANDLE_TCP_KEEPALIVE;
451
0
  else
452
0
    handle->flags &= ~UV_HANDLE_TCP_KEEPALIVE;
453
454
  /* TODO Store delay if uv__stream_fd(handle) == -1 but don't want to enlarge
455
   *      uv_tcp_t with an int that's almost never used...
456
   */
457
458
0
  return 0;
459
0
}
460
461
462
0
int uv_tcp_simultaneous_accepts(uv_tcp_t* handle, int enable) {
463
0
  if (enable)
464
0
    handle->flags &= ~UV_HANDLE_TCP_SINGLE_ACCEPT;
465
0
  else
466
0
    handle->flags |= UV_HANDLE_TCP_SINGLE_ACCEPT;
467
0
  return 0;
468
0
}
469
470
471
0
void uv__tcp_close(uv_tcp_t* handle) {
472
0
  uv__stream_close((uv_stream_t*)handle);
473
0
}
474
475
476
0
int uv_socketpair(int type, int protocol, uv_os_sock_t fds[2], int flags0, int flags1) {
477
0
  uv_os_sock_t temp[2];
478
0
  int err;
479
0
#if defined(__FreeBSD__) || defined(__linux__)
480
0
  int flags;
481
482
0
  flags = type | SOCK_CLOEXEC;
483
0
  if ((flags0 & UV_NONBLOCK_PIPE) && (flags1 & UV_NONBLOCK_PIPE))
484
0
    flags |= SOCK_NONBLOCK;
485
486
0
  if (socketpair(AF_UNIX, flags, protocol, temp))
487
0
    return UV__ERR(errno);
488
489
0
  if (flags & UV_FS_O_NONBLOCK) {
490
0
    fds[0] = temp[0];
491
0
    fds[1] = temp[1];
492
0
    return 0;
493
0
  }
494
#else
495
  if (socketpair(AF_UNIX, type, protocol, temp))
496
    return UV__ERR(errno);
497
498
  if ((err = uv__cloexec(temp[0], 1)))
499
    goto fail;
500
  if ((err = uv__cloexec(temp[1], 1)))
501
    goto fail;
502
#endif
503
504
0
  if (flags0 & UV_NONBLOCK_PIPE)
505
0
    if ((err = uv__nonblock(temp[0], 1)))
506
0
        goto fail;
507
0
  if (flags1 & UV_NONBLOCK_PIPE)
508
0
    if ((err = uv__nonblock(temp[1], 1)))
509
0
      goto fail;
510
511
0
  fds[0] = temp[0];
512
0
  fds[1] = temp[1];
513
0
  return 0;
514
515
0
fail:
516
0
  uv__close(temp[0]);
517
0
  uv__close(temp[1]);
518
0
  return err;
519
0
}