add listener foundation

This commit is contained in:
PoliEcho 2025-06-01 13:13:47 +02:00
parent d48fb807de
commit 0021fce1be
6 changed files with 197 additions and 4 deletions

View File

@ -1,10 +1,15 @@
#ifndef _IF_GLOBAL_HG_
#define _IF_GLOBAL_HG_
#include <string>
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
extern WOLFSSL_CTX *ctx;
extern int sockfd;
extern std::string interface_name;
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
// this is max size standard Ipv4/6 packet can be plus 1 for message type
// what in understand in practise it is much lower around 1500 bytes
#define IP_PACKET_BUFFER_SIZE 65536 + 1
#endif

135
src/common/types.h Normal file
View File

@ -0,0 +1,135 @@
#include <atomic>
#include <cstring>
#include <ctime>
#include <functional>
#include <memory>
#include <signal.h>
#include <stdexcept>
#ifndef TYPES_H
#define TYPES_H
template <typename... Args> class Timer {
public:
using TimerCallback = std::function<void(Args...)>;
enum class TimerType { SINGLE_SHOT, PERIODIC };
private:
struct CallbackContext {
Timer *timer;
TimerCallback callback;
std::tuple<Args...> args;
CallbackContext(Timer *t, TimerCallback cb, Args... arguments)
: timer(t), callback(cb), args(std::make_tuple(arguments...)) {}
};
timer_t timerId;
struct sigevent sev;
struct itimerspec its;
std::unique_ptr<CallbackContext> context;
std::atomic<bool> isActive{false};
std::atomic<bool> isCreated{false};
TimerType timerType;
static void timerExpired(union sigval sv) {
CallbackContext *ctx = static_cast<CallbackContext *>(sv.sival_ptr);
if (ctx && ctx->timer && ctx->timer->isActive.load()) {
// Unpack tuple and call callback with arguments
std::apply(ctx->callback, ctx->args);
if (ctx->timer->timerType == TimerType::SINGLE_SHOT) {
ctx->timer->isActive.store(false);
}
}
}
public:
Timer() {
std::memset(&sev, 0, sizeof(sev));
std::memset(&its, 0, sizeof(its));
sev.sigev_notify = SIGEV_THREAD;
sev.sigev_notify_function = timerExpired;
}
~Timer() {
stop();
if (isCreated.load()) {
timer_delete(timerId);
}
}
/**
* Arm timer with callback and arguments
*/
void arm(int delayMs, int intervalMs, TimerCallback cb, Args... args,
TimerType type = TimerType::SINGLE_SHOT) {
if (!cb) {
throw std::invalid_argument("Callback function cannot be null");
}
stop();
// Create context with callback and arguments
context = std::make_unique<CallbackContext>(this, cb, args...);
timerType = type;
if (!isCreated.load()) {
sev.sigev_value.sival_ptr = context.get();
if (timer_create(CLOCK_MONOTONIC, &sev, &timerId) == -1) {
throw std::runtime_error("Failed to create POSIX timer");
}
isCreated.store(true);
}
// Configure timer
its.it_value.tv_sec = delayMs / 1000;
its.it_value.tv_nsec = (delayMs % 1000) * 1000000;
if (type == TimerType::PERIODIC && intervalMs > 0) {
its.it_interval.tv_sec = intervalMs / 1000;
its.it_interval.tv_nsec = (intervalMs % 1000) * 1000000;
} else {
its.it_interval.tv_sec = 0;
its.it_interval.tv_nsec = 0;
}
if (timer_settime(timerId, 0, &its, nullptr) == -1) {
throw std::runtime_error("Failed to set timer");
}
isActive.store(true);
}
/**
* Reset the timer - restarts with the same configuration
*/
void reset() {
if (!isCreated.load() || !isActive.load()) {
throw std::runtime_error("Timer not armed or not active");
}
// Re-arm the timer with the same settings stored in 'its'
if (timer_settime(timerId, 0, &its, nullptr) == -1) {
throw std::runtime_error("Failed to reset timer");
}
// For single-shot timers that were previously expired, reactivate them
if (timerType == TimerType::SINGLE_SHOT) {
isActive.store(true);
}
}
void stop() {
if (isCreated.load() && isActive.load()) {
struct itimerspec disarm = {{0, 0}, {0, 0}};
timer_settime(timerId, 0, &disarm, nullptr);
isActive.store(false);
}
}
bool active() const { return isActive.load(); }
};
#endif

View File

@ -1,5 +1,6 @@
#include "../common/cleanup.h"
#include "../common/const.h"
#include "../common/global.h"
#include "IF_functions.h"
#include <arpa/inet.h>
#include <cerrno>
@ -17,10 +18,6 @@
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
// this is max size standard Ipv4/6 packet can be plus 1 for message type
// what in understand in practise it is much lower around 1500 bytes
#define IP_PACKET_BUFFER_SIZE 65536 + 1
void process_incoming_ip_packet(unsigned char *buffer, int packet_size,
WOLFSSL *ssl) {
buffer[0] = IP_PACKET_TYPE; // Set message type

48
src/server/listen.cpp Normal file
View File

@ -0,0 +1,48 @@
#include "../common/const.h"
#include "../common/global.h"
#include "../common/types.h"
#include "send.h"
#include <iostream>
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
#include <wolfssl/wolfcrypt/types.h>
Timer<WOLFSSL *> keep_alive_timer;
void send_keep_alive(WOLFSSL *ssl) {}
void listen_for_incoming_packets(WOLFSSL *ssl) {
unsigned char buf[IP_PACKET_BUFFER_SIZE];
keep_alive_timer.arm(
180000, 0, [](WOLFSSL *ssl) { send_keep_alive(ssl); }, ssl);
while (true) {
int bytes = wolfSSL_read(ssl, buf, sizeof(buf) - 1);
if (bytes > 0) {
switch (buf[0]) {
case KEEP_ALIVE_TYPE: {
unsigned char response = KEEPING_ALIVE_TYPE;
wolfSSL_write(ssl, &response, sizeof(response));
std::clog << "Received keep-alive message, sent response." << std::endl;
keep_alive_timer.reset();
break;
}
case IP_PACKET_TYPE: {
send_IP_packet(buf + 1, bytes - 1);
break;
}
case TERMINATE_CONNECTION_TYPE: {
std::cout << "Received terminate connection request." << std::endl;
return;
}
}
} else if (bytes == 0) {
std::cout << "Connection closed by peer" << std::endl;
break;
} else {
int ssl_error = wolfSSL_get_error(ssl, bytes);
std::cerr << "wolfSSL_read failed with error: " << ssl_error << std::endl;
break;
}
}
}

0
src/server/send.cpp Normal file
View File

8
src/server/send.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef SEND_H
#define SEND_H
#include <string>
#include <wolfssl/options.h>
#include <wolfssl/ssl.h>
int send_IP_packet(const unsigned char *packet, int packet_size);
#endif // SEND_H