static void searchResponse(struct RouterModule_Promise* promise, uint32_t lag, struct Address* from, Dict* responseDict) { struct Search* search = Identity_check((struct Search*) promise->userData); struct Allocator* alloc = Allocator_child(search->alloc); Dict* resp = Dict_new(alloc); if (!from) { Dict_putStringCC(resp, "error", "none", alloc); Dict_putIntC(resp, "complete", 1, alloc); Admin_sendMessage(resp, search->txid, search->ctx->admin); Allocator_free(alloc); return; } String* fromStr = Address_toString(from, alloc); Dict_putStringC(resp, "from", fromStr, alloc); Dict_putIntC(resp, "ms", lag, alloc); struct Address_List* addrs = ReplySerializer_parse(from, responseDict, NULL, true, alloc); List* nodes = List_new(alloc); for (int i = 0; addrs && i < addrs->length; i++) { String* addr = Address_toString(&addrs->elems[i], alloc); List_addString(nodes, addr, alloc); } Dict_putListC(resp, "nodes", nodes, alloc); Admin_sendMessage(resp, search->txid, search->ctx->admin); }
static void onGetPeers(Dict* msg, struct Address* src, struct Allocator* tmpAlloc, struct MsgCore_Handler* handler) { struct GetPeersResponder_pvt* gprp = Identity_check((struct GetPeersResponder_pvt*) handler->userData); Log_debug(gprp->log, "Received getPeers req from [%s]", Address_toString(src, tmpAlloc)->bytes); String* txid = Dict_getStringC(msg, "txid"); if (!txid) { Log_debug(gprp->log, "getPeers missing txid"); return; } String* nearLabelStr = Dict_getStringC(msg, "tar"); uint64_t label; if (!nearLabelStr || nearLabelStr->len != 8) { Log_debug(gprp->log, "getPeers does not contain proper target"); return; } else { uint64_t label_be; Bits_memcpy(&label_be, nearLabelStr->bytes, 8); label = Endian_bigEndianToHost64(label_be); } struct Address outAddrs[GETPEERS_RESPONSE_NODES] = { { .padding = 0 } };
static void genericResponse(struct RouterModule_Promise* promise, uint32_t lag, struct Address* from, Dict* responseDict, String* name) { struct Ping* ping = Identity_check((struct Ping*)promise->userData); Dict* out = Dict_new(promise->alloc); String* result = (responseDict) ? name : String_CONST("timeout"); Dict_putString(out, String_CONST("result"), result, promise->alloc); if (responseDict) { struct Address_List* addrs = ReplySerializer_parse(from, responseDict, NULL, promise->alloc); List* nodes = List_new(promise->alloc); for (int i = 0; i < addrs->length; i++) { String* addr = Address_toString(&addrs->elems[i], promise->alloc); List_addString(nodes, addr, promise->alloc); } Dict_putList(out, name, nodes, promise->alloc); } Dict_putInt(out, String_CONST("ms"), lag, promise->alloc); Dict_putString(out, String_CONST("error"), String_CONST("none"), promise->alloc); Admin_sendMessage(out, ping->txid, ping->ctx->admin); }
static void dumpRumorMill(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); Dict* out = Dict_new(requestAlloc); struct RumorMill* rm = getRumorMill(ctx, Dict_getString(args, String_CONST("mill"))); if (!rm) { Dict_putString(out, String_CONST("error"), String_CONST("mill must be one of " "[externalMill,linkMill,nodeMill,dhtMill,splitMill]"), requestAlloc); Admin_sendMessage(out, txid, ctx->admin); return; } int64_t* page = Dict_getInt(args, String_CONST("page")); int ctr = (page) ? *page * ENTRIES_PER_PAGE : 0; List* table = List_new(requestAlloc); for (int i = 0; i < ENTRIES_PER_PAGE && ctr < rm->count; i++) { String* addr = Address_toString(&rm->addresses[ctr++], requestAlloc); List_addString(table, addr, requestAlloc); } Dict_putList(out, String_CONST("addresses"), table, requestAlloc); Dict_putInt(out, String_CONST("total"), rm->count, requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
/** * Incoming message from someone we don't know, maybe someone responding to a beacon? * expects: [ struct LLAddress ][ content ] */ static Iface_DEFUN handleUnexpectedIncoming(struct Message* msg, struct InterfaceController_Iface_pvt* ici) { struct InterfaceController_pvt* ic = ici->ic; struct Sockaddr* lladdr = (struct Sockaddr*) msg->bytes; Message_shift(msg, -lladdr->addrLen, NULL); if (msg->length < CryptoHeader_SIZE) { return NULL; } struct Allocator* epAlloc = Allocator_child(ici->alloc); lladdr = Sockaddr_clone(lladdr, epAlloc); Assert_true(!((uintptr_t)msg->bytes % 4) && "alignment fault"); struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); Identity_set(ep); ep->alloc = epAlloc; ep->ici = ici; ep->lladdr = lladdr; ep->alloc = epAlloc; ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); struct CryptoHeader* ch = (struct CryptoHeader*) msg->bytes; ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, ch->publicKey, true, "outer"); if (CryptoAuth_decrypt(ep->caSession, msg)) { // If the first message is a dud, drop all state for this peer. // probably some random crap that wandered in the socket. Allocator_free(epAlloc); return NULL; } Assert_true(!Bits_isZero(ep->caSession->herPublicKey, 32)); Assert_true(Map_EndpointsBySockaddr_indexForKey(&lladdr, &ici->peerMap) == -1); int index = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); Assert_true(index >= 0); ep->handle = ici->peerMap.handles[index]; Allocator_onFree(epAlloc, closeInterface, ep); ep->state = InterfaceController_PeerState_UNAUTHENTICATED; ep->isIncomingConnection = true; ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "handleUnexpectedIncoming() SwitchCore out of space"); Allocator_free(epAlloc); return NULL; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; Bits_memcpy(ep->addr.key, ep->caSession->herPublicKey, 32); Bits_memcpy(ep->addr.ip6.bytes, ep->caSession->herIp6, 16); Log_info(ic->logger, "Added peer [%s] from incoming message", Address_toString(&ep->addr, msg->alloc)->bytes); return receivedPostCryptoAuth(msg, ep, ic); }
static Iface_DEFUN sessionEnded(struct Message* msg, struct Pathfinder_pvt* pf) { struct Address addr; addressForNode(&addr, msg); String* str = Address_toString(&addr, msg->alloc); Log_debug(pf->log, "Session ended [%s]", str->bytes); return NULL; }
static void sendMsg(struct MsgCore_pvt* mcp, Dict* msgDict, struct Address* addr, struct Allocator* allocator) { struct Allocator* alloc = Allocator_child(allocator); // Send the encoding scheme definition Dict_putString(msgDict, CJDHTConstants_ENC_SCHEME, mcp->schemeDefinition, allocator); // And tell the asker which interface the message came from int encIdx = EncodingScheme_getFormNum(mcp->scheme, addr->path); Assert_true(encIdx != EncodingScheme_getFormNum_INVALID); Dict_putInt(msgDict, CJDHTConstants_ENC_INDEX, encIdx, allocator); // send the protocol version Dict_putInt(msgDict, CJDHTConstants_PROTOCOL, Version_CURRENT_PROTOCOL, allocator); if (!Defined(SUBNODE)) { String* q = Dict_getStringC(msgDict, "q"); String* sq = Dict_getStringC(msgDict, "sq"); if (q || sq) { Log_debug(mcp->log, "Send query [%s] to [%s]", ((q) ? q->bytes : sq->bytes), Address_toString(addr, alloc)->bytes); String* txid = Dict_getStringC(msgDict, "txid"); Assert_true(txid); String* newTxid = String_newBinary(NULL, txid->len + 1, alloc); Bits_memcpy(&newTxid->bytes[1], txid->bytes, txid->len); newTxid->bytes[0] = '1'; Dict_putStringC(msgDict, "txid", newTxid, alloc); } } struct Message* msg = Message_new(0, 2048, alloc); BencMessageWriter_write(msgDict, msg, NULL); //Log_debug(mcp->log, "Sending msg [%s]", Escape_getEscaped(msg->bytes, msg->length, alloc)); // Sanity check (make sure the addr was actually calculated) Assert_true(addr->ip6.bytes[0] == 0xfc); struct DataHeader data; Bits_memset(&data, 0, sizeof(struct DataHeader)); DataHeader_setVersion(&data, DataHeader_CURRENT_VERSION); DataHeader_setContentType(&data, ContentType_CJDHT); Message_push(msg, &data, sizeof(struct DataHeader), NULL); struct RouteHeader route; Bits_memset(&route, 0, sizeof(struct RouteHeader)); Bits_memcpy(route.ip6, addr->ip6.bytes, 16); route.version_be = Endian_hostToBigEndian32(addr->protocolVersion); route.sh.label_be = Endian_hostToBigEndian64(addr->path); Bits_memcpy(route.publicKey, addr->key, 32); Message_push(msg, &route, sizeof(struct RouteHeader), NULL); Iface_send(&mcp->pub.interRouterIf, msg); }
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 Iface_DEFUN peerGone(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 gone [%s]", str->bytes); NodeStore_disconnectedPeer(pf->nodeStore, addr.path); // We notify about the node but with max metric so it will be removed soon. return sendNode(msg, &addr, 0xffffffff, pf); }
static void dumpTable(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* ctx = Identity_check((struct Context*) vcontext); int64_t* page = Dict_getInt(args, String_CONST("page")); int ctr = (page) ? *page * ENTRIES_PER_PAGE : 0; Dict* out = Dict_new(requestAlloc); List* table = List_new(requestAlloc); struct Node_Two* nn = NULL; for (int i = 0; i < ctr+ENTRIES_PER_PAGE; i++) { nn = NodeStore_getNextNode(ctx->store, nn); if (!nn) { break; } if (i < ctr) { continue; } Dict* nodeDict = Dict_new(requestAlloc); String* ip = String_newBinary(NULL, 39, requestAlloc); Address_printIp(ip->bytes, &nn->address); Dict_putString(nodeDict, String_CONST("ip"), ip, requestAlloc); String* addr = Address_toString(&nn->address, requestAlloc); Dict_putString(nodeDict, String_CONST("addr"), addr, requestAlloc); String* path = String_newBinary(NULL, 19, requestAlloc); AddrTools_printPath(path->bytes, nn->address.path); Dict_putString(nodeDict, String_CONST("path"), path, requestAlloc); Dict_putInt(nodeDict, String_CONST("link"), Node_getCost(nn), requestAlloc); Dict_putInt(nodeDict, String_CONST("version"), nn->address.protocolVersion, requestAlloc); Dict_putInt(nodeDict, String_CONST("time"), NodeStore_timeSinceLastPing(ctx->store, nn), requestAlloc); Dict_putInt(nodeDict, String_CONST("bucket"), NodeStore_bucketForAddr(ctx->store->selfAddress, &nn->address), requestAlloc); List_addDict(table, nodeDict, requestAlloc); } Dict_putList(out, String_CONST("routingTable"), table, requestAlloc); if (nn) { Dict_putInt(out, String_CONST("more"), 1, requestAlloc); } Dict_putInt(out, String_CONST("count"), ctx->store->nodeCount, requestAlloc); Dict_putInt(out, String_CONST("peers"), ctx->store->peerCount, requestAlloc); Dict_putString(out, String_CONST("deprecation"), String_CONST("ip,path,version will soon be removed"), requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
static void onPingResponse(struct SwitchPinger_Response* resp, void* onResponseContext) { if (SwitchPinger_Result_OK != resp->res) { return; } struct Peer* ep = Identity_check((struct Peer*) onResponseContext); struct InterfaceController_pvt* ic = Identity_check(ep->ici->ic); ep->addr.protocolVersion = resp->version; if (Defined(Log_DEBUG)) { String* addr = Address_toString(&ep->addr, resp->ping->pingAlloc); if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { Log_debug(ic->logger, "got switch pong from node [%s] with incompatible version", addr->bytes); } else if (ep->addr.path != resp->label) { uint8_t sl[20]; AddrTools_printPath(sl, resp->label); Log_debug(ic->logger, "got switch pong from node [%s] mismatch label [%s]", addr->bytes, sl); } else { Log_debug(ic->logger, "got switch pong from node [%s]", addr->bytes); } } if (!Version_isCompatible(Version_CURRENT_PROTOCOL, resp->version)) { return; } if (ep->state == InterfaceController_PeerState_ESTABLISHED) { sendPeer(0xffffffff, PFChan_Core_PEER, ep); } ep->timeOfLastPing = Time_currentTimeMilliseconds(ic->eventBase); if (Defined(Log_DEBUG)) { String* addr = Address_toString(&ep->addr, resp->ping->pingAlloc); Log_debug(ic->logger, "Received [%s] from lazy endpoint [%s]", SwitchPinger_resultString(resp->res)->bytes, addr->bytes); } }
static void sessionStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = Identity_check((struct Context*) vcontext); int64_t* handleP = Dict_getInt(args, String_CONST("handle")); uint32_t handle = *handleP; struct SessionManager_Session* session = SessionManager_sessionForHandle(handle, context->sm); Dict* r = Dict_new(alloc); if (!session) { Dict_putString(r, String_CONST("error"), String_CONST("no such session"), alloc); Admin_sendMessage(r, txid, context->admin); return; } uint8_t printedAddr[40]; AddrTools_printIp(printedAddr, session->caSession->herIp6); Dict_putString(r, String_CONST("ip6"), String_new(printedAddr, alloc), alloc); String* state = String_new(CryptoAuth_stateString(CryptoAuth_getState(session->caSession)), alloc); Dict_putString(r, String_CONST("state"), state, alloc); struct ReplayProtector* rp = &session->caSession->replayProtector; Dict_putInt(r, String_CONST("duplicates"), rp->duplicates, alloc); Dict_putInt(r, String_CONST("lostPackets"), rp->lostPackets, alloc); Dict_putInt(r, String_CONST("receivedOutOfRange"), rp->receivedOutOfRange, alloc); struct Address addr; Bits_memcpyConst(addr.key, session->caSession->herPublicKey, 32); addr.path = session->sendSwitchLabel; addr.protocolVersion = session->version; Dict_putString(r, String_CONST("addr"), Address_toString(&addr, alloc), alloc); Dict_putString(r, String_CONST("publicKey"), Key_stringify(session->caSession->herPublicKey, alloc), alloc); Dict_putInt(r, String_CONST("version"), session->version, alloc); Dict_putInt(r, String_CONST("handle"), session->receiveHandle, alloc); Dict_putInt(r, String_CONST("sendHandle"), session->sendHandle, alloc); Dict_putInt(r, String_CONST("timeOfLastIn"), session->timeOfLastIn, alloc); Dict_putInt(r, String_CONST("timeOfLastOut"), session->timeOfLastOut, alloc); Dict_putString(r, String_CONST("deprecation"), String_CONST("publicKey,version will soon be removed"), alloc); Admin_sendMessage(r, txid, context->admin); return; }
static void onBestPathChange(void* vPathfinder, struct Node_Two* node) { struct Pathfinder_pvt* pf = Identity_check((struct Pathfinder_pvt*) vPathfinder); struct Allocator* alloc = Allocator_child(pf->alloc); if (pf->bestPathChanges > 128) { String* addrPrinted = Address_toString(&node->address, alloc); Log_debug(pf->log, "Ignore best path change from NodeStore [%s]", addrPrinted->bytes); } else { pf->bestPathChanges++; struct Message* msg = Message_new(0, 256, alloc); Iface_CALL(sendNode, msg, &node->address, Node_getCost(node), pf); } Allocator_free(alloc); }
static void nodeInfo(Dict* args, void* vcontext, String* txid, struct Allocator* requestAlloc) { struct Context* const ctx = Identity_check((struct Context*) vcontext); String* myAddr = Address_toString(ctx->nc->myAddress, requestAlloc); String* schemeStr = EncodingScheme_serialize(ctx->encodingScheme, requestAlloc); List* schemeList = EncodingScheme_asList(ctx->encodingScheme, requestAlloc); Dict* out = Dict_new(requestAlloc); Dict_putStringC(out, "myAddr", myAddr, requestAlloc); char* schemeHex = Hex_print(schemeStr->bytes, schemeStr->len, requestAlloc); Dict_putStringCC(out, "compressedSchemeHex", schemeHex, requestAlloc); Dict_putListC(out, "encodingScheme", schemeList, requestAlloc); Dict_putIntC(out, "version", Version_CURRENT_PROTOCOL, requestAlloc); Dict_putStringCC(out, "error", "none", requestAlloc); Admin_sendMessage(out, txid, ctx->admin); }
static void adminPeerStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = Identity_check((struct Context*)vcontext); struct InterfaceController_PeerStats* stats = NULL; int64_t* page = Dict_getIntC(args, "page"); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; int count = InterfaceController_getPeerStats(context->ic, alloc, &stats); List* list = List_new(alloc); for (int counter=0; i < count && counter++ < ENTRIES_PER_PAGE; i++) { Dict* d = Dict_new(alloc); Dict_putIntC(d, "bytesIn", stats[i].bytesIn, alloc); Dict_putIntC(d, "bytesOut", stats[i].bytesOut, alloc); Dict_putIntC(d, "recvKbps", stats[i].recvKbps, alloc); Dict_putIntC(d, "sendKbps", stats[i].sendKbps, alloc); Dict_putStringC(d, "addr", Address_toString(&stats[i].addr, alloc), alloc); String* stateString = String_new(InterfaceController_stateString(stats[i].state), alloc); Dict_putStringC(d, "state", stateString, alloc); Dict_putIntC(d, "last", stats[i].timeOfLastMessage, alloc); Dict_putIntC(d, "isIncoming", stats[i].isIncomingConnection, alloc); Dict_putIntC(d, "duplicates", stats[i].duplicates, alloc); Dict_putIntC(d, "lostPackets", stats[i].lostPackets, alloc); Dict_putIntC(d, "receivedOutOfRange", stats[i].receivedOutOfRange, alloc); if (stats[i].user) { Dict_putStringC(d, "user", stats[i].user, alloc); } List_addDict(list, d, alloc); } Dict* resp = Dict_new(alloc); Dict_putListC(resp, "peers", list, alloc); Dict_putIntC(resp, "total", count, alloc); if (i < count) { Dict_putIntC(resp, "more", 1, alloc); } Admin_sendMessage(resp, txid, context->admin); }
static Iface_DEFUN session(struct Message* msg, struct Pathfinder_pvt* pf) { struct Address addr; addressForNode(&addr, msg); String* str = Address_toString(&addr, msg->alloc); Log_debug(pf->log, "Session [%s]", str->bytes); /* This triggers for every little ping we send to some random node out there which * sucks too much to ever get into the nodeStore. struct Node_Two* node = NodeStore_nodeForAddr(pf->nodeStore, addr.ip6.bytes); if (!node) { SearchRunner_search(addr.ip6.bytes, 20, 3, pf->searchRunner, pf->alloc); }*/ return NULL; }
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); }
static Iface_DEFUN discoveredPath(struct Message* msg, struct Pathfinder_pvt* pf) { struct Address addr; addressForNode(&addr, msg); // We're somehow aware of this path (even if it's unused) if (NodeStore_linkForPath(pf->nodeStore, addr.path)) { return NULL; } // If we don't already care about the destination, then don't do anything. struct Node_Two* nn = NodeStore_nodeForAddr(pf->nodeStore, addr.ip6.bytes); if (!nn) { return NULL; } // Our best path is "shorter" (label bits which is somewhat representitive of hop count) // basically this is just to dampen the flood to the RM because otherwise it prevents Janitor // from getting any actual work done. if (nn->address.path < addr.path) { return NULL; } Log_debug(pf->log, "Discovered path [%s]", Address_toString(&addr, msg->alloc)->bytes); RumorMill_addNode(pf->rumorMill, &addr); return NULL; }
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); }
static void mkNextRequest(struct ReachabilityCollector_pvt* rcp) { struct PeerInfo_pvt* pi = NULL; for (int i = 0; i < rcp->piList->length; i++) { pi = ArrayList_OfPeerInfo_pvt_get(rcp->piList, i); if (pi->pub.querying && !pi->waitForResponse) { break; } } if (!pi || !pi->pub.querying) { Log_debug(rcp->log, "All [%u] peers have been queried", rcp->piList->length); return; } if (pi->waitForResponse) { Log_debug(rcp->log, "Peer is waiting for response."); return; } struct MsgCore_Promise* query = MsgCore_createQuery(rcp->msgCore, TIMEOUT_MILLISECONDS, rcp->alloc); struct Query* q = Allocator_calloc(query->alloc, sizeof(struct Query), 1); q->rcp = rcp; q->addr = Address_toString(&pi->pub.addr, query->alloc); query->userData = q; query->cb = onReply; Assert_true(AddressCalc_validAddress(pi->pub.addr.ip6.bytes)); query->target = Address_clone(&pi->pub.addr, query->alloc); Dict* d = query->msg = Dict_new(query->alloc); Dict_putStringCC(d, "q", "gp", query->alloc); uint64_t label_be = Endian_hostToBigEndian64(pi->pathToCheck); uint8_t nearbyLabelBytes[8]; Bits_memcpy(nearbyLabelBytes, &label_be, 8); AddrTools_printPath(q->targetPath, pi->pathToCheck); Log_debug(rcp->log, "Getting peers for peer [%s] tar [%s]", q->addr->bytes, q->targetPath); Dict_putStringC(d, "tar", String_newBinary(nearbyLabelBytes, 8, query->alloc), query->alloc); BoilerplateResponder_addBoilerplate(rcp->br, d, &pi->pub.addr, query->alloc); pi->waitForResponse = true; }
static Iface_DEFUN replyMsg(struct MsgCore_pvt* mcp, Dict* content, struct Address* src, struct Message* msg) { Log_debug(mcp->log, "Got reply from [%s]", Address_toString(src, msg->alloc)->bytes); String* txid = Dict_getStringC(content, "txid"); if (!txid) { Log_debug(mcp->log, "DROP Message with no txid"); return NULL; } struct ReplyContext* rc = Allocator_calloc(msg->alloc, sizeof(struct ReplyContext), 1); rc->src = src; rc->content = content; rc->msg = msg; Identity_set(rc); Assert_true(!mcp->currentReply); mcp->currentReply = rc; // Pops out in pingerOnResponse() if the reply is indeed valid... Pinger_pongReceived(txid, mcp->pinger); mcp->currentReply = NULL; return NULL; }
static void adminPeerStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = Identity_check((struct Context*)vcontext); struct InterfaceController_PeerStats* stats = NULL; int64_t* page = Dict_getIntC(args, "page"); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; int count = InterfaceController_getPeerStats(context->ic, alloc, &stats); List* list = List_new(alloc); for (int counter=0; i < count && counter++ < ENTRIES_PER_PAGE; i++) { Dict* d = Dict_new(alloc); Dict_putIntC(d, "bytesIn", stats[i].bytesIn, alloc); Dict_putIntC(d, "bytesOut", stats[i].bytesOut, alloc); Dict_putIntC(d, "recvKbps", stats[i].recvKbps, alloc); Dict_putIntC(d, "sendKbps", stats[i].sendKbps, alloc); Dict_putStringC(d, "addr", Address_toString(&stats[i].addr, alloc), alloc); String* lladdrString; #ifdef HAS_ETH_INTERFACE if (ETHInterface_Sockaddr_SIZE == stats[i].lladdr->addrLen) { struct ETHInterface_Sockaddr* eth = (struct ETHInterface_Sockaddr*) stats[i].lladdr; uint8_t printedMac[18]; AddrTools_printMac(printedMac, eth->mac); lladdrString = String_new(printedMac, alloc); } else { lladdrString = String_new(Sockaddr_print(stats[i].lladdr, alloc), alloc); } #else lladdrString = String_new(Sockaddr_print(stats[i].lladdr, alloc), alloc); #endif Dict_putStringC(d, "lladdr", lladdrString, alloc); String* stateString = String_new(InterfaceController_stateString(stats[i].state), alloc); Dict_putStringC(d, "state", stateString, alloc); Dict_putIntC(d, "last", stats[i].timeOfLastMessage, alloc); Dict_putIntC(d, "isIncoming", stats[i].isIncomingConnection, alloc); Dict_putIntC(d, "duplicates", stats[i].duplicates, alloc); Dict_putIntC(d, "lostPackets", stats[i].lostPackets, alloc); Dict_putIntC(d, "receivedOutOfRange", stats[i].receivedOutOfRange, alloc); Dict_putIntC(d, "ifNum", stats[i].ifNum, alloc); if (stats[i].user) { Dict_putStringC(d, "user", stats[i].user, alloc); } Dict_putIntC(d, "receivedPackets", stats[i].receivedPackets, alloc); List_addDict(list, d, alloc); } Dict* resp = Dict_new(alloc); Dict_putListC(resp, "peers", list, alloc); Dict_putIntC(resp, "total", count, alloc); if (i < count) { Dict_putIntC(resp, "more", 1, alloc); } Admin_sendMessage(resp, txid, context->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); }
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); }
int InterfaceController_bootstrapPeer(struct InterfaceController* ifc, int interfaceNumber, uint8_t* herPublicKey, const struct Sockaddr* lladdrParm, String* password, String* login, String* user, struct Allocator* alloc) { struct InterfaceController_pvt* ic = Identity_check((struct InterfaceController_pvt*) ifc); Assert_true(herPublicKey); Assert_true(password); struct InterfaceController_Iface_pvt* ici = ArrayList_OfIfaces_get(ic->icis, interfaceNumber); if (!ici) { return InterfaceController_bootstrapPeer_BAD_IFNUM; } Log_debug(ic->logger, "bootstrapPeer total [%u]", ici->peerMap.count); uint8_t ip6[16]; AddressCalc_addressForPublicKey(ip6, herPublicKey); if (!AddressCalc_validAddress(ip6) || !Bits_memcmp(ic->ca->publicKey, herPublicKey, 32)) { return InterfaceController_bootstrapPeer_BAD_KEY; } struct Allocator* epAlloc = Allocator_child(ici->alloc); struct Sockaddr* lladdr = Sockaddr_clone(lladdrParm, epAlloc); // TODO(cjd): eps are created in 3 places, there should be a factory function. struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); int index = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); Assert_true(index >= 0); ep->alloc = epAlloc; ep->handle = ici->peerMap.handles[index]; ep->lladdr = lladdr; ep->ici = ici; ep->isIncomingConnection = false; Bits_memcpy(ep->addr.key, herPublicKey, 32); Address_getPrefix(&ep->addr); Identity_set(ep); Allocator_onFree(epAlloc, closeInterface, ep); Allocator_onFree(alloc, freeAlloc, epAlloc); ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, herPublicKey, false, "outer"); CryptoAuth_setAuth(password, login, ep->caSession); if (user) { ep->caSession->displayName = String_clone(user, epAlloc); } ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "bootstrapPeer() SwitchCore out of space"); Allocator_free(epAlloc); return InterfaceController_bootstrapPeer_OUT_OF_SPACE; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; if (Defined(Log_INFO)) { struct Allocator* tempAlloc = Allocator_child(alloc); String* addrStr = Address_toString(&ep->addr, tempAlloc); Log_info(ic->logger, "Adding peer [%s] from bootstrapPeer()", addrStr->bytes); Allocator_free(tempAlloc); } // We can't just add the node directly to the routing table because we do not know // the version. We'll send it a switch ping and when it responds, we will know it's // key (if we don't already) and version number. sendPing(ep); return 0; }
/** * Expects [ struct LLAddress ][ beacon ] */ static Iface_DEFUN handleBeacon(struct Message* msg, struct InterfaceController_Iface_pvt* ici) { struct InterfaceController_pvt* ic = ici->ic; if (!ici->beaconState) { // accepting beacons disabled. Log_debug(ic->logger, "[%s] Dropping beacon because beaconing is disabled", ici->name->bytes); return NULL; } if (msg->length < Headers_Beacon_SIZE) { Log_debug(ic->logger, "[%s] Dropping runt beacon", ici->name->bytes); return NULL; } struct Sockaddr* lladdrInmsg = (struct Sockaddr*) msg->bytes; // clear the bcast flag lladdrInmsg->flags = 0; Message_shift(msg, -lladdrInmsg->addrLen, NULL); struct Headers_Beacon beacon; Message_pop(msg, &beacon, Headers_Beacon_SIZE, NULL); if (Defined(Log_DEBUG)) { char* content = Hex_print(&beacon, Headers_Beacon_SIZE, msg->alloc); Log_debug(ici->ic->logger, "RECV BEACON CONTENT[%s]", content); } struct Address addr; Bits_memset(&addr, 0, sizeof(struct Address)); Bits_memcpy(addr.key, beacon.publicKey, 32); addr.protocolVersion = Endian_bigEndianToHost32(beacon.version_be); Address_getPrefix(&addr); String* printedAddr = NULL; if (Defined(Log_DEBUG)) { printedAddr = Address_toString(&addr, msg->alloc); } if (addr.ip6.bytes[0] != 0xfc || !Bits_memcmp(ic->ca->publicKey, addr.key, 32)) { Log_debug(ic->logger, "handleBeacon invalid key [%s]", printedAddr->bytes); return NULL; } if (!Version_isCompatible(addr.protocolVersion, Version_CURRENT_PROTOCOL)) { if (Defined(Log_DEBUG)) { Log_debug(ic->logger, "[%s] DROP beacon from [%s] which was version [%d] " "our version is [%d] making them incompatable", ici->name->bytes, printedAddr->bytes, addr.protocolVersion, Version_CURRENT_PROTOCOL); } return NULL; } String* beaconPass = String_newBinary(beacon.password, Headers_Beacon_PASSWORD_LEN, msg->alloc); int epIndex = Map_EndpointsBySockaddr_indexForKey(&lladdrInmsg, &ici->peerMap); if (epIndex > -1) { // The password might have changed! struct Peer* ep = ici->peerMap.values[epIndex]; CryptoAuth_setAuth(beaconPass, NULL, ep->caSession); return NULL; } struct Allocator* epAlloc = Allocator_child(ici->alloc); struct Peer* ep = Allocator_calloc(epAlloc, sizeof(struct Peer), 1); struct Sockaddr* lladdr = Sockaddr_clone(lladdrInmsg, epAlloc); ep->alloc = epAlloc; ep->ici = ici; ep->lladdr = lladdr; int setIndex = Map_EndpointsBySockaddr_put(&lladdr, &ep, &ici->peerMap); ep->handle = ici->peerMap.handles[setIndex]; ep->isIncomingConnection = true; Bits_memcpy(&ep->addr, &addr, sizeof(struct Address)); Identity_set(ep); Allocator_onFree(epAlloc, closeInterface, ep); ep->peerLink = PeerLink_new(ic->eventBase, epAlloc); ep->caSession = CryptoAuth_newSession(ic->ca, epAlloc, beacon.publicKey, false, "outer"); CryptoAuth_setAuth(beaconPass, NULL, ep->caSession); ep->switchIf.send = sendFromSwitch; if (SwitchCore_addInterface(ic->switchCore, &ep->switchIf, epAlloc, &ep->addr.path)) { Log_debug(ic->logger, "handleBeacon() SwitchCore out of space"); Allocator_free(epAlloc); return NULL; } // We want the node to immedietly be pinged but we don't want it to appear unresponsive because // the pinger will only ping every (PING_INTERVAL * 8) so we set timeOfLastMessage to // (now - pingAfterMilliseconds - 1) so it will be considered a "lazy node". ep->timeOfLastMessage = Time_currentTimeMilliseconds(ic->eventBase) - ic->pingAfterMilliseconds - 1; Log_info(ic->logger, "Added peer [%s] from beacon", Address_toString(&ep->addr, msg->alloc)->bytes); // This should be safe because this is an outgoing request and we're sure the node will not // be relocated by moveEndpointIfNeeded() sendPeer(0xffffffff, PFChan_Core_PEER, ep); return NULL; }
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 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); } }
/** * 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); }
static void adminPeerStats(Dict* args, void* vcontext, String* txid, struct Allocator* alloc) { struct Context* context = Identity_check((struct Context*)vcontext); struct InterfaceController_PeerStats* stats = NULL; int64_t* page = Dict_getInt(args, String_CONST("page")); int i = (page) ? *page * ENTRIES_PER_PAGE : 0; int count = InterfaceController_getPeerStats(context->ic, alloc, &stats); String* bytesIn = String_CONST("bytesIn"); String* bytesOut = String_CONST("bytesOut"); String* pubKey = String_CONST("publicKey"); String* addr = String_CONST("addr"); String* state = String_CONST("state"); String* last = String_CONST("last"); String* switchLabel = String_CONST("switchLabel"); String* isIncoming = String_CONST("isIncoming"); String* user = String_CONST("user"); String* version = String_CONST("version"); String* duplicates = String_CONST("duplicates"); String* lostPackets = String_CONST("lostPackets"); String* receivedOutOfRange = String_CONST("receivedOutOfRange"); List* list = List_new(alloc); for (int counter=0; i < count && counter++ < ENTRIES_PER_PAGE; i++) { Dict* d = Dict_new(alloc); Dict_putInt(d, bytesIn, stats[i].bytesIn, alloc); Dict_putInt(d, bytesOut, stats[i].bytesOut, alloc); Dict_putString(d, addr, Address_toString(&stats[i].addr, alloc), alloc); Dict_putString(d, pubKey, Key_stringify(stats[i].addr.key, alloc), alloc); String* stateString = String_new(InterfaceController_stateString(stats[i].state), alloc); Dict_putString(d, state, stateString, alloc); Dict_putInt(d, last, stats[i].timeOfLastMessage, alloc); uint8_t labelStack[20]; AddrTools_printPath(labelStack, stats[i].addr.path); Dict_putString(d, switchLabel, String_new((char*)labelStack, alloc), alloc); Dict_putInt(d, isIncoming, stats[i].isIncomingConnection, alloc); Dict_putInt(d, duplicates, stats[i].duplicates, alloc); Dict_putInt(d, lostPackets, stats[i].lostPackets, alloc); Dict_putInt(d, receivedOutOfRange, stats[i].receivedOutOfRange, alloc); if (stats[i].user) { Dict_putString(d, user, stats[i].user, alloc); } uint8_t address[16]; AddressCalc_addressForPublicKey(address, stats[i].addr.key); Dict_putInt(d, version, stats[i].addr.protocolVersion, alloc); List_addDict(list, d, alloc); } Dict* resp = Dict_new(alloc); Dict_putList(resp, String_CONST("peers"), list, alloc); Dict_putInt(resp, String_CONST("total"), count, alloc); if (i < count) { Dict_putInt(resp, String_CONST("more"), 1, alloc); } Dict_putString(resp, String_CONST("deprecation"), String_CONST("publicKey,switchLabel,version will soon be removed"), alloc); Admin_sendMessage(resp, txid, context->admin); }