retry IRC if name in use,
[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 bool fShutdown = false;\r
15 \r
16 \r
17 \r
18 \r
19 \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
23 {\r
24     if (mode & CRYPTO_LOCK)\r
25         ppmutexOpenSSL[i]->Lock();\r
26     else\r
27         ppmutexOpenSSL[i]->Unlock();\r
28 }\r
29 \r
30 // Init\r
31 class CInit\r
32 {\r
33 public:\r
34     CInit()\r
35     {\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
41 \r
42 #ifdef __WXMSW__\r
43         // Seed random number generator with screen scrape and other hardware sources\r
44         RAND_screen();\r
45 #endif\r
46 \r
47         // Seed random number generator with performance counter\r
48         RandAddSeed();\r
49     }\r
50     ~CInit()\r
51     {\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
57     }\r
58 }\r
59 instance_of_cinit;\r
60 \r
61 \r
62 \r
63 \r
64 \r
65 \r
66 \r
67 \r
68 void RandAddSeed()\r
69 {\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
74 }\r
75 \r
76 void RandAddSeedPerfmon()\r
77 {\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
81         return;\r
82     nLastPerfmon = GetTime();\r
83 \r
84 #ifdef __WXMSW__\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
93     {\r
94         uint256 hash;\r
95         SHA256(pdata, nSize, (unsigned char*)&hash);\r
96         RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));\r
97         hash = 0;\r
98         memset(pdata, 0, nSize);\r
99 \r
100         printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);\r
101     }\r
102 #else\r
103     printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
104 #endif\r
105 }\r
106 \r
107 uint64 GetRand(uint64 nMax)\r
108 {\r
109     if (nMax == 0)\r
110         return 0;\r
111 \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
115     uint64 nRand = 0;\r
116     do\r
117         RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
118     while (nRand >= nRange);\r
119     return (nRand % nMax);\r
120 }\r
121 \r
122 \r
123 \r
124 \r
125 \r
126 \r
127 \r
128 \r
129 \r
130 \r
131 \r
132 \r
133 \r
134 // Safer snprintf\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
139 {\r
140     if (limit == 0)\r
141         return 0;\r
142     va_list arg_ptr;\r
143     va_start(arg_ptr, format);\r
144     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
145     va_end(arg_ptr);\r
146     if (ret < 0 || ret >= limit)\r
147     {\r
148         ret = limit - 1;\r
149         buffer[limit-1] = 0;\r
150     }\r
151     return ret;\r
152 }\r
153 \r
154 \r
155 string strprintf(const char* format, ...)\r
156 {\r
157     char buffer[50000];\r
158     char* p = buffer;\r
159     int limit = sizeof(buffer);\r
160     int ret;\r
161     loop\r
162     {\r
163         va_list arg_ptr;\r
164         va_start(arg_ptr, format);\r
165         ret = _vsnprintf(p, limit, format, arg_ptr);\r
166         va_end(arg_ptr);\r
167         if (ret >= 0 && ret < limit)\r
168             break;\r
169         if (p != buffer)\r
170             delete p;\r
171         limit *= 2;\r
172         p = new char[limit];\r
173         if (p == NULL)\r
174             throw std::bad_alloc();\r
175     }\r
176 #ifdef _MSC_VER\r
177     // msvc optimisation\r
178     if (p == buffer)\r
179         return string(p, p+ret);\r
180 #endif\r
181     string str(p, p+ret);\r
182     if (p != buffer)\r
183         delete p;\r
184     return str;\r
185 }\r
186 \r
187 \r
188 bool error(const char* format, ...)\r
189 {\r
190     char buffer[50000];\r
191     int limit = sizeof(buffer);\r
192     va_list arg_ptr;\r
193     va_start(arg_ptr, format);\r
194     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
195     va_end(arg_ptr);\r
196     if (ret < 0 || ret >= limit)\r
197     {\r
198         ret = limit - 1;\r
199         buffer[limit-1] = 0;\r
200     }\r
201     printf("ERROR: %s\n", buffer);\r
202     return false;\r
203 }\r
204 \r
205 \r
206 void ParseString(const string& str, char c, vector<string>& v)\r
207 {\r
208     unsigned int i1 = 0;\r
209     unsigned int i2;\r
210     do\r
211     {\r
212         i2 = str.find(c, i1);\r
213         v.push_back(str.substr(i1, i2-i1));\r
214         i1 = i2+1;\r
215     }\r
216     while (i2 != str.npos);\r
217 }\r
218 \r
219 \r
220 string FormatMoney(int64 n, bool fPlus)\r
221 {\r
222     n /= CENT;\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
227     if (n < 0)\r
228         str.insert((unsigned int)0, 1, '-');\r
229     else if (fPlus && n > 0)\r
230         str.insert((unsigned int)0, 1, '+');\r
231     return str;\r
232 }\r
233 \r
234 bool ParseMoney(const char* pszIn, int64& nRet)\r
235 {\r
236     string strWhole;\r
237     int64 nCents = 0;\r
238     const char* p = pszIn;\r
239     while (isspace(*p))\r
240         p++;\r
241     for (; *p; p++)\r
242     {\r
243         if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))\r
244             continue;\r
245         if (*p == '.')\r
246         {\r
247             p++;\r
248             if (isdigit(*p))\r
249             {\r
250                 nCents = 10 * (*p++ - '0');\r
251                 if (isdigit(*p))\r
252                     nCents += (*p++ - '0');\r
253             }\r
254             break;\r
255         }\r
256         if (isspace(*p))\r
257             break;\r
258         if (!isdigit(*p))\r
259             return false;\r
260         strWhole.insert(strWhole.end(), *p);\r
261     }\r
262     for (; *p; p++)\r
263         if (!isspace(*p))\r
264             return false;\r
265     if (strWhole.size() > 14)\r
266         return false;\r
267     if (nCents < 0 || nCents > 99)\r
268         return false;\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
273         return false;\r
274     if (nValue / COIN != nWhole)\r
275         return false;\r
276     nRet = nValue;\r
277     return true;\r
278 }\r
279 \r
280 \r
281 vector<unsigned char> ParseHex(const char* psz)\r
282 {\r
283     vector<unsigned char> vch;\r
284     while (isspace(*psz))\r
285         psz++;\r
286     vch.reserve((strlen(psz)+1)/3);\r
287 \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
305 \r
306     while (*psz)\r
307     {\r
308         char c = phexdigit[(unsigned char)*psz++];\r
309         if (c == -1)\r
310             break;\r
311         unsigned char n = (c << 4);\r
312         if (*psz)\r
313         {\r
314             char c = phexdigit[(unsigned char)*psz++];\r
315             if (c == -1)\r
316                 break;\r
317             n |= c;\r
318             vch.push_back(n);\r
319         }\r
320         while (isspace(*psz))\r
321             psz++;\r
322     }\r
323 \r
324     return vch;\r
325 }\r
326 \r
327 vector<unsigned char> ParseHex(const std::string& str)\r
328 {\r
329     return ParseHex(str.c_str());\r
330 }\r
331 \r
332 \r
333 void ParseParameters(int argc, char* argv[])\r
334 {\r
335     mapArgs.clear();\r
336     mapMultiArgs.clear();\r
337     for (int i = 0; i < argc; i++)\r
338     {\r
339         char psz[10000];\r
340         strlcpy(psz, argv[i], sizeof(psz));\r
341         char* pszValue = (char*)"";\r
342         if (strchr(psz, '='))\r
343         {\r
344             pszValue = strchr(psz, '=');\r
345             *pszValue++ = '\0';\r
346         }\r
347         #ifdef __WXMSW__\r
348         _strlwr(psz);\r
349         if (psz[0] == '/')\r
350             psz[0] = '-';\r
351         #endif\r
352         mapArgs[psz] = pszValue;\r
353         mapMultiArgs[psz].push_back(pszValue);\r
354     }\r
355 }\r
356 \r
357 \r
358 \r
359 \r
360 \r
361 \r
362 \r
363 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)\r
364 {\r
365 #ifdef __WXMSW__\r
366     char pszModule[MAX_PATH];\r
367     pszModule[0] = '\0';\r
368     GetModuleFileName(NULL, pszModule, sizeof(pszModule));\r
369 #else\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
373 #endif\r
374     if (pex)\r
375         snprintf(pszMessage, 1000,\r
376             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);\r
377     else\r
378         snprintf(pszMessage, 1000,\r
379             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);\r
380 }\r
381 \r
382 void LogException(std::exception* pex, const char* pszThread)\r
383 {\r
384     char pszMessage[1000];\r
385     FormatException(pszMessage, pex, pszThread);\r
386     printf("\n%s", pszMessage);\r
387 }\r
388 \r
389 void PrintException(std::exception* pex, const char* pszThread)\r
390 {\r
391     char pszMessage[1000];\r
392     FormatException(pszMessage, pex, pszThread);\r
393     printf("\n\n************************\n%s\n", pszMessage);\r
394     if (wxTheApp)\r
395         wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);\r
396     throw;\r
397     //DebugBreak();\r
398 }\r
399 \r
400 \r
401 \r
402 \r
403 \r
404 \r
405 \r
406 \r
407 void GetDataDir(char* pszDir)\r
408 {\r
409     // pszDir must be at least MAX_PATH length.\r
410     if (pszSetDataDir[0] != 0)\r
411     {\r
412         strlcpy(pszDir, pszSetDataDir, MAX_PATH);\r
413         static bool fMkdirDone;\r
414         if (!fMkdirDone)\r
415         {\r
416             fMkdirDone = true;\r
417             _mkdir(pszDir);\r
418         }\r
419     }\r
420     else\r
421     {\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
431         {\r
432             strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));\r
433             _mkdir(pszCachedDir);\r
434         }\r
435         strlcpy(pszDir, pszCachedDir, MAX_PATH);\r
436     }\r
437 }\r
438 \r
439 string GetDataDir()\r
440 {\r
441     char pszDir[MAX_PATH];\r
442     GetDataDir(pszDir);\r
443     return pszDir;\r
444 }\r
445 \r
446 int GetFilesize(FILE* file)\r
447 {\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
453     return nFilesize;\r
454 }\r
455 \r
456 void ShrinkDebugFile()\r
457 {\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
462     {\r
463         // Restart the file with some of the end\r
464         char pch[200000];\r
465         fseek(file, -sizeof(pch), SEEK_END);\r
466         int nBytes = fread(pch, 1, sizeof(pch), file);\r
467         fclose(file);\r
468         if (file = fopen(strFile.c_str(), "w"))\r
469         {\r
470             fwrite(pch, 1, nBytes, file);\r
471             fclose(file);\r
472         }\r
473     }\r
474 }\r
475 \r
476 \r
477 \r
478 \r
479 \r
480 \r
481 \r
482 \r
483 \r
484 \r
485 \r
486 //\r
487 // "Never go to sea with two chronometers; take one or three."\r
488 // Our three chronometers are:\r
489 //  - System clock\r
490 //  - Median of other server's clocks\r
491 //  - NTP servers\r
492 //\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
495 //\r
496 int64 GetTime()\r
497 {\r
498     return time(NULL);\r
499 }\r
500 \r
501 static int64 nTimeOffset = 0;\r
502 \r
503 int64 GetAdjustedTime()\r
504 {\r
505     return GetTime() + nTimeOffset;\r
506 }\r
507 \r
508 void AddTimeData(unsigned int ip, int64 nTime)\r
509 {\r
510     int64 nOffsetSample = nTime - GetTime();\r
511 \r
512     // Ignore duplicates\r
513     static set<unsigned int> setKnown;\r
514     if (!setKnown.insert(ip).second)\r
515         return;\r
516 \r
517     // Add data\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
524     {\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
529         {\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
534         }\r
535         foreach(int64 n, vTimeOffsets)\r
536             printf("%+"PRI64d"  ", n);\r
537         printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);\r
538     }\r
539 }\r