2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
9 #include "internal/quic_reactor.h"
10 #include "internal/common.h"
11 #include "internal/thread_arch.h"
14 * Core I/O Reactor Framework
15 * ==========================
17 void ossl_quic_reactor_init(QUIC_REACTOR *rtor,
18 void (*tick_cb)(QUIC_TICK_RESULT *res, void *arg,
21 OSSL_TIME initial_tick_deadline)
23 rtor->poll_r.type = BIO_POLL_DESCRIPTOR_TYPE_NONE;
24 rtor->poll_w.type = BIO_POLL_DESCRIPTOR_TYPE_NONE;
25 rtor->net_read_desired = 0;
26 rtor->net_write_desired = 0;
27 rtor->tick_deadline = initial_tick_deadline;
29 rtor->tick_cb = tick_cb;
30 rtor->tick_cb_arg = tick_cb_arg;
33 void ossl_quic_reactor_set_poll_r(QUIC_REACTOR *rtor, const BIO_POLL_DESCRIPTOR *r)
38 void ossl_quic_reactor_set_poll_w(QUIC_REACTOR *rtor, const BIO_POLL_DESCRIPTOR *w)
43 const BIO_POLL_DESCRIPTOR *ossl_quic_reactor_get_poll_r(QUIC_REACTOR *rtor)
48 const BIO_POLL_DESCRIPTOR *ossl_quic_reactor_get_poll_w(QUIC_REACTOR *rtor)
53 int ossl_quic_reactor_net_read_desired(QUIC_REACTOR *rtor)
55 return rtor->net_read_desired;
58 int ossl_quic_reactor_net_write_desired(QUIC_REACTOR *rtor)
60 return rtor->net_write_desired;
63 OSSL_TIME ossl_quic_reactor_get_tick_deadline(QUIC_REACTOR *rtor)
65 return rtor->tick_deadline;
68 int ossl_quic_reactor_tick(QUIC_REACTOR *rtor, uint32_t flags)
70 QUIC_TICK_RESULT res = {0};
73 * Note that the tick callback cannot fail; this is intentional. Arguably it
74 * does not make that much sense for ticking to 'fail' (in the sense of an
75 * explicit error indicated to the user) because ticking is by its nature
76 * best effort. If something fatal happens with a connection we can report
77 * it on the next actual application I/O call.
79 rtor->tick_cb(&res, rtor->tick_cb_arg, flags);
81 rtor->net_read_desired = res.net_read_desired;
82 rtor->net_write_desired = res.net_write_desired;
83 rtor->tick_deadline = res.tick_deadline;
88 * Blocking I/O Adaptation Layer
89 * =============================
93 * Utility which can be used to poll on up to two FDs. This is designed to
94 * support use of split FDs (e.g. with SSL_set_rfd and SSL_set_wfd where
95 * different FDs are used for read and write).
97 * Generally use of poll(2) is preferred where available. Windows, however,
98 * hasn't traditionally offered poll(2), only select(2). WSAPoll() was
99 * introduced in Vista but has seemingly been buggy until relatively recent
100 * versions of Windows 10. Moreover we support XP so this is not a suitable
101 * target anyway. However, the traditional issues with select(2) turn out not to
102 * be an issue on Windows; whereas traditional *NIX select(2) uses a bitmap of
103 * FDs (and thus is limited in the magnitude of the FDs expressible), Windows
104 * select(2) is very different. In Windows, socket handles are not allocated
105 * contiguously from zero and thus this bitmap approach was infeasible. Thus in
106 * adapting the Berkeley sockets API to Windows a different approach was taken
107 * whereby the fd_set contains a fixed length array of socket handles and an
108 * integer indicating how many entries are valid; thus Windows select()
109 * ironically is actually much more like *NIX poll(2) than *NIX select(2). In
110 * any case, this means that the relevant limit for Windows select() is the
111 * number of FDs being polled, not the magnitude of those FDs. Since we only
112 * poll for two FDs here, this limit does not concern us.
114 * Usage: rfd and wfd may be the same or different. Either or both may also be
115 * -1. If rfd_want_read is 1, rfd is polled for readability, and if
116 * wfd_want_write is 1, wfd is polled for writability. Note that since any
117 * passed FD is always polled for error conditions, setting rfd_want_read=0 and
118 * wfd_want_write=0 is not the same as passing -1 for both FDs.
120 * deadline is a timestamp to return at. If it is ossl_time_infinite(), the call
123 * Returns 0 on error and 1 on success. Timeout expiry is considered a success
124 * condition. We don't elaborate our return values here because the way we are
125 * actually using this doesn't currently care.
127 * If mutex is non-NULL, it is assumed to be held for write and is unlocked for
128 * the duration of the call.
130 * Precondition: mutex is NULL or is held for write (unchecked)
131 * Postcondition: mutex is NULL or is held for write (unless
132 * CRYPTO_THREAD_write_lock fails)
134 static int poll_two_fds(int rfd, int rfd_want_read,
135 int wfd, int wfd_want_write,
139 #if defined(OPENSSL_SYS_WINDOWS) || !defined(POLLIN)
140 fd_set rfd_set, wfd_set, efd_set;
141 OSSL_TIME now, timeout;
142 struct timeval tv, *ptv;
145 # ifndef OPENSSL_SYS_WINDOWS
147 * On Windows there is no relevant limit to the magnitude of a fd value (see
148 * above). On *NIX the fd_set uses a bitmap and we must check the limit.
150 if (rfd >= FD_SETSIZE || wfd >= FD_SETSIZE)
158 if (rfd != -1 && rfd_want_read)
159 openssl_fdset(rfd, &rfd_set);
160 if (wfd != -1 && wfd_want_write)
161 openssl_fdset(wfd, &wfd_set);
163 /* Always check for error conditions. */
165 openssl_fdset(rfd, &efd_set);
167 openssl_fdset(wfd, &efd_set);
173 if (!ossl_assert(rfd != -1 || wfd != -1
174 || !ossl_time_is_infinite(deadline)))
175 /* Do not block forever; should not happen. */
178 # if defined(OPENSSL_THREADS)
180 ossl_crypto_mutex_unlock(mutex);
185 * select expects a timeout, not a deadline, so do the conversion.
186 * Update for each call to ensure the correct value is used if we repeat
189 if (ossl_time_is_infinite(deadline)) {
192 now = ossl_time_now();
194 * ossl_time_subtract saturates to zero so we don't need to check if
197 timeout = ossl_time_subtract(deadline, now);
198 tv = ossl_time_to_timeval(timeout);
202 pres = select(maxfd + 1, &rfd_set, &wfd_set, &efd_set, ptv);
203 } while (pres == -1 && get_last_socket_error_is_eintr());
205 # if defined(OPENSSL_THREADS)
207 ossl_crypto_mutex_lock(mutex);
210 return pres < 0 ? 0 : 1;
212 int pres, timeout_ms;
213 OSSL_TIME now, timeout;
214 struct pollfd pfds[2] = {0};
219 pfds[npfd].events = (rfd_want_read ? POLLIN : 0)
220 | (wfd_want_write ? POLLOUT : 0);
221 if (rfd >= 0 && pfds[npfd].events != 0)
225 pfds[npfd].events = (rfd_want_read ? POLLIN : 0);
226 if (rfd >= 0 && pfds[npfd].events != 0)
230 pfds[npfd].events = (wfd_want_write ? POLLOUT : 0);
231 if (wfd >= 0 && pfds[npfd].events != 0)
235 if (!ossl_assert(npfd != 0 || !ossl_time_is_infinite(deadline)))
236 /* Do not block forever; should not happen. */
239 # if defined(OPENSSL_THREADS)
241 ossl_crypto_mutex_unlock(mutex);
245 if (ossl_time_is_infinite(deadline)) {
248 now = ossl_time_now();
249 timeout = ossl_time_subtract(deadline, now);
250 timeout_ms = ossl_time2ms(timeout);
253 pres = poll(pfds, npfd, timeout_ms);
254 } while (pres == -1 && get_last_socket_error_is_eintr());
256 # if defined(OPENSSL_THREADS)
258 ossl_crypto_mutex_lock(mutex);
261 return pres < 0 ? 0 : 1;
265 static int poll_descriptor_to_fd(const BIO_POLL_DESCRIPTOR *d, int *fd)
267 if (d == NULL || d->type == BIO_POLL_DESCRIPTOR_TYPE_NONE) {
268 *fd = INVALID_SOCKET;
272 if (d->type != BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD
273 || d->value.fd == INVALID_SOCKET)
281 * Poll up to two abstract poll descriptors. Currently we only support
282 * poll descriptors which represent FDs.
284 * If mutex is non-NULL, it is assumed be a lock currently held for write and is
285 * unlocked for the duration of any wait.
287 * Precondition: mutex is NULL or is held for write (unchecked)
288 * Postcondition: mutex is NULL or is held for write (unless
289 * CRYPTO_THREAD_write_lock fails)
291 static int poll_two_descriptors(const BIO_POLL_DESCRIPTOR *r, int r_want_read,
292 const BIO_POLL_DESCRIPTOR *w, int w_want_write,
298 if (!poll_descriptor_to_fd(r, &rfd)
299 || !poll_descriptor_to_fd(w, &wfd))
302 return poll_two_fds(rfd, r_want_read, wfd, w_want_write, deadline, mutex);
306 * Block until a predicate function evaluates to true.
308 * If mutex is non-NULL, it is assumed be a lock currently held for write and is
309 * unlocked for the duration of any wait.
311 * Precondition: Must hold channel write lock (unchecked)
312 * Precondition: mutex is NULL or is held for write (unchecked)
313 * Postcondition: mutex is NULL or is held for write (unless
314 * CRYPTO_THREAD_write_lock fails)
316 int ossl_quic_reactor_block_until_pred(QUIC_REACTOR *rtor,
317 int (*pred)(void *arg), void *pred_arg,
324 if ((flags & SKIP_FIRST_TICK) != 0)
325 flags &= ~SKIP_FIRST_TICK;
328 ossl_quic_reactor_tick(rtor, 0);
330 if ((res = pred(pred_arg)) != 0)
333 if (!poll_two_descriptors(ossl_quic_reactor_get_poll_r(rtor),
334 ossl_quic_reactor_net_read_desired(rtor),
335 ossl_quic_reactor_get_poll_w(rtor),
336 ossl_quic_reactor_net_write_desired(rtor),
337 ossl_quic_reactor_get_tick_deadline(rtor),
340 * We don't actually care why the call succeeded (timeout, FD
341 * readiness), we just call reactor_tick and start trying to do I/O
342 * things again. If poll_two_fds returns 0, this is some other
343 * non-timeout failure and we should stop here.
345 * TODO(QUIC): In the future we could avoid unnecessary syscalls by
346 * not retrying network I/O that isn't ready based on the result of
347 * the poll call. However this might be difficult because it
348 * requires we do the call to poll(2) or equivalent syscall
349 * ourselves, whereas in the general case the application does the
350 * polling and just calls SSL_handle_events(). Implementing this
351 * optimisation in the future will probably therefore require API