1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
8 map
<string
, string
> mapArgs
;
9 map
<string
, vector
<string
> > mapMultiArgs
;
11 bool fPrintToConsole
= false;
12 bool fPrintToDebugger
= false;
13 char pszSetDataDir
[MAX_PATH
] = "";
14 bool fRequestShutdown
= false;
15 bool fShutdown
= false;
17 bool fCommandLine
= false;
18 string strMiscWarning
;
19 bool fTestNet
= false;
25 // Workaround for "multiple definition of `_tls_used'"
26 // http://svn.boost.org/trac/boost/ticket/4258
27 extern "C" void tss_cleanup_implemented() { }
33 // Init openssl library multithreading support
34 static boost::interprocess::interprocess_mutex
** ppmutexOpenSSL
;
35 void locking_callback(int mode
, int i
, const char* file
, int line
)
37 if (mode
& CRYPTO_LOCK
)
38 ppmutexOpenSSL
[i
]->lock();
40 ppmutexOpenSSL
[i
]->unlock();
49 // Init openssl library multithreading support
50 ppmutexOpenSSL
= (boost::interprocess::interprocess_mutex
**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(boost::interprocess::interprocess_mutex
*));
51 for (int i
= 0; i
< CRYPTO_num_locks(); i
++)
52 ppmutexOpenSSL
[i
] = new boost::interprocess::interprocess_mutex();
53 CRYPTO_set_locking_callback(locking_callback
);
56 // Seed random number generator with screen scrape and other hardware sources
60 // Seed random number generator with performance counter
65 // Shutdown openssl library multithreading support
66 CRYPTO_set_locking_callback(NULL
);
67 for (int i
= 0; i
< CRYPTO_num_locks(); i
++)
68 delete ppmutexOpenSSL
[i
];
69 OPENSSL_free(ppmutexOpenSSL
);
83 // Seed with CPU performance counter
84 int64 nCounter
= GetPerformanceCounter();
85 RAND_add(&nCounter
, sizeof(nCounter
), 1.5);
86 memset(&nCounter
, 0, sizeof(nCounter
));
89 void RandAddSeedPerfmon()
93 // This can take up to 2 seconds, so only do it every 10 minutes
94 static int64 nLastPerfmon
;
95 if (GetTime() < nLastPerfmon
+ 10 * 60)
97 nLastPerfmon
= GetTime();
100 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
101 // Seed with the entire set of perfmon data
102 unsigned char pdata
[250000];
103 memset(pdata
, 0, sizeof(pdata
));
104 unsigned long nSize
= sizeof(pdata
);
105 long ret
= RegQueryValueExA(HKEY_PERFORMANCE_DATA
, "Global", NULL
, NULL
, pdata
, &nSize
);
106 RegCloseKey(HKEY_PERFORMANCE_DATA
);
107 if (ret
== ERROR_SUCCESS
)
109 RAND_add(pdata
, nSize
, nSize
/100.0);
110 memset(pdata
, 0, nSize
);
111 printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M", GetTime()).c_str(), nSize
);
116 uint64
GetRand(uint64 nMax
)
121 // The range of the random source must be a multiple of the modulus
122 // to give every possible output value an equal possibility
123 uint64 nRange
= (UINT64_MAX
/ nMax
) * nMax
;
126 RAND_bytes((unsigned char*)&nRand
, sizeof(nRand
));
127 while (nRand
>= nRange
);
128 return (nRand
% nMax
);
131 int GetRandInt(int nMax
)
133 return GetRand(nMax
);
146 inline int OutputDebugStringF(const char* pszFormat
, ...)
153 va_start(arg_ptr
, pszFormat
);
154 ret
= vprintf(pszFormat
, arg_ptr
);
159 // print to debug.log
160 static FILE* fileout
= NULL
;
164 char pszFile
[MAX_PATH
+100];
166 strlcat(pszFile
, "/debug.log", sizeof(pszFile
));
167 fileout
= fopen(pszFile
, "a");
168 setbuf(fileout
, NULL
); // unbuffered
172 //// Debug print useful for profiling
173 //fprintf(fileout, " %"PRI64d" ", GetTimeMillis());
175 va_start(arg_ptr
, pszFormat
);
176 ret
= vfprintf(fileout
, pszFormat
, arg_ptr
);
183 if (fPrintToDebugger
)
185 static CCriticalSection cs_OutputDebugStringF
;
187 // accumulate a line at a time
188 CRITICAL_BLOCK(cs_OutputDebugStringF
)
190 static char pszBuffer
[50000];
195 va_start(arg_ptr
, pszFormat
);
196 int limit
= END(pszBuffer
) - pend
- 2;
197 int ret
= _vsnprintf(pend
, limit
, pszFormat
, arg_ptr
);
199 if (ret
< 0 || ret
>= limit
)
201 pend
= END(pszBuffer
) - 2;
207 char* p1
= pszBuffer
;
209 while (p2
= strchr(p1
, '\n'))
214 OutputDebugStringA(p1
);
219 memmove(pszBuffer
, p1
, pend
- p1
+ 1);
220 pend
-= (p1
- pszBuffer
);
229 // - prints up to limit-1 characters
230 // - output string is always null terminated even if limit reached
231 // - return value is the number of characters actually printed
232 int my_snprintf(char* buffer
, size_t limit
, const char* format
, ...)
237 va_start(arg_ptr
, format
);
238 int ret
= _vsnprintf(buffer
, limit
, format
, arg_ptr
);
240 if (ret
< 0 || ret
>= limit
)
249 string
strprintf(const char* format
, ...)
253 int limit
= sizeof(buffer
);
258 va_start(arg_ptr
, format
);
259 ret
= _vsnprintf(p
, limit
, format
, arg_ptr
);
261 if (ret
>= 0 && ret
< limit
)
268 throw std::bad_alloc();
270 string
str(p
, p
+ret
);
277 bool error(const char* format
, ...)
280 int limit
= sizeof(buffer
);
282 va_start(arg_ptr
, format
);
283 int ret
= _vsnprintf(buffer
, limit
, format
, arg_ptr
);
285 if (ret
< 0 || ret
>= limit
)
290 printf("ERROR: %s\n", buffer
);
295 void ParseString(const string
& str
, char c
, vector
<string
>& v
)
299 string::size_type i1
= 0;
300 string::size_type i2
;
303 i2
= str
.find(c
, i1
);
306 v
.push_back(str
.substr(i1
));
309 v
.push_back(str
.substr(i1
, i2
-i1
));
315 string
FormatMoney(int64 n
, bool fPlus
)
318 string str
= strprintf("%"PRI64d
".%02"PRI64d
, (n
> 0 ? n
: -n
)/100, (n
> 0 ? n
: -n
)%100);
319 for (int i
= 6; i
< str
.size(); i
+= 4)
320 if (isdigit(str
[str
.size() - i
- 1]))
321 str
.insert(str
.size() - i
, 1, ',');
323 str
.insert((unsigned int)0, 1, '-');
324 else if (fPlus
&& n
> 0)
325 str
.insert((unsigned int)0, 1, '+');
330 bool ParseMoney(const string
& str
, int64
& nRet
)
332 return ParseMoney(str
.c_str(), nRet
);
335 bool ParseMoney(const char* pszIn
, int64
& nRet
)
339 const char* p
= pszIn
;
344 if (*p
== ',' && p
> pszIn
&& isdigit(p
[-1]) && isdigit(p
[1]) && isdigit(p
[2]) && isdigit(p
[3]) && !isdigit(p
[4]))
351 nCents
= 10 * (*p
++ - '0');
353 nCents
+= (*p
++ - '0');
361 strWhole
.insert(strWhole
.end(), *p
);
366 if (strWhole
.size() > 14)
368 if (nCents
< 0 || nCents
> 99)
370 int64 nWhole
= atoi64(strWhole
);
371 int64 nPreValue
= nWhole
* 100 + nCents
;
372 int64 nValue
= nPreValue
* CENT
;
373 if (nValue
/ CENT
!= nPreValue
)
375 if (nValue
/ COIN
!= nWhole
)
382 vector
<unsigned char> ParseHex(const char* psz
)
384 static char phexdigit
[256] =
385 { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
386 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
387 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
388 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
389 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
390 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
391 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
392 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
393 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
394 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
395 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
396 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
397 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
398 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
399 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
400 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
402 // convert hex dump to vector
403 vector
<unsigned char> vch
;
406 while (isspace(*psz
))
408 char c
= phexdigit
[(unsigned char)*psz
++];
411 unsigned char n
= (c
<< 4);
412 c
= phexdigit
[(unsigned char)*psz
++];
421 vector
<unsigned char> ParseHex(const string
& str
)
423 return ParseHex(str
.c_str());
427 void ParseParameters(int argc
, char* argv
[])
430 mapMultiArgs
.clear();
431 for (int i
= 1; i
< argc
; i
++)
434 strlcpy(psz
, argv
[i
], sizeof(psz
));
435 char* pszValue
= (char*)"";
436 if (strchr(psz
, '='))
438 pszValue
= strchr(psz
, '=');
448 mapArgs
[psz
] = pszValue
;
449 mapMultiArgs
[psz
].push_back(pszValue
);
454 const char* wxGetTranslation(const char* pszEnglish
)
457 // Wrapper of wxGetTranslation returning the same const char* type as was passed in
458 static CCriticalSection cs
;
462 static map
<string
, char*> mapCache
;
463 map
<string
, char*>::iterator mi
= mapCache
.find(pszEnglish
);
464 if (mi
!= mapCache
.end())
467 // wxWidgets translation
468 wxString strTranslated
= wxGetTranslation(wxString(pszEnglish
, wxConvUTF8
));
470 // We don't cache unknown strings because caller might be passing in a
471 // dynamic string and we would keep allocating memory for each variation.
472 if (strcmp(pszEnglish
, strTranslated
.utf8_str()) == 0)
475 // Add to cache, memory doesn't need to be freed. We only cache because
476 // we must pass back a pointer to permanently allocated memory.
477 char* pszCached
= new char[strlen(strTranslated
.utf8_str())+1];
478 strcpy(pszCached
, strTranslated
.utf8_str());
479 mapCache
[pszEnglish
] = pszCached
;
489 bool WildcardMatch(const char* psz
, const char* mask
)
496 return (*psz
== '\0');
498 return WildcardMatch(psz
, mask
+1) || (*psz
&& WildcardMatch(psz
+1, mask
));
513 bool WildcardMatch(const string
& str
, const string
& mask
)
515 return WildcardMatch(str
.c_str(), mask
.c_str());
525 void FormatException(char* pszMessage
, std::exception
* pex
, const char* pszThread
)
528 char pszModule
[MAX_PATH
];
530 GetModuleFileNameA(NULL
, pszModule
, sizeof(pszModule
));
532 const char* pszModule
= "bitcoin";
535 snprintf(pszMessage
, 1000,
536 "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex
).name(), pex
->what(), pszModule
, pszThread
);
538 snprintf(pszMessage
, 1000,
539 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule
, pszThread
);
542 void LogException(std::exception
* pex
, const char* pszThread
)
544 char pszMessage
[10000];
545 FormatException(pszMessage
, pex
, pszThread
);
546 printf("\n%s", pszMessage
);
549 void PrintException(std::exception
* pex
, const char* pszThread
)
551 char pszMessage
[10000];
552 FormatException(pszMessage
, pex
, pszThread
);
553 printf("\n\n************************\n%s\n", pszMessage
);
554 fprintf(stderr
, "\n\n************************\n%s\n", pszMessage
);
555 strMiscWarning
= pszMessage
;
557 if (wxTheApp
&& !fDaemon
)
558 MyMessageBox(pszMessage
, "Bitcoin", wxOK
| wxICON_ERROR
);
563 void ThreadOneMessageBox(string strMessage
)
565 // Skip message boxes if one is already open
566 static bool fMessageBoxOpen
;
569 fMessageBoxOpen
= true;
570 ThreadSafeMessageBox(strMessage
, "Bitcoin", wxOK
| wxICON_EXCLAMATION
);
571 fMessageBoxOpen
= false;
574 void PrintExceptionContinue(std::exception
* pex
, const char* pszThread
)
576 char pszMessage
[10000];
577 FormatException(pszMessage
, pex
, pszThread
);
578 printf("\n\n************************\n%s\n", pszMessage
);
579 fprintf(stderr
, "\n\n************************\n%s\n", pszMessage
);
580 strMiscWarning
= pszMessage
;
582 if (wxTheApp
&& !fDaemon
)
583 boost::thread(boost::bind(ThreadOneMessageBox
, string(pszMessage
)));
595 typedef WINSHELLAPI
BOOL (WINAPI
*PSHGETSPECIALFOLDERPATHA
)(HWND hwndOwner
, LPSTR lpszPath
, int nFolder
, BOOL fCreate
);
597 string
MyGetSpecialFolderPath(int nFolder
, bool fCreate
)
599 char pszPath
[MAX_PATH
+100] = "";
601 // SHGetSpecialFolderPath isn't always available on old Windows versions
602 HMODULE hShell32
= LoadLibraryA("shell32.dll");
605 PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath
=
606 (PSHGETSPECIALFOLDERPATHA
)GetProcAddress(hShell32
, "SHGetSpecialFolderPathA");
607 if (pSHGetSpecialFolderPath
)
608 (*pSHGetSpecialFolderPath
)(NULL
, pszPath
, nFolder
, fCreate
);
609 FreeModule(hShell32
);
613 if (pszPath
[0] == '\0')
615 if (nFolder
== CSIDL_STARTUP
)
617 strcpy(pszPath
, getenv("USERPROFILE"));
618 strcat(pszPath
, "\\Start Menu\\Programs\\Startup");
620 else if (nFolder
== CSIDL_APPDATA
)
622 strcpy(pszPath
, getenv("APPDATA"));
630 string
GetDefaultDataDir()
632 // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
633 // Mac: ~/Library/Application Support/Bitcoin
637 return MyGetSpecialFolderPath(CSIDL_APPDATA
, true) + "\\Bitcoin";
639 char* pszHome
= getenv("HOME");
640 if (pszHome
== NULL
|| strlen(pszHome
) == 0)
641 pszHome
= (char*)"/";
642 string strHome
= pszHome
;
643 if (strHome
[strHome
.size()-1] != '/')
647 strHome
+= "Library/Application Support/";
648 filesystem::create_directory(strHome
.c_str());
649 return strHome
+ "Bitcoin";
652 return strHome
+ ".bitcoin";
657 void GetDataDir(char* pszDir
)
659 // pszDir must be at least MAX_PATH length.
661 if (pszSetDataDir
[0] != 0)
663 strlcpy(pszDir
, pszSetDataDir
, MAX_PATH
);
668 // This can be called during exceptions by printf, so we cache the
669 // value so we don't have to do memory allocations after that.
670 static char pszCachedDir
[MAX_PATH
];
671 if (pszCachedDir
[0] == 0)
672 strlcpy(pszCachedDir
, GetDefaultDataDir().c_str(), sizeof(pszCachedDir
));
673 strlcpy(pszDir
, pszCachedDir
, MAX_PATH
);
678 char* p
= pszDir
+ strlen(pszDir
);
679 if (p
> pszDir
&& p
[-1] != '/' && p
[-1] != '\\')
681 strcpy(p
, "testnet");
684 static bool pfMkdir
[4];
685 if (!pfMkdir
[nVariation
])
687 pfMkdir
[nVariation
] = true;
688 filesystem::create_directory(pszDir
);
694 char pszDir
[MAX_PATH
];
699 string
GetConfigFile()
701 namespace fs
= boost::filesystem
;
702 fs::path
pathConfig(GetArg("-conf", "bitcoin.conf"));
703 if (!pathConfig
.is_complete())
704 pathConfig
= fs::path(GetDataDir()) / pathConfig
;
705 return pathConfig
.string();
708 void ReadConfigFile(map
<string
, string
>& mapSettingsRet
,
709 map
<string
, vector
<string
> >& mapMultiSettingsRet
)
711 namespace fs
= boost::filesystem
;
712 namespace pod
= boost::program_options::detail
;
714 fs::ifstream
streamConfig(GetConfigFile());
715 if (!streamConfig
.good())
718 set
<string
> setOptions
;
719 setOptions
.insert("*");
721 for (pod::config_file_iterator
it(streamConfig
, setOptions
), end
; it
!= end
; ++it
)
723 // Don't overwrite existing settings so command line settings override bitcoin.conf
724 string strKey
= string("-") + it
->string_key
;
725 if (mapSettingsRet
.count(strKey
) == 0)
726 mapSettingsRet
[strKey
] = it
->value
[0];
727 mapMultiSettingsRet
[strKey
].push_back(it
->value
[0]);
731 int GetFilesize(FILE* file
)
733 int nSavePos
= ftell(file
);
735 if (fseek(file
, 0, SEEK_END
) == 0)
736 nFilesize
= ftell(file
);
737 fseek(file
, nSavePos
, SEEK_SET
);
741 void ShrinkDebugFile()
743 // Scroll debug.log if it's getting too big
744 string strFile
= GetDataDir() + "/debug.log";
745 FILE* file
= fopen(strFile
.c_str(), "r");
746 if (file
&& GetFilesize(file
) > 10 * 1000000)
748 // Restart the file with some of the end
750 fseek(file
, -sizeof(pch
), SEEK_END
);
751 int nBytes
= fread(pch
, 1, sizeof(pch
), file
);
753 if (file
= fopen(strFile
.c_str(), "w"))
755 fwrite(pch
, 1, nBytes
, file
);
769 // "Never go to sea with two chronometers; take one or three."
770 // Our three time sources are:
772 // - Median of other nodes's clocks
773 // - The user (asking the user to fix the system clock if the first two disagree)
780 static int64 nTimeOffset
= 0;
782 int64
GetAdjustedTime()
784 return GetTime() + nTimeOffset
;
787 void AddTimeData(unsigned int ip
, int64 nTime
)
789 int64 nOffsetSample
= nTime
- GetTime();
792 static set
<unsigned int> setKnown
;
793 if (!setKnown
.insert(ip
).second
)
797 static vector
<int64
> vTimeOffsets
;
798 if (vTimeOffsets
.empty())
799 vTimeOffsets
.push_back(0);
800 vTimeOffsets
.push_back(nOffsetSample
);
801 printf("Added time data, samples %d, offset %+"PRI64d
" (%+"PRI64d
" minutes)\n", vTimeOffsets
.size(), vTimeOffsets
.back(), vTimeOffsets
.back()/60);
802 if (vTimeOffsets
.size() >= 5 && vTimeOffsets
.size() % 2 == 1)
804 sort(vTimeOffsets
.begin(), vTimeOffsets
.end());
805 int64 nMedian
= vTimeOffsets
[vTimeOffsets
.size()/2];
806 // Only let other nodes change our time by so much
807 if (abs64(nMedian
) < 70 * 60)
809 nTimeOffset
= nMedian
;
814 // If nobody else has the same time as us, give a warning
816 foreach(int64 nOffset
, vTimeOffsets
)
817 if (nOffset
!= 0 && abs64(nOffset
) < 5 * 60)
820 if (!fMatch
&& !fDone
)
823 string strMessage
= _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
824 strMiscWarning
= strMessage
;
825 printf("*** %s\n", strMessage
.c_str());
826 boost::thread(boost::bind(ThreadSafeMessageBox
, strMessage
+" ", string("Bitcoin"), wxOK
| wxICON_EXCLAMATION
, (wxWindow
*)NULL
, -1, -1));
829 foreach(int64 n
, vTimeOffsets
)
830 printf("%+"PRI64d
" ", n
);
831 printf("| nTimeOffset = %+"PRI64d
" (%+"PRI64d
" minutes)\n", nTimeOffset
, nTimeOffset
/60);