bugfix Db::open/close and zombie sockets bugs fix double-close of socket handle,
[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         // Close sockets\r
58         foreach(CNode* pnode, vNodes)\r
59             if (pnode->hSocket != INVALID_SOCKET)\r
60                 closesocket(pnode->hSocket);\r
61         if (hListenSocket != INVALID_SOCKET)\r
62             if (closesocket(hListenSocket) == SOCKET_ERROR)\r
63                 printf("closesocket(hListenSocket) failed with error %d\n", WSAGetLastError());\r
64 \r
65 #ifdef __WXMSW__\r
66         // Shutdown Windows Sockets\r
67         WSACleanup();\r
68 #endif\r
69     }\r
70 }\r
71 instance_of_cinit;\r
72 \r
73 \r
74 \r
75 \r
76 \r
77 \r
78 \r
79 \r
80 void RandAddSeed()\r
81 {\r
82     // Seed with CPU performance counter\r
83     int64 nCounter = PerformanceCounter();\r
84     RAND_add(&nCounter, sizeof(nCounter), 1.5);\r
85     memset(&nCounter, 0, sizeof(nCounter));\r
86 }\r
87 \r
88 void RandAddSeedPerfmon()\r
89 {\r
90     // This can take up to 2 seconds, so only do it every 10 minutes\r
91     static int64 nLastPerfmon;\r
92     if (GetTime() < nLastPerfmon + 10 * 60)\r
93         return;\r
94     nLastPerfmon = GetTime();\r
95 \r
96 #ifdef __WXMSW__\r
97     // Don't need this on Linux, OpenSSL automatically uses /dev/urandom\r
98     // Seed with the entire set of perfmon data\r
99     unsigned char pdata[250000];\r
100     memset(pdata, 0, sizeof(pdata));\r
101     unsigned long nSize = sizeof(pdata);\r
102     long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL, NULL, pdata, &nSize);\r
103     RegCloseKey(HKEY_PERFORMANCE_DATA);\r
104     if (ret == ERROR_SUCCESS)\r
105     {\r
106         uint256 hash;\r
107         SHA256(pdata, nSize, (unsigned char*)&hash);\r
108         RAND_add(&hash, sizeof(hash), min(nSize/500.0, (double)sizeof(hash)));\r
109         hash = 0;\r
110         memset(pdata, 0, nSize);\r
111 \r
112         printf("%s RandAddSeed() %d bytes\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str(), nSize);\r
113     }\r
114 #else\r
115     printf("%s RandAddSeed()\n", DateTimeStrFormat("%x %H:%M:%S", GetTime()).c_str());\r
116 #endif\r
117 }\r
118 \r
119 uint64 GetRand(uint64 nMax)\r
120 {\r
121     if (nMax == 0)\r
122         return 0;\r
123 \r
124     // The range of the random source must be a multiple of the modulus\r
125     // to give every possible output value an equal possibility\r
126     uint64 nRange = (UINT64_MAX / nMax) * nMax;\r
127     uint64 nRand = 0;\r
128     do\r
129         RAND_bytes((unsigned char*)&nRand, sizeof(nRand));\r
130     while (nRand >= nRange);\r
131     return (nRand % nMax);\r
132 }\r
133 \r
134 \r
135 \r
136 \r
137 \r
138 \r
139 \r
140 \r
141 \r
142 \r
143 \r
144 \r
145 \r
146 // Safer snprintf\r
147 //  - prints up to limit-1 characters\r
148 //  - output string is always null terminated even if limit reached\r
149 //  - return value is the number of characters actually printed\r
150 int my_snprintf(char* buffer, size_t limit, const char* format, ...)\r
151 {\r
152     if (limit == 0)\r
153         return 0;\r
154     va_list arg_ptr;\r
155     va_start(arg_ptr, format);\r
156     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
157     va_end(arg_ptr);\r
158     if (ret < 0 || ret >= limit)\r
159     {\r
160         ret = limit - 1;\r
161         buffer[limit-1] = 0;\r
162     }\r
163     return ret;\r
164 }\r
165 \r
166 \r
167 string strprintf(const char* format, ...)\r
168 {\r
169     char buffer[50000];\r
170     char* p = buffer;\r
171     int limit = sizeof(buffer);\r
172     int ret;\r
173     loop\r
174     {\r
175         va_list arg_ptr;\r
176         va_start(arg_ptr, format);\r
177         ret = _vsnprintf(p, limit, format, arg_ptr);\r
178         va_end(arg_ptr);\r
179         if (ret >= 0 && ret < limit)\r
180             break;\r
181         if (p != buffer)\r
182             delete p;\r
183         limit *= 2;\r
184         p = new char[limit];\r
185         if (p == NULL)\r
186             throw std::bad_alloc();\r
187     }\r
188 #ifdef _MSC_VER\r
189     // msvc optimisation\r
190     if (p == buffer)\r
191         return string(p, p+ret);\r
192 #endif\r
193     string str(p, p+ret);\r
194     if (p != buffer)\r
195         delete p;\r
196     return str;\r
197 }\r
198 \r
199 \r
200 bool error(const char* format, ...)\r
201 {\r
202     char buffer[50000];\r
203     int limit = sizeof(buffer);\r
204     va_list arg_ptr;\r
205     va_start(arg_ptr, format);\r
206     int ret = _vsnprintf(buffer, limit, format, arg_ptr);\r
207     va_end(arg_ptr);\r
208     if (ret < 0 || ret >= limit)\r
209     {\r
210         ret = limit - 1;\r
211         buffer[limit-1] = 0;\r
212     }\r
213     printf("ERROR: %s\n", buffer);\r
214     return false;\r
215 }\r
216 \r
217 \r
218 void ParseString(const string& str, char c, vector<string>& v)\r
219 {\r
220     unsigned int i1 = 0;\r
221     unsigned int i2;\r
222     do\r
223     {\r
224         i2 = str.find(c, i1);\r
225         v.push_back(str.substr(i1, i2-i1));\r
226         i1 = i2+1;\r
227     }\r
228     while (i2 != str.npos);\r
229 }\r
230 \r
231 \r
232 string FormatMoney(int64 n, bool fPlus)\r
233 {\r
234     n /= CENT;\r
235     string str = strprintf("%"PRI64d".%02"PRI64d, (n > 0 ? n : -n)/100, (n > 0 ? n : -n)%100);\r
236     for (int i = 6; i < str.size(); i += 4)\r
237         if (isdigit(str[str.size() - i - 1]))\r
238             str.insert(str.size() - i, 1, ',');\r
239     if (n < 0)\r
240         str.insert((unsigned int)0, 1, '-');\r
241     else if (fPlus && n > 0)\r
242         str.insert((unsigned int)0, 1, '+');\r
243     return str;\r
244 }\r
245 \r
246 bool ParseMoney(const char* pszIn, int64& nRet)\r
247 {\r
248     string strWhole;\r
249     int64 nCents = 0;\r
250     const char* p = pszIn;\r
251     while (isspace(*p))\r
252         p++;\r
253     for (; *p; p++)\r
254     {\r
255         if (*p == ',' && p > pszIn && isdigit(p[-1]) && isdigit(p[1]) && isdigit(p[2]) && isdigit(p[3]) && !isdigit(p[4]))\r
256             continue;\r
257         if (*p == '.')\r
258         {\r
259             p++;\r
260             if (isdigit(*p))\r
261             {\r
262                 nCents = 10 * (*p++ - '0');\r
263                 if (isdigit(*p))\r
264                     nCents += (*p++ - '0');\r
265             }\r
266             break;\r
267         }\r
268         if (isspace(*p))\r
269             break;\r
270         if (!isdigit(*p))\r
271             return false;\r
272         strWhole.insert(strWhole.end(), *p);\r
273     }\r
274     for (; *p; p++)\r
275         if (!isspace(*p))\r
276             return false;\r
277     if (strWhole.size() > 14)\r
278         return false;\r
279     if (nCents < 0 || nCents > 99)\r
280         return false;\r
281     int64 nWhole = atoi64(strWhole);\r
282     int64 nPreValue = nWhole * 100 + nCents;\r
283     int64 nValue = nPreValue * CENT;\r
284     if (nValue / CENT != nPreValue)\r
285         return false;\r
286     if (nValue / COIN != nWhole)\r
287         return false;\r
288     nRet = nValue;\r
289     return true;\r
290 }\r
291 \r
292 \r
293 vector<unsigned char> ParseHex(const char* psz)\r
294 {\r
295     vector<unsigned char> vch;\r
296     while (isspace(*psz))\r
297         psz++;\r
298     vch.reserve((strlen(psz)+1)/3);\r
299 \r
300     static char phexdigit[256] =\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       0,1,2,3,4,5,6,7,8,9,-1,-1,-1,-1,-1,-1,\r
305       -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
306       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
307       -1,0xa,0xb,0xc,0xd,0xe,0xf,-1,-1,-1,-1,-1,-1,-1,-1,-1\r
308       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
309       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
310       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
311       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
312       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
313       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
314       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
315       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,\r
316       -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, };\r
317 \r
318     while (*psz)\r
319     {\r
320         char c = phexdigit[(unsigned char)*psz++];\r
321         if (c == -1)\r
322             break;\r
323         unsigned char n = (c << 4);\r
324         if (*psz)\r
325         {\r
326             char c = phexdigit[(unsigned char)*psz++];\r
327             if (c == -1)\r
328                 break;\r
329             n |= c;\r
330             vch.push_back(n);\r
331         }\r
332         while (isspace(*psz))\r
333             psz++;\r
334     }\r
335 \r
336     return vch;\r
337 }\r
338 \r
339 vector<unsigned char> ParseHex(const std::string& str)\r
340 {\r
341     return ParseHex(str.c_str());\r
342 }\r
343 \r
344 \r
345 void ParseParameters(int argc, char* argv[])\r
346 {\r
347     mapArgs.clear();\r
348     mapMultiArgs.clear();\r
349     for (int i = 0; i < argc; i++)\r
350     {\r
351         char psz[10000];\r
352         strlcpy(psz, argv[i], sizeof(psz));\r
353         char* pszValue = (char*)"";\r
354         if (strchr(psz, '='))\r
355         {\r
356             pszValue = strchr(psz, '=');\r
357             *pszValue++ = '\0';\r
358         }\r
359         #ifdef __WXMSW__\r
360         _strlwr(psz);\r
361         if (psz[0] == '/')\r
362             psz[0] = '-';\r
363         #endif\r
364         mapArgs[psz] = pszValue;\r
365         mapMultiArgs[psz].push_back(pszValue);\r
366     }\r
367 }\r
368 \r
369 \r
370 \r
371 \r
372 \r
373 \r
374 \r
375 void FormatException(char* pszMessage, std::exception* pex, const char* pszThread)\r
376 {\r
377 #ifdef __WXMSW__\r
378     char pszModule[MAX_PATH];\r
379     pszModule[0] = '\0';\r
380     GetModuleFileName(NULL, pszModule, sizeof(pszModule));\r
381 #else\r
382     // might not be thread safe, uses wxString\r
383     //const char* pszModule = wxStandardPaths::Get().GetExecutablePath().mb_str();\r
384     const char* pszModule = "bitcoin";\r
385 #endif\r
386     if (pex)\r
387         snprintf(pszMessage, 1000,\r
388             "EXCEPTION: %s       \n%s       \n%s in %s       \n", typeid(*pex).name(), pex->what(), pszModule, pszThread);\r
389     else\r
390         snprintf(pszMessage, 1000,\r
391             "UNKNOWN EXCEPTION       \n%s in %s       \n", pszModule, pszThread);\r
392 }\r
393 \r
394 void LogException(std::exception* pex, const char* pszThread)\r
395 {\r
396     char pszMessage[1000];\r
397     FormatException(pszMessage, pex, pszThread);\r
398     printf("\n%s", pszMessage);\r
399 }\r
400 \r
401 void PrintException(std::exception* pex, const char* pszThread)\r
402 {\r
403     char pszMessage[1000];\r
404     FormatException(pszMessage, pex, pszThread);\r
405     printf("\n\n************************\n%s\n", pszMessage);\r
406     if (wxTheApp)\r
407         wxMessageBox(pszMessage, "Error", wxOK | wxICON_ERROR);\r
408     throw;\r
409     //DebugBreak();\r
410 }\r
411 \r
412 \r
413 \r
414 \r
415 \r
416 \r
417 \r
418 \r
419 int GetFilesize(FILE* file)\r
420 {\r
421     int nSavePos = ftell(file);\r
422     int nFilesize = -1;\r
423     if (fseek(file, 0, SEEK_END) == 0)\r
424         nFilesize = ftell(file);\r
425     fseek(file, nSavePos, SEEK_SET);\r
426     return nFilesize;\r
427 }\r
428 \r
429 void GetDataDir(char* pszDir)\r
430 {\r
431     // pszDir must be at least MAX_PATH length.\r
432     if (pszSetDataDir[0] != 0)\r
433     {\r
434         strlcpy(pszDir, pszSetDataDir, MAX_PATH);\r
435         static bool fMkdirDone;\r
436         if (!fMkdirDone)\r
437         {\r
438             fMkdirDone = true;\r
439             _mkdir(pszDir);\r
440         }\r
441     }\r
442     else\r
443     {\r
444         // This can be called during exceptions by printf, so we cache the\r
445         // value so we don't have to do memory allocations after that.\r
446         // wxStandardPaths::GetUserDataDir\r
447         //  Return the directory for the user-dependent application data files:\r
448         //  Unix: ~/.appname\r
449         //  Windows: C:\Documents and Settings\username\Application Data\appname\r
450         //  Mac: ~/Library/Application Support/appname\r
451         static char pszCachedDir[MAX_PATH];\r
452         if (pszCachedDir[0] == 0)\r
453         {\r
454             strlcpy(pszCachedDir, wxStandardPaths::Get().GetUserDataDir().c_str(), sizeof(pszCachedDir));\r
455             _mkdir(pszCachedDir);\r
456         }\r
457         strlcpy(pszDir, pszCachedDir, MAX_PATH);\r
458     }\r
459 }\r
460 \r
461 string GetDataDir()\r
462 {\r
463     char pszDir[MAX_PATH];\r
464     GetDataDir(pszDir);\r
465     return pszDir;\r
466 }\r
467 \r
468 \r
469 \r
470 \r
471 \r
472 \r
473 \r
474 \r
475 \r
476 \r
477 //\r
478 // "Never go to sea with two chronometers; take one or three."\r
479 // Our three chronometers are:\r
480 //  - System clock\r
481 //  - Median of other server's clocks\r
482 //  - NTP servers\r
483 //\r
484 // note: NTP isn't implemented yet, so until then we just use the median\r
485 //  of other nodes clocks to correct ours.\r
486 //\r
487 int64 GetTime()\r
488 {\r
489     return time(NULL);\r
490 }\r
491 \r
492 static int64 nTimeOffset = 0;\r
493 \r
494 int64 GetAdjustedTime()\r
495 {\r
496     return GetTime() + nTimeOffset;\r
497 }\r
498 \r
499 void AddTimeData(unsigned int ip, int64 nTime)\r
500 {\r
501     int64 nOffsetSample = nTime - GetTime();\r
502 \r
503     // Ignore duplicates\r
504     static set<unsigned int> setKnown;\r
505     if (!setKnown.insert(ip).second)\r
506         return;\r
507 \r
508     // Add data\r
509     static vector<int64> vTimeOffsets;\r
510     if (vTimeOffsets.empty())\r
511         vTimeOffsets.push_back(0);\r
512     vTimeOffsets.push_back(nOffsetSample);\r
513     printf("Added time data, samples %d, offset %+"PRI64d" (%+"PRI64d" minutes)\n", vTimeOffsets.size(), vTimeOffsets.back(), vTimeOffsets.back()/60);\r
514     if (vTimeOffsets.size() >= 5 && vTimeOffsets.size() % 2 == 1)\r
515     {\r
516         sort(vTimeOffsets.begin(), vTimeOffsets.end());\r
517         int64 nMedian = vTimeOffsets[vTimeOffsets.size()/2];\r
518         nTimeOffset = nMedian;\r
519         if ((nMedian > 0 ? nMedian : -nMedian) > 5 * 60)\r
520         {\r
521             // Only let other nodes change our clock so far before we\r
522             // go to the NTP servers\r
523             /// todo: Get time from NTP servers, then set a flag\r
524             ///    to make sure it doesn't get changed again\r
525         }\r
526         foreach(int64 n, vTimeOffsets)\r
527             printf("%+"PRI64d"  ", n);\r
528         printf("|  nTimeOffset = %+"PRI64d"  (%+"PRI64d" minutes)\n", nTimeOffset, nTimeOffset/60);\r
529     }\r
530 }\r