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