/* * bitdht/bdquery.cc * * BitDHT: An Flexible DHT library. * * Copyright 2010 by Robert Fernie * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License Version 3 as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA. * * Please report all bugs and problems to "bitdht@lunamutt.com". * */ #include "bitdht/bdquery.h" #include "util/bdnet.h" #include #include #include /** * #define DEBUG_QUERY 1 **/ #define EXPECTED_REPLY 10 // Speed up queries #define QUERY_IDLE_RETRY_PEER_PERIOD 300 // 5min = (mFns->bdNodesPerBucket() * 30) /************************************************************ * bdQuery logic: * 1) as replies come in ... maintain list of M closest peers to ID. * 2) select non-queried peer from list, and query. * 3) halt when we have asked all M closest peers about the ID. * * Flags can be set to disguise the target of the search. * This involves */ bdQuery::bdQuery(const bdNodeId *id, std::list &startList, uint32_t queryFlags, bdDhtFunctions *fns) { /* */ mId = *id; mFns = fns; time_t now = time(NULL); std::list::iterator it; for(it = startList.begin(); it != startList.end(); it++) { bdPeer peer; peer.mLastSendTime = 0; peer.mLastRecvTime = 0; peer.mPeerFlags = 0; peer.mFoundTime = now; peer.mPeerId = *it; bdMetric dist; mFns->bdDistance(&mId, &(peer.mPeerId.id), &dist); mClosest.insert(std::pair(dist, peer)); } mState = BITDHT_QUERY_QUERYING; mQueryFlags = queryFlags; mQueryTS = now; mSearchTime = 0; mClosestListSize = (int) (1.5 * mFns->bdNodesPerBucket()); mQueryIdlePeerRetryPeriod = QUERY_IDLE_RETRY_PEER_PERIOD; mRequiredPeerFlags = BITDHT_PEER_STATUS_DHT_ENGINE_VERSION; // XXX to update later. /* setup the limit of the search * by default it is setup to 000000 = exact match */ bdZeroNodeId(&mLimit); } bool bdQuery::result(std::list &answer) { /* get all the matches to our query */ std::multimap::iterator sit, eit; sit = mClosest.begin(); eit = mClosest.upper_bound(mLimit); int i = 0; for(; sit != eit; sit++, i++) { answer.push_back(sit->second.mPeerId); } return (i > 0); } int bdQuery::nextQuery(bdId &id, bdNodeId &targetNodeId) { if ((mState != BITDHT_QUERY_QUERYING) && !(mQueryFlags & BITDHT_QFLAGS_DO_IDLE)) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() Query is done\n"); #endif return 0; } /* search through through list, find closest not queried */ time_t now = time(NULL); /* update IdlePeerRetry */ if ((now - mQueryTS) / 2 > mQueryIdlePeerRetryPeriod) { mQueryIdlePeerRetryPeriod = (now-mQueryTS) / 2; } bool notFinished = false; std::multimap::iterator it; int i = 0; for(it = mClosest.begin(); it != mClosest.end(); it++, i++) { bool queryPeer = false; /* if never queried */ if (it->second.mLastSendTime == 0) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() Found non-sent peer. queryPeer = true : "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); std::cerr << std::endl; #endif queryPeer = true; } /* re-request every so often */ if ((!queryPeer) && (mQueryFlags & BITDHT_QFLAGS_DO_IDLE) && (now - it->second.mLastSendTime > mQueryIdlePeerRetryPeriod)) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() Found out-of-date. queryPeer = true : "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); std::cerr << std::endl; #endif queryPeer = true; } /* expecting every peer to be up-to-date is too hard... * enough just to have received lists from each * - replacement policy will still work. * * Need to wait at least EXPECTED_REPLY, to make sure their answers are pinged */ if (((it->second.mLastRecvTime == 0) || (now - it->second.mLastRecvTime < EXPECTED_REPLY)) && (i < mFns->bdNodesPerBucket())) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() Never Received @Idx(%d) notFinished = true: ", i); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); std::cerr << std::endl; #endif notFinished = true; } if (queryPeer) { id = it->second.mPeerId; it->second.mLastSendTime = now; if (mQueryFlags & BITDHT_QFLAGS_DISGUISE) { /* calc Id mid point between Target and Peer */ bdNodeId midRndId; mFns->bdRandomMidId(&mId, &(id.id), &midRndId); targetNodeId = midRndId; } else { targetNodeId = mId; } #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() Querying Peer: "); mFns->bdPrintId(std::cerr, &id); std::cerr << std::endl; #endif return 1; } } /* allow query to run for a minimal amount of time * This is important as startup - when we might not have any peers. * Probably should be handled elsewhere. */ time_t age = now - mQueryTS; if (age < BITDHT_MIN_QUERY_AGE) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() under Min Time: Query not finished / No Query\n"); #endif return 0; } if (age > BITDHT_MAX_QUERY_AGE) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() under Min Time: Query not finished / No Query\n"); #endif /* fall through and stop */ } else if ((mClosest.size() < mFns->bdNodesPerBucket()) || (notFinished)) { #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() notFinished | !size(): Query not finished / No Query\n"); #endif /* not full yet... */ return 0; } #ifdef DEBUG_QUERY fprintf(stderr, "NextQuery() Finished\n"); #endif /* if we get here - query finished */ if (mState == BITDHT_QUERY_QUERYING) { /* store query time */ mSearchTime = now - mQueryTS; } /* check if we found the node */ if (mClosest.size() > 0) { if ((mClosest.begin()->second).mPeerId.id == mId) { mState = BITDHT_QUERY_SUCCESS; } else if ((mPotentialPeers.begin()->second).mPeerId.id == mId) { mState = BITDHT_QUERY_PEER_UNREACHABLE; } else { mState = BITDHT_QUERY_FOUND_CLOSEST; } } else { mState = BITDHT_QUERY_FAILURE; } return 0; } int bdQuery::addClosestPeer(const bdId *id, uint32_t mode) { bdMetric dist; time_t ts = time(NULL); mFns->bdDistance(&mId, &(id->id), &dist); #ifdef DEBUG_QUERY fprintf(stderr, "bdQuery::addPeer("); mFns->bdPrintId(std::cerr, id); fprintf(stderr, ", %u)\n", mode); #endif std::multimap::iterator it, sit, eit; sit = mClosest.lower_bound(dist); eit = mClosest.upper_bound(dist); int i = 0; int actualCloser = 0; int toDrop = 0; // switched end condition to upper_bound to provide stability for NATTED peers. // we will favour the older entries! for(it = mClosest.begin(); it != eit; it++, i++, actualCloser++) { time_t sendts = ts - it->second.mLastSendTime; bool hasSent = (it->second.mLastSendTime != 0); bool hasReply = (it->second.mLastRecvTime >= it->second.mLastSendTime); if ((hasSent) && (!hasReply) && (sendts > EXPECTED_REPLY)) { i--; /* dont count this one */ toDrop++; } } // Counts where we are. #ifdef DEBUG_QUERY fprintf(stderr, "Searching.... %di = %d - %d peers closer than this one\n", i, actualCloser, toDrop); #endif if (i > mClosestListSize - 1) { #ifdef DEBUG_QUERY fprintf(stderr, "Distance to far... dropping\n"); #endif /* drop it */ return 0; } for(it = sit; it != eit; it++, i++) { /* full id check */ if (mFns->bdSimilarId(id, &(it->second.mPeerId))) { #ifdef DEBUG_QUERY fprintf(stderr, "Peer Already here!\n"); #endif if (mode) { /* also update port from incoming id, as we have definitely recved from it */ if (mFns->bdUpdateSimilarId(&(it->second.mPeerId), id)) { /* updated it... must be Unstable */ it->second.mExtraFlags |= BITDHT_PEER_EXFLAG_UNSTABLE; } } if (mode & BITDHT_PEER_STATUS_RECV_NODES) { /* only update recvTime if sendTime > checkTime.... (then its our query) */ #ifdef DEBUG_QUERY fprintf(stderr, "Updating LastRecvTime\n"); #endif it->second.mLastRecvTime = ts; it->second.mPeerFlags |= mode; } return 1; } } #ifdef DEBUG_QUERY fprintf(stderr, "Peer not in Query\n"); #endif /* firstly drop unresponded (bit ugly - but hard structure to extract from) */ int j; for(j = 0; j < toDrop; j++) { #ifdef DEBUG_QUERY fprintf(stderr, "Dropping Peer that dont reply\n"); #endif bool removed = false; for(it = mClosest.begin(); it != mClosest.end(); ++it) { time_t sendts = ts - it->second.mLastSendTime; bool hasSent = (it->second.mLastSendTime != 0); bool hasReply = (it->second.mLastRecvTime >= it->second.mLastSendTime); if ((hasSent) && (!hasReply) && (sendts > EXPECTED_REPLY)) { #ifdef DEBUG_QUERY fprintf(stderr, "Dropped: "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, "\n"); #endif mClosest.erase(it); removed = true; break ; } } } /* trim it back */ while(mClosest.size() > (uint32_t) (mClosestListSize - 1)) { std::multimap::iterator it; it = mClosest.end(); if (!mClosest.empty()) { it--; #ifdef DEBUG_QUERY fprintf(stderr, "Removing Furthest Peer: "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, "\n"); #endif mClosest.erase(it); } } #ifdef DEBUG_QUERY fprintf(stderr, "bdQuery::addPeer(): Closer Peer!: "); mFns->bdPrintId(std::cerr, id); fprintf(stderr, "\n"); #endif /* add it in */ bdPeer peer; peer.mPeerId = *id; peer.mPeerFlags = mode; peer.mLastSendTime = 0; peer.mLastRecvTime = 0; peer.mFoundTime = ts; if (mode & BITDHT_PEER_STATUS_RECV_NODES) { peer.mLastRecvTime = ts; } mClosest.insert(std::pair(dist, peer)); return 1; } /******************************************************************************************* ********************************* Add Peer Interface ************************************* *******************************************************************************************/ /**** These functions are called by bdNode to add peers to the query * They add/update the three sets of lists. * * int bdQuery::addPeer(const bdId *id, uint32_t mode) * Proper message from a peer. * * int bdQuery::addPotentialPeer(const bdId *id, const bdId *src, uint32_t srcmode) * This returns 1 if worthy of pinging, 0 if to ignore. */ #define PEER_MESSAGE 0 #define FIND_NODE_RESPONSE 1 int bdQuery::addPeer(const bdId *id, uint32_t mode) { addClosestPeer(id, mode); updatePotentialPeer(id, mode, PEER_MESSAGE); updateProxy(id, mode); return 1; } int bdQuery::addPotentialPeer(const bdId *id, const bdId *src, uint32_t srcmode) { // is it a Potential Proxy? Always Check This. addProxy(id, src, srcmode); int worthy = worthyPotentialPeer(id); int shouldPing = 0; if (worthy) { shouldPing = updatePotentialPeer(id, 0, FIND_NODE_RESPONSE); } return shouldPing; } /******************************************************************************************* ********************************* Closest Peer ******************************************** *******************************************************************************************/ /******************************************************************************************* ******************************** Potential Peer ******************************************* *******************************************************************************************/ /******* * Potential Peers are a list of the closest answers to our queries. * Lots of these peers will not be reachable.... so will only exist in this list. * They will also never have there PeerFlags set ;( * */ /*** utility functions ***/ int bdQuery::worthyPotentialPeer(const bdId *id) { bdMetric dist; mFns->bdDistance(&mId, &(id->id), &dist); #ifdef DEBUG_QUERY fprintf(stderr, "bdQuery::addPotentialPeer("); mFns->bdPrintId(std::cerr, id); fprintf(stderr, ", %u)\n", mode); #endif /* we check if this is a worthy potential peer.... * if it is already in mClosest -> false. old peer. * if it is > mClosest.rbegin() -> false. too far way. */ int retval = 1; std::multimap::iterator it, sit, eit; sit = mClosest.lower_bound(dist); eit = mClosest.upper_bound(dist); /* check if outside range, & bucket is full */ if ((sit == mClosest.end()) && (mClosest.size() >= mFns->bdNodesPerBucket())) { #ifdef DEBUG_QUERY fprintf(stderr, "Peer to far away for Potential\n"); #endif return 0; /* too far way */ } for(it = sit; it != eit; it++) { if (mFns->bdSimilarId(id, &(it->second.mPeerId))) { // Not updating Full Peer Id here... as inspection function. #ifdef DEBUG_QUERY fprintf(stderr, "Peer already in mClosest\n"); #endif return 0; } } return 1; /* either within mClosest Range (but not there!), or there aren't enough peers */ } /***** * * mLastSendTime ... is the last FIND_NODE_RESPONSE that we returned 1. (indicating to PING). * mLastRecvTime ... is the last time we received an updatei about/from them * * The update is dependent on the flags passed in the function call. (saves duplicate code). * * * XXX IMPORTANT TO DECIDE WHAT IS RETURNED HERE. * original algorithm return 0 if exists in potential peers, 1 if unknown. * This is used to limit the number of pings to non-responding potentials. * * MUST think about this. Need to install HISTORY tracking again. to look at the statistics. * * It is important that the potential Peers list extends all the way back to == mClosest().end(). * Otherwise we end up with [TARGET] .... [ POTENTIAL ] ..... [ CLOSEST ] ...... * and the gap between POT and CLOSEST will get hammered with pings. * */ #define MIN_PING_POTENTIAL_PERIOD 300 int bdQuery::updatePotentialPeer(const bdId *id, uint32_t mode, uint32_t addType) { bdMetric dist; time_t now = time(NULL); mFns->bdDistance(&mId, &(id->id), &dist); std::multimap::iterator it, sit, eit; sit = mPotentialPeers.lower_bound(dist); eit = mPotentialPeers.upper_bound(dist); bool found = false; for(it = sit; it != eit; it++) { if (mFns->bdSimilarId(id, &(it->second.mPeerId))) { found = true; it->second.mPeerFlags |= mode; it->second.mLastRecvTime = now; if (addType == FIND_NODE_RESPONSE) { // We could lose peers here by not updating port... but should be okay. if (now - it->second.mLastSendTime > MIN_PING_POTENTIAL_PERIOD) { it->second.mLastSendTime = now; return 1; } } else if (mode) { /* also update port from incoming id, as we have definitely recved from it */ if (mFns->bdUpdateSimilarId(&(it->second.mPeerId), id)) { /* updated it... must be Unstable */ it->second.mExtraFlags |= BITDHT_PEER_EXFLAG_UNSTABLE; } } return 0; } } // Removing this check - so that we can have varying length PotentialPeers. // Peer will always be added, then probably removed straight away. #if 0 /* check if outside range, & bucket is full */ if ((sit == mPotentialPeers.end()) && (mPotentialPeers.size() >= mFns->bdNodesPerBucket())) { #ifdef DEBUG_QUERY fprintf(stderr, "Peer to far away for Potential\n"); #endif return 0; } #endif /* add it in */ bdPeer peer; peer.mPeerId = *id; peer.mPeerFlags = mode; peer.mFoundTime = now; peer.mLastRecvTime = now; peer.mLastSendTime = 0; if (addType == FIND_NODE_RESPONSE) { peer.mLastSendTime = now; } mPotentialPeers.insert(std::pair(dist, peer)); #ifdef DEBUG_QUERY fprintf(stderr, "Flagging as Potential Peer!\n"); #endif trimPotentialPeers_toClosest(); return 1; } int bdQuery::trimPotentialPeers_FixedLength() { /* trim it back */ while(mPotentialPeers.size() > (uint32_t) (mFns->bdNodesPerBucket())) { std::multimap::iterator it; it = mPotentialPeers.end(); it--; // must be more than 1 peer here? #ifdef DEBUG_QUERY fprintf(stderr, "Removing Furthest Peer: "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, "\n"); #endif mPotentialPeers.erase(it); } return 1; } int bdQuery::trimPotentialPeers_toClosest() { if (mPotentialPeers.size() <= (uint32_t) (mFns->bdNodesPerBucket())) return 1; std::multimap::reverse_iterator it; it = mClosest.rbegin(); bdMetric lastClosest = it->first; /* trim it back */ while(mPotentialPeers.size() > (uint32_t) (mFns->bdNodesPerBucket())) { std::multimap::iterator it; it = mPotentialPeers.end(); it--; // must be more than 1 peer here? if (lastClosest < it->first) { #ifdef DEBUG_QUERY fprintf(stderr, "Removing Furthest Peer: "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, "\n"); #endif mPotentialPeers.erase(it); } else { return 1; } } return 1; } /******************************************************************************************* ******************************** Potential Proxies **************************************** *******************************************************************************************/ /******** * Potential Proxies. a list of peers that have returned our target in response to a query. * * We are particularly interested in peers with specific flags... * But all the peers have been pinged already by the time they reach this list. * So there are two options: * 1) Track everythings mode history - which is a waste of resources. * 2) Store the list, and ping later. * * We will store these in two lists: Flags & Unknown. * we keep the most recent of each, and move around as required. * * we could also check the Closest/PotentialPeer lists to grab the flags, * for an unknown peer? * * All Functions manipulating PotentialProxies are here. * We need several functions: * * For Extracting Proxies. bool bdQuery::proxies(std::list &answer) bool bdQuery::potentialProxies(std::list &answer) * * For Adding/Updating Proxies. int bdQuery::addProxy(const bdId *id, const bdId *src, uint32_t srcmode) int bdQuery::updateProxy(const bdId *id, uint32_t mode) * */ /*** Two Functions to extract Proxies... ***/ bool bdQuery::proxies(std::list &answer) { /* get all the matches to our query */ std::list::iterator it; int i = 0; for(it = mProxiesFlagged.begin(); it != mProxiesFlagged.end(); it++, i++) { answer.push_back(it->mPeerId); } return (i > 0); } bool bdQuery::potentialProxies(std::list &answer) { /* get all the matches to our query */ std::list::iterator it; int i = 0; for(it = mProxiesUnknown.begin(); it != mProxiesUnknown.end(); it++, i++) { answer.push_back(it->mPeerId); } return (i > 0); } int bdQuery::addProxy(const bdId *id, const bdId *src, uint32_t srcmode) { bdMetric dist; time_t now = time(NULL); mFns->bdDistance(&mId, &(id->id), &dist); /* finally if it is an exact match, add as potential proxy */ int bucket = mFns->bdBucketDistance(&dist); if ((bucket != 0) || (src == NULL)) { /* not a potential proxy */ return 0; } #ifdef DEBUG_QUERY fprintf(stderr, "Bucket = 0, Have Potential Proxy!\n"); #endif bool found = false; if (updateProxyList(src, srcmode, mProxiesUnknown)) { found = true; } if (!found) { if (updateProxyList(src, srcmode, mProxiesFlagged)) { found = true; } } if (!found) { /* if we get here. its not in the list */ #ifdef DEBUG_QUERY fprintf(stderr, "Adding Source to Proxy List:\n"); #endif bdPeer peer; peer.mPeerId = *src; peer.mPeerFlags = srcmode; peer.mLastSendTime = 0; peer.mLastRecvTime = now; peer.mFoundTime = now; /* add it in */ if ((srcmode & mRequiredPeerFlags) == mRequiredPeerFlags) { mProxiesFlagged.push_front(peer); } else { mProxiesUnknown.push_front(peer); } } trimProxies(); return 1; } int bdQuery::updateProxy(const bdId *id, uint32_t mode) { if (!updateProxyList(id, mode, mProxiesUnknown)) { updateProxyList(id, mode, mProxiesFlagged); } trimProxies(); return 1; } /**** Utility functions that do all the work! ****/ int bdQuery::updateProxyList(const bdId *id, uint32_t mode, std::list &searchProxyList) { std::list::iterator it; for(it = searchProxyList.begin(); it != searchProxyList.end(); it++) { if (mFns->bdSimilarId(id, &(it->mPeerId))) { /* found it ;( */ #ifdef DEBUG_QUERY std::cerr << "bdQuery::updateProxyList() Found peer, updating"; std::cerr << std::endl; #endif time_t now = time(NULL); if (mode) { /* also update port from incoming id, as we have definitely recved from it */ if (mFns->bdUpdateSimilarId(&(it->mPeerId), id)) { /* updated it... must be Unstable */ it->mExtraFlags |= BITDHT_PEER_EXFLAG_UNSTABLE; } } it->mPeerFlags |= mode; it->mLastRecvTime = now; /* now move it to the front of required list... * note this could be exactly the same list as &searchProxyList, or a different one! */ bdPeer peer = *it; it = searchProxyList.erase(it); if ((peer.mPeerFlags & mRequiredPeerFlags) == mRequiredPeerFlags) { mProxiesFlagged.push_front(peer); } else { mProxiesUnknown.push_front(peer); } return 1; break; } } return 0; } #define MAX_POTENTIAL_PROXIES 10 int bdQuery::trimProxies() { /* drop excess Potential Proxies */ while(mProxiesUnknown.size() > MAX_POTENTIAL_PROXIES) { mProxiesUnknown.pop_back(); } while(mProxiesFlagged.size() > MAX_POTENTIAL_PROXIES) { mProxiesFlagged.pop_back(); } return 1; } /******************************************************************************************* ******************************** Potential Proxies **************************************** *******************************************************************************************/ /* print query. */ int bdQuery::printQuery() { #ifdef DEBUG_QUERY fprintf(stderr, "bdQuery::printQuery()\n"); #endif time_t ts = time(NULL); fprintf(stderr, "Query for: "); mFns->bdPrintNodeId(std::cerr, &mId); fprintf(stderr, " Query State: %d", mState); fprintf(stderr, " Query Age %ld secs", ts-mQueryTS); if (mState >= BITDHT_QUERY_FAILURE) { fprintf(stderr, " Search Time: %d secs", mSearchTime); } fprintf(stderr, "\n"); #ifdef DEBUG_QUERY fprintf(stderr, "Closest Available Peers:\n"); std::multimap::iterator it; for(it = mClosest.begin(); it != mClosest.end(); it++) { fprintf(stderr, "Id: "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, " Bucket: %d ", mFns->bdBucketDistance(&(it->first))); fprintf(stderr," Found: %ld ago", ts-it->second.mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-it->second.mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-it->second.mLastRecvTime); fprintf(stderr, "\n"); } fprintf(stderr, "\nClosest Potential Peers:\n"); for(it = mPotentialClosest.begin(); it != mPotentialClosest.end(); it++) { fprintf(stderr, "Id: "); mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, " Bucket: %d ", mFns->bdBucketDistance(&(it->first))); fprintf(stderr," Found: %ld ago", ts-it->second.mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-it->second.mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-it->second.mLastRecvTime); fprintf(stderr, "\n"); } std::list::iterator lit; fprintf(stderr, "\nPotential Proxies:\n"); for(lit = mPotentialProxies.begin(); lit != mPotentialProxies.end(); lit++) { fprintf(stderr, "ProxyId: "); mFns->bdPrintId(std::cerr, &(lit->mPeerId)); fprintf(stderr," Found: %ld ago", ts-lit->mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-lit->mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-lit->mLastRecvTime); fprintf(stderr, "\n"); } #else // shortened version. fprintf(stderr, "Closest Available Peer: "); std::multimap::iterator it = mClosest.begin(); if (it != mClosest.end()) { mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, " Bucket: %d ", mFns->bdBucketDistance(&(it->first))); fprintf(stderr," Flags: %x", it->second.mPeerFlags); fprintf(stderr," Found: %ld ago", ts-it->second.mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-it->second.mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-it->second.mLastRecvTime); } fprintf(stderr, "\n"); fprintf(stderr, "Closest Potential Peer: "); it = mPotentialPeers.begin(); if (it != mPotentialPeers.end()) { mFns->bdPrintId(std::cerr, &(it->second.mPeerId)); fprintf(stderr, " Bucket: %d ", mFns->bdBucketDistance(&(it->first))); fprintf(stderr," Flags: %x", it->second.mPeerFlags); fprintf(stderr," Found: %ld ago", ts-it->second.mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-it->second.mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-it->second.mLastRecvTime); } fprintf(stderr, "\n"); std::list::iterator lit; fprintf(stderr, "Flagged Proxies:\n"); for(lit = mProxiesFlagged.begin(); lit != mProxiesFlagged.end(); lit++) { fprintf(stderr, "ProxyId: "); mFns->bdPrintId(std::cerr, &(lit->mPeerId)); fprintf(stderr," Flags: %x", it->second.mPeerFlags); fprintf(stderr," Found: %ld ago", ts-lit->mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-lit->mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-lit->mLastRecvTime); fprintf(stderr, "\n"); } fprintf(stderr, "Potential Proxies:\n"); for(lit = mProxiesUnknown.begin(); lit != mProxiesUnknown.end(); lit++) { fprintf(stderr, "ProxyId: "); mFns->bdPrintId(std::cerr, &(lit->mPeerId)); fprintf(stderr," Flags: %x", it->second.mPeerFlags); fprintf(stderr," Found: %ld ago", ts-lit->mFoundTime); fprintf(stderr," LastSent: %ld ago", ts-lit->mLastSendTime); fprintf(stderr," LastRecv: %ld ago", ts-lit->mLastRecvTime); fprintf(stderr, "\n"); } #endif return 1; } /********************************* Remote Query **************************************/ bdRemoteQuery::bdRemoteQuery(bdId *id, bdNodeId *query, bdToken *transId, uint32_t query_type) :mId(*id), mQuery(*query), mTransId(*transId), mQueryType(query_type) { mQueryTS = time(NULL); }