1 // Copyright (c) 2009 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 fPrintToDebugger = false;
\r
12 bool fPrintToConsole = false;
\r
13 char pszSetDataDir[MAX_PATH] = "";
\r
14 bool fShutdown = false;
\r
20 // Init openssl library multithreading support
\r
21 static wxMutex** ppmutexOpenSSL;
\r
22 void locking_callback(int mode, int i, const char* file, int line)
\r
24 if (mode & CRYPTO_LOCK)
\r
25 ppmutexOpenSSL[i]->Lock();
\r
27 ppmutexOpenSSL[i]->Unlock();
\r
36 // Init openssl library multithreading support
\r
37 ppmutexOpenSSL = (wxMutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(wxMutex*));
\r
38 for (int i = 0; i < CRYPTO_num_locks(); i++)
\r
39 ppmutexOpenSSL[i] = new wxMutex();
\r
40 CRYPTO_set_locking_callback(locking_callback);
\r
43 // Seed random number generator with screen scrape and other hardware sources
\r
47 // Seed random number generator with performance counter
\r
52 // Shutdown openssl library multithreading support
\r
53 CRYPTO_set_locking_callback(NULL);
\r
54 for (int i = 0; i < CRYPTO_num_locks(); i++)
\r
55 delete ppmutexOpenSSL[i];
\r
56 OPENSSL_free(ppmutexOpenSSL);
\r
70 // Seed with CPU performance counter
\r
71 int64 nCounter = PerformanceCounter();
\r
72 RAND_add(&nCounter, sizeof(nCounter), 1.5);
\r
73 memset(&nCounter, 0, sizeof(nCounter));
\r
76 void RandAddSeedPerfmon()
\r
78 // This can take up to 2 seconds, so only do it every 10 minutes
\r
79 static int64 nLastPerfmon;
\r
80 if (GetTime() < nLastPerfmon + 10 * 60)
\r
82 nLastPerfmon = GetTime();
\r
85 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
\r
86 // Seed with the entire set of perfmon data
\r
87 unsigned char pdata[250000];
\r
88 memset(pdata, 0, sizeof(pdata));
\r
89 unsigned long nSize = sizeof(pdata);
\r
90 long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
\r
91 RegCloseKey(HKEY_PERFORMANCE_DATA);
\r
92 if (ret == ERROR_SUCCESS)
\r
95 SHA256(pdata, nSize, (unsigned char*)&hash);
\r
96 RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
\r
98 memset(pdata, 0, nSize);
\r
100 printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);
\r
103 printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());
\r
107 uint64 GetRand(uint64 nMax)
\r
112 // The range of the random source must be a multiple of the modulus
\r
113 // to give every possible output value an equal possibility
\r
114 uint64 nRange = (UINT64_MAX / nMax) * nMax;
\r
117 RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
\r
118 while (nRand >= nRange);
\r
119 return (nRand % nMax);
\r
135 // - prints up to limit-1 characters
\r
136 // - output string is always null terminated even if limit reached
\r
137 // - return value is the number of characters actually printed
\r
138 int my_snprintf(char* buffer, size_t limit, const char* format, ...)
\r
143 va_start(arg_ptr, format);
\r
144 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
\r
146 if (ret < 0 || ret >= limit)
\r
149 buffer[limit-1] = 0;
\r
155 string strprintf(const char* format, ...)
\r
157 char buffer[50000];
\r
159 int limit = sizeof(buffer);
\r
164 va_start(arg_ptr, format);
\r
165 ret = _vsnprintf(p, limit, format, arg_ptr);
\r
167 if (ret >= 0 && ret < limit)
\r
172 p = new char[limit];
\r
174 throw std::bad_alloc();
\r
177 // msvc optimisation
\r
179 return string(p, p+ret);
\r
181 string str(p, p+ret);
\r
188 bool error(const char* format, ...)
\r
190 char buffer[50000];
\r
191 int limit = sizeof(buffer);
\r
193 va_start(arg_ptr, format);
\r
194 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
\r
196 if (ret < 0 || ret >= limit)
\r
199 buffer[limit-1] = 0;
\r
201 printf("ERROR: %s\n", buffer);
\r
206 void ParseString(const string& str, char c, vector<string>& v)
\r
208 unsigned int i1 = 0;
\r
212 i2 = str.find(c, i1);
\r
213 v.push_back(str.substr(i1, i2-i1));
\r
216 while (i2 != str.npos);
\r
220 string FormatMoney(int64 n, bool fPlus)
\r
223 string str = strprintf("%"PRI64d".%02"PRI64d, (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);
\r
224 for (int i = 6; i < str.size(); i += 4)
\r
225 if (isdigit(str[str.size() - i - 1]))
\r
226 str.insert(str.size() - i, 1, ',');
\r
228 str.insert((unsigned int)0, 1, '-');
\r
229 else if (fPlus && n > 0)
\r
230 str.insert((unsigned int)0, 1, '+');
\r
234 bool ParseMoney(const char* pszIn, int64& nRet)
\r
238 const char* p = pszIn;
\r
239 while (isspace(*p))
\r
243 if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))
\r
250 nCents = 10 * (*p++ - '0');
\r
252 nCents += (*p++ - '0');
\r
260 strWhole.insert(strWhole.end(), *p);
\r
265 if (strWhole.size() > 14)
\r
267 if (nCents < 0 || nCents > 99)
\r
269 int64 nWhole = atoi64(strWhole);
\r
270 int64 nPreValue = nWhole * 100 + nCents;
\r
271 int64 nValue = nPreValue * CENT;
\r
272 if (nValue / CENT != nPreValue)
\r
274 if (nValue / COIN != nWhole)
\r
281 vector<unsigned char> ParseHex(const char* psz)
\r
283 vector<unsigned char> vch;
\r
284 while (isspace(*psz))
\r
286 vch.reserve((strlen(psz)+1)/3);
\r
288 static char phexdigit[256] =
\r
289 { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
290 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
291 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
292 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
\r
293 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
294 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
295 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
\r
296 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
297 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
298 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
299 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
300 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
301 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
302 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
303 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
304 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
\r
308 char c = phexdigit[(unsigned char)*psz++];
\r
311 unsigned char n = (c << 4);
\r
314 char c = phexdigit[(unsigned char)*psz++];
\r
320 while (isspace(*psz))
\r
327 vector<unsigned char> ParseHex(const std::string& str)
\r
329 return ParseHex(str.c_str());
\r
333 void ParseParameters(int argc, char* argv[])
\r
336 mapMultiArgs.clear();
\r
337 for (int i = 0; i < argc; i++)
\r
340 strlcpy(psz, argv[i], sizeof(psz));
\r
341 char* pszValue = (char*)"";
\r
342 if (strchr(psz, '='))
\r
344 pszValue = strchr(psz, '=');
\r
345 *pszValue++ = '\0';
\r
352 mapArgs[psz] = pszValue;
\r
353 mapMultiArgs[psz].push_back(pszValue);
\r
363 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
\r
366 char pszModule[MAX_PATH];
\r
367 pszModule[0] = '\0';
\r
368 GetModuleFileName(NULL, pszModule, sizeof(pszModule));
\r
370 // might not be thread safe, uses wxString
\r
371 //const char* pszModule = wxStandardPaths::Get().GetExecutablePath().mb_str();
\r
372 const char* pszModule = "bitcoin";
\r
375 snprintf(pszMessage, 1000,
\r
376 "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
\r
378 snprintf(pszMessage, 1000,
\r
379 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
\r
382 void LogException(std::exception* pex, const char* pszThread)
\r
384 char pszMessage[1000];
\r
385 FormatException(pszMessage, pex, pszThread);
\r
386 printf("\n%s", pszMessage);
\r
389 void PrintException(std::exception* pex, const char* pszThread)
\r
391 char pszMessage[1000];
\r
392 FormatException(pszMessage, pex, pszThread);
\r
393 printf("\n\n************************\n%s\n", pszMessage);
\r
395 wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);
\r
407 void GetDataDir(char* pszDir)
\r
409 // pszDir must be at least MAX_PATH length.
\r
410 if (pszSetDataDir[0] != 0)
\r
412 strlcpy(pszDir, pszSetDataDir, MAX_PATH);
\r
413 static bool fMkdirDone;
\r
422 // This can be called during exceptions by printf, so we cache the
\r
423 // value so we don't have to do memory allocations after that.
\r
424 // wxStandardPaths::GetUserDataDir
\r
425 // Return the directory for the user-dependent application data files:
\r
426 // Unix: ~/.appname
\r
427 // Windows: C:\Documents and Settings\username\Application Data\appname
\r
428 // Mac: ~/Library/Application Support/appname
\r
429 static char pszCachedDir[MAX_PATH];
\r
430 if (pszCachedDir[0] == 0)
\r
432 strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));
\r
433 _mkdir(pszCachedDir);
\r
435 strlcpy(pszDir, pszCachedDir, MAX_PATH);
\r
439 string GetDataDir()
\r
441 char pszDir[MAX_PATH];
\r
442 GetDataDir(pszDir);
\r
446 int GetFilesize(FILE* file)
\r
448 int nSavePos = ftell(file);
\r
449 int nFilesize = -1;
\r
450 if (fseek(file, 0, SEEK_END) == 0)
\r
451 nFilesize = ftell(file);
\r
452 fseek(file, nSavePos, SEEK_SET);
\r
456 void ShrinkDebugFile()
\r
458 // Scroll debug.log if it's getting too big
\r
459 string strFile = GetDataDir() + "/debug.log";
\r
460 FILE* file = fopen(strFile.c_str(), "r");
\r
461 if (file && GetFilesize(file) > 10 * 1000000)
\r
463 // Restart the file with some of the end
\r
465 fseek(file, -sizeof(pch), SEEK_END);
\r
466 int nBytes = fread(pch, 1, sizeof(pch), file);
\r
468 if (file = fopen(strFile.c_str(), "w"))
\r
470 fwrite(pch, 1, nBytes, file);
\r
487 // "Never go to sea with two chronometers; take one or three."
\r
488 // Our three chronometers are:
\r
490 // - Median of other server's clocks
\r
493 // note: NTP isn't implemented yet, so until then we just use the median
\r
494 // of other nodes clocks to correct ours.
\r
501 static int64 nTimeOffset = 0;
\r
503 int64 GetAdjustedTime()
\r
505 return GetTime() + nTimeOffset;
\r
508 void AddTimeData(unsigned int ip, int64 nTime)
\r
510 int64 nOffsetSample = nTime - GetTime();
\r
512 // Ignore duplicates
\r
513 static set<unsigned int> setKnown;
\r
514 if (!setKnown.insert(ip).second)
\r
518 static vector<int64> vTimeOffsets;
\r
519 if (vTimeOffsets.empty())
\r
520 vTimeOffsets.push_back(0);
\r
521 vTimeOffsets.push_back(nOffsetSample);
\r
522 printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
\r
523 if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
\r
525 sort(vTimeOffsets.begin(), vTimeOffsets.end());
\r
526 int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
\r
527 nTimeOffset = nMedian;
\r
528 if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60)
\r
530 // Only let other nodes change our clock so far before we
\r
531 // go to the NTP servers
\r
532 /// todo: Get time from NTP servers, then set a flag
\r
533 /// to make sure it doesn't get changed again
\r
535 foreach(int64 n, vTimeOffsets)
\r
536 printf("%+"PRI64d" ", n);
\r
537 printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
\r