mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-05-09 09:35:32 -04:00

============================================================ This is intended to be a completely independent library from RS, (hosted at sf.net/projects/bitdht) hence is being commited at the top level. As initial further development / testing will be driven by RS integration it is being added to the RS repository. Equally important is ensuring that RS can compile without requiring aux libraries. Once libbitdht is further developed, this section of the repository is expected to be removed... But that will not be for a while, I expect. drbob. git-svn-id: http://svn.code.sf.net/p/retroshare/code/trunk@3276 b45a01b8-16f6-495d-af2f-9b41ad6348cc
739 lines
15 KiB
C++
739 lines
15 KiB
C++
/*
|
|
* 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 "bdpeer.h"
|
|
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
|
|
/**
|
|
* #define BITDHT_DEBUG 1
|
|
**/
|
|
|
|
bdId::bdId()
|
|
{
|
|
/* blank everything */
|
|
memset(&addr, 0, sizeof(struct sockaddr_in));
|
|
memset(&id.data, 0, BITDHT_KEY_LEN);
|
|
}
|
|
|
|
bdId::bdId(bdNodeId in_id, struct sockaddr_in in_addr)
|
|
{
|
|
addr = in_addr;
|
|
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 1;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
#if 0
|
|
void bdRandomId(bdId *id)
|
|
{
|
|
bdRandomNodeId(&(id->id));
|
|
|
|
id->addr.sin_addr.s_addr = rand();
|
|
id->addr.sin_port = rand();
|
|
|
|
return;
|
|
}
|
|
|
|
void bdRandomNodeId(bdNodeId *id)
|
|
{
|
|
uint32_t *a_data = (uint32_t *) id->data;
|
|
for(int i = 0; i < BITDHT_KEY_INTLEN; i++)
|
|
{
|
|
a_data[i] = rand();
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
/* fills in dbNodeId r, with XOR of a and b */
|
|
int bdDistance(const bdNodeId *a, const bdNodeId *b, bdMetric *r)
|
|
{
|
|
uint8_t *a_data = (uint8_t *) a->data;
|
|
uint8_t *b_data = (uint8_t *) b->data;
|
|
uint8_t *ans = (uint8_t *) r->data;
|
|
for(int i = 0; i < BITDHT_KEY_LEN; i++)
|
|
{
|
|
*(ans++) = *(a_data++) ^ *(b_data++);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void bdRandomMidId(const bdNodeId *target, const bdNodeId *other, bdNodeId *midId)
|
|
{
|
|
bdMetric dist;
|
|
|
|
/* get distance between a & c */
|
|
bdDistance(target, other, &dist);
|
|
|
|
/* generate Random Id */
|
|
bdRandomNodeId(midId);
|
|
|
|
/* zero bits of Random Id until under 1/2 of distance
|
|
* done in bytes for ease... matches one extra byte than distance = 0
|
|
* -> hence wierd order of operations
|
|
*/
|
|
bool done = false;
|
|
for(int i = 0; i < BITDHT_KEY_LEN; i++)
|
|
{
|
|
midId->data[i] = target->data[i];
|
|
|
|
if (dist.data[i] != 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
std::string bdConvertToPrintable(std::string input)
|
|
{
|
|
std::ostringstream out;
|
|
for(uint32_t i = 0; i < input.length(); i++)
|
|
{
|
|
/* sensible chars */
|
|
if ((input[i] > 31) && (input[i] < 127))
|
|
{
|
|
out << input[i];
|
|
}
|
|
else
|
|
{
|
|
out << "[0x" << std::hex << (uint32_t) input[i] << "]";
|
|
out << std::dec;
|
|
}
|
|
}
|
|
return out.str();
|
|
}
|
|
|
|
void bdPrintNodeId(std::ostream &out, const bdNodeId *a)
|
|
{
|
|
for(int i = 0; i < BITDHT_KEY_LEN; i++)
|
|
{
|
|
out << std::setw(2) << std::setfill('0') << std::hex << (uint32_t) (a->data)[i];
|
|
}
|
|
out << std::dec;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void bdPrintId(std::ostream &out, const bdId *a)
|
|
{
|
|
bdPrintNodeId(out, &(a->id));
|
|
out << " ip:" << inet_ntoa(a->addr.sin_addr);
|
|
out << ":" << ntohs(a->addr.sin_port);
|
|
return;
|
|
}
|
|
|
|
/* returns 0-160 depending on bucket */
|
|
int bdBucketDistance(const bdNodeId *a, const bdNodeId *b)
|
|
{
|
|
bdMetric m;
|
|
bdDistance(a, b, &m);
|
|
return bdBucketDistance(&m);
|
|
}
|
|
|
|
/* returns 0-160 depending on bucket */
|
|
int bdBucketDistance(const bdMetric *m)
|
|
{
|
|
for(int i = 0; i < BITDHT_KEY_BITLEN; i++)
|
|
{
|
|
int bit = BITDHT_KEY_BITLEN - i - 1;
|
|
int byte = i / 8;
|
|
int bbit = 7 - (i % 8);
|
|
unsigned char comp = (1 << bbit);
|
|
|
|
#ifdef BITDHT_DEBUG
|
|
fprintf(stderr, "bdBucketDistance: bit:%d byte:%d bbit:%d comp:%x, data:%x\n", bit, byte, bbit, comp, m->data[byte]);
|
|
#endif
|
|
|
|
if (comp & m->data[byte])
|
|
{
|
|
return bit;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
bdBucket::bdBucket()
|
|
{
|
|
return;
|
|
}
|
|
|
|
bdSpace::bdSpace(bdNodeId *ownId, bdDhtFunctions *fns)
|
|
:mOwnId(*ownId), mFns(fns)
|
|
{
|
|
/* make some space for data */
|
|
buckets.resize(mFns->bdNumBuckets());
|
|
return;
|
|
}
|
|
|
|
int bdSpace::find_nearest_nodes(const bdNodeId *id, int number, std::list<bdId> excluding, std::multimap<bdMetric, bdId> &nearest)
|
|
{
|
|
std::multimap<bdMetric, bdId> closest;
|
|
std::multimap<bdMetric, bdId>::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<bdBucket>::iterator it;
|
|
std::list<bdPeer>::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++)
|
|
{
|
|
mFns->bdDistance(id, &(eit->mPeerId.id), &dist);
|
|
closest.insert(std::pair<bdMetric, bdId>(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::out_of_date_peer(bdId &id)
|
|
{
|
|
/*
|
|
*
|
|
*/
|
|
|
|
std::map<bdMetric, bdId> closest;
|
|
std::map<bdMetric, bdId>::iterator mit;
|
|
|
|
std::vector<bdBucket>::iterator it;
|
|
std::list<bdPeer>::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(); eit++)
|
|
{
|
|
/* timeout on last send time! */
|
|
if (ts - eit->mLastSendTime > BITDHT_MAX_SEND_PERIOD )
|
|
{
|
|
id = eit->mPeerId;
|
|
eit->mLastSendTime = ts;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* 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_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<bdPeer>::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++)
|
|
{
|
|
if (*id == it->mPeerId)
|
|
// should check addr too!
|
|
{
|
|
bdPeer peer = *it;
|
|
it = buck.entries.erase(it);
|
|
|
|
peer.mLastRecvTime = ts;
|
|
peer.mPeerFlags |= peerflags; /* must be cumulative ... so can do online, replynodes, etc */
|
|
|
|
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 (peer.mLastRecvTime - ts > 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 = ts; //????
|
|
newPeer.mPeerFlags = peerflags;
|
|
|
|
buck.entries.push_back(newPeer);
|
|
|
|
#ifdef DEBUG_BD_SPACE
|
|
#endif
|
|
/* useful debug */
|
|
std::cerr << "bdSpace::add_peer() Added Bucket[";
|
|
std::cerr << bucket << "] Entry: ";
|
|
mFns->bdPrintId(std::cerr, id);
|
|
std::cerr << std::endl;
|
|
}
|
|
return add;
|
|
}
|
|
|
|
|
|
|
|
/* print tables.
|
|
*/
|
|
|
|
int bdSpace::printDHT()
|
|
{
|
|
std::map<bdMetric, bdId> closest;
|
|
std::map<bdMetric, bdId>::iterator mit;
|
|
|
|
std::vector<bdBucket>::iterator it;
|
|
std::list<bdPeer>::iterator eit;
|
|
|
|
fprintf(stderr, "bdSpace::printDHT()\n");
|
|
/* iterate through the buckets, and sort by distance */
|
|
int i = 0;
|
|
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");
|
|
}
|
|
}
|
|
fprintf(stderr, "--------------------------------------\n");
|
|
fprintf(stderr, "Summary ------------------------------\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)
|
|
fprintf(stderr, "Estimated NetSize >> %llu\n", no_nets);
|
|
}
|
|
else
|
|
{
|
|
#ifdef BITDHT_DEBUG
|
|
if (doPrint)
|
|
fprintf(stderr, " Bucket = Net / >> %llu\n", no_nets);
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
no_peers = no_nets * size;
|
|
if (size)
|
|
{
|
|
if (doPrint)
|
|
fprintf(stderr, "Estimated NetSize = %llu\n", no_peers);
|
|
}
|
|
else
|
|
{
|
|
|
|
#ifdef BITDHT_DEBUG
|
|
if (doPrint)
|
|
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
|
|
{
|
|
fprintf(stderr, "Estimated Network Size = (%llu / %d) = %llu\n", sum, count, sum / count);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|