mirror of
https://github.com/NeoFlock/neonucleus.git
synced 2025-12-31 07:15:16 +01:00
159 lines
5.6 KiB
C
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);
|
|
}
|