Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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);
}
Exemplo n.º 3
0
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();
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}
Exemplo n.º 8
0
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);
}
Exemplo n.º 10
0
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);
}
Exemplo n.º 11
0
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);
}
Exemplo n.º 12
0
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;
}
Exemplo n.º 13
0
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;
}
Exemplo n.º 14
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));
}
Exemplo n.º 15
0
Arquivo: Admin.c Projeto: Ralith/cjdns
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);
}
Exemplo n.º 16
0
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);
}
Exemplo n.º 18
0
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;
}
Exemplo n.º 19
0
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);
}
Exemplo n.º 20
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;
}
Exemplo n.º 21
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;
}
Exemplo n.º 22
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;
}