/* * bitdht/bdpeer.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/bdpeer.h" #include "util/bdnet.h" #include "util/bdrandom.h" #include "util/bdstring.h" #include "bitdht/bdiface.h" #include #include #include #include #include /** * #define BITDHT_DEBUG 1 **/ void bdSockAddrInit(struct sockaddr_in *addr) { memset(addr, 0, sizeof(struct sockaddr_in)); addr->sin_family = AF_INET; } bdId::bdId() { /* blank everything */ bdSockAddrInit(&addr); memset(&id.data, 0, BITDHT_KEY_LEN); } bdId::bdId(bdNodeId in_id, struct sockaddr_in in_addr) { /* this bit is to ensure the address is valid for windows / osx */ bdSockAddrInit(&addr); addr.sin_addr.s_addr = in_addr.sin_addr.s_addr; addr.sin_port = in_addr.sin_port; for(int i = 0; i < BITDHT_KEY_LEN; i++) { id.data[i] = in_id.data[i]; } }; void bdZeroNodeId(bdNodeId *id) { uint32_t *a_data = (uint32_t *) id->data; for(int i = 0; i < BITDHT_KEY_INTLEN; i++) { a_data[i] = 0; } return; } int operator<(const bdNodeId &a, const bdNodeId &b) { #if 0 std::cerr << "operator<("); bdPrintNodeId(std::cerr, &a); std::cerr << ","; bdPrintNodeId(std::cerr, &b); std::cerr << ")" << std::endl; #endif uint8_t *a_data = (uint8_t *) a.data; uint8_t *b_data = (uint8_t *) b.data; for(int i = 0; i < BITDHT_KEY_LEN; i++) { if (*a_data < *b_data) { //fprintf(stderr, "Return 1, at i = %d\n", i); return 1; } else if (*a_data > *b_data) { //fprintf(stderr, "Return 0, at i = %d\n", i); return 0; } a_data++; b_data++; } //fprintf(stderr, "Return 0, at i = KEYLEN\n"); return 0; } #if 0 int operator<(const struct sockaddr_in &a, const struct sockaddr_in &b) { /* else NodeIds the same - check id addresses */ if (a.sin_addr.s_addr < b.sin_addr.s_addr) return 1; if (b.sin_addr.s_addr > a.sin_addr.s_addr) return 0; if (a.sin_port < b.sin_port) return 1; return 0; } #endif int operator<(const bdId &a, const bdId &b) { if (a.id < b.id) return 1; if (b.id < a.id) return 0; /* else NodeIds the same - check id addresses */ if (a.addr.sin_addr.s_addr < b.addr.sin_addr.s_addr) return 1; if (b.addr.sin_addr.s_addr > a.addr.sin_addr.s_addr) return 0; if (a.addr.sin_port < b.addr.sin_port) return 1; return 0; } int operator==(const bdNodeId &a, const bdNodeId &b) { uint8_t *a_data = (uint8_t *) a.data; uint8_t *b_data = (uint8_t *) b.data; for(int i = 0; i < BITDHT_KEY_LEN; i++) { if (*a_data < *b_data) { return 0; } else if (*a_data > *b_data) { return 0; } a_data++; b_data++; } return 1; } int operator==(const bdId &a, const bdId &b) { if (!(a.id == b.id)) return 0; if ((a.addr.sin_addr.s_addr == b.addr.sin_addr.s_addr) && (a.addr.sin_port == b.addr.sin_port)) { return 1; } return 0; } bdBucket::bdBucket() { return; } bdSpace::bdSpace(bdNodeId *ownId, bdDhtFunctions *fns) :mOwnId(*ownId), mFns(fns) { /* make some space for data */ buckets.resize(mFns->bdNumBuckets()); mAttachTS = 0; mAttachedFlags = 0; mAttachedCount = 0; return; } /* empty the buckets */ int bdSpace::clear() { std::vector::iterator it; /* iterate through the buckets, and sort by distance */ for(it = buckets.begin(); it != buckets.end(); it++) { it->entries.clear(); } return 1; } int bdSpace::setAttachedFlag(uint32_t withflags, int count) { mAttachedFlags = withflags; mAttachedCount = count; mAttachTS = 0; return 1; } int bdSpace::find_nearest_nodes_with_flags(const bdNodeId *id, int number, std::list /* excluding */, std::multimap &nearest, uint32_t with_flags) { std::multimap closest; std::multimap::iterator mit; bdMetric dist; mFns->bdDistance(id, &(mOwnId), &dist); #ifdef DEBUG_BD_SPACE int bucket = mFns->bdBucketDistance(&dist); std::cerr << "bdSpace::find_nearest_nodes(NodeId:"; mFns->bdPrintNodeId(std::cerr, id); std::cerr << " Number: " << number; std::cerr << " Query Bucket #: " << bucket; std::cerr << std::endl; #endif std::vector::iterator it; std::list::iterator eit; /* iterate through the buckets, and sort by distance */ for(it = buckets.begin(); it != buckets.end(); it++) { for(eit = it->entries.begin(); eit != it->entries.end(); eit++) { if ((!with_flags) || ((with_flags & eit->mPeerFlags) == with_flags)) { mFns->bdDistance(id, &(eit->mPeerId.id), &dist); closest.insert(std::pair(dist, eit->mPeerId)); #if 0 std::cerr << "Added NodeId: "; bdPrintNodeId(std::cerr, &(eit->mPeerId.id)); std::cerr << " Metric: "; bdPrintNodeId(std::cerr, &(dist)); std::cerr << std::endl; #endif } } } /* take the first number of nodes */ int i = 0; for(mit = closest.begin(); (mit != closest.end()) && (i < number); mit++, i++) { mFns->bdDistance(&(mOwnId), &(mit->second.id), &dist); #ifdef DEBUG_BD_SPACE int iBucket = mFns->bdBucketDistance(&(mit->first)); std::cerr << "Closest " << i << ": "; mFns->bdPrintNodeId(std::cerr, &(mit->second.id)); std::cerr << " Bucket: " << iBucket; std::cerr << std::endl; #endif #if 0 std::cerr << "\tNodeId: "; mFns->bdPrintNodeId(std::cerr, &(mit->second.id)); std::cerr << std::endl; std::cerr << "\tOwn Id: "; mFns->bdPrintNodeId(std::cerr, &(mOwnId)); std::cerr << std::endl; std::cerr << " Us Metric: "; mFns->bdPrintNodeId(std::cerr, &dist); std::cerr << " Bucket: " << oBucket; std::cerr << std::endl; std::cerr << "\tFindId: "; mFns->bdPrintNodeId(std::cerr, id); std::cerr << std::endl; std::cerr << " Id Metric: "; mFns->bdPrintNodeId(std::cerr, &(mit->first)); std::cerr << " Bucket: " << iBucket; std::cerr << std::endl; #endif nearest.insert(*mit); } #ifdef DEBUG_BD_SPACE std::cerr << "#Nearest: " << (int) nearest.size(); std::cerr << " #Closest: " << (int) closest.size(); std::cerr << " #Requested: " << number; std::cerr << std::endl << std::endl; #endif return 1; } int bdSpace::find_nearest_nodes(const bdNodeId *id, int number, std::multimap &nearest) { std::list excluding; uint32_t with_flag = 0; return find_nearest_nodes_with_flags(id, number, excluding, nearest, with_flag); } /* This is much cheaper than find nearest... we only look in the one bucket */ int bdSpace::find_node(const bdNodeId *id, int number, std::list &matchIds, uint32_t with_flags) { bdMetric dist; mFns->bdDistance(id, &(mOwnId), &dist); int buckno = mFns->bdBucketDistance(&dist); #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_node(NodeId:"; mFns->bdPrintNodeId(std::cerr, id); std::cerr << ")"; std::cerr << " Number: " << number; std::cerr << " Bucket #: " << buckno; std::cerr << std::endl; #else (void)number; #endif bdBucket &buck = buckets[buckno]; std::list::iterator eit; int matchCount = 0; for(eit = buck.entries.begin(); eit != buck.entries.end(); eit++) { #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_node() Checking Against Peer: "; mFns->bdPrintId(std::cerr, &(eit->mPeerId)); std::cerr << " withFlags: " << eit->mPeerFlags; std::cerr << std::endl; #endif if ((!with_flags) || ((with_flags & eit->mPeerFlags) == with_flags)) { if (*id == eit->mPeerId.id) { matchIds.push_back(eit->mPeerId); matchCount++; #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_node() Found Matching Peer: "; mFns->bdPrintId(std::cerr, &(eit->mPeerId)); std::cerr << " withFlags: " << eit->mPeerFlags; std::cerr << std::endl; #endif } } else { if (*id == eit->mPeerId.id) { //matchIds.push_back(eit->mPeerId); //matchCount++; #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_node() Found (WITHOUT FLAGS) Matching Peer: "; mFns->bdPrintId(std::cerr, &(eit->mPeerId)); std::cerr << " withFlags: " << eit->mPeerFlags; std::cerr << std::endl; #endif } } } #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_node() Found " << matchCount << " Matching Peers"; std::cerr << std::endl << std::endl; #endif return matchCount; } /* even cheaper again... no big lists */ int bdSpace::find_exactnode(const bdId *id, bdPeer &peer) { bdMetric dist; mFns->bdDistance(&(id->id), &(mOwnId), &dist); int buckno = mFns->bdBucketDistance(&dist); #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_exactnode(Id:"; mFns->bdPrintId(std::cerr, id); std::cerr << ")"; std::cerr << " Bucket #: " << buckno; std::cerr << std::endl; #endif bdBucket &buck = buckets[buckno]; std::list::iterator eit; for(eit = buck.entries.begin(); eit != buck.entries.end(); eit++) { if (*id == eit->mPeerId) { #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_exactnode() Found Matching Peer: "; mFns->bdPrintId(std::cerr, &(eit->mPeerId)); std::cerr << " withFlags: " << eit->mPeerFlags; std::cerr << std::endl; #endif peer = (*eit); return 1; } } #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::find_exactnode() WARNING Failed to find Matching Peer: "; std::cerr << std::endl; #endif return 0; } int bdSpace::clean_node_flags(uint32_t flags) { std::cerr << "bdSpace::clean_node_flags(" << flags << ")"; std::cerr << std::endl; int count = 0; std::vector::iterator bit; for(bit = buckets.begin(); bit != buckets.end(); bit++) { std::list::iterator eit; for(eit = bit->entries.begin(); eit != bit->entries.end(); eit++) { if (flags & eit->mPeerFlags) { #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::clean_node_flags() Found Match: "; mFns->bdPrintId(std::cerr, &(eit->mPeerId)); std::cerr << " withFlags: " << eit->mPeerFlags; std::cerr << std::endl; #endif count++; eit->mPeerFlags &= ~flags; } } } #ifdef DEBUG_BD_SPACE std::cerr << "bdSpace::clean_node_flags() Cleaned " << count << " Matching Peers"; std::cerr << std::endl; #endif return count; } #define BITDHT_ATTACHED_SEND_PERIOD 17 int bdSpace::scanOutOfDatePeers(std::list &peerIds) { /* * */ bool doAttached = (mAttachedCount > 0); uint32_t attachedCount = 0; std::map closest; std::map::iterator mit; std::vector::iterator it; std::list::iterator eit; time_t ts = time(NULL); /* iterate through the buckets, and sort by distance */ for(it = buckets.begin(); it != buckets.end(); it++) { for(eit = it->entries.begin(); eit != it->entries.end(); ) { bool added = false; if (doAttached) { if (eit->mExtraFlags & BITDHT_PEER_EXFLAG_ATTACHED) { /* add to send list, if we haven't pinged recently */ if ((ts - eit->mLastSendTime > BITDHT_ATTACHED_SEND_PERIOD ) && (ts - eit->mLastRecvTime > BITDHT_ATTACHED_SEND_PERIOD )) { peerIds.push_back(eit->mPeerId); eit->mLastSendTime = ts; added = true; } attachedCount++; } } /* timeout on last send time! */ if ((!added) && (ts - eit->mLastSendTime > BITDHT_MAX_SEND_PERIOD )) { /* We want to ping a peer iff: * 1) They are out-of-date: mLastRecvTime is too old. * 2) They don't have 0x0001 flag (we haven't received a PONG) and never sent. */ if ((ts - eit->mLastRecvTime > BITDHT_MAX_SEND_PERIOD ) || !(eit->mPeerFlags & BITDHT_PEER_STATUS_RECV_PONG)) { peerIds.push_back(eit->mPeerId); eit->mLastSendTime = ts; } } /* we also want to remove very old entries (should it happen here?) * which are not pushed out by newer entries (will happen in for closer buckets) */ bool discard = false; /* discard very old entries */ if (ts - eit->mLastRecvTime > BITDHT_DISCARD_PERIOD) { discard = true; } /* discard peers which have not responded to anything (ie have no flags set) */ /* changed into have not id'ed themselves, as we've added ping to list of flags. */ if ((ts - eit->mFoundTime > BITDHT_MAX_RESPONSE_PERIOD ) && !(eit->mPeerFlags & BITDHT_PEER_STATUS_RECV_PONG)) { discard = true; } /* INCREMENT */ if (discard) { eit = it->entries.erase(eit); } else { eit++; } } } #define ATTACH_UPDATE_PERIOD 600 if ((ts - mAttachTS > ATTACH_UPDATE_PERIOD) || (attachedCount != mAttachedCount)) { //std::cerr << "Updating ATTACH Stuff"; //std::cerr << std::endl; updateAttachedPeers(); /* XXX TEMP HACK to look at stability */ mAttachTS = ts; } return (peerIds.size()); } /* Attached should be changed to preferentially choose the ones we want * If we have RELAYS enabled - then we want them to attach to the RELAYS * Not sure about this yet! * * Have to think about it a bit more. (and redesign code to handle multiple passes) */ int bdSpace::updateAttachedPeers() { /* * */ bool doAttached = (mAttachedCount > 0); uint32_t attachedCount = 0; // Must scan through - otherwise we can never remove Attached state. // It is only once every 10 minutes or so! #if 0 if (!doAttached) { return 0; } #endif std::map closest; std::map::iterator mit; std::vector::iterator it; std::list::reverse_iterator eit; /* skip the first bucket, as we don't want to ping ourselves! */ it = buckets.begin(); if (it != buckets.end()) { it++; } /* iterate through the buckets (sorted by distance) */ for(; it != buckets.end(); it++) { /* start from the back, as these are the most recently seen (and more likely to be the old ATTACHED) */ for(eit = it->entries.rbegin(); eit != it->entries.rend(); eit++) { if (doAttached) { if ((eit->mPeerFlags & mAttachedFlags) == mAttachedFlags) { /* flag as attached */ eit->mExtraFlags |= BITDHT_PEER_EXFLAG_ATTACHED; /* inc count, and cancel search if we've found them */ attachedCount++; if (attachedCount >= mAttachedCount) { doAttached = false; } } else { eit->mExtraFlags &= ~BITDHT_PEER_EXFLAG_ATTACHED; } } else { eit->mExtraFlags &= ~BITDHT_PEER_EXFLAG_ATTACHED; } } } return 1; } /* Called to add or update peer. * sorts bucket lists by lastRecvTime. * updates requested node. */ /* peer flags * order is important! * higher bits = more priority. * BITDHT_PEER_STATUS_RECVPING * BITDHT_PEER_STATUS_RECVPONG * BITDHT_PEER_STATUS_RECVNODES * BITDHT_PEER_STATUS_RECVHASHES * BITDHT_PEER_STATUS_DHT_ENGINE (dbXXxx) * BITDHT_PEER_STATUS_DHT_APPL (XXRSxx) * BITDHT_PEER_STATUS_DHT_VERSION (XXxx50) * */ int bdSpace::add_peer(const bdId *id, uint32_t peerflags) { /* find the peer */ bool add = false; time_t ts = time(NULL); #ifdef DEBUG_BD_SPACE fprintf(stderr, "bdSpace::add_peer()\n"); #endif /* calculate metric */ bdMetric met; mFns->bdDistance(&(mOwnId), &(id->id), &met); int bucket = mFns->bdBucketDistance(&met); #ifdef DEBUG_BD_SPACE fprintf(stderr, "peer:"); mFns->bdPrintId(std::cerr, id); fprintf(stderr, " bucket: %d", bucket); fprintf(stderr, "\n"); #endif /* select correct bucket */ bdBucket &buck = buckets[bucket]; std::list::iterator it; /* calculate the score for this new peer */ uint32_t minScore = peerflags; /* loop through ids, to find it */ for(it = buck.entries.begin(); it != buck.entries.end(); it++) { /* similar id check */ if (mFns->bdSimilarId(id, &(it->mPeerId))) { bdPeer peer = *it; it = buck.entries.erase(it); peer.mLastRecvTime = ts; peer.mPeerFlags |= peerflags; /* must be cumulative ... so can do online, replynodes, etc */ /* also update port from incoming id, as we have definitely recved from it */ if (mFns->bdUpdateSimilarId(&(peer.mPeerId), id)) { /* updated it... must be Unstable */ peer.mExtraFlags |= BITDHT_PEER_EXFLAG_UNSTABLE; } buck.entries.push_back(peer); #ifdef DEBUG_BD_SPACE std::cerr << "Peer already in bucket: moving to back of the list" << std::endl; #endif return 1; } /* find lowest score */ if (it->mPeerFlags < minScore) { minScore = it->mPeerFlags; } } /* not in the list! */ if (buck.entries.size() < mFns->bdNodesPerBucket()) { #ifdef DEBUG_BD_SPACE std::cerr << "Bucket not full: allowing add" << std::endl; #endif add = true; } else { /* check head of list */ bdPeer &peer = buck.entries.front(); if (ts - peer.mLastRecvTime > BITDHT_MAX_RECV_PERIOD) { #ifdef DEBUG_BD_SPACE std::cerr << "Dropping Out-of-Date peer in bucket" << std::endl; #endif buck.entries.pop_front(); add = true; } else if (peerflags > minScore) { /* find one to drop */ for(it = buck.entries.begin(); it != buck.entries.end(); it++) { if (it->mPeerFlags == minScore) { /* delete low priority peer */ it = buck.entries.erase(it); add = true; break; } } #ifdef DEBUG_BD_SPACE std::cerr << "Inserting due to Priority: minScore: " << minScore << " new Peer Score: " << peerscore << << std::endl; #endif } else { #ifdef DEBUG_BD_SPACE std::cerr << "No Out-Of-Date peers in bucket... dropping new entry" << std::endl; #endif } } if (add) { bdPeer newPeer; newPeer.mPeerId = *id; newPeer.mLastRecvTime = ts; newPeer.mLastSendTime = 0; // ts; //???? newPeer.mFoundTime = ts; newPeer.mPeerFlags = peerflags; newPeer.mExtraFlags = 0; buck.entries.push_back(newPeer); #ifdef DEBUG_BD_SPACE /* useful debug */ std::cerr << "bdSpace::add_peer() Added Bucket["; std::cerr << bucket << "] Entry: "; mFns->bdPrintId(std::cerr, id); std::cerr << std::endl; #endif } return add; } /* flag peer */ bool bdSpace::flagpeer(const bdId *id, uint32_t flags, uint32_t ex_flags) { #ifdef DEBUG_BD_SPACE fprintf(stderr, "bdSpace::flagpeer()\n"); #endif /* calculate metric */ bdMetric met; mFns->bdDistance(&(mOwnId), &(id->id), &met); int bucket = mFns->bdBucketDistance(&met); /* select correct bucket */ bdBucket &buck = buckets[bucket]; /* loop through ids, to find it */ std::list::iterator it; for(it = buck.entries.begin(); it != buck.entries.end(); it++) { /* similar id check */ if (mFns->bdSimilarId(id, &(it->mPeerId))) { #ifdef DEBUG_BD_SPACE fprintf(stderr, "peer:"); mFns->bdPrintId(std::cerr, id); fprintf(stderr, " bucket: %d", bucket); fprintf(stderr, "\n"); fprintf(stderr, "Original Flags: %x Extra: %x\n", it->mPeerFlags, it->mExtraFlags); #endif it->mPeerFlags |= flags; it->mExtraFlags |= ex_flags; #ifdef DEBUG_BD_SPACE fprintf(stderr, "Updated Flags: %x Extra: %x\n", it->mPeerFlags, it->mExtraFlags); #endif } } return true; } /* print tables. */ int bdSpace::printDHT() { std::map closest; std::map::iterator mit; std::vector::iterator it; std::list::iterator eit; /* iterate through the buckets, and sort by distance */ int i = 0; #ifdef BITDHT_DEBUG fprintf(stderr, "bdSpace::printDHT()\n"); for(it = buckets.begin(); it != buckets.end(); it++, i++) { if (it->entries.size() > 0) { fprintf(stderr, "Bucket %d ----------------------------\n", i); } for(eit = it->entries.begin(); eit != it->entries.end(); eit++) { bdMetric dist; mFns->bdDistance(&(mOwnId), &(eit->mPeerId.id), &dist); fprintf(stderr, " Metric: "); mFns->bdPrintNodeId(std::cerr, &(dist)); fprintf(stderr, " Id: "); mFns->bdPrintId(std::cerr, &(eit->mPeerId)); fprintf(stderr, " PeerFlags: %08x", eit->mPeerFlags); fprintf(stderr, "\n"); } } #endif fprintf(stderr, "--------------------------------------\n"); fprintf(stderr, "DHT Table Summary --------------------\n"); fprintf(stderr, "--------------------------------------\n"); /* little summary */ unsigned long long sum = 0; unsigned long long no_peers = 0; uint32_t count = 0; bool doPrint = false; bool doAvg = false; i = 0; for(it = buckets.begin(); it != buckets.end(); it++, i++) { int size = it->entries.size(); int shift = BITDHT_KEY_BITLEN - i; bool toBig = false; if (shift > BITDHT_ULLONG_BITS - mFns->bdBucketBitSize() - 1) { toBig = true; shift = BITDHT_ULLONG_BITS - mFns->bdBucketBitSize() - 1; } unsigned long long no_nets = ((unsigned long long) 1 << shift); /* use doPrint so it acts as a single switch */ if (size && !doAvg && !doPrint) { doAvg = true; } if (size && !doPrint) { doPrint = true; } if (size == 0) { /* reset counters - if empty slot - to discount outliers in average */ sum = 0; no_peers = 0; count = 0; } if (doPrint) { if (size) fprintf(stderr, "Bucket %d: %d peers: ", i, size); #ifdef BITDHT_DEBUG else fprintf(stderr, "Bucket %d: %d peers: ", i, size); #endif } if (toBig) { if (size) { if (doPrint) bd_fprintf(stderr, "Estimated NetSize >> %llu\n", no_nets); } else { #ifdef BITDHT_DEBUG if (doPrint) bd_fprintf(stderr, " Bucket = Net / >> %llu\n", no_nets); #endif } } else { no_peers = no_nets * size; if (size) { if (doPrint) bd_fprintf(stderr, "Estimated NetSize = %llu\n", no_peers); } else { #ifdef BITDHT_DEBUG if (doPrint) bd_fprintf(stderr, " Bucket = Net / %llu\n", no_nets); #endif } } if (doPrint && doAvg && !toBig) { if (size == mFns->bdNodesPerBucket()) { /* last average */ doAvg = false; } if (no_peers != 0) { sum += no_peers; count++; #ifdef BITDHT_DEBUG fprintf(stderr, "Est: %d: %llu => %llu / %d\n", i, no_peers, sum, count); #endif } } } if (count == 0) { fprintf(stderr, "Zero Network Size (count = 0)\n"); } else { bd_fprintf(stderr, "Estimated Network Size = (%llu / %d) = %llu\n", sum, count, sum / count); } return 1; } int bdSpace::getDhtBucket(const int idx, bdBucket &bucket) { if ((idx < 0) || (idx > (int) buckets.size() - 1 )) { return 0; } bucket = buckets[idx]; return 1; } uint32_t bdSpace::calcNetworkSize() { std::vector::iterator it; /* little summary */ unsigned long long sum = 0; unsigned long long no_peers = 0; uint32_t count = 0; bool doPrint = false; bool doAvg = false; int i = 0; for(it = buckets.begin(); it != buckets.end(); it++, i++) { int size = it->entries.size(); int shift = BITDHT_KEY_BITLEN - i; bool toBig = false; if (shift > BITDHT_ULLONG_BITS - mFns->bdBucketBitSize() - 1) { toBig = true; shift = BITDHT_ULLONG_BITS - mFns->bdBucketBitSize() - 1; } unsigned long long no_nets = ((unsigned long long) 1 << shift); /* use doPrint so it acts as a single switch */ if (size && !doAvg && !doPrint) { doAvg = true; } if (size && !doPrint) { doPrint = true; } if (size == 0) { /* reset counters - if empty slot - to discount outliers in average */ sum = 0; no_peers = 0; count = 0; } if (!toBig) { no_peers = no_nets * size; } if (doPrint && doAvg && !toBig) { if (size == mFns->bdNodesPerBucket()) { /* last average */ doAvg = false; } if (no_peers != 0) { sum += no_peers; count++; } } } uint32_t NetSize = 0; if (count != 0) { NetSize = sum / count; } //std::cerr << "bdSpace::calcNetworkSize() : " << NetSize; //std::cerr << std::endl; return NetSize; } uint32_t bdSpace::calcNetworkSizeWithFlag(uint32_t withFlag) { std::vector::iterator it; /* little summary */ unsigned long long sum = 0; unsigned long long no_peers = 0; uint32_t count = 0; uint32_t totalcount = 0; bool doPrint = false; bool doAvg = false; int i = 0; for(it = buckets.begin(); it != buckets.end(); it++, i++) { int size = 0; std::list::iterator lit; for(lit = it->entries.begin(); lit != it->entries.end(); lit++) { if (withFlag & lit->mPeerFlags) { size++; } } totalcount += size; int shift = BITDHT_KEY_BITLEN - i; bool toBig = false; if (shift > BITDHT_ULLONG_BITS - mFns->bdBucketBitSize() - 1) { toBig = true; shift = BITDHT_ULLONG_BITS - mFns->bdBucketBitSize() - 1; } unsigned long long no_nets = ((unsigned long long) 1 << shift); /* use doPrint so it acts as a single switch */ if (size && !doAvg && !doPrint) { doAvg = true; } if (size && !doPrint) { doPrint = true; } if (size == 0) { /* reset counters - if empty slot - to discount outliers in average */ sum = 0; no_peers = 0; count = 0; } if (!toBig) { no_peers = no_nets * size; } if (doPrint && doAvg && !toBig) { if (size == mFns->bdNodesPerBucket()) { /* last average */ doAvg = false; } if (no_peers != 0) { sum += no_peers; count++; } } } uint32_t NetSize = 0; if (count != 0) { NetSize = sum / count; } //std::cerr << "bdSpace::calcNetworkSize() : " << NetSize; //std::cerr << std::endl; return NetSize; } uint32_t bdSpace::calcSpaceSize() { std::vector::iterator it; /* little summary */ uint32_t totalcount = 0; for(it = buckets.begin(); it != buckets.end(); it++) { totalcount += it->entries.size(); } return totalcount; } uint32_t bdSpace::calcSpaceSizeWithFlag(uint32_t withFlag) { std::vector::iterator it; /* little summary */ uint32_t totalcount = 0; it = buckets.begin(); if (it != buckets.end()) { it++; /* skip own bucket! */ } for(; it != buckets.end(); it++) { int size = 0; std::list::iterator lit; for(lit = it->entries.begin(); lit != it->entries.end(); lit++) { if (withFlag & lit->mPeerFlags) { size++; } } totalcount += size; } return totalcount; } /* special function to enable DHT localisation (i.e find peers from own network) */ bool bdSpace::findRandomPeerWithFlag(bdId &id, uint32_t withFlag) { std::vector::iterator it; uint32_t totalcount = calcSpaceSizeWithFlag(withFlag); if(totalcount == 0) return false ; uint32_t rnd = bdRandom::random_u32() % totalcount; uint32_t i = 0; uint32_t buck = 0; //std::cerr << "bdSpace::findRandomPeerWithFlag()"; //std::cerr << std::endl; it = buckets.begin(); if (it != buckets.end()) { it++; /* skip own bucket! */ buck++; } for(; it != buckets.end(); it++, buck++) { std::list::iterator lit; for(lit = it->entries.begin(); lit != it->entries.end(); lit++) { if (withFlag & lit->mPeerFlags) { if (i == rnd) { #ifdef BITDHT_DEBUG std::cerr << "bdSpace::findRandomPeerWithFlag() found #" << i; std::cerr << " in bucket #" << buck; std::cerr << std::endl; #endif /* found */ id = lit->mPeerId; return true; } i++; } } } std::cerr << "bdSpace::findRandomPeerWithFlag() failed to find " << rnd << " / " << totalcount; std::cerr << std::endl; #ifdef BITDHT_DEBUG #endif return false; }