diff options
author | Toni Uhlig <matzeton@googlemail.com> | 2023-09-10 19:11:58 +0200 |
---|---|---|
committer | Toni Uhlig <matzeton@googlemail.com> | 2023-09-10 19:11:58 +0200 |
commit | 96b0a8a4749f56244b9d6841de3696ab7fe1fd0e (patch) | |
tree | 048ff902133f63e4a9addf24b85d43eb3c8f131c | |
parent | 091fd4d11654949e2d8e6c8f03cc9c675d472a91 (diff) |
Add event I/O abstraction.
* required to support non-Linux OS e.g. Mac OS X / BSD
* see Github issue #19
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
-rw-r--r-- | CMakeLists.txt | 17 | ||||
-rw-r--r-- | cmake/CheckEpoll.cmake | 28 | ||||
-rw-r--r-- | nDPId-test.c | 1 | ||||
-rw-r--r-- | nio.c | 330 | ||||
-rw-r--r-- | nio.h | 61 |
5 files changed, 432 insertions, 5 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index b328ed1ac..d7fb621be 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,13 @@ set(CPACK_PACKAGE_VERSION_PATCH 0) include(CPack) include(CheckFunctionExists) +include(CheckEpoll) + +check_epoll(HAS_EPOLL) +if(HAS_EPOLL) + set(EPOLL_DEFS "-DENABLE_EPOLL=1") + set(EPOLL_SRCS "nio.c") +endif() if(NOT MATH_FUNCTION_EXISTS AND NOT NEED_LINKING_AGAINST_LIBM) CHECK_FUNCTION_EXISTS(log2f MATH_FUNCTION_EXISTS) @@ -86,8 +93,8 @@ else() unset(NDPI_WITH_MAXMINDDB CACHE) endif() -add_executable(nDPId nDPId.c utils.c) -add_executable(nDPIsrvd nDPIsrvd.c utils.c) +add_executable(nDPId nDPId.c ${EPOLL_SRCS} utils.c) +add_executable(nDPIsrvd nDPIsrvd.c ${EPOLL_SRCS} utils.c) add_executable(nDPId-test nDPId-test.c) add_custom_target(dist) @@ -298,20 +305,20 @@ if(NOT pkgcfg_lib_PCAP_pcap) endif() target_compile_options(nDPId PRIVATE "-pthread") -target_compile_definitions(nDPId PRIVATE -D_GNU_SOURCE=1 -DGIT_VERSION=\"${GIT_VERSION}\" ${NDPID_DEFS} ${ZLIB_DEFS}) +target_compile_definitions(nDPId PRIVATE -D_GNU_SOURCE=1 -DGIT_VERSION=\"${GIT_VERSION}\" ${NDPID_DEFS} ${EPOLL_DEFS} ${ZLIB_DEFS}) target_include_directories(nDPId PRIVATE "${STATIC_LIBNDPI_INC}" "${DEFAULT_NDPI_INCLUDE}" ${NDPID_DEPS_INC}) target_link_libraries(nDPId "${STATIC_LIBNDPI_LIB}" "${pkgcfg_lib_PCAP_pcap}" "${pkgcfg_lib_NDPI_ndpi}" "${pkgcfg_lib_PCRE_pcre}" "${pkgcfg_lib_MAXMINDDB_maxminddb}" "${pkgcfg_lib_ZLIB_z}" "${GCRYPT_LIBRARY}" "${GCRYPT_ERROR_LIBRARY}" "${PCAP_LIBRARY}" "${LIBM_LIB}" "-pthread") -target_compile_definitions(nDPIsrvd PRIVATE -D_GNU_SOURCE=1 -DGIT_VERSION=\"${GIT_VERSION}\" ${NDPID_DEFS}) +target_compile_definitions(nDPIsrvd PRIVATE -D_GNU_SOURCE=1 -DGIT_VERSION=\"${GIT_VERSION}\" ${NDPID_DEFS} ${EPOLL_DEFS}) target_include_directories(nDPIsrvd PRIVATE ${NDPID_DEPS_INC}) target_include_directories(nDPId-test PRIVATE ${NDPID_DEPS_INC}) target_compile_options(nDPId-test PRIVATE "-Wno-unused-function" "-pthread") target_compile_definitions(nDPId-test PRIVATE -D_GNU_SOURCE=1 -DNO_MAIN=1 -DGIT_VERSION=\"${GIT_VERSION}\" - ${NDPID_DEFS} ${ZLIB_DEFS} ${NDPID_TEST_MPROF_DEFS}) + ${NDPID_DEFS} ${EPOLL_DEFS} ${ZLIB_DEFS} ${NDPID_TEST_MPROF_DEFS}) target_include_directories(nDPId-test PRIVATE "${STATIC_LIBNDPI_INC}" "${DEFAULT_NDPI_INCLUDE}" ${NDPID_DEPS_INC}) target_link_libraries(nDPId-test "${STATIC_LIBNDPI_LIB}" "${pkgcfg_lib_PCAP_pcap}" "${pkgcfg_lib_NDPI_ndpi}" diff --git a/cmake/CheckEpoll.cmake b/cmake/CheckEpoll.cmake new file mode 100644 index 000000000..766d7470f --- /dev/null +++ b/cmake/CheckEpoll.cmake @@ -0,0 +1,28 @@ +# - Check if the system supports epoll. +# CHECK_EPOLL(<var>) +# <var> - variable to store the result +# (1 for success, empty for failure) + +#============================================================================= +# This software is in the public domain, furnished "as is", without technical +# support, and with no warranty, express or implied, as to its usefulness for +# any purpose. +#============================================================================= + +macro(CHECK_EPOLL VARIABLE) + if(UNIX) + if("${VARIABLE}" MATCHES "^${VARIABLE}$") + message(STATUS "Check if the system supports epoll") + include(CheckSymbolExists) + check_symbol_exists(epoll_create "sys/epoll.h" EPOLL_PROTOTYPE_EXISTS) + + if(EPOLL_PROTOTYPE_EXISTS) + message(STATUS "Check if the system supports epoll - yes") + set(${VARIABLE} 1 CACHE INTERNAL "Result of CHECK_EPOLL" FORCE) + else(EPOLL_PROTOTYPE_EXISTS) + message(STATUS "Check if the system supports epoll - no") + set(${VARIABLE} "" CACHE INTERNAL "Result of CHECK_EPOLL" FORCE) + endif(EPOLL_PROTOTYPE_EXISTS) + endif("${VARIABLE}" MATCHES "^${VARIABLE}$") + endif(UNIX) +endmacro(CHECK_EPOLL) diff --git a/nDPId-test.c b/nDPId-test.c index 081662c78..8167a8ebe 100644 --- a/nDPId-test.c +++ b/nDPId-test.c @@ -10,6 +10,7 @@ static void nDPIsrvd_memprof_log_free(size_t free_size); //#define VERBOSE_MEMORY_PROFILING 1 #define NO_MAIN 1 #include "utils.c" +#include "nio.c" #include "nDPIsrvd.c" #include "nDPId.c" @@ -0,0 +1,330 @@ +#include "nio.h" + +#include <stdint.h> +#include <stdlib.h> +#ifdef ENABLE_EPOLL +#include <sys/epoll.h> +#endif + +void nio_init(struct nio * io) +{ + io->nready = -1; + io->poll_max_fds = -1; + io->poll_cur_fds = 0; + io->poll_fds = NULL; + io->poll_ptrs = NULL; + io->epoll_fd = -1; + io->max_events = 0; + io->events = NULL; +} + +int nio_use_poll(struct nio * io, nfds_t max_fds) +{ + if (io->epoll_fd != -1 || io->poll_max_fds != 0 || max_fds <= 0) + return NIO_ERROR_INTERNAL; + + io->poll_max_fds = max_fds; + io->poll_fds = (struct pollfd *)calloc(max_fds, sizeof(*io->poll_fds)); + io->poll_ptrs = calloc(max_fds, sizeof(*io->poll_ptrs)); + + return io->poll_fds == NULL || io->poll_ptrs == NULL; // return NIO_ERROR_INTERNAL on error +} + +int nio_use_epoll(struct nio * io, int max_events) +{ +#ifdef ENABLE_EPOLL + if (io->epoll_fd != -1 || io->poll_max_fds != 0 || max_events == 0) + return NIO_ERROR_INTERNAL; + + io->epoll_fd = epoll_create1(EPOLL_CLOEXEC); + io->max_events = max_events; + io->events = calloc(max_events, sizeof(struct epoll_event)); + + return io->epoll_fd; +#else + (void)io; + (void)max_events; + + return NIO_ERROR_INTERNAL; +#endif +} + +int nio_add_fd(struct nio * io, int fd, int event_flags, void * ptr) +{ +#ifdef ENABLE_EPOLL + if (io->epoll_fd >= 0) + { + struct epoll_event event = {}; + + if (ptr == NULL) + { + event.data.fd = fd; + } + else + { + event.data.ptr = ptr; + } + + if ((event_flags & NIO_EVENT_INPUT) != 0) + event.events |= EPOLLIN; + if ((event_flags & NIO_EVENT_OUTPUT) != 0) + event.events |= EPOLLOUT; + if (event.events == 0) + return NIO_ERROR_INTERNAL; + + return epoll_ctl(io->epoll_fd, EPOLL_CTL_ADD, fd, &event); + } + else +#endif + if (io->poll_max_fds > 0) + { + struct pollfd * unused_pollfd = NULL; + void ** unused_ptr = NULL; + + if (io->poll_cur_fds == io->poll_max_fds || fd < 0) + return NIO_ERROR_INTERNAL; + + for (size_t i = 0; i < io->poll_max_fds; ++i) + { + if (io->poll_fds[i].fd < 0) + { + unused_pollfd = &io->poll_fds[i]; + unused_ptr = &io->poll_ptrs[i]; + break; + } + } + if (unused_pollfd == NULL) + return NIO_ERROR_INTERNAL; + + unused_pollfd->events = 0; + if ((event_flags & NIO_EVENT_INPUT) != 0) + unused_pollfd->events |= POLLIN; + if ((event_flags & NIO_EVENT_OUTPUT) != 0) + unused_pollfd->events |= POLLOUT; + if (unused_pollfd->events == 0) + return NIO_ERROR_INTERNAL; + + unused_pollfd->fd = fd; + *unused_ptr = ptr; + io->poll_cur_fds++; + + return NIO_ERROR_SUCCESS; + } + + return NIO_ERROR_INTERNAL; +} + +int nio_mod_fd(struct nio * io, int fd, int event_flags, void * ptr) +{ +#ifdef ENABLE_EPOLL + if (io->epoll_fd >= 0) + { + struct epoll_event event = {}; + + if (ptr == NULL) + { + event.data.fd = fd; + } + else + { + event.data.ptr = ptr; + } + + if ((event_flags & NIO_EVENT_INPUT) != 0) + event.events |= EPOLLIN; + if ((event_flags & NIO_EVENT_OUTPUT) != 0) + event.events |= EPOLLOUT; + if (event.events == 0) + return NIO_ERROR_INTERNAL; + + return epoll_ctl(io->epoll_fd, EPOLL_CTL_MOD, fd, &event); + } + else +#endif + if (io->poll_max_fds > 0) + { + struct pollfd * unused_pollfd = NULL; + void ** unused_ptr = NULL; + + if (io->poll_cur_fds == io->poll_max_fds || fd < 0) + return NIO_ERROR_INTERNAL; + + for (size_t i = 0; i < io->poll_max_fds; ++i) + { + if (io->poll_fds[i].fd < 0) + { + unused_pollfd = &io->poll_fds[i]; + unused_ptr = &io->poll_ptrs[i]; + break; + } + } + if (unused_pollfd == NULL) + return NIO_ERROR_INTERNAL; + + unused_pollfd->events = 0; + if ((event_flags & NIO_EVENT_INPUT) != 0) + unused_pollfd->events |= POLLIN; + if ((event_flags & NIO_EVENT_OUTPUT) != 0) + unused_pollfd->events |= POLLOUT; + if (unused_pollfd->events == 0) + return NIO_ERROR_INTERNAL; + + unused_pollfd->fd = fd; + *unused_ptr = ptr; + io->poll_cur_fds++; + + return NIO_ERROR_SUCCESS; + } + + return NIO_ERROR_INTERNAL; +} + +int nio_del_fd(struct nio * io, int fd) +{ +#ifdef ENABLE_EPOLL + if (io->epoll_fd >= 0) + { + return epoll_ctl(io->epoll_fd, EPOLL_CTL_DEL, fd, NULL); + } + else +#endif + if (io->poll_max_fds > 0) + { + struct pollfd * unused_pollfd = NULL; + void ** unused_ptr = NULL; + + if (io->poll_cur_fds == io->poll_max_fds || fd < 0) + return NIO_ERROR_INTERNAL; + + for (size_t i = 0; i < io->poll_max_fds; ++i) + { + if (io->poll_fds[i].fd < 0) + { + unused_pollfd = &io->poll_fds[i]; + unused_ptr = &io->poll_ptrs[i]; + break; + } + } + if (unused_pollfd == NULL) + return NIO_ERROR_INTERNAL; + + unused_pollfd->fd = -1; + *unused_ptr = NULL; + io->poll_cur_fds--; + + return NIO_ERROR_SUCCESS; + } + + return NIO_ERROR_INTERNAL; +} + +int nio_run(struct nio * io, int timeout) +{ +#ifdef ENABLE_EPOLL + if (io->epoll_fd >= 0) + { + io->nready = epoll_wait(io->epoll_fd, io->events, io->max_events, timeout); + if (io->nready < 0) + return NIO_ERROR_SYSTEM; + } + else +#endif + if (io->poll_max_fds > 0) + { + io->nready = poll(io->poll_fds, io->poll_max_fds, timeout); + if (io->nready < 0) + return NIO_ERROR_SYSTEM; + else + io->nready = io->poll_max_fds; + } + + return NIO_ERROR_SUCCESS; +} + +int nio_check(struct nio * io, int index, int events) +{ + if (index < 0 || index >= io->nready) + return NIO_ERROR_INTERNAL; + +#ifdef ENABLE_EPOLL + if (io->epoll_fd >= 0 && index >= 0 && index < io->max_events) + { + uint32_t epoll_events = 0; + + if ((events & NIO_EVENT_INPUT) != 0) + epoll_events |= EPOLLIN; + if ((events & NIO_EVENT_OUTPUT) != 0) + epoll_events |= EPOLLOUT; + if (epoll_events == 0) + return NIO_ERROR_INTERNAL; + + struct epoll_event * ee = (struct epoll_event *)io->events; + if ((ee[index].events & epoll_events) != epoll_events) + return NIO_ERROR_INTERNAL; + + return NIO_ERROR_SUCCESS; + } + else +#endif + if (io->poll_max_fds > 0 && index >= 0 && index < (int)io->poll_max_fds) + { + short int poll_events = 0; + + if ((events & NIO_EVENT_INPUT) != 0) + poll_events |= POLLIN; + if ((events & NIO_EVENT_OUTPUT) != 0) + poll_events |= POLLOUT; + if (poll_events == 0) + return NIO_ERROR_INTERNAL; + + if (io->poll_fds[index].revents != poll_events) + return NIO_ERROR_INTERNAL; + + return NIO_ERROR_SUCCESS; + } + + return NIO_ERROR_INTERNAL; +} + +int nio_is_valid(struct nio * io, int index) +{ + if (index < 0 || index >= io->nready) + return NIO_ERROR_INTERNAL; + +#ifdef ENABLE_EPOLL + if (io->epoll_fd >= 0 && index >= 0 && index <= io->max_events) + { + return NIO_ERROR_SUCCESS; + } + else +#endif + if (io->poll_max_fds > 0 && index >= 0 && index < (int)io->poll_max_fds) + { + if (io->poll_fds[index].revents != 0) + return NIO_ERROR_SUCCESS; + } + + return NIO_ERROR_INTERNAL; +} + +int nio_has_input(struct nio * io, int index) +{ + return nio_check(io, index, NIO_EVENT_INPUT); +} + +int nio_can_output(struct nio * io, int index) +{ + return nio_check(io, index, NIO_EVENT_OUTPUT); +} + +int nio_has_error(struct nio * io, int index) +{ + return nio_check(io, index, NIO_EVENT_ERROR); +} + +void nio_free(struct nio * io) +{ + free(io->poll_fds); + free(io->poll_ptrs); + free(io->events); +} @@ -0,0 +1,61 @@ +#ifndef NIO_H +#define NIO_H 1 + +#include <poll.h> + +enum +{ + NIO_ERROR_SUCCESS = 0, + NIO_ERROR_INTERNAL = 1, + NIO_ERROR_SYSTEM = -1 +}; + +enum +{ + NIO_EVENT_INVALID = 0, + NIO_EVENT_INPUT = 1, + NIO_EVENT_OUTPUT = 2, + NIO_EVENT_ERROR = 3, +}; + +struct nio +{ + int nready; + + nfds_t poll_max_fds; + nfds_t poll_cur_fds; + struct pollfd * poll_fds; + void ** poll_ptrs; + + int epoll_fd; + int max_events; + void * events; +}; + +void nio_init(struct nio * io); + +int nio_use_poll(struct nio * io, nfds_t max_fds); + +int nio_use_epoll(struct nio * io, int max_events); + +int nio_add_fd(struct nio * io, int fd, int event_flags, void * ptr); + +int nio_mod_fd(struct nio * io, int fd, int event_flags, void * ptr); + +int nio_del_fd(struct nio * io, int fd); + +int nio_run(struct nio * io, int timeout); + +int nio_check(struct nio * io, int index, int events); + +int nio_is_valid(struct nio * io, int index); + +int nio_has_input(struct nio * io, int index); + +int nio_can_output(struct nio * io, int index); + +int nio_has_error(struct nio * io, int index); + +void nio_free(struct nio * io); + +#endif |