Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/ssl/rio/poll_immediate.c
48261 views
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
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
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
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
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
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
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
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
480