/* * bitdht/bdnode.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/bdquerymgr.h" #include "bitdht/bdnode.h" #include #include #include #include #include #include #define BITDHT_QUERY_START_PEERS 10 #define BITDHT_QUERY_NEIGHBOUR_PEERS 8 #define BITDHT_MAX_REMOTE_QUERY_AGE 10 /**** * #define DEBUG_NODE_MULTIPEER 1 * #define DEBUG_NODE_MSGS 1 * #define DEBUG_NODE_ACTIONS 1 * #define DEBUG_NODE_MSGIN 1 * #define DEBUG_NODE_MSGOUT 1 ***/ //#define DEBUG_NODE_MSGS 1 bdQueryManager::bdQueryManager(bdSpace *space, bdDhtFunctions *fns, bdNodePublisher *pub) :mNodeSpace(space), mFns(fns), mPub(pub) { } /***** Startup / Shutdown ******/ void bdQueryManager::shutdownQueries() { /* clear the queries */ std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end();it++) { delete (*it); } mLocalQueries.clear(); } void bdQueryManager::printQueries() { std::cerr << "bdQueryManager::printQueries()"; std::cerr << std::endl; int i = 0; std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end(); it++, i++) { fprintf(stderr, "Query #%d:\n", i); (*it)->printQuery(); fprintf(stderr, "\n"); } } int bdQueryManager::iterateQueries(int maxQueries) { #ifdef DEBUG_NODE_MULTIPEER std::cerr << "bdQueryManager::iterateQueries() of Peer: "; mFns->bdPrintNodeId(std::cerr, &mOwnId); std::cerr << std::endl; #endif /* allow each query to send up to one query... until maxMsgs has been reached */ int numQueries = mLocalQueries.size(); int sentQueries = 0; int i = 0; bdId id; bdNodeId targetNodeId; while((i < numQueries) && (sentQueries < maxQueries)) { bdQuery *query = mLocalQueries.front(); mLocalQueries.pop_front(); mLocalQueries.push_back(query); /* go through the possible queries */ if (query->nextQuery(id, targetNodeId)) { #ifdef DEBUG_NODE_MSGS std::cerr << "bdQueryManager::iteration() send_query("; mFns->bdPrintId(std::cerr, &id); std::cerr << ","; mFns->bdPrintNodeId(std::cerr, &targetNodeId); std::cerr << ")"; std::cerr << std::endl; #endif mPub->send_query(&id, &targetNodeId); sentQueries++; } i++; } #ifdef DEBUG_NODE_ACTIONS std::cerr << "bdQueryManager::iteration() maxMsgs: " << maxMsgs << " sentPings: " << sentPings; std::cerr << " / " << allowedPings; std::cerr << " sentQueries: " << sentQueries; std::cerr << " / " << numQueries; std::cerr << std::endl; #endif //printQueries(); return sentQueries; } bool bdQueryManager::checkPotentialPeer(bdId *id, bdId *src) { bool isWorthyPeer = false; /* also push to queries */ std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end(); it++) { if ((*it)->addPotentialPeer(id, src, 0)) { isWorthyPeer = true; } } if (!isWorthyPeer) { isWorthyPeer = checkWorthyPeerSources(src); } return isWorthyPeer; } void bdQueryManager::addPeer(const bdId *id, uint32_t peerflags) { #ifdef DEBUG_NODE_ACTIONS fprintf(stderr, "bdQueryManager::addPeer("); mFns->bdPrintId(std::cerr, id); fprintf(stderr, ")\n"); #endif /* iterate through queries */ std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end(); it++) { (*it)->addPeer(id, peerflags); } } /************************************ Query Details *************************/ void bdQueryManager::addQuery(const bdNodeId *id, uint32_t qflags) { std::list startList; std::multimap nearest; std::multimap::iterator it; mNodeSpace->find_nearest_nodes(id, BITDHT_QUERY_START_PEERS, nearest); #ifdef DEBUG_NODE_ACTIONS fprintf(stderr, "bdQueryManager::addQuery("); mFns->bdPrintNodeId(std::cerr, id); fprintf(stderr, ")\n"); #endif for(it = nearest.begin(); it != nearest.end(); it++) { startList.push_back(it->second); } bdQuery *query = new bdQuery(id, startList, qflags, mFns); mLocalQueries.push_back(query); } void bdQueryManager::clearQuery(const bdNodeId *rmId) { std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end();) { if ((*it)->mId == *rmId) { bdQuery *query = (*it); it = mLocalQueries.erase(it); delete query; } else { it++; } } } void bdQueryManager::QueryStatus(std::map &statusMap) { std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end(); it++) { bdQueryStatus status; status.mStatus = (*it)->mState; status.mQFlags = (*it)->mQueryFlags; (*it)->result(status.mResults); statusMap[(*it)->mId] = status; } } int bdQueryManager::QuerySummary(const bdNodeId *id, bdQuerySummary &query) { std::list::iterator it; for(it = mLocalQueries.begin(); it != mLocalQueries.end(); it++) { if ((*it)->mId == *id) { query.mId = (*it)->mId; query.mLimit = (*it)->mLimit; query.mState = (*it)->mState; query.mQueryTS = (*it)->mQueryTS; query.mQueryFlags = (*it)->mQueryFlags; query.mSearchTime = (*it)->mSearchTime; query.mClosest = (*it)->mClosest; query.mPotentialPeers = (*it)->mPotentialPeers; query.mProxiesUnknown = (*it)->mProxiesUnknown; query.mProxiesFlagged = (*it)->mProxiesFlagged; query.mQueryIdlePeerRetryPeriod = (*it)->mQueryIdlePeerRetryPeriod; return 1; } } return 0; } /* Extract Results from Peer Queries */ #define BDQRYMGR_RESULTS 1 #define BDQRYMGR_PROXIES 2 #define BDQRYMGR_POTPROXIES 3 int bdQueryManager::getResults(bdNodeId *target, std::list &answer, int querytype) { /* grab any peers from any existing query */ int results = 0; std::list::iterator qit; for(qit = mLocalQueries.begin(); qit != mLocalQueries.end(); qit++) { if (!((*qit)->mId == (*target))) { continue; } #ifdef DEBUG_NODE_CONNECTION std::cerr << "bdQueryManager::getResults() Found Matching Query"; std::cerr << std::endl; #endif switch(querytype) { default: case BDQRYMGR_RESULTS: results = (*qit)->result(answer); break; case BDQRYMGR_PROXIES: results = (*qit)->proxies(answer); break; case BDQRYMGR_POTPROXIES: results = (*qit)->potentialProxies(answer); break; } /* will only be one matching query.. so end loop */ return results; } return 0; } int bdQueryManager::result(bdNodeId *target, std::list &answer) { return getResults(target, answer, BDQRYMGR_RESULTS); } int bdQueryManager::proxies(bdNodeId *target, std::list &answer) { return getResults(target, answer, BDQRYMGR_PROXIES); } int bdQueryManager::potentialProxies(bdNodeId *target, std::list &answer) { return getResults(target, answer, BDQRYMGR_POTPROXIES); } /************ WORTHY PEERS **********/ #define MAX_WORTHY_PEER_AGE 15 void bdQueryManager::addWorthyPeerSource(bdId *src) { time_t now = time(NULL); bdPeer peer; peer.mPeerId = *src; peer.mFoundTime = now; #ifdef DEBUG_NODE_ACTIONS std::cerr << "bdQueryManager::addWorthyPeerSource("; mFns->bdPrintId(std::cerr, src); std::cerr << ")" << std::endl; #endif mWorthyPeerSources.push_back(peer); } bool bdQueryManager::checkWorthyPeerSources(bdId *src) { if (!src) return false; time_t now = time(NULL); std::list::iterator it; for(it = mWorthyPeerSources.begin(); it != mWorthyPeerSources.end(); ) { if (now - it->mFoundTime > MAX_WORTHY_PEER_AGE) { #ifdef DEBUG_NODE_ACTIONS std::cerr << "bdQueryManager::checkWorthyPeerSource() Discard old Source: "; mFns->bdPrintId(std::cerr, &(it->mPeerId)); std::cerr << std::endl; #endif it = mWorthyPeerSources.erase(it); } else { if (it->mPeerId == *src) { #ifdef DEBUG_NODE_ACTIONS std::cerr << "bdQueryManager::checkWorthyPeerSource("; mFns->bdPrintId(std::cerr, src); std::cerr << ") = true" << std::endl; #endif return true; } it++; } } return false; }