1 /*
2 * Copyright 2024-2026 The OpenSSL Project Authors. All Rights Reserved.
3 *
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
8 */
9
10 #include "internal/common.h"
11 #include "internal/quic_ssl.h"
12 #include "internal/quic_reactor_wait_ctx.h"
13 #include <openssl/ssl.h>
14 #include <openssl/err.h>
15 #include "../ssl_local.h"
16 #include "poll_builder.h"
17
18 #if defined(_AIX)
19 /*
20 * Some versions of AIX define macros for events and revents for use when
21 * accessing pollfd structures (see Github issue #24236). That interferes
22 * with our use of these names here. We simply undef them.
23 */
24 #undef revents
25 #undef events
26 #endif
27
28 #define ITEM_N(items, stride, n) \
29 (*(SSL_POLL_ITEM *)((char *)(items) + (n) * (stride)))
30
31 #define FAIL_FROM(n) \
32 do { \
33 size_t j; \
34 \
35 for (j = (n); j < num_items; ++j) \
36 ITEM_N(items, stride, j).revents = 0; \
37 \
38 ok = 0; \
39 goto out; \
40 } while (0)
41
42 #define FAIL_ITEM(idx) \
43 do { \
44 size_t idx_ = (idx); \
45 \
46 ITEM_N(items, stride, idx_).revents = SSL_POLL_EVENT_F; \
47 ++result_count; \
48 FAIL_FROM(idx_ + 1); \
49 } while (0)
50
51 #ifndef OPENSSL_NO_QUIC
52 /*
53 * Test instrumentation only; see poll_builder.h. Always NULL in production
54 * use.
55 */
56 void (*ossl_quic_poll_translate_test_step_cb)(size_t idx, void *arg) = NULL;
57 void *ossl_quic_poll_translate_test_step_cb_arg = NULL;
58
poll_translate_ssl_quic(SSL * ssl,QUIC_REACTOR_WAIT_CTX * wctx,RIO_POLL_BUILDER * rpb,uint64_t events,int * abort_blocking)59 static int poll_translate_ssl_quic(SSL *ssl,
60 QUIC_REACTOR_WAIT_CTX *wctx,
61 RIO_POLL_BUILDER *rpb,
62 uint64_t events,
63 int *abort_blocking)
64 {
65 BIO_POLL_DESCRIPTOR rd, wd;
66 int fd1 = -1, fd2 = -1, fd_nfy = -1;
67 int fd1_r = 0, fd1_w = 0, fd2_w = 0;
68
69 if (SSL_net_read_desired(ssl)) {
70 if (!SSL_get_rpoll_descriptor(ssl, &rd)) {
71 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
72 "SSL_poll requires the network BIOs underlying "
73 "a QUIC SSL object provide poll descriptors");
74 return 0;
75 }
76
77 if (rd.type != BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD) {
78 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
79 "SSL_poll requires the poll descriptors of the "
80 "network BIOs underlying a QUIC SSL object be "
81 "of socket type");
82 return 0;
83 }
84
85 fd1 = rd.value.fd;
86 fd1_r = 1;
87 }
88
89 if (SSL_net_write_desired(ssl)) {
90 if (!SSL_get_wpoll_descriptor(ssl, &wd)) {
91 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
92 "SSL_poll requires the network BIOs underlying "
93 "a QUIC SSL object provide poll descriptors");
94 return 0;
95 }
96
97 if (wd.type != BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD) {
98 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
99 "SSL_poll requires the poll descriptors of the "
100 "network BIOs underlying a QUIC SSL object be "
101 "of socket type");
102 return 0;
103 }
104
105 fd2 = wd.value.fd;
106 fd2_w = 1;
107 }
108
109 if (fd2 == fd1) {
110 fd2 = -1;
111 fd1_w = fd2_w;
112 }
113
114 if (fd1 != -1)
115 if (!ossl_rio_poll_builder_add_fd(rpb, fd1, fd1_r, fd1_w))
116 return 0;
117
118 if (fd2 != -1 && fd2_w)
119 if (!ossl_rio_poll_builder_add_fd(rpb, fd2, /*r = */ 0, fd2_w))
120 return 0;
121
122 /*
123 * Add the notifier FD for the QUIC domain this SSL object is a part of (if
124 * there is one). This ensures we get woken up if another thread calls into
125 * that QUIC domain and some readiness event relevant to the SSL_poll call
126 * on this thread arises without the underlying network socket ever becoming
127 * readable.
128 */
129 fd_nfy = ossl_quic_get_notifier_fd(ssl);
130 if (fd_nfy != -1) {
131 uint64_t revents = 0;
132
133 if (!ossl_rio_poll_builder_add_fd(rpb, fd_nfy, /*r = */ 1, /*w = */ 0))
134 return 0;
135
136 /* Tell QUIC domain we need to receive notifications. */
137 ossl_quic_enter_blocking_section(ssl, wctx);
138
139 /*
140 * Only after the above call returns is it guaranteed that any readiness
141 * events will cause the above notifier to become readable. Therefore,
142 * it is possible the object became ready after our initial
143 * poll_readout() call (before we determined that nothing was ready and
144 * we needed to block). We now need to do another readout, in which case
145 * blocking is to be aborted.
146 */
147 if (!ossl_quic_conn_poll_events(ssl, events, /*do_tick = */ 0, &revents)) {
148 ossl_quic_leave_blocking_section(ssl, wctx);
149 return 0;
150 }
151
152 if (revents != 0) {
153 ossl_quic_leave_blocking_section(ssl, wctx);
154 *abort_blocking = 1;
155 return 1;
156 }
157 }
158
159 return 1;
160 }
161
postpoll_translation_cleanup_ssl_quic(SSL * ssl,QUIC_REACTOR_WAIT_CTX * wctx)162 static void postpoll_translation_cleanup_ssl_quic(SSL *ssl,
163 QUIC_REACTOR_WAIT_CTX *wctx)
164 {
165 if (ossl_quic_get_notifier_fd(ssl) != -1)
166 ossl_quic_leave_blocking_section(ssl, wctx);
167 }
168
postpoll_translation_cleanup(SSL_POLL_ITEM * items,size_t num_items,size_t stride,QUIC_REACTOR_WAIT_CTX * wctx)169 static void postpoll_translation_cleanup(SSL_POLL_ITEM *items,
170 size_t num_items,
171 size_t stride,
172 QUIC_REACTOR_WAIT_CTX *wctx)
173 {
174 SSL_POLL_ITEM *item;
175 SSL *ssl;
176 size_t i;
177
178 for (i = 0; i < num_items; ++i) {
179 item = &ITEM_N(items, stride, i);
180
181 switch (item->desc.type) {
182 case BIO_POLL_DESCRIPTOR_TYPE_SSL:
183 ssl = item->desc.value.ssl;
184 if (ssl == NULL)
185 break;
186
187 switch (ssl->type) {
188 #ifndef OPENSSL_NO_QUIC
189 case SSL_TYPE_QUIC_LISTENER:
190 case SSL_TYPE_QUIC_CONNECTION:
191 case SSL_TYPE_QUIC_XSO:
192 postpoll_translation_cleanup_ssl_quic(ssl, wctx);
193 break;
194 #endif
195 default:
196 break;
197 }
198 break;
199 default:
200 break;
201 }
202 }
203 }
204
poll_translate(SSL_POLL_ITEM * items,size_t num_items,size_t stride,QUIC_REACTOR_WAIT_CTX * wctx,RIO_POLL_BUILDER * rpb,OSSL_TIME * p_earliest_wakeup_deadline,int * abort_blocking,size_t * p_result_count)205 static int poll_translate(SSL_POLL_ITEM *items,
206 size_t num_items,
207 size_t stride,
208 QUIC_REACTOR_WAIT_CTX *wctx,
209 RIO_POLL_BUILDER *rpb,
210 OSSL_TIME *p_earliest_wakeup_deadline,
211 int *abort_blocking,
212 size_t *p_result_count)
213 {
214 int ok = 1;
215 SSL_POLL_ITEM *item;
216 size_t result_count = 0;
217 SSL *ssl;
218 OSSL_TIME earliest_wakeup_deadline = ossl_time_infinite();
219 struct timeval timeout;
220 int is_infinite = 0;
221 size_t i;
222
223 for (i = 0; i < num_items; ++i) {
224 item = &ITEM_N(items, stride, i);
225
226 if (ossl_quic_poll_translate_test_step_cb != NULL)
227 ossl_quic_poll_translate_test_step_cb(i,
228 ossl_quic_poll_translate_test_step_cb_arg);
229
230 switch (item->desc.type) {
231 case BIO_POLL_DESCRIPTOR_TYPE_SSL:
232 ssl = item->desc.value.ssl;
233 if (ssl == NULL)
234 /* NULL items are no-ops and have revents reported as 0 */
235 break;
236
237 switch (ssl->type) {
238 #ifndef OPENSSL_NO_QUIC
239 case SSL_TYPE_QUIC_LISTENER:
240 case SSL_TYPE_QUIC_CONNECTION:
241 case SSL_TYPE_QUIC_XSO:
242 if (!poll_translate_ssl_quic(ssl, wctx, rpb, item->events,
243 abort_blocking))
244 FAIL_ITEM(i);
245
246 if (*abort_blocking)
247 goto out;
248
249 if (!SSL_get_event_timeout(ssl, &timeout, &is_infinite))
250 FAIL_ITEM(i++); /* need to clean up this item too */
251
252 if (!is_infinite)
253 earliest_wakeup_deadline
254 = ossl_time_min(earliest_wakeup_deadline,
255 ossl_time_add(ossl_time_now(),
256 ossl_time_from_timeval(timeout)));
257
258 break;
259 #endif
260
261 default:
262 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
263 "SSL_poll currently only supports QUIC SSL "
264 "objects");
265 FAIL_ITEM(i);
266 }
267 break;
268
269 case BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD:
270 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
271 "SSL_poll currently does not support polling "
272 "sockets");
273 FAIL_ITEM(i);
274
275 default:
276 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
277 "SSL_poll does not support unknown poll descriptor "
278 "type %d",
279 item->desc.type);
280 FAIL_ITEM(i);
281 }
282 }
283
284 out:
285 /*
286 * On abort_blocking, the item which triggered the abort has already
287 * balanced its own enter/leave of the blocking section (see
288 * poll_translate_ssl_quic()); only items 0..i-1 still need cleanup here.
289 */
290 if (!ok || *abort_blocking)
291 postpoll_translation_cleanup(items, i, stride, wctx);
292
293 *p_earliest_wakeup_deadline = earliest_wakeup_deadline;
294 *p_result_count = result_count;
295 return ok;
296 }
297
poll_block(SSL_POLL_ITEM * items,size_t num_items,size_t stride,OSSL_TIME user_deadline,size_t * p_result_count)298 static int poll_block(SSL_POLL_ITEM *items,
299 size_t num_items,
300 size_t stride,
301 OSSL_TIME user_deadline,
302 size_t *p_result_count)
303 {
304 int ok = 0, abort_blocking = 0;
305 RIO_POLL_BUILDER rpb;
306 QUIC_REACTOR_WAIT_CTX wctx;
307 OSSL_TIME earliest_wakeup_deadline;
308
309 /*
310 * Blocking is somewhat involved and involves the following steps:
311 *
312 * - Translation, in which the various logical items (SSL objects, etc.) to
313 * be polled are translated into items an OS polling API understands.
314 *
315 * - Synchronisation bookkeeping. This ensures that we can be woken up
316 * not just by readiness of any underlying file descriptor distilled from
317 * the provided items but also by other threads, which might do work
318 * on a relevant QUIC object to cause the object to be ready without the
319 * underlying file descriptor ever becoming ready from our perspective.
320 *
321 * - The blocking call to the OS polling API.
322 *
323 * - Currently we do not do reverse translation but simply call
324 * poll_readout() again to read out all readiness state for all
325 * descriptors which the user passed.
326 *
327 * TODO(QUIC POLLING): In the future we will do reverse translation here
328 * also to facilitate a more efficient readout.
329 */
330 ossl_quic_reactor_wait_ctx_init(&wctx);
331 ossl_rio_poll_builder_init(&rpb);
332
333 if (!poll_translate(items, num_items, stride, &wctx, &rpb,
334 &earliest_wakeup_deadline,
335 &abort_blocking,
336 p_result_count))
337 goto out;
338
339 if (abort_blocking) {
340 /*
341 * Nothing actually failed; we just shouldn't block because an item
342 * may have become ready while we were setting up. The caller's
343 * retry loop will call poll_readout() again to pick this up.
344 */
345 ok = 1;
346 goto out;
347 }
348
349 earliest_wakeup_deadline = ossl_time_min(earliest_wakeup_deadline,
350 user_deadline);
351
352 ok = ossl_rio_poll_builder_poll(&rpb, earliest_wakeup_deadline);
353
354 postpoll_translation_cleanup(items, num_items, stride, &wctx);
355
356 out:
357 ossl_rio_poll_builder_cleanup(&rpb);
358 ossl_quic_reactor_wait_ctx_cleanup(&wctx);
359 return ok;
360 }
361 #endif
362
poll_readout(SSL_POLL_ITEM * items,size_t num_items,size_t stride,int do_tick,size_t * p_result_count)363 static int poll_readout(SSL_POLL_ITEM *items,
364 size_t num_items,
365 size_t stride,
366 int do_tick,
367 size_t *p_result_count)
368 {
369 int ok = 1;
370 size_t i, result_count = 0;
371 SSL_POLL_ITEM *item;
372 SSL *ssl;
373 #ifndef OPENSSL_NO_QUIC
374 uint64_t events;
375 #endif
376 uint64_t revents;
377
378 for (i = 0; i < num_items; ++i) {
379 item = &ITEM_N(items, stride, i);
380 #ifndef OPENSSL_NO_QUIC
381 events = item->events;
382 #endif
383 revents = 0;
384
385 switch (item->desc.type) {
386 case BIO_POLL_DESCRIPTOR_TYPE_SSL:
387 ssl = item->desc.value.ssl;
388 if (ssl == NULL)
389 /* NULL items are no-ops and have revents reported as 0 */
390 break;
391
392 switch (ssl->type) {
393 #ifndef OPENSSL_NO_QUIC
394 case SSL_TYPE_QUIC_LISTENER:
395 case SSL_TYPE_QUIC_CONNECTION:
396 case SSL_TYPE_QUIC_XSO:
397 if (!ossl_quic_conn_poll_events(ssl, events, do_tick, &revents))
398 /* above call raises ERR */
399 FAIL_ITEM(i);
400
401 if (revents != 0)
402 ++result_count;
403
404 break;
405 #endif
406
407 default:
408 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
409 "SSL_poll currently only supports QUIC SSL "
410 "objects");
411 FAIL_ITEM(i);
412 }
413 break;
414 case BIO_POLL_DESCRIPTOR_TYPE_SOCK_FD:
415 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
416 "SSL_poll currently does not support polling "
417 "sockets");
418 FAIL_ITEM(i);
419 default:
420 ERR_raise_data(ERR_LIB_SSL, SSL_R_POLL_REQUEST_NOT_SUPPORTED,
421 "SSL_poll does not support unknown poll descriptor "
422 "type %d",
423 item->desc.type);
424 FAIL_ITEM(i);
425 }
426
427 item->revents = revents;
428 }
429
430 out:
431 if (p_result_count != NULL)
432 *p_result_count = result_count;
433
434 return ok;
435 }
436
SSL_poll(SSL_POLL_ITEM * items,size_t num_items,size_t stride,const struct timeval * timeout,uint64_t flags,size_t * p_result_count)437 int SSL_poll(SSL_POLL_ITEM *items,
438 size_t num_items,
439 size_t stride,
440 const struct timeval *timeout,
441 uint64_t flags,
442 size_t *p_result_count)
443 {
444 int ok = 1;
445 size_t result_count = 0;
446 ossl_unused int do_tick = ((flags & SSL_POLL_FLAG_NO_HANDLE_EVENTS) == 0);
447 OSSL_TIME deadline;
448
449 /* Trivial case. */
450 if (num_items == 0) {
451 if (timeout == NULL)
452 goto out;
453 OSSL_sleep(ossl_time2ms(ossl_time_from_timeval(*timeout)));
454 goto out;
455 }
456
457 /* Convert timeout to deadline. */
458 if (timeout == NULL)
459 deadline = ossl_time_infinite();
460 else if (timeout->tv_sec == 0 && timeout->tv_usec == 0)
461 deadline = ossl_time_zero();
462 else
463 deadline = ossl_time_add(ossl_time_now(),
464 ossl_time_from_timeval(*timeout));
465
466 /* Loop until we have something to report. */
467 for (;;) {
468 /* Readout phase - poll current state of each item. */
469 if (!poll_readout(items, num_items, stride, do_tick, &result_count)) {
470 ok = 0;
471 goto out;
472 }
473
474 /*
475 * If we got anything, or we are in immediate mode (zero timeout), or
476 * the deadline has expired, we're done.
477 */
478 if (result_count > 0
479 || ossl_time_is_zero(deadline) /* (avoids now call) */
480 || ossl_time_compare(ossl_time_now(), deadline) >= 0)
481 goto out;
482
483 /*
484 * Block until something is ready. Ignore NO_HANDLE_EVENTS from this
485 * point onwards.
486 */
487 do_tick = 1;
488 #ifndef OPENSSL_NO_QUIC
489 if (!poll_block(items, num_items, stride, deadline, &result_count)) {
490 ok = 0;
491 goto out;
492 }
493 #endif
494 }
495
496 /* TODO(QUIC POLLING): Support for polling FDs */
497
498 out:
499 if (p_result_count != NULL)
500 *p_result_count = result_count;
501
502 return ok;
503 }
504