Changeset View
Changeset View
Standalone View
Standalone View
src/seeder/main.cpp
// Copyright (c) 2017-2020 The Bitcoin developers | // Copyright (c) 2017-2020 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <chainparams.h> | #include <chainparams.h> | ||||
#include <clientversion.h> | #include <clientversion.h> | ||||
#include <fs.h> | #include <fs.h> | ||||
#include <init.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/strencodings.h> | ||||
#include <util/system.h> | #include <util/system.h> | ||||
Show All 17 Lines | |||||
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 = ""; | ||||
static const std::string DEFAULT_SEEDER_DEBUGLOGFILE = "seederdebug.log"; | |||||
class CDnsSeedOpts { | class CDnsSeedOpts { | ||||
public: | public: | ||||
int nThreads; | int nThreads; | ||||
int nPort; | int nPort; | ||||
int nDnsThreads; | int nDnsThreads; | ||||
bool fWipeBan; | bool fWipeBan; | ||||
bool fWipeIgnore; | bool fWipeIgnore; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | int ParseCommandLine(int argc, char **argv) { | ||||
"Specified data directory \"%s\" does not exist.\n", | "Specified data directory \"%s\" does not exist.\n", | ||||
gArgs.GetArg("-datadir", "")); | gArgs.GetArg("-datadir", "")); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | ||||
} | } | ||||
// Warn about relative -datadir path | // Warn about relative -datadir path | ||||
if (gArgs.IsArgSet("-datadir") && | if (gArgs.IsArgSet("-datadir") && | ||||
!fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) { | !fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) { | ||||
tfm::format( | LogPrintf("Warning: relative datadir option '%s' specified, which " | ||||
std::cout, | "will be interpreted relative to the current working " | ||||
"Warning: relative datadir option '%s' specified, which will " | "directory '%s'. This is fragile, because if the seeder " | ||||
"be interpreted relative to the current working directory " | "is started in the future from a different location, it " | ||||
"'%s'. This is fragile, because if the seeder is started in " | "will be unable to locate the current data files.\n", | ||||
"the future from a different location, it will be unable to " | gArgs.GetArg("-datadir", ""), | ||||
"locate the current data files.\n", | fs::current_path().string()); | ||||
gArgs.GetArg("-datadir", ""), fs::current_path().string()); | |||||
} | } | ||||
tfm::format(std::cout, "Default data directory %s\n", | LogPrintf("Default data directory %s\n", | ||||
GetDefaultDataDir().string() + "/seeder"); | GetDefaultDataDir().string() + "/seeder"); | ||||
tfm::format(std::cout, "Using data directory %s\n", | LogPrintf("Using data directory %s\n", GetDataDir().string()); | ||||
GetDataDir().string()); | |||||
if (gArgs.IsArgSet("-filter")) { | if (gArgs.IsArgSet("-filter")) { | ||||
// Parse whitelist additions | // Parse whitelist additions | ||||
std::string flagString = gArgs.GetArg("-filter", ""); | std::string flagString = gArgs.GetArg("-filter", ""); | ||||
size_t flagstartpos = 0; | size_t flagstartpos = 0; | ||||
while (flagstartpos < flagString.size()) { | while (flagstartpos < flagString.size()) { | ||||
size_t flagendpos = flagString.find_first_of(',', flagstartpos); | size_t flagendpos = flagString.find_first_of(',', flagstartpos); | ||||
uint64_t flag = atoi64(flagString.substr( | uint64_t flag = atoi64(flagString.substr( | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | void SetupSeederArgs() { | ||||
ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); | ||||
gArgs.AddArg("-help-debug", | gArgs.AddArg("-help-debug", | ||||
"Show all debugging options (usage: --help -help-debug)", | "Show all debugging options (usage: --help -help-debug)", | ||||
ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); | ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); | ||||
gArgs.AddArg( | gArgs.AddArg( | ||||
"-datadir=<dir>", | "-datadir=<dir>", | ||||
"Specifies the directory that the seeder reads from and writes to.", | "Specifies the directory that the seeder reads from and writes to.", | ||||
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | ||||
gArgs.AddArg("-printtoconsole", | |||||
"Send trace/debug info to console (default: 1)", | |||||
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | |||||
gArgs.AddArg("-debuglogfile=<file>", | |||||
"Specify location of debug log file. Relative paths will " | |||||
"be prefixed by a net-specific datadir location. (0 to " | |||||
"disbale; default: seederdebug.log)", | |||||
ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); | |||||
SetupChainParamsBaseOptions(); | SetupChainParamsBaseOptions(); | ||||
gArgs.AddArg("-help", "", ArgsManager::ALLOW_ANY, | gArgs.AddArg("-help", "", ArgsManager::ALLOW_ANY, | ||||
OptionsCategory::HIDDEN); | OptionsCategory::HIDDEN); | ||||
gArgs.AddArg("-h", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN); | gArgs.AddArg("-h", "", ArgsManager::ALLOW_ANY, OptionsCategory::HIDDEN); | ||||
} | } | ||||
}; | }; | ||||
▲ Show 20 Lines • Show All 307 Lines • ▼ Show 20 Lines | do { | ||||
} | } | ||||
} | } | ||||
Sleep(1800000); | Sleep(1800000); | ||||
} while (1); | } while (1); | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
// The logger dump everything on the console by default. | |||||
LogInstance().m_print_to_console = true; | |||||
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; | ||||
} | } | ||||
tfm::format(std::cout, "Supporting whitelisted filters: "); | // Set up logger | ||||
BCLog::Logger &logger = LogInstance(); | |||||
logger.m_print_to_console = gArgs.GetBoolArg("-printtoconsole", true); | |||||
logger.m_print_to_file = !gArgs.IsArgNegated("-debuglogfile"); | |||||
logger.m_file_path = AbsPathForConfigVal( | |||||
gArgs.GetArg("-debuglogfile", DEFAULT_SEEDER_DEBUGLOGFILE)); | |||||
if (!logger.StartLogging()) { | |||||
logger.m_print_to_file = false; | |||||
tfm::format(std::cout, "Could not open debug log file %s\n", | |||||
logger.m_file_path.string()); | |||||
tfm::format(std::cout, "Logging only to console\n"); | |||||
} | |||||
if (!logger.m_log_timestamps) { | |||||
LogPrintf("Startup time: %s\n", FormatISO8601DateTime(GetTime())); | |||||
} | |||||
LogPrintf(PACKAGE_NAME " Seeder version %s\n", FormatFullVersion()); | |||||
LogPrintfToBeContinued("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()) { | ||||
tfm::format(std::cout, ","); | LogPrintfToBeContinued(","); | ||||
} | } | ||||
tfm::format(std::cout, "0x%lx", (unsigned long)*it); | LogPrintfToBeContinued("0x%lx", (unsigned long)*it); | ||||
} | } | ||||
tfm::format(std::cout, "\n"); | LogPrintf("\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()) { | ||||
tfm::format(std::cout, "Using Tor proxy at %s\n", | LogPrintf("Using Tor proxy at %s\n", service.ToStringIPPort()); | ||||
service.ToStringIPPort()); | |||||
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()) { | ||||
tfm::format(std::cout, "Using IPv4 proxy at %s\n", | LogPrintf("Using IPv4 proxy at %s\n", service.ToStringIPPort()); | ||||
service.ToStringIPPort()); | |||||
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()) { | ||||
tfm::format(std::cout, "Using IPv6 proxy at %s\n", | LogPrintf("Using IPv6 proxy at %s\n", service.ToStringIPPort()); | ||||
service.ToStringIPPort()); | |||||
SetProxy(NET_IPV6, proxyType(service)); | SetProxy(NET_IPV6, proxyType(service)); | ||||
} | } | ||||
} | } | ||||
bool fDNS = true; | bool fDNS = true; | ||||
tfm::format(std::cout, "Using %s.\n", gArgs.GetChainName()); | LogPrintf("Using %s.\n", gArgs.GetChainName()); | ||||
netMagic = Params().NetMagic(); | netMagic = Params().NetMagic(); | ||||
if (opts.ns.empty()) { | if (opts.ns.empty()) { | ||||
tfm::format(std::cout, "No nameserver set. Not starting DNS server.\n"); | LogPrintf("No nameserver set. Not starting DNS server.\n"); | ||||
fDNS = false; | fDNS = false; | ||||
} | } | ||||
if (fDNS && opts.host.empty()) { | if (fDNS && opts.host.empty()) { | ||||
tfm::format(std::cerr, "No hostname set. Please use -h.\n"); | LogPrintf("No hostname set. Please use -h.\n"); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | ||||
} | } | ||||
if (fDNS && opts.mbox.empty()) { | if (fDNS && opts.mbox.empty()) { | ||||
tfm::format(std::cerr, "No e-mail address set. Please use -m.\n"); | LogPrintf("No e-mail address set. Please use -m.\n"); | ||||
return EXIT_FAILURE; | return EXIT_FAILURE; | ||||
} | } | ||||
FILE *f = fsbridge::fopen(GetDataDir() / "dnsseed.dat", "r"); | FILE *f = fsbridge::fopen(GetDataDir() / "dnsseed.dat", "r"); | ||||
if (f) { | if (f) { | ||||
tfm::format(std::cout, "Loading dnsseed.dat..."); | LogPrintfToBeContinued("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(); | ||||
tfm::format(std::cout, "Ban list wiped..."); | LogPrintfToBeContinued("Ban list wiped..."); | ||||
} | } | ||||
if (opts.fWipeIgnore) { | if (opts.fWipeIgnore) { | ||||
db.ResetIgnores(); | db.ResetIgnores(); | ||||
tfm::format(std::cout, "Ignore list wiped..."); | LogPrintfToBeContinued("Ignore list wiped..."); | ||||
} | } | ||||
tfm::format(std::cout, "done\n"); | LogPrintf("done\n"); | ||||
} | } | ||||
pthread_t threadDns, threadSeed, threadDump, threadStats; | pthread_t threadDns, threadSeed, threadDump, threadStats; | ||||
if (fDNS) { | if (fDNS) { | ||||
tfm::format(std::cout, | LogPrintfToBeContinued( | ||||
"Starting %i DNS threads for %s on %s (port %i)...", | "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]); | ||||
tfm::format(std::cout, "."); | LogPrintfToBeContinued("."); | ||||
Sleep(20); | Sleep(20); | ||||
} | } | ||||
tfm::format(std::cout, "done\n"); | LogPrintf("done\n"); | ||||
} | } | ||||
tfm::format(std::cout, "Starting seeder..."); | LogPrintfToBeContinued("Starting seeder..."); | ||||
pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); | pthread_create(&threadSeed, nullptr, ThreadSeeder, nullptr); | ||||
tfm::format(std::cout, "done\n"); | LogPrintf("done\n"); | ||||
tfm::format(std::cout, "Starting %i crawler threads...", opts.nThreads); | LogPrintfToBeContinued("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); | ||||
tfm::format(std::cout, "done\n"); | LogPrintf("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; | ||||
} | } |