Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/main.cpp
#include <clientversion.h> | #include <clientversion.h> | ||||
#include <fs.h> | #include <fs.h> | ||||
#include <logging.h> | #include <logging.h> | ||||
#include <protocol.h> | #include <protocol.h> | ||||
#include <seeder/bitcoin.h> | #include <seeder/bitcoin.h> | ||||
#include <seeder/db.h> | #include <seeder/db.h> | ||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
#include <streams.h> | #include <streams.h> | ||||
#include <util/strencodings.h> | |||||
#include <util/system.h> | #include <util/system.h> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include <atomic> | #include <atomic> | ||||
#include <cinttypes> | #include <cinttypes> | ||||
#include <csignal> | #include <csignal> | ||||
#include <cstdlib> | #include <cstdlib> | ||||
#include <getopt.h> | #include <getopt.h> | ||||
Show All 17 Lines | public: | ||||
const char *ipv6_proxy; | const char *ipv6_proxy; | ||||
std::set<uint64_t> filter_whitelist; | std::set<uint64_t> filter_whitelist; | ||||
CDnsSeedOpts() | CDnsSeedOpts() | ||||
: nThreads(96), nPort(53), nDnsThreads(4), fUseTestNet(false), | : nThreads(96), nPort(53), nDnsThreads(4), fUseTestNet(false), | ||||
fWipeBan(false), fWipeIgnore(false), mbox(nullptr), ns(nullptr), | fWipeBan(false), fWipeIgnore(false), mbox(nullptr), ns(nullptr), | ||||
host(nullptr), tor(nullptr), ipv4_proxy(nullptr), | host(nullptr), tor(nullptr), ipv4_proxy(nullptr), | ||||
ipv6_proxy(nullptr) {} | ipv6_proxy(nullptr) {} | ||||
void ParseCommandLine(int argc, char **argv) { | |||||
static const char *help = | |||||
"Bitcoin-cash-seeder\n" | |||||
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p " | |||||
"<port>]\n" | |||||
"\n" | |||||
"Options:\n" | |||||
"-h <host> Hostname of the DNS seed\n" | |||||
"-n <ns> Hostname of the nameserver\n" | |||||
"-m <mbox> E-Mail address reported in SOA records\n" | |||||
"-t <threads> Number of crawlers to run in parallel (default " | |||||
"96)\n" | |||||
"-d <threads> Number of DNS server threads (default 4)\n" | |||||
"-p <port> UDP port to listen on (default 53)\n" | |||||
"-o <ip:port> Tor proxy IP/Port\n" | |||||
"-i <ip:port> IPV4 SOCKS5 proxy IP/Port\n" | |||||
"-k <ip:port> IPV6 SOCKS5 proxy IP/Port\n" | |||||
"-w f1,f2,... Allow these flag combinations as filters\n" | |||||
"--testnet Use testnet\n" | |||||
"--wipeban Wipe list of banned nodes\n" | |||||
"--wipeignore Wipe list of ignored nodes\n" | |||||
"-?, --help Show this text\n" | |||||
"\n"; | |||||
bool showHelp = false; | |||||
while (1) { | |||||
static struct option long_options[] = { | |||||
{"host", required_argument, 0, 'h'}, | |||||
{"ns", required_argument, 0, 'n'}, | |||||
{"mbox", required_argument, 0, 'm'}, | |||||
{"threads", required_argument, 0, 't'}, | |||||
{"dnsthreads", required_argument, 0, 'd'}, | |||||
{"port", required_argument, 0, 'p'}, | |||||
{"onion", required_argument, 0, 'o'}, | |||||
{"proxyipv4", required_argument, 0, 'i'}, | |||||
{"proxyipv6", required_argument, 0, 'k'}, | |||||
{"filter", required_argument, 0, 'w'}, | |||||
{"testnet", no_argument, &fUseTestNet, 1}, | |||||
{"wipeban", no_argument, &fWipeBan, 1}, | |||||
{"wipeignore", no_argument, &fWipeBan, 1}, | |||||
{"help", no_argument, 0, 'h'}, | |||||
{0, 0, 0, 0}}; | |||||
int option_index = 0; | |||||
int c = | |||||
getopt_long(argc, argv, "h:n:m:t:p:d:o:i:k:w:", long_options, | |||||
&option_index); | |||||
if (c == -1) break; | |||||
switch (c) { | |||||
case 'h': { | |||||
host = optarg; | |||||
break; | |||||
} | |||||
case 'm': { | |||||
mbox = optarg; | |||||
break; | |||||
} | |||||
case 'n': { | |||||
ns = optarg; | |||||
break; | |||||
} | |||||
case 't': { | |||||
int n = strtol(optarg, nullptr, 10); | |||||
if (n > 0 && n < 1000) nThreads = n; | |||||
break; | |||||
} | |||||
case 'd': { | |||||
int n = strtol(optarg, nullptr, 10); | |||||
if (n > 0 && n < 1000) nDnsThreads = n; | |||||
break; | |||||
} | |||||
case 'p': { | |||||
int p = strtol(optarg, nullptr, 10); | |||||
if (p > 0 && p < 65536) nPort = p; | |||||
break; | |||||
} | |||||
case 'o': { | |||||
tor = optarg; | |||||
break; | |||||
} | |||||
case 'i': { | |||||
ipv4_proxy = optarg; | |||||
break; | |||||
} | |||||
case 'k': { | |||||
ipv6_proxy = optarg; | |||||
break; | |||||
} | |||||
case 'w': { | |||||
char *ptr = optarg; | |||||
while (*ptr != 0) { | |||||
unsigned long l = strtoul(ptr, &ptr, 0); | |||||
if (*ptr == ',') { | |||||
ptr++; | |||||
} else if (*ptr != 0) { | |||||
break; | |||||
} | |||||
filter_whitelist.insert(l); | |||||
} | |||||
break; | |||||
} | |||||
case '?': { | |||||
showHelp = true; | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
if (filter_whitelist.empty()) { | |||||
filter_whitelist.insert(NODE_NETWORK); | |||||
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); | |||||
filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN); | |||||
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN); | |||||
} | |||||
if (host != nullptr && ns == nullptr) showHelp = true; | |||||
if (showHelp) fprintf(stderr, help, argv[0]); | |||||
} | |||||
}; | }; | ||||
extern "C" { | extern "C" { | ||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
} | } | ||||
CAddrDb db; | CAddrDb db; | ||||
▲ Show 20 Lines • Show All 291 Lines • ▼ Show 20 Lines | do { | ||||
true); | true); | ||||
} | } | ||||
} | } | ||||
Sleep(1800000); | Sleep(1800000); | ||||
} while (1); | } while (1); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
int main(int argc, char **argv) { | static void SetupSeederArgs() { | ||||
gArgs.AddArg("-?", _("Print this help message and exit"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-host=<host>", _("Hostname of the DNS seed"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-ns=<ns>", _("Hostname of the nameserver"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-mbox=<mbox>", _("E-Mail address reported in SOA records"), | |||||
false, OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-threads=<threads>", | |||||
_("Number of crawlers to run in parallel (default 96)"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-dnsthreads=<threads>", | |||||
_("Number of DNS server threads (default 4)"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-port=<port>", _("UDP port to listen on (default 53)"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-onion=<ip:port>", _("Tor proxy IP/Port"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-proxyipv4=<ip:port>", _("IPV4 SOCKS5 proxy IP/Port"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-proxyipv6=<ip:port>", _("IPV6 SOCKS5 proxy IP/Port"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-filter=<f1,f2,...>", | |||||
_("Allow these flag combinations as filters"), false, | |||||
OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-testnet", _("Use testnet"), false, | |||||
OptionsCategory::CHAINPARAMS); | |||||
deadalnix: It is worth noting that this isn't present in other utilities we have, and yet, this parameter… | |||||
gArgs.AddArg("-wipeban", _("Wipe list of banned nodes"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-wipeignore", _("Wipe list of ignored nodes"), false, | |||||
OptionsCategory::CONNECTION); | |||||
gArgs.AddArg("-help", "", false, OptionsCategory::HIDDEN); | |||||
gArgs.AddArg("-h", "", false, OptionsCategory::HIDDEN); | |||||
} | |||||
static bool AppInit(int argc, char *argv[]) { | |||||
// The logger dump everything on the console by default. | // The logger dump everything on the console by default. | ||||
GetLogger().m_print_to_console = true; | GetLogger().m_print_to_console = true; | ||||
signal(SIGPIPE, SIG_IGN); | signal(SIGPIPE, SIG_IGN); | ||||
setbuf(stdout, nullptr); | setbuf(stdout, nullptr); | ||||
SetupSeederArgs(); | |||||
std::string error; | |||||
if (!gArgs.ParseParameters(argc, argv, error)) { | |||||
fprintf(stderr, "Error parsing command line arguments: %s\n", | |||||
error.c_str()); | |||||
return false; | |||||
} | |||||
if (HelpRequested(gArgs)) { | |||||
std::string strUsage = "Bitcoin-cash-seeder\n"; | |||||
strUsage += "Usage: bitcoin-seeder -host=<host> -ns=<ns> " | |||||
"[-mbox=<mbox>] [-threads=<threads>] [-port=<port>]\n"; | |||||
strUsage += "\n" + gArgs.GetHelpMessage(); | |||||
fprintf(stdout, "%s", strUsage.c_str()); | |||||
return true; | |||||
} | |||||
// Error out when loose non-argument tokens are encountered on command line | |||||
for (int i = 1; i < argc; i++) { | |||||
if (!IsSwitchChar(argv[i][0])) { | |||||
fprintf(stderr, | |||||
"Error: Command line contains unexpected token '%s', see " | |||||
"bitcoin-seeder -help for a list of options.\n", | |||||
argv[i]); | |||||
return false; | |||||
} | |||||
} | |||||
deadalnixUnsubmitted Not Done Inline ActionsIs that necessary? It doesn't look like there is a test plan for this. deadalnix: Is that necessary? It doesn't look like there is a test plan for this. | |||||
CDnsSeedOpts opts; | CDnsSeedOpts opts; | ||||
opts.ParseCommandLine(argc, argv); | |||||
// Get whitelist filter flags | |||||
if (gArgs.IsArgSet("-filter")) { | |||||
// Parse whitelist additions | |||||
auto flags = gArgs.GetArg("-filter", ""); | |||||
size_t pos = 0; | |||||
while (pos < flags.size() && pos != std::string::npos) { | |||||
size_t flagEnd = flags.find_first_of(",", pos); | |||||
unsigned long flag = atoi64(flags.substr(pos, (flagEnd - pos))); | |||||
opts.filter_whitelist.insert(flag); | |||||
if (flagEnd == std::string::npos) { | |||||
break; | |||||
} | |||||
pos = flagEnd + 1; | |||||
} | |||||
} | |||||
if (opts.filter_whitelist.empty()) { | |||||
opts.filter_whitelist.insert(NODE_NETWORK); | |||||
opts.filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); | |||||
opts.filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN); | |||||
opts.filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN); | |||||
} | |||||
fprintf(stdout, "Supporting whitelisted filters: "); | fprintf(stdout, "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, ","); | fprintf(stdout, ","); | ||||
} | } | ||||
fprintf(stdout, "0x%lx", (unsigned long)*it); | fprintf(stdout, "0x%lx", (unsigned long)*it); | ||||
} | } | ||||
// Get tor proxy | |||||
if (gArgs.IsArgSet("-onion")) { | |||||
opts.tor = gArgs.GetArg("-onion", "").c_str(); | |||||
} | |||||
fprintf(stdout, "\n"); | fprintf(stdout, "\n"); | ||||
if (opts.tor) { | if (opts.tor) { | ||||
CService service(LookupNumeric(opts.tor, 9050)); | CService service(LookupNumeric(opts.tor, 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using Tor proxy at %s\n", | fprintf(stdout, "Using Tor proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_ONION, proxyType(service)); | SetProxy(NET_ONION, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
// Get ipv4 proxy | |||||
if (gArgs.IsArgSet("-proxyipv4")) { | |||||
opts.ipv6_proxy = gArgs.GetArg("-proxyipv4", "").c_str(); | |||||
} | |||||
if (opts.ipv4_proxy) { | if (opts.ipv4_proxy) { | ||||
CService service(LookupNumeric(opts.ipv4_proxy, 9050)); | CService service(LookupNumeric(opts.ipv4_proxy, 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using IPv4 proxy at %s\n", | fprintf(stdout, "Using IPv4 proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_IPV4, proxyType(service)); | SetProxy(NET_IPV4, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
// Get ipv6 proxy | |||||
if (gArgs.IsArgSet("-proxyipv6")) { | |||||
opts.ipv6_proxy = gArgs.GetArg("-proxyipv6", "").c_str(); | |||||
} | |||||
if (opts.ipv6_proxy) { | if (opts.ipv6_proxy) { | ||||
CService service(LookupNumeric(opts.ipv6_proxy, 9050)); | CService service(LookupNumeric(opts.ipv6_proxy, 9050)); | ||||
if (service.IsValid()) { | if (service.IsValid()) { | ||||
fprintf(stdout, "Using IPv6 proxy at %s\n", | fprintf(stdout, "Using IPv6 proxy at %s\n", | ||||
service.ToStringIPPort().c_str()); | service.ToStringIPPort().c_str()); | ||||
SetProxy(NET_IPV6, proxyType(service)); | SetProxy(NET_IPV6, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
// Get -testnet option | |||||
bool fDNS = true; | bool fDNS = true; | ||||
if (opts.fUseTestNet) { | if (gArgs.GetBoolArg("-testnet", false)) { | ||||
fprintf(stdout, "Using testnet.\n"); | fprintf(stdout, "Using testnet.\n"); | ||||
netMagic[0] = 0xf4; | netMagic[0] = 0xf4; | ||||
netMagic[1] = 0xe5; | netMagic[1] = 0xe5; | ||||
netMagic[2] = 0xf3; | netMagic[2] = 0xf3; | ||||
netMagic[3] = 0xf4; | netMagic[3] = 0xf4; | ||||
seeds = testnet_seeds; | seeds = testnet_seeds; | ||||
fTestNet = true; | fTestNet = true; | ||||
} | } | ||||
if (!opts.ns) { | |||||
// Get hostname of nameserver | |||||
if (gArgs.IsArgSet("-ns")) { | |||||
opts.ns = gArgs.GetArg("-ns", "").c_str(); | |||||
} else { | |||||
// No hostname set | |||||
fprintf(stdout, "No nameserver set. Not starting DNS server.\n"); | fprintf(stdout, "No nameserver set. Not starting DNS server.\n"); | ||||
fDNS = false; | fDNS = false; | ||||
} | } | ||||
// Get hostname of DNS seed | |||||
if (gArgs.IsArgSet("-host")) { | |||||
opts.host = gArgs.GetArg("-host", "").c_str(); | |||||
} | |||||
if (fDNS && !opts.host) { | if (fDNS && !opts.host) { | ||||
fprintf(stderr, "No hostname set. Please use -h.\n"); | fprintf(stderr, "No hostname set. Please use -host.\n"); | ||||
exit(1); | return false; | ||||
} | |||||
// Get email | |||||
if (gArgs.IsArgSet("-mbox")) { | |||||
opts.mbox = gArgs.GetArg("-mbox", "").c_str(); | |||||
} | } | ||||
if (fDNS && !opts.mbox) { | if (fDNS && !opts.mbox) { | ||||
fprintf(stderr, "No e-mail address set. Please use -m.\n"); | fprintf(stderr, "No e-mail address set. Please use -mbox.\n"); | ||||
exit(1); | return false; | ||||
} | } | ||||
FILE *f = fsbridge::fopen("dnsseed.dat", "r"); | FILE *f = fsbridge::fopen("dnsseed.dat", "r"); | ||||
if (f) { | if (f) { | ||||
fprintf(stdout, "Loading dnsseed.dat..."); | fprintf(stdout, "Loading dnsseed.dat..."); | ||||
CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | CAutoFile cf(f, SER_DISK, CLIENT_VERSION); | ||||
cf >> db; | cf >> db; | ||||
if (opts.fWipeBan) db.banned.clear(); | // Check for -wipeban and the -wipeignore | ||||
if (opts.fWipeIgnore) db.ResetIgnores(); | if (gArgs.GetBoolArg("-wipeban", false)) { | ||||
db.banned.clear(); | |||||
} | |||||
if (gArgs.GetBoolArg("-wipeignore", false)) { | |||||
db.ResetIgnores(); | |||||
} | |||||
fprintf(stdout, "done\n"); | fprintf(stdout, "done\n"); | ||||
} | } | ||||
// Get DNS threading and port options | |||||
if (gArgs.IsArgSet("-dnsthreads")) { | |||||
int d = atoi(gArgs.GetArg("-dnsthreads", "4")); | |||||
deadalnixUnsubmitted Not Done Inline Actions... deadalnix: ... | |||||
if (d > 0 && d < 1000) { | |||||
opts.nDnsThreads = d; | |||||
} | |||||
} | |||||
if (gArgs.IsArgSet("-port")) { | |||||
int p = atoi(gArgs.GetArg("-port", "53")); | |||||
if (p > 0 && p < 65536) { | |||||
opts.nPort = p; | |||||
} | |||||
} | |||||
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)...", | fprintf(stdout, "Starting %i DNS threads for %s on %s (port %i)...", | ||||
opts.nDnsThreads, opts.host, opts.ns, opts.nPort); | opts.nDnsThreads, opts.host, opts.ns, 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, "."); | fprintf(stdout, "."); | ||||
Sleep(20); | Sleep(20); | ||||
} | } | ||||
fprintf(stdout, "done\n"); | fprintf(stdout, "done\n"); | ||||
} | } | ||||
// Get threading options | |||||
if (gArgs.IsArgSet("-threads")) { | |||||
int t = atoi(gArgs.GetArg("-threads", "96")); | |||||
if (t > 0 && t < 1000) { | |||||
opts.nThreads = t; | |||||
} | |||||
} | |||||
fprintf(stdout, "Starting seeder..."); | fprintf(stdout, "Starting seeder..."); | ||||
pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); | pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); | ||||
fprintf(stdout, "done\n"); | fprintf(stdout, "done\n"); | ||||
fprintf(stdout, "Starting %i crawler threads...", opts.nThreads); | fprintf(stdout, "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"); | fprintf(stdout, "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 0; | return 0; | ||||
} | } | ||||
int main(int argc, char **argv) { | |||||
return AppInit(argc, argv); | |||||
deadalnixUnsubmitted Not Done Inline ActionsClearly, AppInit isn't doing simply initialization. In addition, why is that necessary? deadalnix: Clearly, AppInit isn't doing simply initialization. In addition, why is that necessary? | |||||
} |
It is worth noting that this isn't present in other utilities we have, and yet, this parameter works. There must be something at play.