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