static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext) { if (SwitchPinger_Result_OK != resp->res) { return; } struct InterfaceController_Peer* ep = Identity_check((struct InterfaceController_Peer*) onResponseContext); struct InterfaceController_pvt* ic = ifcontrollerForPeer(ep); struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpyConst(addr.key, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); addr.path = ep->switchLabel; addr.protocolVersion = resp->version; #ifdef Log_DEBUG uint8_t addrStr[60]; Address_print(addrStr, &addr); uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version [%d]", key, resp->version); } else { Log_debug(ic->logger, "got switch pong from node [%s] with version [%d]", key, resp->version); } if (!ep->timeOfLastPing) { // We've never heard from this machine before (or we've since forgotten about it) // This is here because we want the tests to function without the janitor present. // Other than that, it just makes a slightly more synchronous/guaranteed setup. Router_sendGetPeers(ic->router, &addr, 0, 0, ic->allocator); } struct Node_Link* link = Router_linkForPath(ic->router, resp->label); if (!link || !Node_getBestParent(link->child)) { RumorMill_addNode(ic->rumorMill, &addr); } else { Log_debug(ic->logger, "link exists"); } ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase); #ifdef Log_DEBUG // This will be false if it times out. //Assert_true(label == ep->switchLabel); uint8_t path[20]; AddrTools_printPath(path, resp->label); uint8_t sl[20]; AddrTools_printPath(sl, ep->switchLabel); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s] [%s]", SwitchPinger_resultString(resp->res)->bytes, path, sl); #endif }
static Iface_DEFUN peer(struct Message* msg, struct Pathfinder_pvt* pf) { struct Address addr; addressForNode(&addr, msg); String* str = Address_toString(&addr, msg->alloc); Log_debug(pf->log, "Peer [%s]", str->bytes); struct Node_Link* link = NodeStore_linkForPath(pf->nodeStore, addr.path); // It exists, it's parent is the self-node, and it's label is equal to the switchLabel. if (link && Node_getBestParent(link->child) && Node_getBestParent(link->child)->parent->address.path == 1 && Node_getBestParent(link->child)->cannonicalLabel == addr.path) { return NULL; } //RumorMill_addNode(pf->rumorMill, &addr); Router_sendGetPeers(pf->router, &addr, 0, 0, pf->alloc); return sendNode(msg, &addr, 0xffffff00, pf); }
/** * Check the table for nodes which might need to be pinged, ping a node if necessary. * If a node has not responded in unresponsiveAfterMilliseconds then mark them as unresponsive * and if the connection is incoming and the node has not responded in forgetAfterMilliseconds * then drop them entirely. * This is called every PING_INTERVAL_MILLISECONDS but pingCallback is a misleading name. */ static void pingCallback(void* vic) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) vic); if (!ic->peerMap.count) { return; } uint64_t now = Time_currentTimeMilliseconds(ic->eventBase); // scan for endpoints have not sent anything recently. uint32_t startAt = Random_uint32(ic->rand) % ic->peerMap.count; for (uint32_t i = startAt, count = 0; (!count || i != startAt) && count <= ic->peerMap.count;) { i = (i + 1) % ic->peerMap.count; count++; struct InterfaceController_Peer* ep = ic->peerMap.values[i]; if (now < ep->timeOfLastMessage + ic->pingAfterMilliseconds) { if (now < ep->timeOfLastPing + ic->pingAfterMilliseconds) { // Possibly an out-of-date node which is mangling packets, don't ping too often // because it causes the RumorMill to be filled with this node over and over. continue; } struct Node_Link* link = Router_linkForPath(ic->router, ep->switchLabel); // It exists, it's parent is the self-node, and it's label is equal to the switchLabel. if (link && Node_getBestParent(link->child) && Node_getBestParent(link->child)->parent->address.path == 1 && Node_getBestParent(link->child)->cannonicalLabel == ep->switchLabel) { continue; } } #ifdef Log_DEBUG uint8_t key[56]; Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32); #endif if (ep->isIncomingConnection && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) { Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] " "seconds, dropping connection", key, ic->forgetAfterMilliseconds / 1024); Allocator_free(ep->external->allocator); continue; } bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds); if (unresponsive) { // our link to the peer is broken... Router_disconnectedPeer(ic->router, ep->switchLabel); // Lets skip 87% of pings when they're really down. if (ep->pingCount % 8) { ep->pingCount++; continue; } ep->state = InterfaceController_PeerState_UNRESPONSIVE; } #ifdef Log_DEBUG uint32_t lag = (now - ep->timeOfLastMessage) / 1024; Log_debug(ic->logger, "Pinging %s peer [%s.k] lag [%u]", (unresponsive ? "unresponsive" : "lazy"), key, lag); #endif sendPing(ep); // we only ping one node return; } }
static void nodeForAddr(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); // no ipStr specified --> return self-node struct Node_Two* node = ctx->store->selfNode; String* ipStr = Dict_getString(args, String_new("ip", alloc)); uint8_t ip[16]; while (ipStr) { if (AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("parse_ip", alloc), alloc); } else if (!(node = NodeStore_nodeForAddr(ctx->store, ip))) { // not found } else { break; } Admin_sendMessage(ret, txid, ctx->admin); return; } Dict_putInt(result, String_new("protocolVersion", alloc), node->address.protocolVersion, alloc); String* key = Key_stringify(node->address.key, alloc); Dict_putString(result, String_new("key", alloc), key, alloc); uint32_t count = linkCount(node); Dict_putInt(result, String_new("linkCount", alloc), count, alloc); Dict_putInt(result, String_new("cost", alloc), Node_getCost(node), alloc); List* encScheme = EncodingScheme_asList(node->encodingScheme, alloc); Dict_putList(result, String_new("encodingScheme", alloc), encScheme, alloc); Dict* bestParent = Dict_new(alloc); String* parentIp = String_newBinary(NULL, 39, alloc); AddrTools_printIp(parentIp->bytes, Node_getBestParent(node)->parent->address.ip6.bytes); Dict_putString(bestParent, String_CONST("ip"), parentIp, alloc); String* parentChildLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(parentChildLabel->bytes, Node_getBestParent(node)->cannonicalLabel); Dict_putString(bestParent, String_CONST("parentChildLabel"), parentChildLabel, alloc); int isOneHop = Node_isOneHopLink(Node_getBestParent(node)); Dict_putInt(bestParent, String_CONST("isOneHop"), isOneHop, alloc); Dict_putDict(result, String_CONST("bestParent"), bestParent, alloc); String* bestLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(bestLabel->bytes, node->address.path); Dict_putString(result, String_CONST("routeLabel"), bestLabel, alloc); Admin_sendMessage(ret, txid, ctx->admin); }
static void getLink(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); Dict* ret = Dict_new(alloc); Dict* result = Dict_new(alloc); Dict_putDict(ret, String_new("result", alloc), result, alloc); Dict_putString(ret, String_new("error", alloc), String_new("none", alloc), alloc); struct Node_Link* link = NULL; struct Node_Two* node = NULL; String* ipStr = Dict_getString(args, String_new("parent", alloc)); int64_t* linkNum = Dict_getInt(args, String_new("linkNum", alloc)); if (ipStr && ipStr->len) { uint8_t ip[16]; if (AddrTools_parseIp(ip, ipStr->bytes)) { Dict_remove(ret, String_CONST("result")); Dict_putString(ret, String_new("error", alloc), String_new("parse_parent", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } else if (!(node = NodeStore_nodeForAddr(ctx->store, ip))) { Dict_putString(ret, String_new("error", alloc), String_new("not_found", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } else if (!(link = getLinkByNum(node, *linkNum))) { Dict_putString(ret, String_new("error", alloc), String_new("unknown", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } } else { for (int i = 0; i <= *linkNum; i++) { link = NodeStore_getNextLink(ctx->store, link); if (!link) { break; } } if (!link) { Dict_putString(ret, String_new("error", alloc), String_new("not_found", alloc), alloc); Admin_sendMessage(ret, txid, ctx->admin); return; } } Dict_putInt(result, String_new("inverseLinkEncodingFormNumber", alloc), link->inverseLinkEncodingFormNumber, alloc); Dict_putInt(result, String_new("linkCost", alloc), link->linkCost, alloc); Dict_putInt(result, String_new("isOneHop", alloc), Node_isOneHopLink(link), alloc); int bestParent = (Node_getBestParent(link->child) == link); Dict_putInt(result, String_new("bestParent", alloc), bestParent, alloc); String* cannonicalLabel = String_newBinary(NULL, 19, alloc); AddrTools_printPath(cannonicalLabel->bytes, link->cannonicalLabel); Dict_putString(result, String_new("cannonicalLabel", alloc), cannonicalLabel, alloc); String* parent = Address_toString(&link->parent->address, alloc); Dict_putString(result, String_new("parent", alloc), parent, alloc); String* child = Address_toString(&link->child->address, alloc); Dict_putString(result, String_new("child", alloc), child, alloc); Admin_sendMessage(ret, txid, ctx->admin); }