1 // Copyright (c) 2009-2010 Satoshi Nakamoto
\r
2 // Distributed under the MIT/X11 software license, see the accompanying
\r
3 // file license.txt or http://www.opensource.org/licenses/mit-license.php.
\r
8 map<string, string> mapArgs;
\r
9 map<string, vector<string> > mapMultiArgs;
\r
10 bool fDebug = false;
\r
11 bool fPrintToConsole = false;
\r
12 bool fPrintToDebugger = false;
\r
13 char pszSetDataDir[MAX_PATH] = "";
\r
14 bool fShutdown = false;
\r
15 bool fDaemon = false;
\r
21 // Init openssl library multithreading support
\r
22 static wxMutex** ppmutexOpenSSL;
\r
23 void locking_callback(int mode, int i, const char* file, int line)
\r
25 if (mode & CRYPTO_LOCK)
\r
26 ppmutexOpenSSL[i]->Lock();
\r
28 ppmutexOpenSSL[i]->Unlock();
\r
37 // Init openssl library multithreading support
\r
38 ppmutexOpenSSL = (wxMutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(wxMutex*));
\r
39 for (int i = 0; i < CRYPTO_num_locks(); i++)
\r
40 ppmutexOpenSSL[i] = new wxMutex();
\r
41 CRYPTO_set_locking_callback(locking_callback);
\r
44 // Seed random number generator with screen scrape and other hardware sources
\r
48 // Seed random number generator with performance counter
\r
53 // Shutdown openssl library multithreading support
\r
54 CRYPTO_set_locking_callback(NULL);
\r
55 for (int i = 0; i < CRYPTO_num_locks(); i++)
\r
56 delete ppmutexOpenSSL[i];
\r
57 OPENSSL_free(ppmutexOpenSSL);
\r
71 // Seed with CPU performance counter
\r
72 int64 nCounter = PerformanceCounter();
\r
73 RAND_add(&nCounter, sizeof(nCounter), 1.5);
\r
74 memset(&nCounter, 0, sizeof(nCounter));
\r
77 void RandAddSeedPerfmon()
\r
81 // This can take up to 2 seconds, so only do it every 10 minutes
\r
82 static int64 nLastPerfmon;
\r
83 if (GetTime() < nLastPerfmon + 10 * 60)
\r
85 nLastPerfmon = GetTime();
\r
88 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
\r
89 // Seed with the entire set of perfmon data
\r
90 unsigned char pdata[250000];
\r
91 memset(pdata, 0, sizeof(pdata));
\r
92 unsigned long nSize = sizeof(pdata);
\r
93 long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
\r
94 RegCloseKey(HKEY_PERFORMANCE_DATA);
\r
95 if (ret == ERROR_SUCCESS)
\r
98 SHA256(pdata, nSize, (unsigned char*)&hash);
\r
99 RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
\r
101 memset(pdata, 0, nSize);
\r
103 printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);
\r
106 printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
\r
110 uint64 GetRand(uint64 nMax)
\r
115 // The range of the random source must be a multiple of the modulus
\r
116 // to give every possible output value an equal possibility
\r
117 uint64 nRange = (UINT64_MAX / nMax) * nMax;
\r
120 RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
\r
121 while (nRand >= nRange);
\r
122 return (nRand % nMax);
\r
135 inline int OutputDebugStringF(const char* pszFormat, ...)
\r
138 if (fPrintToConsole || wxTheApp == NULL)
\r
140 // print to console
\r
142 va_start(arg_ptr, pszFormat);
\r
143 ret = vprintf(pszFormat, arg_ptr);
\r
148 // print to debug.log
\r
149 char pszFile[MAX_PATH+100];
\r
150 GetDataDir(pszFile);
\r
151 strlcat(pszFile, "/debug.log", sizeof(pszFile));
\r
152 FILE* fileout = fopen(pszFile, "a");
\r
155 //// Debug print useful for profiling
\r
156 //fprintf(fileout, " %"PRI64d" ", wxGetLocalTimeMillis().GetValue());
\r
158 va_start(arg_ptr, pszFormat);
\r
159 ret = vfprintf(fileout, pszFormat, arg_ptr);
\r
166 if (fPrintToDebugger)
\r
168 // accumulate a line at a time
\r
169 static CCriticalSection cs_OutputDebugStringF;
\r
170 CRITICAL_BLOCK(cs_OutputDebugStringF)
\r
172 static char pszBuffer[50000];
\r
177 va_start(arg_ptr, pszFormat);
\r
178 int limit = END(pszBuffer) - pend - 2;
\r
179 int ret = _vsnprintf(pend, limit, pszFormat, arg_ptr);
\r
181 if (ret < 0 || ret >= limit)
\r
183 pend = END(pszBuffer) - 2;
\r
189 char* p1 = pszBuffer;
\r
191 while (p2 = strchr(p1, '\n'))
\r
196 OutputDebugStringA(p1);
\r
200 if (p1 != pszBuffer)
\r
201 memmove(pszBuffer, p1, pend - p1 + 1);
\r
202 pend -= (p1 - pszBuffer);
\r
211 // - prints up to limit-1 characters
\r
212 // - output string is always null terminated even if limit reached
\r
213 // - return value is the number of characters actually printed
\r
214 int my_snprintf(char* buffer, size_t limit, const char* format, ...)
\r
219 va_start(arg_ptr, format);
\r
220 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
\r
222 if (ret < 0 || ret >= limit)
\r
225 buffer[limit-1] = 0;
\r
231 string strprintf(const char* format, ...)
\r
233 char buffer[50000];
\r
235 int limit = sizeof(buffer);
\r
240 va_start(arg_ptr, format);
\r
241 ret = _vsnprintf(p, limit, format, arg_ptr);
\r
243 if (ret >= 0 && ret < limit)
\r
248 p = new char[limit];
\r
250 throw std::bad_alloc();
\r
253 // msvc optimisation
\r
255 return string(p, p+ret);
\r
257 string str(p, p+ret);
\r
264 bool error(const char* format, ...)
\r
266 char buffer[50000];
\r
267 int limit = sizeof(buffer);
\r
269 va_start(arg_ptr, format);
\r
270 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
\r
272 if (ret < 0 || ret >= limit)
\r
275 buffer[limit-1] = 0;
\r
277 printf("ERROR: %s\n", buffer);
\r
282 void ParseString(const string& str, char c, vector<string>& v)
\r
284 unsigned int i1 = 0;
\r
288 i2 = str.find(c, i1);
\r
289 v.push_back(str.substr(i1, i2-i1));
\r
292 while (i2 != str.npos);
\r
296 string FormatMoney(int64 n, bool fPlus)
\r
299 string str = strprintf("%"PRI64d".%02"PRI64d, (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);
\r
300 for (int i = 6; i < str.size(); i += 4)
\r
301 if (isdigit(str[str.size() - i - 1]))
\r
302 str.insert(str.size() - i, 1, ',');
\r
304 str.insert((unsigned int)0, 1, '-');
\r
305 else if (fPlus && n > 0)
\r
306 str.insert((unsigned int)0, 1, '+');
\r
310 bool ParseMoney(const char* pszIn, int64& nRet)
\r
314 const char* p = pszIn;
\r
315 while (isspace(*p))
\r
319 if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))
\r
326 nCents = 10 * (*p++ - '0');
\r
328 nCents += (*p++ - '0');
\r
336 strWhole.insert(strWhole.end(), *p);
\r
341 if (strWhole.size() > 14)
\r
343 if (nCents < 0 || nCents > 99)
\r
345 int64 nWhole = atoi64(strWhole);
\r
346 int64 nPreValue = nWhole * 100 + nCents;
\r
347 int64 nValue = nPreValue * CENT;
\r
348 if (nValue / CENT != nPreValue)
\r
350 if (nValue / COIN != nWhole)
\r
357 vector<unsigned char> ParseHex(const char* psz)
\r
359 vector<unsigned char> vch;
\r
360 while (isspace(*psz))
\r
362 vch.reserve((strlen(psz)+1)/3);
\r
364 static char phexdigit[256] =
\r
365 { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
366 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
367 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
368 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
\r
369 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
370 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
371 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
\r
372 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
373 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
374 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
375 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
376 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
377 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
378 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
379 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
380 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
\r
384 char c = phexdigit[(unsigned char)*psz++];
\r
387 unsigned char n = (c << 4);
\r
390 char c = phexdigit[(unsigned char)*psz++];
\r
396 while (isspace(*psz))
\r
403 vector<unsigned char> ParseHex(const std::string& str)
\r
405 return ParseHex(str.c_str());
\r
409 void ParseParameters(int argc, char* argv[])
\r
412 mapMultiArgs.clear();
\r
413 for (int i = 0; i < argc; i++)
\r
416 strlcpy(psz, argv[i], sizeof(psz));
\r
417 char* pszValue = (char*)"";
\r
418 if (strchr(psz, '='))
\r
420 pszValue = strchr(psz, '=');
\r
421 *pszValue++ = '\0';
\r
428 mapArgs[psz] = pszValue;
\r
429 mapMultiArgs[psz].push_back(pszValue);
\r
439 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
\r
442 char pszModule[MAX_PATH];
\r
443 pszModule[0] = '\0';
\r
444 GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));
\r
446 // might not be thread safe, uses wxString
\r
447 //const char* pszModule = wxStandardPaths::Get().GetExecutablePath().mb_str();
\r
448 const char* pszModule = "bitcoin";
\r
451 snprintf(pszMessage, 1000,
\r
452 "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
\r
454 snprintf(pszMessage, 1000,
\r
455 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
\r
458 void LogException(std::exception* pex, const char* pszThread)
\r
460 char pszMessage[1000];
\r
461 FormatException(pszMessage, pex, pszThread);
\r
462 printf("\n%s", pszMessage);
\r
465 void PrintException(std::exception* pex, const char* pszThread)
\r
467 char pszMessage[1000];
\r
468 FormatException(pszMessage, pex, pszThread);
\r
469 printf("\n\n************************\n%s\n", pszMessage);
\r
471 wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);
\r
483 void GetDataDir(char* pszDir)
\r
485 // pszDir must be at least MAX_PATH length.
\r
486 if (pszSetDataDir[0] != 0)
\r
488 strlcpy(pszDir, pszSetDataDir, MAX_PATH);
\r
489 static bool fMkdirDone;
\r
498 // This can be called during exceptions by printf, so we cache the
\r
499 // value so we don't have to do memory allocations after that.
\r
500 // wxStandardPaths::GetUserDataDir
\r
501 // Return the directory for the user-dependent application data files:
\r
502 // Unix: ~/.appname
\r
503 // Windows: C:\Documents and Settings\username\Application Data\appname
\r
504 // Mac: ~/Library/Application Support/appname
\r
505 static char pszCachedDir[MAX_PATH];
\r
506 if (pszCachedDir[0] == 0)
\r
508 strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));
\r
509 _mkdir(pszCachedDir);
\r
511 strlcpy(pszDir, pszCachedDir, MAX_PATH);
\r
515 string GetDataDir()
\r
517 char pszDir[MAX_PATH];
\r
518 GetDataDir(pszDir);
\r
522 int GetFilesize(FILE* file)
\r
524 int nSavePos = ftell(file);
\r
525 int nFilesize = -1;
\r
526 if (fseek(file, 0, SEEK_END) == 0)
\r
527 nFilesize = ftell(file);
\r
528 fseek(file, nSavePos, SEEK_SET);
\r
532 void ShrinkDebugFile()
\r
534 // Scroll debug.log if it's getting too big
\r
535 string strFile = GetDataDir() + "/debug.log";
\r
536 FILE* file = fopen(strFile.c_str(), "r");
\r
537 if (file && GetFilesize(file) > 10 * 1000000)
\r
539 // Restart the file with some of the end
\r
541 fseek(file, -sizeof(pch), SEEK_END);
\r
542 int nBytes = fread(pch, 1, sizeof(pch), file);
\r
544 if (file = fopen(strFile.c_str(), "w"))
\r
546 fwrite(pch, 1, nBytes, file);
\r
563 // "Never go to sea with two chronometers; take one or three."
\r
564 // Our three chronometers are:
\r
566 // - Median of other server's clocks
\r
569 // note: NTP isn't implemented yet, so until then we just use the median
\r
570 // of other nodes clocks to correct ours.
\r
577 static int64 nTimeOffset = 0;
\r
579 int64 GetAdjustedTime()
\r
581 return GetTime() + nTimeOffset;
\r
584 void AddTimeData(unsigned int ip, int64 nTime)
\r
586 int64 nOffsetSample = nTime - GetTime();
\r
588 // Ignore duplicates
\r
589 static set<unsigned int> setKnown;
\r
590 if (!setKnown.insert(ip).second)
\r
594 static vector<int64> vTimeOffsets;
\r
595 if (vTimeOffsets.empty())
\r
596 vTimeOffsets.push_back(0);
\r
597 vTimeOffsets.push_back(nOffsetSample);
\r
598 printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
\r
599 if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
\r
601 sort(vTimeOffsets.begin(), vTimeOffsets.end());
\r
602 int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
\r
603 nTimeOffset = nMedian;
\r
604 if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60)
\r
606 // Only let other nodes change our clock so far before we
\r
607 // go to the NTP servers
\r
608 /// todo: Get time from NTP servers, then set a flag
\r
609 /// to make sure it doesn't get changed again
\r
611 foreach(int64 n, vTimeOffsets)
\r
612 printf("%+"PRI64d" ", n);
\r
613 printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
\r