Example #1
0
static void splice()
{
    // 000000100
    uint64_t goHere = 1<<2;

    // 000000100
    uint64_t viaHere = 1<<2;

    // 000010000
    uint64_t expected = 1<<4;

    uint64_t out = LabelSplicer_splice(goHere, viaHere);

    printf("Splicing %" PRIu64 " with %" PRIu64 " yields %" PRIu64 ", expecting %" PRIu64 "\n",
           goHere, viaHere, out, expected);

    Assert_always(expected == out);
}
Example #2
0
/**
 * For serializing and parsing responses to getPeers and search requests.
 */
struct Address_List* ReplySerializer_parse(struct Address* fromNode,
                                           Dict* result,
                                           struct Log* log,
                                           bool splicePath,
                                           struct Allocator* alloc)
{
    String* nodes = Dict_getString(result, CJDHTConstants_NODES);

    if (!nodes) { return NULL; }

    if (nodes->len == 0 || nodes->len % Address_SERIALIZED_SIZE != 0) {
        Log_debug(log, "Dropping unrecognized reply");
        return NULL;
    }

    struct VersionList* versions = NULL;
    String* versionsStr = Dict_getString(result, CJDHTConstants_NODE_PROTOCOLS);
    if (versionsStr) {
        versions = VersionList_parse(versionsStr, alloc);
    }
    if (!versions || versions->length != (nodes->len / Address_SERIALIZED_SIZE)) {
        Log_debug(log, "Reply with missing or invalid versions");
        return NULL;
    }

    struct Address_List* out = Address_List_new(versions->length, alloc);

    uint32_t j = 0;
    for (uint32_t i = 0; nodes && i < nodes->len; i += Address_SERIALIZED_SIZE) {

        struct Address addr = { .path = 0 };
        Address_parse(&addr, (uint8_t*) &nodes->bytes[i]);
        addr.protocolVersion = versions->versions[i / Address_SERIALIZED_SIZE];

        // calculate the ipv6
        Address_getPrefix(&addr);

        if (splicePath) {
            // We need to splice the given address on to the end of the
            // address of the node which gave it to us.
            uint64_t path = LabelSplicer_splice(addr.path, fromNode->path);

            if (path == UINT64_MAX) {
                /* common, lots of noise
                uint8_t discovered[60];
                uint8_t fromAddr[60];
                Address_print(discovered, &addr);
                Address_print(fromAddr, fromNode);
                Log_debug(log,
                          "Dropping response [%s] from [%s] because route could not be spliced",
                          discovered, fromAddr);*/
                continue;
            }

            addr.path = path;
        }

        /*#ifdef Log_DEBUG
            uint8_t printedAddr[60];
            Address_print(printedAddr, &addr);
            Log_debug(log, "discovered node [%s]", printedAddr);
        #endif*/

        Address_getPrefix(&addr);
        if (!AddressCalc_validAddress(addr.ip6.bytes)) {
            struct Allocator* tmpAlloc = Allocator_child(alloc);
            String* printed = Address_toString(&addr, tmpAlloc);
            uint8_t ipPrinted[40];
            Address_printIp(ipPrinted, &addr);
            Log_debug(log, "Was told garbage addr [%s] [%s]", printed->bytes, ipPrinted);
            Allocator_free(tmpAlloc);
            // This should never happen, badnode.
            continue;
        }

        Bits_memcpy(&out->elems[j++], &addr, sizeof(struct Address));
    }
    out->length = j;
    return out;
}

void ReplySerializer_serialize(struct Address_List* addrs,
                               Dict* out,
                               struct Address* convertDirectorFor,
                               struct Allocator* alloc)
{
    if (!addrs->length) { return; }
    String* nodes = String_newBinary(NULL, addrs->length * Address_SERIALIZED_SIZE, alloc);
    struct VersionList* versions = VersionList_new(addrs->length, alloc);
    for (int i = 0; i < addrs->length; i++) {
        versions->versions[i] = addrs->elems[i].protocolVersion;
        if (!convertDirectorFor) {
            Address_serialize(&nodes->bytes[i * Address_SERIALIZED_SIZE], &addrs->elems[i]);
        } else {
            struct Address addr;
            Bits_memcpy(&addr, &addrs->elems[i], sizeof(struct Address));
            addr.path = NumberCompress_getLabelFor(addr.path, convertDirectorFor->path);
            Address_serialize(&nodes->bytes[i * Address_SERIALIZED_SIZE], &addr);
        }
    }
    Dict_putStringC(out, "n", nodes, alloc);
    Dict_putStringC(out, "np", VersionList_stringify(versions, alloc), alloc);
}
Example #3
0
static void responseCallback(struct RouterModule_Promise* promise,
                             uint32_t lagMilliseconds,
                             struct Node* fromNode,
                             Dict* result)
{
    struct RouteTracer_Trace* trace = Identity_cast((struct RouteTracer_Trace*)promise->userData);
    struct RouteTracer_pvt* ctx = Identity_cast((struct RouteTracer_pvt*)trace->tracer);
    if (!fromNode) {
        // trace has stalled.
        log(ctx->logger, trace, "STALLED request timed out");
        noPeers(trace);
        return;
    }

    if (trace->pub.callback) {
        trace->pub.callback(&trace->pub, lagMilliseconds, fromNode, result);
    }

    String* nodes = Dict_getString(result, CJDHTConstants_NODES);

    if (nodes && (nodes->len == 0 || nodes->len % Address_SERIALIZED_SIZE != 0)) {
        log(ctx->logger, trace, "STALLED dropping unrecognized reply");
        noPeers(trace);
        return;
    }

    struct VersionList* versions = NULL;
    String* versionsStr = Dict_getString(result, CJDHTConstants_NODE_PROTOCOLS);
    if (versionsStr) {
        versions = VersionList_parse(versionsStr, promise->alloc);
        #ifdef Version_1_COMPAT
            // Version 1 lies about the versions of other nodes, assume they're all v1.
            if (fromNode->version < 2) {
                for (int i = 0; i < (int)versions->length; i++) {
                    versions->versions[i] = 1;
                }
            }
        #endif
    }

    struct Node* next = NULL;

    for (uint32_t i = 0; nodes && i < nodes->len; i += Address_SERIALIZED_SIZE) {

        struct Address addr;
        Address_parse(&addr, (uint8_t*) &nodes->bytes[i]);

        // calculate the ipv6
        Address_getPrefix(&addr);

        // We need to splice the given address on to the end of the
        // address of the node which gave it to us.
        addr.path = LabelSplicer_splice(addr.path, fromNode->address.path);

        if (addr.path == UINT64_MAX) {
            log(ctx->logger, trace, "dropping node because route could not be spliced");
            continue;
        }

        /*#ifdef Log_DEBUG
            uint8_t printedAddr[60];
            Address_print(printedAddr, &addr);
            Log_debug(ctx->logger, "discovered node [%s]", printedAddr);
        #endif*/

        if (!Bits_memcmp(ctx->myAddress, addr.ip6.bytes, 16)) {
            // Any path which loops back through us is necessarily a dead route.
            uint8_t printedAddr[60];
            Address_print(printedAddr, &addr);
            Log_debug(ctx->logger, "Loop route [%s]", printedAddr);
            NodeStore_brokenPath(addr.path, ctx->nodeStore);
            continue;
        }

        if (!AddressCalc_validAddress(addr.ip6.bytes)) {
            log(ctx->logger, trace, "was told garbage");
            // This should never happen, badnode.
            break;
        }

        // Nodes we are told about are inserted with 0 reach and assumed version 1.
        uint32_t version = (versions) ? versions->versions[i / Address_SERIALIZED_SIZE] : 1;
        struct Node* n = NodeStore_addNode(ctx->nodeStore, &addr, 0, version);

        if (!n) {
            // incompatible version, introduced to ourselves...
        } else if (!LabelSplicer_routesThrough(trace->target, n->address.path)) {
            // not on the way
        } else  if (n->address.path <= fromNode->address.path) {
            // losing ground
        } else if (next && n->address.path >= next->address.path) {
            // not better than the one we have
        } else {
            next = n;
        }
    }

    if (fromNode->address.path == trace->target) {
        log(ctx->logger, trace, "Trace completed successfully");
        noPeers(trace);
        return;
    }

    if (!nodes) {
        log(ctx->logger, trace, "No nodes in trace response");
    }

    if (!next) {
        log(ctx->logger, trace, "STALLED no suitable peers in reply");
        noPeers(trace);
        return;
    }

    if (!LabelSplicer_routesThrough(trace->target, next->address.path)) {
        log(ctx->logger, trace, "STALLED Nodestore broke the path of the best option");
        noPeers(trace);
        return;
    }

    traceStep(trace, next);
}