Changeset 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 <pthread.h> | #include <pthread.h> | ||||
const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr; | const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr; | ||||
static const int DEFAULT_NUM_THREADS = 96; | static const int DEFAULT_NUM_THREADS = 96; | ||||
static const int DEFAULT_PORT = 53; | static const int DEFAULT_PORT = 53; | ||||
static const int DEFAULT_NUM_DNS_THREADS = 4; | static const int DEFAULT_NUM_DNS_THREADS = 4; | ||||
static const bool DEFAULT_TESTNET = false; | static const bool DEFAULT_TESTNET = false; | ||||
static const bool DEFAULT_WIPE_BAN = false; | static const bool DEFAULT_WIPE_BAN = false; | ||||
static const bool DEFAULT_WIPE_IGNORE = false; | static const bool DEFAULT_WIPE_IGNORE = false; | ||||
static const std::string DEFAULT_EMAIL = ""; | static const std::string DEFAULT_EMAIL = ""; | ||||
static const std::string DEFAULT_NAMESERVER = ""; | static const std::string DEFAULT_NAMESERVER = ""; | ||||
static const std::string DEFAULT_HOST = ""; | static const std::string DEFAULT_HOST = ""; | ||||
static const std::string DEFAULT_TOR_PROXY = ""; | static const std::string DEFAULT_TOR_PROXY = ""; | ||||
static const std::string DEFAULT_IPV4_PROXY = ""; | static const std::string DEFAULT_IPV4_PROXY = ""; | ||||
static const std::string DEFAULT_IPV6_PROXY = ""; | static const std::string DEFAULT_IPV6_PROXY = ""; | ||||
enum class ParseStatus { | |||||
RunSeeder, | |||||
deadalnix: How is `RunSeeder` even a `ParseStatus` ?
The structure is better now, but these names are… | |||||
HelpRequested, | |||||
ParseError, | |||||
deadalnixUnsubmitted Not Done Inline ActionsThat seems to be a classic case of smurf naming. If the error wasn't about parsing, then that'd be a very good sign that the whole approach is cursed and should be reconsidered. And if it is, then why say it? deadalnix: That seems to be a classic case of smurf naming. If the error wasn't about parsing, then that'd… | |||||
}; | |||||
deadalnixUnsubmitted Not Done Inline ActionsThis would probably benefit being scoped in CDnsSeedOpts because ParseStatus is not something that does make sense in isolation. What was parsed? Is it even a status to begin with? The parser having a status would seems to indicate is is still doing something and is in some state - it has a STATus. But in this case, the parsing process is finished. deadalnix: This would probably benefit being scoped in `CDnsSeedOpts` because `ParseStatus` is not… | |||||
class CDnsSeedOpts { | class CDnsSeedOpts { | ||||
public: | public: | ||||
int nThreads; | int nThreads; | ||||
int nPort; | int nPort; | ||||
int nDnsThreads; | int nDnsThreads; | ||||
int fUseTestNet; | bool fUseTestNet; | ||||
int fWipeBan; | bool fWipeBan; | ||||
int fWipeIgnore; | bool fWipeIgnore; | ||||
std::string mbox; | std::string mbox; | ||||
std::string ns; | std::string ns; | ||||
std::string host; | std::string host; | ||||
std::string tor; | std::string tor; | ||||
std::string ipv4_proxy; | std::string ipv4_proxy; | ||||
std::string ipv6_proxy; | std::string ipv6_proxy; | ||||
std::set<uint64_t> filter_whitelist; | std::set<uint64_t> filter_whitelist; | ||||
CDnsSeedOpts() | CDnsSeedOpts() | ||||
: nThreads(DEFAULT_NUM_THREADS), nPort(DEFAULT_PORT), | : nThreads(DEFAULT_NUM_THREADS), nPort(DEFAULT_PORT), | ||||
nDnsThreads(DEFAULT_NUM_DNS_THREADS), fUseTestNet(DEFAULT_TESTNET), | nDnsThreads(DEFAULT_NUM_DNS_THREADS), fUseTestNet(DEFAULT_TESTNET), | ||||
fWipeBan(DEFAULT_WIPE_BAN), fWipeIgnore(DEFAULT_WIPE_IGNORE), | fWipeBan(DEFAULT_WIPE_BAN), fWipeIgnore(DEFAULT_WIPE_IGNORE), | ||||
mbox(DEFAULT_EMAIL), ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), | mbox(DEFAULT_EMAIL), ns(DEFAULT_NAMESERVER), host(DEFAULT_HOST), | ||||
tor(DEFAULT_TOR_PROXY), ipv4_proxy(DEFAULT_IPV4_PROXY), | tor(DEFAULT_TOR_PROXY), ipv4_proxy(DEFAULT_IPV4_PROXY), | ||||
ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ipv6_proxy(DEFAULT_IPV6_PROXY) {} | ||||
void ParseCommandLine(int argc, char **argv) { | ParseStatus ParseCommandLine(int argc, char **argv) { | ||||
static const char *help = | SetupSeederArgs(); | ||||
"Bitcoin-cash-seeder\n" | std::string error; | ||||
"Usage: %s -h <host> -n <ns> [-m <mbox>] [-t <threads>] [-p " | if (!gArgs.ParseParameters(argc, argv, error)) { | ||||
"<port>]\n" | fprintf(stderr, "Error parsing command line arguments: %s\n", | ||||
"\n" | error.c_str()); | ||||
"Options:\n" | return ParseStatus::ParseError; | ||||
"-h <host> Hostname of the DNS seed\n" | } | ||||
"-n <ns> Hostname of the nameserver\n" | if (HelpRequested(gArgs)) { | ||||
"-m <mbox> E-Mail address reported in SOA records\n" | std::string strUsage = "Bitcoin-cash-seeder\nUsage: bitcoin-seeder " | ||||
"-t <threads> Number of crawlers to run in parallel (default " | "-host=<host> -ns=<ns> [-mbox=<mbox>] " | ||||
"96)\n" | "[-threads=<threads>] [-port=<port>]\n\n" + | ||||
"-d <threads> Number of DNS server threads (default 4)\n" | gArgs.GetHelpMessage(); | ||||
"-p <port> UDP port to listen on (default 53)\n" | |||||
"-o <ip:port> Tor proxy IP/Port\n" | fprintf(stdout, "%s", strUsage.c_str()); | ||||
"-i <ip:port> IPV4 SOCKS5 proxy IP/Port\n" | return ParseStatus::HelpRequested; | ||||
"-k <ip:port> IPV6 SOCKS5 proxy IP/Port\n" | } | ||||
"-w f1,f2,... Allow these flag combinations as filters\n" | |||||
"--testnet Use testnet\n" | nThreads = gArgs.GetArg("-threads", DEFAULT_NUM_THREADS); | ||||
"--wipeban Wipe list of banned nodes\n" | nPort = gArgs.GetArg("-port", DEFAULT_PORT); | ||||
"--wipeignore Wipe list of ignored nodes\n" | nDnsThreads = gArgs.GetArg("-dnsthreads", DEFAULT_NUM_DNS_THREADS); | ||||
"-?, --help Show this text\n" | fUseTestNet = gArgs.GetBoolArg("-testnet", DEFAULT_TESTNET); | ||||
"\n"; | fWipeBan = gArgs.GetBoolArg("-wipeban", DEFAULT_WIPE_BAN); | ||||
bool showHelp = false; | fWipeIgnore = gArgs.GetBoolArg("-wipeignore", DEFAULT_WIPE_IGNORE); | ||||
mbox = gArgs.GetArg("-mbox", DEFAULT_EMAIL); | |||||
while (1) { | ns = gArgs.GetArg("-ns", DEFAULT_NAMESERVER); | ||||
static struct option long_options[] = { | host = gArgs.GetArg("-host", DEFAULT_HOST); | ||||
{"host", required_argument, 0, 'h'}, | tor = gArgs.GetArg("-onion", DEFAULT_TOR_PROXY); | ||||
{"ns", required_argument, 0, 'n'}, | ipv4_proxy = gArgs.GetArg("-proxyipv4", DEFAULT_IPV4_PROXY); | ||||
{"mbox", required_argument, 0, 'm'}, | ipv6_proxy = gArgs.GetArg("-proxyipv6", DEFAULT_IPV6_PROXY); | ||||
{"threads", required_argument, 0, 't'}, | |||||
{"dnsthreads", required_argument, 0, 'd'}, | if (gArgs.IsArgSet("-filter")) { | ||||
{"port", required_argument, 0, 'p'}, | // Parse whitelist additions | ||||
{"onion", required_argument, 0, 'o'}, | std::string flags = gArgs.GetArg("-filter", ""); | ||||
{"proxyipv4", required_argument, 0, 'i'}, | size_t flagstartpos = 0; | ||||
{"proxyipv6", required_argument, 0, 'k'}, | while (flagstartpos < flags.size()) { | ||||
{"filter", required_argument, 0, 'w'}, | size_t flagendpos = flags.find_first_of(",", flagstartpos); | ||||
{"testnet", no_argument, &fUseTestNet, 1}, | uint64_t flag = atoi64( | ||||
{"wipeban", no_argument, &fWipeBan, 1}, | flags.substr(flagstartpos, (flagendpos - flagstartpos))); | ||||
{"wipeignore", no_argument, &fWipeIgnore, 1}, | filter_whitelist.insert(flag); | ||||
{"help", no_argument, 0, 'h'}, | if (flagendpos == std::string::npos) { | ||||
{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 = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'm': { | |||||
mbox = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'n': { | |||||
ns = std::string(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 = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'i': { | |||||
ipv4_proxy = std::string(optarg); | |||||
break; | |||||
} | |||||
case 'k': { | |||||
ipv6_proxy = std::string(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; | break; | ||||
} | } | ||||
flagstartpos = flagendpos + 1; | |||||
} | } | ||||
} | } | ||||
if (filter_whitelist.empty()) { | if (filter_whitelist.empty()) { | ||||
filter_whitelist.insert(NODE_NETWORK); | filter_whitelist.insert(NODE_NETWORK); | ||||
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); | filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM); | ||||
filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN); | filter_whitelist.insert(NODE_NETWORK | NODE_XTHIN); | ||||
filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN); | filter_whitelist.insert(NODE_NETWORK | NODE_BLOOM | NODE_XTHIN); | ||||
} | } | ||||
if (!host.empty() && ns.empty()) showHelp = true; | return ParseStatus::RunSeeder; | ||||
if (showHelp) fprintf(stderr, help, argv[0]); | } | ||||
private: | |||||
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::CONNECTION); | |||||
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); | |||||
deadalnixUnsubmitted Not Done Inline ActionsThis is still not how it is done thorough the codebase. It is important because without doing it like the rest of the application expect, you will not be able to use the chain params, and will have to continue to duplicate infos such as net magic. deadalnix: This is still not how it is done thorough the codebase. It is important because without doing… | |||||
nakihitoAuthorUnsubmitted Done Inline ActionsThis is exactly what is done by bitcoin-cli.cpp (line 58 and 149) and chainparamsbase.cpp (lines 23-24). Are you saying I should use SetupChainParamsBaseOptions()? The seeder doesn't really make any sense to run on regtest, so adding that to the help message (or even as an option in general) would only serve to cause confusion. nakihito: This is exactly what is done by `bitcoin-cli.cpp` (line 58 and 149) and `chainparamsbase.cpp`… | |||||
nakihitoAuthorUnsubmitted Done Inline ActionsSorry, I misunderstood how regtest worked. Got a better understanding of the problem after talking with Jason. nakihito: Sorry, I misunderstood how regtest worked. Got a better understanding of the problem after… | |||||
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); | |||||
} | } | ||||
}; | }; | ||||
extern "C" { | extern "C" { | ||||
#include <seeder/dns.h> | #include <seeder/dns.h> | ||||
} | } | ||||
CAddrDb db; | CAddrDb db; | ||||
▲ Show 20 Lines • Show All 300 Lines • ▼ Show 20 Lines | |||||
int main(int argc, char **argv) { | int main(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); | ||||
CDnsSeedOpts opts; | CDnsSeedOpts opts; | ||||
opts.ParseCommandLine(argc, argv); | ParseStatus parseResults = opts.ParseCommandLine(argc, argv); | ||||
if (parseResults == ParseStatus::HelpRequested) { | |||||
return 0; | |||||
deadalnixUnsubmitted Not Done Inline ActionsEXIT_SUCCESS deadalnix: EXIT_SUCCESS | |||||
} | |||||
if (parseResults == ParseStatus::ParseError) { | |||||
return 1; | |||||
deadalnixUnsubmitted Not Done Inline ActionsEXIT_FAILURE deadalnix: EXIT_FAILURE | |||||
} | |||||
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); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 95 Lines • Show Last 20 Lines |
How is RunSeeder even a ParseStatus ?
The structure is better now, but these names are clearly working against the comprehension of the code rather than the opposite.