You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
10 KiB
355 lines
10 KiB
// Copyright (c) 2009-2010 Satoshi Nakamoto |
|
// Copyright (c) 2009-2017 The Bitcoin Core developers |
|
// Distributed under the MIT software license, see the accompanying |
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php. |
|
|
|
/** |
|
* Server/client environment: argument handling, config file parsing, |
|
* logging, thread wrappers, startup time |
|
*/ |
|
#ifndef BITCOIN_UTIL_H |
|
#define BITCOIN_UTIL_H |
|
|
|
#if defined(HAVE_CONFIG_H) |
|
#include <config/bitcoin-config.h> |
|
#endif |
|
|
|
#include <compat.h> |
|
#include <fs.h> |
|
#include <sync.h> |
|
#include <tinyformat.h> |
|
#include <utiltime.h> |
|
|
|
#include <atomic> |
|
#include <exception> |
|
#include <map> |
|
#include <memory> |
|
#include <stdint.h> |
|
#include <string> |
|
#include <vector> |
|
|
|
#include <boost/signals2/signal.hpp> |
|
#include <boost/thread/condition_variable.hpp> // for boost::thread_interrupted |
|
|
|
// Application startup time (used for uptime calculation) |
|
int64_t GetStartupTime(); |
|
|
|
static const bool DEFAULT_LOGTIMEMICROS = false; |
|
static const bool DEFAULT_LOGIPS = false; |
|
static const bool DEFAULT_LOGTIMESTAMPS = true; |
|
extern const char * const DEFAULT_DEBUGLOGFILE; |
|
|
|
/** Signals for translation. */ |
|
class CTranslationInterface |
|
{ |
|
public: |
|
/** Translate a message to the native language of the user. */ |
|
boost::signals2::signal<std::string (const char* psz)> Translate; |
|
}; |
|
|
|
extern bool fPrintToConsole; |
|
extern bool fPrintToDebugLog; |
|
|
|
extern bool fLogTimestamps; |
|
extern bool fLogTimeMicros; |
|
extern bool fLogIPs; |
|
extern std::atomic<bool> fReopenDebugLog; |
|
extern CTranslationInterface translationInterface; |
|
|
|
extern const char * const BITCOIN_CONF_FILENAME; |
|
extern const char * const BITCOIN_PID_FILENAME; |
|
|
|
extern std::atomic<uint32_t> logCategories; |
|
|
|
/** |
|
* Translation function: Call Translate signal on UI interface, which returns a boost::optional result. |
|
* If no translation slot is registered, nothing is returned, and simply return the input. |
|
*/ |
|
inline std::string _(const char* psz) |
|
{ |
|
boost::optional<std::string> rv = translationInterface.Translate(psz); |
|
return rv ? (*rv) : psz; |
|
} |
|
|
|
void SetupEnvironment(); |
|
bool SetupNetworking(); |
|
|
|
struct CLogCategoryActive |
|
{ |
|
std::string category; |
|
bool active; |
|
}; |
|
|
|
namespace BCLog { |
|
enum LogFlags : uint32_t { |
|
NONE = 0, |
|
NET = (1 << 0), |
|
TOR = (1 << 1), |
|
MEMPOOL = (1 << 2), |
|
HTTP = (1 << 3), |
|
BENCH = (1 << 4), |
|
ZMQ = (1 << 5), |
|
DB = (1 << 6), |
|
RPC = (1 << 7), |
|
ESTIMATEFEE = (1 << 8), |
|
ADDRMAN = (1 << 9), |
|
SELECTCOINS = (1 << 10), |
|
REINDEX = (1 << 11), |
|
CMPCTBLOCK = (1 << 12), |
|
RAND = (1 << 13), |
|
PRUNE = (1 << 14), |
|
PROXY = (1 << 15), |
|
MEMPOOLREJ = (1 << 16), |
|
LIBEVENT = (1 << 17), |
|
COINDB = (1 << 18), |
|
QT = (1 << 19), |
|
LEVELDB = (1 << 20), |
|
KEVA = (1 << 21), |
|
ALL = ~(uint32_t)0, |
|
}; |
|
} |
|
/** Return true if log accepts specified category */ |
|
static inline bool LogAcceptCategory(uint32_t category) |
|
{ |
|
return (logCategories.load(std::memory_order_relaxed) & category) != 0; |
|
} |
|
|
|
/** Returns a string with the log categories. */ |
|
std::string ListLogCategories(); |
|
|
|
/** Returns a vector of the active log categories. */ |
|
std::vector<CLogCategoryActive> ListActiveLogCategories(); |
|
|
|
/** Return true if str parses as a log category and set the flags in f */ |
|
bool GetLogCategory(uint32_t *f, const std::string *str); |
|
|
|
/** Send a string to the log output */ |
|
int LogPrintStr(const std::string &str); |
|
|
|
/** Get format string from VA_ARGS for error reporting */ |
|
template<typename... Args> std::string FormatStringFromLogArgs(const char *fmt, const Args&... args) { return fmt; } |
|
|
|
static inline void MarkUsed() {} |
|
template<typename T, typename... Args> static inline void MarkUsed(const T& t, const Args&... args) |
|
{ |
|
(void)t; |
|
MarkUsed(args...); |
|
} |
|
|
|
// Be conservative when using LogPrintf/error or other things which |
|
// unconditionally log to debug.log! It should not be the case that an inbound |
|
// peer can fill up a users disk with debug.log entries. |
|
|
|
#ifdef USE_COVERAGE |
|
#define LogPrintf(...) do { MarkUsed(__VA_ARGS__); } while(0) |
|
#define LogPrint(category, ...) do { MarkUsed(__VA_ARGS__); } while(0) |
|
#else |
|
#define LogPrintf(...) do { \ |
|
std::string _log_msg_; /* Unlikely name to avoid shadowing variables */ \ |
|
try { \ |
|
_log_msg_ = tfm::format(__VA_ARGS__); \ |
|
} catch (tinyformat::format_error &fmterr) { \ |
|
/* Original format string will have newline so don't add one here */ \ |
|
_log_msg_ = "Error \"" + std::string(fmterr.what()) + "\" while formatting log message: " + FormatStringFromLogArgs(__VA_ARGS__); \ |
|
} \ |
|
LogPrintStr(_log_msg_); \ |
|
} while(0) |
|
|
|
#define LogPrint(category, ...) do { \ |
|
if (LogAcceptCategory((category))) { \ |
|
LogPrintf(__VA_ARGS__); \ |
|
} \ |
|
} while(0) |
|
#endif |
|
|
|
template<typename... Args> |
|
bool error(const char* fmt, const Args&... args) |
|
{ |
|
LogPrintStr("ERROR: " + tfm::format(fmt, args...) + "\n"); |
|
return false; |
|
} |
|
|
|
void PrintExceptionContinue(const std::exception *pex, const char* pszThread); |
|
void FileCommit(FILE *file); |
|
bool TruncateFile(FILE *file, unsigned int length); |
|
int RaiseFileDescriptorLimit(int nMinFD); |
|
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length); |
|
bool RenameOver(fs::path src, fs::path dest); |
|
bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false); |
|
|
|
/** Release all directory locks. This is used for unit testing only, at runtime |
|
* the global destructor will take care of the locks. |
|
*/ |
|
void ReleaseDirectoryLocks(); |
|
|
|
bool TryCreateDirectories(const fs::path& p); |
|
fs::path GetDefaultDataDir(); |
|
const fs::path &GetDataDir(bool fNetSpecific = true); |
|
void ClearDatadirCache(); |
|
fs::path GetConfigFile(const std::string& confPath); |
|
#ifndef WIN32 |
|
fs::path GetPidFile(); |
|
void CreatePidFile(const fs::path &path, pid_t pid); |
|
#endif |
|
#ifdef WIN32 |
|
fs::path GetSpecialFolderPath(int nFolder, bool fCreate = true); |
|
#endif |
|
fs::path GetDebugLogPath(); |
|
bool OpenDebugLog(); |
|
void ShrinkDebugFile(); |
|
void runCommand(const std::string& strCommand); |
|
|
|
inline bool IsSwitchChar(char c) |
|
{ |
|
#ifdef WIN32 |
|
return c == '-' || c == '/'; |
|
#else |
|
return c == '-'; |
|
#endif |
|
} |
|
|
|
class ArgsManager |
|
{ |
|
protected: |
|
mutable CCriticalSection cs_args; |
|
std::map<std::string, std::string> mapArgs; |
|
std::map<std::string, std::vector<std::string>> mapMultiArgs; |
|
public: |
|
void ParseParameters(int argc, const char*const argv[]); |
|
void ReadConfigFile(const std::string& confPath); |
|
|
|
/** |
|
* Return a vector of strings of the given argument |
|
* |
|
* @param strArg Argument to get (e.g. "-foo") |
|
* @return command-line arguments |
|
*/ |
|
std::vector<std::string> GetArgs(const std::string& strArg) const; |
|
|
|
/** |
|
* Return true if the given argument has been manually set |
|
* |
|
* @param strArg Argument to get (e.g. "-foo") |
|
* @return true if the argument has been set |
|
*/ |
|
bool IsArgSet(const std::string& strArg) const; |
|
|
|
/** |
|
* Return string argument or default value |
|
* |
|
* @param strArg Argument to get (e.g. "-foo") |
|
* @param strDefault (e.g. "1") |
|
* @return command-line argument or default value |
|
*/ |
|
std::string GetArg(const std::string& strArg, const std::string& strDefault) const; |
|
|
|
/** |
|
* Return integer argument or default value |
|
* |
|
* @param strArg Argument to get (e.g. "-foo") |
|
* @param nDefault (e.g. 1) |
|
* @return command-line argument (0 if invalid number) or default value |
|
*/ |
|
int64_t GetArg(const std::string& strArg, int64_t nDefault) const; |
|
|
|
/** |
|
* Return boolean argument or default value |
|
* |
|
* @param strArg Argument to get (e.g. "-foo") |
|
* @param fDefault (true or false) |
|
* @return command-line argument or default value |
|
*/ |
|
bool GetBoolArg(const std::string& strArg, bool fDefault) const; |
|
|
|
/** |
|
* Set an argument if it doesn't already have a value |
|
* |
|
* @param strArg Argument to set (e.g. "-foo") |
|
* @param strValue Value (e.g. "1") |
|
* @return true if argument gets set, false if it already had a value |
|
*/ |
|
bool SoftSetArg(const std::string& strArg, const std::string& strValue); |
|
|
|
/** |
|
* Set a boolean argument if it doesn't already have a value |
|
* |
|
* @param strArg Argument to set (e.g. "-foo") |
|
* @param fValue Value (e.g. false) |
|
* @return true if argument gets set, false if it already had a value |
|
*/ |
|
bool SoftSetBoolArg(const std::string& strArg, bool fValue); |
|
|
|
// Forces an arg setting. Called by SoftSetArg() if the arg hasn't already |
|
// been set. Also called directly in testing. |
|
void ForceSetArg(const std::string& strArg, const std::string& strValue); |
|
}; |
|
|
|
extern ArgsManager gArgs; |
|
|
|
/** |
|
* Format a string to be used as group of options in help messages |
|
* |
|
* @param message Group name (e.g. "RPC server options:") |
|
* @return the formatted string |
|
*/ |
|
std::string HelpMessageGroup(const std::string& message); |
|
|
|
/** |
|
* Format a string to be used as option description in help messages |
|
* |
|
* @param option Option message (e.g. "-rpcuser=<user>") |
|
* @param message Option description (e.g. "Username for JSON-RPC connections") |
|
* @return the formatted string |
|
*/ |
|
std::string HelpMessageOpt(const std::string& option, const std::string& message); |
|
|
|
/** |
|
* Return the number of physical cores available on the current system. |
|
* @note This does not count virtual cores, such as those provided by HyperThreading |
|
* when boost is newer than 1.56. |
|
*/ |
|
int GetNumCores(); |
|
|
|
void RenameThread(const char* name); |
|
|
|
/** |
|
* .. and a wrapper that just calls func once |
|
*/ |
|
template <typename Callable> void TraceThread(const char* name, Callable func) |
|
{ |
|
std::string s = strprintf("bitcoin-%s", name); |
|
RenameThread(s.c_str()); |
|
try |
|
{ |
|
LogPrintf("%s thread start\n", name); |
|
func(); |
|
LogPrintf("%s thread exit\n", name); |
|
} |
|
catch (const boost::thread_interrupted&) |
|
{ |
|
LogPrintf("%s thread interrupt\n", name); |
|
throw; |
|
} |
|
catch (const std::exception& e) { |
|
PrintExceptionContinue(&e, name); |
|
throw; |
|
} |
|
catch (...) { |
|
PrintExceptionContinue(nullptr, name); |
|
throw; |
|
} |
|
} |
|
|
|
std::string CopyrightHolders(const std::string& strPrefix); |
|
|
|
//! Substitute for C++14 std::make_unique. |
|
template <typename T, typename... Args> |
|
std::unique_ptr<T> MakeUnique(Args&&... args) |
|
{ |
|
return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
|
} |
|
|
|
double ConvertNBitsToDiff(uint32_t nBits); |
|
uint64_t ConvertNBitsToDiffU64(uint32_t nBits); |
|
|
|
#endif // BITCOIN_UTIL_H
|
|
|