reduced max outbound connections from 15 to 8 --version 0.3 rc4
[novacoin.git] / init.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 \r
9 \r
10 void ExitTimeout(void* parg)\r
11 {\r
12 #ifdef __WXMSW__\r
13     Sleep(5000);\r
14     ExitProcess(0);\r
15 #endif\r
16 }\r
17 \r
18 void Shutdown(void* parg)\r
19 {\r
20     static CCriticalSection cs_Shutdown;\r
21     static bool fTaken;\r
22     bool fFirstThread;\r
23     CRITICAL_BLOCK(cs_Shutdown)\r
24     {\r
25         fFirstThread = !fTaken;\r
26         fTaken = true;\r
27     }\r
28     static bool fExit;\r
29     if (fFirstThread)\r
30     {\r
31         fShutdown = true;\r
32         nTransactionsUpdated++;\r
33         DBFlush(false);\r
34         StopNode();\r
35         DBFlush(true);\r
36         CreateThread(ExitTimeout, NULL);\r
37         Sleep(50);\r
38         printf("Bitcoin exiting\n\n");\r
39         fExit = true;\r
40         exit(0);\r
41     }\r
42     else\r
43     {\r
44         while (!fExit)\r
45             Sleep(500);\r
46         Sleep(100);\r
47         ExitThread(0);\r
48     }\r
49 }\r
50 \r
51 \r
52 \r
53 \r
54 \r
55 \r
56 //////////////////////////////////////////////////////////////////////////////\r
57 //\r
58 // Startup folder\r
59 //\r
60 \r
61 #ifdef __WXMSW__\r
62 typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);\r
63 \r
64 string MyGetSpecialFolderPath(int nFolder, bool fCreate)\r
65 {\r
66     char pszPath[MAX_PATH+100] = "";\r
67 \r
68     // SHGetSpecialFolderPath is not usually available on NT 4.0\r
69     HMODULE hShell32 = LoadLibraryA("shell32.dll");\r
70     if (hShell32)\r
71     {\r
72         PSHGETSPECIALFOLDERPATHA pSHGetSpecialFolderPath =\r
73             (PSHGETSPECIALFOLDERPATHA)GetProcAddress(hShell32, "SHGetSpecialFolderPathA");\r
74         if (pSHGetSpecialFolderPath)\r
75             (*pSHGetSpecialFolderPath)(NULL, pszPath, nFolder, fCreate);\r
76         FreeModule(hShell32);\r
77     }\r
78 \r
79     // Backup option\r
80     if (pszPath[0] == '\0')\r
81     {\r
82         if (nFolder == CSIDL_STARTUP)\r
83         {\r
84             strcpy(pszPath, getenv("USERPROFILE"));\r
85             strcat(pszPath, "\\Start Menu\\Programs\\Startup");\r
86         }\r
87         else if (nFolder == CSIDL_APPDATA)\r
88         {\r
89             strcpy(pszPath, getenv("APPDATA"));\r
90         }\r
91     }\r
92 \r
93     return pszPath;\r
94 }\r
95 \r
96 string StartupShortcutPath()\r
97 {\r
98     return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";\r
99 }\r
100 \r
101 bool GetStartOnSystemStartup()\r
102 {\r
103     return wxFileExists(StartupShortcutPath());\r
104 }\r
105 \r
106 void SetStartOnSystemStartup(bool fAutoStart)\r
107 {\r
108     // If the shortcut exists already, remove it for updating\r
109     remove(StartupShortcutPath().c_str());\r
110 \r
111     if (fAutoStart)\r
112     {\r
113         CoInitialize(NULL);\r
114 \r
115         // Get a pointer to the IShellLink interface.\r
116         IShellLink* psl = NULL;\r
117         HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,\r
118                                 CLSCTX_INPROC_SERVER, IID_IShellLink,\r
119                                 reinterpret_cast<void**>(&psl));\r
120 \r
121         if (SUCCEEDED(hres))\r
122         {\r
123             // Get the current executable path\r
124             TCHAR pszExePath[MAX_PATH];\r
125             GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));\r
126 \r
127             // Set the path to the shortcut target\r
128             psl->SetPath(pszExePath);\r
129             PathRemoveFileSpec(pszExePath);\r
130             psl->SetWorkingDirectory(pszExePath);\r
131             psl->SetShowCmd(SW_SHOWMINNOACTIVE);\r
132 \r
133             // Query IShellLink for the IPersistFile interface for\r
134             // saving the shortcut in persistent storage.\r
135             IPersistFile* ppf = NULL;\r
136             hres = psl->QueryInterface(IID_IPersistFile,\r
137                                        reinterpret_cast<void**>(&ppf));\r
138             if (SUCCEEDED(hres))\r
139             {\r
140                 WCHAR pwsz[MAX_PATH];\r
141                 // Ensure that the string is ANSI.\r
142                 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);\r
143                 // Save the link by calling IPersistFile::Save.\r
144                 hres = ppf->Save(pwsz, TRUE);\r
145                 ppf->Release();\r
146             }\r
147             psl->Release();\r
148         }\r
149         CoUninitialize();\r
150     }\r
151 }\r
152 #else\r
153 bool GetStartOnSystemStartup() { return false; }\r
154 void SetStartOnSystemStartup(bool fAutoStart) { }\r
155 #endif\r
156 \r
157 \r
158 \r
159 \r
160 \r
161 \r
162 \r
163 //////////////////////////////////////////////////////////////////////////////\r
164 //\r
165 // CMyApp\r
166 //\r
167 \r
168 // Define a new application\r
169 class CMyApp: public wxApp\r
170 {\r
171 public:\r
172     wxLocale m_locale;\r
173 \r
174     CMyApp(){};\r
175     ~CMyApp(){};\r
176     bool OnInit();\r
177     bool OnInit2();\r
178     int OnExit();\r
179 \r
180     // Hook Initialize so we can start without GUI\r
181     virtual bool Initialize(int& argc, wxChar** argv);\r
182 \r
183     // 2nd-level exception handling: we get all the exceptions occurring in any\r
184     // event handler here\r
185     virtual bool OnExceptionInMainLoop();\r
186 \r
187     // 3rd, and final, level exception handling: whenever an unhandled\r
188     // exception is caught, this function is called\r
189     virtual void OnUnhandledException();\r
190 \r
191     // and now for something different: this function is called in case of a\r
192     // crash (e.g. dereferencing null pointer, division by 0, ...)\r
193     virtual void OnFatalException();\r
194 };\r
195 \r
196 IMPLEMENT_APP(CMyApp)\r
197 \r
198 bool CMyApp::Initialize(int& argc, wxChar** argv)\r
199 {\r
200     if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') &&\r
201         wxString(argv[1]) != "start")\r
202     {\r
203         fCommandLine = true;\r
204     }\r
205     else if (!fGUI)\r
206     {\r
207         fDaemon = true;\r
208     }\r
209     else\r
210     {\r
211         // wxApp::Initialize will remove environment-specific parameters,\r
212         // so it's too early to call ParseParameters yet\r
213         for (int i = 1; i < argc; i++)\r
214         {\r
215             wxString str = argv[i];\r
216             #ifdef __WXMSW__\r
217             if (str.size() >= 1 && str[0] == '/')\r
218                 str[0] = '-';\r
219             str = str.MakeLower();\r
220             #endif\r
221             // haven't decided which argument to use for this yet\r
222             if (str == "-daemon" || str == "-d" || str == "start")\r
223                 fDaemon = true;\r
224         }\r
225     }\r
226 \r
227 #ifdef __WXGTK__\r
228     if (fDaemon || fCommandLine)\r
229     {\r
230         // Call the original Initialize while suppressing error messages\r
231         // and ignoring failure.  If unable to initialize GTK, it fails\r
232         // near the end so hopefully the last few things don't matter.\r
233         {\r
234             wxLogNull logNo;\r
235             wxApp::Initialize(argc, argv);\r
236         }\r
237 \r
238         if (fDaemon)\r
239         {\r
240             // Daemonize\r
241             pid_t pid = fork();\r
242             if (pid < 0)\r
243             {\r
244                 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);\r
245                 return false;\r
246             }\r
247             if (pid > 0)\r
248                 pthread_exit((void*)0);\r
249         }\r
250 \r
251         return true;\r
252     }\r
253 #endif\r
254 \r
255     return wxApp::Initialize(argc, argv);\r
256 }\r
257 \r
258 bool CMyApp::OnInit()\r
259 {\r
260     bool fRet = false;\r
261     try\r
262     {\r
263         fRet = OnInit2();\r
264     }\r
265     catch (std::exception& e) {\r
266         PrintException(&e, "OnInit()");\r
267     } catch (...) {\r
268         PrintException(NULL, "OnInit()");\r
269     }\r
270     if (!fRet)\r
271         Shutdown(NULL);\r
272     return fRet;\r
273 }\r
274 \r
275 extern int g_isPainting;\r
276 \r
277 bool CMyApp::OnInit2()\r
278 {\r
279 #ifdef _MSC_VER\r
280     // Turn off microsoft heap dump noise\r
281     _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);\r
282     _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));\r
283 #endif\r
284 #if _MSC_VER >= 1400\r
285     // Disable confusing "helpful" text message on abort, ctrl-c\r
286     _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);\r
287 #endif\r
288 #if defined(__WXMSW__) && defined(__WXDEBUG__) && wxUSE_GUI\r
289     // Disable malfunctioning wxWidgets debug assertion\r
290     g_isPainting = 10000;\r
291 #endif\r
292 #if wxUSE_GUI\r
293     wxImage::AddHandler(new wxPNGHandler);\r
294 #endif\r
295 #if defined(__WXMSW__ ) || defined(__WXMAC__)\r
296     SetAppName("Bitcoin");\r
297 #else\r
298     SetAppName("bitcoin");\r
299 #endif\r
300 #ifndef __WXMSW__\r
301     umask(077);\r
302 #endif\r
303 #ifdef __WXMSW__\r
304 #if wxUSE_UNICODE\r
305     // Hack to set wxConvLibc codepage to UTF-8 on Windows,\r
306     // may break if wxMBConv_win32 implementation in strconv.cpp changes.\r
307     class wxMBConv_win32 : public wxMBConv\r
308     {\r
309     public:\r
310         long m_CodePage;\r
311         size_t m_minMBCharWidth;\r
312     };\r
313     if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)\r
314         ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;\r
315 #endif\r
316 #endif\r
317 \r
318     // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file\r
319     m_locale.Init(wxLANGUAGE_DEFAULT, 0);\r
320     m_locale.AddCatalogLookupPathPrefix("locale");\r
321     if (!fWindows)\r
322     {\r
323         m_locale.AddCatalogLookupPathPrefix("/usr/share/locale");\r
324         m_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");\r
325     }\r
326     m_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any\r
327     m_locale.AddCatalog("bitcoin");\r
328 \r
329     //\r
330     // Parameters\r
331     //\r
332     if (fCommandLine)\r
333     {\r
334         int ret = CommandLineRPC(argc, argv);\r
335         exit(ret);\r
336     }\r
337 \r
338     ParseParameters(argc, argv);\r
339     if (mapArgs.count("-?") || mapArgs.count("--help"))\r
340     {\r
341         wxString strUsage = string() +\r
342           _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +\r
343             "  bitcoin [options]       \t" + "\n" +\r
344             "  bitcoin [command]       \t" + _("Send command to bitcoin running with -server or -daemon\n") +\r
345             "  bitcoin [command] -?    \t" + _("Get help for a command\n") +\r
346             "  bitcoin help            \t" + _("List commands\n") +\r
347           _("Options:\n") +\r
348             "  -gen            \t  " + _("Generate coins\n") +\r
349             "  -gen=0          \t  " + _("Don't generate coins\n") +\r
350             "  -min            \t  " + _("Start minimized\n") +\r
351             "  -datadir=<dir>  \t  " + _("Specify data directory\n") +\r
352             "  -proxy=<ip:port>\t  " + _("Connect through socks4 proxy\n") +\r
353             "  -addnode=<ip>   \t  " + _("Add a node to connect to\n") +\r
354             "  -connect=<ip>   \t  " + _("Connect only to the specified node\n") +\r
355             "  -server         \t  " + _("Accept command line and JSON-RPC commands\n") +\r
356             "  -daemon         \t  " + _("Run in the background as a daemon and accept commands\n") +\r
357             "  -?              \t  " + _("This help message\n");\r
358 \r
359 \r
360         if (fWindows && fGUI)\r
361         {\r
362             // Tabs make the columns line up in the message box\r
363             wxMessageBox(strUsage, "Bitcoin", wxOK);\r
364         }\r
365         else\r
366         {\r
367             // Remove tabs\r
368             strUsage.Replace("\t", "");\r
369             fprintf(stderr, "%s", ((string)strUsage).c_str());\r
370         }\r
371         return false;\r
372     }\r
373 \r
374     if (mapArgs.count("-datadir"))\r
375         strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));\r
376 \r
377     if (mapArgs.count("-debug"))\r
378         fDebug = true;\r
379 \r
380     if (mapArgs.count("-printtodebugger"))\r
381         fPrintToDebugger = true;\r
382 \r
383     if (!fDebug && !pszSetDataDir[0])\r
384         ShrinkDebugFile();\r
385     printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");\r
386     printf("Bitcoin version %d.%d.%d%s, OS version %s\n", VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer, ((string)wxGetOsDescription()).c_str());\r
387     printf("System default language is %d %s\n", m_locale.GetSystemLanguage(), ((string)m_locale.GetSysName()).c_str());\r
388     printf("Language file %s (%s)\n", (string("locale/") + (string)m_locale.GetCanonicalName() + "/LC_MESSAGES/bitcoin.mo").c_str(), ((string)m_locale.GetLocale()).c_str());\r
389 \r
390     if (mapArgs.count("-loadblockindextest"))\r
391     {\r
392         CTxDB txdb("r");\r
393         txdb.LoadBlockIndex();\r
394         PrintBlockTree();\r
395         return false;\r
396     }\r
397 \r
398     //\r
399     // Limit to single instance per user\r
400     // Required to protect the database files if we're going to keep deleting log.*\r
401     //\r
402 #ifdef __WXMSW__\r
403     // todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file\r
404     //  maybe should go by whether successfully bind port 8333 instead\r
405     wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");\r
406     for (int i = 0; i < strMutexName.size(); i++)\r
407         if (!isalnum(strMutexName[i]))\r
408             strMutexName[i] = '.';\r
409     wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
410     if (psingleinstancechecker->IsAnotherRunning())\r
411     {\r
412         printf("Existing instance found\n");\r
413         unsigned int nStart = GetTime();\r
414         loop\r
415         {\r
416             // TODO: find out how to do this in Linux, or replace with wxWidgets commands\r
417             // Show the previous instance and exit\r
418             HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");\r
419             if (hwndPrev)\r
420             {\r
421                 if (IsIconic(hwndPrev))\r
422                     ShowWindow(hwndPrev, SW_RESTORE);\r
423                 SetForegroundWindow(hwndPrev);\r
424                 return false;\r
425             }\r
426 \r
427             if (GetTime() > nStart + 60)\r
428                 return false;\r
429 \r
430             // Resume this instance if the other exits\r
431             delete psingleinstancechecker;\r
432             Sleep(1000);\r
433             psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);\r
434             if (!psingleinstancechecker->IsAnotherRunning())\r
435                 break;\r
436         }\r
437     }\r
438 #endif\r
439 \r
440     // Bind to the port early so we can tell if another instance is already running.\r
441     // This is a backup to wxSingleInstanceChecker, which doesn't work on Linux.\r
442     string strErrors;\r
443     if (!BindListenPort(strErrors))\r
444     {\r
445         wxMessageBox(strErrors, "Bitcoin");\r
446         return false;\r
447     }\r
448 \r
449     //\r
450     // Load data files\r
451     //\r
452     if (fDaemon)\r
453         fprintf(stdout, "bitcoin server starting\n");\r
454     strErrors = "";\r
455     int64 nStart;\r
456 \r
457     printf("Loading addresses...\n");\r
458     nStart = GetTimeMillis();\r
459     if (!LoadAddresses())\r
460         strErrors += _("Error loading addr.dat      \n");\r
461     printf(" addresses   %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
462 \r
463     printf("Loading block index...\n");\r
464     nStart = GetTimeMillis();\r
465     if (!LoadBlockIndex())\r
466         strErrors += _("Error loading blkindex.dat      \n");\r
467     printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
468 \r
469     printf("Loading wallet...\n");\r
470     nStart = GetTimeMillis();\r
471     bool fFirstRun;\r
472     if (!LoadWallet(fFirstRun))\r
473         strErrors += _("Error loading wallet.dat      \n");\r
474     printf(" wallet      %15"PRI64d"ms\n", GetTimeMillis() - nStart);\r
475 \r
476     printf("Done loading\n");\r
477 \r
478         //// debug print\r
479         printf("mapBlockIndex.size() = %d\n",   mapBlockIndex.size());\r
480         printf("nBestHeight = %d\n",            nBestHeight);\r
481         printf("mapKeys.size() = %d\n",         mapKeys.size());\r
482         printf("mapPubKeys.size() = %d\n",      mapPubKeys.size());\r
483         printf("mapWallet.size() = %d\n",       mapWallet.size());\r
484         printf("mapAddressBook.size() = %d\n",  mapAddressBook.size());\r
485 \r
486     if (!strErrors.empty())\r
487     {\r
488         wxMessageBox(strErrors, "Bitcoin");\r
489         return false;\r
490     }\r
491 \r
492     // Add wallet transactions that aren't already in a block to mapTransactions\r
493     ReacceptWalletTransactions();\r
494 \r
495     //\r
496     // Parameters\r
497     //\r
498     if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))\r
499     {\r
500         PrintBlockTree();\r
501         return false;\r
502     }\r
503 \r
504     if (mapArgs.count("-printblock"))\r
505     {\r
506         string strMatch = mapArgs["-printblock"];\r
507         int nFound = 0;\r
508         for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)\r
509         {\r
510             uint256 hash = (*mi).first;\r
511             if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)\r
512             {\r
513                 CBlockIndex* pindex = (*mi).second;\r
514                 CBlock block;\r
515                 block.ReadFromDisk(pindex);\r
516                 block.BuildMerkleTree();\r
517                 block.print();\r
518                 printf("\n");\r
519                 nFound++;\r
520             }\r
521         }\r
522         if (nFound == 0)\r
523             printf("No blocks matching %s were found\n", strMatch.c_str());\r
524         return false;\r
525     }\r
526 \r
527     if (mapArgs.count("-gen"))\r
528     {\r
529         if (mapArgs["-gen"].empty())\r
530             fGenerateBitcoins = true;\r
531         else\r
532             fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);\r
533     }\r
534 \r
535     if (mapArgs.count("-proxy"))\r
536     {\r
537         fUseProxy = true;\r
538         addrProxy = CAddress(mapArgs["-proxy"]);\r
539         if (!addrProxy.IsValid())\r
540         {\r
541             wxMessageBox(_("Invalid -proxy address"), "Bitcoin");\r
542             return false;\r
543         }\r
544     }\r
545 \r
546     if (mapArgs.count("-addnode"))\r
547     {\r
548         foreach(string strAddr, mapMultiArgs["-addnode"])\r
549         {\r
550             CAddress addr(strAddr, NODE_NETWORK);\r
551             addr.nTime = 0; // so it won't relay unless successfully connected\r
552             if (addr.IsValid())\r
553                 AddAddress(addr);\r
554         }\r
555     }\r
556 \r
557     //\r
558     // Create the main window and start the node\r
559     //\r
560     if (!fDaemon)\r
561         CreateMainWindow();\r
562 \r
563     if (!CheckDiskSpace())\r
564         return false;\r
565 \r
566     RandAddSeedPerfmon();\r
567 \r
568     if (!CreateThread(StartNode, NULL))\r
569         wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");\r
570 \r
571     if (mapArgs.count("-server") || fDaemon)\r
572         CreateThread(ThreadRPCServer, NULL);\r
573 \r
574     if (fFirstRun)\r
575         SetStartOnSystemStartup(true);\r
576 \r
577     return true;\r
578 }\r
579 \r
580 int CMyApp::OnExit()\r
581 {\r
582     Shutdown(NULL);\r
583     return wxApp::OnExit();\r
584 }\r
585 \r
586 bool CMyApp::OnExceptionInMainLoop()\r
587 {\r
588     try\r
589     {\r
590         throw;\r
591     }\r
592     catch (std::exception& e)\r
593     {\r
594         PrintException(&e, "CMyApp::OnExceptionInMainLoop()");\r
595         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());\r
596         Sleep(1000);\r
597         throw;\r
598     }\r
599     catch (...)\r
600     {\r
601         PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");\r
602         wxLogWarning("Unknown exception");\r
603         Sleep(1000);\r
604         throw;\r
605     }\r
606     return true;\r
607 }\r
608 \r
609 void CMyApp::OnUnhandledException()\r
610 {\r
611     // this shows how we may let some exception propagate uncaught\r
612     try\r
613     {\r
614         throw;\r
615     }\r
616     catch (std::exception& e)\r
617     {\r
618         PrintException(&e, "CMyApp::OnUnhandledException()");\r
619         wxLogWarning("Exception %s %s", typeid(e).name(), e.what());\r
620         Sleep(1000);\r
621         throw;\r
622     }\r
623     catch (...)\r
624     {\r
625         PrintException(NULL, "CMyApp::OnUnhandledException()");\r
626         wxLogWarning("Unknown exception");\r
627         Sleep(1000);\r
628         throw;\r
629     }\r
630 }\r
631 \r
632 void CMyApp::OnFatalException()\r
633 {\r
634     wxMessageBox(_("Program has crashed and will terminate.  "), "Bitcoin", wxOK | wxICON_ERROR);\r
635 }\r