// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
# ifndef WIN32
// for posix_fallocate
# ifdef __linux__
# define _POSIX_C_SOURCE 200112L
# endif
# include <algorithm>
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/resource.h>
# endif
# include "chainparams.h"
# include "util.h"
# include "sync.h"
# include "version.h"
# include "ui_interface.h"
# include <boost/algorithm/string/join.hpp>
# include <boost/algorithm/string/case_conv.hpp> // for to_lower()
# include <boost/algorithm/string/predicate.hpp> // for startswith() and endswith()
// Work around clang compilation problem in Boost 1.46:
// /usr/include/boost/program_options/detail/config_file.hpp:163:17: error: call to function 'to_internal' that is neither visible in the template definition nor found by argument-dependent lookup
// See also: http://stackoverflow.com/questions/10020179/compilation-fail-in-boost-librairies-program-options
// http://clang.debian.net/status.php?version=3.0&key=CANNOT_FIND_FUNCTION
namespace boost {
namespace program_options {
std : : string to_internal ( const std : : string & ) ;
}
}
# include <boost/program_options/detail/config_file.hpp>
# include <boost/program_options/parsers.hpp>
# include <boost/filesystem.hpp>
# include <boost/filesystem/fstream.hpp>
# include <boost/foreach.hpp>
# include <boost/thread.hpp>
# include <openssl/crypto.h>
# include <openssl/rand.h>
# include <stdarg.h>
# ifdef WIN32
# ifdef _MSC_VER
# pragma warning(disable:4786)
# pragma warning(disable:4804)
# pragma warning(disable:4805)
# pragma warning(disable:4717)
# endif
# ifdef _WIN32_WINNT
# undef _WIN32_WINNT
# endif
# define _WIN32_WINNT 0x0501
# ifdef _WIN32_IE
# undef _WIN32_IE
# endif
# define _WIN32_IE 0x0501
# define WIN32_LEAN_AND_MEAN 1
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <io.h> /* for _commit */
# include "shlobj.h"
# elif defined(__linux__)
# include <sys / prctl.h>
# endif
using namespace std ;
map < string , string > mapArgs ;
map < string , vector < string > > mapMultiArgs ;
bool fDebug = false ;
bool fDebugNet = false ;
bool fPrintToConsole = false ;
bool fPrintToDebugger = false ;
bool fDaemon = false ;
bool fServer = false ;
string strMiscWarning ;
bool fNoListen = false ;
bool fLogTimestamps = false ;
CMedianFilter < int64 > vTimeOffsets ( 200 , 0 ) ;
volatile bool fReopenDebugLog = false ;
// Init OpenSSL library multithreading support
static CCriticalSection * * ppmutexOpenSSL ;
void locking_callback ( int mode , int i , const char * file , int line )
{
if ( mode & CRYPTO_LOCK ) {
ENTER_CRITICAL_SECTION ( * ppmutexOpenSSL [ i ] ) ;
} else {
LEAVE_CRITICAL_SECTION ( * ppmutexOpenSSL [ i ] ) ;
}
}
LockedPageManager LockedPageManager : : instance ;
// Init
class CInit
{
public :
CInit ( )
{
// Init OpenSSL library multithreading support
ppmutexOpenSSL = ( CCriticalSection * * ) OPENSSL_malloc ( CRYPTO_num_locks ( ) * sizeof ( CCriticalSection * ) ) ;
for ( int i = 0 ; i < CRYPTO_num_locks ( ) ; i + + )
ppmutexOpenSSL [ i ] = new CCriticalSection ( ) ;
CRYPTO_set_locking_callback ( locking_callback ) ;
# ifdef WIN32
// Seed random number generator with screen scrape and other hardware sources
RAND_screen ( ) ;
# endif
// Seed random number generator with performance counter
RandAddSeed ( ) ;
}
~ CInit ( )
{
// Shutdown OpenSSL library multithreading support
CRYPTO_set_locking_callback ( NULL ) ;
for ( int i = 0 ; i < CRYPTO_num_locks ( ) ; i + + )
delete ppmutexOpenSSL [ i ] ;
OPENSSL_free ( ppmutexOpenSSL ) ;
}
}
instance_of_cinit ;
void RandAddSeed ( )
{
// Seed with CPU performance counter
int64 nCounter = GetPerformanceCounter ( ) ;
RAND_add ( & nCounter , sizeof ( nCounter ) , 1.5 ) ;
memset ( & nCounter , 0 , sizeof ( nCounter ) ) ;
}
void RandAddSeedPerfmon ( )
{
RandAddSeed ( ) ;
// This can take up to 2 seconds, so only do it every 10 minutes
static int64 nLastPerfmon ;
if ( GetTime ( ) < nLastPerfmon + 10 * 60 )
return ;
nLastPerfmon = GetTime ( ) ;
# ifdef WIN32
// Don't need this on Linux, OpenSSL automatically uses /dev/urandom
// Seed with the entire set of perfmon data
unsigned char pdata [ 250000 ] ;
memset ( pdata , 0 , sizeof ( pdata ) ) ;
unsigned long nSize = sizeof ( pdata ) ;
long ret = RegQueryValueExA ( HKEY_PERFORMANCE_DATA , " Global " , NULL , NULL , pdata , & nSize ) ;
RegCloseKey ( HKEY_PERFORMANCE_DATA ) ;
if ( ret = = ERROR_SUCCESS )
{
RAND_add ( pdata , nSize , nSize / 100.0 ) ;
OPENSSL_cleanse ( pdata , nSize ) ;
LogPrint ( " rand " , " RandAddSeed() %lu bytes \n " , nSize ) ;
}
# endif
}
uint64 GetRand ( uint64 nMax )
{
if ( nMax = = 0 )
return 0 ;
// The range of the random source must be a multiple of the modulus
// to give every possible output value an equal possibility
uint64 nRange = ( std : : numeric_limits < uint64 > : : max ( ) / nMax ) * nMax ;
uint64 nRand = 0 ;
do
RAND_bytes ( ( unsigned char * ) & nRand , sizeof ( nRand ) ) ;
while ( nRand > = nRange ) ;
return ( nRand % nMax ) ;
}
int GetRandInt ( int nMax )
{
return GetRand ( nMax ) ;
}
uint256 GetRandHash ( )
{
uint256 hash ;
RAND_bytes ( ( unsigned char * ) & hash , sizeof ( hash ) ) ;
return hash ;
}
// LogPrintf() has been broken a couple of times now
// by well-meaning people adding mutexes in the most straightforward way.
// It breaks because it may be called by global destructors during shutdown.
// Since the order of destruction of static/global objects is undefined,
// defining a mutex as a global object doesn't work (the mutex gets
// destroyed, and then some later destructor calls OutputDebugStringF,
// maybe indirectly, and you get a core dump at shutdown trying to lock
// the mutex).
static boost : : once_flag debugPrintInitFlag = BOOST_ONCE_INIT ;
// We use boost::call_once() to make sure these are initialized in
// in a thread-safe manner the first time it is called:
static FILE * fileout = NULL ;
static boost : : mutex * mutexDebugLog = NULL ;
static void DebugPrintInit ( )
{
assert ( fileout = = NULL ) ;
assert ( mutexDebugLog = = NULL ) ;
boost : : filesystem : : path pathDebug = GetDataDir ( ) / " debug.log " ;
fileout = fopen ( pathDebug . string ( ) . c_str ( ) , " a " ) ;
if ( fileout ) setbuf ( fileout , NULL ) ; // unbuffered
mutexDebugLog = new boost : : mutex ( ) ;
}
int LogPrint ( const char * category , const char * pszFormat , . . . )
{
if ( category ! = NULL )
{
if ( ! fDebug ) return 0 ;
const vector < string > & categories = mapMultiArgs [ " -debug " ] ;
if ( find ( categories . begin ( ) , categories . end ( ) , string ( category ) ) = = categories . end ( ) )
return 0 ;
}
int ret = 0 ; // Returns total number of characters written
if ( fPrintToConsole )
{
// print to console
va_list arg_ptr ;
va_start ( arg_ptr , pszFormat ) ;
ret + = vprintf ( pszFormat , arg_ptr ) ;
va_end ( arg_ptr ) ;
}
else if ( ! fPrintToDebugger )
{
static bool fStartedNewLine = true ;
boost : : call_once ( & DebugPrintInit , debugPrintInitFlag ) ;
if ( fileout = = NULL )
return ret ;
boost : : mutex : : scoped_lock scoped_lock ( * mutexDebugLog ) ;
// reopen the log file, if requested
if ( fReopenDebugLog ) {
fReopenDebugLog = false ;
boost : : filesystem : : path pathDebug = GetDataDir ( ) / " debug.log " ;
if ( freopen ( pathDebug . string ( ) . c_str ( ) , " a " , fileout ) ! = NULL )
setbuf ( fileout , NULL ) ; // unbuffered
}
// Debug print useful for profiling
if ( fLogTimestamps & & fStartedNewLine )
ret + = fprintf ( fileout , " %s " , DateTimeStrFormat ( " %Y-%m-%d %H:%M:%S " , GetTime ( ) ) . c_str ( ) ) ;
if ( pszFormat [ strlen ( pszFormat ) - 1 ] = = ' \n ' )
fStartedNewLine = true ;
else
fStartedNewLine = false ;
va_list arg_ptr ;
va_start ( arg_ptr , pszFormat ) ;
ret + = vfprintf ( fileout , pszFormat , arg_ptr ) ;
va_end ( arg_ptr ) ;
}
# ifdef WIN32
if ( fPrintToDebugger )
{
static CCriticalSection cs_OutputDebugStringF ;
// accumulate and output a line at a time
{
LOCK ( cs_OutputDebugStringF ) ;
static std : : string buffer ;
va_list arg_ptr ;
va_start ( arg_ptr , pszFormat ) ;
buffer + = vstrprintf ( pszFormat , arg_ptr ) ;
va_end ( arg_ptr ) ;
int line_start = 0 , line_end ;
while ( ( line_end = buffer . find ( ' \n ' , line_start ) ) ! = - 1 )
{
OutputDebugStringA ( buffer . substr ( line_start , line_end - line_start ) . c_str ( ) ) ;
line_start = line_end + 1 ;
ret + = line_end - line_start ;
}
buffer . erase ( 0 , line_start ) ;
}
}
# endif
return ret ;
}
string vstrprintf ( const char * format , va_list ap )
{
char buffer [ 50000 ] ;
char * p = buffer ;
int limit = sizeof ( buffer ) ;
int ret ;
while ( true )
{
va_list arg_ptr ;
va_copy ( arg_ptr , ap ) ;
# ifdef WIN32
ret = _vsnprintf ( p , limit , format , arg_ptr ) ;
# else
ret = vsnprintf ( p , limit , format , arg_ptr ) ;
# endif
va_end ( arg_ptr ) ;
if ( ret > = 0 & & ret < limit )
break ;
if ( p ! = buffer )
delete [ ] p ;
limit * = 2 ;
p = new char [ limit ] ;
if ( p = = NULL )
throw std : : bad_alloc ( ) ;
}
string str ( p , p + ret ) ;
if ( p ! = buffer )
delete [ ] p ;
return str ;
}
string real_strprintf ( const char * format , int dummy , . . . )
{
va_list arg_ptr ;
va_start ( arg_ptr , dummy ) ;
string str = vstrprintf ( format , arg_ptr ) ;
va_end ( arg_ptr ) ;
return str ;
}
string real_strprintf ( const std : : string & format , int dummy , . . . )
{
va_list arg_ptr ;
va_start ( arg_ptr , dummy ) ;
string str = vstrprintf ( format . c_str ( ) , arg_ptr ) ;
va_end ( arg_ptr ) ;
return str ;
}
bool error ( const char * format , . . . )
{
va_list arg_ptr ;
va_start ( arg_ptr , format ) ;
std : : string str = vstrprintf ( format , arg_ptr ) ;
va_end ( arg_ptr ) ;
LogPrintf ( " ERROR: %s \n " , str . c_str ( ) ) ;
return false ;
}
void ParseString ( const string & str , char c , vector < string > & v )
{
if ( str . empty ( ) )
return ;
string : : size_type i1 = 0 ;
string : : size_type i2 ;
while ( true )
{
i2 = str . find ( c , i1 ) ;
if ( i2 = = str . npos )
{
v . push_back ( str . substr ( i1 ) ) ;
return ;
}
v . push_back ( str . substr ( i1 , i2 - i1 ) ) ;
i1 = i2 + 1 ;
}
}
string FormatMoney ( int64 n , bool fPlus )
{
// Note: not using straight sprintf here because we do NOT want
// localized number formatting.
int64 n_abs = ( n > 0 ? n : - n ) ;
int64 quotient = n_abs / COIN ;
int64 remainder = n_abs % COIN ;
string str = strprintf ( " % " PRI64d " .%08 " PRI64d , quotient , remainder ) ;
// Right-trim excess zeros before the decimal point:
int nTrim = 0 ;
for ( int i = str . size ( ) - 1 ; ( str [ i ] = = ' 0 ' & & isdigit ( str [ i - 2 ] ) ) ; - - i )
+ + nTrim ;
if ( nTrim )
str . erase ( str . size ( ) - nTrim , nTrim ) ;
if ( n < 0 )
str . insert ( ( unsigned int ) 0 , 1 , ' - ' ) ;
else if ( fPlus & & n > 0 )
str . insert ( ( unsigned int ) 0 , 1 , ' + ' ) ;
return str ;
}
bool ParseMoney ( const string & str , int64 & nRet )
{
return ParseMoney ( str . c_str ( ) , nRet ) ;
}
bool ParseMoney ( const char * pszIn , int64 & nRet )
{
string strWhole ;
int64 nUnits = 0 ;
const char * p = pszIn ;
while ( isspace ( * p ) )
p + + ;
for ( ; * p ; p + + )
{
if ( * p = = ' . ' )
{
p + + ;
int64 nMult = CENT * 10 ;
while ( isdigit ( * p ) & & ( nMult > 0 ) )
{
nUnits + = nMult * ( * p + + - ' 0 ' ) ;
nMult / = 10 ;
}
break ;
}
if ( isspace ( * p ) )
break ;
if ( ! isdigit ( * p ) )
return false ;
strWhole . insert ( strWhole . end ( ) , * p ) ;
}
for ( ; * p ; p + + )
if ( ! isspace ( * p ) )
return false ;
if ( strWhole . size ( ) > 10 ) // guard against 63 bit overflow
return false ;
if ( nUnits < 0 | | nUnits > COIN )
return false ;
int64 nWhole = atoi64 ( strWhole ) ;
int64 nValue = nWhole * COIN + nUnits ;
nRet = nValue ;
return true ;
}
static const signed char phexdigit [ 256 ] =
{ - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , 0xa , 0xb , 0xc , 0xd , 0xe , 0xf , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , 0xa , 0xb , 0xc , 0xd , 0xe , 0xf , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , } ;
bool IsHex ( const string & str )
{
BOOST_FOREACH ( unsigned char c , str )
{
if ( phexdigit [ c ] < 0 )
return false ;
}
return ( str . size ( ) > 0 ) & & ( str . size ( ) % 2 = = 0 ) ;
}
vector < unsigned char > ParseHex ( const char * psz )
{
// convert hex dump to vector
vector < unsigned char > vch ;
while ( true )
{
while ( isspace ( * psz ) )
psz + + ;
signed char c = phexdigit [ ( unsigned char ) * psz + + ] ;
if ( c = = ( signed char ) - 1 )
break ;
unsigned char n = ( c < < 4 ) ;
c = phexdigit [ ( unsigned char ) * psz + + ] ;
if ( c = = ( signed char ) - 1 )
break ;
n | = c ;
vch . push_back ( n ) ;
}
return vch ;
}
vector < unsigned char > ParseHex ( const string & str )
{
return ParseHex ( str . c_str ( ) ) ;
}
static void InterpretNegativeSetting ( string name , map < string , string > & mapSettingsRet )
{
// interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
if ( name . find ( " -no " ) = = 0 )
{
std : : string positive ( " - " ) ;
positive . append ( name . begin ( ) + 3 , name . end ( ) ) ;
if ( mapSettingsRet . count ( positive ) = = 0 )
{
bool value = ! GetBoolArg ( name , false ) ;
mapSettingsRet [ positive ] = ( value ? " 1 " : " 0 " ) ;
}
}
}
void ParseParameters ( int argc , const char * const argv [ ] )
{
mapArgs . clear ( ) ;
mapMultiArgs . clear ( ) ;
for ( int i = 1 ; i < argc ; i + + )
{
std : : string str ( argv [ i ] ) ;
std : : string strValue ;
size_t is_index = str . find ( ' = ' ) ;
if ( is_index ! = std : : string : : npos )
{
strValue = str . substr ( is_index + 1 ) ;
str = str . substr ( 0 , is_index ) ;
}
# ifdef WIN32
boost : : to_lower ( str ) ;
if ( boost : : algorithm : : starts_with ( str , " / " ) )
str = " - " + str . substr ( 1 ) ;
# endif
if ( str [ 0 ] ! = ' - ' )
break ;
mapArgs [ str ] = strValue ;
mapMultiArgs [ str ] . push_back ( strValue ) ;
}
// New 0.6 features:
BOOST_FOREACH ( const PAIRTYPE ( string , string ) & entry , mapArgs )
{
string name = entry . first ;
// interpret --foo as -foo (as long as both are not set)
if ( name . find ( " -- " ) = = 0 )
{
std : : string singleDash ( name . begin ( ) + 1 , name . end ( ) ) ;
if ( mapArgs . count ( singleDash ) = = 0 )
mapArgs [ singleDash ] = entry . second ;
name = singleDash ;
}
// interpret -nofoo as -foo=0 (and -nofoo=0 as -foo=1) as long as -foo not set
InterpretNegativeSetting ( name , mapArgs ) ;
}
}
std : : string GetArg ( const std : : string & strArg , const std : : string & strDefault )
{
if ( mapArgs . count ( strArg ) )
return mapArgs [ strArg ] ;
return strDefault ;
}
int64 GetArg ( const std : : string & strArg , int64 nDefault )
{
if ( mapArgs . count ( strArg ) )
return atoi64 ( mapArgs [ strArg ] ) ;
return nDefault ;
}
bool GetBoolArg ( const std : : string & strArg , bool fDefault )
{
if ( mapArgs . count ( strArg ) )
{
if ( mapArgs [ strArg ] . empty ( ) )
return true ;
return ( atoi ( mapArgs [ strArg ] ) ! = 0 ) ;
}
return fDefault ;
}
bool SoftSetArg ( const std : : string & strArg , const std : : string & strValue )
{
if ( mapArgs . count ( strArg ) )
return false ;
mapArgs [ strArg ] = strValue ;
return true ;
}
bool SoftSetBoolArg ( const std : : string & strArg , bool fValue )
{
if ( fValue )
return SoftSetArg ( strArg , std : : string ( " 1 " ) ) ;
else
return SoftSetArg ( strArg , std : : string ( " 0 " ) ) ;
}
string EncodeBase64 ( const unsigned char * pch , size_t len )
{
static const char * pbase64 = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
string strRet = " " ;
strRet . reserve ( ( len + 2 ) / 3 * 4 ) ;
int mode = 0 , left = 0 ;
const unsigned char * pchEnd = pch + len ;
while ( pch < pchEnd )
{
int enc = * ( pch + + ) ;
switch ( mode )
{
case 0 : // we have no bits
strRet + = pbase64 [ enc > > 2 ] ;
left = ( enc & 3 ) < < 4 ;
mode = 1 ;
break ;
case 1 : // we have two bits
strRet + = pbase64 [ left | ( enc > > 4 ) ] ;
left = ( enc & 15 ) < < 2 ;
mode = 2 ;
break ;
case 2 : // we have four bits
strRet + = pbase64 [ left | ( enc > > 6 ) ] ;
strRet + = pbase64 [ enc & 63 ] ;
mode = 0 ;
break ;
}
}
if ( mode )
{
strRet + = pbase64 [ left ] ;
strRet + = ' = ' ;
if ( mode = = 1 )
strRet + = ' = ' ;
}
return strRet ;
}
string EncodeBase64 ( const string & str )
{
return EncodeBase64 ( ( const unsigned char * ) str . c_str ( ) , str . size ( ) ) ;
}
vector < unsigned char > DecodeBase64 ( const char * p , bool * pfInvalid )
{
static const int decode64_table [ 256 ] =
{
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , 62 , - 1 , - 1 , - 1 , 63 , 52 , 53 , 54 , 55 , 56 , 57 , 58 , 59 , 60 , 61 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ,
15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 26 , 27 , 28 ,
29 , 30 , 31 , 32 , 33 , 34 , 35 , 36 , 37 , 38 , 39 , 40 , 41 , 42 , 43 , 44 , 45 , 46 , 47 , 48 ,
49 , 50 , 51 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1
} ;
if ( pfInvalid )
* pfInvalid = false ;
vector < unsigned char > vchRet ;
vchRet . reserve ( strlen ( p ) * 3 / 4 ) ;
int mode = 0 ;
int left = 0 ;
while ( 1 )
{
int dec = decode64_table [ ( unsigned char ) * p ] ;
if ( dec = = - 1 ) break ;
p + + ;
switch ( mode )
{
case 0 : // we have no bits and get 6
left = dec ;
mode = 1 ;
break ;
case 1 : // we have 6 bits and keep 4
vchRet . push_back ( ( left < < 2 ) | ( dec > > 4 ) ) ;
left = dec & 15 ;
mode = 2 ;
break ;
case 2 : // we have 4 bits and get 6, we keep 2
vchRet . push_back ( ( left < < 4 ) | ( dec > > 2 ) ) ;
left = dec & 3 ;
mode = 3 ;
break ;
case 3 : // we have 2 bits and get 6
vchRet . push_back ( ( left < < 6 ) | dec ) ;
mode = 0 ;
break ;
}
}
if ( pfInvalid )
switch ( mode )
{
case 0 : // 4n base64 characters processed: ok
break ;
case 1 : // 4n+1 base64 character processed: impossible
* pfInvalid = true ;
break ;
case 2 : // 4n+2 base64 characters processed: require '=='
if ( left | | p [ 0 ] ! = ' = ' | | p [ 1 ] ! = ' = ' | | decode64_table [ ( unsigned char ) p [ 2 ] ] ! = - 1 )
* pfInvalid = true ;
break ;
case 3 : // 4n+3 base64 characters processed: require '='
if ( left | | p [ 0 ] ! = ' = ' | | decode64_table [ ( unsigned char ) p [ 1 ] ] ! = - 1 )
* pfInvalid = true ;
break ;
}
return vchRet ;
}
string DecodeBase64 ( const string & str )
{
vector < unsigned char > vchRet = DecodeBase64 ( str . c_str ( ) ) ;
return string ( ( const char * ) & vchRet [ 0 ] , vchRet . size ( ) ) ;
}
string EncodeBase32 ( const unsigned char * pch , size_t len )
{
static const char * pbase32 = " abcdefghijklmnopqrstuvwxyz234567 " ;
string strRet = " " ;
strRet . reserve ( ( len + 4 ) / 5 * 8 ) ;
int mode = 0 , left = 0 ;
const unsigned char * pchEnd = pch + len ;
while ( pch < pchEnd )
{
int enc = * ( pch + + ) ;
switch ( mode )
{
case 0 : // we have no bits
strRet + = pbase32 [ enc > > 3 ] ;
left = ( enc & 7 ) < < 2 ;
mode = 1 ;
break ;
case 1 : // we have three bits
strRet + = pbase32 [ left | ( enc > > 6 ) ] ;
strRet + = pbase32 [ ( enc > > 1 ) & 31 ] ;
left = ( enc & 1 ) < < 4 ;
mode = 2 ;
break ;
case 2 : // we have one bit
strRet + = pbase32 [ left | ( enc > > 4 ) ] ;
left = ( enc & 15 ) < < 1 ;
mode = 3 ;
break ;
case 3 : // we have four bits
strRet + = pbase32 [ left | ( enc > > 7 ) ] ;
strRet + = pbase32 [ ( enc > > 2 ) & 31 ] ;
left = ( enc & 3 ) < < 3 ;
mode = 4 ;
break ;
case 4 : // we have two bits
strRet + = pbase32 [ left | ( enc > > 5 ) ] ;
strRet + = pbase32 [ enc & 31 ] ;
mode = 0 ;
}
}
static const int nPadding [ 5 ] = { 0 , 6 , 4 , 3 , 1 } ;
if ( mode )
{
strRet + = pbase32 [ left ] ;
for ( int n = 0 ; n < nPadding [ mode ] ; n + + )
strRet + = ' = ' ;
}
return strRet ;
}
string EncodeBase32 ( const string & str )
{
return EncodeBase32 ( ( const unsigned char * ) str . c_str ( ) , str . size ( ) ) ;
}
vector < unsigned char > DecodeBase32 ( const char * p , bool * pfInvalid )
{
static const int decode32_table [ 256 ] =
{
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 26 , 27 , 28 , 29 , 30 , 31 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 ,
15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 , 23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , 0 , 1 , 2 ,
3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 ,
23 , 24 , 25 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 ,
- 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1
} ;
if ( pfInvalid )
* pfInvalid = false ;
vector < unsigned char > vchRet ;
vchRet . reserve ( ( strlen ( p ) ) * 5 / 8 ) ;
int mode = 0 ;
int left = 0 ;
while ( 1 )
{
int dec = decode32_table [ ( unsigned char ) * p ] ;
if ( dec = = - 1 ) break ;
p + + ;
switch ( mode )
{
case 0 : // we have no bits and get 5
left = dec ;
mode = 1 ;
break ;
case 1 : // we have 5 bits and keep 2
vchRet . push_back ( ( left < < 3 ) | ( dec > > 2 ) ) ;
left = dec & 3 ;
mode = 2 ;
break ;
case 2 : // we have 2 bits and keep 7
left = left < < 5 | dec ;
mode = 3 ;
break ;
case 3 : // we have 7 bits and keep 4
vchRet . push_back ( ( left < < 1 ) | ( dec > > 4 ) ) ;
left = dec & 15 ;
mode = 4 ;
break ;
case 4 : // we have 4 bits, and keep 1
vchRet . push_back ( ( left < < 4 ) | ( dec > > 1 ) ) ;
left = dec & 1 ;
mode = 5 ;
break ;
case 5 : // we have 1 bit, and keep 6
left = left < < 5 | dec ;
mode = 6 ;
break ;
case 6 : // we have 6 bits, and keep 3
vchRet . push_back ( ( left < < 2 ) | ( dec > > 3 ) ) ;
left = dec & 7 ;
mode = 7 ;
break ;
case 7 : // we have 3 bits, and keep 0
vchRet . push_back ( ( left < < 5 ) | dec ) ;
mode = 0 ;
break ;
}
}
if ( pfInvalid )
switch ( mode )
{
case 0 : // 8n base32 characters processed: ok
break ;
case 1 : // 8n+1 base32 characters processed: impossible
case 3 : // +3
case 6 : // +6
* pfInvalid = true ;
break ;
case 2 : // 8n+2 base32 characters processed: require '======'
if ( left | | p [ 0 ] ! = ' = ' | | p [ 1 ] ! = ' = ' | | p [ 2 ] ! = ' = ' | | p [ 3 ] ! = ' = ' | | p [ 4 ] ! = ' = ' | | p [ 5 ] ! = ' = ' | | decode32_table [ ( unsigned char ) p [ 6 ] ] ! = - 1 )
* pfInvalid = true ;
break ;
case 4 : // 8n+4 base32 characters processed: require '===='
if ( left | | p [ 0 ] ! = ' = ' | | p [ 1 ] ! = ' = ' | | p [ 2 ] ! = ' = ' | | p [ 3 ] ! = ' = ' | | decode32_table [ ( unsigned char ) p [ 4 ] ] ! = - 1 )
* pfInvalid = true ;
break ;
case 5 : // 8n+5 base32 characters processed: require '==='
if ( left | | p [ 0 ] ! = ' = ' | | p [ 1 ] ! = ' = ' | | p [ 2 ] ! = ' = ' | | decode32_table [ ( unsigned char ) p [ 3 ] ] ! = - 1 )
* pfInvalid = true ;
break ;
case 7 : // 8n+7 base32 characters processed: require '='
if ( left | | p [ 0 ] ! = ' = ' | | decode32_table [ ( unsigned char ) p [ 1 ] ] ! = - 1 )
* pfInvalid = true ;
break ;
}
return vchRet ;
}
string DecodeBase32 ( const string & str )
{
vector < unsigned char > vchRet = DecodeBase32 ( str . c_str ( ) ) ;
return string ( ( const char * ) & vchRet [ 0 ] , vchRet . size ( ) ) ;
}
bool WildcardMatch ( const char * psz , const char * mask )
{
while ( true )
{
switch ( * mask )
{
case ' \0 ' :
return ( * psz = = ' \0 ' ) ;
case ' * ' :
return WildcardMatch ( psz , mask + 1 ) | | ( * psz & & WildcardMatch ( psz + 1 , mask ) ) ;
case ' ? ' :
if ( * psz = = ' \0 ' )
return false ;
break ;
default :
if ( * psz ! = * mask )
return false ;
break ;
}
psz + + ;
mask + + ;
}
}
bool WildcardMatch ( const string & str , const string & mask )
{
return WildcardMatch ( str . c_str ( ) , mask . c_str ( ) ) ;
}
static std : : string FormatException ( std : : exception * pex , const char * pszThread )
{
# ifdef WIN32
char pszModule [ MAX_PATH ] = " " ;
GetModuleFileNameA ( NULL , pszModule , sizeof ( pszModule ) ) ;
# else
const char * pszModule = " bitcoin " ;
# endif
if ( pex )
return strprintf (
" EXCEPTION: %s \n %s \n %s in %s \n " , typeid ( * pex ) . name ( ) , pex - > what ( ) , pszModule , pszThread ) ;
else
return strprintf (
" UNKNOWN EXCEPTION \n %s in %s \n " , pszModule , pszThread ) ;
}
void LogException ( std : : exception * pex , const char * pszThread )
{
std : : string message = FormatException ( pex , pszThread ) ;
LogPrintf ( " \n %s " , message . c_str ( ) ) ;
}
void PrintException ( std : : exception * pex , const char * pszThread )
{
std : : string message = FormatException ( pex , pszThread ) ;
LogPrintf ( " \n \n ************************ \n %s \n " , message . c_str ( ) ) ;
fprintf ( stderr , " \n \n ************************ \n %s \n " , message . c_str ( ) ) ;
strMiscWarning = message ;
throw ;
}
void PrintExceptionContinue ( std : : exception * pex , const char * pszThread )
{
std : : string message = FormatException ( pex , pszThread ) ;
LogPrintf ( " \n \n ************************ \n %s \n " , message . c_str ( ) ) ;
fprintf ( stderr , " \n \n ************************ \n %s \n " , message . c_str ( ) ) ;
strMiscWarning = message ;
}
boost : : filesystem : : path GetDefaultDataDir ( )
{
namespace fs = boost : : filesystem ;
// Windows < Vista: C:\Documents and Settings\Username\Application Data\Bitcoin
// Windows >= Vista: C:\Users\Username\AppData\Roaming\Bitcoin
// Mac: ~/Library/Application Support/Bitcoin
// Unix: ~/.bitcoin
# ifdef WIN32
// Windows
return GetSpecialFolderPath ( CSIDL_APPDATA ) / " Bitcoin " ;
# else
fs : : path pathRet ;
char * pszHome = getenv ( " HOME " ) ;
if ( pszHome = = NULL | | strlen ( pszHome ) = = 0 )
pathRet = fs : : path ( " / " ) ;
else
pathRet = fs : : path ( pszHome ) ;
# ifdef MAC_OSX
// Mac
pathRet / = " Library/Application Support " ;
fs : : create_directory ( pathRet ) ;
return pathRet / " Bitcoin " ;
# else
// Unix
return pathRet / " .bitcoin " ;
# endif
# endif
}
static boost : : filesystem : : path pathCached [ CChainParams : : MAX_NETWORK_TYPES + 1 ] ;
static CCriticalSection csPathCached ;
const boost : : filesystem : : path & GetDataDir ( bool fNetSpecific )
{
namespace fs = boost : : filesystem ;
LOCK ( csPathCached ) ;
int nNet = CChainParams : : MAX_NETWORK_TYPES ;
if ( fNetSpecific ) nNet = Params ( ) . NetworkID ( ) ;
fs : : path & path = pathCached [ nNet ] ;
// This can be called during exceptions by LogPrintf(), so we cache the
// value so we don't have to do memory allocations after that.
if ( ! path . empty ( ) )
return path ;
if ( mapArgs . count ( " -datadir " ) ) {
path = fs : : system_complete ( mapArgs [ " -datadir " ] ) ;
if ( ! fs : : is_directory ( path ) ) {
path = " " ;
return path ;
}
} else {
path = GetDefaultDataDir ( ) ;
}
if ( fNetSpecific )
path / = Params ( ) . DataDir ( ) ;
fs : : create_directories ( path ) ;
return path ;
}
void ClearDatadirCache ( )
{
std : : fill ( & pathCached [ 0 ] , & pathCached [ CChainParams : : MAX_NETWORK_TYPES + 1 ] ,
boost : : filesystem : : path ( ) ) ;
}
boost : : filesystem : : path GetConfigFile ( )
{
boost : : filesystem : : path pathConfigFile ( GetArg ( " -conf " , " bitcoin.conf " ) ) ;
if ( ! pathConfigFile . is_complete ( ) ) pathConfigFile = GetDataDir ( false ) / pathConfigFile ;
return pathConfigFile ;
}
void ReadConfigFile ( map < string , string > & mapSettingsRet ,
map < string , vector < string > > & mapMultiSettingsRet )
{
boost : : filesystem : : ifstream streamConfig ( GetConfigFile ( ) ) ;
if ( ! streamConfig . good ( ) )
return ; // No bitcoin.conf file is OK
set < string > setOptions ;
setOptions . insert ( " * " ) ;
for ( boost : : program_options : : detail : : config_file_iterator it ( streamConfig , setOptions ) , end ; it ! = end ; + + it )
{
// Don't overwrite existing settings so command line settings override bitcoin.conf
string strKey = string ( " - " ) + it - > string_key ;
if ( mapSettingsRet . count ( strKey ) = = 0 )
{
mapSettingsRet [ strKey ] = it - > value [ 0 ] ;
// interpret nofoo=1 as foo=0 (and nofoo=0 as foo=1) as long as foo not set)
InterpretNegativeSetting ( strKey , mapSettingsRet ) ;
}
mapMultiSettingsRet [ strKey ] . push_back ( it - > value [ 0 ] ) ;
}
// If datadir is changed in .conf file:
ClearDatadirCache ( ) ;
}
boost : : filesystem : : path GetPidFile ( )
{
boost : : filesystem : : path pathPidFile ( GetArg ( " -pid " , " bitcoind.pid " ) ) ;
if ( ! pathPidFile . is_complete ( ) ) pathPidFile = GetDataDir ( ) / pathPidFile ;
return pathPidFile ;
}
# ifndef WIN32
void CreatePidFile ( const boost : : filesystem : : path & path , pid_t pid )
{
FILE * file = fopen ( path . string ( ) . c_str ( ) , " w " ) ;
if ( file )
{
fprintf ( file , " %d \n " , pid ) ;
fclose ( file ) ;
}
}
# endif
bool RenameOver ( boost : : filesystem : : path src , boost : : filesystem : : path dest )
{
# ifdef WIN32
return MoveFileExA ( src . string ( ) . c_str ( ) , dest . string ( ) . c_str ( ) ,
MOVEFILE_REPLACE_EXISTING ) ;
# else
int rc = std : : rename ( src . string ( ) . c_str ( ) , dest . string ( ) . c_str ( ) ) ;
return ( rc = = 0 ) ;
# endif /* WIN32 */
}
void FileCommit ( FILE * fileout )
{
fflush ( fileout ) ; // harmless if redundantly called
# ifdef WIN32
_commit ( _fileno ( fileout ) ) ;
# else
# if defined(__linux__) || defined(__NetBSD__)
fdatasync ( fileno ( fileout ) ) ;
# elif defined(__APPLE__) && defined(F_FULLFSYNC)
fcntl ( fileno ( fileout ) , F_FULLFSYNC , 0 ) ;
# else
fsync ( fileno ( fileout ) ) ;
# endif
# endif
}
int GetFilesize ( FILE * file )
{
int nSavePos = ftell ( file ) ;
int nFilesize = - 1 ;
if ( fseek ( file , 0 , SEEK_END ) = = 0 )
nFilesize = ftell ( file ) ;
fseek ( file , nSavePos , SEEK_SET ) ;
return nFilesize ;
}
bool TruncateFile ( FILE * file , unsigned int length ) {
# if defined(WIN32)
return _chsize ( _fileno ( file ) , length ) = = 0 ;
# else
return ftruncate ( fileno ( file ) , length ) = = 0 ;
# endif
}
// this function tries to raise the file descriptor limit to the requested number.
// It returns the actual file descriptor limit (which may be more or less than nMinFD)
int RaiseFileDescriptorLimit ( int nMinFD ) {
# if defined(WIN32)
return 2048 ;
# else
struct rlimit limitFD ;
if ( getrlimit ( RLIMIT_NOFILE , & limitFD ) ! = - 1 ) {
if ( limitFD . rlim_cur < ( rlim_t ) nMinFD ) {
limitFD . rlim_cur = nMinFD ;
if ( limitFD . rlim_cur > limitFD . rlim_max )
limitFD . rlim_cur = limitFD . rlim_max ;
setrlimit ( RLIMIT_NOFILE , & limitFD ) ;
getrlimit ( RLIMIT_NOFILE , & limitFD ) ;
}
return limitFD . rlim_cur ;
}
return nMinFD ; // getrlimit failed, assume it's fine
# endif
}
// this function tries to make a particular range of a file allocated (corresponding to disk space)
// it is advisory, and the range specified in the arguments will never contain live data
void AllocateFileRange ( FILE * file , unsigned int offset , unsigned int length ) {
# if defined(WIN32)
// Windows-specific version
HANDLE hFile = ( HANDLE ) _get_osfhandle ( _fileno ( file ) ) ;
LARGE_INTEGER nFileSize ;
int64 nEndPos = ( int64 ) offset + length ;
nFileSize . u . LowPart = nEndPos & 0xFFFFFFFF ;
nFileSize . u . HighPart = nEndPos > > 32 ;
SetFilePointerEx ( hFile , nFileSize , 0 , FILE_BEGIN ) ;
SetEndOfFile ( hFile ) ;
# elif defined(MAC_OSX)
// OSX specific version
fstore_t fst ;
fst . fst_flags = F_ALLOCATECONTIG ;
fst . fst_posmode = F_PEOFPOSMODE ;
fst . fst_offset = 0 ;
fst . fst_length = ( off_t ) offset + length ;
fst . fst_bytesalloc = 0 ;
if ( fcntl ( fileno ( file ) , F_PREALLOCATE , & fst ) = = - 1 ) {
fst . fst_flags = F_ALLOCATEALL ;
fcntl ( fileno ( file ) , F_PREALLOCATE , & fst ) ;
}
ftruncate ( fileno ( file ) , fst . fst_length ) ;
# elif defined(__linux__)
// Version using posix_fallocate
off_t nEndPos = ( off_t ) offset + length ;
posix_fallocate ( fileno ( file ) , 0 , nEndPos ) ;
# else
// Fallback version
// TODO: just write one byte per block
static const char buf [ 65536 ] = { } ;
fseek ( file , offset , SEEK_SET ) ;
while ( length > 0 ) {
unsigned int now = 65536 ;
if ( length < now )
now = length ;
fwrite ( buf , 1 , now , file ) ; // allowed to fail; this function is advisory anyway
length - = now ;
}
# endif
}
void ShrinkDebugFile ( )
{
// Scroll debug.log if it's getting too big
boost : : filesystem : : path pathLog = GetDataDir ( ) / " debug.log " ;
FILE * file = fopen ( pathLog . string ( ) . c_str ( ) , " r " ) ;
if ( file & & GetFilesize ( file ) > 10 * 1000000 )
{
// Restart the file with some of the end
char pch [ 200000 ] ;
fseek ( file , - sizeof ( pch ) , SEEK_END ) ;
int nBytes = fread ( pch , 1 , sizeof ( pch ) , file ) ;
fclose ( file ) ;
file = fopen ( pathLog . string ( ) . c_str ( ) , " w " ) ;
if ( file )
{
fwrite ( pch , 1 , nBytes , file ) ;
fclose ( file ) ;
}
}
else if ( file ! = NULL )
fclose ( file ) ;
}
//
// "Never go to sea with two chronometers; take one or three."
// Our three time sources are:
// - System clock
// - Median of other nodes clocks
// - The user (asking the user to fix the system clock if the first two disagree)
//
static int64 nMockTime = 0 ; // For unit testing
int64 GetTime ( )
{
if ( nMockTime ) return nMockTime ;
return time ( NULL ) ;
}
void SetMockTime ( int64 nMockTimeIn )
{
nMockTime = nMockTimeIn ;
}
static int64 nTimeOffset = 0 ;
int64 GetTimeOffset ( )
{
return nTimeOffset ;
}
int64 GetAdjustedTime ( )
{
return GetTime ( ) + GetTimeOffset ( ) ;
}
void AddTimeData ( const CNetAddr & ip , int64 nTime )
{
int64 nOffsetSample = nTime - GetTime ( ) ;
// Ignore duplicates
static set < CNetAddr > setKnown ;
if ( ! setKnown . insert ( ip ) . second )
return ;
// Add data
Retain only the most recent time samples
Remembering all time samples makes nTimeOffset slow to respond to
system clock corrections. For instance, I start my node with a system
clock that's 30 minutes slow and run it for a few days. During that
time, I accumulate 10,000 offset samples with a median of 1800
seconds. Now I correct my system clock. Without this change, my node
must collect another 10,000 samples before nTimeOffset is correct
again. With this change, I must only accumulate 100 samples to
correct the offset.
Storing unlimited time samples also allows an attacker with many IP
addresses (ex, a large botnet) to perform a memory exhaustion attack
against Bitcoin nodes. The attacker sends a version message from each
IP to his target, consuming more of the target's memory each time.
Time samples are small, so this attack might be impractical under the
old code, but it's impossible with the new code.
13 years ago
vTimeOffsets . input ( nOffsetSample ) ;
LogPrintf ( " Added time data, samples %d, offset %+ " PRI64d " (%+ " PRI64d " minutes) \n " , vTimeOffsets . size ( ) , nOffsetSample , nOffsetSample / 60 ) ;
if ( vTimeOffsets . size ( ) > = 5 & & vTimeOffsets . size ( ) % 2 = = 1 )
{
int64 nMedian = vTimeOffsets . median ( ) ;
std : : vector < int64 > vSorted = vTimeOffsets . sorted ( ) ;
// Only let other nodes change our time by so much
if ( abs64 ( nMedian ) < 70 * 60 )
{
nTimeOffset = nMedian ;
}
else
{
nTimeOffset = 0 ;
static bool fDone ;
if ( ! fDone )
{
// If nobody has a time different than ours but within 5 minutes of ours, give a warning
bool fMatch = false ;
BOOST_FOREACH ( int64 nOffset , vSorted )
if ( nOffset ! = 0 & & abs64 ( nOffset ) < 5 * 60 )
fMatch = true ;
if ( ! fMatch )
{
fDone = true ;
string strMessage = _ ( " Warning: Please check that your computer's date and time are correct! If your clock is wrong Bitcoin will not work properly. " ) ;
strMiscWarning = strMessage ;
LogPrintf ( " *** %s \n " , strMessage . c_str ( ) ) ;
uiInterface . ThreadSafeMessageBox ( strMessage , " " , CClientUIInterface : : MSG_WARNING ) ;
}
}
}
if ( fDebug ) {
BOOST_FOREACH ( int64 n , vSorted )
LogPrintf ( " %+ " PRI64d " " , n ) ;
LogPrintf ( " | " ) ;
}
LogPrintf ( " nTimeOffset = %+ " PRI64d " (%+ " PRI64d " minutes) \n " , nTimeOffset , nTimeOffset / 60 ) ;
}
}
uint32_t insecure_rand_Rz = 11 ;
uint32_t insecure_rand_Rw = 11 ;
void seed_insecure_rand ( bool fDeterministic )
{
//The seed values have some unlikely fixed points which we avoid.
if ( fDeterministic )
{
insecure_rand_Rz = insecure_rand_Rw = 11 ;
} else {
uint32_t tmp ;
do {
RAND_bytes ( ( unsigned char * ) & tmp , 4 ) ;
} while ( tmp = = 0 | | tmp = = 0x9068ffffU ) ;
insecure_rand_Rz = tmp ;
do {
RAND_bytes ( ( unsigned char * ) & tmp , 4 ) ;
} while ( tmp = = 0 | | tmp = = 0x464fffffU ) ;
insecure_rand_Rw = tmp ;
}
}
string FormatVersion ( int nVersion )
{
if ( nVersion % 100 = = 0 )
return strprintf ( " %d.%d.%d " , nVersion / 1000000 , ( nVersion / 10000 ) % 100 , ( nVersion / 100 ) % 100 ) ;
else
return strprintf ( " %d.%d.%d.%d " , nVersion / 1000000 , ( nVersion / 10000 ) % 100 , ( nVersion / 100 ) % 100 , nVersion % 100 ) ;
}
string FormatFullVersion ( )
{
return CLIENT_BUILD ;
}
// Format the subversion field according to BIP 14 spec (https://en.bitcoin.it/wiki/BIP_0014)
std : : string FormatSubVersion ( const std : : string & name , int nClientVersion , const std : : vector < std : : string > & comments )
{
std : : ostringstream ss ;
ss < < " / " ;
ss < < name < < " : " < < FormatVersion ( nClientVersion ) ;
if ( ! comments . empty ( ) )
ss < < " ( " < < boost : : algorithm : : join ( comments , " ; " ) < < " ) " ;
ss < < " / " ;
return ss . str ( ) ;
}
# ifdef WIN32
boost : : filesystem : : path GetSpecialFolderPath ( int nFolder , bool fCreate )
{
namespace fs = boost : : filesystem ;
char pszPath [ MAX_PATH ] = " " ;
if ( SHGetSpecialFolderPathA ( NULL , pszPath , nFolder , fCreate ) )
{
return fs : : path ( pszPath ) ;
}
LogPrintf ( " SHGetSpecialFolderPathA() failed, could not obtain requested path. \n " ) ;
return fs : : path ( " " ) ;
}
# endif
boost : : filesystem : : path GetTempPath ( ) {
# if BOOST_FILESYSTEM_VERSION == 3
return boost : : filesystem : : temp_directory_path ( ) ;
# else
// TODO: remove when we don't support filesystem v2 anymore
boost : : filesystem : : path path ;
# ifdef WIN32
char pszPath [ MAX_PATH ] = " " ;
if ( GetTempPathA ( MAX_PATH , pszPath ) )
path = boost : : filesystem : : path ( pszPath ) ;
# else
path = boost : : filesystem : : path ( " /tmp " ) ;
# endif
if ( path . empty ( ) | | ! boost : : filesystem : : is_directory ( path ) ) {
LogPrintf ( " GetTempPath(): failed to find temp path \n " ) ;
return boost : : filesystem : : path ( " " ) ;
}
return path ;
# endif
}
void runCommand ( std : : string strCommand )
{
int nErr = : : system ( strCommand . c_str ( ) ) ;
if ( nErr )
LogPrintf ( " runCommand error: system(%s) returned %d \n " , strCommand . c_str ( ) , nErr ) ;
}
void RenameThread ( const char * name )
{
# if defined(PR_SET_NAME)
// Only the first 15 characters are used (16 - NUL terminator)
: : prctl ( PR_SET_NAME , name , 0 , 0 , 0 ) ;
# elif 0 && (defined(__FreeBSD__) || defined(__OpenBSD__))
// TODO: This is currently disabled because it needs to be verified to work
// on FreeBSD or OpenBSD first. When verified the '0 &&' part can be
// removed.
pthread_set_name_np ( pthread_self ( ) , name ) ;
# elif defined(MAC_OSX) && defined(__MAC_OS_X_VERSION_MAX_ALLOWED)
// pthread_setname_np is XCode 10.6-and-later
# if __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060
pthread_setname_np ( name ) ;
# endif
# else
// Prevent warnings for unused parameters...
( void ) name ;
# endif
}