Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/openssl/ssl/rio/poll_builder.c
48266 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 <assert.h>
11
#include <errno.h>
12
#include "internal/safe_math.h"
13
#include "poll_builder.h"
14
15
OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)
16
17
int ossl_rio_poll_builder_init(RIO_POLL_BUILDER *rpb)
18
{
19
#if RIO_POLL_METHOD == RIO_POLL_METHOD_NONE
20
return 0;
21
#elif RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT
22
FD_ZERO(&rpb->rfd);
23
FD_ZERO(&rpb->wfd);
24
FD_ZERO(&rpb->efd);
25
rpb->hwm_fd = -1;
26
#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
27
rpb->pfd_heap = NULL;
28
rpb->pfd_num = 0;
29
rpb->pfd_alloc = OSSL_NELEM(rpb->pfds);
30
#endif
31
return 1;
32
}
33
34
void ossl_rio_poll_builder_cleanup(RIO_POLL_BUILDER *rpb)
35
{
36
if (rpb == NULL)
37
return;
38
39
#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
40
OPENSSL_free(rpb->pfd_heap);
41
#endif
42
}
43
44
#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
45
static int rpb_ensure_alloc(RIO_POLL_BUILDER *rpb, size_t alloc)
46
{
47
struct pollfd *pfd_heap_new;
48
size_t total_size;
49
int error = 0;
50
51
if (alloc <= rpb->pfd_alloc)
52
return 1;
53
54
total_size = safe_mul_size_t(alloc, sizeof(struct pollfd), &error);
55
if (error)
56
return 0;
57
58
pfd_heap_new = OPENSSL_realloc(rpb->pfd_heap, total_size);
59
if (pfd_heap_new == NULL)
60
return 0;
61
62
if (rpb->pfd_heap == NULL) {
63
/* Copy the contents of the stacked array. */
64
memcpy(pfd_heap_new, rpb->pfds, sizeof(rpb->pfds));
65
}
66
rpb->pfd_heap = pfd_heap_new;
67
rpb->pfd_alloc = alloc;
68
return 1;
69
}
70
#endif
71
72
int ossl_rio_poll_builder_add_fd(RIO_POLL_BUILDER *rpb, int fd,
73
int want_read, int want_write)
74
{
75
#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
76
size_t i;
77
struct pollfd *pfds = (rpb->pfd_heap != NULL ? rpb->pfd_heap : rpb->pfds);
78
struct pollfd *pfd;
79
#endif
80
81
if (fd < 0)
82
return 0;
83
84
#if RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT
85
86
# ifndef OPENSSL_SYS_WINDOWS
87
/*
88
* On Windows there is no relevant limit to the magnitude of a fd value (see
89
* above). On *NIX the fd_set uses a bitmap and we must check the limit.
90
*/
91
if (fd >= FD_SETSIZE)
92
return 0;
93
# endif
94
95
if (want_read)
96
openssl_fdset(fd, &rpb->rfd);
97
98
if (want_write)
99
openssl_fdset(fd, &rpb->wfd);
100
101
openssl_fdset(fd, &rpb->efd);
102
if (fd > rpb->hwm_fd)
103
rpb->hwm_fd = fd;
104
105
return 1;
106
107
#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
108
for (i = 0; i < rpb->pfd_num; ++i) {
109
pfd = &pfds[i];
110
111
if (pfd->fd == -1 || pfd->fd == fd)
112
break;
113
}
114
115
if (i >= rpb->pfd_alloc) {
116
if (!rpb_ensure_alloc(rpb, rpb->pfd_alloc * 2))
117
return 0;
118
pfds = rpb->pfd_heap;
119
}
120
121
assert((rpb->pfd_heap != NULL && rpb->pfd_heap == pfds) ||
122
(rpb->pfd_heap == NULL && rpb->pfds == pfds));
123
assert(i <= rpb->pfd_num && rpb->pfd_num <= rpb->pfd_alloc);
124
pfds[i].fd = fd;
125
pfds[i].events = 0;
126
127
if (want_read)
128
pfds[i].events |= POLLIN;
129
if (want_write)
130
pfds[i].events |= POLLOUT;
131
132
if (i == rpb->pfd_num)
133
++rpb->pfd_num;
134
135
return 1;
136
#endif
137
}
138
139
int ossl_rio_poll_builder_poll(RIO_POLL_BUILDER *rpb, OSSL_TIME deadline)
140
{
141
int rc;
142
143
#if RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT
144
do {
145
struct timeval timeout, *p_timeout = &timeout;
146
147
/*
148
* select expects a timeout, not a deadline, so do the conversion.
149
* Update for each call to ensure the correct value is used if we repeat
150
* due to EINTR.
151
*/
152
if (ossl_time_is_infinite(deadline))
153
p_timeout = NULL;
154
else
155
/*
156
* ossl_time_subtract saturates to zero so we don't need to check if
157
* now > deadline.
158
*/
159
timeout = ossl_time_to_timeval(ossl_time_subtract(deadline,
160
ossl_time_now()));
161
162
rc = select(rpb->hwm_fd + 1, &rpb->rfd, &rpb->wfd, &rpb->efd, p_timeout);
163
} while (rc == -1 && get_last_socket_error_is_eintr());
164
#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL
165
do {
166
int timeout_ms;
167
168
if (ossl_time_is_infinite(deadline))
169
timeout_ms = -1;
170
else
171
timeout_ms = ossl_time2ms(ossl_time_subtract(deadline,
172
ossl_time_now()));
173
174
rc = poll(rpb->pfd_heap != NULL ? rpb->pfd_heap : rpb->pfds,
175
rpb->pfd_num, timeout_ms);
176
} while (rc == -1 && get_last_socket_error_is_eintr());
177
#endif
178
179
return rc < 0 ? 0 : 1;
180
}
181
182