all builds are now with wxWidgets-2.9.0, we are now using UTF-8,
[novacoin.git] / util.cpp
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
4 \r
5 #include "headers.h"\r
6 \r
7 \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
16 \r
17 \r
18 \r
19 \r
20 \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
24 {\r
25     if (mode & CRYPTO_LOCK)\r
26         ppmutexOpenSSL[i]->Lock();\r
27     else\r
28         ppmutexOpenSSL[i]->Unlock();\r
29 }\r
30 \r
31 // Init\r
32 class CInit\r
33 {\r
34 public:\r
35     CInit()\r
36     {\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
42 \r
43 #ifdef __WXMSW__\r
44         // Seed random number generator with screen scrape and other hardware sources\r
45         RAND_screen();\r
46 #endif\r
47 \r
48         // Seed random number generator with performance counter\r
49         RandAddSeed();\r
50     }\r
51     ~CInit()\r
52     {\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
58     }\r
59 }\r
60 instance_of_cinit;\r
61 \r
62 \r
63 \r
64 \r
65 \r
66 \r
67 \r
68 \r
69 void RandAddSeed()\r
70 {\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
75 }\r
76 \r
77 void RandAddSeedPerfmon()\r
78 {\r
79     RandAddSeed();\r
80 \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
84         return;\r
85     nLastPerfmon = GetTime();\r
86 \r
87 #ifdef __WXMSW__\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
96     {\r
97         uint256 hash;\r
98         SHA256(pdata, nSize, (unsigned char*)&hash);\r
99         RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));\r
100         hash = 0;\r
101         memset(pdata, 0, nSize);\r
102 \r
103         printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);\r
104     }\r
105 #else\r
106     printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
107 #endif\r
108 }\r
109 \r
110 uint64 GetRand(uint64 nMax)\r
111 {\r
112     if (nMax == 0)\r
113         return 0;\r
114 \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
118     uint64 nRand = 0;\r
119     do\r
120         RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
121     while (nRand >= nRange);\r
122     return (nRand % nMax);\r
123 }\r
124 \r
125 \r
126 \r
127 \r
128 \r
129 \r
130 \r
131 \r
132 \r
133 \r
134 \r
135 inline int OutputDebugStringF(const char* pszFormat, ...)\r
136 {\r
137     int ret = 0;\r
138     if (fPrintToConsole || wxTheApp == NULL)\r
139     {\r
140         // print to console\r
141         va_list arg_ptr;\r
142         va_start(arg_ptr, pszFormat);\r
143         ret = vprintf(pszFormat, arg_ptr);\r
144         va_end(arg_ptr);\r
145     }\r
146     else\r
147     {\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
153         if (fileout)\r
154         {\r
155             //// Debug print useful for profiling\r
156             //fprintf(fileout, " %"PRI64d" ", wxGetLocalTimeMillis().GetValue());\r
157             va_list arg_ptr;\r
158             va_start(arg_ptr, pszFormat);\r
159             ret = vfprintf(fileout, pszFormat, arg_ptr);\r
160             va_end(arg_ptr);\r
161             fclose(fileout);\r
162         }\r
163     }\r
164 \r
165 #ifdef __WXMSW__\r
166     if (fPrintToDebugger)\r
167     {\r
168         // accumulate a line at a time\r
169         static CCriticalSection cs_OutputDebugStringF;\r
170         CRITICAL_BLOCK(cs_OutputDebugStringF)\r
171         {\r
172             static char pszBuffer[50000];\r
173             static char* pend;\r
174             if (pend == NULL)\r
175                 pend = pszBuffer;\r
176             va_list arg_ptr;\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
180             va_end(arg_ptr);\r
181             if (ret < 0 || ret >= limit)\r
182             {\r
183                 pend = END(pszBuffer) - 2;\r
184                 *pend++ = '\n';\r
185             }\r
186             else\r
187                 pend += ret;\r
188             *pend = '\0';\r
189             char* p1 = pszBuffer;\r
190             char* p2;\r
191             while (p2 = strchr(p1, '\n'))\r
192             {\r
193                 p2++;\r
194                 char c = *p2;\r
195                 *p2 = '\0';\r
196                 OutputDebugStringA(p1);\r
197                 *p2 = c;\r
198                 p1 = p2;\r
199             }\r
200             if (p1 != pszBuffer)\r
201                 memmove(pszBuffer, p1, pend - p1 + 1);\r
202             pend -= (p1 - pszBuffer);\r
203         }\r
204     }\r
205 #endif\r
206     return ret;\r
207 }\r
208 \r
209 \r
210 // Safer snprintf\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
215 {\r
216     if (limit == 0)\r
217         return 0;\r
218     va_list arg_ptr;\r
219     va_start(arg_ptr, format);\r
220     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
221     va_end(arg_ptr);\r
222     if (ret < 0 || ret >= limit)\r
223     {\r
224         ret = limit - 1;\r
225         buffer[limit-1] = 0;\r
226     }\r
227     return ret;\r
228 }\r
229 \r
230 \r
231 string strprintf(const char* format, ...)\r
232 {\r
233     char buffer[50000];\r
234     char* p = buffer;\r
235     int limit = sizeof(buffer);\r
236     int ret;\r
237     loop\r
238     {\r
239         va_list arg_ptr;\r
240         va_start(arg_ptr, format);\r
241         ret = _vsnprintf(p, limit, format, arg_ptr);\r
242         va_end(arg_ptr);\r
243         if (ret >= 0 && ret < limit)\r
244             break;\r
245         if (p != buffer)\r
246             delete p;\r
247         limit *= 2;\r
248         p = new char[limit];\r
249         if (p == NULL)\r
250             throw std::bad_alloc();\r
251     }\r
252 #ifdef _MSC_VER\r
253     // msvc optimisation\r
254     if (p == buffer)\r
255         return string(p, p+ret);\r
256 #endif\r
257     string str(p, p+ret);\r
258     if (p != buffer)\r
259         delete p;\r
260     return str;\r
261 }\r
262 \r
263 \r
264 bool error(const char* format, ...)\r
265 {\r
266     char buffer[50000];\r
267     int limit = sizeof(buffer);\r
268     va_list arg_ptr;\r
269     va_start(arg_ptr, format);\r
270     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
271     va_end(arg_ptr);\r
272     if (ret < 0 || ret >= limit)\r
273     {\r
274         ret = limit - 1;\r
275         buffer[limit-1] = 0;\r
276     }\r
277     printf("ERROR: %s\n", buffer);\r
278     return false;\r
279 }\r
280 \r
281 \r
282 void ParseString(const string& str, char c, vector<string>& v)\r
283 {\r
284     unsigned int i1 = 0;\r
285     unsigned int i2;\r
286     do\r
287     {\r
288         i2 = str.find(c, i1);\r
289         v.push_back(str.substr(i1, i2-i1));\r
290         i1 = i2+1;\r
291     }\r
292     while (i2 != str.npos);\r
293 }\r
294 \r
295 \r
296 string FormatMoney(int64 n, bool fPlus)\r
297 {\r
298     n /= CENT;\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
303     if (n < 0)\r
304         str.insert((unsigned int)0, 1, '-');\r
305     else if (fPlus && n > 0)\r
306         str.insert((unsigned int)0, 1, '+');\r
307     return str;\r
308 }\r
309 \r
310 bool ParseMoney(const char* pszIn, int64& nRet)\r
311 {\r
312     string strWhole;\r
313     int64 nCents = 0;\r
314     const char* p = pszIn;\r
315     while (isspace(*p))\r
316         p++;\r
317     for (; *p; p++)\r
318     {\r
319         if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))\r
320             continue;\r
321         if (*p == '.')\r
322         {\r
323             p++;\r
324             if (isdigit(*p))\r
325             {\r
326                 nCents = 10 * (*p++ - '0');\r
327                 if (isdigit(*p))\r
328                     nCents += (*p++ - '0');\r
329             }\r
330             break;\r
331         }\r
332         if (isspace(*p))\r
333             break;\r
334         if (!isdigit(*p))\r
335             return false;\r
336         strWhole.insert(strWhole.end(), *p);\r
337     }\r
338     for (; *p; p++)\r
339         if (!isspace(*p))\r
340             return false;\r
341     if (strWhole.size() > 14)\r
342         return false;\r
343     if (nCents < 0 || nCents > 99)\r
344         return false;\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
349         return false;\r
350     if (nValue / COIN != nWhole)\r
351         return false;\r
352     nRet = nValue;\r
353     return true;\r
354 }\r
355 \r
356 \r
357 vector<unsigned char> ParseHex(const char* psz)\r
358 {\r
359     vector<unsigned char> vch;\r
360     while (isspace(*psz))\r
361         psz++;\r
362     vch.reserve((strlen(psz)+1)/3);\r
363 \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
381 \r
382     while (*psz)\r
383     {\r
384         char c = phexdigit[(unsigned char)*psz++];\r
385         if (c == -1)\r
386             break;\r
387         unsigned char n = (c << 4);\r
388         if (*psz)\r
389         {\r
390             char c = phexdigit[(unsigned char)*psz++];\r
391             if (c == -1)\r
392                 break;\r
393             n |= c;\r
394             vch.push_back(n);\r
395         }\r
396         while (isspace(*psz))\r
397             psz++;\r
398     }\r
399 \r
400     return vch;\r
401 }\r
402 \r
403 vector<unsigned char> ParseHex(const std::string& str)\r
404 {\r
405     return ParseHex(str.c_str());\r
406 }\r
407 \r
408 \r
409 void ParseParameters(int argc, char* argv[])\r
410 {\r
411     mapArgs.clear();\r
412     mapMultiArgs.clear();\r
413     for (int i = 0; i < argc; i++)\r
414     {\r
415         char psz[10000];\r
416         strlcpy(psz, argv[i], sizeof(psz));\r
417         char* pszValue = (char*)"";\r
418         if (strchr(psz, '='))\r
419         {\r
420             pszValue = strchr(psz, '=');\r
421             *pszValue++ = '\0';\r
422         }\r
423         #ifdef __WXMSW__\r
424         _strlwr(psz);\r
425         if (psz[0] == '/')\r
426             psz[0] = '-';\r
427         #endif\r
428         mapArgs[psz] = pszValue;\r
429         mapMultiArgs[psz].push_back(pszValue);\r
430     }\r
431 }\r
432 \r
433 \r
434 \r
435 \r
436 \r
437 \r
438 \r
439 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)\r
440 {\r
441 #ifdef __WXMSW__\r
442     char pszModule[MAX_PATH];\r
443     pszModule[0] = '\0';\r
444     GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));\r
445 #else\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
449 #endif\r
450     if (pex)\r
451         snprintf(pszMessage, 1000,\r
452             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);\r
453     else\r
454         snprintf(pszMessage, 1000,\r
455             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);\r
456 }\r
457 \r
458 void LogException(std::exception* pex, const char* pszThread)\r
459 {\r
460     char pszMessage[1000];\r
461     FormatException(pszMessage, pex, pszThread);\r
462     printf("\n%s", pszMessage);\r
463 }\r
464 \r
465 void PrintException(std::exception* pex, const char* pszThread)\r
466 {\r
467     char pszMessage[1000];\r
468     FormatException(pszMessage, pex, pszThread);\r
469     printf("\n\n************************\n%s\n", pszMessage);\r
470     if (wxTheApp)\r
471         wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);\r
472     throw;\r
473     //DebugBreak();\r
474 }\r
475 \r
476 \r
477 \r
478 \r
479 \r
480 \r
481 \r
482 \r
483 void GetDataDir(char* pszDir)\r
484 {\r
485     // pszDir must be at least MAX_PATH length.\r
486     if (pszSetDataDir[0] != 0)\r
487     {\r
488         strlcpy(pszDir, pszSetDataDir, MAX_PATH);\r
489         static bool fMkdirDone;\r
490         if (!fMkdirDone)\r
491         {\r
492             fMkdirDone = true;\r
493             _mkdir(pszDir);\r
494         }\r
495     }\r
496     else\r
497     {\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
507         {\r
508             strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));\r
509             _mkdir(pszCachedDir);\r
510         }\r
511         strlcpy(pszDir, pszCachedDir, MAX_PATH);\r
512     }\r
513 }\r
514 \r
515 string GetDataDir()\r
516 {\r
517     char pszDir[MAX_PATH];\r
518     GetDataDir(pszDir);\r
519     return pszDir;\r
520 }\r
521 \r
522 int GetFilesize(FILE* file)\r
523 {\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
529     return nFilesize;\r
530 }\r
531 \r
532 void ShrinkDebugFile()\r
533 {\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
538     {\r
539         // Restart the file with some of the end\r
540         char pch[200000];\r
541         fseek(file, -sizeof(pch), SEEK_END);\r
542         int nBytes = fread(pch, 1, sizeof(pch), file);\r
543         fclose(file);\r
544         if (file = fopen(strFile.c_str(), "w"))\r
545         {\r
546             fwrite(pch, 1, nBytes, file);\r
547             fclose(file);\r
548         }\r
549     }\r
550 }\r
551 \r
552 \r
553 \r
554 \r
555 \r
556 \r
557 \r
558 \r
559 \r
560 \r
561 \r
562 //\r
563 // "Never go to sea with two chronometers; take one or three."\r
564 // Our three chronometers are:\r
565 //  - System clock\r
566 //  - Median of other server's clocks\r
567 //  - NTP servers\r
568 //\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
571 //\r
572 int64 GetTime()\r
573 {\r
574     return time(NULL);\r
575 }\r
576 \r
577 static int64 nTimeOffset = 0;\r
578 \r
579 int64 GetAdjustedTime()\r
580 {\r
581     return GetTime() + nTimeOffset;\r
582 }\r
583 \r
584 void AddTimeData(unsigned int ip, int64 nTime)\r
585 {\r
586     int64 nOffsetSample = nTime - GetTime();\r
587 \r
588     // Ignore duplicates\r
589     static set<unsigned int> setKnown;\r
590     if (!setKnown.insert(ip).second)\r
591         return;\r
592 \r
593     // Add data\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
600     {\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
605         {\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
610         }\r
611         foreach(int64 n, vTimeOffsets)\r
612             printf("%+"PRI64d"  ", n);\r
613         printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);\r
614     }\r
615 }\r