Ejemplo n.º 1
0
static void routesThrough()
{
    // 0000000000000000100100000000101011101010100101011100101001010101
    uint64_t dest = 0x0000900aea95ca55llu;
    // 0000000000000000000000010110010100100110001110011100011001010101
    uint64_t mid =  0x000001652639c655llu;
    Assert_always(!LabelSplicer_routesThrough(dest, mid));
}
Ejemplo n.º 2
0
static void traceStep(struct RouteTracer_Trace* trace, struct Node* next)
{
    struct RouteTracer_pvt* ctx = Identity_cast((struct RouteTracer_pvt*)trace->tracer);

    if (!next) {
        // can't find a next node, stalled.
        Timeout_setTimeout(noPeers, trace, 0, trace->tracer->eventBase, trace->pub.alloc);
        return;
    }

    Assert_true(LabelSplicer_routesThrough(trace->target, next->address.path));

    trace->lastNodeAsked = next->address.path;

    struct RouterModule_Promise* rp =
        RouterModule_newMessage(next, 0, ctx->router, trace->pub.alloc);

    Dict* message = Dict_new(rp->alloc);

    #ifdef Version_4_COMPAT
        if (next->version < 5) {
            // The node doesn't support the new API so try running a search for
            // the bitwise complement of their address to get some peers.
            Dict_putString(message, CJDHTConstants_QUERY, CJDHTConstants_QUERY_FN, rp->alloc);
            String* notAddr = String_newBinary((char*)next->address.ip6.bytes, 16, rp->alloc);
            for (int i = 0; i < 16; i++) {
                notAddr->bytes[i] ^= 0xff;
            }
            Dict_putString(message, CJDHTConstants_TARGET, notAddr, rp->alloc);
            log(ctx->logger, trace, "Sending legacy search method because getpeers is unavailable");
        } else {
    #endif

    Dict_putString(message, CJDHTConstants_QUERY, CJDHTConstants_QUERY_GP, rp->alloc);
    uint64_t labelForThem = LabelSplicer_unsplice(trace->target, next->address.path);
    labelForThem = Endian_hostToBigEndian64(labelForThem);
    String* target = String_newBinary((char*)&labelForThem, 8, rp->alloc);
    Dict_putString(message, CJDHTConstants_TARGET, target, rp->alloc);
    log(ctx->logger, trace, "Sending getpeers request");

    #ifdef Version_4_COMPAT
        }
    #endif

    rp->userData = trace;
    rp->callback = responseCallback;

    RouterModule_sendMessage(rp, message);
}
Ejemplo n.º 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);
}