Line data Source code
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 16236 : write_ni(int fd, const void *buf, size_t n)
43 : {
44 16236 : int r;
45 16236 : again:
46 16236 : r = (int) write(fd, buf, n);
47 16236 : if (r < 0) {
48 0 : if (errno == EINTR)
49 0 : goto again;
50 : else
51 0 : 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 23744 : read_ni(int fd, void *buf, size_t n)
59 : {
60 23744 : int r;
61 23744 : again:
62 23744 : r = (int) read(fd, buf, n);
63 23744 : if (r < 0) {
64 7541 : if (errno == EINTR)
65 0 : goto again;
66 : else
67 7541 : 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 2814 : send_ni(int fd, const void *buf, size_t n, int flags)
77 : {
78 2814 : int r;
79 2814 : again:
80 2814 : r = (int) send(fd, buf, n, flags);
81 2814 : if (r < 0) {
82 0 : int error = tor_socket_errno(fd);
83 0 : if (ERRNO_IS_EINTR(error))
84 0 : goto again;
85 : else
86 0 : 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 5597 : recv_ni(int fd, void *buf, size_t n, int flags)
95 : {
96 5597 : int r;
97 5597 : again:
98 5597 : r = (int) recv(fd, buf, n, flags);
99 5597 : if (r < 0) {
100 2797 : int error = tor_socket_errno(fd);
101 2797 : if (ERRNO_IS_EINTR(error))
102 0 : goto again;
103 : else
104 2797 : 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 8675 : eventfd_alert(int fd)
113 : {
114 8675 : uint64_t u = 1;
115 8675 : int r = write_ni(fd, (void*)&u, sizeof(u));
116 8675 : if (r < 0 && -r != EAGAIN)
117 0 : return -1;
118 : return 0;
119 : }
120 :
121 : /* Drain all events from an eventfd <b>fd</b>. */
122 : static int
123 8657 : eventfd_drain(int fd)
124 : {
125 8657 : uint64_t u = 0;
126 8657 : int r = read_ni(fd, (void*)&u, sizeof(u));
127 8657 : if (r < 0 && -r != EAGAIN)
128 0 : 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 7561 : pipe_alert(int fd)
137 : {
138 7561 : ssize_t r = write_ni(fd, "x", 1);
139 7561 : if (r < 0 && -r != EAGAIN)
140 0 : 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 7541 : pipe_drain(int fd)
148 : {
149 15087 : char buf[32];
150 15087 : ssize_t r;
151 15087 : do {
152 15087 : r = read_ni(fd, buf, sizeof(buf));
153 15087 : } while (r > 0);
154 7541 : if (r < 0 && errno != EAGAIN)
155 0 : 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 2814 : sock_alert(tor_socket_t fd)
165 : {
166 2814 : ssize_t r = send_ni(fd, "x", 1, 0);
167 2814 : if (r < 0 && !ERRNO_IS_EAGAIN(-r))
168 0 : 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 2797 : sock_drain(tor_socket_t fd)
176 : {
177 5597 : char buf[32];
178 5597 : ssize_t r;
179 5597 : do {
180 5597 : r = recv_ni(fd, buf, sizeof(buf), 0);
181 5597 : } while (r > 0);
182 2797 : if (r < 0 && !ERRNO_IS_EAGAIN(-r))
183 0 : 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 7 : alert_sockets_create(alert_sockets_t *socks_out, uint32_t flags)
192 : {
193 7 : 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 7 : if (!(flags & ASOCKS_NOEVENTFD2))
200 3 : socks[0] = eventfd(0, EFD_CLOEXEC|EFD_NONBLOCK);
201 : #endif
202 7 : if (socks[0] < 0 && !(flags & ASOCKS_NOEVENTFD)) {
203 1 : socks[0] = eventfd(0,0);
204 1 : if (socks[0] >= 0) {
205 2 : if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 ||
206 1 : 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 7 : if (socks[0] >= 0) {
216 4 : socks_out->read_fd = socks_out->write_fd = socks[0];
217 4 : socks_out->alert_fn = eventfd_alert;
218 4 : socks_out->drain_fn = eventfd_drain;
219 4 : 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 4 : if (!(flags & ASOCKS_NOPIPE2) &&
227 1 : pipe2(socks, O_NONBLOCK|O_CLOEXEC) == 0) {
228 1 : socks_out->read_fd = socks[0];
229 1 : socks_out->write_fd = socks[1];
230 1 : socks_out->alert_fn = pipe_alert;
231 1 : socks_out->drain_fn = pipe_drain;
232 1 : 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 3 : if (!(flags & ASOCKS_NOPIPE) &&
240 1 : pipe(socks) == 0) {
241 2 : if (fcntl(socks[0], F_SETFD, FD_CLOEXEC) < 0 ||
242 2 : fcntl(socks[1], F_SETFD, FD_CLOEXEC) < 0 ||
243 2 : set_socket_nonblocking(socks[0]) < 0 ||
244 1 : 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 1 : socks_out->read_fd = socks[0];
253 1 : socks_out->write_fd = socks[1];
254 1 : socks_out->alert_fn = pipe_alert;
255 1 : socks_out->drain_fn = pipe_drain;
256 1 : return 0;
257 : }
258 : #endif /* defined(HAVE_PIPE) */
259 :
260 : /* If nothing else worked, fall back on socketpair(). */
261 2 : if (!(flags & ASOCKS_NOSOCKETPAIR) &&
262 1 : tor_socketpair(AF_UNIX, SOCK_STREAM, 0, socks) == 0) {
263 2 : if (set_socket_nonblocking(socks[0]) < 0 ||
264 1 : 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 1 : socks_out->read_fd = socks[0];
273 1 : socks_out->write_fd = socks[1];
274 1 : socks_out->alert_fn = sock_alert;
275 1 : socks_out->drain_fn = sock_drain;
276 1 : return 0;
277 : }
278 : return -1;
279 : }
280 :
281 : /** Close the sockets in <b>socks</b>. */
282 : void
283 0 : alert_sockets_close(alert_sockets_t *socks)
284 : {
285 0 : if (socks->alert_fn == sock_alert) {
286 : /* they are sockets. */
287 0 : tor_close_socket(socks->read_fd);
288 0 : tor_close_socket(socks->write_fd);
289 : } else {
290 0 : close(socks->read_fd);
291 0 : if (socks->write_fd != socks->read_fd)
292 0 : close(socks->write_fd);
293 : }
294 0 : socks->read_fd = socks->write_fd = -1;
295 0 : }
|