neonucleus/src/components/loopbackModem.c
2025-07-20 17:26:05 +02:00

145 lines
4.2 KiB
C

#include "../neonucleus.h"
typedef struct nn_modemLoop {
nn_Context ctx;
nn_debugLoopbackNetworkOpts opts;
nn_size_t *openPorts;
nn_size_t strength;
char wakeup[NN_MAX_WAKEUPMSG];
nn_size_t wakeupLen;
} nn_modemLoop;
void nn_loopModem_deinit(nn_modemLoop *loop) {
nn_Context ctx = loop->ctx;
nn_deallocStr(&ctx.allocator, loop->opts.address);
nn_dealloc(&ctx.allocator, loop->openPorts, loop->opts.maxOpenPorts * sizeof(nn_size_t));
nn_dealloc(&ctx.allocator, loop, sizeof(nn_modemLoop));
}
nn_bool_t nn_loopModem_isOpen(nn_modemLoop *loop, nn_size_t port, nn_errorbuf_t err) {
for(nn_size_t i = 0; i < loop->opts.maxOpenPorts; i++) {
if(loop->openPorts[i] == port) {
return true;
}
}
return false;
}
nn_bool_t nn_loopModem_open(nn_modemLoop *loop, nn_size_t port, nn_errorbuf_t err) {
int slot = -1;
for(nn_size_t i = 0; i < loop->opts.maxOpenPorts; i++) {
if(loop->openPorts[i] == NN_PORT_CLOSEALL) {
slot = i;
break;
}
}
if(slot == -1) {
nn_error_write(err, "too many open ports");
return false;
}
loop->openPorts[slot] = port;
return true;
}
nn_bool_t nn_loopModem_close(nn_modemLoop *loop, nn_size_t port, nn_errorbuf_t err) {
if(port == NN_PORT_CLOSEALL) {
for(nn_size_t i = 0; i < loop->opts.maxOpenPorts; i++) loop->openPorts[i] = NN_PORT_CLOSEALL;
return true;
}
for(nn_size_t i = 0; i < loop->opts.maxOpenPorts; i++) {
if(loop->openPorts[i] == port) {
loop->openPorts[i] = NN_PORT_CLOSEALL;
return true;
}
}
nn_error_write(err, "port already closed");
return false;
}
nn_size_t nn_loopModem_getPorts(nn_modemLoop *loop, nn_size_t *ports, nn_errorbuf_t err) {
nn_size_t len = 0;
for(nn_size_t i = 0; i < loop->opts.maxOpenPorts; i++) {
if(loop->openPorts[i] != NN_PORT_CLOSEALL) {
ports[len] = loop->openPorts[i];
len++;
}
}
return len;
}
nn_bool_t nn_loopModem_send(nn_modemLoop *loop, nn_address address, nn_size_t port, nn_value *values, nn_size_t valuec, nn_errorbuf_t err) {
if(address == NULL) {
// broadcasting, set it to our address
address = loop->opts.address;
}
// error is discarded as packet loss
nn_pushNetworkMessage(loop->opts.computer, loop->opts.address, address, port, loop->strength, values, valuec);
return true;
}
double nn_loopModem_getStrength(nn_modemLoop *loop, nn_errorbuf_t err) {
return loop->strength;
}
double nn_loopModem_setStrength(nn_modemLoop *loop, double n, nn_errorbuf_t err) {
loop->strength = n;
return n;
}
nn_size_t nn_loopModem_getWakeMessage(nn_modemLoop *loop, char *msg, nn_errorbuf_t err) {
nn_memcpy(msg, loop->wakeup, loop->wakeupLen);
return loop->wakeupLen;
}
nn_size_t nn_loopModem_setWakeMessage(nn_modemLoop *loop, const char *msg, nn_size_t msglen, nn_bool_t fuzzy, nn_errorbuf_t err) {
loop->wakeupLen = msglen;
nn_memcpy(loop->wakeup, msg, loop->wakeupLen);
return loop->wakeupLen;
}
nn_modem *nn_debugLoopbackModem(nn_Context *context, nn_debugLoopbackNetworkOpts opts, nn_networkControl control) {
opts.address = nn_strdup(&context->allocator, opts.address);
nn_modemLoop *m = nn_alloc(&context->allocator, sizeof(nn_modemLoop));
m->ctx = *context;
m->opts = opts;
m->strength = opts.maxStrength;
m->wakeupLen = 0;
m->openPorts = nn_alloc(&context->allocator, opts.maxOpenPorts * sizeof(nn_size_t));
for(nn_size_t i = 0; i < opts.maxOpenPorts; i++) {
m->openPorts[i] = NN_PORT_CLOSEALL; // used as a NULL port
}
nn_modemTable table = {
.userdata = m,
.deinit = (void *)nn_loopModem_deinit,
.wireless = opts.isWireless,
.maxValues = opts.maxValues,
.maxOpenPorts = opts.maxOpenPorts,
.maxPacketSize = opts.maxPacketSize,
.isOpen = (void *)nn_loopModem_isOpen,
.open = (void *)nn_loopModem_open,
.close = (void *)nn_loopModem_close,
.getPorts = (void *)nn_loopModem_getPorts,
.send = (void *)nn_loopModem_send,
.maxStrength = opts.maxStrength,
.getStrength = (void *)nn_loopModem_getStrength,
.setStrength = (void *)nn_loopModem_setStrength,
.setWakeMessage = (void *)nn_loopModem_setWakeMessage,
.getWakeMessage = (void *)nn_loopModem_getWakeMessage,
};
return nn_newModem(context, table, control);
}