Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/main.cpp
Show First 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | CDnsSeedOpts() | ||||
fWipeIgnore(DEFAULT_WIPE_IGNORE), mbox(DEFAULT_EMAIL), | fWipeIgnore(DEFAULT_WIPE_IGNORE), mbox(DEFAULT_EMAIL), | ||||
ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), tor(DEFAULT_TOR_PROXY), | ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), tor(DEFAULT_TOR_PROXY), | ||||
ipv4_proxy(DEFAULT_IPV4_PROXY), ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ipv4_proxy(DEFAULT_IPV4_PROXY), ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ||||
int ParseCommandLine(int argc, char **argv) { | int ParseCommandLine(int argc, char **argv) { | ||||
SetupSeederArgs(); | SetupSeederArgs(); | ||||
std::string error; | std::string error; | ||||
if (!gArgs.ParseParameters(argc, argv, error)) { | if (!gArgs.ParseParameters(argc, argv, error)) { | ||||
fprintf(stderr, "Error parsing command line arguments: %s\n", | tfm::format(std::cerr, "Error parsing command line arguments: %s\n", | ||||
error.c_str()); | error.c_str()); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | ||||
} | } | ||||
if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { | if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { | ||||
std::string strUsage = | std::string strUsage = | ||||
PACKAGE_NAME " Seeder " + FormatFullVersion() + "\n"; | PACKAGE_NAME " Seeder " + FormatFullVersion() + "\n"; | ||||
if (HelpRequested(gArgs)) { | if (HelpRequested(gArgs)) { | ||||
strUsage += | strUsage += | ||||
"\nUsage: bitcoin-seeder -host=<host> -ns=<ns> " | "\nUsage: bitcoin-seeder -host=<host> -ns=<ns> " | ||||
"[-mbox=<mbox>] [-threads=<threads>] [-port=<port>]\n\n" + | "[-mbox=<mbox>] [-threads=<threads>] [-port=<port>]\n\n" + | ||||
gArgs.GetHelpMessage(); | gArgs.GetHelpMessage(); | ||||
} | } | ||||
fprintf(stdout, "%s", strUsage.c_str()); | tfm::format(std::cout, "%s", strUsage.c_str()); | ||||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||||
} | } | ||||
nThreads = gArgs.GetArg("-threads", DEFAULT_NUM_THREADS); | nThreads = gArgs.GetArg("-threads", DEFAULT_NUM_THREADS); | ||||
nPort = gArgs.GetArg("-port", DEFAULT_PORT); | nPort = gArgs.GetArg("-port", DEFAULT_PORT); | ||||
nDnsThreads = gArgs.GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS); | nDnsThreads = gArgs.GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS); | ||||
fWipeBan = gArgs.GetBoolArg("-wipeban", DEFAULT_WIPE_BAN); | fWipeBan = gArgs.GetBoolArg("-wipeban", DEFAULT_WIPE_BAN); | ||||
fWipeIgnore = gArgs.GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE); | fWipeIgnore = gArgs.GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE); | ||||
▲ Show 20 Lines • Show All 283 Lines • ▼ Show 20 Lines | do { | ||||
FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+"); | FILE *f = fsbridge::fopen("dnsseed.dat.new", "w+"); | ||||
if (f) { | if (f) { | ||||
{ | { | ||||
CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | ||||
cf << db; | cf << db; | ||||
} | } | ||||
rename("dnsseed.dat.new", "dnsseed.dat"); | rename("dnsseed.dat.new", "dnsseed.dat"); | ||||
} | } | ||||
FILE *d = fsbridge::fopen("dnsseed.dump", "w"); | fsbridge::ofstream d{"dnsseed.dump"}; | ||||
fprintf(d, "# address good " | tfm::format( | ||||
d, "# address good " | |||||
"lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) " | "lastSuccess %%(2h) %%(8h) %%(1d) %%(7d) " | ||||
"%%(30d) blocks svcs version\n"); | "%%(30d) blocks svcs version\n"); | ||||
double stat[5] = {0, 0, 0, 0, 0}; | double stat[5] = {0, 0, 0, 0, 0}; | ||||
for (CAddrReport rep : v) { | for (CAddrReport rep : v) { | ||||
fprintf( | tfm::format( | ||||
d, | d, | ||||
"%-47s %4d %11" PRId64 | "%-47s %4d %11" PRId64 | ||||
" %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64 | " %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6.2f%% %6i %08" PRIx64 | ||||
" %5i \"%s\"\n", | " %5i \"%s\"\n", | ||||
rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, | rep.ip.ToString().c_str(), (int)rep.fGood, rep.lastSuccess, | ||||
100.0 * rep.uptime[0], 100.0 * rep.uptime[1], | 100.0 * rep.uptime[0], 100.0 * rep.uptime[1], | ||||
100.0 * rep.uptime[2], 100.0 * rep.uptime[3], | 100.0 * rep.uptime[2], 100.0 * rep.uptime[3], | ||||
100.0 * rep.uptime[4], rep.blocks, rep.services, | 100.0 * rep.uptime[4], rep.blocks, rep.services, | ||||
rep.clientVersion, rep.clientSubVersion.c_str()); | rep.clientVersion, rep.clientSubVersion.c_str()); | ||||
stat[0] += rep.uptime[0]; | stat[0] += rep.uptime[0]; | ||||
stat[1] += rep.uptime[1]; | stat[1] += rep.uptime[1]; | ||||
stat[2] += rep.uptime[2]; | stat[2] += rep.uptime[2]; | ||||
stat[3] += rep.uptime[3]; | stat[3] += rep.uptime[3]; | ||||
stat[4] += rep.uptime[4]; | stat[4] += rep.uptime[4]; | ||||
} | } | ||||
fclose(d); | fsbridge::ofstream ff{"dnsstats.log", std::ios_base::app}; | ||||
FILE *ff = fsbridge::fopen("dnsstats.log", "a"); | tfm::format(ff, "%llu %g %g %g %g %g\n", | ||||
fprintf(ff, "%llu %g %g %g %g %g\n", | |||||
(unsigned long long)(time(nullptr)), stat[0], stat[1], | (unsigned long long)(time(nullptr)), stat[0], stat[1], | ||||
stat[2], stat[3], stat[4]); | stat[2], stat[3], stat[4]); | ||||
fclose(ff); | |||||
} | } | ||||
} while (1); | } while (1); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
extern "C" void *ThreadStats(void *) { | extern "C" void *ThreadStats(void *) { | ||||
bool first = true; | bool first = true; | ||||
do { | do { | ||||
char c[256]; | char c[256]; | ||||
time_t tim = time(nullptr); | time_t tim = time(nullptr); | ||||
struct tm *tmp = localtime(&tim); | struct tm *tmp = localtime(&tim); | ||||
strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); | strftime(c, 256, "[%y-%m-%d %H:%M:%S]", tmp); | ||||
CAddrDbStats stats; | CAddrDbStats stats; | ||||
db.GetStats(stats); | db.GetStats(stats); | ||||
if (first) { | if (first) { | ||||
first = false; | first = false; | ||||
fprintf(stdout, "\n\n\n\x1b[3A"); | tfm::format(std::cout, "\n\n\n\x1b[3A"); | ||||
} else { | } else { | ||||
fprintf(stdout, "\x1b[2K\x1b[u"); | tfm::format(std::cout, "\x1b[2K\x1b[u"); | ||||
} | } | ||||
fprintf(stdout, "\x1b[s"); | tfm::format(std::cout, "\x1b[s"); | ||||
uint64_t requests = 0; | uint64_t requests = 0; | ||||
uint64_t queries = 0; | uint64_t queries = 0; | ||||
for (unsigned int i = 0; i < dnsThread.size(); i++) { | for (unsigned int i = 0; i < dnsThread.size(); i++) { | ||||
requests += dnsThread[i]->dns_opt.nRequests; | requests += dnsThread[i]->dns_opt.nRequests; | ||||
queries += dnsThread[i]->dbQueries; | queries += dnsThread[i]->dbQueries; | ||||
} | } | ||||
fprintf(stdout, | tfm::format( | ||||
std::cout, | |||||
"%s %i/%i available (%i tried in %is, %i new, %i active), %i " | "%s %i/%i available (%i tried in %is, %i new, %i active), %i " | ||||
"banned; %llu DNS requests, %llu db queries\n", | "banned; %llu DNS requests, %llu db queries\n", | ||||
c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, | c, stats.nGood, stats.nAvail, stats.nTracked, stats.nAge, | ||||
stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, | stats.nNew, stats.nAvail - stats.nTracked - stats.nNew, | ||||
stats.nBanned, (unsigned long long)requests, | stats.nBanned, (unsigned long long)requests, | ||||
(unsigned long long)queries); | (unsigned long long)queries); | ||||
Sleep(1000); | Sleep(1000); | ||||
} while (1); | } while (1); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
const static unsigned int MAX_HOSTS_PER_SEED = 128; | const static unsigned int MAX_HOSTS_PER_SEED = 128; | ||||
extern "C" void *ThreadSeeder(void *) { | extern "C" void *ThreadSeeder(void *) { | ||||
Show All 18 Lines | int main(int argc, char **argv) { | ||||
signal(SIGPIPE, SIG_IGN); | signal(SIGPIPE, SIG_IGN); | ||||
setbuf(stdout, nullptr); | setbuf(stdout, nullptr); | ||||
CDnsSeedOpts opts; | CDnsSeedOpts opts; | ||||
int parseResults = opts.ParseCommandLine(argc, argv); | int parseResults = opts.ParseCommandLine(argc, argv); | ||||
if (parseResults != CONTINUE_EXECUTION) { | if (parseResults != CONTINUE_EXECUTION) { | ||||
return parseResults; | return parseResults; | ||||
} | } | ||||
fprintf(stdout, "Supporting whitelisted filters: "); | tfm::format(std::cout, "Supporting whitelisted filters: "); | ||||
for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin(); | for (std::set<uint64_t>::const_iterator it = opts.filter_whitelist.begin(); | ||||
it != opts.filter_whitelist.end(); it++) { | it != opts.filter_whitelist.end(); it++) { | ||||
if (it != opts.filter_whitelist.begin()) { | if (it != opts.filter_whitelist.begin()) { | ||||
fprintf(stdout, ","); | tfm::format(std::cout, ","); | ||||
} | } | ||||
fprintf(stdout, "0x%lx", (unsigned long)*it); | tfm::format(std::cout, "0x%lx", (unsigned long)*it); | ||||
} | } | ||||
fprintf(stdout, "\n"); | tfm::format(std::cout, "\n"); | ||||
if (!opts.tor.empty()) { | if (!opts.tor.empty()) { | ||||
CService service(LookupNumeric(opts.tor.c_str(), 9050)); | CService service(LookupNumeric(opts.tor.c_str(), 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using Tor proxy at %s\n", | tfm::format(std::cout, "Using Tor proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_ONION, proxyType(service)); | SetProxy(NET_ONION, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
if (!opts.ipv4_proxy.empty()) { | if (!opts.ipv4_proxy.empty()) { | ||||
CService service(LookupNumeric(opts.ipv4_proxy.c_str(), 9050)); | CService service(LookupNumeric(opts.ipv4_proxy.c_str(), 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using IPv4 proxy at %s\n", | tfm::format(std::cout, "Using IPv4 proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_IPV4, proxyType(service)); | SetProxy(NET_IPV4, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
if (!opts.ipv6_proxy.empty()) { | if (!opts.ipv6_proxy.empty()) { | ||||
CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050)); | CService service(LookupNumeric(opts.ipv6_proxy.c_str(), 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using IPv6 proxy at %s\n", | tfm::format(std::cout, "Using IPv6 proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_IPV6, proxyType(service)); | SetProxy(NET_IPV6, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
bool fDNS = true; | bool fDNS = true; | ||||
fprintf(stdout, "Using %s.\n", gArgs.GetChainName().c_str()); | tfm::format(std::cout, "Using %s.\n", gArgs.GetChainName().c_str()); | ||||
netMagic = Params().NetMagic(); | netMagic = Params().NetMagic(); | ||||
if (opts.ns.empty()) { | if (opts.ns.empty()) { | ||||
fprintf(stdout, "No nameserver set. Not starting DNS server.\n"); | tfm::format(std::cout, "No nameserver set. Not starting DNS server.\n"); | ||||
fDNS = false; | fDNS = false; | ||||
} | } | ||||
if (fDNS && opts.host.empty()) { | if (fDNS && opts.host.empty()) { | ||||
fprintf(stderr, "No hostname set. Please use -h.\n"); | tfm::format(std::cerr, "No hostname set. Please use -h.\n"); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | ||||
} | } | ||||
if (fDNS && opts.mbox.empty()) { | if (fDNS && opts.mbox.empty()) { | ||||
fprintf(stderr, "No e-mail address set. Please use -m.\n"); | tfm::format(std::cerr, "No e-mail address set. Please use -m.\n"); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | ||||
} | } | ||||
FILE *f = fsbridge::fopen("dnsseed.dat", "r"); | FILE *f = fsbridge::fopen("dnsseed.dat", "r"); | ||||
if (f) { | if (f) { | ||||
fprintf(stdout, "Loading dnsseed.dat..."); | tfm::format(std::cout, "Loading dnsseed.dat..."); | ||||
CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | ||||
cf >> db; | cf >> db; | ||||
if (opts.fWipeBan) { | if (opts.fWipeBan) { | ||||
db.banned.clear(); | db.banned.clear(); | ||||
fprintf(stdout, "Ban list wiped..."); | tfm::format(std::cout, "Ban list wiped..."); | ||||
} | } | ||||
if (opts.fWipeIgnore) { | if (opts.fWipeIgnore) { | ||||
db.ResetIgnores(); | db.ResetIgnores(); | ||||
fprintf(stdout, "Ignore list wiped..."); | tfm::format(std::cout, "Ignore list wiped..."); | ||||
} | } | ||||
fprintf(stdout, "done\n"); | tfm::format(std::cout, "done\n"); | ||||
} | } | ||||
pthread_t threadDns, threadSeed, threadDump, threadStats; | pthread_t threadDns, threadSeed, threadDump, threadStats; | ||||
if (fDNS) { | if (fDNS) { | ||||
fprintf(stdout, "Starting %i DNS threads for %s on %s (port %i)...", | tfm::format( | ||||
opts.nDnsThreads, opts.host.c_str(), opts.ns.c_str(), | std::cout, "Starting %i DNS threads for %s on %s (port %i)...", | ||||
opts.nPort); | opts.nDnsThreads, opts.host.c_str(), opts.ns.c_str(), opts.nPort); | ||||
dnsThread.clear(); | dnsThread.clear(); | ||||
for (int i = 0; i < opts.nDnsThreads; i++) { | for (int i = 0; i < opts.nDnsThreads; i++) { | ||||
dnsThread.push_back(new CDnsThread(&opts, i)); | dnsThread.push_back(new CDnsThread(&opts, i)); | ||||
pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]); | pthread_create(&threadDns, nullptr, ThreadDNS, dnsThread[i]); | ||||
fprintf(stdout, "."); | tfm::format(std::cout, "."); | ||||
Sleep(20); | Sleep(20); | ||||
} | } | ||||
fprintf(stdout, "done\n"); | tfm::format(std::cout, "done\n"); | ||||
} | } | ||||
fprintf(stdout, "Starting seeder..."); | tfm::format(std::cout, "Starting seeder..."); | ||||
pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); | pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); | ||||
fprintf(stdout, "done\n"); | tfm::format(std::cout, "done\n"); | ||||
fprintf(stdout, "Starting %i crawler threads...", opts.nThreads); | tfm::format(std::cout, "Starting %i crawler threads...", opts.nThreads); | ||||
pthread_attr_t attr_crawler; | pthread_attr_t attr_crawler; | ||||
pthread_attr_init(&attr_crawler); | pthread_attr_init(&attr_crawler); | ||||
pthread_attr_setstacksize(&attr_crawler, 0x20000); | pthread_attr_setstacksize(&attr_crawler, 0x20000); | ||||
for (int i = 0; i < opts.nThreads; i++) { | for (int i = 0; i < opts.nThreads; i++) { | ||||
pthread_t thread; | pthread_t thread; | ||||
pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); | pthread_create(&thread, &attr_crawler, ThreadCrawler, &opts.nThreads); | ||||
} | } | ||||
pthread_attr_destroy(&attr_crawler); | pthread_attr_destroy(&attr_crawler); | ||||
fprintf(stdout, "done\n"); | tfm::format(std::cout, "done\n"); | ||||
pthread_create(&threadStats, nullptr, ThreadStats, nullptr); | pthread_create(&threadStats, nullptr, ThreadStats, nullptr); | ||||
pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); | pthread_create(&threadDump, nullptr, ThreadDumper, nullptr); | ||||
void *res; | void *res; | ||||
pthread_join(threadDump, &res); | pthread_join(threadDump, &res); | ||||
return EXIT_SUCCESS; | return EXIT_SUCCESS; | ||||
} | } |