mirror of
https://github.com/utoni/nDPId.git
synced 2026-10-19 07:43:37 +00:00
Some checks failed
ArchLinux PKGBUILD / build (push) Has been cancelled
CentOs / centos8 (push) Has been cancelled
Docker Build / docker (push) Has been cancelled
FreeBSD Build / Build and Test (push) Has been cancelled
Build OpenWrt Packages / build (armsr-armv8) (push) Has been cancelled
Build OpenWrt Packages / build (malta-be) (push) Has been cancelled
Build OpenWrt Packages / build (ramips-mt7621) (push) Has been cancelled
Build OpenWrt Packages / build (x86-64) (push) Has been cancelled
RPM Build / build (push) Has been cancelled
Build / macOS-14 cc (push) Has been cancelled
Build / ubuntu-latest clang (push) Has been cancelled
Build / ubuntu-latest clang-1 (push) Has been cancelled
Build / ubuntu-22.04 clang-12 (push) Has been cancelled
Build / ubuntu-latest gcc (push) Has been cancelled
Build / ubuntu-latest gcc-1 (push) Has been cancelled
Build / ubuntu-latest gcc-2 (push) Has been cancelled
Build / ubuntu-22.04 gcc-10 (push) Has been cancelled
Build / ubuntu-22.04 gcc-9 (push) Has been cancelled
SonarQube Scan / Build and analyze (push) Has been cancelled
Add support for nDPIsrvd TCP/TLS collectors. * Removed fallback-to-blocking nonsense; a single-threaded event-io forwarding application is useless with such an option * Fix missing poll-in / poll-out handling for TLS / OpenSSL * Fix I/O (out)event handling * Fix error for select in NIO and fixed event mod ops in nDPIsrvd Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
433 lines
10 KiB
C
433 lines
10 KiB
C
#include "nio.h"
|
|
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#ifdef ENABLE_EPOLL
|
|
#include <sys/epoll.h>
|
|
#endif
|
|
#include <unistd.h>
|
|
|
|
void nio_init(struct nio * io)
|
|
{
|
|
io->nready = -1;
|
|
io->poll_max_fds = 0;
|
|
io->poll_fds = NULL;
|
|
io->poll_ptrs = NULL;
|
|
io->poll_fds_set = 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));
|
|
io->poll_fds_set = calloc(max_fds, sizeof(*io->poll_fds_set));
|
|
|
|
if (io->poll_fds == NULL)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
for (size_t i = 0; i < max_fds; ++i)
|
|
{
|
|
io->poll_fds[i].fd = -1;
|
|
}
|
|
|
|
return io->poll_ptrs == NULL || io->poll_fds_set == NULL ? NIO_ERROR_INTERNAL : NIO_SUCCESS;
|
|
}
|
|
|
|
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->events == NULL || io->epoll_fd < 0; // return NIO_ERROR_INTERNAL on error
|
|
#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)
|
|
{
|
|
if (fd < 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
int rv;
|
|
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;
|
|
|
|
while ((rv = epoll_ctl(io->epoll_fd, EPOLL_CTL_ADD, fd, &event)) != 0 && errno == EINTR)
|
|
{
|
|
/* If epoll_ctl() was interrupted by the system, repeat. */
|
|
}
|
|
return rv;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
struct pollfd * unused_pollfd = NULL;
|
|
void ** unused_ptr = NULL;
|
|
|
|
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;
|
|
|
|
return NIO_SUCCESS;
|
|
}
|
|
|
|
return NIO_ERROR_INTERNAL;
|
|
}
|
|
|
|
int nio_mod_fd(struct nio * io, int fd, int event_flags, void * ptr)
|
|
{
|
|
if (fd < 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
int rv;
|
|
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;
|
|
else
|
|
event.events &= ~EPOLLIN;
|
|
if ((event_flags & NIO_EVENT_OUTPUT) != 0)
|
|
event.events |= EPOLLOUT;
|
|
else
|
|
event.events &= ~EPOLLOUT;
|
|
if (event.events == 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
while ((rv = epoll_ctl(io->epoll_fd, EPOLL_CTL_MOD, fd, &event)) != 0 && errno == EINTR)
|
|
{
|
|
/* If epoll_ctl() was interrupted by the system, repeat. */
|
|
}
|
|
return rv;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
struct pollfd * used_pollfd = NULL;
|
|
void ** used_ptr = NULL;
|
|
|
|
for (size_t i = 0; i < io->poll_max_fds; ++i)
|
|
{
|
|
if (io->poll_fds[i].fd == fd)
|
|
{
|
|
used_pollfd = &io->poll_fds[i];
|
|
used_ptr = &io->poll_ptrs[i];
|
|
break;
|
|
}
|
|
}
|
|
if (used_pollfd == NULL)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
used_pollfd->events = 0;
|
|
if ((event_flags & NIO_EVENT_INPUT) != 0)
|
|
used_pollfd->events |= POLLIN;
|
|
else
|
|
used_pollfd->events &= ~POLLIN;
|
|
if ((event_flags & NIO_EVENT_OUTPUT) != 0)
|
|
used_pollfd->events |= POLLOUT;
|
|
else
|
|
used_pollfd->events &= ~POLLOUT;
|
|
if (used_pollfd->events == 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
used_pollfd->fd = fd;
|
|
*used_ptr = ptr;
|
|
|
|
return NIO_SUCCESS;
|
|
}
|
|
|
|
return NIO_ERROR_INTERNAL;
|
|
}
|
|
|
|
int nio_del_fd(struct nio * io, int fd)
|
|
{
|
|
if (fd < 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
int rv;
|
|
|
|
while ((rv = epoll_ctl(io->epoll_fd, EPOLL_CTL_DEL, fd, NULL)) != 0 && errno == EINTR)
|
|
{
|
|
/* If epoll_ctl() was interrupted by the system, repeat. */
|
|
}
|
|
return rv;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
struct pollfd * used_pollfd = NULL;
|
|
void ** used_ptr = NULL;
|
|
|
|
for (size_t i = 0; i < io->poll_max_fds; ++i)
|
|
{
|
|
if (io->poll_fds[i].fd == fd)
|
|
{
|
|
used_pollfd = &io->poll_fds[i];
|
|
used_ptr = &io->poll_ptrs[i];
|
|
break;
|
|
}
|
|
}
|
|
if (used_pollfd == NULL)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
used_pollfd->fd = -1;
|
|
used_pollfd->events = 0;
|
|
used_pollfd->revents = 0;
|
|
*used_ptr = NULL;
|
|
|
|
return NIO_SUCCESS;
|
|
}
|
|
|
|
return NIO_ERROR_INTERNAL;
|
|
}
|
|
|
|
int nio_run(struct nio * io, int timeout)
|
|
{
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
do
|
|
{
|
|
io->nready = epoll_wait(io->epoll_fd, io->events, io->max_events, timeout);
|
|
} while (io->nready < 0 && errno == EINTR);
|
|
|
|
if (io->nready < 0)
|
|
return NIO_ERROR_SYSTEM;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
do
|
|
{
|
|
io->nready = poll(io->poll_fds, io->poll_max_fds, timeout);
|
|
} while (io->nready < 0 && errno == EINTR);
|
|
|
|
if (io->nready < 0)
|
|
return NIO_ERROR_SYSTEM;
|
|
|
|
if (io->nready > 0)
|
|
{
|
|
nfds_t ready = 0;
|
|
|
|
for (nfds_t i = 0; i < io->poll_max_fds; ++i)
|
|
{
|
|
if (io->poll_fds[i].fd >= 0 && io->poll_fds[i].revents != 0)
|
|
{
|
|
io->poll_fds_set[ready++] = i;
|
|
}
|
|
}
|
|
|
|
io->nready = (int)ready;
|
|
}
|
|
}
|
|
|
|
return NIO_SUCCESS;
|
|
}
|
|
|
|
int nio_check(struct nio * io, int index, int event_flags)
|
|
{
|
|
if (nio_is_valid(io, index) != NIO_SUCCESS)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
uint32_t epoll_events = 0;
|
|
|
|
if ((event_flags & NIO_EVENT_INPUT) != 0)
|
|
epoll_events |= EPOLLIN;
|
|
if ((event_flags & NIO_EVENT_OUTPUT) != 0)
|
|
epoll_events |= EPOLLOUT;
|
|
if ((event_flags & NIO_EVENT_ERROR) != 0)
|
|
epoll_events |= EPOLLERR | EPOLLHUP;
|
|
if (epoll_events == 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
struct epoll_event const * const events = (struct epoll_event *)io->events;
|
|
if ((events[index].events & epoll_events) == 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
return NIO_SUCCESS;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
short int poll_events = 0;
|
|
|
|
if ((event_flags & NIO_EVENT_INPUT) != 0)
|
|
poll_events |= POLLIN;
|
|
if ((event_flags & NIO_EVENT_OUTPUT) != 0)
|
|
poll_events |= POLLOUT;
|
|
if ((event_flags & NIO_EVENT_ERROR) != 0)
|
|
poll_events |= POLLERR | POLLHUP;
|
|
if (poll_events == 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
if ((io->poll_fds[io->poll_fds_set[index]].revents & poll_events) == 0)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
return NIO_SUCCESS;
|
|
}
|
|
|
|
return NIO_ERROR_INTERNAL;
|
|
}
|
|
|
|
int nio_is_valid(struct nio const * const io, int index)
|
|
{
|
|
if (index < 0 || index >= io->nready)
|
|
return NIO_ERROR_INTERNAL;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
return NIO_SUCCESS;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0 && io->poll_fds[io->poll_fds_set[index]].fd >= 0)
|
|
{
|
|
return NIO_SUCCESS;
|
|
}
|
|
|
|
return NIO_ERROR_INTERNAL;
|
|
}
|
|
|
|
int nio_get_fd(struct nio * io, int index)
|
|
{
|
|
if (nio_is_valid(io, index) != NIO_SUCCESS)
|
|
return -1;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
struct epoll_event const * const events = (struct epoll_event *)io->events;
|
|
|
|
return events[index].data.fd;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
return io->poll_fds[io->poll_fds_set[index]].fd;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void * nio_get_ptr(struct nio * io, int index)
|
|
{
|
|
if (nio_is_valid(io, index) != NIO_SUCCESS)
|
|
return NULL;
|
|
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
struct epoll_event * const events = (struct epoll_event *)io->events;
|
|
|
|
return events[index].data.ptr;
|
|
}
|
|
else
|
|
#endif
|
|
if (io->poll_max_fds > 0)
|
|
{
|
|
return io->poll_ptrs[io->poll_fds_set[index]];
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void nio_free(struct nio * io)
|
|
{
|
|
for (size_t i = 0; i < io->poll_max_fds; ++i)
|
|
{
|
|
if (io->poll_fds[i].fd >= 0)
|
|
{
|
|
close(io->poll_fds[i].fd);
|
|
io->poll_fds[i].fd = -1;
|
|
}
|
|
}
|
|
#ifdef ENABLE_EPOLL
|
|
if (io->epoll_fd >= 0)
|
|
{
|
|
close(io->epoll_fd);
|
|
io->epoll_fd = -1;
|
|
}
|
|
#endif
|
|
free(io->poll_fds);
|
|
free(io->poll_ptrs);
|
|
free(io->poll_fds_set);
|
|
free(io->events);
|
|
}
|