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