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
10 void ExitTimeout(void* parg)
\r
18 void Shutdown(void* parg)
\r
20 static CCriticalSection cs_Shutdown;
\r
23 CRITICAL_BLOCK(cs_Shutdown)
\r
25 fFirstThread = !fTaken;
\r
32 nTransactionsUpdated++;
\r
36 CreateThread(ExitTimeout, NULL);
\r
38 printf("Bitcoin exiting\n\n");
\r
56 //////////////////////////////////////////////////////////////////////////////
\r
62 typedef WINSHELLAPI BOOL (WINAPI *PSHGETSPECIALFOLDERPATHA)(HWND hwndOwner, LPSTR lpszPath, int nFolder, BOOL fCreate);
\r
64 string MyGetSpecialFolderPath(int nFolder, bool fCreate)
\r
66 char pszPath[MAX_PATH+100] = "";
\r
68 // SHGetSpecialFolderPath is not usually available on NT 4.0
\r
69 HMODULE hShell32 = LoadLibraryA("shell32.dll");
\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
80 if (pszPath[0] == '\0')
\r
82 if (nFolder == CSIDL_STARTUP)
\r
84 strcpy(pszPath, getenv("USERPROFILE"));
\r
85 strcat(pszPath, "\\Start Menu\\Programs\\Startup");
\r
87 else if (nFolder == CSIDL_APPDATA)
\r
89 strcpy(pszPath, getenv("APPDATA"));
\r
96 string StartupShortcutPath()
\r
98 return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
\r
101 bool GetStartOnSystemStartup()
\r
103 return wxFileExists(StartupShortcutPath());
\r
106 void SetStartOnSystemStartup(bool fAutoStart)
\r
108 // If the shortcut exists already, remove it for updating
\r
109 remove(StartupShortcutPath().c_str());
\r
113 CoInitialize(NULL);
\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
121 if (SUCCEEDED(hres))
\r
123 // Get the current executable path
\r
124 TCHAR pszExePath[MAX_PATH];
\r
125 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
\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
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
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
153 bool GetStartOnSystemStartup() { return false; }
\r
154 void SetStartOnSystemStartup(bool fAutoStart) { }
\r
163 //////////////////////////////////////////////////////////////////////////////
\r
168 // Define a new application
\r
169 class CMyApp: public wxApp
\r
180 // Hook Initialize so we can start without GUI
\r
181 virtual bool Initialize(int& argc, wxChar** argv);
\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
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
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
196 IMPLEMENT_APP(CMyApp)
\r
198 bool CMyApp::Initialize(int& argc, wxChar** argv)
\r
200 if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') &&
\r
201 wxString(argv[1]) != "start")
\r
203 fCommandLine = true;
\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
215 wxString str = argv[i];
\r
217 if (str.size() >= 1 && str[0] == '/')
\r
219 str = str.MakeLower();
\r
221 // haven't decided which argument to use for this yet
\r
222 if (str == "-daemon" || str == "-d" || str == "start")
\r
228 if (fDaemon || fCommandLine)
\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
235 wxApp::Initialize(argc, argv);
\r
241 pid_t pid = fork();
\r
244 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
\r
248 pthread_exit((void*)0);
\r
255 return wxApp::Initialize(argc, argv);
\r
258 bool CMyApp::OnInit()
\r
265 catch (std::exception& e) {
\r
266 PrintException(&e, "OnInit()");
\r
268 PrintException(NULL, "OnInit()");
\r
275 extern int g_isPainting;
\r
277 bool CMyApp::OnInit2()
\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
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
288 #if defined(__WXMSW__) && defined(__WXDEBUG__) && wxUSE_GUI
\r
289 // Disable malfunctioning wxWidgets debug assertion
\r
290 g_isPainting = 10000;
\r
293 wxImage::AddHandler(new wxPNGHandler);
\r
295 #if defined(__WXMSW__ ) || defined(__WXMAC__)
\r
296 SetAppName("Bitcoin");
\r
298 SetAppName("bitcoin");
\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
311 size_t m_minMBCharWidth;
\r
313 if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
\r
314 ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
\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
323 m_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
\r
324 m_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
\r
326 m_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
\r
327 m_locale.AddCatalog("bitcoin");
\r
334 int ret = CommandLineRPC(argc, argv);
\r
338 ParseParameters(argc, argv);
\r
339 if (mapArgs.count("-?") || mapArgs.count("--help"))
\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
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
360 if (fWindows && fGUI)
\r
362 // Tabs make the columns line up in the message box
\r
363 wxMessageBox(strUsage, "Bitcoin", wxOK);
\r
368 strUsage.Replace("\t", "");
\r
369 fprintf(stderr, "%s", ((string)strUsage).c_str());
\r
374 if (mapArgs.count("-datadir"))
\r
375 strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));
\r
377 if (mapArgs.count("-debug"))
\r
380 if (mapArgs.count("-printtodebugger"))
\r
381 fPrintToDebugger = true;
\r
383 if (!fDebug && !pszSetDataDir[0])
\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
390 if (mapArgs.count("-loadblockindextest"))
\r
393 txdb.LoadBlockIndex();
\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
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
412 printf("Existing instance found\n");
\r
413 unsigned int nStart = GetTime();
\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
421 if (IsIconic(hwndPrev))
\r
422 ShowWindow(hwndPrev, SW_RESTORE);
\r
423 SetForegroundWindow(hwndPrev);
\r
427 if (GetTime() > nStart + 60)
\r
430 // Resume this instance if the other exits
\r
431 delete psingleinstancechecker;
\r
433 psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
434 if (!psingleinstancechecker->IsAnotherRunning())
\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
443 if (!BindListenPort(strErrors))
\r
445 wxMessageBox(strErrors, "Bitcoin");
\r
453 fprintf(stdout, "bitcoin server starting\n");
\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
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
469 printf("Loading wallet...\n");
\r
470 nStart = GetTimeMillis();
\r
472 if (!LoadWallet(fFirstRun))
\r
473 strErrors += _("Error loading wallet.dat \n");
\r
474 printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
476 printf("Done loading\n");
\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
486 if (!strErrors.empty())
\r
488 wxMessageBox(strErrors, "Bitcoin");
\r
492 // Add wallet transactions that aren't already in a block to mapTransactions
\r
493 ReacceptWalletTransactions();
\r
498 if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))
\r
504 if (mapArgs.count("-printblock"))
\r
506 string strMatch = mapArgs["-printblock"];
\r
508 for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
\r
510 uint256 hash = (*mi).first;
\r
511 if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
\r
513 CBlockIndex* pindex = (*mi).second;
\r
515 block.ReadFromDisk(pindex);
\r
516 block.BuildMerkleTree();
\r
523 printf("No blocks matching %s were found\n", strMatch.c_str());
\r
527 if (mapArgs.count("-gen"))
\r
529 if (mapArgs["-gen"].empty())
\r
530 fGenerateBitcoins = true;
\r
532 fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);
\r
535 if (mapArgs.count("-proxy"))
\r
538 addrProxy = CAddress(mapArgs["-proxy"]);
\r
539 if (!addrProxy.IsValid())
\r
541 wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
\r
546 if (mapArgs.count("-addnode"))
\r
548 foreach(string strAddr, mapMultiArgs["-addnode"])
\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
558 // Create the main window and start the node
\r
561 CreateMainWindow();
\r
563 if (!CheckDiskSpace())
\r
566 RandAddSeedPerfmon();
\r
568 if (!CreateThread(StartNode, NULL))
\r
569 wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
\r
571 if (mapArgs.count("-server") || fDaemon)
\r
572 CreateThread(ThreadRPCServer, NULL);
\r
575 SetStartOnSystemStartup(true);
\r
580 int CMyApp::OnExit()
\r
583 return wxApp::OnExit();
\r
586 bool CMyApp::OnExceptionInMainLoop()
\r
592 catch (std::exception& e)
\r
594 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
\r
595 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
601 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
\r
602 wxLogWarning("Unknown exception");
\r
609 void CMyApp::OnUnhandledException()
\r
611 // this shows how we may let some exception propagate uncaught
\r
616 catch (std::exception& e)
\r
618 PrintException(&e, "CMyApp::OnUnhandledException()");
\r
619 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
625 PrintException(NULL, "CMyApp::OnUnhandledException()");
\r
626 wxLogWarning("Unknown exception");
\r
632 void CMyApp::OnFatalException()
\r
634 wxMessageBox(_("Program has crashed and will terminate. "), "Bitcoin", wxOK | wxICON_ERROR);
\r