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
19 // Init openssl library multithreading support
\r
20 static wxMutex** ppmutexOpenSSL;
\r
21 void locking_callback(int mode, int i, const char* file, int line)
\r
23 if (mode & CRYPTO_LOCK)
\r
24 ppmutexOpenSSL[i]->Lock();
\r
26 ppmutexOpenSSL[i]->Unlock();
\r
35 // Init openssl library multithreading support
\r
36 ppmutexOpenSSL = (wxMutex**)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(wxMutex*));
\r
37 for (int i = 0; i < CRYPTO_num_locks(); i++)
\r
38 ppmutexOpenSSL[i] = new wxMutex();
\r
39 CRYPTO_set_locking_callback(locking_callback);
\r
42 // Seed random number generator with screen scrape and other hardware sources
\r
46 // Seed random number generator with performance counter
\r
51 // Shutdown openssl library multithreading support
\r
52 CRYPTO_set_locking_callback(NULL);
\r
53 for (int i = 0; i < CRYPTO_num_locks(); i++)
\r
54 delete ppmutexOpenSSL[i];
\r
55 OPENSSL_free(ppmutexOpenSSL);
\r
69 // Seed with CPU performance counter
\r
70 int64 nCounter = PerformanceCounter();
\r
71 RAND_add(&nCounter, sizeof(nCounter), 1.5);
\r
72 memset(&nCounter, 0, sizeof(nCounter));
\r
75 void RandAddSeedPerfmon()
\r
78 // Don't need this on Linux, OpenSSL automatically uses /dev/urandom
\r
79 // This can take up to 2 seconds, so only do it every 10 minutes
\r
80 static int64 nLastPerfmon;
\r
81 if (GetTime() < nLastPerfmon + 10 * 60)
\r
83 nLastPerfmon = GetTime();
\r
85 // Seed with the entire set of perfmon data
\r
86 unsigned char pdata[250000];
\r
87 memset(pdata, 0, sizeof(pdata));
\r
88 unsigned long nSize = sizeof(pdata);
\r
89 long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);
\r
90 RegCloseKey(HKEY_PERFORMANCE_DATA);
\r
91 if (ret == ERROR_SUCCESS)
\r
94 SHA256(pdata, nSize, (unsigned char*)&hash);
\r
95 RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));
\r
97 memset(pdata, 0, nSize);
\r
101 struct tm* ptmTime = gmtime(&nTime);
\r
103 strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime);
\r
104 printf("%s RandAddSeed() %d bytes\n", pszTime, nSize);
\r
118 // - prints up to limit-1 characters
\r
119 // - output string is always null terminated even if limit reached
\r
120 // - return value is the number of characters actually printed
\r
121 int my_snprintf(char* buffer, size_t limit, const char* format, ...)
\r
126 va_start(arg_ptr, format);
\r
127 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
\r
129 if (ret < 0 || ret >= limit)
\r
132 buffer[limit-1] = 0;
\r
138 string strprintf(const char* format, ...)
\r
140 char buffer[50000];
\r
142 int limit = sizeof(buffer);
\r
147 va_start(arg_ptr, format);
\r
148 ret = _vsnprintf(p, limit, format, arg_ptr);
\r
150 if (ret >= 0 && ret < limit)
\r
155 p = new char[limit];
\r
157 throw std::bad_alloc();
\r
160 // msvc optimisation
\r
162 return string(p, p+ret);
\r
164 string str(p, p+ret);
\r
171 bool error(const char* format, ...)
\r
173 char buffer[50000];
\r
174 int limit = sizeof(buffer);
\r
176 va_start(arg_ptr, format);
\r
177 int ret = _vsnprintf(buffer, limit, format, arg_ptr);
\r
179 if (ret < 0 || ret >= limit)
\r
182 buffer[limit-1] = 0;
\r
184 printf("ERROR: %s\n", buffer);
\r
189 void ParseString(const string& str, char c, vector<string>& v)
\r
191 unsigned int i1 = 0;
\r
195 i2 = str.find(c, i1);
\r
196 v.push_back(str.substr(i1, i2-i1));
\r
199 while (i2 != str.npos);
\r
203 string FormatMoney(int64 n, bool fPlus)
\r
206 string str = strprintf("%"PRI64d".%02"PRI64d, (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);
\r
207 for (int i = 6; i < str.size(); i += 4)
\r
208 if (isdigit(str[str.size() - i - 1]))
\r
209 str.insert(str.size() - i, 1, ',');
\r
211 str.insert((unsigned int)0, 1, '-');
\r
212 else if (fPlus && n > 0)
\r
213 str.insert((unsigned int)0, 1, '+');
\r
217 bool ParseMoney(const char* pszIn, int64& nRet)
\r
221 const char* p = pszIn;
\r
222 while (isspace(*p))
\r
226 if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))
\r
233 nCents = 10 * (*p++ - '0');
\r
235 nCents += (*p++ - '0');
\r
243 strWhole.insert(strWhole.end(), *p);
\r
248 if (strWhole.size() > 14)
\r
250 if (nCents < 0 || nCents > 99)
\r
252 int64 nWhole = atoi64(strWhole);
\r
253 int64 nPreValue = nWhole * 100 + nCents;
\r
254 int64 nValue = nPreValue * CENT;
\r
255 if (nValue / CENT != nPreValue)
\r
257 if (nValue / COIN != nWhole)
\r
264 vector<unsigned char> ParseHex(const char* psz)
\r
266 vector<unsigned char> vch;
\r
267 while (isspace(*psz))
\r
269 vch.reserve((strlen(psz)+1)/3);
\r
271 static char phexdigit[256] =
\r
272 { -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
273 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
274 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
275 0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,
\r
276 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
277 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
278 -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1
\r
279 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
280 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
281 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
282 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
283 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
284 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
285 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
286 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
\r
287 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };
\r
291 char c = phexdigit[(unsigned char)*psz++];
\r
294 unsigned char n = (c << 4);
\r
297 char c = phexdigit[(unsigned char)*psz++];
\r
303 while (isspace(*psz))
\r
310 vector<unsigned char> ParseHex(const std::string& str)
\r
312 return ParseHex(str.c_str());
\r
316 void ParseParameters(int argc, char* argv[])
\r
319 mapMultiArgs.clear();
\r
320 for (int i = 0; i < argc; i++)
\r
323 strlcpy(psz, argv[i], sizeof(psz));
\r
324 char* pszValue = "";
\r
325 if (strchr(psz, '='))
\r
327 pszValue = strchr(psz, '=');
\r
328 *pszValue++ = '\0';
\r
335 mapArgs[psz] = pszValue;
\r
336 mapMultiArgs[psz].push_back(pszValue);
\r
346 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)
\r
349 char pszModule[MAX_PATH];
\r
350 pszModule[0] = '\0';
\r
351 GetModuleFileName(NULL, pszModule, sizeof(pszModule));
\r
353 const char* pszModule = wxStandardPaths::Get().GetExecutablePath().mb_str();
\r
356 snprintf(pszMessage, 1000,
\r
357 "EXCEPTION: %s \n%s \n%s in %s \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);
\r
359 snprintf(pszMessage, 1000,
\r
360 "UNKNOWN EXCEPTION \n%s in %s \n", pszModule, pszThread);
\r
363 void LogException(std::exception* pex, const char* pszThread)
\r
365 char pszMessage[1000];
\r
366 FormatException(pszMessage, pex, pszThread);
\r
367 printf("\n%s", pszMessage);
\r
370 void PrintException(std::exception* pex, const char* pszThread)
\r
372 char pszMessage[1000];
\r
373 FormatException(pszMessage, pex, pszThread);
\r
374 printf("\n\n************************\n%s\n", pszMessage);
\r
376 wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);
\r
388 int GetFilesize(FILE* file)
\r
390 int nSavePos = ftell(file);
\r
391 int nFilesize = -1;
\r
392 if (fseek(file, 0, SEEK_END) == 0)
\r
393 nFilesize = ftell(file);
\r
394 fseek(file, nSavePos, SEEK_SET);
\r
398 void GetDataDir(char* pszDir)
\r
400 // pszDir must be at least MAX_PATH length.
\r
401 if (pszSetDataDir[0] != 0)
\r
403 strlcpy(pszDir, pszSetDataDir, MAX_PATH);
\r
404 static bool fMkdirDone;
\r
413 // This can be called during exceptions by printf, so we cache the
\r
414 // value so we don't have to do memory allocations after that.
\r
415 // wxStandardPaths::GetUserDataDir
\r
416 // Return the directory for the user-dependent application data files:
\r
417 // Unix: ~/.appname
\r
418 // Windows: C:\Documents and Settings\username\Application Data\appname
\r
419 // Mac: ~/Library/Application Support/appname
\r
420 static char pszCachedDir[MAX_PATH];
\r
421 if (pszCachedDir[0] == 0)
\r
423 strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));
\r
424 _mkdir(pszCachedDir);
\r
426 strlcpy(pszDir, pszCachedDir, MAX_PATH);
\r
431 string GetDataDir()
\r
433 char pszDir[MAX_PATH];
\r
434 GetDataDir(pszDir);
\r
445 uint64 GetRand(uint64 nMax)
\r
450 // The range of the random source must be a multiple of the modulus
\r
451 // to give every possible output value an equal possibility
\r
452 uint64 nRange = (_UI64_MAX / nMax) * nMax;
\r
455 RAND_bytes((unsigned char*)&nRand, sizeof(nRand));
\r
456 while (nRand >= nRange);
\r
457 return (nRand % nMax);
\r
470 // "Never go to sea with two chronometers; take one or three."
\r
471 // Our three chronometers are:
\r
473 // - Median of other server's clocks
\r
476 // note: NTP isn't implemented yet, so until then we just use the median
\r
477 // of other nodes clocks to correct ours.
\r
485 static int64 nTimeOffset = 0;
\r
487 int64 GetAdjustedTime()
\r
489 return GetTime() + nTimeOffset;
\r
492 void AddTimeData(unsigned int ip, int64 nTime)
\r
494 int64 nOffsetSample = nTime - GetTime();
\r
496 // Ignore duplicates
\r
497 static set<unsigned int> setKnown;
\r
498 if (!setKnown.insert(ip).second)
\r
502 static vector<int64> vTimeOffsets;
\r
503 if (vTimeOffsets.empty())
\r
504 vTimeOffsets.push_back(0);
\r
505 vTimeOffsets.push_back(nOffsetSample);
\r
506 printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);
\r
507 if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)
\r
509 sort(vTimeOffsets.begin(), vTimeOffsets.end());
\r
510 int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];
\r
511 nTimeOffset = nMedian;
\r
512 if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60)
\r
514 // Only let other nodes change our clock so far before we
\r
515 // go to the NTP servers
\r
516 /// todo: Get time from NTP servers, then set a flag
\r
517 /// to make sure it doesn't get changed again
\r
519 foreach(int64 n, vTimeOffsets)
\r
520 printf("%+"PRI64d" ", n);
\r
521 printf("| nTimeOffset = %+"PRI64d" (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);
\r