unix build merged in, bitmap resources from xpm instead of rc, better addr relay...
[novacoin.git] / util.cpp
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
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 fPrintToDebugger = false;\r
12 bool fPrintToConsole = false;\r
13 char pszSetDataDir[MAX_PATH] = "";\r
14 \r
15 \r
16 \r
17 \r
18 \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
22 {\r
23     if (mode & CRYPTO_LOCK)\r
24         ppmutexOpenSSL[i]->Lock();\r
25     else\r
26         ppmutexOpenSSL[i]->Unlock();\r
27 }\r
28 \r
29 // Init\r
30 class CInit\r
31 {\r
32 public:\r
33     CInit()\r
34     {\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
40 \r
41 #ifdef __WXMSW__\r
42         // Seed random number generator with screen scrape and other hardware sources\r
43         RAND_screen();\r
44 #endif\r
45 \r
46         // Seed random number generator with performance counter\r
47         RandAddSeed();\r
48     }\r
49     ~CInit()\r
50     {\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
56     }\r
57 }\r
58 instance_of_cinit;\r
59 \r
60 \r
61 \r
62 \r
63 \r
64 \r
65 \r
66 \r
67 void RandAddSeed()\r
68 {\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
73 }\r
74 \r
75 void RandAddSeedPerfmon()\r
76 {\r
77 #ifdef __WXMSW__\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
82         return;\r
83     nLastPerfmon = GetTime();\r
84 \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
92     {\r
93         uint256 hash;\r
94         SHA256(pdata, nSize, (unsigned char*)&hash);\r
95         RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));\r
96         hash = 0;\r
97         memset(pdata, 0, nSize);\r
98 \r
99         time_t nTime;\r
100         time(&nTime);\r
101         struct tm* ptmTime = gmtime(&nTime);\r
102         char pszTime[200];\r
103         strftime(pszTime, sizeof(pszTime), "%x %H:%M:%S", ptmTime);\r
104         printf("%s RandAddSeed() %d bytes\n", pszTime, nSize);\r
105     }\r
106 #endif\r
107 }\r
108 \r
109 \r
110 \r
111 \r
112 \r
113 \r
114 \r
115 \r
116 \r
117 // Safer snprintf\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
122 {\r
123     if (limit == 0)\r
124         return 0;\r
125     va_list arg_ptr;\r
126     va_start(arg_ptr, format);\r
127     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
128     va_end(arg_ptr);\r
129     if (ret < 0 || ret >= limit)\r
130     {\r
131         ret = limit - 1;\r
132         buffer[limit-1] = 0;\r
133     }\r
134     return ret;\r
135 }\r
136 \r
137 \r
138 string strprintf(const char* format, ...)\r
139 {\r
140     char buffer[50000];\r
141     char* p = buffer;\r
142     int limit = sizeof(buffer);\r
143     int ret;\r
144     loop\r
145     {\r
146         va_list arg_ptr;\r
147         va_start(arg_ptr, format);\r
148         ret = _vsnprintf(p, limit, format, arg_ptr);\r
149         va_end(arg_ptr);\r
150         if (ret >= 0 && ret < limit)\r
151             break;\r
152         if (p != buffer)\r
153             delete p;\r
154         limit *= 2;\r
155         p = new char[limit];\r
156         if (p == NULL)\r
157             throw std::bad_alloc();\r
158     }\r
159 #ifdef _MSC_VER\r
160     // msvc optimisation\r
161     if (p == buffer)\r
162         return string(p, p+ret);\r
163 #endif\r
164     string str(p, p+ret);\r
165     if (p != buffer)\r
166         delete p;\r
167     return str;\r
168 }\r
169 \r
170 \r
171 bool error(const char* format, ...)\r
172 {\r
173     char buffer[50000];\r
174     int limit = sizeof(buffer);\r
175     va_list arg_ptr;\r
176     va_start(arg_ptr, format);\r
177     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
178     va_end(arg_ptr);\r
179     if (ret < 0 || ret >= limit)\r
180     {\r
181         ret = limit - 1;\r
182         buffer[limit-1] = 0;\r
183     }\r
184     printf("ERROR: %s\n", buffer);\r
185     return false;\r
186 }\r
187 \r
188 \r
189 void ParseString(const string& str, char c, vector<string>& v)\r
190 {\r
191     unsigned int i1 = 0;\r
192     unsigned int i2;\r
193     do\r
194     {\r
195         i2 = str.find(c, i1);\r
196         v.push_back(str.substr(i1, i2-i1));\r
197         i1 = i2+1;\r
198     }\r
199     while (i2 != str.npos);\r
200 }\r
201 \r
202 \r
203 string FormatMoney(int64 n, bool fPlus)\r
204 {\r
205     n /= CENT;\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
210     if (n < 0)\r
211         str.insert((unsigned int)0, 1, '-');\r
212     else if (fPlus && n > 0)\r
213         str.insert((unsigned int)0, 1, '+');\r
214     return str;\r
215 }\r
216 \r
217 bool ParseMoney(const char* pszIn, int64& nRet)\r
218 {\r
219     string strWhole;\r
220     int64 nCents = 0;\r
221     const char* p = pszIn;\r
222     while (isspace(*p))\r
223         p++;\r
224     for (; *p; p++)\r
225     {\r
226         if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))\r
227             continue;\r
228         if (*p == '.')\r
229         {\r
230             p++;\r
231             if (isdigit(*p))\r
232             {\r
233                 nCents = 10 * (*p++ - '0');\r
234                 if (isdigit(*p))\r
235                     nCents += (*p++ - '0');\r
236             }\r
237             break;\r
238         }\r
239         if (isspace(*p))\r
240             break;\r
241         if (!isdigit(*p))\r
242             return false;\r
243         strWhole.insert(strWhole.end(), *p);\r
244     }\r
245     for (; *p; p++)\r
246         if (!isspace(*p))\r
247             return false;\r
248     if (strWhole.size() > 14)\r
249         return false;\r
250     if (nCents < 0 || nCents > 99)\r
251         return false;\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
256         return false;\r
257     if (nValue / COIN != nWhole)\r
258         return false;\r
259     nRet = nValue;\r
260     return true;\r
261 }\r
262 \r
263 \r
264 vector<unsigned char> ParseHex(const char* psz)\r
265 {\r
266     vector<unsigned char> vch;\r
267     while (isspace(*psz))\r
268         psz++;\r
269     vch.reserve((strlen(psz)+1)/3);\r
270 \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
288 \r
289     while (*psz)\r
290     {\r
291         char c = phexdigit[(unsigned char)*psz++];\r
292         if (c == -1)\r
293             break;\r
294         unsigned char n = (c << 4);\r
295         if (*psz)\r
296         {\r
297             char c = phexdigit[(unsigned char)*psz++];\r
298             if (c == -1)\r
299                 break;\r
300             n |= c;\r
301             vch.push_back(n);\r
302         }\r
303         while (isspace(*psz))\r
304             psz++;\r
305     }\r
306 \r
307     return vch;\r
308 }\r
309 \r
310 vector<unsigned char> ParseHex(const std::string& str)\r
311 {\r
312     return ParseHex(str.c_str());\r
313 }\r
314 \r
315 \r
316 void ParseParameters(int argc, char* argv[])\r
317 {\r
318     mapArgs.clear();\r
319     mapMultiArgs.clear();\r
320     for (int i = 0; i < argc; i++)\r
321     {\r
322         char psz[10000];\r
323         strlcpy(psz, argv[i], sizeof(psz));\r
324         char* pszValue = "";\r
325         if (strchr(psz, '='))\r
326         {\r
327             pszValue = strchr(psz, '=');\r
328             *pszValue++ = '\0';\r
329         }\r
330         #ifdef __WXMSW__\r
331         _strlwr(psz);\r
332         if (psz[0] == '/')\r
333             psz[0] = '-';\r
334         #endif\r
335         mapArgs[psz] = pszValue;\r
336         mapMultiArgs[psz].push_back(pszValue);\r
337     }\r
338 }\r
339 \r
340 \r
341 \r
342 \r
343 \r
344 \r
345 \r
346 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)\r
347 {\r
348 #ifdef __WXMSW__\r
349     char pszModule[MAX_PATH];\r
350     pszModule[0] = '\0';\r
351     GetModuleFileName(NULL, pszModule, sizeof(pszModule));\r
352 #else\r
353     const char* pszModule = wxStandardPaths::Get().GetExecutablePath().mb_str();\r
354 #endif\r
355     if (pex)\r
356         snprintf(pszMessage, 1000,\r
357             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);\r
358     else\r
359         snprintf(pszMessage, 1000,\r
360             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);\r
361 }\r
362 \r
363 void LogException(std::exception* pex, const char* pszThread)\r
364 {\r
365     char pszMessage[1000];\r
366     FormatException(pszMessage, pex, pszThread);\r
367     printf("\n%s", pszMessage);\r
368 }\r
369 \r
370 void PrintException(std::exception* pex, const char* pszThread)\r
371 {\r
372     char pszMessage[1000];\r
373     FormatException(pszMessage, pex, pszThread);\r
374     printf("\n\n************************\n%s\n", pszMessage);\r
375     if (wxTheApp)\r
376         wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);\r
377     throw;\r
378     //DebugBreak();\r
379 }\r
380 \r
381 \r
382 \r
383 \r
384 \r
385 \r
386 \r
387 \r
388 int GetFilesize(FILE* file)\r
389 {\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
395     return nFilesize;\r
396 }\r
397 \r
398 void GetDataDir(char* pszDir)\r
399 {\r
400     // pszDir must be at least MAX_PATH length.\r
401     if (pszSetDataDir[0] != 0)\r
402     {\r
403         strlcpy(pszDir, pszSetDataDir, MAX_PATH);\r
404         static bool fMkdirDone;\r
405         if (!fMkdirDone)\r
406         {\r
407             fMkdirDone = true;\r
408             _mkdir(pszDir);\r
409         }\r
410     }\r
411     else\r
412     {\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
422         {\r
423             strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));\r
424             _mkdir(pszCachedDir);\r
425         }\r
426         strlcpy(pszDir, pszCachedDir, MAX_PATH);\r
427     }\r
428 \r
429 }\r
430 \r
431 string GetDataDir()\r
432 {\r
433     char pszDir[MAX_PATH];\r
434     GetDataDir(pszDir);\r
435     return pszDir;\r
436 }\r
437 \r
438 \r
439 \r
440 \r
441 \r
442 \r
443 \r
444 \r
445 uint64 GetRand(uint64 nMax)\r
446 {\r
447     if (nMax == 0)\r
448         return 0;\r
449 \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
453     uint64 nRand = 0;\r
454     do\r
455         RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
456     while (nRand >= nRange);\r
457     return (nRand % nMax);\r
458 }\r
459 \r
460 \r
461 \r
462 \r
463 \r
464 \r
465 \r
466 \r
467 \r
468 \r
469 //\r
470 // "Never go to sea with two chronometers; take one or three."\r
471 // Our three chronometers are:\r
472 //  - System clock\r
473 //  - Median of other server's clocks\r
474 //  - NTP servers\r
475 //\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
478 //\r
479 \r
480 int64 GetTime()\r
481 {\r
482     return time(NULL);\r
483 }\r
484 \r
485 static int64 nTimeOffset = 0;\r
486 \r
487 int64 GetAdjustedTime()\r
488 {\r
489     return GetTime() + nTimeOffset;\r
490 }\r
491 \r
492 void AddTimeData(unsigned int ip, int64 nTime)\r
493 {\r
494     int64 nOffsetSample = nTime - GetTime();\r
495 \r
496     // Ignore duplicates\r
497     static set<unsigned int> setKnown;\r
498     if (!setKnown.insert(ip).second)\r
499         return;\r
500 \r
501     // Add data\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
508     {\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
513         {\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
518         }\r
519         foreach(int64 n, vTimeOffsets)\r
520             printf("%+"PRI64d"  ", n);\r
521         printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);\r
522     }\r
523 }\r