aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorToni Uhlig <matzeton@googlemail.com>2023-09-10 19:11:58 +0200
committerToni Uhlig <matzeton@googlemail.com>2023-09-10 19:11:58 +0200
commit96b0a8a4749f56244b9d6841de3696ab7fe1fd0e (patch)
tree048ff902133f63e4a9addf24b85d43eb3c8f131c
parent091fd4d11654949e2d8e6c8f03cc9c675d472a91 (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.txt17
-rw-r--r--cmake/CheckEpoll.cmake28
-rw-r--r--nDPId-test.c1
-rw-r--r--nio.c330
-rw-r--r--nio.h61
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"
diff --git a/nio.c b/nio.c
new file mode 100644
index 000000000..92e657d47
--- /dev/null
+++ b/nio.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);
+}
diff --git a/nio.h b/nio.h
new file mode 100644
index 000000000..5ee67d883
--- /dev/null
+++ b/nio.h
@@ -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