seeder/db.h

202 lines
6.1 KiB
C
Raw Normal View History

2011-12-16 18:37:05 +01:00
#include <stdint.h>
2011-12-19 23:18:06 +01:00
#include <math.h>
2011-12-16 18:37:05 +01:00
#include <set>
#include <map>
#include <vector>
#include <deque>
#include "netbase.h"
#include "protocol.h"
#include "util.h"
2011-12-19 23:18:06 +01:00
#define TAU 86400.0
2011-12-20 05:20:50 +01:00
#define MIN_RETRY 1000
2011-12-19 23:18:06 +01:00
2011-12-20 14:29:21 +01:00
std::string static inline ToString(const CIPPort &ip) {
std::string str = ip.ToString();
while (str.size() < 22) str += ' ';
return str;
}
2011-12-16 18:37:05 +01:00
class CAddrInfo {
private:
2011-12-19 23:18:06 +01:00
CIPPort ip;
2011-12-16 18:37:05 +01:00
uint64_t services;
2011-12-20 08:35:22 +01:00
int64 lastTry;
int64 ourLastTry;
2011-12-19 23:18:06 +01:00
double reliability;
double timing;
2011-12-16 18:37:05 +01:00
double weight;
2011-12-19 23:18:06 +01:00
double count;
int total;
int success;
public:
2011-12-20 14:29:21 +01:00
double GetCount() const { return count; }
double GetAvgAge() const { return timing/weight; }
double GetReliability() const { return reliability/weight; }
2011-12-19 23:18:06 +01:00
bool IsGood() {
2011-12-20 14:29:21 +01:00
return (weight > 0 && GetReliability() > 0.8 && GetAvgAge() < 86400 && ip.GetPort() == 8333 && ip.IsRoutable());
2011-12-19 23:18:06 +01:00
}
bool IsTerrible() {
2011-12-20 14:29:21 +01:00
return ((weight > 0.1 && GetCount() > 5 && GetReliability() < 0.05) || (weight > 0.5 && GetReliability() < 0.2 && GetAvgAge() > 7200 && GetCount() > 5));
2011-12-19 23:18:06 +01:00
}
2011-12-19 23:45:18 +01:00
void Update(bool good);
2011-12-19 23:18:06 +01:00
friend class CAddrDb;
2011-12-20 08:35:22 +01:00
IMPLEMENT_SERIALIZE (
int version = 0;
READWRITE(version);
READWRITE(ip);
READWRITE(services);
READWRITE(lastTry);
READWRITE(ourLastTry);
READWRITE(reliability);
READWRITE(timing);
READWRITE(weight);
READWRITE(count);
READWRITE(total);
READWRITE(success);
)
2011-12-19 23:18:06 +01:00
};
2011-12-16 18:37:05 +01:00
2011-12-16 18:51:45 +01:00
// seen nodes
// / \
2011-12-20 14:29:21 +01:00
// (a) banned nodes available nodes--------------
// / | \
// tracked nodes (b) unknown nodes (e) active nodes
2011-12-16 18:51:45 +01:00
// / \
// (d) good nodes (c) non-good nodes
2011-12-16 18:37:05 +01:00
class CAddrDb {
private:
2011-12-20 08:35:22 +01:00
mutable CCriticalSection cs;
2011-12-16 18:37:05 +01:00
int nId; // number of address id's
2011-12-20 14:29:21 +01:00
std::map<int, CAddrInfo> idToInfo; // map address id to address info (b,c,d,e)
std::map<CIPPort, int> ipToId; // map ip to id (b,c,d,e)
2011-12-19 23:18:06 +01:00
std::deque<int> ourId; // sequence of tried nodes, in order we have tried connecting to them (c,d)
std::set<int> unkId; // set of nodes not yet tried (b)
2011-12-20 14:29:21 +01:00
std::set<int> goodId; // set of good nodes (d, good e)
2011-12-19 23:18:06 +01:00
std::map<CIPPort, time_t> banned; // nodes that are banned, with their unban time (a)
2011-12-20 14:29:21 +01:00
bool fDirty;
2011-12-16 18:37:05 +01:00
2011-12-19 23:18:06 +01:00
protected:
2011-12-20 14:29:21 +01:00
// internal routines that assume proper locks are acquired
void Add_(const CAddress &addr); // add an address
bool Get_(CIPPort &ip, int& wait); // get an IP to test (must call Good_, Bad_, or Skipped_ on result afterwards)
void Good_(const CIPPort &ip); // mark an IP as good (must have been returned by Get_)
void Bad_(const CIPPort &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_)
void Skipped_(const CIPPort &ip); // mark an IP as skipped (must have been returned by Get_)
int Lookup_(const CIPPort &ip); // look up id of an IP
void GetIPs_(std::set<CIP>& ips, int max, bool fOnlyIPv4); // get a random set of IPs (shared lock only)
2011-12-16 18:37:05 +01:00
2011-12-19 23:18:06 +01:00
public:
2011-12-20 08:35:22 +01:00
2011-12-20 14:29:21 +01:00
// seriazlization code
// format:
// nVersion (0 for now)
// nOur (number of ips in (c,d))
// nUnk (number of ips in (b))
// CAddrInfo[nOur]
// CAddrInfo[nUnk]
// banned
// acquires a shared lock (this does not suffice for read mode, but we assume that only happens at startup, single-threaded)
// this way, dumping does not interfere with GetIPs_, which is called from the DNS thread
2011-12-20 08:35:22 +01:00
IMPLEMENT_SERIALIZE (({
int nVersion = 0;
READWRITE(nVersion);
2011-12-20 09:31:28 +01:00
SHARED_CRITICAL_BLOCK(cs) {
2011-12-20 08:35:22 +01:00
if (fWrite) {
CAddrDb *db = const_cast<CAddrDb*>(this);
int nOur = ourId.size();
int nUnk = unkId.size();
READWRITE(nOur);
READWRITE(nUnk);
for (std::deque<int>::const_iterator it = ourId.begin(); it != ourId.end(); it++) {
std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it);
READWRITE((*ci).second);
}
for (std::set<int>::const_iterator it = unkId.begin(); it != unkId.end(); it++) {
std::map<int, CAddrInfo>::iterator ci = db->idToInfo.find(*it);
READWRITE((*ci).second);
}
} else {
CAddrDb *db = const_cast<CAddrDb*>(this);
db->nId = 0;
int nOur, nUnk;
READWRITE(nOur);
READWRITE(nUnk);
for (int i=0; i<nOur; i++) {
CAddrInfo info;
READWRITE(info);
2011-12-20 14:29:21 +01:00
if (!info.IsTerrible()) {
int id = db->nId++;
db->idToInfo[id] = info;
db->ipToId[info.ip] = id;
db->ourId.push_back(id);
if (info.IsGood()) db->goodId.insert(id);
}
2011-12-20 08:35:22 +01:00
}
for (int i=0; i<nUnk; i++) {
CAddrInfo info;
READWRITE(info);
2011-12-20 14:29:21 +01:00
if (!info.IsTerrible()) {
int id = db->nId++;
db->idToInfo[id] = info;
db->ipToId[info.ip] = id;
db->unkId.insert(id);
}
2011-12-20 08:35:22 +01:00
}
2011-12-20 14:29:21 +01:00
db->fDirty = true;
2011-12-20 08:35:22 +01:00
}
READWRITE(banned);
}
});)
2011-12-20 14:29:21 +01:00
// print statistics
2011-12-20 05:20:50 +01:00
void Stats() {
2011-12-20 14:29:21 +01:00
SHARED_CRITICAL_BLOCK(cs) {
if (fDirty) {
printf("**** %i available (%i tracked, %i new, %i active), %i banned; %i good\n",
(int)idToInfo.size(),
(int)ourId.size(),
(int)unkId.size(),
(int)idToInfo.size() - (int)ourId.size() - (int)unkId.size(),
(int)banned.size(),
(int)goodId.size());
fDirty = false; // hopefully atomic
}
}
2011-12-20 05:20:50 +01:00
}
2011-12-19 23:18:06 +01:00
void Add(const CAddress &addr) {
CRITICAL_BLOCK(cs)
Add_(addr);
}
void Add(const std::vector<CAddress> &vAddr) {
CRITICAL_BLOCK(cs)
for (int i=0; i<vAddr.size(); i++)
Add_(vAddr[i]);
}
void Good(const CIPPort &addr) {
CRITICAL_BLOCK(cs)
Good_(addr);
}
void Skipped(const CIPPort &addr) {
CRITICAL_BLOCK(cs)
Skipped_(addr);
}
void Bad(const CIPPort &addr, int ban = 0) {
CRITICAL_BLOCK(cs)
Bad_(addr, ban);
}
2011-12-20 06:42:48 +01:00
bool Get(CIPPort &ip, int& wait) {
2011-12-19 23:18:06 +01:00
CRITICAL_BLOCK(cs)
2011-12-20 06:42:48 +01:00
return Get_(ip, wait);
2011-12-19 23:18:06 +01:00
}
void GetIPs(std::set<CIP>& ips, int max, bool fOnlyIPv4 = true) {
2011-12-20 09:31:28 +01:00
SHARED_CRITICAL_BLOCK(cs)
2011-12-19 23:18:06 +01:00
GetIPs_(ips, max, fOnlyIPv4);
}
};