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
write_ni(int fd,const void * buf,size_t n)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
read_ni(int fd,void * buf,size_t n)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
send_ni(int fd,const void * buf,size_t n,int flags)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
recv_ni(int fd,void * buf,size_t n,int flags)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
eventfd_alert(int fd)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
eventfd_drain(int fd)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
pipe_alert(int fd)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
pipe_drain(int fd)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
sock_alert(tor_socket_t fd)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
sock_drain(tor_socket_t fd)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
alert_sockets_create(alert_sockets_t * socks_out,uint32_t flags)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
alert_sockets_close(alert_sockets_t * socks)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 }
296