data card and stuff
anything but device info
This commit is contained in:
@@ -501,7 +501,11 @@ int main(int argc, char **argv) {
|
||||
ncl_mountKeyboard(scrstate, "mainKB");
|
||||
|
||||
nn_Computer *c = nn_createComputer(u, NULL, NULL, ramTotal, 256, 256);
|
||||
nn_setComputerEnvironment(c, (nn_Environment) {.userdata = NULL, .handler = ne_env});
|
||||
nn_Environment cEnv = {
|
||||
.userdata = NULL,
|
||||
.handler = ne_env,
|
||||
};
|
||||
nn_setComputerEnvironment(c, cEnv);
|
||||
nn_setCallBudget(c, 0);
|
||||
nn_setTotalEnergy(c, allEnergy);
|
||||
|
||||
@@ -693,6 +697,8 @@ int main(int argc, char **argv) {
|
||||
nn_removeEnergy(c, ncl_getScreenEnergyUsage(nn_getComponentState(screen)));
|
||||
|
||||
if(noIdle) nn_resetIdleTime(c);
|
||||
// OC computers consume 0.5W when running, 0.05W when running but idle
|
||||
nn_removeEnergy(c, nn_isComputerIdle(c) ? 0.05 : 0.5);
|
||||
nn_Exit e = nn_tick(c);
|
||||
if(e != NN_OK) {
|
||||
printf("error: %s\n", nn_getError(c));
|
||||
|
||||
219
src/neonucleus.c
219
src/neonucleus.c
@@ -113,11 +113,6 @@ void nn_free(nn_Context *ctx, void *memory, size_t size) {
|
||||
}
|
||||
|
||||
void *nn_realloc(nn_Context *ctx, void *memory, size_t oldSize, size_t newSize) {
|
||||
// nn_realloc passed memory (which is NULL here) as first argument
|
||||
// to nn_alloc instead of ctx. nn_alloc dereferences it as a context
|
||||
// struct to call ctx->alloc(), so this is a NULL pointer dereference.
|
||||
// Confirmed by test_realloc crashing on nn_realloc(&ctx, NULL, 0, 64).
|
||||
// Original: if(memory == NULL) return nn_alloc(memory, newSize); if(memory == ctx->alloc) return nn_alloc(memory, newSize);
|
||||
if(memory == NULL) return nn_alloc(ctx, newSize);
|
||||
if(memory == ctx->alloc) return nn_alloc(ctx, newSize);
|
||||
if(newSize == 0) {
|
||||
@@ -1221,6 +1216,11 @@ nn_Exit nn_startComputer(nn_Computer *computer) {
|
||||
return err;
|
||||
}
|
||||
computer->archState = req.localState;
|
||||
nn_EnvironmentRequest envreq;
|
||||
envreq.userdata = computer->env.userdata;
|
||||
envreq.computer = computer;
|
||||
envreq.action = NN_ENV_POWERON;
|
||||
computer->env.handler(&envreq);
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
@@ -1234,6 +1234,12 @@ void nn_stopComputer(nn_Computer *computer) {
|
||||
req.action = NN_ARCH_DEINIT;
|
||||
computer->arch.handler(&req);
|
||||
computer->archState = NULL;
|
||||
|
||||
nn_EnvironmentRequest envreq;
|
||||
envreq.userdata = computer->env.userdata;
|
||||
envreq.computer = computer;
|
||||
envreq.action = NN_ENV_POWEROFF;
|
||||
computer->env.handler(&envreq);
|
||||
}
|
||||
computer->state = NN_BOOTUP;
|
||||
for(size_t i = 0; i < computer->signalCount; i++) {
|
||||
@@ -1609,6 +1615,11 @@ nn_Exit nn_tick(nn_Computer *computer) {
|
||||
if(err) {
|
||||
computer->state = NN_CRASHED;
|
||||
nn_setErrorFromExit(computer, err);
|
||||
nn_EnvironmentRequest envreq;
|
||||
envreq.userdata = computer->env.userdata;
|
||||
envreq.computer = computer;
|
||||
envreq.action = NN_ENV_CRASHED;
|
||||
computer->env.handler(&envreq);
|
||||
return err;
|
||||
}
|
||||
return NN_OK;
|
||||
@@ -1628,6 +1639,11 @@ nn_Exit nn_tickSynchronized(nn_Computer *computer) {
|
||||
if(err) {
|
||||
computer->state = NN_CRASHED;
|
||||
nn_setErrorFromExit(computer, err);
|
||||
nn_EnvironmentRequest envreq;
|
||||
envreq.userdata = computer->env.userdata;
|
||||
envreq.computer = computer;
|
||||
envreq.action = NN_ENV_CRASHED;
|
||||
computer->env.handler(&envreq);
|
||||
return err;
|
||||
}
|
||||
return NN_OK;
|
||||
@@ -5842,6 +5858,197 @@ nn_Component *nn_createGPU(
|
||||
return c;
|
||||
}
|
||||
|
||||
typedef enum nn_DataNum {
|
||||
NN_DATANUM_GETLIMIT,
|
||||
|
||||
NN_DATANUM_DECODE64,
|
||||
|
||||
NN_DATANUM_ENCODE64,
|
||||
|
||||
NN_DATANUM_CRC32,
|
||||
|
||||
NN_DATANUM_MD5,
|
||||
|
||||
NN_DATANUM_SHA256,
|
||||
|
||||
NN_DATANUM_DEFLATE,
|
||||
|
||||
NN_DATANUM_INFLATE,
|
||||
|
||||
NN_DATANUM_ENCRYPT,
|
||||
|
||||
NN_DATANUM_DECRYPT,
|
||||
|
||||
NN_DATANUM_RANDOM,
|
||||
|
||||
NN_DATANUM_MAXRANDOM,
|
||||
|
||||
NN_DATANUM_GENKEYPAIR,
|
||||
|
||||
NN_DATANUM_ECDSA,
|
||||
|
||||
NN_DATANUM_ECDH,
|
||||
|
||||
NN_DATANUM_DESERIALIZEKEY,
|
||||
|
||||
NN_DATANUM_COUNT,
|
||||
} nn_DataNum;
|
||||
|
||||
typedef struct nn_DataState {
|
||||
nn_Context *ctx;
|
||||
nn_DataCard dataCard;
|
||||
nn_DataCardHandler *handler;
|
||||
} nn_DataState;
|
||||
|
||||
nn_DataCard nn_defaultDataCards[3] = {
|
||||
NN_INIT(nn_DataCard) {
|
||||
.limit = NN_MiB,
|
||||
.maxRandom = NN_KiB,
|
||||
.canHash = true,
|
||||
.canEncrypt = false,
|
||||
.canECDH = false,
|
||||
.canCompress = true,
|
||||
.trivialCost = 0.2,
|
||||
.trivialCostByte = 0.005,
|
||||
.simpleCost = 1.0,
|
||||
.simpleCostByte = 0.01,
|
||||
.complexCost = 6.0,
|
||||
.complexCostByte = 0.1,
|
||||
.assymetricCost = 10.0,
|
||||
},
|
||||
NN_INIT(nn_DataCard) {
|
||||
.limit = NN_MiB,
|
||||
.maxRandom = NN_KiB,
|
||||
.canHash = true,
|
||||
.canEncrypt = true,
|
||||
.canECDH = false,
|
||||
.canCompress = true,
|
||||
.trivialCost = 0.2,
|
||||
.trivialCostByte = 0.005,
|
||||
.simpleCost = 1.0,
|
||||
.simpleCostByte = 0.01,
|
||||
.complexCost = 6.0,
|
||||
.complexCostByte = 0.1,
|
||||
.assymetricCost = 10.0,
|
||||
},
|
||||
NN_INIT(nn_DataCard) {
|
||||
.limit = NN_MiB,
|
||||
.maxRandom = NN_KiB,
|
||||
.canHash = true,
|
||||
.canEncrypt = true,
|
||||
.canECDH = true,
|
||||
.canCompress = true,
|
||||
.trivialCost = 0.2,
|
||||
.trivialCostByte = 0.005,
|
||||
.simpleCost = 1.0,
|
||||
.simpleCostByte = 0.01,
|
||||
.complexCost = 6.0,
|
||||
.complexCostByte = 0.1,
|
||||
.assymetricCost = 10.0,
|
||||
},
|
||||
};
|
||||
static nn_Exit nn_dataHandler(nn_ComponentRequest *req) {
|
||||
if(req->action == NN_COMP_SIGNAL) return NN_OK;
|
||||
nn_Context *ctx = req->ctx;
|
||||
nn_DataState *state = req->classState;
|
||||
nn_Computer *C = req->computer;
|
||||
|
||||
nn_DataCard dataCard = state->dataCard;
|
||||
nn_DataNum method = req->methodIdx;
|
||||
|
||||
if(req->action == NN_COMP_CHECKMETHOD) {
|
||||
if(method == NN_DATANUM_SHA256 || method == NN_DATANUM_MD5) {
|
||||
req->methodEnabled = dataCard.canHash;
|
||||
}
|
||||
if(method == NN_DATANUM_DEFLATE || method == NN_DATANUM_INFLATE || method == NN_DATANUM_RANDOM || method == NN_DATANUM_MAXRANDOM) {
|
||||
req->methodEnabled = dataCard.canCompress;
|
||||
}
|
||||
if(method == NN_DATANUM_ENCRYPT || method == NN_DATANUM_DECRYPT) {
|
||||
req->methodEnabled = dataCard.canEncrypt;
|
||||
}
|
||||
if(method == NN_DATANUM_GENKEYPAIR || method == NN_DATANUM_ECDH || method == NN_DATANUM_ECDSA || method == NN_DATANUM_DESERIALIZEKEY) {
|
||||
req->methodEnabled = dataCard.canECDH;
|
||||
}
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
nn_DataCardRequest dreq;
|
||||
dreq.ctx = ctx;
|
||||
dreq.computer = C;
|
||||
dreq.state = req->state;
|
||||
dreq.dataCard = &state->dataCard;
|
||||
nn_Exit e;
|
||||
|
||||
if(req->action == NN_COMP_DROP) {
|
||||
dreq.action = NN_DATA_DROP;
|
||||
state->handler(&dreq);
|
||||
nn_free(ctx, state, sizeof(*state));
|
||||
return NN_OK;
|
||||
}
|
||||
|
||||
if(method == NN_DATANUM_GETLIMIT) {
|
||||
req->returnCount = 1;
|
||||
return nn_pushinteger(C, dataCard.limit);
|
||||
}
|
||||
if(method == NN_DATANUM_MAXRANDOM) {
|
||||
req->returnCount = 1;
|
||||
return nn_pushinteger(C, dataCard.maxRandom);
|
||||
}
|
||||
|
||||
// TODO: the cool methods
|
||||
|
||||
if(C) nn_setError(C, "data: not implemented yet");
|
||||
return NN_EBADCALL;
|
||||
}
|
||||
|
||||
nn_Component *nn_createDataCard(nn_Universe *universe, const char *address, const nn_DataCard *dataCard, void *state, nn_DataCardHandler *handler) {
|
||||
nn_Component *c = nn_createComponent(
|
||||
universe, address, "data");
|
||||
if(c == NULL) return NULL;
|
||||
|
||||
nn_Method methods[NN_DATANUM_COUNT] = {
|
||||
[NN_DATANUM_GETLIMIT] = {"getLimit", "function(): integer - Get the buffer capacity of the card", NN_DIRECT},
|
||||
[NN_DATANUM_DECODE64] = {"decode64", "function(data: string): string - Decodes the string as base64 data", NN_DIRECT},
|
||||
[NN_DATANUM_ENCODE64] = {"encode64", "function(data: string): string - Encodes the string into base64 data", NN_DIRECT},
|
||||
[NN_DATANUM_CRC32] = {"crc32", "function(data: string): string - Computes the CRC-32 hash of the data", NN_DIRECT},
|
||||
[NN_DATANUM_MD5] = {"md5", "function(data: string): string - Computes the MD5 hash of the data", NN_DIRECT},
|
||||
[NN_DATANUM_SHA256] = {"sha256", "function(data: string): string - Computes the SHA256 hash of the data", NN_DIRECT},
|
||||
[NN_DATANUM_DEFLATE] = {"deflate", "function(data: string): string - Compresses the data", NN_DIRECT},
|
||||
[NN_DATANUM_INFLATE] = {"deflate", "function(data: string): string - Decompresses the compressed data", NN_DIRECT},
|
||||
[NN_DATANUM_ENCRYPT] = {"encrypt", "function(data: string, key: string, iv: string): string - Encrypts the data", NN_DIRECT},
|
||||
[NN_DATANUM_DECRYPT] = {"decrypt", "function(data: string, key: string, iv: string): string - Decrypts the data", NN_DIRECT},
|
||||
[NN_DATANUM_RANDOM] = {"random", "function(size: integer): string - Generates an amount of secure random bytes", NN_DIRECT},
|
||||
[NN_DATANUM_MAXRANDOM] = {"getRandomLimit", "function(): integer - Maximum amount of secure random bytes the data card will generate", NN_DIRECT},
|
||||
[NN_DATANUM_GENKEYPAIR] = {"generateKeyPair", "function(bitLen?: integer): userdata, userdata - Generates a pair of 2 ECDH keys; ec-public and ec-private respectively. Supports 256-bit and 384-bit keys.", NN_DIRECT},
|
||||
[NN_DATANUM_ECDSA] = {"ecdsa", "function(data: string, key: userdata, sig: string?): string or boolean - Either generates a signature using a private key, or if signature is specified, verifies it with public key", NN_DIRECT},
|
||||
[NN_DATANUM_ECDH] = {"ecdh", "function(privateKey: userdata, publicKey: userdata): string - Computes a shared secret using a private and public key from different pairs. The rule is, ecdh(a.private, b.public) == ecdh(b.private, a.public)", NN_DIRECT},
|
||||
[NN_DATANUM_DESERIALIZEKEY] = {"deserializeKey", "function(data: string, type: string): userdata - Deserializes key data assuming a specific type. Public keys are of type ec-public, and private ones of type ec-private.", NN_DIRECT},
|
||||
};
|
||||
|
||||
if(dataCard->canEncrypt && dataCard->canHash) {
|
||||
methods[NN_DATANUM_SHA256].doc = "function(data: string, hmacKey: string?): string - Computes the SHA256 hash / HMAC";
|
||||
methods[NN_DATANUM_MD5].doc = "function(data: string, hmacKey: string?): string - Computes the MD5 hash / HMAC";
|
||||
}
|
||||
|
||||
nn_Exit e = nn_setComponentMethodsArray(
|
||||
c, methods, NN_DATANUM_COUNT);
|
||||
if(e) { nn_dropComponent(c); return NULL; }
|
||||
|
||||
nn_Context *ctx = &universe->ctx;
|
||||
nn_DataState *cls = nn_alloc(ctx, sizeof(*cls));
|
||||
if(cls == NULL) {
|
||||
nn_dropComponent(c);
|
||||
return NULL;
|
||||
}
|
||||
cls->ctx = ctx;
|
||||
cls->dataCard = *dataCard;
|
||||
cls->handler = handler;
|
||||
nn_setComponentState(c, state);
|
||||
nn_setComponentClassState(c, cls);
|
||||
nn_setComponentHandler(c, nn_dataHandler);
|
||||
return c;
|
||||
}
|
||||
|
||||
typedef enum nn_ModemNum {
|
||||
NN_MODEMNUM_ISWIRED,
|
||||
NN_MODEMNUM_ISWIRELESS,
|
||||
@@ -5934,7 +6141,7 @@ static nn_Exit nn_modemHandler(nn_ComponentRequest *req) {
|
||||
|
||||
nn_Component *nn_createModem(nn_Universe *universe, const char *address, const nn_Modem *modem, void *state, nn_ModemHandler *handler) {
|
||||
nn_Component *c = nn_createComponent(
|
||||
universe, address, "gpu");
|
||||
universe, address, "modem");
|
||||
if(c == NULL) return NULL;
|
||||
|
||||
const nn_Method methods[NN_MODEMNUM_COUNT] = {
|
||||
|
||||
103
src/neonucleus.h
103
src/neonucleus.h
@@ -1594,6 +1594,109 @@ nn_Component *nn_createScreen(
|
||||
nn_ScreenHandler *handler
|
||||
);
|
||||
|
||||
typedef struct nn_DataCard {
|
||||
// The buffer size of the data card, limit in both input and output.
|
||||
// This buffer is allocated on the heap before the call, thus setting it to be very large will lead to huge *spikes* in memory usage.
|
||||
// In OC, this value is 1MiB regardless of tier.
|
||||
size_t limit;
|
||||
|
||||
// The maximum amount of secure random bytes that can be generated.
|
||||
// In OC, this was hardcoded to 1024. Here, its configurable.
|
||||
// Unlike the normal limit, this does not preallocate the maximum capacity,
|
||||
// as the amount of bytes needed is known perfectly.
|
||||
size_t maxRandom;
|
||||
|
||||
// Capabilities
|
||||
bool canHash;
|
||||
bool canEncrypt;
|
||||
bool canECDH;
|
||||
bool canCompress;
|
||||
|
||||
// Trivial operation cost (CRC32 and base64 encoding/decoding)
|
||||
double trivialCost;
|
||||
double trivialCostByte;
|
||||
|
||||
// Simple operation cost (MD5 and encryption/decryption)
|
||||
double simpleCost;
|
||||
double simpleCostByte;
|
||||
|
||||
double complexCost;
|
||||
double complexCostByte;
|
||||
|
||||
// Assymetric operation cost (ECDH, ECDSA). ECDH has no per-byte cost, and ECDSA uses complexCostByte as it relies on SHA256.
|
||||
double assymetricCost;
|
||||
} nn_DataCard;
|
||||
|
||||
typedef enum nn_DataCardAction {
|
||||
// Data card destroyed
|
||||
NN_DATA_DROP,
|
||||
|
||||
// If you want to match the behavior of OC, which you should if you want
|
||||
// data compressed or encrypted in OC to work in your emulators, you should
|
||||
// aim to match what the JVM, com.google.common.hash.Hashing and javax.crypto do.
|
||||
// For more details, see https://github.com/MightyPirates/OpenComputers/blob/master-MC1.7.10/src/main/scala/li/cil/oc/server/component/DataCard.scala
|
||||
|
||||
// encoding base64
|
||||
NN_DATA_ENCODE64,
|
||||
|
||||
NN_DATA_DECODE64,
|
||||
// hashing
|
||||
|
||||
// CRC32, little endian
|
||||
NN_DATA_CRC32,
|
||||
|
||||
// SHA2-256 hash, optional HMAC key (javax.crypto HmacSHA256)
|
||||
NN_DATA_SHA256,
|
||||
|
||||
// MD5 hash, optional HMAC key (javax.crypto HmacMD5)
|
||||
NN_DATA_MD5,
|
||||
|
||||
// Deflate. To match OC, make it follow the ZLIB format, which has a 2 byte header.
|
||||
NN_DATA_DEFLATE,
|
||||
|
||||
// Inflate. Should support the ZLIB format, as thats what OC uses, and GZIP support is optional.
|
||||
NN_DATA_INFALTE,
|
||||
|
||||
// Encrypt data with AES-128. The full algorithm is AES/CBC/PKCS5, as is use PKCS5 for padding, CBC for block sequences, and AES-128 for encrypting blocks.
|
||||
// It does also receive a 128-bit AES Initialization Vector, for better security.
|
||||
NN_DATA_ENCRYPT,
|
||||
|
||||
// Decrypt data, also using AES/CBC/PKCS5.
|
||||
NN_DATA_DECRYPT,
|
||||
|
||||
// Meant to be *secure RNG*, and can generate anywhere between 1 and the data card's maxRandom.
|
||||
NN_DATA_RANDOM,
|
||||
|
||||
// Generate an ECDH public/private pair of either 256 or 384 bits each.
|
||||
NN_DATA_GENKEYS,
|
||||
|
||||
// Does an ECDH pass, matching javax.crypto.KeyAgreement.
|
||||
// This generates a shared secret as binary data.
|
||||
// This is not an AES key as output, the AES key is often computed by either MD5 hashing
|
||||
// the shared secret, or SHA256 hashing it and chopping the hash in half.
|
||||
NN_DATA_ECDH,
|
||||
|
||||
// ECDSA algorithm, sign data using an ECDH (private) key.
|
||||
NN_DATA_ECDSA_SIGN,
|
||||
// ECDSA algorithm, verify data using an ECDH (public) key and signature.
|
||||
NN_DATA_ECDSA_VERIFY,
|
||||
} nn_DataCardAction;
|
||||
|
||||
typedef struct nn_DataCardRequest {
|
||||
nn_Context *ctx;
|
||||
nn_Computer *computer;
|
||||
void *state;
|
||||
const nn_DataCard *dataCard;
|
||||
nn_DataCardAction action;
|
||||
// TODO: the fields
|
||||
} nn_DataCardRequest;
|
||||
|
||||
typedef nn_Exit (nn_DataCardHandler)(nn_DataCardRequest *req);
|
||||
|
||||
extern nn_DataCard nn_defaultDataCards[3];
|
||||
|
||||
nn_Component *nn_createDataCard(nn_Universe *universe, const char *address, const nn_DataCard *dataCard, void *state, nn_DataCardHandler *handler);
|
||||
|
||||
typedef struct nn_Modem {
|
||||
// maximum range. Set to 0 for non-wireless modems
|
||||
size_t maxRange;
|
||||
|
||||
Reference in New Issue
Block a user