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 }