static int indexOf(struct AddrSet_pvt* ap, struct Address* addr) { for (int i = 0; i < ap->addrList->length; i++) { struct Elem* el = ArrayList_OfAddrs_get(ap->addrList, i); // We will just match on the same IP, even if the path is not the same if (Address_isSameIp(addr, &el->addr)) { return i; } } return -1; }
static void onReplyTimeout(struct MsgCore_Promise* prom) { struct Query* q = (struct Query*) prom->userData; struct ReachabilityCollector_pvt* rcp = Identity_check((struct ReachabilityCollector_pvt*) q->rcp); struct PeerInfo_pvt* pi = NULL; for (int j = 0; j < rcp->piList->length; j++) { pi = ArrayList_OfPeerInfo_pvt_get(rcp->piList, j); if (Address_isSameIp(&pi->pub.addr, prom->target)) { pi->waitForResponse = false; return; } } }
static void change0(struct ReachabilityCollector_pvt* rcp, struct Address* nodeAddr, struct Allocator* tempAlloc) { for (int i = 0; i < rcp->piList->length; i++) { struct PeerInfo_pvt* pi = ArrayList_OfPeerInfo_pvt_get(rcp->piList, i); if (Address_isSameIp(nodeAddr, &pi->pub.addr)) { if (nodeAddr->path == 0) { Log_debug(rcp->log, "Peer [%s] dropped", Address_toString(&pi->pub.addr, tempAlloc)->bytes); ArrayList_OfPeerInfo_pvt_remove(rcp->piList, i); Allocator_free(pi->alloc); } else if (nodeAddr->path != pi->pub.addr.path) { Log_debug(rcp->log, "Peer [%s] changed path", Address_toString(&pi->pub.addr, tempAlloc)->bytes); pi->pub.pathThemToUs = -1; pi->pathToCheck = 1; pi->pub.querying = true; pi->pub.addr.path = nodeAddr->path; } if (rcp->pub.onChange) { rcp->pub.onChange(&rcp->pub, nodeAddr->ip6.bytes, 0, 0, 0, 0xffff, 0xffff, 0xffff); } return; } } if (nodeAddr->path == 0) { Log_debug(rcp->log, "Nonexistant peer [%s] dropped", Address_toString(nodeAddr, tempAlloc)->bytes); return; } struct Allocator* piAlloc = Allocator_child(rcp->alloc); struct PeerInfo_pvt* pi = Allocator_calloc(piAlloc, sizeof(struct PeerInfo_pvt), 1); Identity_set(pi); Bits_memcpy(&pi->pub.addr, nodeAddr, Address_SIZE); pi->alloc = piAlloc; pi->pub.querying = true; pi->pathToCheck = 1; pi->pub.pathThemToUs = -1; pi->waitForResponse = false; ArrayList_OfPeerInfo_pvt_add(rcp->piList, pi); Log_debug(rcp->log, "Peer [%s] added", Address_toString(&pi->pub.addr, tempAlloc)->bytes); mkNextRequest(rcp); }
static void onReply(Dict* msg, struct Address* src, struct MsgCore_Promise* prom) { struct ReachabilityCollector_pvt* rcp = Identity_check((struct ReachabilityCollector_pvt*) prom->userData); Assert_true(prom == rcp->msgOnWire); if (!src) { onReplyTimeout(prom); mkNextRequest(rcp); return; } struct Address_List* results = ReplySerializer_parse(src, msg, rcp->log, false, prom->alloc); uint64_t path = 1; struct PeerInfo* pi = NULL; for (int j = 0; j < rcp->piList->length; j++) { struct PeerInfo* pi0 = ArrayList_OfPeerInfo_get(rcp->piList, j); if (Address_isSameIp(&pi0->addr, src)) { pi = pi0; break; } } if (!pi) { Log_debug(rcp->log, "Got message from peer which is gone from list"); return; } for (int i = 0; i < results->length; i++) { path = results->elems[i].path; if (Bits_memcmp(results->elems[i].ip6.bytes, rcp->myAddr->ip6.bytes, 16)) { continue; } if (pi->pathThemToUs != path) { Log_debug(rcp->log, "Found back-route for [%s]", Address_toString(src, prom->alloc)->bytes); if (rcp->pub.onChange) { rcp->pub.onChange( &rcp->pub, src->ip6.bytes, path, src->path, 0, 0xffff, 0xffff, 0xffff); } } pi->pathThemToUs = path; pi->querying = false; return; } pi->pathToCheck = (results->length < 8) ? 1 : path; mkNextRequest(rcp); }
// adding a peer should be non-null Assert_true( NodeStore_addNode(store, randomIp((int[]){2,1}/*0x15*/), 1, Version_CURRENT_PROTOCOL) ); // adding a node behind our peer should also be non-null Assert_true( NodeStore_addNode(store, randomIp((int[]){2,2,1}/*0x155*/), 1, Version_CURRENT_PROTOCOL) ); // test at capacity and verify worst path is replaced NodeStore_addNode(store, randomIp((int[]){3,2,1}/*0x157*/), 1, Version_CURRENT_PROTOCOL); struct Node* node = NodeStore_addNode(store, randomIp((int[]){0,1}/*0x13*/), 1, Version_CURRENT_PROTOCOL); Assert_true( Address_isSameIp(&node->address, &NodeStore_dumpTable(store,1)->address) ); } static void test_getNodesByAddr() { struct Address* myAddr = randomAddress(); struct NodeStore* store = setUp(myAddr, 8); struct Address* otherAddr = randomIp((int[]){0,1}/*0x13*/); // make sure we can add an addr and get it back NodeStore_addNode(store, otherAddr, 1, Version_CURRENT_PROTOCOL); struct NodeList* list = NodeStore_getNodesByAddr(otherAddr, 1, alloc, store); Assert_true(list->size == 1); Assert_true(Address_isSameIp(&list->nodes[0]->address, otherAddr)); // try for two
static void pingCycle(void* vsn) { struct SupernodeHunter_pvt* snp = Identity_check((struct SupernodeHunter_pvt*) vsn); if (snp->pub.snodeIsReachable) { return; } if (!snp->authorizedSnodes->length) { return; } if (!snp->peers->length) { return; } Log_debug(snp->log, "\n\nping cycle\n\n"); // We're not handling replies... struct MsgCore_Promise* qp = MsgCore_createQuery(snp->msgCore, 0, snp->alloc); struct Query* q = Allocator_calloc(qp->alloc, sizeof(struct Query), 1); Identity_set(q); q->snp = snp; q->sendTime = Time_currentTimeMilliseconds(snp->base); Dict* msg = qp->msg = Dict_new(qp->alloc); qp->cb = onReply; qp->userData = q; bool isGetPeers = snp->nodeListIndex & 1; int idx = snp->nodeListIndex++ >> 1; for (;;) { if (idx < snp->peers->length) { qp->target = AddrSet_get(snp->peers, idx); break; } idx -= snp->peers->length; if (idx < snp->nodes->length) { qp->target = AddrSet_get(snp->nodes, idx); break; } snp->snodeAddrIdx++; idx -= snp->nodes->length; } struct Address* snode = AddrSet_get(snp->authorizedSnodes, snp->snodeAddrIdx % snp->authorizedSnodes->length); if (Address_isSameIp(snode, qp->target)) { // Supernode is a peer... AddrSet_add(snp->snodeCandidates, qp->target); } if (snp->snodeCandidates->length) { qp->target = AddrSet_get(snp->snodeCandidates, snp->snodeCandidates->length - 1); Log_debug(snp->log, "Sending getRoute to snode %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "sq", "gr", qp->alloc); Dict_putStringC(msg, "src", snp->selfAddrStr, qp->alloc); String* target = String_newBinary(qp->target->ip6.bytes, 16, qp->alloc); Dict_putStringC(msg, "tar", target, qp->alloc); q->isGetRoute = true; return; } if (isGetPeers) { Log_debug(snp->log, "Sending getPeers to %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "q", "gp", qp->alloc); Dict_putStringC(msg, "tar", String_newBinary("\0\0\0\0\0\0\0\1", 8, qp->alloc), qp->alloc); } else { q->searchTar = Address_clone(snode, qp->alloc); Log_debug(snp->log, "Sending findNode to %s", Address_toString(qp->target, qp->alloc)->bytes); Dict_putStringCC(msg, "q", "fn", qp->alloc); Dict_putStringC(msg, "tar", String_newBinary(snode->ip6.bytes, 16, qp->alloc), qp->alloc); } }
static void onReply(Dict* msg, struct Address* src, struct MsgCore_Promise* prom) { struct Query* q = Identity_check((struct Query*) prom->userData); struct SupernodeHunter_pvt* snp = Identity_check(q->snp); // TODO(cjd): if we sent a message to a discovered node, we should drop them from the list // if we sent to one of snodeCandidates then we need to drop it from that list. if (!src) { String* addrStr = Address_toString(prom->target, prom->alloc); Log_debug(snp->log, "timeout sending to %s", addrStr->bytes); return; } String* addrStr = Address_toString(src, prom->alloc); Log_debug(snp->log, "Reply from %s", addrStr->bytes); int64_t* snodeRecvTime = Dict_getIntC(msg, "recvTime"); if (q->isGetRoute) { //struct Address_List* al = ReplySerializer_parse(src, msg, snp->log, false, prom->alloc); if (!snodeRecvTime) { Log_warn(snp->log, "getRoute reply with no timeStamp, bad snode"); return; } Log_debug(snp->log, "\n\nSupernode location confirmed [%s]\n\n", Address_toString(src, prom->alloc)->bytes); Bits_memcpy(&snp->pub.snodeAddr, src, Address_SIZE); if (snp->pub.snodeIsReachable) { // If while we were searching, the outside code declared that indeed the snode // is reachable, we will not try to change their snode. } else if (snp->pub.onSnodeChange) { snp->pub.snodeIsReachable = true; snp->pub.onSnodeChange( snp->pub.userData, &snp->pub.snodeAddr, q->sendTime, *snodeRecvTime); } else { Log_warn(snp->log, "onSnodeChange is not set"); } } struct Address_List* results = ReplySerializer_parse(src, msg, snp->log, true, prom->alloc); if (!results) { Log_debug(snp->log, "reply without nodes"); return; } for (int i = 0; i < results->length; i++) { if (!q->searchTar) { // This is a getPeers Log_debug(snp->log, "getPeers reply [%s]", Address_toString(&results->elems[i], prom->alloc)->bytes); if (Address_isSameIp(&results->elems[i], snp->myAddress)) { continue; } if (snp->nodes->length >= SupernodeHunter_pvt_nodes_MAX) { AddrSet_flush(snp->nodes); } AddrSet_add(snp->nodes, &results->elems[i]); } else { if (!Bits_memcmp(&results->elems[i].ip6.bytes, q->searchTar->ip6.bytes, 16)) { Log_debug(snp->log, "\n\nFound a supernode w000t [%s]\n\n", Address_toString(&results->elems[i], prom->alloc)->bytes); if (snp->snodeCandidates->length >= SupernodeHunter_pvt_snodeCandidates_MAX) { AddrSet_flush(snp->snodeCandidates); } AddrSet_add(snp->snodeCandidates, &results->elems[i]); } else { //Log_debug(snp->log, "findNode reply [%s] to discard", // Address_toString(&results->elems[i], prom->alloc)->bytes); } } } }
static void onReply(Dict* msg, struct Address* src, struct MsgCore_Promise* prom) { struct Query* q = (struct Query*) prom->userData; struct ReachabilityCollector_pvt* rcp = Identity_check((struct ReachabilityCollector_pvt*) q->rcp); if (!src) { onReplyTimeout(prom); mkNextRequest(rcp); return; } struct PeerInfo_pvt* pi = NULL; for (int j = 0; j < rcp->piList->length; j++) { struct PeerInfo_pvt* pi0 = ArrayList_OfPeerInfo_pvt_get(rcp->piList, j); if (Address_isSameIp(&pi0->pub.addr, src)) { pi = pi0; break; } } if (!pi) { Log_debug(rcp->log, "Got message from peer which is gone from list"); return; } pi->waitForResponse = false; struct Address_List* results = ReplySerializer_parse(src, msg, rcp->log, false, prom->alloc); uint64_t path = 1; if (!results) { Log_debug(rcp->log, "Got invalid getPeers reply from [%s]", Address_toString(src, prom->alloc)->bytes); return; } for (int i = results->length - 1; i >= 0; i--) { path = results->elems[i].path; Log_debug(rcp->log, "getPeers result [%s] [%s][%s]", Address_toString(&results->elems[i], prom->alloc)->bytes, q->addr->bytes, q->targetPath); if (Bits_memcmp(results->elems[i].ip6.bytes, rcp->myAddr->ip6.bytes, 16)) { continue; } if (pi->pub.pathThemToUs != path) { Log_debug(rcp->log, "Found back-route for [%s]", Address_toString(src, prom->alloc)->bytes); pi->pub.pathThemToUs = path; if (rcp->pub.onChange) { rcp->pub.onChange( &rcp->pub, src->ip6.bytes, path, src->path, 0, 0xffff, 0xffff, 0xffff); } } pi->pub.querying = false; mkNextRequest(rcp); return; } if (results->length < 8) { // Peer's gp response does not include my addr, meaning the peer might not know us yet. // should wait peer sendPing (see InterfaceControl.c). pi->pathToCheck = 1; return; } else { pi->pathToCheck = path; } mkNextRequest(rcp); }
void NodeStore_addNode(struct NodeStore* store, struct Address* addr, const int64_t reachDifference) { Address_getPrefix(addr); if (memcmp(addr->ip6.bytes, store->thisNodeAddress, 16) == 0) { printf("got introduced to ourselves\n"); return; } if (addr->ip6.bytes[0] != 0xfc) { uint8_t address[60]; Address_print(address, addr); Log_critical1(store->logger, "tried to insert address %s which does not begin with 0xFC.\n", address); assert(false); } // TODO: maintain a sorted list. uint32_t pfx = Address_getPrefix(addr); if (store->size < store->capacity) { for (uint32_t i = 0; i < store->size; i++) { if (store->headers[i].addressPrefix == pfx && Address_isSameIp(&store->nodes[i].address, addr)) { int red = Address_checkRedundantRoute(&store->nodes[i].address, addr); if (red == 1) { #ifdef Log_DEBUG uint8_t nodeAddr[60]; Address_print(nodeAddr, &store->nodes[i].address); uint8_t newAddr[20]; Address_printNetworkAddress(newAddr, addr); Log_debug2(store->logger, "Found a better route to %s via %s\n", nodeAddr, newAddr); struct Node* n = NodeStore_getNodeByNetworkAddr(addr->networkAddress_be, store); if (n) { Log_warn(store->logger, "This route is probably invalid, giving up.\n"); continue; } #endif store->nodes[i].address.networkAddress_be = addr->networkAddress_be; } else if (red == 0 && store->nodes[i].address.networkAddress_be != addr->networkAddress_be) { // Completely different routes, store seperately. continue; } /*#ifdef Log_DEBUG uint32_t oldReach = store->headers[i].reach; #endif*/ adjustReach(&store->headers[i], reachDifference); /*#ifdef Log_DEBUG if (oldReach != store->headers[i].reach) { uint8_t nodeAddr[60]; Address_print(nodeAddr, addr); Log_debug3(store->logger, "Altering reach for node %s, old reach %u, new reach %u.\n", nodeAddr, oldReach, store->headers[i].reach); if (oldReach > store->headers[i].reach) { Log_debug(store->logger, "Reach was decreased!\n"); } } #endif*/ return; } #ifdef Log_DEBUG else if (store->headers[i].addressPrefix == pfx) { uint8_t realAddr[16]; AddressCalc_addressForPublicKey(realAddr, addr->key); assert(!memcmp(realAddr, addr->ip6.bytes, 16)); } #endif } #ifdef Log_DEBUG uint8_t nodeAddr[60]; Address_print(nodeAddr, addr); Log_debug2(store->logger, "Discovered node: %s reach %u\n", nodeAddr, reachDifference); #endif // Free space, regular insert. replaceNode(&store->nodes[store->size], &store->headers[store->size], addr); adjustReach(&store->headers[store->size], reachDifference); store->size++; return; } // The node whose reach OR distance is the least. // This means nodes who are close and have short reach will be removed uint32_t indexOfNodeToReplace = 0; uint32_t leastReachOrDistance = UINT32_MAX; for (uint32_t i = 0; i < store->size; i++) { uint32_t distance = store->headers[i].addressPrefix ^ pfx; if (distance == 0 && Address_isSame(&store->nodes[i].address, addr)) { // Node already exists adjustReach(&store->headers[store->size], reachDifference); return; } uint32_t reachOrDistance = store->headers[i].reach | distance; if (reachOrDistance < leastReachOrDistance) { leastReachOrDistance = reachOrDistance; indexOfNodeToReplace = i; } } replaceNode(&store->nodes[indexOfNodeToReplace], &store->headers[indexOfNodeToReplace], addr); adjustReach(&store->headers[indexOfNodeToReplace], reachDifference); }