static void routesThrough() { // 0000000000000000100100000000101011101010100101011100101001010101 uint64_t dest = 0x0000900aea95ca55llu; // 0000000000000000000000010110010100100110001110011100011001010101 uint64_t mid = 0x000001652639c655llu; Assert_always(!LabelSplicer_routesThrough(dest, mid)); }
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); }
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); }