diff --git a/db.cpp b/db.cpp index f7020f2..3c19bed 100644 --- a/db.cpp +++ b/db.cpp @@ -166,7 +166,7 @@ void CAddrDb::Add_(const CAddress &addr, bool force) { nDirty++; } -void CAddrDb::GetIPs_(set& ips, int max, const bool* nets) { +void CAddrDb::GetIPs_(set& ips, uint64_t requestedFlags, int max, const bool* nets) { if (goodId.size() == 0) { int id = -1; if (ourId.size() == 0) { @@ -175,22 +175,31 @@ void CAddrDb::GetIPs_(set& ips, int max, const bool* nets) { } else { id = *ourId.begin(); } - if (id >= 0) { + if (id >= 0 && idToInfo[id].services & requestedFlags) { ips.insert(idToInfo[id].ip); } return; } - if (max > goodId.size() / 2) - max = goodId.size() / 2; + std::set goodIdFiltered; + for (std::set::const_iterator it = goodId.begin(); it != goodId.end(); it++) { + if ((idToInfo[*it].services & requestedFlags) == requestedFlags) + goodIdFiltered.insert(*it); + } + + if (!goodIdFiltered.size()) + return; + + if (max > goodIdFiltered.size() / 2) + max = goodIdFiltered.size() / 2; if (max < 1) max = 1; - int low = *goodId.begin(); - int high = *goodId.rbegin(); + int low = *goodIdFiltered.begin(); + int high = *goodIdFiltered.rbegin(); set ids; while (ids.size() < max) { int range = high-low+1; int pos = low + (rand() % range); - int id = *(goodId.lower_bound(pos)); + int id = *(goodIdFiltered.lower_bound(pos)); ids.insert(id); } for (set::const_iterator it = ids.begin(); it != ids.end(); it++) { diff --git a/db.h b/db.h index e5f00b7..55e1149 100644 --- a/db.h +++ b/db.h @@ -219,7 +219,7 @@ protected: void Bad_(const CService &ip, int ban); // mark an IP as bad (and optionally ban it) (must have been returned by Get_) void Skipped_(const CService &ip); // mark an IP as skipped (must have been returned by Get_) int Lookup_(const CService &ip); // look up id of an IP - void GetIPs_(std::set& ips, int max, const bool *nets); // get a random set of IPs (shared lock only) + void GetIPs_(std::set& ips, uint64_t requestedFlags, int max, const bool *nets); // get a random set of IPs (shared lock only) public: std::map banned; // nodes that are banned, with their unban time (a) @@ -351,8 +351,8 @@ public: } } } - void GetIPs(std::set& ips, int max, const bool *nets) { + void GetIPs(std::set& ips, uint64_t requestedFlags, int max, const bool *nets) { SHARED_CRITICAL_BLOCK(cs) - GetIPs_(ips, max, nets); + GetIPs_(ips, requestedFlags, max, nets); } }; diff --git a/dns.c b/dns.c index ee2f29d..305091f 100644 --- a/dns.c +++ b/dns.c @@ -327,7 +327,7 @@ ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insi // A/AAAA records if ((typ == TYPE_A || typ == TYPE_AAAA || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { addr_t addr[32]; - int naddr = opt->cb((void*)opt, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY); + int naddr = opt->cb((void*)opt, name, addr, 32, typ == TYPE_A || typ == QTYPE_ANY, typ == TYPE_AAAA || typ == QTYPE_ANY); int n = 0; while (n < naddr) { int ret = 1; diff --git a/dns.h b/dns.h index 97dd321..d1fddd7 100644 --- a/dns.h +++ b/dns.h @@ -18,7 +18,7 @@ typedef struct { const char *host; const char *ns; const char *mbox; - int (*cb)(void *opt, addr_t *addr, int max, int ipv4, int ipv6); + int (*cb)(void *opt, char *requested_hostname, addr_t *addr, int max, int ipv4, int ipv6); // stats uint64_t nRequests; } dns_opt_t; diff --git a/main.cpp b/main.cpp index 627f990..19a3df8 100644 --- a/main.cpp +++ b/main.cpp @@ -167,19 +167,19 @@ extern "C" void* ThreadCrawler(void* data) { } while(1); } -extern "C" int GetIPList(void *thread, addr_t *addr, int max, int ipv4, int ipv6); +extern "C" int GetIPList(void *thread, char *requestedHostname, addr_t *addr, int max, int ipv4, int ipv6); class CDnsThread { public: dns_opt_t dns_opt; // must be first const int id; - vector cache; + std::map > cache; int nIPv4, nIPv6; time_t cacheTime; unsigned int cacheHits; uint64_t dbQueries; - void cacheHit(bool force = false) { + void cacheHit(uint64_t requestedFlags, bool force = false) { static bool nets[NET_MAX] = {}; if (!nets[NET_IPV4]) { nets[NET_IPV4] = true; @@ -187,14 +187,14 @@ public: } time_t now = time(NULL); cacheHits++; - if (force || cacheHits > (cache.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) { + if (force || cacheHits > (cache[requestedFlags].size()*cache[requestedFlags].size()/400) || (cacheHits*cacheHits > cache[requestedFlags].size() / 20 && (now - cacheTime > 5))) { set ips; - db.GetIPs(ips, 1000, nets); + db.GetIPs(ips, requestedFlags, 1000, nets); dbQueries++; - cache.clear(); + cache[requestedFlags].clear(); nIPv4 = 0; nIPv6 = 0; - cache.reserve(ips.size()); + cache[requestedFlags].reserve(ips.size()); for (set::iterator it = ips.begin(); it != ips.end(); it++) { struct in_addr addr; struct in6_addr addr6; @@ -202,13 +202,13 @@ public: addr_t a; a.v = 4; memcpy(&a.data.v4, &addr, 4); - cache.push_back(a); + cache[requestedFlags].push_back(a); nIPv4++; } else if ((*it).GetIn6Addr(&addr6)) { addr_t a; a.v = 6; memcpy(&a.data.v6, &addr6, 16); - cache.push_back(a); + cache[requestedFlags].push_back(a); nIPv6++; } } @@ -227,13 +227,11 @@ public: dns_opt.port = opts->nPort; dns_opt.nRequests = 0; cache.clear(); - cache.reserve(1000); cacheTime = 0; cacheHits = 0; dbQueries = 0; nIPv4 = 0; nIPv6 = 0; - cacheHit(true); } void run() { @@ -241,10 +239,19 @@ public: } }; -extern "C" int GetIPList(void *data, addr_t* addr, int max, int ipv4, int ipv6) { +extern "C" int GetIPList(void *data, char *requestedHostname, addr_t* addr, int max, int ipv4, int ipv6) { CDnsThread *thread = (CDnsThread*)data; - thread->cacheHit(); - unsigned int size = thread->cache.size(); + + uint64_t requestedFlags = 0; + int hostlen = strlen(requestedHostname); + if (hostlen > 1 && requestedHostname[0] == 'x' && requestedHostname[1] != '0') { + char *pEnd; + uint64_t flags = (uint64_t)strtoull(requestedHostname+1, &pEnd, 16); + if (*pEnd == '.' && pEnd <= requestedHostname+17) + requestedFlags = flags; + } + thread->cacheHit(requestedFlags); + unsigned int size = thread->cache[requestedFlags].size(); unsigned int maxmax = (ipv4 ? thread->nIPv4 : 0) + (ipv6 ? thread->nIPv6 : 0); if (max > size) max = size; @@ -254,16 +261,16 @@ extern "C" int GetIPList(void *data, addr_t* addr, int max, int ipv4, int ipv6) while (icache[j].v == 4) || - (ipv6 && thread->cache[j].v == 6); + bool ok = (ipv4 && thread->cache[requestedFlags][j].v == 4) || + (ipv6 && thread->cache[requestedFlags][j].v == 6); if (ok) break; j++; if (j==size) j=i; } while(1); - addr[i] = thread->cache[j]; - thread->cache[j] = thread->cache[i]; - thread->cache[i] = addr[i]; + addr[i] = thread->cache[requestedFlags][j]; + thread->cache[requestedFlags][j] = thread->cache[requestedFlags][i]; + thread->cache[requestedFlags][i] = addr[i]; i++; } return max; @@ -306,11 +313,11 @@ extern "C" void* ThreadDumper(void*) { rename("dnsseed.dat.new", "dnsseed.dat"); } FILE *d = fopen("dnsseed.dump", "w"); - fprintf(d, "# address good lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) %%(30d) blocks svcs version\n"); + fprintf(d, "# address servicebits good lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) %%(30d) blocks svcs version\n"); double stat[5]={0,0,0,0,0}; for (vector::const_iterator it = v.begin(); it < v.end(); it++) { CAddrReport rep = *it; - fprintf(d, "%-47s %4d %11"PRId64" %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08"PRIx64" %5i \"%s\"\n", rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str()); + fprintf(d, "%-47s %8lld %4d %11"PRId64" %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08"PRIx64" %5i \"%s\"\n", rep.ip.ToString().c_str(), (uint64_t)rep.services, (int)rep.fGood, rep.lastSuccess, 100.0*rep.uptime[0], 100.0*rep.uptime[1], 100.0*rep.uptime[2], 100.0*rep.uptime[3], 100.0*rep.uptime[4], rep.blocks, rep.services, rep.clientVersion, rep.clientSubVersion.c_str()); stat[0] += rep.uptime[0]; stat[1] += rep.uptime[1]; stat[2] += rep.uptime[2];