tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

alertsock.c (7466B)


      1 /* Copyright (c) 2003-2004, Roger Dingledine
      2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
      3 * Copyright (c) 2007-2021, The Tor Project, Inc. */
      4 /* See LICENSE for licensing information */
      5 
      6 /**
      7 * \file alertsock.c
      8 *
      9 * \brief Use a socket to alert the main thread from a worker thread.
     10 *
     11 * Because our main loop spends all of its time in select, epoll, kqueue, or
     12 * etc, we need a way to wake up the main loop from another thread.  This code
     13 * tries to provide the fastest reasonable way to do that, depending on our
     14 * platform.
     15 **/
     16 
     17 #include "orconfig.h"
     18 #include "lib/net/alertsock.h"
     19 #include "lib/net/socket.h"
     20 #include "lib/log/util_bug.h"
     21 
     22 #ifdef HAVE_SYS_EVENTFD_H
     23 #include <sys/eventfd.h>
     24 #endif
     25 #ifdef HAVE_FCNTL_H
     26 #include <fcntl.h>
     27 #endif
     28 #ifdef HAVE_UNISTD_H
     29 #include <unistd.h>
     30 #endif
     31 #ifdef HAVE_SYS_SOCKET_H
     32 #include <sys/socket.h>
     33 #endif
     34 #ifdef _WIN32
     35 #include <winsock2.h>
     36 #endif
     37 
     38 #if defined(HAVE_EVENTFD) || defined(HAVE_PIPE)
     39 /* As write(), but retry on EINTR, and return the negative error code on
     40 * error. */
     41 static int
     42 write_ni(int fd, const void *buf, size_t n)
     43 {
     44  int r;
     45 again:
     46  r = (int) write(fd, buf, n);
     47  if (r < 0) {
     48    if (errno == EINTR)
     49      goto again;
     50    else
     51      return -errno;
     52  }
     53  return r;
     54 }
     55 /* As read(), but retry on EINTR, and return the negative error code on error.
     56 */
     57 static int
     58 read_ni(int fd, void *buf, size_t n)
     59 {
     60  int r;
     61 again:
     62  r = (int) read(fd, buf, n);
     63  if (r < 0) {
     64    if (errno == EINTR)
     65      goto again;
     66    else
     67      return -errno;
     68  }
     69  return r;
     70 }
     71 #endif /* defined(HAVE_EVENTFD) || defined(HAVE_PIPE) */
     72 
     73 /** As send(), but retry on EINTR, and return the negative error code on
     74 * error. */
     75 static int
     76 send_ni(int fd, const void *buf, size_t n, int flags)
     77 {
     78  int r;
     79 again:
     80  r = (int) send(fd, buf, n, flags);
     81  if (r < 0) {
     82    int error = tor_socket_errno(fd);
     83    if (ERRNO_IS_EINTR(error))
     84      goto again;
     85    else
     86      return -error;
     87  }
     88  return r;
     89 }
     90 
     91 /** As recv(), but retry on EINTR, and return the negative error code on
     92 * error. */
     93 static int
     94 recv_ni(int fd, void *buf, size_t n, int flags)
     95 {
     96  int r;
     97 again:
     98  r = (int) recv(fd, buf, n, flags);
     99  if (r < 0) {
    100    int error = tor_socket_errno(fd);
    101    if (ERRNO_IS_EINTR(error))
    102      goto again;
    103    else
    104      return -error;
    105  }
    106  return r;
    107 }
    108 
    109 #ifdef HAVE_EVENTFD
    110 /* Increment the event count on an eventfd <b>fd</b> */
    111 static int
    112 eventfd_alert(int fd)
    113 {
    114  uint64_t u = 1;
    115  int r = write_ni(fd, (void*)&u, sizeof(u));
    116  if (r < 0 && -r != EAGAIN)
    117    return -1;
    118  return 0;
    119 }
    120 
    121 /* Drain all events from an eventfd <b>fd</b>. */
    122 static int
    123 eventfd_drain(int fd)
    124 {
    125  uint64_t u = 0;
    126  int r = read_ni(fd, (void*)&u, sizeof(u));
    127  if (r < 0 && -r != EAGAIN)
    128    return r;
    129  return 0;
    130 }
    131 #endif /* defined(HAVE_EVENTFD) */
    132 
    133 #ifdef HAVE_PIPE
    134 /** Send a byte over a pipe. Return 0 on success or EAGAIN; -1 on error */
    135 static int
    136 pipe_alert(int fd)
    137 {
    138  ssize_t r = write_ni(fd, "x", 1);
    139  if (r < 0 && -r != EAGAIN)
    140    return (int)r;
    141  return 0;
    142 }
    143 
    144 /** Drain all input from a pipe <b>fd</b> and ignore it.  Return 0 on
    145 * success, -1 on error. */
    146 static int
    147 pipe_drain(int fd)
    148 {
    149  char buf[32];
    150  ssize_t r;
    151  do {
    152    r = read_ni(fd, buf, sizeof(buf));
    153  } while (r > 0);
    154  if (r < 0 && errno != EAGAIN)
    155    return -errno;
    156  /* A value of r = 0 means EOF on the fd so successfully drained. */
    157  return 0;
    158 }
    159 #endif /* defined(HAVE_PIPE) */
    160 
    161 /** Send a byte on socket <b>fd</b>t.  Return 0 on success or EAGAIN,
    162 * -1 on error. */
    163 static int
    164 sock_alert(tor_socket_t fd)
    165 {
    166  ssize_t r = send_ni(fd, "x", 1, 0);
    167  if (r < 0 && !ERRNO_IS_EAGAIN(-r))
    168    return (int)r;
    169  return 0;
    170 }
    171 
    172 /** Drain all the input from a socket <b>fd</b>, and ignore it.  Return 0 on
    173 * success, -errno on error. */
    174 static int
    175 sock_drain(tor_socket_t fd)
    176 {
    177  char buf[32];
    178  ssize_t r;
    179  do {
    180    r = recv_ni(fd, buf, sizeof(buf), 0);
    181  } while (r > 0);
    182  if (r < 0 && !ERRNO_IS_EAGAIN(-r))
    183    return (int)r;
    184  /* A value of r = 0 means EOF on the fd so successfully drained. */
    185  return 0;
    186 }
    187 
    188 /** Allocate a new set of alert sockets, and set the appropriate function
    189 * pointers, in <b>socks_out</b>. */
    190 int
    191 alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags)
    192 {
    193  tor_socket_t socks[2] = { TOR_INVALID_SOCKET, TOR_INVALID_SOCKET };
    194 
    195 #ifdef HAVE_EVENTFD
    196  /* First, we try the Linux eventfd() syscall.  This gives a 64-bit counter
    197   * associated with a single file descriptor. */
    198 #if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
    199  if (!(flags & ASOCKS_NOEVENTFD2))
    200    socks[0] = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
    201 #endif
    202  if (socks[0] < 0 && !(flags & ASOCKS_NOEVENTFD)) {
    203    socks[0] = eventfd(0,0);
    204    if (socks[0] >= 0) {
    205      if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 ||
    206          set_socket_nonblocking(socks[0]) < 0) {
    207        // LCOV_EXCL_START -- if eventfd succeeds, fcntl will.
    208        tor_assert_nonfatal_unreached();
    209        close(socks[0]);
    210        return -1;
    211        // LCOV_EXCL_STOP
    212      }
    213    }
    214  }
    215  if (socks[0] >= 0) {
    216    socks_out->read_fd = socks_out->write_fd = socks[0];
    217    socks_out->alert_fn = eventfd_alert;
    218    socks_out->drain_fn = eventfd_drain;
    219    return 0;
    220  }
    221 #endif /* defined(HAVE_EVENTFD) */
    222 
    223 #ifdef HAVE_PIPE2
    224  /* Now we're going to try pipes. First type the pipe2() syscall, if we
    225   * have it, so we can save some calls... */
    226  if (!(flags & ASOCKS_NOPIPE2) &&
    227      pipe2(socks, O_NONBLOCK|O_CLOEXEC) == 0) {
    228    socks_out->read_fd = socks[0];
    229    socks_out->write_fd = socks[1];
    230    socks_out->alert_fn = pipe_alert;
    231    socks_out->drain_fn = pipe_drain;
    232    return 0;
    233  }
    234 #endif /* defined(HAVE_PIPE2) */
    235 
    236 #ifdef HAVE_PIPE
    237  /* Now try the regular pipe() syscall.  Pipes have a bit lower overhead than
    238   * socketpairs, fwict. */
    239  if (!(flags & ASOCKS_NOPIPE) &&
    240      pipe(socks) == 0) {
    241    if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 ||
    242        fcntl(socks[1], F_SETFD, FD_CLOEXEC) < 0 ||
    243        set_socket_nonblocking(socks[0]) < 0 ||
    244        set_socket_nonblocking(socks[1]) < 0) {
    245      // LCOV_EXCL_START -- if pipe succeeds, you can fcntl the output
    246      tor_assert_nonfatal_unreached();
    247      close(socks[0]);
    248      close(socks[1]);
    249      return -1;
    250      // LCOV_EXCL_STOP
    251    }
    252    socks_out->read_fd = socks[0];
    253    socks_out->write_fd = socks[1];
    254    socks_out->alert_fn = pipe_alert;
    255    socks_out->drain_fn = pipe_drain;
    256    return 0;
    257  }
    258 #endif /* defined(HAVE_PIPE) */
    259 
    260  /* If nothing else worked, fall back on socketpair(). */
    261  if (!(flags & ASOCKS_NOSOCKETPAIR) &&
    262      tor_socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == 0) {
    263    if (set_socket_nonblocking(socks[0]) < 0 ||
    264        set_socket_nonblocking(socks[1])) {
    265      // LCOV_EXCL_START -- if socketpair worked, you can make it nonblocking.
    266      tor_assert_nonfatal_unreached();
    267      tor_close_socket(socks[0]);
    268      tor_close_socket(socks[1]);
    269      return -1;
    270      // LCOV_EXCL_STOP
    271    }
    272    socks_out->read_fd = socks[0];
    273    socks_out->write_fd = socks[1];
    274    socks_out->alert_fn = sock_alert;
    275    socks_out->drain_fn = sock_drain;
    276    return 0;
    277  }
    278  return -1;
    279 }
    280 
    281 /** Close the sockets in <b>socks</b>. */
    282 void
    283 alert_sockets_close(alert_sockets_t *socks)
    284 {
    285  if (socks->alert_fn == sock_alert) {
    286    /* they are sockets. */
    287    tor_close_socket(socks->read_fd);
    288    tor_close_socket(socks->write_fd);
    289  } else {
    290    close(socks->read_fd);
    291    if (socks->write_fd != socks->read_fd)
    292      close(socks->write_fd);
    293  }
    294  socks->read_fd = socks->write_fd = -1;
    295 }