From: Razvan Becheriu Date: Wed, 29 Oct 2025 12:43:30 +0000 (+0200) Subject: [#4141] implemented select event handler X-Git-Tag: Kea-3.1.4~104 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e952b83edb3c6c1f48e97fd67224d95d9ecebbb4;p=thirdparty%2Fkea.git [#4141] implemented select event handler --- diff --git a/src/lib/dhcp/fd_event_handler.cc b/src/lib/dhcp/fd_event_handler.cc new file mode 100644 index 0000000000..11ad33588d --- /dev/null +++ b/src/lib/dhcp/fd_event_handler.cc @@ -0,0 +1,22 @@ +// Copyright (C) 2011-2025 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include + +namespace isc { +namespace dhcp { + +FDEventHandler::FDEventHandler(HandlerType type) : type_(type) { +} + +FDEventHandler::HandlerType FDEventHandler::type() { + return (type_); +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/lib/dhcp/fd_event_handler.h b/src/lib/dhcp/fd_event_handler.h new file mode 100644 index 0000000000..dd54240cc2 --- /dev/null +++ b/src/lib/dhcp/fd_event_handler.h @@ -0,0 +1,83 @@ +// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef FD_EVENT_HANDLER_H +#define FD_EVENT_HANDLER_H + +#include +#include + +namespace isc { +namespace dhcp { + +/// @brief File descriptor event handler class handles events for registered +/// file descriptors. +class FDEventHandler { +public: + enum HandlerType : uint16_t { + TYPE_UNKNOWN = 0, + TYPE_SELECT = 1, + TYPE_EPOLL = 2, // Linux OS (Linux like OS) only + TYPE_KQUEUE = 3, // BSD (BSD like OS) only + }; + + // @brief Constructor. + // + // @param type The file descriptor event handler type. + FDEventHandler(HandlerType type = TYPE_UNKNOWN); + + // @brief Destructor. + virtual ~FDEventHandler() = default; + + // @brief Add file descriptor to watch for events. + // + // @param fd The file descriptor. + // @param read The flag indicating if the file descriptor should be + // registered for read ready events. + // @param write The flag indicating if the file descriptor should be + // registered for write ready events. + virtual void addFD(int fd, bool read = true, bool write = false) = 0; + + // @brief Wait for events on registered file descriptors. + // + // @param timeout_sec The wait timeout in seconds. + // @param timeout_usec The wait timeout in micro seconds + // @return -1 on error, 0 if no data is available (timeout expired), + // 1 if data is ready. + virtual int waitEvent(uint32_t timeout_sec, uint32_t timeout_usec = 0) = 0; + + // @brief Check if file descriptor is ready for read operation. + // + // @param fd The file descriptor. + // + // @return True if file descriptor is ready for reading. + virtual bool readReadyFD(int fd) = 0; + + // @brief Check if file descriptor is ready for write operation. + // + // @param fd The file descriptor. + // + // @return True if file descriptor is ready for writing. + virtual bool writeReady(int fd) = 0; + + // @brief Clear registered file descriptors. + virtual void clear() = 0; + + // @brief Return the event handler type. + HandlerType type(); + +private: + // @brief The event handler type. + HandlerType type_; +}; + +/// @brief Shared pointer to an FD event handler. +typedef boost::shared_ptr FDEventHandlerPtr; + +} // namespace isc::dhcp +} // namespace isc + +#endif // FD_EVENT_HANDLER_H diff --git a/src/lib/dhcp/meson.build b/src/lib/dhcp/meson.build index 6d2c0ab733..7133b3f6e3 100644 --- a/src/lib/dhcp/meson.build +++ b/src/lib/dhcp/meson.build @@ -15,6 +15,7 @@ kea_dhcp_lib = shared_library( 'classify.cc', 'duid.cc', 'duid_factory.cc', + 'fd_event_handler.cc', 'hwaddr.cc', 'iface_mgr.cc', iface_mgr, @@ -54,6 +55,7 @@ kea_dhcp_lib = shared_library( 'pkt_filter_inet6.cc', pkt_filter_cc, 'protocol_util.cc', + 'select_event_handler.cc', include_directories: [include_directories('.')] + INCLUDES, install: true, install_dir: LIBDIR, @@ -72,6 +74,7 @@ kea_dhcp_headers = [ 'docsis3_option_defs.h', 'duid.h', 'duid_factory.h', + 'fd_event_handler.h', 'hwaddr.h', 'iface_mgr.h', 'iface_mgr_error_handler.h', @@ -119,6 +122,7 @@ kea_dhcp_headers = [ 'pkt_filter_lpf.h', 'pkt_template.h', 'protocol_util.h', + 'select_event_handler.h', 'socket_info.h', 'std_option_defs.h', ] diff --git a/src/lib/dhcp/select_event_handler.cc b/src/lib/dhcp/select_event_handler.cc new file mode 100644 index 0000000000..41b8234c76 --- /dev/null +++ b/src/lib/dhcp/select_event_handler.cc @@ -0,0 +1,75 @@ +// Copyright (C) 2011-2025 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include + +#include +#include + +namespace isc { +namespace dhcp { + +SelectEventHandler::SelectEventHandler() : FDEventHandler(TYPE_SELECT), max_fd_(0) { + clear(); +} + +void SelectEventHandler::add(int fd, bool read /* = true */, bool write /* = false */) { + if (fd < 0) { + isc_throw(BadValue, "invalid negative value for fd"); + } + if (fd >= FD_SETSIZE) { + isc_throw(BadValue, "invalid value for fd exceeds maximum allowed " << FD_SETSIZE); + } + if (read) { + // Add this socket to read set + FD_SET(fd, &read_fd_set_); + } + if (write) { + // Add this socket to write set + FD_SET(fd, &write_fd_set_); + } +} + +// @brief Wait for events on registered file descriptors. +int SelectEventHandler::waitEvent(uint32_t timeout_sec, uint32_t timeout_usec /* = 0 */) { + // Sanity check for microsecond timeout. + if (timeout_usec >= 1000000) { + isc_throw(BadValue, "fractional timeout must be shorter than" + " one million microseconds"); + } + struct timeval select_timeout; + select_timeout.tv_sec = timeout_sec; + select_timeout.tv_usec = timeout_usec; + + return (select(max_fd_ + 1, &read_fd_set_, &write_fd_set_, 0, &select_timeout)); +} + +// @brief Check if file descriptor is ready for read operation. +// +// @param fd The file descriptor. +// +// @return True if file descriptor is ready for reading. +bool SelectEventHandler::readReady(int fd) { + return (FD_ISSET(fd, &read_fd_set_)); +} + +// @brief Check if file descriptor is ready for write operation. +// +// @param fd The file descriptor. +// +// @return True if file descriptor is ready for writing. +bool SelectEventHandler::writeReady(int fd) { + return (FD_ISSET(fd, &write_fd_set_)); +} + +void SelectEventHandler::clear() { + FD_ZERO(&read_fd_set_); + FD_ZERO(&write_fd_set_); + max_fd_ = 0; +} + +} // end of namespace isc::dhcp +} // end of namespace isc diff --git a/src/lib/dhcp/select_event_handler.h b/src/lib/dhcp/select_event_handler.h new file mode 100644 index 0000000000..2a5cd064df --- /dev/null +++ b/src/lib/dhcp/select_event_handler.h @@ -0,0 +1,75 @@ +// Copyright (C) 2010-2024 Internet Systems Consortium, Inc. ("ISC") +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#ifndef SELECT_EVENT_HANDLER_H +#define SELECT_EVENT_HANDLER_H + +#include + +#include + +namespace isc { +namespace dhcp { + +/// @brief File descriptor event handler class handles events for registered +/// file descriptors. This class uses the OS select syscall for event handling. +class SelectEventHandler : public FDEventHandler { +public: + // @brief Constructor. + SelectEventHandler(); + + // @brief Destructor. + virtual ~SelectEventHandler() = default; + + // @brief Add file descriptor to watch for events. + // + // @param fd The file descriptor. + // @param read The flag indicating if the file descriptor should be + // registered for read ready events. + // @param write The flag indicating if the file descriptor should be + // registered for write ready events. + void add(int fd, bool read = true, bool write = false); + + // @brief Wait for events on registered file descriptors. + // + // @param timeout_sec The wait timeout in seconds. + // @param timeout_usec The wait timeout in micro seconds + // @return -1 on error, 0 if no data is available (timeout expired), + // 1 if data is ready. + int waitEvent(uint32_t timeout_sec, uint32_t timeout_usec = 0); + + // @brief Check if file descriptor is ready for read operation. + // + // @param fd The file descriptor. + // + // @return True if file descriptor is ready for reading. + bool readReady(int fd); + + // @brief Check if file descriptor is ready for write operation. + // + // @param fd The file descriptor. + // + // @return True if file descriptor is ready for writing. + bool writeReady(int fd); + + // @brief Clear registered file descriptors. + void clear(); + +private: + // @brief The maximum value of registered file descriptors. + int max_fd_; + + // @brief The read event FD set. + fd_set read_fd_set_; + + // @brief The write event FD set. + fd_set write_fd_set_; +}; + +} // namespace isc::dhcp +} // namespace isc + +#endif // SELECT_EVENT_HANDLER_H