Browse Source

Multiple DNS threads

pull/1/head
Pieter Wuille 13 years ago
parent
commit
54fb24d7c3
  1. 8
      Makefile
  2. 28
      dns.c
  3. 2
      dns.h
  4. 98
      main.cpp

8
Makefile

@ -1,14 +1,10 @@
dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o dnsseed: dns.o bitcoin.o netbase.o protocol.o db.o main.o
g++ -pthread -lcrypto -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o g++ -pthread -lcrypto -o dnsseed dns.o bitcoin.o netbase.o protocol.o db.o main.o
strip -s dnsseed
dnsseed.dbg: dns.o bitcoin.o netbase.o protocol.o db.o main.o
g++ -pthread -lcrypto -o dnsseed.dbg dns.o bitcoin.o netbase.o protocol.o db.o main.o
%.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h %.o: %.cpp bitcoin.h netbase.h protocol.h db.h serialize.h uint256.h util.h
g++ -pthread -O3 -ggdb3 -march=nocona -Wno-invalid-offsetof -c -o $@ $< g++ -pthread -O2 -ggdb3 -march=nocona -Wno-invalid-offsetof -c -o $@ $<
dns.o: dns.c dns.o: dns.c
gcc -pthread -std=c99 -O3 -g0 -march=nocona dns.c -c -o dns.o gcc -pthread -std=c99 -O2 -ggdb3 -march=nocona dns.c -c -o dns.o
%.o: %.cpp %.o: %.cpp

28
dns.c

@ -296,7 +296,7 @@ ssize_t static dnshandle(dns_opt_t *opt, const unsigned char *inbuf, size_t insi
// A records // A records
if ((typ == TYPE_A || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) { if ((typ == TYPE_A || typ == QTYPE_ANY) && (cls == CLASS_IN || cls == QCLASS_ANY)) {
struct in_addr addr[32]; struct in_addr addr[32];
int naddr = opt->cb(addr, 32, 1); int naddr = opt->cb((void*)opt, addr, 32, 1);
int n = 0; int n = 0;
while (n < naddr) { while (n < naddr) {
int ret = write_record_a(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]); int ret = write_record_a(&outpos, outend - auth_size, "", offset, CLASS_IN, opt->datattl, &addr[n]);
@ -333,27 +333,39 @@ error:
return 12; return 12;
} }
static int listenSocket = -1;
int dnsserver(dns_opt_t *opt) { int dnsserver(dns_opt_t *opt) {
struct sockaddr_in si_me, si_other; struct sockaddr_in si_other;
socklen_t s, slen=sizeof(si_other); int senderSocket = -1;
unsigned char inbuf[BUFLEN], outbuf[BUFLEN]; senderSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if ((s=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) if (senderSocket == -1)
return -3;
if (listenSocket == -1) {
struct sockaddr_in si_me;
if ((listenSocket=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP))==-1) {
listenSocket = -1;
return -1; return -1;
}
memset((char *) &si_me, 0, sizeof(si_me)); memset((char *) &si_me, 0, sizeof(si_me));
si_me.sin_family = AF_INET; si_me.sin_family = AF_INET;
si_me.sin_port = htons(opt->port); si_me.sin_port = htons(opt->port);
si_me.sin_addr.s_addr = INADDR_ANY; si_me.sin_addr.s_addr = INADDR_ANY;
if (bind(s, (struct sockaddr*)&si_me, sizeof(si_me))==-1) if (bind(listenSocket, (struct sockaddr*)&si_me, sizeof(si_me))==-1)
return -2; return -2;
}
unsigned char inbuf[BUFLEN], outbuf[BUFLEN];
do { do {
ssize_t insize = recvfrom(s, inbuf, BUFLEN, 0, (struct sockaddr*)&si_other, &slen); socklen_t si_other_len = sizeof(si_other);
ssize_t insize = recvfrom(listenSocket, inbuf, BUFLEN, 0, (struct sockaddr*)&si_other, &si_other_len);
unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr; unsigned char *addr = (unsigned char*)&si_other.sin_addr.s_addr;
// printf("DNS: Request %llu from %i.%i.%i.%i:%i of %i bytes\n", (unsigned long long)(opt->nRequests), addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize); // printf("DNS: Request %llu from %i.%i.%i.%i:%i of %i bytes\n", (unsigned long long)(opt->nRequests), addr[0], addr[1], addr[2], addr[3], ntohs(si_other.sin_port), (int)insize);
opt->nRequests++; opt->nRequests++;
if (insize > 0) { if (insize > 0) {
ssize_t ret = dnshandle(opt, inbuf, insize, outbuf); ssize_t ret = dnshandle(opt, inbuf, insize, outbuf);
if (ret > 0) if (ret > 0)
sendto(s, outbuf, ret, 0, (struct sockaddr*)&si_other, slen); sendto(listenSocket, outbuf, ret, 0, (struct sockaddr*)&si_other, sizeof(si_other));
} }
} while(1); } while(1);
return 0; return 0;

2
dns.h

@ -10,7 +10,7 @@ typedef struct {
const char *host; const char *host;
const char *ns; const char *ns;
const char *mbox; const char *mbox;
int (*cb)(struct in_addr *addr, int max, int ipv4only); int (*cb)(void *opt, struct in_addr *addr, int max, int ipv4only);
// stats // stats
uint64_t nRequests; uint64_t nRequests;
} dns_opt_t; } dns_opt_t;

98
main.cpp

@ -16,11 +16,12 @@ class CDnsSeedOpts {
public: public:
int nThreads; int nThreads;
int nPort; int nPort;
int nDnsThreads;
const char *mbox; const char *mbox;
const char *ns; const char *ns;
const char *host; const char *host;
CDnsSeedOpts() : nThreads(24), nPort(53), mbox(NULL), ns(NULL), host(NULL) {} CDnsSeedOpts() : nThreads(24), nDnsThreads(24), nPort(53), mbox(NULL), ns(NULL), host(NULL) {}
void ParseCommandLine(int argc, char **argv) { void ParseCommandLine(int argc, char **argv) {
static const char *help = "Bitcoin-seeder\n" static const char *help = "Bitcoin-seeder\n"
@ -31,6 +32,7 @@ public:
"-n <ns> Hostname of the nameserver\n" "-n <ns> Hostname of the nameserver\n"
"-m <mbox> E-Mail address reported in SOA records\n" "-m <mbox> E-Mail address reported in SOA records\n"
"-t <threads> Number of crawlers to run in parallel (default 24)\n" "-t <threads> Number of crawlers to run in parallel (default 24)\n"
"-d <threads> Number of DNS server threads (default 24)\n"
"-p <port> UDP port to listen on (default 53)\n" "-p <port> UDP port to listen on (default 53)\n"
"-?, --help Show this text\n" "-?, --help Show this text\n"
"\n"; "\n";
@ -42,12 +44,13 @@ public:
{"ns", required_argument, 0, 'n'}, {"ns", required_argument, 0, 'n'},
{"mbox", required_argument, 0, 'm'}, {"mbox", required_argument, 0, 'm'},
{"threads", required_argument, 0, 't'}, {"threads", required_argument, 0, 't'},
{"dnsthreads", required_argument, 0, 'd'},
{"port", required_argument, 0, 'p'}, {"port", required_argument, 0, 'p'},
{"help", no_argument, 0, 'h'}, {"help", no_argument, 0, 'h'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
int option_index = 0; int option_index = 0;
int c = getopt_long(argc, argv, "h:n:m:t:p:", long_options, &option_index); int c = getopt_long(argc, argv, "h:n:m:t:p:d:", long_options, &option_index);
if (c == -1) break; if (c == -1) break;
switch (c) { switch (c) {
case 'h': { case 'h': {
@ -71,6 +74,12 @@ public:
break; break;
} }
case 'd': {
int n = strtol(optarg, NULL, 10);
if (n > 0 && n < 1000) nDnsThreads = n;
break;
}
case 'p': { case 'p': {
int p = strtol(optarg, NULL, 10); int p = strtol(optarg, NULL, 10);
if (p > 0 && p < 65536) nPort = p; if (p > 0 && p < 65536) nPort = p;
@ -118,15 +127,20 @@ extern "C" void* ThreadCrawler(void* data) {
} while(1); } while(1);
} }
static vector<struct in_addr> cache; extern "C" int GetIPList(void *thread, struct in_addr *addr, int max, int ipv4only);
static time_t cacheTime;
static unsigned int cacheHits = 1000000000;
static uint64_t dbQueries = 0;
void static cacheRefresh(int ipv4only) { class CDnsThread {
public:
dns_opt_t dns_opt;
vector<struct in_addr> cache;
time_t cacheTime;
unsigned int cacheHits;
uint64_t dbQueries;
void cacheHit(int ipv4only, bool force = false) {
time_t now = time(NULL); time_t now = time(NULL);
cacheHits++; cacheHits++;
if (cacheHits > (cache.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) { if (force || cacheHits > (cache.size()*cache.size()/400) || (cacheHits*cacheHits > cache.size() / 20 && (now - cacheTime > 5))) {
set<CIP> ips; set<CIP> ips;
db.GetIPs(ips, 1000, ipv4only); db.GetIPs(ips, 1000, ipv4only);
dbQueries++; dbQueries++;
@ -143,23 +157,7 @@ void static cacheRefresh(int ipv4only) {
} }
} }
extern "C" int GetIPList(struct in_addr *addr, int max, int ipv4only) { CDnsThread(CDnsSeedOpts* opts) {
cacheRefresh(ipv4only);
if (max > cache.size())
max = cache.size();
for (int i=0; i<max; i++) {
int j = i + (rand() % (cache.size() - i));
addr[i] = cache[j];
cache[j] = cache[i];
cache[i] = addr[i];
}
return max;
}
static dns_opt_t dns_opt;
extern "C" void* ThreadDNS(void* arg) {
CDnsSeedOpts *opts = (CDnsSeedOpts*)arg;
dns_opt.host = opts->host; dns_opt.host = opts->host;
dns_opt.ns = opts->ns; dns_opt.ns = opts->ns;
dns_opt.mbox = opts->mbox; dns_opt.mbox = opts->mbox;
@ -168,8 +166,40 @@ extern "C" void* ThreadDNS(void* arg) {
dns_opt.cb = GetIPList; dns_opt.cb = GetIPList;
dns_opt.port = opts->nPort; dns_opt.port = opts->nPort;
dns_opt.nRequests = 0; dns_opt.nRequests = 0;
cache.clear();
cache.reserve(1000);
cacheTime = 0;
cacheHits = 0;
dbQueries = 0;
cacheHit(true, true);
}
void run() {
dnsserver(&dns_opt); dnsserver(&dns_opt);
} }
};
extern "C" int GetIPList(void *data, struct in_addr *addr, int max, int ipv4only) {
CDnsThread *thread = (CDnsThread*)data;
thread->cacheHit(ipv4only);
unsigned int size = thread->cache.size();
if (max > size)
max = size;
for (int i=0; i<max; i++) {
int j = i + (rand() % (size - i));
addr[i] = thread->cache[j];
thread->cache[j] = thread->cache[i];
thread->cache[i] = addr[i];
}
return max;
}
vector<CDnsThread*> dnsThread;
extern "C" void* ThreadDNS(void* arg) {
CDnsThread *thread = (CDnsThread*)arg;
thread->run();
}
int StatCompare(const CAddrReport& a, const CAddrReport& b) { int StatCompare(const CAddrReport& a, const CAddrReport& b) {
if (a.uptime[4] == b.uptime[4]) { if (a.uptime[4] == b.uptime[4]) {
@ -223,7 +253,13 @@ extern "C" void* ThreadStats(void*) {
CAddrDbStats stats; CAddrDbStats stats;
db.GetStats(stats); db.GetStats(stats);
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b");
printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests, %llu db reads", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)dns_opt.nRequests, (unsigned long long)dbQueries); uint64_t requests = 0;
uint64_t queries = 0;
for (unsigned int i=0; i<dnsThread.size(); i++) {
requests += dnsThread[i]->dns_opt.nRequests;
queries += dnsThread[i]->dbQueries;
}
printf("%s %i/%i available (%i tried in %is, %i new, %i active), %i banned; %llu DNS requests, %llu db queries", c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, stats.nBanned, (unsigned long long)requests, (unsigned long long)queries);
Sleep(1000); Sleep(1000);
} while(1); } while(1);
} }
@ -276,8 +312,14 @@ int main(int argc, char **argv) {
printf("done\n"); printf("done\n");
pthread_create(&threadDump, NULL, ThreadDumper, NULL); pthread_create(&threadDump, NULL, ThreadDumper, NULL);
if (fDNS) { if (fDNS) {
printf("Starting DNS server for %s on %s (port %i)...", opts.host, opts.ns, opts.nPort); printf("Starting %i DNS threads for %s on %s (port %i)...", opts.nDnsThreads, opts.host, opts.ns, opts.nPort);
pthread_create(&threadDns, NULL, ThreadDNS, &opts); dnsThread.clear();
for (int i=0; i<opts.nDnsThreads; i++) {
dnsThread.push_back(new CDnsThread(&opts));
pthread_create(&threadDns, NULL, ThreadDNS, dnsThread[i]);
printf(".");
Sleep(20);
}
printf("done\n"); printf("done\n");
} }
pthread_create(&threadStats, NULL, ThreadStats, NULL); pthread_create(&threadStats, NULL, ThreadStats, NULL);

Loading…
Cancel
Save