static bool checkArgs(Dict* args, struct Function* func, String* txid, struct Admin* admin) { struct Dict_Entry* entry = *func->args; String* error = NULL; uint8_t buffer[1024]; struct Allocator* alloc = BufferAllocator_new(buffer, 1024); while (entry != NULL) { String* key = (String*) entry->key; Assert_true(entry->val->type == Object_DICT); Dict* value = entry->val->as.dictionary; entry = entry->next; if (*Dict_getInt(value, String_CONST("required")) == 0) { continue; } String* type = Dict_getString(value, String_CONST("type")); if ((type == STRING && !Dict_getString(args, key)) || (type == DICT && !Dict_getDict(args, key)) || (type == INTEGER && !Dict_getInt(args, key)) || (type == LIST && !Dict_getList(args, key))) { error = String_printf(alloc, "Entry [%s] is required and must be of type [%s]", key->bytes, type->bytes); break; } } if (error) { Dict d = Dict_CONST(String_CONST("error"), String_OBJ(error), NULL); Admin_sendMessage(&d, txid, admin); } return !error; }
static void initTunnel(Dict* args, void* vcontext, String* txid) { struct Context* const ctx = (struct Context*) vcontext; #define BUFFERSZ 1024 uint8_t buffer[BUFFERSZ]; struct Allocator* const alloc = BufferAllocator_new(buffer, BUFFERSZ); struct Jmp jmp; Jmp_try(jmp) { Core_initTunnel(Dict_getString(args, String_CONST("desiredTunName")), ctx->ipAddr, 8, ctx->ducttape, ctx->logger, ctx->ipTunnel, ctx->eventBase, ctx->alloc, &jmp.handler); } Jmp_catch { String* error = String_printf(alloc, "Failed to configure tunnel [%s]", jmp.message); sendResponse(error, ctx->admin, txid, alloc); return; } sendResponse(String_CONST("none"), ctx->admin, txid, alloc); }
static inline uint8_t incomingDHT(struct Message* message, struct Address* addr, struct Ducttape_pvt* context) { struct DHTMessage dht; Bits_memset(&dht, 0, sizeof(struct DHTMessage)); // TODO: These copies are not necessary at all. const uint32_t length = (message->length < DHTMessage_MAX_SIZE) ? message->length : DHTMessage_MAX_SIZE; Bits_memcpy(dht.bytes, message->bytes, length); dht.address = addr; uint8_t buffer[PER_MESSAGE_BUF_SZ]; dht.allocator = BufferAllocator_new(buffer, PER_MESSAGE_BUF_SZ); struct Jmp j; Jmp_try(j) { BufferAllocator_onOOM(dht.allocator, &j.handler); DHTModuleRegistry_handleIncoming(&dht, context->registry); } Jmp_catch { uint8_t printed[60]; Address_print(printed, addr); Log_warn(context->logger, "Parsing message from [%s] failed; out of memory.", printed); } // TODO: return something meaningful. return Error_NONE; }
int testDeserialization() { char context[12]; struct DHTModule module = { .name = "TestModule", .context = context, .deserialize = deserialize }; char buffer[512]; struct Allocator* allocator = BufferAllocator_new(buffer, 512); struct Reader* reader = ArrayReader_new(control, strlen(control), allocator); struct DHTModuleRegistry* reg = DHTModules_deserialize(reader, allocator); DHTModules_register(&module, reg); context[11] = '\0'; printf("Deserialization output is: %s\n", context); return memcmp(context, "Hello World", 11); } int main() { return testSerialization() | testDeserialization(); }
static inline uint8_t incomingDHT(struct Message* message, struct Address* addr, struct Ducttape* context) { struct DHTMessage dht; memset(&dht, 0, sizeof(struct DHTMessage)); // TODO: These copies are not necessary at all. const uint32_t length = (message->length < DHTMessage_MAX_SIZE) ? message->length : DHTMessage_MAX_SIZE; Bits_memcpy(dht.bytes, message->bytes, length); dht.address = addr; uint8_t buffer[PER_MESSAGE_BUF_SZ]; dht.allocator = BufferAllocator_new(buffer, PER_MESSAGE_BUF_SZ); jmp_buf towel; if (!setjmp(towel)) { BufferAllocator_onOOM(dht.allocator, outOfMemory, &towel); DHTModuleRegistry_handleIncoming(&dht, context->registry); } // TODO: return something meaningful. return Error_NONE; }
static void doLog(struct Log* genericLog, enum Log_Level logLevel, const char* fullFilePath, uint32_t line, const char* format, va_list args) { struct AdminLog* log = (struct AdminLog*) genericLog; Dict* message = NULL; #define ALLOC_BUFFER_SZ 4096 uint8_t allocBuffer[ALLOC_BUFFER_SZ]; for (int i = 0; i < (int)log->subscriptionCount; i++) { if (isMatch(&log->subscriptions[i], log, logLevel, fullFilePath, line)) { if (!message) { struct Allocator* alloc = BufferAllocator_new(allocBuffer, ALLOC_BUFFER_SZ); message = makeLogMessage(&log->subscriptions[i], log, logLevel, fullFilePath, line, format, args, alloc); } int ret = Admin_sendMessage(message, log->subscriptions[i].txid, log->admin); if (ret) { removeSubscription(log, &log->subscriptions[i]); } } } }
static Dict* serialize(void* vcontext) { char* buffer = calloc(2048, 1); struct Allocator* allocator = BufferAllocator_new(buffer, 2048); Dict* out = Dict_new(allocator); Dict_putString(out, &hi, String_new((char*) vcontext, allocator), allocator); return out; }
static void sendResponse(String* msg, struct Admin* admin, String* txid) { #define BUFFERSZ 1024 uint8_t buffer[BUFFERSZ]; struct Allocator* alloc = BufferAllocator_new(buffer, BUFFERSZ); Dict* output = Dict_new(alloc); Dict_putString(output, String_CONST("error"), msg, alloc); Admin_sendMessage(output, txid, admin); }
int main() { char buffer[512]; char out[512]; struct Allocator* alloc = BufferAllocator_new(buffer, 512); struct Writer* writer = ArrayWriter_new(out, 512, alloc); struct Reader* reader = ArrayReader_new(out, 512, alloc); return testSerialize(writer, reader); }
static void adminPing(Dict* input, void* vadmin, String* txid) { uint8_t buffer[256]; struct Allocator* alloc = BufferAllocator_new(buffer, 256); String* pong = BSTR("pong"); Dict* d = Dict_new(alloc); Dict_putString(d, CJDHTConstants_QUERY, pong, alloc); Admin_sendMessage(d, txid, (struct Admin*) vadmin); }
static void adminMemory(Dict* input, void* vcontext, String* txid) { struct Context* context = (struct Context*) vcontext; uint8_t buffer[256]; struct Allocator* alloc = BufferAllocator_new(buffer, 256); String* bytes = BSTR("bytes"); Dict* d = Dict_new(alloc); Dict_putInt(d, bytes, MallocAllocator_bytesAllocated(context->allocator), alloc); Admin_sendMessage(d, txid, context->admin); }
int main() { #define ENTRY_COUNT 13 // {seconds,entry} const uint32_t testData[ENTRY_COUNT][3] = { // The entry between the */and/* is the one which was just altered. // second col1 col2 col3 average { 0,/* */0/* */, 0}, { 1,/* 0 */1/* */, 0}, { 2,/* 0 1 */2/* */, 1}, { 3,/* */3/* 1 2 */, 2}, { 4,/* 3 */4/* 2 */, 3}, { 5,/* 3 4 */5/* */, 4}, { 6,/* */6/* 4 5 */, 5}, { 7,/* 6 */7/* 5 */, 6}, { 8,/* 6 7 */8/* */, 7}, { 9,/* */9/* 7 8 */, 8}, // 9 */7/* 8 8 skipped a second {11,/* 9 7 */7/* */, 7}, {12,/* */6/* 7 7 */, 6}, // 6 */7/* 7 6 skipped a second {14,/* 6 7 */4/* */, 5} }; const uint32_t windowSeconds = 3; uint8_t buffer[4096]; struct Allocator* allocator = BufferAllocator_new(buffer, 4096); struct event_base* eventBase = event_base_new(); struct AverageRoller* roller = (struct AverageRoller*) AverageRoller_new(windowSeconds, eventBase, allocator); // To make life easy we will pretend it's january first 1970... roller->lastUpdateTime = 0; uint32_t ret = 0; for (uint32_t i = 0; i < ENTRY_COUNT; i++) { uint32_t average = update(roller, testData[i][0], testData[i][1]); if (average != testData[i][2]) { printf("For average #%d, expected %d, got %d, float: %f, entryCount: %d\n", (int) i, (int) testData[i][2], (int) average, ((float) roller->sum) / roller->entryCount, (int) roller->entryCount); ret = 1; } } return ret; }
int main() { srand(time(NULL)); char buffer[1024]; struct Allocator* allocator = BufferAllocator_new(buffer, 1024); struct SearchNodeIndex index = {rand() % SearchStore_MAX_SEARCHES, rand() % SearchStore_SEARCH_NODES}; String* str = tidForSearchNodeIndex(&index, allocator); struct SearchNodeIndex index2 = searchNodeIndexForTid(str); if (index.search - index2.search + index.node - index2.node) { printf("inputs were %d and %d\noutputs were %d and %d\nintermediet was %s\nlength was: %d", index.search, index.node, index2.search, index2.node, str->bytes, (int) str->len); return -1; } return 0; }
int parseEmptyList() { char* test = "d" "2:hi" "le" "e"; char buffer[512]; struct Allocator* alloc = BufferAllocator_new(buffer, 512); struct Reader* reader = ArrayReader_new(test, strlen(test), alloc); Dict d; int ret = StandardBencSerializer_get()->parseDictionary(reader, alloc, &d); if (ret) { return ret; } char out[256]; struct Writer* w = ArrayWriter_new(out, 256, alloc); ret = StandardBencSerializer_get()->serializeDictionary(w, &d); if (ret) { return ret; } return Bits_memcmp(test, out, strlen(test)); }
void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } uint8_t buff[MAX_API_REQUEST_SIZE]; uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); int skip = (txid) ? 8 : 0; struct Writer* w = ArrayWriter_new(buff + skip, MAX_API_REQUEST_SIZE - skip, allocator); StandardBencSerializer_get()->serializeDictionary(w, message); size_t written = w->bytesWritten(w) + skip; if (txid) { memcpy(buff, "4567", 4); memcpy(buff + 4, txid->bytes, 4); } write(admin->outFd, buff, written); }
static void spawnAngel(int* fromAngelOut, int* toAngelOut) { int pipeToAngel[2]; int pipeFromAngel[2]; Assert_true(!Pipe_createUniPipe(pipeToAngel) && !Pipe_createUniPipe(pipeFromAngel)); char pipeToAngelStr[8]; snprintf(pipeToAngelStr, 8, "%d", pipeToAngel[0]); char pipeFromAngelStr[8]; snprintf(pipeFromAngelStr, 8, "%d", pipeFromAngel[1]); char* args[] = { "angel", pipeToAngelStr, pipeFromAngelStr, NULL }; uint8_t allocBuff[256]; struct Allocator* tempAlloc = BufferAllocator_new(allocBuff, 256); char* path = Process_getPath(tempAlloc); Assert_true(path); Process_spawn(path, args); *fromAngelOut = pipeFromAngel[0]; *toAngelOut = pipeToAngel[1]; }
static int testSerialization() { char* context = "Hello World"; struct DHTModule module = { .name = "TestModule", .context = context, .serialize = serialize }; char buffer[256]; struct Allocator* allocator = BufferAllocator_new(buffer, 256); char writeBuffer[64]; memset(writeBuffer, 0, 64); struct Writer* writer = ArrayWriter_new(writeBuffer, 64, allocator); struct DHTModuleRegistry* reg = DHTModules_new(allocator); DHTModules_register(&module, reg); DHTModules_serialize(reg, writer); /* This is ok because the output is null padded at the end. */ printf("The content is: %s\nand the length is: %d\n", writeBuffer, (int) writer->bytesWritten(writer)); if (writer->bytesWritten(writer) != strlen(control)) { printf("Length mismatch! expected: %d", (int) strlen(control)); } return memcmp(writeBuffer, control, writer->bytesWritten(writer)); } static void deserialize(const Dict* serialData, void* vcontext) { char* context = (char*) vcontext; String* out = Dict_getString(serialData, &hi); memcpy(context, out->bytes, out->len); }
static inline uint8_t incomingDHT(struct Message* message, struct Address* addr, struct Context* context) { struct DHTMessage dht; memset(&dht, 0, sizeof(struct DHTMessage)); // TODO: These copies are not necessary at all. const uint32_t length = (message->length < MAX_MESSAGE_SIZE) ? message->length : MAX_MESSAGE_SIZE; memcpy(dht.bytes, message->bytes, length); dht.address = addr; uint8_t buffer[PER_MESSAGE_BUF_SZ]; dht.allocator = BufferAllocator_new(buffer, PER_MESSAGE_BUF_SZ);; DHTModules_handleIncoming(&dht, context->registry); // TODO: return something meaningful. return Error_NONE; }
void encryptRndNonceTest() { uint8_t buff[44]; memset(buff, 0, 44); uint8_t nonce[24]; memset(nonce, 0, 24); uint8_t secret[32]; memset(secret, 0, 32); struct Message m = { .bytes=&buff[32], .length=12, .padding=32}; strcpy((char*) m.bytes, "hello world"); Exports_encryptRndNonce(nonce, &m, secret); uint8_t* expected = (uint8_t*) "1391ac5d03ba9f7099bffbb6e6c69d67ae5bd79391a5b94399b293dc"; uint8_t output[57]; Hex_encode(output, 57, m.bytes, m.length); //printf("\n%s\n%s\n", (char*) expected, (char*) output); Assert_always(!memcmp(expected, output, 56)); Assert_always(!Exports_decryptRndNonce(nonce, &m, secret)); Assert_always(m.length == 12 && !memcmp(m.bytes, "hello world", m.length)); } void createNew() { uint8_t buff[BUFFER_SIZE]; struct Allocator* allocator = BufferAllocator_new(buff, BUFFER_SIZE); struct CryptoAuth* ca = CryptoAuth_new(allocator, privateKey, eventBase, NULL); /*for (int i = 0; i < 32; i++) { printf("%.2x", ca->publicKey[i]); }*/ Assert_always(memcmp(ca->publicKey, publicKey, 32) == 0); }
void testSearch(struct DHTMessage** outMessagePtr, struct RouterModule* routerModule, struct DHTModuleRegistry* registry, struct Allocator* allocator) { *outMessagePtr = NULL; #define REQUEST_HASH "\xfc\x01\x01\x01\x01\x01\x01\x01\x21\x01\x01\x01\x01\x01\x01\x01" struct DHTMessage* callbackMessage = NULL; RouterModule_beginSearch((uint8_t*) REQUEST_HASH, testSearch_callback, &callbackMessage, routerModule); struct DHTMessage* outMessage = *outMessagePtr; assert(outMessage != NULL); // Need to be able to work around the fact that the string contains nulls. #define EXPECTED_OUTPUT(tid) \ "d" \ "1:q" "2:fn" \ "3:tar" "16:" REQUEST_HASH \ "4:txid" "2:" tid \ "e" for (uint32_t i = 0; i < (uint32_t) outMessage->length; i++) { //printf("%.2X", (unsigned int) outMessage->bytes[i] & 0xFF); } //printf("\n%s\n", outMessage->bytes); //printf("\n%s\n", outMessage->peerAddress); assert(outMessage->length == strlen(EXPECTED_OUTPUT("xx"))); assert(memcmp(outMessage->bytes, EXPECTED_OUTPUT("8\x00"), outMessage->length) == 0); //assert(strcmp(outMessage->address->networkAddress, " 00014 ") == 0); // In a normal DHT, 00014 is the closest node, however, 00011 has sent us a message in // testQuery() and thus his reach is 1 and he beats all other nodes which are 0-reach. // Search queries are allowed to select nodes which are further from the target than us. assert(strcmp((char*) &outMessage->address->networkAddress_be, " 00011 ") == 0); #undef EXPECTED_OUTPUT #define CRAFTED_REPLY(tid) \ "d" \ "1:n" "200:" \ "97bkjs8qpd5hc1mubj3qbfyqzmzxp3rg" " 00017 " \ "by1szn122nqk1vncjtm612444rlh6ztr" " 00018 " \ "u42wbyr0wznhkbqr1r7u627dwsvb8853" " 00019 " \ "97bkjs8qpd5hc1mubj3qbfyqzmzxp3rg" " 00020 " \ "2lr8w01hhrxqng8mm8nf3nlwh5nyxzyl" " 00021 " \ "4:txid" "2:" tid \ "e" struct Address address = { .key = "ponmlkjihgzyxwvutsrq \0" }; memcpy(&address.networkAddress_be, " 00011 ", 8); struct DHTMessage message = { .length = strlen(CRAFTED_REPLY("xx")), .allocator = allocator, .address = &address }; memcpy(message.bytes, CRAFTED_REPLY("8\x00"), message.length); // memcpy(message.peerAddress, peerAddress, 18); *outMessagePtr = NULL; DHTModules_handleIncoming(&message, registry); // Make sure the callback was called. assert(callbackMessage != NULL); // Make sure the node was promoted for it's fine service :P struct Address addr; memset(&addr, 0, sizeof(struct Address)); memcpy(&addr.key, "ponmlkjihgzyxwvutsrq \0", 32); struct Node* node1 = NodeStore_getNode(routerModule->nodeStore, &addr); //printf("node reach = %d", node1->reach); assert(node1->reach == 1601894175); /* outMessage = *outMessagePtr; assert(outMessage != NULL); assert(strcmp("000022", outMessage->peerAddress) == 0);*/ } int main() { char buffer[1<<20]; struct Allocator* allocator = BufferAllocator_new(buffer, 1<<20); struct DHTModuleRegistry* registry = DHTModules_new(allocator); ReplyModule_register(registry, allocator); struct RouterModule* routerModule = RouterModule_register(registry, allocator, (uint8_t*) MY_ADDRESS, event_base_new(), NULL); SerializationModule_register(registry, allocator); struct DHTMessage* outMessage; // dummy "network module" which just catches outgoing messages and makes them available. TestFramework_registerOutputCatcher(&outMessage, registry, allocator); struct Address addr; // damn this \0, was a mistake but to fix it would break all of the hashes :( #define ADD_NODE(address, netAddr) \ memset(&addr, 0, sizeof(struct Address)); \ memcpy(&addr.networkAddress_be, netAddr " ", 8); \ memcpy(&addr.key, (uint8_t*) address " \0", 32); \ RouterModule_addNode(&addr, routerModule) // most significant byte --vv ADD_NODE("qponmlkjihgzyxwvutsr", " 00001"); // fce8:573b:d230:ca3b 1c4e:f9d6 0632:9445 ADD_NODE("bcdefghijklmnopqrstu", " 00002"); // fc65:9f4c:c061:84f9 2018:6e31 de3d:3bcf ADD_NODE("onmlkjihgzyxwvutsrqp", " 00003"); // fcbe:26ce:5c7a:9a0f 205b:358c b8f8:08bb // search target --> fc01:0101:0101:0101 2101:0101 0101:0101 ADD_NODE("mlkjihgzyxwvutsrqpon", " 00004"); // fc08:d8e6:e000:c95c 2192:d676 94f9:63a7 ADD_NODE("lkjihgzyxwvutsrqponm", " 00005"); // fc7c:6c8d:e5ee:cf99 2f16:06c7 95ca:0c0b ADD_NODE("fghijklmnopqrstuvwxy", " 00006"); // fcac:3963:cbd1:6390 3e83:be89 a23f:ce66 ADD_NODE("jihgzyxwvutsrqponmlk", " 00007"); // fc2e:3a5e:5e47:9769 4964:8f7f 3894:8c07 ADD_NODE("kjihgzyxwvutsrqponml", " 00008"); // fc37:10aa:39ed:12bf 4a70:1507 dbe9:a054 ADD_NODE("cdefghijklmnopqrstuv", " 00009"); // fcaa:113e:88da:d432 65f0:1c14 38d9:b656 // this node --> fc39:c3ba:c711:00aa 666d:90b0 1ab6:e8c3 ADD_NODE("rqponmlkjihgzyxwvuts", " 00010"); // fc43:41e7:2adc:d13b 78ce:1959 e4cc:c76e ADD_NODE("ponmlkjihgzyxwvutsrq", " 00011"); // fc83:2ab3:b65b:9ad1 7e7b:f61f e0fa:cb40 ADD_NODE("efghijklmnopqrstuvwx", " 00012"); // fc08:0ba6:a8e2:7731 9dae:f9fd e502:767c ADD_NODE("abcdefghijklmnopqrst", " 00013"); // fc81:cab3:eda0:61aa 9fff:bdde 0168:f0dd ADD_NODE("ihgzyxwvutsrqponmlkj", " 00014"); // fc49:8fc7:7e43:981a bac1:0b5d 77fb:8818 ADD_NODE("nmlkjihgzyxwvutsrqpo", " 00015"); // fc69:61a1:2bec:1444 bb9e:47d1 f8b3:a6a0 ADD_NODE("defghijklmnopqrstuvw", " 00016"); // fc40:1d18:89a6:9a7e c8af:20fd 5c9f:8140 ADD_NODE("ghijklmnopqrstuvwxyz", " 00017"); // fc74:0f2e:d77a:e5e7 cf4e:8fe9 7791:98e1 #undef ADD_NODE testQuery(&outMessage, registry, allocator); testSearch(&outMessage, routerModule, registry, allocator); return 0; }
/** * send a message */ static void adminChannelSendData(struct Admin* admin, uint32_t channelNum, const void *data, uint32_t length) { /* if this changes, we need to fragment the messages * into MAX_MESSAGE_SIZE chunks */ Assert_compileTime(MAX_API_REQUEST_SIZE == MAX_MESSAGE_SIZE); Assert_true(length <= MAX_MESSAGE_SIZE); struct Admin_MessageHeader header = { .magic = admin->pipeMagic, .length = length, .channelNum = channelNum }; const uint8_t* buf = (const uint8_t*) data; // TODO: check result, buffer writes write(admin->outFd, &header, Admin_MessageHeader_SIZE); if (length > 0) { write(admin->outFd, buf, length); } } /** * public function to send responses */ void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } Assert_true(txid); uint32_t channelNum; struct Admin_Channel* channel = adminChannelFindByTxid(admin, txid, &channelNum); if (!channel) { // txid too short, invalid channel number, closed channel or not matching serial Log_debug(admin->logger, "Dropped response because channel isn't open anymore."); return; } uint8_t buff[MAX_API_REQUEST_SIZE]; uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); // Bounce back the user-supplied txid. String userTxid = { .bytes = txid->bytes + Admin_TxidPrefix_SIZE, .len = txid->len - Admin_TxidPrefix_SIZE }; if (txid->len > Admin_TxidPrefix_SIZE) { Dict_putString(message, TXID, &userTxid, allocator); } struct Writer* w = ArrayWriter_new(buff, sizeof(buff), allocator); StandardBencSerializer_get()->serializeDictionary(w, message); adminChannelSendData(admin, channelNum, buff, w->bytesWritten(w)); } /** * close a channel (for example if an error happened or we received non-empty * messages on a invalid channel number) * also used to cleanup if we receive a close message */ static void adminChannelClose(struct Admin* admin, uint32_t channelNum) { struct Admin_Channel* channel = adminChannelFindById(admin, channelNum); if (channel) { switch (channel->state) { case Admin_ChannelState_OPEN: break; case Admin_ChannelState_CLOSED: case Admin_ChannelState_WAIT_FOR_CLOSE: return; // already sent close, nothing to do } channel->state = Admin_ChannelState_WAIT_FOR_CLOSE; // clean up bufers channel->bufferLen = 0; channel->buffer = NULL; if (channel->allocator) { channel->allocator->free(channel->allocator); channel->allocator = NULL; } } adminChannelSendData(admin, channelNum, NULL, 0); } /** * handle a received channel close (the received header is in admin->messageHeader) * as invalid channels are never OPEN we never have to ACK a close on them */ static void adminChannelHandleClose(struct Admin* admin) { uint32_t channelNum = admin->messageHeader.channelNum; struct Admin_Channel* channel = adminChannelFindById(admin, channelNum); if (channel) { switch (channel->state) { case Admin_ChannelState_OPEN: // close active channel adminChannelClose(admin, channelNum); // now the state is WAIT_FOR_CLOSE, set it to CLOSED channel->state = Admin_ChannelState_CLOSED; break; case Admin_ChannelState_WAIT_FOR_CLOSE: channel->state = Admin_ChannelState_CLOSED; channel->serial++; break; case Admin_ChannelState_CLOSED: // nothing to do break; } } } static inline bool authValid(Dict* message, uint8_t* buffer, uint32_t length, struct Admin* admin) { String* cookieStr = Dict_getString(message, String_CONST("cookie")); uint32_t cookie = (cookieStr != NULL) ? strtoll(cookieStr->bytes, NULL, 10) : 0; if (!cookie) { int64_t* cookieInt = Dict_getInt(message, String_CONST("cookie")); cookie = (cookieInt) ? *cookieInt : 0; } uint64_t nowSecs = Time_currentTimeSeconds(admin->eventBase); String* submittedHash = Dict_getString(message, String_CONST("hash")); if (cookie > nowSecs || cookie < nowSecs - 20 || !submittedHash || submittedHash->len != 64) { return false; } uint8_t* hashPtr = (uint8_t*) strstr((char*) buffer, submittedHash->bytes); if (!hashPtr || !admin->password) { return false; } uint8_t passAndCookie[64]; snprintf((char*) passAndCookie, 64, "%s%u", admin->password->bytes, cookie); uint8_t hash[32]; crypto_hash_sha256(hash, passAndCookie, strlen((char*) passAndCookie)); Hex_encode(hashPtr, 64, hash, 32); crypto_hash_sha256(hash, buffer, length); Hex_encode(hashPtr, 64, hash, 32); return memcmp(hashPtr, submittedHash->bytes, 64) == 0; }
void Admin_sendMessage(Dict* message, String* txid, struct Admin* admin) { if (!admin) { return; } Assert_true(txid); uint8_t buff[MAX_API_REQUEST_SIZE + TXID_LEN]; // Write the inter-process txid. Bits_memcpyConst(buff, txid->bytes, TXID_LEN); uint8_t allocBuff[256]; struct Allocator* allocator = BufferAllocator_new(allocBuff, 256); // Bounce back the user-supplied txid. String userTxid = { .bytes = txid->bytes + TXID_LEN, .len = txid->len - TXID_LEN }; if (txid->len > TXID_LEN) { Dict_putString(message, TXID, &userTxid, allocator); } struct Writer* w = ArrayWriter_new(buff + TXID_LEN, MAX_API_REQUEST_SIZE, allocator); StandardBencSerializer_get()->serializeDictionary(w, message); write(admin->outFd, buff, w->bytesWritten(w) + TXID_LEN); } struct Admin* Admin_new(struct sockaddr_storage* addr, int addrLen, String* password, char* user, struct event_base* eventBase, struct ExceptionHandler* eh, struct Log* logger, struct Allocator* allocator) { errno = 0; int pipes[2][2]; if (pipe(pipes[0]) || pipe(pipes[1])) { eh->exception(__FILE__ " Failed to create pipes.", errno, eh); } int pgid = getpid(); int pid = fork(); if (pid < 0) { eh->exception(__FILE__ " Failed to fork()", errno, eh); } bool isChild = (pid == 0); int inFd = pipes[isChild][0]; close(pipes[!isChild][0]); int outFd = pipes[!isChild][1]; close(pipes[isChild][1]); if (isChild) { // Set the process group so that children will not // become orphaned if the parent gets signal 11 err um 9. setpgid(0, pgid); if (user) { Security_setUser(user, NULL, AbortHandler_INSTANCE); } struct ChildContext context; memset(&context, 0, sizeof(struct ChildContext)); context.inFd = inFd; context.outFd = outFd; context.allocator = allocator; event_reinit(eventBase); context.eventBase = eventBase; child(addr, addrLen, user, &context); fprintf(stderr, "Admin process exiting."); exit(0); } setpgid(pid, pgid); struct Admin* admin = allocator->calloc(sizeof(struct Admin), 1, allocator); admin->inFd = inFd; admin->outFd = outFd; admin->allocator = allocator; admin->logger = logger; admin->functionCount = 0; admin->eventBase = eventBase; admin->password = password; Bits_memcpyConst(&admin->address, addr, sizeof(struct sockaddr_storage)); admin->addressLength = addrLen; admin->pipeEv = event_new(eventBase, inFd, EV_READ | EV_PERSIST, inFromChild, admin); event_add(admin->pipeEv, NULL); event_base_dispatch(eventBase); return admin; }