2025-07-28 20:20:34 +02:00

159 lines
5.6 KiB
C

#include "../neonucleus.h"
typedef struct nn_tunnel {
nn_Context ctx;
nn_refc refc;
nn_guard *lock;
nn_tunnelTable table;
nn_networkControl ctrl;
} nn_tunnel;
nn_tunnel *nn_newTunnel(nn_Context *context, nn_tunnelTable table, nn_networkControl control) {
nn_Alloc *a = &context->allocator;
nn_tunnel *t = nn_alloc(a, sizeof(nn_tunnel));
if(t == NULL) return NULL;
t->lock = nn_newGuard(context);
if(t->lock == NULL) {
nn_dealloc(a, t, sizeof(nn_tunnel));
return NULL;
}
t->ctx = *context;
t->refc = 1;
t->table = table;
t->ctrl = control;
return t;
}
nn_guard *nn_getTunnelLock(nn_tunnel *tunnel) {
return tunnel->lock;
}
void nn_retainTunnel(nn_tunnel *tunnel) {
nn_incRef(&tunnel->refc);
}
nn_bool_t nn_destroyTunnel(nn_tunnel *tunnel) {
if(!nn_decRef(&tunnel->refc)) return false;
return true;
}
void nn_tunnel_destroy(void *_, nn_component *component, nn_tunnel *tunnel) {
nn_destroyTunnel(tunnel);
}
static void nni_tunnel_maxPacketSize(nn_tunnel *tunnel, void *_, nn_component *component, nn_computer *computer) {
nn_return_integer(computer, tunnel->table.maxPacketSize);
}
static void nni_tunnel_maxValues(nn_tunnel *tunnel, void *_, nn_component *component, nn_computer *computer) {
nn_return_integer(computer, tunnel->table.maxValues);
}
static void nni_tunnel_getChannel(nn_tunnel *tunnel, void *_, nn_component *component, nn_computer *computer) {
nn_errorbuf_t err = "";
char buf[NN_MAX_CHANNEL_SIZE];
nn_lock(&tunnel->ctx, tunnel->lock);
nn_size_t len = tunnel->table.getChannel(tunnel->table.userdata, buf, err);
nn_unlock(&tunnel->ctx, tunnel->lock);
if(!nn_error_isEmpty(err)) {
nn_setError(computer, err);
return;
}
nn_return_string(computer, buf, len);
}
static void nni_tunnel_getWakeMessage(nn_tunnel *tunnel, void *_, nn_component *component, nn_computer *computer) {
nn_errorbuf_t err = "";
char buf[NN_MAX_CHANNEL_SIZE];
nn_lock(&tunnel->ctx, tunnel->lock);
nn_size_t len = tunnel->table.getWakeMessage(tunnel->table.userdata, buf, err);
nn_unlock(&tunnel->ctx, tunnel->lock);
if(!nn_error_isEmpty(err)) {
nn_setError(computer, err);
return;
}
nn_return_string(computer, buf, len);
}
static void nni_tunnel_setWakeMessage(nn_tunnel *tunnel, void *_, nn_component *component, nn_computer *computer) {
nn_size_t buflen;
const char *buf = nn_toString(nn_getArgument(computer, 0), &buflen);
if(buf == NULL) {
nn_setCError(computer, "invalid wake message");
return;
}
if(buflen > NN_MAX_WAKEUPMSG) {
buflen = NN_MAX_WAKEUPMSG;
}
nn_bool_t fuzzy = nn_toBoolean(nn_getArgument(computer, 1)); // nil is false
nn_errorbuf_t err = "";
nn_lock(&tunnel->ctx, tunnel->lock);
buflen = tunnel->table.setWakeMessage(tunnel->table.userdata, buf, buflen, fuzzy, err);
nn_unlock(&tunnel->ctx, tunnel->lock);
if(!nn_error_isEmpty(err)) {
nn_setError(computer, err);
return;
}
nn_return_string(computer, buf, buflen);
}
static void nni_tunnel_send(nn_tunnel *tunnel, void *_, nn_component *component, nn_computer *computer) {
nn_value vals[tunnel->table.maxValues];
nn_size_t valLen = nn_getArgumentCount(computer);
if(valLen > tunnel->table.maxValues) {
nn_setCError(computer, "too many values");
return;
}
for(nn_size_t i = 0; i < valLen; i++) {
vals[i] = nn_getArgument(computer, i);
}
nn_size_t bytesSent = nn_measurePacketSize(vals, valLen);
if(bytesSent > tunnel->table.maxPacketSize) {
nn_setCError(computer, "packet too big");
return;
}
nn_simulateBufferedIndirect(component, bytesSent, tunnel->ctrl.packetBytesPerTick);
double d = (double)bytesSent / tunnel->table.maxPacketSize;
nn_addHeat(computer, d * tunnel->ctrl.heatPerFullPacket);
nn_removeEnergy(computer, d * tunnel->ctrl.energyPerFullPacket);
nn_errorbuf_t err = "";
nn_lock(&tunnel->ctx, tunnel->lock);
tunnel->table.send(tunnel->table.userdata, vals, valLen, err);
nn_unlock(&tunnel->ctx, tunnel->lock);
if(!nn_error_isEmpty(err)) {
nn_setError(computer, err);
return;
}
nn_return_boolean(computer, true);
}
void nn_loadTunnelTable(nn_universe *universe) {
nn_componentTable *tunnelTable = nn_newComponentTable(nn_getAllocator(universe), "tunnel", NULL, NULL, (nn_componentDestructor *)nn_tunnel_destroy);
nn_storeUserdata(universe, "NN:TUNNEL", tunnelTable);
nn_defineMethod(tunnelTable, "maxPacketSize", (nn_componentMethod *)nni_tunnel_maxPacketSize, "maxPacketSize(): integer - Returns the maximum size of a packet");
nn_defineMethod(tunnelTable, "maxValues", (nn_componentMethod *)nni_tunnel_maxValues, "maxValues(): integer - the maximum number of values which can be sent in a packet");
nn_defineMethod(tunnelTable, "getChannel", (nn_componentMethod *)nni_tunnel_getChannel, "getChannel(): string - Gets the ID of the communications channel of the tunnel. Under normal conditions, there are only 2 cards in the same universe which share this.");
nn_defineMethod(tunnelTable, "getWakeMessage", (nn_componentMethod *)nni_tunnel_getWakeMessage, "getWakeMessage(): string - Returns the current wake message");
nn_defineMethod(tunnelTable, "setWakeMessage", (nn_componentMethod *)nni_tunnel_setWakeMessage, "setWakeMessage(msg: string[, fuzzy: boolean]): string - Sets the new wake message");
nn_defineMethod(tunnelTable, "send", (nn_componentMethod *)nni_tunnel_send, "send(...): boolean - Sends a tunnel message. Returns whether it was sent.");
}
nn_component *nn_addTunnel(nn_computer *computer, nn_address address, int slot, nn_tunnel *tunnel) {
nn_componentTable *tunnelTable = nn_queryUserdata(nn_getUniverse(computer), "NN:TUNNEL");
return nn_newComponent(computer, address, slot, tunnelTable, tunnel);
}