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
);
182 if (fPrintToDebugger
)
184 static CCriticalSection cs_OutputDebugStringF
;
186 // accumulate a line at a time
187 CRITICAL_BLOCK(cs_OutputDebugStringF
)
189 static char pszBuffer
[50000];
194 va_start(arg_ptr
, pszFormat
);
195 int limit
= END(pszBuffer
) - pend
- 2;
196 int ret
= _vsnprintf(pend
, limit
, pszFormat
, arg_ptr
);
198 if (ret
< 0 || ret
>= limit
)
200 pend
= END(pszBuffer
) - 2;
206 char* p1
= pszBuffer
;
208 while (p2
= strchr(p1
, '\n'))
213 OutputDebugStringA(p1
);
218 memmove(pszBuffer
, p1
, pend
- p1
+ 1);
219 pend
-= (p1
- pszBuffer
);
228 // - prints up to limit-1 characters
229 // - output string is always null terminated even if limit reached
230 // - return value is the number of characters actually printed
231 int my_snprintf(char* buffer
, size_t limit
, const char* format
, ...)
236 va_start(arg_ptr
, format
);
237 int ret
= _vsnprintf(buffer
, limit
, format
, arg_ptr
);
239 if (ret
< 0 || ret
>= limit
)
248 string
strprintf(const char* format
, ...)
252 int limit
= sizeof(buffer
);
257 va_start(arg_ptr
, format
);
258 ret
= _vsnprintf(p
, limit
, format
, arg_ptr
);
260 if (ret
>= 0 && ret
< limit
)
267 throw std::bad_alloc();
269 string
str(p
, p
+ret
);
276 bool error(const char* format
, ...)
279 int limit
= sizeof(buffer
);
281 va_start(arg_ptr
, format
);
282 int ret
= _vsnprintf(buffer
, limit
, format
, arg_ptr
);
284 if (ret
< 0 || ret
>= limit
)
289 printf("ERROR: %s\n", buffer
);
294 void ParseString(const string
& str
, char c
, vector
<string
>& v
)
298 string::size_type i1
= 0;
299 string::size_type i2
;
302 i2
= str
.find(c
, i1
);
305 v
.push_back(str
.substr(i1
));
308 v
.push_back(str
.substr(i1
, i2
-i1
));
314 string
FormatMoney(int64 n
, bool fPlus
)
317 string str
= strprintf("%"PRI64d
".%02"PRI64d
, (n
> 0 ? n
: -n
)/100, (n
> 0 ? n
: -n
)%100);
318 for (int i
= 6; i
< str
.size(); i
+= 4)
319 if (isdigit(str
[str
.size() - i
- 1]))
320 str
.insert(str
.size() - i
, 1, ',');
322 str
.insert((unsigned int)0, 1, '-');
323 else if (fPlus
&& n
> 0)
324 str
.insert((unsigned int)0, 1, '+');
329 bool ParseMoney(const string
& str
, int64
& nRet
)
331 return ParseMoney(str
.c_str(), nRet
);
334 bool ParseMoney(const char* pszIn
, int64
& nRet
)
338 const char* p
= pszIn
;
343 if (*p
== ',' && p
> pszIn
&& isdigit(p
[-1]) && isdigit(p
[1]) && isdigit(p
[2]) && isdigit(p
[3]) && !isdigit(p
[4]))
350 nCents
= 10 * (*p
++ - '0');
352 nCents
+= (*p
++ - '0');
360 strWhole
.insert(strWhole
.end(), *p
);
365 if (strWhole
.size() > 14)
367 if (nCents
< 0 || nCents
> 99)
369 int64 nWhole
= atoi64(strWhole
);
370 int64 nPreValue
= nWhole
* 100 + nCents
;
371 int64 nValue
= nPreValue
* CENT
;
372 if (nValue
/ CENT
!= nPreValue
)
374 if (nValue
/ COIN
!= nWhole
)
381 vector
<unsigned char> ParseHex(const char* psz
)
383 static char phexdigit
[256] =
384 { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
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 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
388 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
389 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
390 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
391 -1,-1,-1,-1,-1,-1,-1,-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, };
401 // convert hex dump to vector
402 vector
<unsigned char> vch
;
405 while (isspace(*psz
))
407 char c
= phexdigit
[(unsigned char)*psz
++];
410 unsigned char n
= (c
<< 4);
411 c
= phexdigit
[(unsigned char)*psz
++];
420 vector
<unsigned char> ParseHex(const string
& str
)
422 return ParseHex(str
.c_str());
426 void ParseParameters(int argc
, char* argv
[])
429 mapMultiArgs
.clear();
430 for (int i
= 1; i
< argc
; i
++)
433 strlcpy(psz
, argv
[i
], sizeof(psz
));
434 char* pszValue
= (char*)"";
435 if (strchr(psz
, '='))
437 pszValue
= strchr(psz
, '=');
447 mapArgs
[psz
] = pszValue
;
448 mapMultiArgs
[psz
].push_back(pszValue
);
453 const char* wxGetTranslation(const char* pszEnglish
)
456 // Wrapper of wxGetTranslation returning the same const char* type as was passed in
457 static CCriticalSection cs
;
461 static map
<string
, char*> mapCache
;
462 map
<string
, char*>::iterator mi
= mapCache
.find(pszEnglish
);
463 if (mi
!= mapCache
.end())
466 // wxWidgets translation
467 wxString strTranslated
= wxGetTranslation(wxString(pszEnglish
, wxConvUTF8
));
469 // We don't cache unknown strings because caller might be passing in a
470 // dynamic string and we would keep allocating memory for each variation.
471 if (strcmp(pszEnglish
, strTranslated
.utf8_str()) == 0)
474 // Add to cache, memory doesn't need to be freed. We only cache because
475 // we must pass back a pointer to permanently allocated memory.
476 char* pszCached
= new char[strlen(strTranslated
.utf8_str())+1];
477 strcpy(pszCached
, strTranslated
.utf8_str());
478 mapCache
[pszEnglish
] = pszCached
;
488 bool WildcardMatch(const char* psz
, const char* mask
)
495 return (*psz
== '\0');
497 return WildcardMatch(psz
, mask
+1) || (*psz
&& WildcardMatch(psz
+1, mask
));
512 bool WildcardMatch(const string
& str
, const string
& mask
)
514 return WildcardMatch(str
.c_str(), mask
.c_str());
524 void FormatException(char* pszMessage
, std::exception
* pex
, const char* pszThread
)
527 char pszModule
[MAX_PATH
];
529 GetModuleFileNameA(NULL
, pszModule
, sizeof(pszModule
));
531 const char* pszModule
= "bitcoin";
534 snprintf(pszMessage
, 1000,
535 "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex
).name(), pex
->what(), pszModule
, pszThread
);
537 snprintf(pszMessage
, 1000,
538 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule
, pszThread
);
541 void LogException(std::exception
* pex
, const char* pszThread
)
543 char pszMessage
[10000];
544 FormatException(pszMessage
, pex
, pszThread
);
545 printf("\n%s", pszMessage
);
548 void PrintException(std::exception
* pex
, const char* pszThread
)
550 char pszMessage
[10000];
551 FormatException(pszMessage
, pex
, pszThread
);
552 printf("\n\n************************\n%s\n", pszMessage
);
553 fprintf(stderr
, "\n\n************************\n%s\n", pszMessage
);
554 strMiscWarning
= pszMessage
;
556 if (wxTheApp
&& !fDaemon
)
557 MyMessageBox(pszMessage
, "Bitcoin", wxOK
| wxICON_ERROR
);
562 void ThreadOneMessageBox(string strMessage
)
564 // Skip message boxes if one is already open
565 static bool fMessageBoxOpen
;
568 fMessageBoxOpen
= true;
569 ThreadSafeMessageBox(strMessage
, "Bitcoin", wxOK
| wxICON_EXCLAMATION
);
570 fMessageBoxOpen
= false;
573 void PrintExceptionContinue(std::exception
* pex
, const char* pszThread
)
575 char pszMessage
[10000];
576 FormatException(pszMessage
, pex
, pszThread
);
577 printf("\n\n************************\n%s\n", pszMessage
);
578 fprintf(stderr
, "\n\n************************\n%s\n", pszMessage
);
579 strMiscWarning
= pszMessage
;
581 if (wxTheApp
&& !fDaemon
)
582 boost::thread(boost::bind(ThreadOneMessageBox
, string(pszMessage
)));
594 typedef WINSHELLAPI
BOOL (WINAPI
*PSHGETSPECIALFOLDERPATHA
)(HWND hwndOwner
, LPSTR lpszPath
, int nFolder
, BOOL fCreate
);
596 string
MyGetSpecialFolderPath(int nFolder
, bool fCreate
)
598 char pszPath
[MAX_PATH
+100] = "";
600 // SHGetSpecialFolderPath isn't always available on old Windows versions
601 HMODULE hShell32
= LoadLibraryA("shell32.dll");
604 PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath
=
605 (PSHGETSPECIALFOLDERPATHA
)GetProcAddress(hShell32
, "SHGetSpecialFolderPathA");
606 if (pSHGetSpecialFolderPath
)
607 (*pSHGetSpecialFolderPath
)(NULL
, pszPath
, nFolder
, fCreate
);
608 FreeModule(hShell32
);
612 if (pszPath
[0] == '\0')
614 if (nFolder
== CSIDL_STARTUP
)
616 strcpy(pszPath
, getenv("USERPROFILE"));
617 strcat(pszPath
, "\\Start Menu\\Programs\\Startup");
619 else if (nFolder
== CSIDL_APPDATA
)
621 strcpy(pszPath
, getenv("APPDATA"));
629 string
GetDefaultDataDir()
631 // Windows: C:\Documents and Settings\username\Application Data\Bitcoin
632 // Mac: ~/Library/Application Support/Bitcoin
636 return MyGetSpecialFolderPath(CSIDL_APPDATA
, true) + "\\Bitcoin";
638 char* pszHome
= getenv("HOME");
639 if (pszHome
== NULL
|| strlen(pszHome
) == 0)
640 pszHome
= (char*)"/";
641 string strHome
= pszHome
;
642 if (strHome
[strHome
.size()-1] != '/')
646 strHome
+= "Library/Application Support/";
647 filesystem::create_directory(strHome
.c_str());
648 return strHome
+ "Bitcoin";
651 return strHome
+ ".bitcoin";
656 void GetDataDir(char* pszDir
)
658 // pszDir must be at least MAX_PATH length.
660 if (pszSetDataDir
[0] != 0)
662 strlcpy(pszDir
, pszSetDataDir
, MAX_PATH
);
667 // This can be called during exceptions by printf, so we cache the
668 // value so we don't have to do memory allocations after that.
669 static char pszCachedDir
[MAX_PATH
];
670 if (pszCachedDir
[0] == 0)
671 strlcpy(pszCachedDir
, GetDefaultDataDir().c_str(), sizeof(pszCachedDir
));
672 strlcpy(pszDir
, pszCachedDir
, MAX_PATH
);
677 char* p
= pszDir
+ strlen(pszDir
);
678 if (p
> pszDir
&& p
[-1] != '/' && p
[-1] != '\\')
680 strcpy(p
, "testnet");
683 static bool pfMkdir
[4];
684 if (!pfMkdir
[nVariation
])
686 pfMkdir
[nVariation
] = true;
687 filesystem::create_directory(pszDir
);
693 char pszDir
[MAX_PATH
];
698 string
GetConfigFile()
700 namespace fs
= boost::filesystem
;
701 fs::path
pathConfig(GetArg("-conf", "bitcoin.conf"));
702 if (!pathConfig
.is_complete())
703 pathConfig
= fs::path(GetDataDir()) / pathConfig
;
704 return pathConfig
.string();
707 void ReadConfigFile(map
<string
, string
>& mapSettingsRet
,
708 map
<string
, vector
<string
> >& mapMultiSettingsRet
)
710 namespace fs
= boost::filesystem
;
711 namespace pod
= boost::program_options::detail
;
713 fs::ifstream
streamConfig(GetConfigFile());
714 if (!streamConfig
.good())
717 set
<string
> setOptions
;
718 setOptions
.insert("*");
720 for (pod::config_file_iterator
it(streamConfig
, setOptions
), end
; it
!= end
; ++it
)
722 // Don't overwrite existing settings so command line settings override bitcoin.conf
723 string strKey
= string("-") + it
->string_key
;
724 if (mapSettingsRet
.count(strKey
) == 0)
725 mapSettingsRet
[strKey
] = it
->value
[0];
726 mapMultiSettingsRet
[strKey
].push_back(it
->value
[0]);
730 int GetFilesize(FILE* file
)
732 int nSavePos
= ftell(file
);
734 if (fseek(file
, 0, SEEK_END
) == 0)
735 nFilesize
= ftell(file
);
736 fseek(file
, nSavePos
, SEEK_SET
);
740 void ShrinkDebugFile()
742 // Scroll debug.log if it's getting too big
743 string strFile
= GetDataDir() + "/debug.log";
744 FILE* file
= fopen(strFile
.c_str(), "r");
745 if (file
&& GetFilesize(file
) > 10 * 1000000)
747 // Restart the file with some of the end
749 fseek(file
, -sizeof(pch
), SEEK_END
);
750 int nBytes
= fread(pch
, 1, sizeof(pch
), file
);
752 if (file
= fopen(strFile
.c_str(), "w"))
754 fwrite(pch
, 1, nBytes
, file
);
768 // "Never go to sea with two chronometers; take one or three."
769 // Our three time sources are:
771 // - Median of other nodes's clocks
772 // - The user (asking the user to fix the system clock if the first two disagree)
779 static int64 nTimeOffset
= 0;
781 int64
GetAdjustedTime()
783 return GetTime() + nTimeOffset
;
786 void AddTimeData(unsigned int ip
, int64 nTime
)
788 int64 nOffsetSample
= nTime
- GetTime();
791 static set
<unsigned int> setKnown
;
792 if (!setKnown
.insert(ip
).second
)
796 static vector
<int64
> vTimeOffsets
;
797 if (vTimeOffsets
.empty())
798 vTimeOffsets
.push_back(0);
799 vTimeOffsets
.push_back(nOffsetSample
);
800 printf("Added time data, samples %d, offset %+"PRI64d
" (%+"PRI64d
" minutes)\n", vTimeOffsets
.size(), vTimeOffsets
.back(), vTimeOffsets
.back()/60);
801 if (vTimeOffsets
.size() >= 5 && vTimeOffsets
.size() % 2 == 1)
803 sort(vTimeOffsets
.begin(), vTimeOffsets
.end());
804 int64 nMedian
= vTimeOffsets
[vTimeOffsets
.size()/2];
805 // Only let other nodes change our time by so much
806 if (abs64(nMedian
) < 70 * 60)
808 nTimeOffset
= nMedian
;
813 // If nobody else has the same time as us, give a warning
815 foreach(int64 nOffset
, vTimeOffsets
)
816 if (nOffset
!= 0 && abs64(nOffset
) < 5 * 60)
819 if (!fMatch
&& !fDone
)
822 string strMessage
= _("Warning: Please check that your computer's date and time are correct. If your clock is wrong Bitcoin will not work properly.");
823 strMiscWarning
= strMessage
;
824 printf("*** %s\n", strMessage
.c_str());
825 boost::thread(boost::bind(ThreadSafeMessageBox
, strMessage
+" ", string("Bitcoin"), wxOK
| wxICON_EXCLAMATION
, (wxWindow
*)NULL
, -1, -1));
828 foreach(int64 n
, vTimeOffsets
)
829 printf("%+"PRI64d
" ", n
);
830 printf("| nTimeOffset = %+"PRI64d
" (%+"PRI64d
" minutes)\n", nTimeOffset
, nTimeOffset
/60);