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
7 extern string GetDefaultDataDir(); /// todo: delete this later, just used by debug test
\r
12 void ExitTimeout(void* parg)
\r
20 void Shutdown(void* parg)
\r
22 static CCriticalSection cs_Shutdown;
\r
25 CRITICAL_BLOCK(cs_Shutdown)
\r
27 fFirstThread = !fTaken;
\r
34 nTransactionsUpdated++;
\r
38 CreateThread(ExitTimeout, NULL);
\r
40 printf("Bitcoin exiting\n\n");
\r
58 //////////////////////////////////////////////////////////////////////////////
\r
64 string StartupShortcutPath()
\r
66 return MyGetSpecialFolderPath(CSIDL_STARTUP, true) + "\\Bitcoin.lnk";
\r
69 bool GetStartOnSystemStartup()
\r
71 return filesystem::exists(StartupShortcutPath().c_str());
\r
74 void SetStartOnSystemStartup(bool fAutoStart)
\r
76 // If the shortcut exists already, remove it for updating
\r
77 remove(StartupShortcutPath().c_str());
\r
83 // Get a pointer to the IShellLink interface.
\r
84 IShellLink* psl = NULL;
\r
85 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
\r
86 CLSCTX_INPROC_SERVER, IID_IShellLink,
\r
87 reinterpret_cast<void**>(&psl));
\r
89 if (SUCCEEDED(hres))
\r
91 // Get the current executable path
\r
92 TCHAR pszExePath[MAX_PATH];
\r
93 GetModuleFileName(NULL, pszExePath, sizeof(pszExePath));
\r
95 // Set the path to the shortcut target
\r
96 psl->SetPath(pszExePath);
\r
97 PathRemoveFileSpec(pszExePath);
\r
98 psl->SetWorkingDirectory(pszExePath);
\r
99 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
\r
101 // Query IShellLink for the IPersistFile interface for
\r
102 // saving the shortcut in persistent storage.
\r
103 IPersistFile* ppf = NULL;
\r
104 hres = psl->QueryInterface(IID_IPersistFile,
\r
105 reinterpret_cast<void**>(&ppf));
\r
106 if (SUCCEEDED(hres))
\r
108 WCHAR pwsz[MAX_PATH];
\r
109 // Ensure that the string is ANSI.
\r
110 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().c_str(), -1, pwsz, MAX_PATH);
\r
111 // Save the link by calling IPersistFile::Save.
\r
112 hres = ppf->Save(pwsz, TRUE);
\r
121 #elif defined(__WXGTK__)
\r
124 // Follow the Desktop Application Autostart Spec:
\r
125 // http://standards.freedesktop.org/autostart-spec/autostart-spec-latest.html
\r
128 boost::filesystem::path GetAutostartDir()
\r
130 namespace fs = boost::filesystem;
\r
132 char* pszConfigHome = getenv("XDG_CONFIG_HOME");
\r
133 if (pszConfigHome) return fs::path(pszConfigHome) / fs::path("autostart");
\r
134 char* pszHome = getenv("HOME");
\r
135 if (pszHome) return fs::path(pszHome) / fs::path(".config/autostart");
\r
139 boost::filesystem::path GetAutostartFilePath()
\r
141 return GetAutostartDir() / boost::filesystem::path("bitcoin.desktop");
\r
144 bool GetStartOnSystemStartup()
\r
146 boost::filesystem::ifstream optionFile(GetAutostartFilePath());
\r
147 if (!optionFile.good())
\r
149 // Scan through file for "Hidden=true":
\r
151 while (!optionFile.eof())
\r
153 getline(optionFile, line);
\r
154 if (line.find("Hidden") != string::npos &&
\r
155 line.find("true") != string::npos)
\r
158 optionFile.close();
\r
163 void SetStartOnSystemStartup(bool fAutoStart)
\r
167 unlink(GetAutostartFilePath().native_file_string().c_str());
\r
171 boost::filesystem::create_directories(GetAutostartDir());
\r
173 boost::filesystem::ofstream optionFile(GetAutostartFilePath(), ios_base::out|ios_base::trunc);
\r
174 if (!optionFile.good())
\r
176 wxMessageBox(_("Cannot write autostart/bitcoin.desktop file"), "Bitcoin");
\r
179 // Write a bitcoin.desktop file to the autostart directory:
\r
180 char pszExePath[MAX_PATH+1];
\r
181 memset(pszExePath, 0, sizeof(pszExePath));
\r
182 readlink("/proc/self/exe", pszExePath, sizeof(pszExePath)-1);
\r
183 optionFile << "[Desktop Entry]\n";
\r
184 optionFile << "Type=Application\n";
\r
185 optionFile << "Name=Bitcoin\n";
\r
186 optionFile << "Exec=" << pszExePath << "\n";
\r
187 optionFile << "Terminal=false\n";
\r
188 optionFile << "Hidden=false\n";
\r
189 optionFile.close();
\r
194 // TODO: OSX startup stuff; see:
\r
195 // http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/CustomLogin.html
\r
197 bool GetStartOnSystemStartup() { return false; }
\r
198 void SetStartOnSystemStartup(bool fAutoStart) { }
\r
208 //////////////////////////////////////////////////////////////////////////////
\r
213 // Define a new application
\r
214 class CMyApp : public wxApp
\r
225 // Hook Initialize so we can start without GUI
\r
226 virtual bool Initialize(int& argc, wxChar** argv);
\r
228 // 2nd-level exception handling: we get all the exceptions occurring in any
\r
229 // event handler here
\r
230 virtual bool OnExceptionInMainLoop();
\r
232 // 3rd, and final, level exception handling: whenever an unhandled
\r
233 // exception is caught, this function is called
\r
234 virtual void OnUnhandledException();
\r
236 // and now for something different: this function is called in case of a
\r
237 // crash (e.g. dereferencing null pointer, division by 0, ...)
\r
238 virtual void OnFatalException();
\r
241 IMPLEMENT_APP(CMyApp)
\r
243 bool CMyApp::Initialize(int& argc, wxChar** argv)
\r
245 if (argc > 1 && argv[1][0] != '-' && (!fWindows || argv[1][0] != '/') &&
\r
246 wxString(argv[1]) != "start")
\r
248 fCommandLine = true;
\r
256 // wxApp::Initialize will remove environment-specific parameters,
\r
257 // so it's too early to call ParseParameters yet
\r
258 for (int i = 1; i < argc; i++)
\r
260 wxString str = argv[i];
\r
262 if (str.size() >= 1 && str[0] == '/')
\r
264 char pszLower[MAX_PATH];
\r
265 strlcpy(pszLower, str.c_str(), sizeof(pszLower));
\r
269 // haven't decided which argument to use for this yet
\r
270 if (str == "-daemon" || str == "-d" || str == "start")
\r
276 if (fDaemon || fCommandLine)
\r
278 // Call the original Initialize while suppressing error messages
\r
279 // and ignoring failure. If unable to initialize GTK, it fails
\r
280 // near the end so hopefully the last few things don't matter.
\r
283 wxApp::Initialize(argc, argv);
\r
289 pid_t pid = fork();
\r
292 fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
\r
296 pthread_exit((void*)0);
\r
303 return wxApp::Initialize(argc, argv);
\r
306 bool CMyApp::OnInit()
\r
313 catch (std::exception& e) {
\r
314 PrintException(&e, "OnInit()");
\r
316 PrintException(NULL, "OnInit()");
\r
323 extern int g_isPainting;
\r
325 bool CMyApp::OnInit2()
\r
328 // Turn off microsoft heap dump noise
\r
329 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
\r
330 _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0));
\r
332 #if _MSC_VER >= 1400
\r
333 // Disable confusing "helpful" text message on abort, ctrl-c
\r
334 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
\r
336 #if defined(__WXMSW__) && defined(__WXDEBUG__) && wxUSE_GUI
\r
337 // Disable malfunctioning wxWidgets debug assertion
\r
338 g_isPainting = 10000;
\r
341 wxImage::AddHandler(new wxPNGHandler);
\r
343 #if defined(__WXMSW__ ) || defined(__WXMAC__)
\r
344 SetAppName("Bitcoin");
\r
346 SetAppName("bitcoin");
\r
353 // Hack to set wxConvLibc codepage to UTF-8 on Windows,
\r
354 // may break if wxMBConv_win32 implementation in strconv.cpp changes.
\r
355 class wxMBConv_win32 : public wxMBConv
\r
359 size_t m_minMBCharWidth;
\r
361 if (((wxMBConv_win32*)&wxConvLibc)->m_CodePage == CP_ACP)
\r
362 ((wxMBConv_win32*)&wxConvLibc)->m_CodePage = CP_UTF8;
\r
366 // Load locale/<lang>/LC_MESSAGES/bitcoin.mo language file
\r
367 m_locale.Init(wxLANGUAGE_DEFAULT, 0);
\r
368 m_locale.AddCatalogLookupPathPrefix("locale");
\r
371 m_locale.AddCatalogLookupPathPrefix("/usr/share/locale");
\r
372 m_locale.AddCatalogLookupPathPrefix("/usr/local/share/locale");
\r
374 m_locale.AddCatalog("wxstd"); // wxWidgets standard translations, if any
\r
375 m_locale.AddCatalog("bitcoin");
\r
382 int ret = CommandLineRPC(argc, argv);
\r
386 ParseParameters(argc, argv);
\r
387 if (mapArgs.count("-?") || mapArgs.count("--help"))
\r
389 wxString strUsage = string() +
\r
390 _("Usage:") + "\t\t\t\t\t\t\t\t\t\t\n" +
\r
391 " bitcoin [options] \t" + "\n" +
\r
392 " bitcoin [command] \t" + _("Send command to bitcoin running with -server or -daemon\n") +
\r
393 " bitcoin [command] -? \t" + _("Get help for a command\n") +
\r
394 " bitcoin help \t" + _("List commands\n") +
\r
396 " -gen \t " + _("Generate coins\n") +
\r
397 " -gen=0 \t " + _("Don't generate coins\n") +
\r
398 " -min \t " + _("Start minimized\n") +
\r
399 " -datadir=<dir> \t " + _("Specify data directory\n") +
\r
400 " -proxy=<ip:port>\t " + _("Connect through socks4 proxy\n") +
\r
401 " -addnode=<ip> \t " + _("Add a node to connect to\n") +
\r
402 " -connect=<ip> \t " + _("Connect only to the specified node\n") +
\r
403 " -server \t " + _("Accept command line and JSON-RPC commands\n") +
\r
404 " -daemon \t " + _("Run in the background as a daemon and accept commands\n") +
\r
405 " -? \t " + _("This help message\n");
\r
407 #if defined(__WXMSW__) && wxUSE_GUI
\r
408 // Tabs make the columns line up in the message box
\r
409 wxMessageBox(strUsage, "Bitcoin", wxOK);
\r
412 strUsage.Replace("\t", "");
\r
413 fprintf(stderr, "%s", ((string)strUsage).c_str());
\r
418 if (mapArgs.count("-datadir"))
\r
419 strlcpy(pszSetDataDir, mapArgs["-datadir"].c_str(), sizeof(pszSetDataDir));
\r
421 if (mapArgs.count("-debug"))
\r
424 if (mapArgs.count("-printtodebugger"))
\r
425 fPrintToDebugger = true;
\r
427 if (!fDebug && !pszSetDataDir[0])
\r
429 printf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n");
\r
430 printf("Bitcoin version %d.%d.%d%s beta, OS version %s\n", VERSION/10000, (VERSION/100)%100, VERSION%100, pszSubVer, ((string)wxGetOsDescription()).c_str());
\r
431 printf("System default language is %d %s\n", m_locale.GetSystemLanguage(), ((string)m_locale.GetSysName()).c_str());
\r
432 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
434 /// debug - for now, just watching if these match
\r
435 if (pszSetDataDir[0] == 0)
\r
437 if (GetDefaultDataDir() != GetDataDir())
\r
438 printf("**** GetDefaultDataDir() %s != %s\n", GetDefaultDataDir().c_str(), GetDataDir().c_str());
\r
440 printf("OK GetDefaultDataDir() %s == %s\n", GetDefaultDataDir().c_str(), GetDataDir().c_str());
\r
443 if (mapArgs.count("-loadblockindextest"))
\r
446 txdb.LoadBlockIndex();
\r
452 // Limit to single instance per user
\r
453 // Required to protect the database files if we're going to keep deleting log.*
\r
456 // todo: wxSingleInstanceChecker wasn't working on Linux, never deleted its lock file
\r
457 // maybe should go by whether successfully bind port 8333 instead
\r
458 wxString strMutexName = wxString("bitcoin_running.") + getenv("HOMEPATH");
\r
459 for (int i = 0; i < strMutexName.size(); i++)
\r
460 if (!isalnum(strMutexName[i]))
\r
461 strMutexName[i] = '.';
\r
462 wxSingleInstanceChecker* psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
463 if (psingleinstancechecker->IsAnotherRunning())
\r
465 printf("Existing instance found\n");
\r
466 unsigned int nStart = GetTime();
\r
469 // TODO: find out how to do this in Linux, or replace with wxWidgets commands
\r
470 // Show the previous instance and exit
\r
471 HWND hwndPrev = FindWindowA("wxWindowClassNR", "Bitcoin");
\r
474 if (IsIconic(hwndPrev))
\r
475 ShowWindow(hwndPrev, SW_RESTORE);
\r
476 SetForegroundWindow(hwndPrev);
\r
480 if (GetTime() > nStart + 60)
\r
483 // Resume this instance if the other exits
\r
484 delete psingleinstancechecker;
\r
486 psingleinstancechecker = new wxSingleInstanceChecker(strMutexName);
\r
487 if (!psingleinstancechecker->IsAnotherRunning())
\r
493 // Bind to the port early so we can tell if another instance is already running.
\r
494 // This is a backup to wxSingleInstanceChecker, which doesn't work on Linux.
\r
496 if (!BindListenPort(strErrors))
\r
498 wxMessageBox(strErrors, "Bitcoin");
\r
506 fprintf(stdout, "bitcoin server starting\n");
\r
510 printf("Loading addresses...\n");
\r
511 nStart = GetTimeMillis();
\r
512 if (!LoadAddresses())
\r
513 strErrors += _("Error loading addr.dat \n");
\r
514 printf(" addresses %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
516 printf("Loading block index...\n");
\r
517 nStart = GetTimeMillis();
\r
518 if (!LoadBlockIndex())
\r
519 strErrors += _("Error loading blkindex.dat \n");
\r
520 printf(" block index %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
522 printf("Loading wallet...\n");
\r
523 nStart = GetTimeMillis();
\r
525 if (!LoadWallet(fFirstRun))
\r
526 strErrors += _("Error loading wallet.dat \n");
\r
527 printf(" wallet %15"PRI64d"ms\n", GetTimeMillis() - nStart);
\r
529 printf("Done loading\n");
\r
532 printf("mapBlockIndex.size() = %d\n", mapBlockIndex.size());
\r
533 printf("nBestHeight = %d\n", nBestHeight);
\r
534 printf("mapKeys.size() = %d\n", mapKeys.size());
\r
535 printf("mapPubKeys.size() = %d\n", mapPubKeys.size());
\r
536 printf("mapWallet.size() = %d\n", mapWallet.size());
\r
537 printf("mapAddressBook.size() = %d\n", mapAddressBook.size());
\r
539 if (!strErrors.empty())
\r
541 wxMessageBox(strErrors, "Bitcoin");
\r
545 // Add wallet transactions that aren't already in a block to mapTransactions
\r
546 ReacceptWalletTransactions();
\r
551 if (mapArgs.count("-printblockindex") || mapArgs.count("-printblocktree"))
\r
557 if (mapArgs.count("-printblock"))
\r
559 string strMatch = mapArgs["-printblock"];
\r
561 for (map<uint256, CBlockIndex*>::iterator mi = mapBlockIndex.begin(); mi != mapBlockIndex.end(); ++mi)
\r
563 uint256 hash = (*mi).first;
\r
564 if (strncmp(hash.ToString().c_str(), strMatch.c_str(), strMatch.size()) == 0)
\r
566 CBlockIndex* pindex = (*mi).second;
\r
568 block.ReadFromDisk(pindex);
\r
569 block.BuildMerkleTree();
\r
576 printf("No blocks matching %s were found\n", strMatch.c_str());
\r
580 if (mapArgs.count("-gen"))
\r
582 if (mapArgs["-gen"].empty())
\r
583 fGenerateBitcoins = true;
\r
585 fGenerateBitcoins = (atoi(mapArgs["-gen"].c_str()) != 0);
\r
588 if (mapArgs.count("-proxy"))
\r
591 addrProxy = CAddress(mapArgs["-proxy"]);
\r
592 if (!addrProxy.IsValid())
\r
594 wxMessageBox(_("Invalid -proxy address"), "Bitcoin");
\r
599 if (mapArgs.count("-addnode"))
\r
601 foreach(string strAddr, mapMultiArgs["-addnode"])
\r
603 CAddress addr(strAddr, NODE_NETWORK);
\r
604 addr.nTime = 0; // so it won't relay unless successfully connected
\r
605 if (addr.IsValid())
\r
611 // Create the main window and start the node
\r
614 CreateMainWindow();
\r
616 if (!CheckDiskSpace())
\r
619 RandAddSeedPerfmon();
\r
621 if (!CreateThread(StartNode, NULL))
\r
622 wxMessageBox("Error: CreateThread(StartNode) failed", "Bitcoin");
\r
624 if (mapArgs.count("-server") || fDaemon)
\r
625 CreateThread(ThreadRPCServer, NULL);
\r
628 SetStartOnSystemStartup(true);
\r
633 int CMyApp::OnExit()
\r
636 return wxApp::OnExit();
\r
639 bool CMyApp::OnExceptionInMainLoop()
\r
645 catch (std::exception& e)
\r
647 PrintException(&e, "CMyApp::OnExceptionInMainLoop()");
\r
648 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
654 PrintException(NULL, "CMyApp::OnExceptionInMainLoop()");
\r
655 wxLogWarning("Unknown exception");
\r
662 void CMyApp::OnUnhandledException()
\r
664 // this shows how we may let some exception propagate uncaught
\r
669 catch (std::exception& e)
\r
671 PrintException(&e, "CMyApp::OnUnhandledException()");
\r
672 wxLogWarning("Exception %s %s", typeid(e).name(), e.what());
\r
678 PrintException(NULL, "CMyApp::OnUnhandledException()");
\r
679 wxLogWarning("Unknown exception");
\r
685 void CMyApp::OnFatalException()
\r
687 wxMessageBox(_("Program has crashed and will terminate. "), "Bitcoin", wxOK | wxICON_ERROR);
\r