Remove do-nothing command and add warning about it
[amule.git] / src / amule.cpp
blob478ba81cc043ee9c4a1806f47ca4b000a4d939aa
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "amule.h" // Interface declarations.
29 #include <csignal>
30 #include <cstring>
31 #include <wx/process.h>
32 #include <wx/sstream.h>
33 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
34 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
35 // and ENABLE_NLS
36 #include <common/ClientVersion.h>
38 #include <wx/cmdline.h> // Needed for wxCmdLineParser
39 #include <wx/config.h> // Do_not_auto_remove (win32)
40 #include <wx/fileconf.h>
41 #include <wx/socket.h>
42 #include <wx/tokenzr.h>
43 #include <wx/wfstream.h>
44 #include <wx/stopwatch.h> // Needed for wxStopWatch
47 #include <common/Format.h> // Needed for CFormat
48 #include "kademlia/kademlia/Kademlia.h"
49 #include "kademlia/kademlia/Prefs.h"
50 #include "kademlia/kademlia/UDPFirewallTester.h"
51 #include "CanceledFileList.h"
52 #include "ClientCreditsList.h" // Needed for CClientCreditsList
53 #include "ClientList.h" // Needed for CClientList
54 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
55 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
56 #include <common/FileFunctions.h> // Needed for CDirIterator
57 #include "FriendList.h" // Needed for CFriendList
58 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
59 #include "InternalEvents.h" // Needed for CMuleInternalEvent
60 #include "IPFilter.h" // Needed for CIPFilter
61 #include "KnownFileList.h" // Needed for CKnownFileList
62 #include "ListenSocket.h" // Needed for CListenSocket
63 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
64 #include "MagnetURI.h" // Needed for CMagnetURI
65 #include "OtherFunctions.h"
66 #include "PartFile.h" // Needed for CPartFile
67 #include "PlatformSpecific.h" // Needed for PlatformSpecific::AllowSleepMode();
68 #include "Preferences.h" // Needed for CPreferences
69 #include "SearchList.h" // Needed for CSearchList
70 #include "Server.h" // Needed for GetListName
71 #include "ServerList.h" // Needed for CServerList
72 #include "ServerConnect.h" // Needed for CServerConnect
73 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
74 #include "Statistics.h" // Needed for CStatistics
75 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
76 #include "ThreadTasks.h"
77 #include "UploadQueue.h" // Needed for CUploadQueue
78 #include "UploadBandwidthThrottler.h"
79 #include "UserEvents.h"
80 #include "ScopedPtr.h"
82 #ifdef ENABLE_UPNP
83 #include "UPnPBase.h" // Needed for UPnP
84 #endif
86 #ifdef __WXMAC__
87 #include <wx/sysopt.h> // Do_not_auto_remove
88 #endif
90 #ifndef AMULE_DAEMON
91 #ifdef __WXMAC__
92 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
93 #if wxCHECK_VERSION(2, 9, 0)
94 #include <wx/osx/core/cfstring.h> // Do_not_auto_remove
95 #else
96 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
97 #endif
98 #endif
99 #include <wx/msgdlg.h>
101 #include "amuleDlg.h"
102 #endif
105 #ifdef HAVE_SYS_RESOURCE_H
106 #include <sys/resource.h>
107 #endif
109 #ifdef HAVE_SYS_STATVFS_H
110 #include <sys/statvfs.h> // Do_not_auto_remove
111 #endif
114 #ifdef __GLIBC__
115 # define RLIMIT_RESOURCE __rlimit_resource
116 #else
117 # define RLIMIT_RESOURCE int
118 #endif
120 #ifdef AMULE_DAEMON
121 CamuleDaemonApp *theApp;
122 #else
123 CamuleGuiApp *theApp;
124 #endif
126 static void UnlimitResource(RLIMIT_RESOURCE resType)
128 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
129 struct rlimit rl;
130 getrlimit(resType, &rl);
131 rl.rlim_cur = rl.rlim_max;
132 setrlimit(resType, &rl);
133 #endif
137 static void SetResourceLimits()
139 #ifdef HAVE_SYS_RESOURCE_H
140 UnlimitResource(RLIMIT_DATA);
141 #ifndef __UCLIBC__
142 UnlimitResource(RLIMIT_FSIZE);
143 #endif
144 UnlimitResource(RLIMIT_NOFILE);
145 #ifdef RLIMIT_RSS
146 UnlimitResource(RLIMIT_RSS);
147 #endif
148 #endif
151 // We store the received signal in order to avoid race-conditions
152 // in the signal handler.
153 bool g_shutdownSignal = false;
155 void OnShutdownSignal( int /* sig */ )
157 signal(SIGINT, SIG_DFL);
158 signal(SIGTERM, SIG_DFL);
160 g_shutdownSignal = true;
162 #ifdef AMULE_DAEMON
163 theApp->ExitMainLoop();
164 #endif
168 CamuleApp::CamuleApp()
170 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
171 // Kry - I love to init the vars on init, even before timer.
172 StartTickTimer();
174 // Initialization
175 m_app_state = APP_STATE_STARTING;
177 theApp = &wxGetApp();
179 clientlist = NULL;
180 searchlist = NULL;
181 knownfiles = NULL;
182 canceledfiles = NULL;
183 serverlist = NULL;
184 serverconnect = NULL;
185 sharedfiles = NULL;
186 listensocket = NULL;
187 clientudp = NULL;
188 clientcredits = NULL;
189 friendlist = NULL;
190 downloadqueue = NULL;
191 uploadqueue = NULL;
192 ipfilter = NULL;
193 ECServerHandler = NULL;
194 glob_prefs = NULL;
195 m_statistics = NULL;
196 uploadBandwidthThrottler = NULL;
197 #ifdef ENABLE_UPNP
198 m_upnp = NULL;
199 m_upnpMappings.resize(4);
200 #endif
201 core_timer = NULL;
203 m_localip = 0;
204 m_dwPublicIP = 0;
205 webserver_pid = 0;
207 enable_daemon_fork = false;
209 // Apprently needed for *BSD
210 SetResourceLimits();
212 #ifdef _MSC_VER
213 _CrtSetDbgFlag(0); // Disable useless memleak debugging
214 #endif
217 CamuleApp::~CamuleApp()
219 // Closing the log-file as the very last thing, since
220 // wxWidgets log-events are saved in it as well.
221 theLogger.CloseLogfile();
224 int CamuleApp::OnExit()
226 if (m_app_state!=APP_STATE_STARTING) {
227 AddLogLineNS(_("Now, exiting main app..."));
230 // From wxWidgets docs, wxConfigBase:
231 // ...
232 // Note that you must delete this object (usually in wxApp::OnExit)
233 // in order to avoid memory leaks, wxWidgets won't do it automatically.
235 // As it happens, you may even further simplify the procedure described
236 // above: you may forget about calling Set(). When Get() is called and
237 // there is no current object, it will create one using Create() function.
238 // To disable this behaviour DontCreateOnDemand() is provided.
239 delete wxConfigBase::Set((wxConfigBase *)NULL);
241 // Save credits
242 clientcredits->SaveList();
244 // Kill amuleweb if running
245 if (webserver_pid) {
246 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid '%ld' ... ")) % webserver_pid);
247 wxKillError rc;
248 if (wxKill(webserver_pid, wxSIGTERM, &rc) == -1) {
249 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid '%ld' ... ")) % webserver_pid);
250 if (wxKill(webserver_pid, wxSIGKILL, &rc) == -1) {
251 AddLogLineNS(_("Failed"));
256 if (m_app_state!=APP_STATE_STARTING) {
257 AddLogLineNS(_("aMule OnExit: Terminating core."));
260 delete serverlist;
261 serverlist = NULL;
263 delete searchlist;
264 searchlist = NULL;
266 delete clientcredits;
267 clientcredits = NULL;
269 delete friendlist;
270 friendlist = NULL;
272 // Destroying CDownloadQueue calls destructor for CPartFile
273 // calling CSharedFileList::SafeAddKFile occasionally.
274 delete sharedfiles;
275 sharedfiles = NULL;
277 delete serverconnect;
278 serverconnect = NULL;
280 delete listensocket;
281 listensocket = NULL;
283 delete clientudp;
284 clientudp = NULL;
286 delete knownfiles;
287 knownfiles = NULL;
289 delete canceledfiles;
290 canceledfiles = NULL;
292 delete clientlist;
293 clientlist = NULL;
295 delete uploadqueue;
296 uploadqueue = NULL;
298 delete downloadqueue;
299 downloadqueue = NULL;
301 delete ipfilter;
302 ipfilter = NULL;
304 #ifdef ENABLE_UPNP
305 delete m_upnp;
306 m_upnp = NULL;
307 #endif
309 delete ECServerHandler;
310 ECServerHandler = NULL;
312 delete m_statistics;
313 m_statistics = NULL;
315 delete glob_prefs;
316 glob_prefs = NULL;
317 CPreferences::EraseItemList();
319 delete uploadBandwidthThrottler;
320 uploadBandwidthThrottler = NULL;
322 #ifdef ASIO_SOCKETS
323 delete m_AsioService;
324 m_AsioService = NULL;
325 #endif
327 wxSocketBase::Shutdown(); // needed because we also called Initialize() manually
329 if (m_app_state!=APP_STATE_STARTING) {
330 AddLogLineNS(_("aMule shutdown completed."));
333 #if wxUSE_MEMORY_TRACING
334 AddLogLineNS(_("Memory debug results for aMule exit:"));
335 // Log mem debug mesages to wxLogStderr
336 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
337 //AddLogLineNS(wxT("**************Classes**************");
338 //wxDebugContext::PrintClasses();
339 //AddLogLineNS(wxT("***************Dump***************");
340 //wxDebugContext::Dump();
341 AddLogLineNS(wxT("***************Stats**************"));
342 wxDebugContext::PrintStatistics(true);
344 // Set back to wxLogGui
345 delete wxLog::SetActiveTarget(oldLog);
346 #endif
348 StopTickTimer();
350 // Return 0 for succesful program termination
351 return AMULE_APP_BASE::OnExit();
355 int CamuleApp::InitGui(bool, wxString &)
357 return 0;
362 // Application initialization
364 bool CamuleApp::OnInit()
366 #if wxUSE_MEMORY_TRACING
367 // any text before call of Localize_mule needs not to be translated.
368 AddLogLineNS(wxT("Checkpoint set on app init for memory debug")); // debug output
369 wxDebugContext::SetCheckpoint();
370 #endif
372 // Forward wxLog events to CLogger
373 wxLog::SetActiveTarget(new CLoggerTarget);
375 m_localip = StringHosttoUint32(::wxGetFullHostName());
377 #ifndef __WINDOWS__
378 // get rid of sigpipe
379 signal(SIGPIPE, SIG_IGN);
380 #else
381 // Handle CTRL-Break
382 signal(SIGBREAK, OnShutdownSignal);
383 #endif
384 // Handle sigint and sigterm
385 signal(SIGINT, OnShutdownSignal);
386 signal(SIGTERM, OnShutdownSignal);
388 #ifdef __WXMAC__
389 // For listctrl's to behave on Mac
390 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
391 #endif
393 // Handle uncaught exceptions
394 InstallMuleExceptionHandler();
396 if (!InitCommon(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv)) {
397 return false;
400 glob_prefs = new CPreferences();
402 CPath outDir;
403 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), thePrefs::GetConfigDir() + wxT("Temp"), outDir)) {
404 thePrefs::SetTempDir(outDir);
405 } else {
406 return false;
409 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), thePrefs::GetConfigDir() + wxT("Incoming"), outDir)) {
410 thePrefs::SetIncomingDir(outDir);
411 } else {
412 return false;
415 // Initialize wx sockets (needed for http download in background with Asio sockets)
416 wxSocketBase::Initialize();
418 // Some sanity check
419 if (!thePrefs::UseTrayIcon()) {
420 thePrefs::SetMinToTray(false);
423 // Build the filenames for the two OS files
424 SetOSFiles(thePrefs::GetOSDir().GetRaw());
426 // Check if we have the old style locale config
427 bool old_localedef = false;
428 wxString langId = thePrefs::GetLanguageID();
429 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
430 old_localedef = true;
431 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
432 glob_prefs->Save();
435 #ifdef ENABLE_NLS
436 // Load localization settings
437 Localize_mule();
439 if (old_localedef) {
440 ShowAlert(_("Your locale has been changed to System Default due to a configuration change. Sorry."), _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
442 #endif
444 // Configure EC for amuled when invoked with ec-config
445 if (ec_config) {
446 AddLogLineNS(_("\nEC configuration"));
447 thePrefs::SetECPass(GetPassword(false).Encode());
448 thePrefs::EnableExternalConnections(true);
449 AddLogLineNS(_("Password set and external connections enabled."));
452 #ifndef __WINDOWS__
453 if (getuid() == 0) {
454 wxString msg =
455 wxT("Warning! You are running aMule as root.\n")
456 wxT("Doing so is not recommended for security reasons,\n")
457 wxT("and you are advised to run aMule as an normal\n")
458 wxT("user instead.");
460 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
462 fprintf(stderr, "\n--------------------------------------------------\n");
463 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
464 fprintf(stderr, "\n--------------------------------------------------\n\n");
466 #endif
468 // Display notification on new version or first run
469 wxTextFile vfile( thePrefs::GetConfigDir() + wxT("lastversion") );
470 wxString newMule(wxT( VERSION ));
472 if ( !wxFileExists( vfile.GetName() ) ) {
473 vfile.Create();
476 if ( vfile.Open() ) {
477 // Check if this version has been run before
478 bool found = false;
479 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
480 // Check if this version has been run before
481 if ( vfile.GetLine(i) == newMule ) {
482 found = true;
483 break;
487 // We havent run this version before?
488 if ( !found ) {
489 // Insert new at top to provide faster searches
490 vfile.InsertLine( newMule, 0 );
492 Trigger_New_version( newMule );
495 // Keep at most 10 entires
496 while ( vfile.GetLineCount() > 10 )
497 vfile.RemoveLine( vfile.GetLineCount() - 1 );
499 vfile.Write();
500 vfile.Close();
503 m_statistics = new CStatistics();
505 clientlist = new CClientList();
506 friendlist = new CFriendList();
507 searchlist = new CSearchList();
508 knownfiles = new CKnownFileList();
509 canceledfiles = new CCanceledFileList;
510 serverlist = new CServerList();
512 sharedfiles = new CSharedFileList(knownfiles);
513 clientcredits = new CClientCreditsList();
515 // bugfix - do this before creating the uploadqueue
516 downloadqueue = new CDownloadQueue();
517 uploadqueue = new CUploadQueue();
518 ipfilter = new CIPFilter();
520 // Creates all needed listening sockets
521 wxString msg;
522 if (!ReinitializeNetwork(&msg)) {
523 AddLogLineNS(wxT("\n"));
524 AddLogLineNS(msg);
527 // Test if there's any new version
528 if (thePrefs::GetCheckNewVersion()) {
529 // We use the thread base because I don't want a dialog to pop up.
530 CHTTPDownloadThread* version_check =
531 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
532 thePrefs::GetConfigDir() + wxT("last_version_check"), thePrefs::GetConfigDir() + wxT("last_version"), HTTP_VersionCheck, false, false);
533 version_check->Create();
534 version_check->Run();
537 // Create main dialog, or fork to background (daemon).
538 InitGui(m_geometryEnabled, m_geometryString);
540 #ifdef AMULE_DAEMON
541 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
542 if (enable_daemon_fork) {
543 RefreshSingleInstanceChecker();
544 // No need to check IsAnotherRunning() - we've done it before.
546 #endif
548 // Has to be created after the call to InitGui, as fork
549 // (when using posix threads) only replicates the mainthread,
550 // and the UBT constructor creates a thread.
551 uploadBandwidthThrottler = new UploadBandwidthThrottler();
553 #ifdef ASIO_SOCKETS
554 m_AsioService = new CAsioService;
555 #endif
557 // Start performing background tasks
558 // This will start loading the IP filter. It will start right away.
559 // Log is confusing, because log entries from background will only be printed
560 // once foreground becomes idle, and that will only be after loading
561 // of the partfiles has finished.
562 CThreadScheduler::Start();
564 // These must be initialized after the gui is loaded.
565 if (thePrefs::GetNetworkED2K()) {
566 serverlist->Init();
568 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
569 sharedfiles->Reload();
571 // Ensure that the up/down ratio is used
572 CPreferences::CheckUlDlRatio();
574 // Load saved friendlist (now, so it can update in GUI right away)
575 friendlist->LoadList();
577 // The user can start pressing buttons like mad if he feels like it.
578 m_app_state = APP_STATE_RUNNING;
580 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
581 // There are no servers and ED2K active -> ask for download.
582 // As we cannot ask in amuled, we just update there
583 #ifndef AMULE_DAEMON
584 if (wxYES == wxMessageBox(
585 wxString(
586 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
587 wxString(_("Server list download")),
588 wxYES_NO,
589 static_cast<wxWindow*>(theApp->amuledlg)))
590 #endif
592 serverlist->UpdateServerMetFromURL(thePrefs::GetEd2kServersUrl());
597 // Autoconnect if that option is enabled
598 if (thePrefs::DoAutoConnect()) {
599 // IP filter is still loading and will be finished on event.
600 // Tell it to autoconnect.
601 if (thePrefs::GetNetworkED2K()) {
602 ipfilter->ConnectToAnyServerWhenReady();
604 if (thePrefs::GetNetworkKademlia()) {
605 ipfilter->StartKADWhenReady();
609 // Enable GeoIP
610 #ifdef ENABLE_IP2COUNTRY
611 theApp->amuledlg->EnableIP2Country();
612 #endif
614 // Run webserver?
615 if (thePrefs::GetWSIsEnabled()) {
616 wxString aMuleConfigFile = thePrefs::GetConfigDir() + m_configFile;
617 wxString amulewebPath = thePrefs::GetWSPath();
619 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
620 // For the Mac GUI application, look for amuleweb in the bundle
621 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
622 CFBundleGetMainBundle(), CFSTR("amuleweb"));
624 if (amulewebUrl) {
625 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
626 CFRelease(amulewebUrl);
628 if (absoluteUrl) {
629 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
630 CFRelease(absoluteUrl);
631 #if wxCHECK_VERSION(2, 9, 0)
632 amulewebPath = wxCFStringRef(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
633 #else
634 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
635 #endif
638 #endif
640 #ifdef __WINDOWS__
641 # define QUOTE wxT("\"")
642 #else
643 # define QUOTE wxT("\'")
644 #endif
646 wxString cmd =
647 QUOTE +
648 amulewebPath +
649 QUOTE wxT(" ") QUOTE wxT("--amule-config-file=") +
650 aMuleConfigFile +
651 QUOTE;
652 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
653 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
654 bool webserver_ok = webserver_pid > 0;
655 if (webserver_ok) {
656 AddLogLineC(CFormat(_("web server running on pid %d")) % webserver_pid);
657 } else {
658 delete p;
659 ShowAlert(_(
660 "You requested to run web server on startup, but the amuleweb binary cannot be run. Please install the package containing aMule web server, or compile aMule using --enable-webserver and run make install"),
661 _("ERROR"), wxOK | wxICON_ERROR);
665 return true;
668 bool CamuleApp::ReinitializeNetwork(wxString* msg)
670 bool ok = true;
671 static bool firstTime = true;
673 if (!firstTime) {
674 // TODO: Destroy previously created sockets
676 firstTime = false;
678 // Some sanity checks first
679 if (thePrefs::ECPort() == thePrefs::GetPort()) {
680 // Select a random usable port in the range 1025 ... 2^16 - 1
681 uint16 port = thePrefs::ECPort();
682 while ( port < 1024 || port == thePrefs::GetPort() ) {
683 port = (uint16)rand();
685 thePrefs::SetECPort( port );
687 wxString err =
688 wxT("Network configuration failed! You cannot use the same port\n")
689 wxT("for the main TCP port and the External Connections port.\n")
690 wxT("The EC port has been changed to avoid conflict, see the\n")
691 wxT("preferences for the new value.\n");
692 *msg << err;
694 AddLogLineN(wxEmptyString );
695 AddLogLineC(err );
696 AddLogLineN(wxEmptyString );
698 ok = false;
701 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
702 // Select a random usable value in the range 1025 ... 2^16 - 1
703 uint16 port = thePrefs::GetUDPPort();
704 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
705 port = (uint16)rand();
707 thePrefs::SetUDPPort( port );
709 wxString err =
710 wxT("Network configuration failed! You set your UDP port to\n")
711 wxT("the value of the main TCP port plus 3.\n")
712 wxT("This port has been reserved for the Server-UDP port. The\n")
713 wxT("port value has been changed to avoid conflict, see the\n")
714 wxT("preferences for the new value\n");
715 *msg << err;
717 AddLogLineN(wxEmptyString );
718 AddLogLineC(err );
719 AddLogLineN(wxEmptyString );
721 ok = false;
724 // Create the address where we are going to listen
725 // TODO: read this from configuration file
726 amuleIPV4Address myaddr[4];
728 // Create the External Connections Socket.
729 // Default is 4712.
730 // Get ready to handle connections from apps like amulecmd
731 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
732 myaddr[0].AnyAddress();
734 myaddr[0].Service(thePrefs::ECPort());
735 ECServerHandler = new ExternalConn(myaddr[0], msg);
737 // Create the UDP socket TCP+3.
738 // Used for source asking on servers.
739 if (thePrefs::GetAddress().IsEmpty()) {
740 myaddr[1].AnyAddress();
741 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
742 myaddr[1].AnyAddress();
743 AddLogLineC(CFormat(_("Could not bind ports to the specified address: %s"))
744 % thePrefs::GetAddress());
747 wxString ip = myaddr[1].IPAddress();
748 myaddr[1].Service(thePrefs::GetPort()+3);
749 serverconnect = new CServerConnect(serverlist, myaddr[1]);
750 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
751 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
753 // Create the ListenSocket (aMule TCP socket).
754 // Used for Client Port / Connections from other clients,
755 // Client to Client Source Exchange.
756 // Default is 4662.
757 myaddr[2] = myaddr[1];
758 myaddr[2].Service(thePrefs::GetPort());
759 listensocket = new CListenSocket(myaddr[2]);
760 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
761 % ip % (unsigned int)(thePrefs::GetPort());
762 // Notify(true) has already been called to the ListenSocket, so events may
763 // be already comming in.
764 if (!listensocket->IsOk()) {
765 // If we wern't able to start listening, we need to warn the user
766 wxString err;
767 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
768 (unsigned int)(thePrefs::GetPort());
769 *msg << err;
770 AddLogLineC(err);
771 err.Clear();
772 err = CFormat(
773 _("Port %u is not available!\n\nThis means that you will be LOWID.\n\nCheck your network to make sure the port is open for output and input.")) %
774 (unsigned int)(thePrefs::GetPort());
775 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
778 // Create the UDP socket.
779 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
780 // Also used for Kademlia.
781 // Default is port 4672.
782 myaddr[3] = myaddr[1];
783 myaddr[3].Service(thePrefs::GetUDPPort());
784 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
785 if (!thePrefs::IsUDPDisabled()) {
786 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
787 % ip % thePrefs::GetUDPPort();
788 } else {
789 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
792 #ifdef ENABLE_UPNP
793 if (thePrefs::GetUPnPEnabled()) {
794 try {
795 m_upnpMappings[0] = CUPnPPortMapping(
796 myaddr[0].Service(),
797 "TCP",
798 thePrefs::GetUPnPECEnabled(),
799 "aMule TCP External Connections Socket");
800 m_upnpMappings[1] = CUPnPPortMapping(
801 myaddr[1].Service(),
802 "UDP",
803 thePrefs::GetUPnPEnabled(),
804 "aMule UDP socket (TCP+3)");
805 m_upnpMappings[2] = CUPnPPortMapping(
806 myaddr[2].Service(),
807 "TCP",
808 thePrefs::GetUPnPEnabled(),
809 "aMule TCP Listen Socket");
810 m_upnpMappings[3] = CUPnPPortMapping(
811 myaddr[3].Service(),
812 "UDP",
813 thePrefs::GetUPnPEnabled(),
814 "aMule UDP Extended eMule Socket");
815 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
817 wxStopWatch count; // Wait UPnP service responses for 3s before add port mappings
818 while (count.Time() < 3000 && !m_upnp->WanServiceDetected());
820 m_upnp->AddPortMappings(m_upnpMappings);
821 } catch(CUPnPException &e) {
822 wxString error_msg;
823 error_msg << e.what();
824 AddLogLineC(error_msg);
825 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
828 #endif
830 return ok;
833 /* Original implementation by Bouc7 of the eMule Project.
834 aMule Signature idea was designed by BigBob and implemented
835 by Un-Thesis, with design inputs and suggestions from bothie.
837 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
839 // Do not do anything if online signature is disabled in Preferences
840 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
841 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
842 // that means m_amulesig_path is empty too.
843 return;
846 // Remove old signature files
847 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
848 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
851 wxTextFile amulesig_out;
852 wxTextFile emulesig_out;
854 // Open both files if needed
855 if ( !emulesig_out.Create( m_emulesig_path) ) {
856 AddLogLineC(_("Failed to create OnlineSig File"));
857 // Will never try again.
858 m_amulesig_path.Clear();
859 m_emulesig_path.Clear();
860 return;
863 if ( !amulesig_out.Create(m_amulesig_path) ) {
864 AddLogLineC(_("Failed to create aMule OnlineSig File"));
865 // Will never try again.
866 m_amulesig_path.Clear();
867 m_emulesig_path.Clear();
868 return;
871 wxString emulesig_string;
872 wxString temp;
874 if (zero) {
875 emulesig_string = wxT("0\xA0.0|0.0|0");
876 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
877 } else {
878 if (IsConnectedED2K()) {
880 temp = CFormat(wxT("%d")) % serverconnect->GetCurrentServer()->GetPort();
882 // We are online
883 emulesig_string =
884 // Connected
885 wxT("1|")
886 //Server name
887 + serverconnect->GetCurrentServer()->GetListName()
888 + wxT("|")
889 // IP and port of the server
890 + serverconnect->GetCurrentServer()->GetFullIP()
891 + wxT("|")
892 + temp;
895 // Now for amule sig
897 // Connected. State 1, full info
898 amulesig_out.AddLine(wxT("1"));
899 // Server Name
900 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
901 // Server IP
902 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
903 // Server Port
904 amulesig_out.AddLine(temp);
906 if (serverconnect->IsLowID()) {
907 amulesig_out.AddLine(wxT("L"));
908 } else {
909 amulesig_out.AddLine(wxT("H"));
912 } else if (serverconnect->IsConnecting()) {
913 emulesig_string = wxT("0");
915 // Connecting. State 2, No info.
916 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
917 } else {
918 // Not connected to a server
919 emulesig_string = wxT("0");
921 // Not connected, state 0, no info
922 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
924 if (IsConnectedKad()) {
925 if(Kademlia::CKademlia::IsFirewalled()) {
926 // Connected. Firewalled. State 1.
927 amulesig_out.AddLine(wxT("1"));
928 } else {
929 // Connected. State 2.
930 amulesig_out.AddLine(wxT("2"));
932 } else {
933 // Not connected.State 0.
934 amulesig_out.AddLine(wxT("0"));
936 emulesig_string += wxT("\xA");
938 // Datarate for downloads
939 temp = CFormat(wxT("%.1f")) % (theStats::GetDownloadRate() / 1024.0);
941 emulesig_string += temp + wxT("|");
942 amulesig_out.AddLine(temp);
944 // Datarate for uploads
945 temp = CFormat(wxT("%.1f")) % (theStats::GetUploadRate() / 1024.0);
947 emulesig_string += temp + wxT("|");
948 amulesig_out.AddLine(temp);
950 // Number of users waiting for upload
951 temp = CFormat(wxT("%d")) % theStats::GetWaitingUserCount();
953 emulesig_string += temp;
954 amulesig_out.AddLine(temp);
956 // Number of shared files (not on eMule)
957 amulesig_out.AddLine(CFormat(wxT("%d")) % theStats::GetSharedFileCount());
960 // eMule signature finished here. Write the line to the wxTextFile.
961 emulesig_out.AddLine(emulesig_string);
963 // Now for aMule signature extras
965 // Nick on the network
966 amulesig_out.AddLine(thePrefs::GetUserNick());
968 // Total received in bytes
969 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalReceivedBytes());
971 // Total sent in bytes
972 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalSentBytes());
974 // amule version
975 #ifdef SVNDATE
976 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
977 #else
978 amulesig_out.AddLine(wxT(VERSION));
979 #endif
981 if (zero) {
982 amulesig_out.AddLine(wxT("0"));
983 amulesig_out.AddLine(wxT("0"));
984 amulesig_out.AddLine(wxT("0"));
985 } else {
986 // Total received bytes in session
987 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
988 theStats::GetSessionReceivedBytes() );
990 // Total sent bytes in session
991 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
992 theStats::GetSessionSentBytes() );
994 // Uptime
995 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
998 // Flush the files
999 emulesig_out.Write();
1000 amulesig_out.Write();
1001 } //End Added By Bouc7
1004 #if wxUSE_ON_FATAL_EXCEPTION
1005 // Gracefully handle fatal exceptions and print backtrace if possible
1006 void CamuleApp::OnFatalException()
1008 /* Print the backtrace */
1009 wxString msg;
1010 msg << wxT("\n--------------------------------------------------------------------------------\n")
1011 << wxT("A fatal error has occurred and aMule has crashed.\n")
1012 << wxT("Please assist us in fixing this problem by posting the backtrace below in our\n")
1013 << wxT("'aMule Crashes' forum and include as much information as possible regarding the\n")
1014 << wxT("circumstances of this crash. The forum is located here:\n")
1015 << wxT(" http://forum.amule.org/index.php?board=67.0\n")
1016 << wxT("If possible, please try to generate a real backtrace of this crash:\n")
1017 << wxT(" http://wiki.amule.org/wiki/Backtraces\n\n")
1018 << wxT("----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n")
1019 << wxT("Current version is: ") << FullMuleVersion
1020 << wxT("\nRunning on: ") << OSDescription
1021 << wxT("\n\n")
1022 << get_backtrace(1) // 1 == skip this function.
1023 << wxT("\n--------------------------------------------------------------------------------\n");
1025 theLogger.EmergencyLog(msg, true);
1027 #endif
1030 // Sets the localization of aMule
1031 void CamuleApp::Localize_mule()
1033 InitCustomLanguages();
1034 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1035 if (!m_locale.IsOk()) {
1036 AddLogLineN(_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1041 // Displays information related to important changes in aMule.
1042 // Is called when the user runs a new version of aMule
1043 void CamuleApp::Trigger_New_version(wxString new_version)
1045 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1046 if (new_version == wxT("SVN")) {
1047 info += _("This version is a testing version, updated daily, and\n");
1048 info += _("we give no warranty it won't break anything, burn your house,\n");
1049 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1052 // General info
1053 info += wxT("\n");
1054 info += _("More information, support and new releases can found at our homepage,\n");
1055 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1056 info += wxT("\n");
1057 info += _("Feel free to report any bugs to http://forum.amule.org");
1059 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1063 void CamuleApp::SetOSFiles(const wxString& new_path)
1065 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1066 if ( ::wxDirExists(new_path) ) {
1067 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1068 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1069 } else {
1070 ShowAlert(_("The folder for Online Signature files you specified is INVALID!\n OnlineSignature will be DISABLED until you fix it on preferences."), _("ERROR"), wxOK | wxICON_ERROR);
1071 m_emulesig_path.Clear();
1072 m_amulesig_path.Clear();
1074 } else {
1075 m_emulesig_path.Clear();
1076 m_amulesig_path.Clear();
1081 #ifdef __WXDEBUG__
1082 #ifndef wxUSE_STACKWALKER
1083 #define wxUSE_STACKWALKER 0
1084 #endif
1085 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1086 const wxChar* func, const wxChar* cond, const wxChar* msg)
1088 wxString errmsg = CFormat( wxT("Assertion failed: %s:%s:%d: Assertion '%s' failed. %s\nBacktrace follows:\n%s\n") )
1089 % file % func % line % cond % ( msg ? msg : wxT("") )
1090 % get_backtrace(2); // Skip the function-calls directly related to the assert call.
1091 theLogger.EmergencyLog(errmsg, false);
1093 if (wxThread::IsMain() && IsRunning()) {
1094 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1095 } else {
1096 #ifdef _MSC_VER
1097 wxString s = CFormat(wxT("%s in %s")) % cond % func;
1098 if (msg) {
1099 s << wxT(" : ") << msg;
1101 _wassert(s.wc_str(), file, line);
1102 #else
1103 // Abort, allows gdb to catch the assertion
1104 raise( SIGABRT );
1105 #endif
1108 #endif
1111 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1113 CServerUDPSocket* socket =reinterpret_cast<CServerUDPSocket*>(evt.GetClientData());
1114 socket->OnHostnameResolved(evt.GetExtraLong());
1118 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1120 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1124 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1126 AddLogLineNS(_("Server hostname notified"));
1127 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1131 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1133 if(!IsRunning()) {
1134 return;
1136 serverconnect->StopConnectionTry();
1137 if (IsConnectedED2K() ) {
1138 return;
1140 serverconnect->ConnectToAnyServer();
1144 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1146 // Former TimerProc section
1147 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1148 uint64 msCur = theStats::GetUptimeMillis();
1149 TheTime = msCur / 1000;
1151 if (!IsRunning()) {
1152 return;
1155 #ifndef AMULE_DAEMON
1156 // Check if we should terminate the app
1157 if ( g_shutdownSignal ) {
1158 wxWindow* top = GetTopWindow();
1160 if ( top ) {
1161 top->Close(true);
1162 } else {
1163 // No top-window, have to force termination.
1164 wxExit();
1167 #endif
1169 // There is a theoretical chance that the core time function can recurse:
1170 // if an event function gets blocked on a mutex (communicating with the
1171 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1172 // If CPU load gets high a new core timer event could be generated before the last
1173 // one was finished and so recursion could occur, which would be bad.
1174 // Detect this and do an early return then.
1175 static bool recurse = false;
1176 if (recurse) {
1177 return;
1179 recurse = true;
1181 uploadqueue->Process();
1182 downloadqueue->Process();
1183 //theApp->clientcredits->Process();
1184 theStats::CalculateRates();
1186 if (msCur-msPrevHist > 1000) {
1187 // unlike the other loop counters in this function this one will sometimes
1188 // produce two calls in quick succession (if there was a gap of more than one
1189 // second between calls to TimerProc) - this is intentional! This way the
1190 // history list keeps an average of one node per second and gets thinned out
1191 // correctly as time progresses.
1192 msPrevHist += 1000;
1194 m_statistics->RecordHistory();
1199 if (msCur-msPrev1 > 1000) { // approximately every second
1200 msPrev1 = msCur;
1201 clientcredits->Process();
1202 clientlist->Process();
1204 // Publish files to server if needed.
1205 sharedfiles->Process();
1207 if( Kademlia::CKademlia::IsRunning() ) {
1208 Kademlia::CKademlia::Process();
1209 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1210 StopKad();
1211 clientudp->Close();
1212 clientudp->Open();
1213 if (thePrefs::Reconnect()) {
1214 StartKad();
1219 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1220 serverconnect->TryAnotherConnectionrequest();
1222 if (serverconnect->IsConnecting()) {
1223 serverconnect->CheckForTimeout();
1225 listensocket->UpdateConnectionsStatus();
1230 if (msCur-msPrev5 > 5000) { // every 5 seconds
1231 msPrev5 = msCur;
1232 listensocket->Process();
1235 if (msCur-msPrevSave >= 60000) {
1236 msPrevSave = msCur;
1237 theStats::Save();
1240 // Special
1241 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1242 OnlineSig(); // Added By Bouc7
1243 msPrevOS = msCur;
1246 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1247 // Save Shared Files data
1248 knownfiles->Save();
1249 msPrevKnownMet = msCur;
1253 // Recomended by lugdunummaster himself - from emule 0.30c
1254 serverconnect->KeepConnectionAlive();
1256 // Disarm recursion protection
1257 recurse = false;
1261 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1263 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1265 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1266 CKnownFile* result = evt.GetResult();
1268 if (owner) {
1269 // Check if the partfile still exists, as it might have
1270 // been deleted in the mean time.
1271 if (downloadqueue->IsPartFile(owner)) {
1272 // This cast must not be done before the IsPartFile
1273 // call, as dynamic_cast will barf on dangling pointers.
1274 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1276 } else {
1277 static uint64 bytecount = 0;
1279 if (knownfiles->SafeAddKFile(result, true)) {
1280 AddDebugLogLineN(logKnownFiles,
1281 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1282 sharedfiles->SafeAddKFile(result);
1284 bytecount += result->GetFileSize();
1285 // If we have added files with a total size of ~3000mb
1286 if (bytecount >= wxULL(3145728000)) {
1287 AddDebugLogLineN(logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1288 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1289 knownfiles->Save();
1290 bytecount = 0;
1293 } else {
1294 AddDebugLogLineN(logKnownFiles,
1295 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1296 delete result;
1302 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1304 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1306 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1307 CScopedPtr<CKnownFile> result(evt.GetResult());
1309 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1310 CAICHHashSet* oldSet = owner->GetAICHHashset();
1311 CAICHHashSet* newSet = result->GetAICHHashset();
1313 owner->SetAICHHashset(newSet);
1314 newSet->SetOwner(owner);
1316 result->SetAICHHashset(oldSet);
1317 oldSet->SetOwner(result.get());
1322 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1324 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1325 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1326 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1328 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1329 if (evt.ErrorOccured()) {
1330 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1333 // Check if we should execute an script/app/whatever.
1334 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1337 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1339 CPartFile *file = evt.GetFile();
1340 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1341 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1343 file->SetStatus(PS_EMPTY);
1345 if (evt.Succeeded()) {
1346 if (evt.IsPaused()) {
1347 file->StopFile();
1348 } else {
1349 file->ResumeFile();
1351 } else {
1352 AddLogLineN(CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1353 file->StopFile();
1356 file->AllocationFinished();
1359 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1361 #ifdef AMULE_DAEMON
1362 evt.Notify();
1363 #else
1364 if (theApp->amuledlg) {
1365 evt.Notify();
1367 #endif
1371 void CamuleApp::ShutDown()
1373 // Just in case
1374 PlatformSpecific::AllowSleepMode();
1376 // Log
1377 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has started."));
1379 // Signal the hashing thread to terminate
1380 m_app_state = APP_STATE_SHUTTINGDOWN;
1382 // Stop ASIO thread
1383 #ifdef ASIO_SOCKETS // only needed to suppress the log message in non-Asio build
1384 AddDebugLogLineN(logGeneral, wxT("Terminate ASIO thread."));
1385 m_AsioService->Stop();
1386 #endif
1388 StopKad();
1390 // Kry - Save the sources seeds on app exit
1391 if (thePrefs::GetSrcSeedsOn()) {
1392 downloadqueue->SaveSourceSeeds();
1395 OnlineSig(true); // Added By Bouc7
1397 // Exit HTTP downloads
1398 CHTTPDownloadThread::StopAll();
1400 // Exit thread scheduler and upload thread
1401 CThreadScheduler::Terminate();
1403 AddDebugLogLineN(logGeneral, wxT("Terminate upload thread."));
1404 uploadBandwidthThrottler->EndThread();
1406 // Close sockets to avoid new clients coming in
1407 if (listensocket) {
1408 listensocket->Close();
1409 listensocket->KillAllSockets();
1412 if (serverconnect) {
1413 serverconnect->Disconnect();
1416 ECServerHandler->KillAllSockets();
1418 #ifdef ENABLE_UPNP
1419 if (thePrefs::GetUPnPEnabled()) {
1420 if (m_upnp) {
1421 m_upnp->DeletePortMappings(m_upnpMappings);
1424 #endif
1426 // saving data & stuff
1427 if (knownfiles) {
1428 knownfiles->Save();
1431 theStats::Save();
1433 CPath configFileName = CPath(thePrefs::GetConfigDir() + m_configFile);
1434 CPath::BackupFile(configFileName, wxT(".bak"));
1436 if (clientlist) {
1437 clientlist->DeleteAll();
1440 // Log
1441 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1445 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1447 if ( serverlist->AddServer(srv, fromUser) ) {
1448 Notify_ServerAdd(srv);
1449 return true;
1451 return false;
1455 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1457 if (m_dwPublicIP == 0) {
1458 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1459 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1460 } else {
1461 return ignorelocal ? 0 : m_localip;
1465 return m_dwPublicIP;
1469 void CamuleApp::SetPublicIP(const uint32 dwIP)
1471 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1473 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1474 m_dwPublicIP = dwIP;
1475 serverlist->CheckForExpiredUDPKeys();
1476 } else {
1477 m_dwPublicIP = dwIP;
1482 wxString CamuleApp::GetLog(bool reset)
1484 wxFile logfile;
1485 logfile.Open(thePrefs::GetConfigDir() + wxT("logfile"));
1486 if ( !logfile.IsOpened() ) {
1487 return _("ERROR: can't open logfile");
1489 int len = logfile.Length();
1490 if ( len == 0 ) {
1491 return _("WARNING: logfile is empty. Something is wrong.");
1493 char *tmp_buffer = new char[len + sizeof(wxChar)];
1494 logfile.Read(tmp_buffer, len);
1495 memset(tmp_buffer + len, 0, sizeof(wxChar));
1497 // try to guess file format
1498 wxString str;
1499 if (tmp_buffer[0] && tmp_buffer[1]) {
1500 str = wxString(UTF82unicode(tmp_buffer));
1501 } else {
1502 str = wxWCharBuffer((wchar_t *)tmp_buffer);
1505 delete [] tmp_buffer;
1506 if ( reset ) {
1507 theLogger.CloseLogfile();
1508 if (theLogger.OpenLogfile(thePrefs::GetConfigDir() + wxT("logfile"))) {
1509 AddLogLineN(_("Log has been reset"));
1511 ECServerHandler->ResetAllLogs();
1513 return str;
1517 wxString CamuleApp::GetServerLog(bool reset)
1519 wxString ret = server_msg;
1520 if ( reset ) {
1521 server_msg.Clear();
1523 return ret;
1526 wxString CamuleApp::GetDebugLog(bool reset)
1528 return GetLog(reset);
1532 void CamuleApp::AddServerMessageLine(wxString &msg)
1534 server_msg += msg + wxT("\n");
1535 AddLogLineN(CFormat(_("ServerMessage: %s")) % msg);
1540 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1542 switch (event.GetInt()) {
1543 case HTTP_IPFilter:
1544 ipfilter->DownloadFinished(event.GetExtraLong());
1545 break;
1546 case HTTP_ServerMet:
1547 if (serverlist->DownloadFinished(event.GetExtraLong()) && !IsConnectedED2K()) {
1548 // If successfully downloaded a server list, and are not connected at the moment, try to connect.
1549 // This happens when no server met is available on startup.
1550 serverconnect->ConnectToAnyServer();
1552 break;
1553 case HTTP_ServerMetAuto:
1554 serverlist->AutoDownloadFinished(event.GetExtraLong());
1555 break;
1556 case HTTP_VersionCheck:
1557 CheckNewVersion(event.GetExtraLong());
1558 break;
1559 case HTTP_NodesDat:
1560 if (event.GetExtraLong() == HTTP_Success) {
1562 wxString file = thePrefs::GetConfigDir() + wxT("nodes.dat");
1563 if (wxFileExists(file)) {
1564 wxRemoveFile(file);
1567 if ( Kademlia::CKademlia::IsRunning() ) {
1568 Kademlia::CKademlia::Stop();
1571 wxRenameFile(file + wxT(".download"),file);
1573 Kademlia::CKademlia::Start();
1574 theApp->ShowConnectionState();
1575 // cppcheck-suppress duplicateBranch
1576 } else if (event.GetExtraLong() == HTTP_Skipped) {
1577 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1578 } else {
1579 AddLogLineC(_("Failed to download the nodes list."));
1581 break;
1582 #ifdef ENABLE_IP2COUNTRY
1583 case HTTP_GeoIP:
1584 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1585 // If we updated, the dialog is already up. Redraw it to show the flags.
1586 theApp->amuledlg->Refresh();
1587 break;
1588 #endif
1592 void CamuleApp::CheckNewVersion(uint32 result)
1594 if (result == HTTP_Success) {
1595 wxString filename = thePrefs::GetConfigDir() + wxT("last_version_check");
1596 wxTextFile file;
1598 if (!file.Open(filename)) {
1599 AddLogLineC(_("Failed to open the downloaded version check file") );
1600 return;
1601 } else if (!file.GetLineCount()) {
1602 AddLogLineC(_("Corrupted version check file"));
1603 } else {
1604 wxString versionLine = file.GetFirstLine();
1605 wxStringTokenizer tkz(versionLine, wxT("."));
1607 AddDebugLogLineN(logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1609 long fields[] = {0, 0, 0};
1610 for (int i = 0; i < 3; ++i) {
1611 if (!tkz.HasMoreTokens()) {
1612 AddLogLineC(_("Corrupted version check file"));
1613 return;
1614 } else {
1615 wxString token = tkz.GetNextToken();
1617 if (!token.ToLong(&fields[i])) {
1618 AddLogLineC(_("Corrupted version check file"));
1619 return;
1624 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1625 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1627 if (curVer < newVer) {
1628 AddLogLineC(_("You are using an outdated version of aMule!"));
1629 // cppcheck-suppress zerodiv
1630 AddLogLineN(CFormat(_("Your aMule version is %i.%i.%i and the latest version is %li.%li.%li")) % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1631 AddLogLineN(_("The latest version can always be found at http://www.amule.org"));
1632 #ifdef AMULE_DAEMON
1633 AddLogLineCS(CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1634 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1635 #endif
1636 } else {
1637 AddLogLineN(_("Your copy of aMule is up to date."));
1641 file.Close();
1642 wxRemoveFile(filename);
1643 } else {
1644 AddLogLineC(_("Failed to download the version check file"));
1650 bool CamuleApp::IsConnected() const
1652 return (IsConnectedED2K() || IsConnectedKad());
1656 bool CamuleApp::IsConnectedED2K() const
1658 return serverconnect && serverconnect->IsConnected();
1662 bool CamuleApp::IsConnectedKad() const
1664 return Kademlia::CKademlia::IsConnected();
1668 bool CamuleApp::IsFirewalled() const
1670 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1671 return false; // we have an eD2K HighID -> not firewalled
1674 return IsFirewalledKad(); // If kad says ok, it's ok.
1677 bool CamuleApp::IsFirewalledKad() const
1679 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1680 || Kademlia::CKademlia::IsFirewalled();
1683 bool CamuleApp::IsFirewalledKadUDP() const
1685 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1686 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1689 bool CamuleApp::IsKadRunning() const
1691 return Kademlia::CKademlia::IsRunning();
1694 bool CamuleApp::IsKadRunningInLanMode() const
1696 return Kademlia::CKademlia::IsRunningInLANMode();
1699 // Kad stats
1700 uint32 CamuleApp::GetKadUsers() const
1702 return Kademlia::CKademlia::GetKademliaUsers();
1705 uint32 CamuleApp::GetKadFiles() const
1707 return Kademlia::CKademlia::GetKademliaFiles();
1710 uint32 CamuleApp::GetKadIndexedSources() const
1712 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1715 uint32 CamuleApp::GetKadIndexedKeywords() const
1717 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1720 uint32 CamuleApp::GetKadIndexedNotes() const
1722 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1725 uint32 CamuleApp::GetKadIndexedLoad() const
1727 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1731 // True IP of machine
1732 uint32 CamuleApp::GetKadIPAdress() const
1734 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1737 // Buddy status
1738 uint8 CamuleApp::GetBuddyStatus() const
1740 return clientlist->GetBuddyStatus();
1743 uint32 CamuleApp::GetBuddyIP() const
1745 return clientlist->GetBuddyIP();
1748 uint32 CamuleApp::GetBuddyPort() const
1750 return clientlist->GetBuddyPort();
1753 const Kademlia::CUInt128& CamuleApp::GetKadID() const
1755 return Kademlia::CKademlia::GetKadID();
1758 bool CamuleApp::CanDoCallback(uint32 clientServerIP, uint16 clientServerPort)
1760 if (Kademlia::CKademlia::IsConnected()) {
1761 if (IsConnectedED2K()) {
1762 if (serverconnect->IsLowID()) {
1763 if (Kademlia::CKademlia::IsFirewalled()) {
1764 //Both Connected - Both Firewalled
1765 return false;
1766 } else {
1767 if (clientServerIP == theApp->serverconnect->GetCurrentServer()->GetIP() &&
1768 clientServerPort == theApp->serverconnect->GetCurrentServer()->GetPort()) {
1769 // Both Connected - Server lowID, Kad Open - Client on same server
1770 // We prevent a callback to the server as this breaks the protocol
1771 // and will get you banned.
1772 return false;
1773 } else {
1774 // Both Connected - Server lowID, Kad Open - Client on remote server
1775 return true;
1778 } else {
1779 //Both Connected - Server HighID, Kad don't care
1780 return true;
1782 } else {
1783 if (Kademlia::CKademlia::IsFirewalled()) {
1784 //Only Kad Connected - Kad Firewalled
1785 return false;
1786 } else {
1787 //Only Kad Conected - Kad Open
1788 return true;
1791 } else {
1792 if (IsConnectedED2K()) {
1793 if (serverconnect->IsLowID()) {
1794 //Only Server Connected - Server LowID
1795 return false;
1796 } else {
1797 //Only Server Connected - Server HighID
1798 return true;
1800 } else {
1801 //We are not connected at all!
1802 return false;
1807 void CamuleApp::ShowUserCount() {
1808 uint32 totaluser = 0, totalfile = 0;
1810 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
1812 wxString buffer;
1814 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
1815 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
1817 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1818 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1819 } else if (thePrefs::GetNetworkED2K()) {
1820 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
1821 } else if (thePrefs::GetNetworkKademlia()) {
1822 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1823 } else {
1824 buffer = _("No networks selected");
1827 Notify_ShowUserCount(buffer);
1831 #ifndef ASIO_SOCKETS
1832 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
1834 { wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket")); }
1835 { wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
1836 wxT("Invalid event received for listen-socket")); }
1838 if (m_app_state == APP_STATE_RUNNING) {
1839 listensocket->OnAccept();
1840 } else if (m_app_state == APP_STATE_STARTING) {
1841 // When starting up, connection may be made before we are able
1842 // to handle them. However, if these are ignored, no futher
1843 // connection-events will be triggered, so we have to accept it.
1844 CLibSocket* socket = listensocket->Accept(false);
1846 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
1848 socket->Destroy();
1851 #endif
1854 void CamuleApp::ShowConnectionState(bool forceUpdate)
1856 static uint8 old_state = (1<<7); // This flag doesn't exist
1858 uint8 state = 0;
1860 if (theApp->serverconnect->IsConnected()) {
1861 state |= CONNECTED_ED2K;
1864 if (Kademlia::CKademlia::IsRunning()) {
1865 if (Kademlia::CKademlia::IsConnected()) {
1866 if (!Kademlia::CKademlia::IsFirewalled()) {
1867 state |= CONNECTED_KAD_OK;
1868 } else {
1869 state |= CONNECTED_KAD_FIREWALLED;
1871 } else {
1872 state |= CONNECTED_KAD_NOT;
1876 if (old_state != state) {
1877 // Get the changed value
1878 int changed_flags = old_state ^ state;
1880 if (changed_flags & CONNECTED_ED2K) {
1881 // ED2K status changed
1882 wxString connected_server;
1883 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
1884 if (ed2k_server) {
1885 connected_server = ed2k_server->GetListName();
1887 if (state & CONNECTED_ED2K) {
1888 // We connected to some server
1889 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
1891 AddLogLineC(CFormat(_("Connected to %s %s")) % connected_server % id);
1892 } else {
1893 // cppcheck-suppress duplicateBranch
1894 if ( theApp->serverconnect->IsConnecting() ) {
1895 AddLogLineC(CFormat(_("Connecting to %s")) % connected_server);
1896 } else {
1897 AddLogLineC(_("Disconnected from eD2k"));
1902 if (changed_flags & CONNECTED_KAD_NOT) {
1903 // cppcheck-suppress duplicateBranch
1904 if (state & CONNECTED_KAD_NOT) {
1905 AddLogLineC(_("Kad started."));
1906 } else {
1907 AddLogLineC(_("Kad stopped."));
1911 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1912 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1913 // cppcheck-suppress duplicateBranch
1914 if (state & CONNECTED_KAD_OK) {
1915 AddLogLineC(_("Connected to Kad (ok)"));
1916 } else {
1917 AddLogLineC(_("Connected to Kad (firewalled)"));
1919 } else {
1920 AddLogLineC(_("Disconnected from Kad"));
1924 old_state = state;
1926 theApp->downloadqueue->OnConnectionState(IsConnected());
1929 ShowUserCount();
1930 Notify_ShowConnState(forceUpdate);
1934 #ifndef ASIO_SOCKETS
1935 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
1937 CMuleUDPSocket* socket = reinterpret_cast<CMuleUDPSocket*>(event.GetClientData());
1938 wxCHECK_RET(socket, wxT("No socket owner specified."));
1940 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1942 if (!IsRunning()) {
1943 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
1944 // Back to the queue!
1945 theApp->AddPendingEvent(event);
1946 return;
1950 switch (event.GetSocketEvent()) {
1951 case wxSOCKET_INPUT:
1952 socket->OnReceive(0);
1953 break;
1955 case wxSOCKET_OUTPUT:
1956 socket->OnSend(0);
1957 break;
1959 case wxSOCKET_LOST:
1960 socket->OnDisconnected(0);
1961 break;
1963 default:
1964 wxFAIL;
1965 break;
1968 #endif
1971 void CamuleApp::OnUnhandledException()
1973 // Call the generic exception-handler.
1974 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1975 ::OnUnhandledException();
1978 void CamuleApp::StartKad()
1980 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1981 // Kad makes no sense without the Client-UDP socket.
1982 if (!thePrefs::IsUDPDisabled()) {
1983 if (ipfilter->IsReady()) {
1984 Kademlia::CKademlia::Start();
1985 } else {
1986 ipfilter->StartKADWhenReady();
1988 } else {
1989 AddLogLineC(_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1991 } else if (!thePrefs::GetNetworkKademlia()) {
1992 AddLogLineC(_("Kad network disabled on preferences, not connecting."));
1996 void CamuleApp::StopKad()
1998 // Stop Kad if it's running
1999 if (Kademlia::CKademlia::IsRunning()) {
2000 Kademlia::CKademlia::Stop();
2005 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
2007 if (!Kademlia::CKademlia::IsRunning()) {
2008 Kademlia::CKademlia::Start();
2009 theApp->ShowConnectionState();
2012 Kademlia::CKademlia::Bootstrap(ip, port);
2016 void CamuleApp::UpdateNotesDat(const wxString& url)
2018 wxString strTempFilename(thePrefs::GetConfigDir() + wxT("nodes.dat.download"));
2020 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, thePrefs::GetConfigDir() + wxT("nodes.dat"), HTTP_NodesDat, true, false);
2021 downloader->Create();
2022 downloader->Run();
2026 void CamuleApp::DisconnectED2K()
2028 // Stop ED2K if it's running
2029 if (IsConnectedED2K()) {
2030 serverconnect->Disconnect();
2034 bool CamuleApp::CryptoAvailable() const
2036 return clientcredits && clientcredits->CryptoAvailable();
2039 uint32 CamuleApp::GetED2KID() const {
2040 return serverconnect ? serverconnect->GetClientID() : 0;
2043 uint32 CamuleApp::GetID() const {
2044 uint32 ID;
2046 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2047 // We trust Kad above ED2K
2048 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2049 } else if( theApp->serverconnect->IsConnected() ) {
2050 ID = theApp->serverconnect->GetClientID();
2051 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2052 // A firewalled Kad client get's a "1"
2053 ID = 1;
2054 } else {
2055 ID = 0;
2058 return ID;
2061 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2062 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2063 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2064 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2065 // File_checked_for_headers