xref: /freebsd/crypto/openssl/ssl/rio/poll_immediate.c (revision 78e936b2d0b5e6554425009199be31e76bc67c10)
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