Path: blob/main/crypto/openssl/ssl/rio/poll_builder.c
48266 views
/*1* Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved.2*3* Licensed under the Apache License 2.0 (the "License"). You may not use4* this file except in compliance with the License. You can obtain a copy5* in the file LICENSE in the source distribution or at6* https://www.openssl.org/source/license.html7*/89#include <assert.h>10#include <errno.h>11#include "internal/safe_math.h"12#include "poll_builder.h"1314OSSL_SAFE_MATH_UNSIGNED(size_t, size_t)1516int ossl_rio_poll_builder_init(RIO_POLL_BUILDER *rpb)17{18#if RIO_POLL_METHOD == RIO_POLL_METHOD_NONE19return 0;20#elif RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT21FD_ZERO(&rpb->rfd);22FD_ZERO(&rpb->wfd);23FD_ZERO(&rpb->efd);24rpb->hwm_fd = -1;25#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL26rpb->pfd_heap = NULL;27rpb->pfd_num = 0;28rpb->pfd_alloc = OSSL_NELEM(rpb->pfds);29#endif30return 1;31}3233void ossl_rio_poll_builder_cleanup(RIO_POLL_BUILDER *rpb)34{35if (rpb == NULL)36return;3738#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL39OPENSSL_free(rpb->pfd_heap);40#endif41}4243#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL44static int rpb_ensure_alloc(RIO_POLL_BUILDER *rpb, size_t alloc)45{46struct pollfd *pfd_heap_new;47size_t total_size;48int error = 0;4950if (alloc <= rpb->pfd_alloc)51return 1;5253total_size = safe_mul_size_t(alloc, sizeof(struct pollfd), &error);54if (error)55return 0;5657pfd_heap_new = OPENSSL_realloc(rpb->pfd_heap, total_size);58if (pfd_heap_new == NULL)59return 0;6061if (rpb->pfd_heap == NULL) {62/* Copy the contents of the stacked array. */63memcpy(pfd_heap_new, rpb->pfds, sizeof(rpb->pfds));64}65rpb->pfd_heap = pfd_heap_new;66rpb->pfd_alloc = alloc;67return 1;68}69#endif7071int ossl_rio_poll_builder_add_fd(RIO_POLL_BUILDER *rpb, int fd,72int want_read, int want_write)73{74#if RIO_POLL_METHOD == RIO_POLL_METHOD_POLL75size_t i;76struct pollfd *pfds = (rpb->pfd_heap != NULL ? rpb->pfd_heap : rpb->pfds);77struct pollfd *pfd;78#endif7980if (fd < 0)81return 0;8283#if RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT8485# ifndef OPENSSL_SYS_WINDOWS86/*87* On Windows there is no relevant limit to the magnitude of a fd value (see88* above). On *NIX the fd_set uses a bitmap and we must check the limit.89*/90if (fd >= FD_SETSIZE)91return 0;92# endif9394if (want_read)95openssl_fdset(fd, &rpb->rfd);9697if (want_write)98openssl_fdset(fd, &rpb->wfd);99100openssl_fdset(fd, &rpb->efd);101if (fd > rpb->hwm_fd)102rpb->hwm_fd = fd;103104return 1;105106#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL107for (i = 0; i < rpb->pfd_num; ++i) {108pfd = &pfds[i];109110if (pfd->fd == -1 || pfd->fd == fd)111break;112}113114if (i >= rpb->pfd_alloc) {115if (!rpb_ensure_alloc(rpb, rpb->pfd_alloc * 2))116return 0;117pfds = rpb->pfd_heap;118}119120assert((rpb->pfd_heap != NULL && rpb->pfd_heap == pfds) ||121(rpb->pfd_heap == NULL && rpb->pfds == pfds));122assert(i <= rpb->pfd_num && rpb->pfd_num <= rpb->pfd_alloc);123pfds[i].fd = fd;124pfds[i].events = 0;125126if (want_read)127pfds[i].events |= POLLIN;128if (want_write)129pfds[i].events |= POLLOUT;130131if (i == rpb->pfd_num)132++rpb->pfd_num;133134return 1;135#endif136}137138int ossl_rio_poll_builder_poll(RIO_POLL_BUILDER *rpb, OSSL_TIME deadline)139{140int rc;141142#if RIO_POLL_METHOD == RIO_POLL_METHOD_SELECT143do {144struct timeval timeout, *p_timeout = &timeout;145146/*147* select expects a timeout, not a deadline, so do the conversion.148* Update for each call to ensure the correct value is used if we repeat149* due to EINTR.150*/151if (ossl_time_is_infinite(deadline))152p_timeout = NULL;153else154/*155* ossl_time_subtract saturates to zero so we don't need to check if156* now > deadline.157*/158timeout = ossl_time_to_timeval(ossl_time_subtract(deadline,159ossl_time_now()));160161rc = select(rpb->hwm_fd + 1, &rpb->rfd, &rpb->wfd, &rpb->efd, p_timeout);162} while (rc == -1 && get_last_socket_error_is_eintr());163#elif RIO_POLL_METHOD == RIO_POLL_METHOD_POLL164do {165int timeout_ms;166167if (ossl_time_is_infinite(deadline))168timeout_ms = -1;169else170timeout_ms = ossl_time2ms(ossl_time_subtract(deadline,171ossl_time_now()));172173rc = poll(rpb->pfd_heap != NULL ? rpb->pfd_heap : rpb->pfds,174rpb->pfd_num, timeout_ms);175} while (rc == -1 && get_last_socket_error_is_eintr());176#endif177178return rc < 0 ? 0 : 1;179}180181182