2 // This file is part of the aMule Project.
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 )
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
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.
31 #include <wx/process.h>
32 #include <wx/sstream.h>
35 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
36 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
40 #include <common/ClientVersion.h>
42 #include <wx/cmdline.h> // Needed for wxCmdLineParser
43 #include <wx/config.h> // Do_not_auto_remove (win32)
44 #include <wx/fileconf.h>
45 #include <wx/socket.h>
46 #include <wx/tokenzr.h>
47 #include <wx/wfstream.h>
50 #include <common/Format.h> // Needed for CFormat
51 #include "kademlia/kademlia/Kademlia.h"
52 #include "kademlia/kademlia/Prefs.h"
53 #include "kademlia/kademlia/UDPFirewallTester.h"
54 #include "CanceledFileList.h"
55 #include "ClientCreditsList.h" // Needed for CClientCreditsList
56 #include "ClientList.h" // Needed for CClientList
57 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
58 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
59 #include <common/FileFunctions.h> // Needed for CDirIterator
60 #include "FriendList.h" // Needed for CFriendList
61 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
62 #include "InternalEvents.h" // Needed for CMuleInternalEvent
63 #include "IPFilter.h" // Needed for CIPFilter
64 #include "KnownFileList.h" // Needed for CKnownFileList
65 #include "ListenSocket.h" // Needed for CListenSocket
66 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
67 #include "MagnetURI.h" // Needed for CMagnetURI
68 #include "OtherFunctions.h"
69 #include "PartFile.h" // Needed for CPartFile
70 #include "PlatformSpecific.h" // Needed for PlatformSpecific::AllowSleepMode();
71 #include "Preferences.h" // Needed for CPreferences
72 #include "SearchList.h" // Needed for CSearchList
73 #include "Server.h" // Needed for GetListName
74 #include "ServerList.h" // Needed for CServerList
75 #include "ServerConnect.h" // Needed for CServerConnect
76 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
77 #include "Statistics.h" // Needed for CStatistics
78 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
79 #include "ThreadTasks.h"
80 #include "UploadQueue.h" // Needed for CUploadQueue
81 #include "UploadBandwidthThrottler.h"
82 #include "UserEvents.h"
83 #include "ScopedPtr.h"
86 #include "UPnPBase.h" // Needed for UPnP
90 #include <wx/sysopt.h> // Do_not_auto_remove
95 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
96 #if wxCHECK_VERSION(2, 9, 0)
97 #include <wx/osx/core/cfstring.h> // Do_not_auto_remove
99 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
102 #include <wx/msgdlg.h>
104 #include "amuleDlg.h"
108 #ifdef HAVE_SYS_RESOURCE_H
109 #include <sys/resource.h>
112 #ifdef HAVE_SYS_STATVFS_H
113 #include <sys/statvfs.h> // Do_not_auto_remove
118 # define RLIMIT_RESOURCE __rlimit_resource
120 # define RLIMIT_RESOURCE int
124 CamuleDaemonApp
*theApp
;
126 CamuleGuiApp
*theApp
;
129 static void UnlimitResource(RLIMIT_RESOURCE resType
)
131 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
133 getrlimit(resType
, &rl
);
134 rl
.rlim_cur
= rl
.rlim_max
;
135 setrlimit(resType
, &rl
);
140 static void SetResourceLimits()
142 #ifdef HAVE_SYS_RESOURCE_H
143 UnlimitResource(RLIMIT_DATA
);
145 UnlimitResource(RLIMIT_FSIZE
);
147 UnlimitResource(RLIMIT_NOFILE
);
149 UnlimitResource(RLIMIT_RSS
);
154 // We store the received signal in order to avoid race-conditions
155 // in the signal handler.
156 bool g_shutdownSignal
= false;
158 void OnShutdownSignal( int /* sig */ )
160 signal(SIGINT
, SIG_DFL
);
161 signal(SIGTERM
, SIG_DFL
);
163 g_shutdownSignal
= true;
166 theApp
->ExitMainLoop();
171 CamuleApp::CamuleApp()
173 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
174 // Kry - I love to init the vars on init, even before timer.
178 m_app_state
= APP_STATE_STARTING
;
180 theApp
= &wxGetApp();
185 canceledfiles
= NULL
;
187 serverconnect
= NULL
;
191 clientcredits
= NULL
;
193 downloadqueue
= NULL
;
196 ECServerHandler
= NULL
;
199 uploadBandwidthThrottler
= NULL
;
202 m_upnpMappings
.resize(4);
210 enable_daemon_fork
= false;
212 // Apprently needed for *BSD
216 _CrtSetDbgFlag(0); // Disable useless memleak debugging
220 CamuleApp::~CamuleApp()
222 // Closing the log-file as the very last thing, since
223 // wxWidgets log-events are saved in it as well.
224 theLogger
.CloseLogfile();
227 int CamuleApp::OnExit()
229 if (m_app_state
!=APP_STATE_STARTING
) {
230 AddLogLineNS(_("Now, exiting main app..."));
233 // From wxWidgets docs, wxConfigBase:
235 // Note that you must delete this object (usually in wxApp::OnExit)
236 // in order to avoid memory leaks, wxWidgets won't do it automatically.
238 // As it happens, you may even further simplify the procedure described
239 // above: you may forget about calling Set(). When Get() is called and
240 // there is no current object, it will create one using Create() function.
241 // To disable this behaviour DontCreateOnDemand() is provided.
242 delete wxConfigBase::Set((wxConfigBase
*)NULL
);
245 clientcredits
->SaveList();
247 // Kill amuleweb if running
249 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid '%ld' ... ")) % webserver_pid
);
251 if (wxKill(webserver_pid
, wxSIGTERM
, &rc
) == -1) {
252 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid '%ld' ... ")) % webserver_pid
);
253 if (wxKill(webserver_pid
, wxSIGKILL
, &rc
) == -1) {
254 AddLogLineNS(_("Failed"));
259 if (m_app_state
!=APP_STATE_STARTING
) {
260 AddLogLineNS(_("aMule OnExit: Terminating core."));
269 delete clientcredits
;
270 clientcredits
= NULL
;
275 // Destroying CDownloadQueue calls destructor for CPartFile
276 // calling CSharedFileList::SafeAddKFile occasionally.
280 delete serverconnect
;
281 serverconnect
= NULL
;
292 delete canceledfiles
;
293 canceledfiles
= NULL
;
301 delete downloadqueue
;
302 downloadqueue
= NULL
;
312 delete ECServerHandler
;
313 ECServerHandler
= NULL
;
320 CPreferences::EraseItemList();
322 delete uploadBandwidthThrottler
;
323 uploadBandwidthThrottler
= NULL
;
326 delete m_AsioService
;
327 m_AsioService
= NULL
;
330 wxSocketBase::Shutdown(); // needed because we also called Initialize() manually
332 if (m_app_state
!=APP_STATE_STARTING
) {
333 AddLogLineNS(_("aMule shutdown completed."));
336 #if wxUSE_MEMORY_TRACING
337 AddLogLineNS(_("Memory debug results for aMule exit:"));
338 // Log mem debug mesages to wxLogStderr
339 wxLog
* oldLog
= wxLog::SetActiveTarget(new wxLogStderr
);
340 //AddLogLineNS(wxT("**************Classes**************");
341 //wxDebugContext::PrintClasses();
342 //AddLogLineNS(wxT("***************Dump***************");
343 //wxDebugContext::Dump();
344 AddLogLineNS(wxT("***************Stats**************"));
345 wxDebugContext::PrintStatistics(true);
347 // Set back to wxLogGui
348 delete wxLog::SetActiveTarget(oldLog
);
353 // Return 0 for succesful program termination
354 return AMULE_APP_BASE::OnExit();
358 int CamuleApp::InitGui(bool, wxString
&)
365 // Application initialization
367 bool CamuleApp::OnInit()
369 #if wxUSE_MEMORY_TRACING
370 // any text before call of Localize_mule needs not to be translated.
371 AddLogLineNS(wxT("Checkpoint set on app init for memory debug")); // debug output
372 wxDebugContext::SetCheckpoint();
375 // Forward wxLog events to CLogger
376 wxLog::SetActiveTarget(new CLoggerTarget
);
378 m_localip
= StringHosttoUint32(::wxGetFullHostName());
381 // get rid of sigpipe
382 signal(SIGPIPE
, SIG_IGN
);
385 signal(SIGBREAK
, OnShutdownSignal
);
387 // Handle sigint and sigterm
388 signal(SIGINT
, OnShutdownSignal
);
389 signal(SIGTERM
, OnShutdownSignal
);
392 // For listctrl's to behave on Mac
393 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
396 // Handle uncaught exceptions
397 InstallMuleExceptionHandler();
399 if (!InitCommon(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
)) {
403 glob_prefs
= new CPreferences();
406 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), thePrefs::GetConfigDir() + wxT("Temp"), outDir
)) {
407 thePrefs::SetTempDir(outDir
);
412 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), thePrefs::GetConfigDir() + wxT("Incoming"), outDir
)) {
413 thePrefs::SetIncomingDir(outDir
);
418 // Initialize wx sockets (needed for http download in background with Asio sockets)
419 wxSocketBase::Initialize();
422 if (!thePrefs::UseTrayIcon()) {
423 thePrefs::SetMinToTray(false);
426 // Build the filenames for the two OS files
427 SetOSFiles(thePrefs::GetOSDir().GetRaw());
429 // Check if we have the old style locale config
430 bool old_localedef
= false;
431 wxString langId
= thePrefs::GetLanguageID();
432 if (!langId
.IsEmpty() && (langId
.GetChar(0) >= '0' && langId
.GetChar(0) <= '9')) {
433 old_localedef
= true;
434 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT
));
439 // Load localization settings
443 ShowAlert(_("Your locale has been changed to System Default due to a configuration change. Sorry."), _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
447 // Configure EC for amuled when invoked with ec-config
449 AddLogLineNS(_("\nEC configuration"));
450 thePrefs::SetECPass(GetPassword(false).Encode());
451 thePrefs::EnableExternalConnections(true);
452 AddLogLineNS(_("Password set and external connections enabled."));
458 wxT("Warning! You are running aMule as root.\n")
459 wxT("Doing so is not recommended for security reasons,\n")
460 wxT("and you are advised to run aMule as an normal\n")
461 wxT("user instead.");
463 ShowAlert(msg
, _("WARNING"), wxCENTRE
| wxOK
| wxICON_ERROR
);
465 fprintf(stderr
, "\n--------------------------------------------------\n");
466 fprintf(stderr
, "%s", (const char*)unicode2UTF8(msg
));
467 fprintf(stderr
, "\n--------------------------------------------------\n\n");
471 // Display notification on new version or first run
472 wxTextFile
vfile( thePrefs::GetConfigDir() + wxT("lastversion") );
473 wxString
newMule(wxT( VERSION
));
475 if ( !wxFileExists( vfile
.GetName() ) ) {
479 if ( vfile
.Open() ) {
480 // Check if this version has been run before
482 for ( size_t i
= 0; i
< vfile
.GetLineCount(); i
++ ) {
483 // Check if this version has been run before
484 if ( vfile
.GetLine(i
) == newMule
) {
490 // We havent run this version before?
492 // Insert new at top to provide faster searches
493 vfile
.InsertLine( newMule
, 0 );
495 Trigger_New_version( newMule
);
498 // Keep at most 10 entires
499 while ( vfile
.GetLineCount() > 10 )
500 vfile
.RemoveLine( vfile
.GetLineCount() - 1 );
506 m_statistics
= new CStatistics();
508 clientlist
= new CClientList();
509 friendlist
= new CFriendList();
510 searchlist
= new CSearchList();
511 knownfiles
= new CKnownFileList();
512 canceledfiles
= new CCanceledFileList
;
513 serverlist
= new CServerList();
515 sharedfiles
= new CSharedFileList(knownfiles
);
516 clientcredits
= new CClientCreditsList();
518 // bugfix - do this before creating the uploadqueue
519 downloadqueue
= new CDownloadQueue();
520 uploadqueue
= new CUploadQueue();
521 ipfilter
= new CIPFilter();
523 // Creates all needed listening sockets
525 if (!ReinitializeNetwork(&msg
)) {
526 AddLogLineNS(wxT("\n"));
530 // Test if there's any new version
531 if (thePrefs::GetCheckNewVersion()) {
532 // We use the thread base because I don't want a dialog to pop up.
533 CHTTPDownloadThread
* version_check
=
534 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
535 thePrefs::GetConfigDir() + wxT("last_version_check"), thePrefs::GetConfigDir() + wxT("last_version"), HTTP_VersionCheck
, false, false);
536 version_check
->Create();
537 version_check
->Run();
540 // Create main dialog, or fork to background (daemon).
541 InitGui(m_geometryEnabled
, m_geometryString
);
544 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
545 if (enable_daemon_fork
) {
546 RefreshSingleInstanceChecker();
547 // No need to check IsAnotherRunning() - we've done it before.
551 // Has to be created after the call to InitGui, as fork
552 // (when using posix threads) only replicates the mainthread,
553 // and the UBT constructor creates a thread.
554 uploadBandwidthThrottler
= new UploadBandwidthThrottler();
557 m_AsioService
= new CAsioService
;
560 // Start performing background tasks
561 // This will start loading the IP filter. It will start right away.
562 // Log is confusing, because log entries from background will only be printed
563 // once foreground becomes idle, and that will only be after loading
564 // of the partfiles has finished.
565 CThreadScheduler::Start();
567 // These must be initialized after the gui is loaded.
568 if (thePrefs::GetNetworkED2K()) {
571 downloadqueue
->LoadMetFiles(thePrefs::GetTempDir());
572 sharedfiles
->Reload();
574 // Ensure that the up/down ratio is used
575 CPreferences::CheckUlDlRatio();
577 // Load saved friendlist (now, so it can update in GUI right away)
578 friendlist
->LoadList();
580 // The user can start pressing buttons like mad if he feels like it.
581 m_app_state
= APP_STATE_RUNNING
;
583 if (!serverlist
->GetServerCount() && thePrefs::GetNetworkED2K()) {
584 // There are no servers and ED2K active -> ask for download.
585 // As we cannot ask in amuled, we just update there
587 if (wxYES
== wxMessageBox(
589 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
590 wxString(_("Server list download")),
592 static_cast<wxWindow
*>(theApp
->amuledlg
)))
595 serverlist
->UpdateServerMetFromURL(thePrefs::GetEd2kServersUrl());
600 // Autoconnect if that option is enabled
601 if (thePrefs::DoAutoConnect()) {
602 // IP filter is still loading and will be finished on event.
603 // Tell it to autoconnect.
604 if (thePrefs::GetNetworkED2K()) {
605 ipfilter
->ConnectToAnyServerWhenReady();
607 if (thePrefs::GetNetworkKademlia()) {
608 ipfilter
->StartKADWhenReady();
613 #ifdef ENABLE_IP2COUNTRY
614 theApp
->amuledlg
->EnableIP2Country();
618 if (thePrefs::GetWSIsEnabled()) {
619 wxString aMuleConfigFile
= thePrefs::GetConfigDir() + m_configFile
;
620 wxString amulewebPath
= thePrefs::GetWSPath();
622 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
623 // For the Mac GUI application, look for amuleweb in the bundle
624 CFURLRef amulewebUrl
= CFBundleCopyAuxiliaryExecutableURL(
625 CFBundleGetMainBundle(), CFSTR("amuleweb"));
628 CFURLRef absoluteUrl
= CFURLCopyAbsoluteURL(amulewebUrl
);
629 CFRelease(amulewebUrl
);
632 CFStringRef amulewebCfstr
= CFURLCopyFileSystemPath(absoluteUrl
, kCFURLPOSIXPathStyle
);
633 CFRelease(absoluteUrl
);
634 #if wxCHECK_VERSION(2, 9, 0)
635 amulewebPath
= wxCFStringRef(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
637 amulewebPath
= wxMacCFStringHolder(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
644 # define QUOTE wxT("\"")
646 # define QUOTE wxT("\'")
652 QUOTE
wxT(" ") QUOTE
wxT("--amule-config-file=") +
655 CTerminationProcessAmuleweb
*p
= new CTerminationProcessAmuleweb(cmd
, &webserver_pid
);
656 webserver_pid
= wxExecute(cmd
, wxEXEC_ASYNC
, p
);
657 bool webserver_ok
= webserver_pid
> 0;
659 AddLogLineC(CFormat(_("web server running on pid %d")) % webserver_pid
);
663 "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"),
664 _("ERROR"), wxOK
| wxICON_ERROR
);
671 bool CamuleApp::ReinitializeNetwork(wxString
* msg
)
674 static bool firstTime
= true;
677 // TODO: Destroy previously created sockets
681 // Some sanity checks first
682 if (thePrefs::ECPort() == thePrefs::GetPort()) {
683 // Select a random usable port in the range 1025 ... 2^16 - 1
684 uint16 port
= thePrefs::ECPort();
685 while ( port
< 1024 || port
== thePrefs::GetPort() ) {
686 port
= (uint16
)rand();
688 thePrefs::SetECPort( port
);
691 wxT("Network configuration failed! You cannot use the same port\n")
692 wxT("for the main TCP port and the External Connections port.\n")
693 wxT("The EC port has been changed to avoid conflict, see the\n")
694 wxT("preferences for the new value.\n");
697 AddLogLineN(wxEmptyString
);
699 AddLogLineN(wxEmptyString
);
704 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
705 // Select a random usable value in the range 1025 ... 2^16 - 1
706 uint16 port
= thePrefs::GetUDPPort();
707 while ( port
< 1024 || port
== thePrefs::GetPort() + 3 ) {
708 port
= (uint16
)rand();
710 thePrefs::SetUDPPort( port
);
713 wxT("Network configuration failed! You set your UDP port to\n")
714 wxT("the value of the main TCP port plus 3.\n")
715 wxT("This port has been reserved for the Server-UDP port. The\n")
716 wxT("port value has been changed to avoid conflict, see the\n")
717 wxT("preferences for the new value\n");
720 AddLogLineN(wxEmptyString
);
722 AddLogLineN(wxEmptyString
);
727 // Create the address where we are going to listen
728 // TODO: read this from configuration file
729 amuleIPV4Address myaddr
[4];
731 // Create the External Connections Socket.
733 // Get ready to handle connections from apps like amulecmd
734 if (thePrefs::GetECAddress().IsEmpty() || !myaddr
[0].Hostname(thePrefs::GetECAddress())) {
735 myaddr
[0].AnyAddress();
737 myaddr
[0].Service(thePrefs::ECPort());
738 ECServerHandler
= new ExternalConn(myaddr
[0], msg
);
740 // Create the UDP socket TCP+3.
741 // Used for source asking on servers.
742 if (thePrefs::GetAddress().IsEmpty()) {
743 myaddr
[1].AnyAddress();
744 } else if (!myaddr
[1].Hostname(thePrefs::GetAddress())) {
745 myaddr
[1].AnyAddress();
746 AddLogLineC(CFormat(_("Could not bind ports to the specified address: %s"))
747 % thePrefs::GetAddress());
750 wxString ip
= myaddr
[1].IPAddress();
751 myaddr
[1].Service(thePrefs::GetPort()+3);
752 serverconnect
= new CServerConnect(serverlist
, myaddr
[1]);
753 *msg
<< CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
754 % ip
% ((unsigned int)thePrefs::GetPort() + 3u);
756 // Create the ListenSocket (aMule TCP socket).
757 // Used for Client Port / Connections from other clients,
758 // Client to Client Source Exchange.
760 myaddr
[2] = myaddr
[1];
761 myaddr
[2].Service(thePrefs::GetPort());
762 listensocket
= new CListenSocket(myaddr
[2]);
763 *msg
<< CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
764 % ip
% (unsigned int)(thePrefs::GetPort());
765 // Notify(true) has already been called to the ListenSocket, so events may
766 // be already comming in.
767 if (!listensocket
->IsOk()) {
768 // If we wern't able to start listening, we need to warn the user
770 err
= CFormat(_("Port %u is not available. You will be LOWID\n")) %
771 (unsigned int)(thePrefs::GetPort());
776 _("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.")) %
777 (unsigned int)(thePrefs::GetPort());
778 ShowAlert(err
, _("ERROR"), wxOK
| wxICON_ERROR
);
781 // Create the UDP socket.
782 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
783 // Also used for Kademlia.
784 // Default is port 4672.
785 myaddr
[3] = myaddr
[1];
786 myaddr
[3].Service(thePrefs::GetUDPPort());
787 clientudp
= new CClientUDPSocket(myaddr
[3], thePrefs::GetProxyData());
788 if (!thePrefs::IsUDPDisabled()) {
789 *msg
<< CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
790 % ip
% thePrefs::GetUDPPort();
792 *msg
<< wxT("*** Client UDP socket (extended eMule) disabled on preferences");
796 if (thePrefs::GetUPnPEnabled()) {
798 m_upnpMappings
[0] = CUPnPPortMapping(
801 thePrefs::GetUPnPECEnabled(),
802 "aMule TCP External Connections Socket");
803 m_upnpMappings
[1] = CUPnPPortMapping(
806 thePrefs::GetUPnPEnabled(),
807 "aMule UDP socket (TCP+3)");
808 m_upnpMappings
[2] = CUPnPPortMapping(
811 thePrefs::GetUPnPEnabled(),
812 "aMule TCP Listen Socket");
813 m_upnpMappings
[3] = CUPnPPortMapping(
816 thePrefs::GetUPnPEnabled(),
817 "aMule UDP Extended eMule Socket");
818 m_upnp
= new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
819 m_upnp
->AddPortMappings(m_upnpMappings
);
820 } catch(CUPnPException
&e
) {
822 error_msg
<< e
.what();
823 AddLogLineC(error_msg
);
824 fprintf(stderr
, "%s\n", (const char *)unicode2char(error_msg
));
832 /* Original implementation by Bouc7 of the eMule Project.
833 aMule Signature idea was designed by BigBob and implemented
834 by Un-Thesis, with design inputs and suggestions from bothie.
836 void CamuleApp::OnlineSig(bool zero
/* reset stats (used on shutdown) */)
838 // Do not do anything if online signature is disabled in Preferences
839 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path
.IsEmpty()) {
840 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
841 // that means m_amulesig_path is empty too.
845 // Remove old signature files
846 if ( wxFileExists( m_emulesig_path
) ) { wxRemoveFile( m_emulesig_path
); }
847 if ( wxFileExists( m_amulesig_path
) ) { wxRemoveFile( m_amulesig_path
); }
850 wxTextFile amulesig_out
;
851 wxTextFile emulesig_out
;
853 // Open both files if needed
854 if ( !emulesig_out
.Create( m_emulesig_path
) ) {
855 AddLogLineC(_("Failed to create OnlineSig File"));
856 // Will never try again.
857 m_amulesig_path
.Clear();
858 m_emulesig_path
.Clear();
862 if ( !amulesig_out
.Create(m_amulesig_path
) ) {
863 AddLogLineC(_("Failed to create aMule OnlineSig File"));
864 // Will never try again.
865 m_amulesig_path
.Clear();
866 m_emulesig_path
.Clear();
870 wxString emulesig_string
;
874 emulesig_string
= wxT("0\xA0.0|0.0|0");
875 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
877 if (IsConnectedED2K()) {
879 temp
= CFormat(wxT("%d")) % serverconnect
->GetCurrentServer()->GetPort();
886 + serverconnect
->GetCurrentServer()->GetListName()
888 // IP and port of the server
889 + serverconnect
->GetCurrentServer()->GetFullIP()
896 // Connected. State 1, full info
897 amulesig_out
.AddLine(wxT("1"));
899 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetListName());
901 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetFullIP());
903 amulesig_out
.AddLine(temp
);
905 if (serverconnect
->IsLowID()) {
906 amulesig_out
.AddLine(wxT("L"));
908 amulesig_out
.AddLine(wxT("H"));
911 } else if (serverconnect
->IsConnecting()) {
912 emulesig_string
= wxT("0");
914 // Connecting. State 2, No info.
915 amulesig_out
.AddLine(wxT("2\n0\n0\n0\n0"));
917 // Not connected to a server
918 emulesig_string
= wxT("0");
920 // Not connected, state 0, no info
921 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0"));
923 if (IsConnectedKad()) {
924 if(Kademlia::CKademlia::IsFirewalled()) {
925 // Connected. Firewalled. State 1.
926 amulesig_out
.AddLine(wxT("1"));
928 // Connected. State 2.
929 amulesig_out
.AddLine(wxT("2"));
932 // Not connected.State 0.
933 amulesig_out
.AddLine(wxT("0"));
935 emulesig_string
+= wxT("\xA");
937 // Datarate for downloads
938 temp
= CFormat(wxT("%.1f")) % (theStats::GetDownloadRate() / 1024.0);
940 emulesig_string
+= temp
+ wxT("|");
941 amulesig_out
.AddLine(temp
);
943 // Datarate for uploads
944 temp
= CFormat(wxT("%.1f")) % (theStats::GetUploadRate() / 1024.0);
946 emulesig_string
+= temp
+ wxT("|");
947 amulesig_out
.AddLine(temp
);
949 // Number of users waiting for upload
950 temp
= CFormat(wxT("%d")) % theStats::GetWaitingUserCount();
952 emulesig_string
+= temp
;
953 amulesig_out
.AddLine(temp
);
955 // Number of shared files (not on eMule)
956 amulesig_out
.AddLine(CFormat(wxT("%d")) % theStats::GetSharedFileCount());
959 // eMule signature finished here. Write the line to the wxTextFile.
960 emulesig_out
.AddLine(emulesig_string
);
962 // Now for aMule signature extras
964 // Nick on the network
965 amulesig_out
.AddLine(thePrefs::GetUserNick());
967 // Total received in bytes
968 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalReceivedBytes());
970 // Total sent in bytes
971 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalSentBytes());
975 amulesig_out
.AddLine(wxT(VERSION
) wxT(" ") wxT(SVNDATE
));
977 amulesig_out
.AddLine(wxT(VERSION
));
981 amulesig_out
.AddLine(wxT("0"));
982 amulesig_out
.AddLine(wxT("0"));
983 amulesig_out
.AddLine(wxT("0"));
985 // Total received bytes in session
986 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
987 theStats::GetSessionReceivedBytes() );
989 // Total sent bytes in session
990 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
991 theStats::GetSessionSentBytes() );
994 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
998 emulesig_out
.Write();
999 amulesig_out
.Write();
1000 } //End Added By Bouc7
1003 #if wxUSE_ON_FATAL_EXCEPTION
1004 // Gracefully handle fatal exceptions and print backtrace if possible
1005 void CamuleApp::OnFatalException()
1007 /* Print the backtrace */
1009 msg
<< wxT("\n--------------------------------------------------------------------------------\n")
1010 << wxT("A fatal error has occurred and aMule has crashed.\n")
1011 << wxT("Please assist us in fixing this problem by posting the backtrace below in our\n")
1012 << wxT("'aMule Crashes' forum and include as much information as possible regarding the\n")
1013 << wxT("circumstances of this crash. The forum is located here:\n")
1014 << wxT(" http://forum.amule.org/index.php?board=67.0\n")
1015 << wxT("If possible, please try to generate a real backtrace of this crash:\n")
1016 << wxT(" http://wiki.amule.org/wiki/Backtraces\n\n")
1017 << wxT("----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n")
1018 << wxT("Current version is: ") << FullMuleVersion
1019 << wxT("\nRunning on: ") << OSDescription
1021 << get_backtrace(1) // 1 == skip this function.
1022 << wxT("\n--------------------------------------------------------------------------------\n");
1024 theLogger
.EmergencyLog(msg
, true);
1029 // Sets the localization of aMule
1030 void CamuleApp::Localize_mule()
1032 InitCustomLanguages();
1033 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
1034 if (!m_locale
.IsOk()) {
1035 AddLogLineN(_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1040 // Displays information related to important changes in aMule.
1041 // Is called when the user runs a new version of aMule
1042 void CamuleApp::Trigger_New_version(wxString new_version
)
1044 wxString info
= wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version
+ wxT(" ---\n\n");
1045 if (new_version
== wxT("SVN")) {
1046 info
+= _("This version is a testing version, updated daily, and\n");
1047 info
+= _("we give no warranty it won't break anything, burn your house,\n");
1048 info
+= _("or kill your dog. But it *should* be safe to use anyway.\n");
1053 info
+= _("More information, support and new releases can found at our homepage,\n");
1054 info
+= _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1056 info
+= _("Feel free to report any bugs to http://forum.amule.org");
1058 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
1062 void CamuleApp::SetOSFiles(const wxString
& new_path
)
1064 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1065 if ( ::wxDirExists(new_path
) ) {
1066 m_emulesig_path
= JoinPaths(new_path
, wxT("onlinesig.dat"));
1067 m_amulesig_path
= JoinPaths(new_path
, wxT("amulesig.dat"));
1069 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
);
1070 m_emulesig_path
.Clear();
1071 m_amulesig_path
.Clear();
1074 m_emulesig_path
.Clear();
1075 m_amulesig_path
.Clear();
1081 #ifndef wxUSE_STACKWALKER
1082 #define wxUSE_STACKWALKER 0
1084 void CamuleApp::OnAssertFailure(const wxChar
* file
, int line
,
1085 const wxChar
* func
, const wxChar
* cond
, const wxChar
* msg
)
1087 wxString errmsg
= CFormat( wxT("Assertion failed: %s:%s:%d: Assertion '%s' failed. %s\nBacktrace follows:\n%s\n") )
1088 % file
% func
% line
% cond
% ( msg
? msg
: wxT("") )
1089 % get_backtrace(2); // Skip the function-calls directly related to the assert call.
1090 theLogger
.EmergencyLog(errmsg
, false);
1092 if (wxThread::IsMain() && IsRunning()) {
1093 AMULE_APP_BASE::OnAssertFailure(file
, line
, func
, cond
, msg
);
1096 wxString s
= CFormat(wxT("%s in %s")) % cond
% func
;
1098 s
<< wxT(" : ") << msg
;
1100 _wassert(s
.wc_str(), file
, line
);
1102 // Abort, allows gdb to catch the assertion
1110 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent
& evt
)
1112 CServerUDPSocket
* socket
=reinterpret_cast<CServerUDPSocket
*>(evt
.GetClientData());
1113 socket
->OnHostnameResolved(evt
.GetExtraLong());
1117 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent
& evt
)
1119 downloadqueue
->OnHostnameResolved(evt
.GetExtraLong());
1123 void CamuleApp::OnServerDnsDone(CMuleInternalEvent
& evt
)
1125 AddLogLineNS(_("Server hostname notified"));
1126 serverconnect
->OnServerHostnameResolved(evt
.GetClientData(), evt
.GetExtraLong());
1130 void CamuleApp::OnTCPTimer(CTimerEvent
& WXUNUSED(evt
))
1135 serverconnect
->StopConnectionTry();
1136 if (IsConnectedED2K() ) {
1139 serverconnect
->ConnectToAnyServer();
1143 void CamuleApp::OnCoreTimer(CTimerEvent
& WXUNUSED(evt
))
1145 // Former TimerProc section
1146 static uint64 msPrev1
, msPrev5
, msPrevSave
, msPrevHist
, msPrevOS
, msPrevKnownMet
;
1147 uint64 msCur
= theStats::GetUptimeMillis();
1148 TheTime
= msCur
/ 1000;
1154 #ifndef AMULE_DAEMON
1155 // Check if we should terminate the app
1156 if ( g_shutdownSignal
) {
1157 wxWindow
* top
= GetTopWindow();
1162 // No top-window, have to force termination.
1168 // There is a theoretical chance that the core time function can recurse:
1169 // if an event function gets blocked on a mutex (communicating with the
1170 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1171 // If CPU load gets high a new core timer event could be generated before the last
1172 // one was finished and so recursion could occur, which would be bad.
1173 // Detect this and do an early return then.
1174 static bool recurse
= false;
1180 uploadqueue
->Process();
1181 downloadqueue
->Process();
1182 //theApp->clientcredits->Process();
1183 theStats::CalculateRates();
1185 if (msCur
-msPrevHist
> 1000) {
1186 // unlike the other loop counters in this function this one will sometimes
1187 // produce two calls in quick succession (if there was a gap of more than one
1188 // second between calls to TimerProc) - this is intentional! This way the
1189 // history list keeps an average of one node per second and gets thinned out
1190 // correctly as time progresses.
1193 m_statistics
->RecordHistory();
1198 if (msCur
-msPrev1
> 1000) { // approximately every second
1200 clientcredits
->Process();
1201 clientlist
->Process();
1203 // Publish files to server if needed.
1204 sharedfiles
->Process();
1206 if( Kademlia::CKademlia::IsRunning() ) {
1207 Kademlia::CKademlia::Process();
1208 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1212 if (thePrefs::Reconnect()) {
1218 if( serverconnect
->IsConnecting() && !serverconnect
->IsSingleConnect() ) {
1219 serverconnect
->TryAnotherConnectionrequest();
1221 if (serverconnect
->IsConnecting()) {
1222 serverconnect
->CheckForTimeout();
1224 listensocket
->UpdateConnectionsStatus();
1229 if (msCur
-msPrev5
> 5000) { // every 5 seconds
1231 listensocket
->Process();
1234 if (msCur
-msPrevSave
>= 60000) {
1240 if (msCur
- msPrevOS
>= thePrefs::GetOSUpdate() * 1000ull) {
1241 OnlineSig(); // Added By Bouc7
1245 if (msCur
- msPrevKnownMet
>= 30*60*1000/*There must be a prefs option for this*/) {
1246 // Save Shared Files data
1248 msPrevKnownMet
= msCur
;
1252 // Recomended by lugdunummaster himself - from emule 0.30c
1253 serverconnect
->KeepConnectionAlive();
1255 // Disarm recursion protection
1260 void CamuleApp::OnFinishedHashing(CHashingEvent
& evt
)
1262 wxCHECK_RET(evt
.GetResult(), wxT("No result of hashing"));
1264 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1265 CKnownFile
* result
= evt
.GetResult();
1268 // Check if the partfile still exists, as it might have
1269 // been deleted in the mean time.
1270 if (downloadqueue
->IsPartFile(owner
)) {
1271 // This cast must not be done before the IsPartFile
1272 // call, as dynamic_cast will barf on dangling pointers.
1273 dynamic_cast<CPartFile
*>(owner
)->PartFileHashFinished(result
);
1276 static uint64 bytecount
= 0;
1278 if (knownfiles
->SafeAddKFile(result
, true)) {
1279 AddDebugLogLineN(logKnownFiles
,
1280 CFormat(wxT("Safe adding file to sharedlist: %s")) % result
->GetFileName());
1281 sharedfiles
->SafeAddKFile(result
);
1283 bytecount
+= result
->GetFileSize();
1284 // If we have added files with a total size of ~3000mb
1285 if (bytecount
>= wxULL(3145728000)) {
1286 AddDebugLogLineN(logKnownFiles
, wxT("Failsafe for crash on file hashing creation"));
1287 if ( m_app_state
!= APP_STATE_SHUTTINGDOWN
) {
1293 AddDebugLogLineN(logKnownFiles
,
1294 CFormat(wxT("File not added to sharedlist: %s")) % result
->GetFileName());
1301 void CamuleApp::OnFinishedAICHHashing(CHashingEvent
& evt
)
1303 wxCHECK_RET(evt
.GetResult(), wxT("No result of AICH-hashing"));
1305 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1306 CScopedPtr
<CKnownFile
> result(evt
.GetResult());
1308 if (result
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
) {
1309 CAICHHashSet
* oldSet
= owner
->GetAICHHashset();
1310 CAICHHashSet
* newSet
= result
->GetAICHHashset();
1312 owner
->SetAICHHashset(newSet
);
1313 newSet
->SetOwner(owner
);
1315 result
->SetAICHHashset(oldSet
);
1316 oldSet
->SetOwner(result
.get());
1321 void CamuleApp::OnFinishedCompletion(CCompletionEvent
& evt
)
1323 CPartFile
* completed
= const_cast<CPartFile
*>(evt
.GetOwner());
1324 wxCHECK_RET(completed
, wxT("Completion event sent for unspecified file"));
1325 wxASSERT_MSG(downloadqueue
->IsPartFile(completed
), wxT("CCompletionEvent for unknown partfile."));
1327 completed
->CompleteFileEnded(evt
.ErrorOccured(), evt
.GetFullPath());
1328 if (evt
.ErrorOccured()) {
1329 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion
, completed
);
1332 // Check if we should execute an script/app/whatever.
1333 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted
, completed
);
1336 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent
& evt
)
1338 CPartFile
*file
= evt
.GetFile();
1339 wxCHECK_RET(file
, wxT("Allocation finished event sent for unspecified file"));
1340 wxASSERT_MSG(downloadqueue
->IsPartFile(file
), wxT("CAllocFinishedEvent for unknown partfile"));
1342 file
->SetStatus(PS_EMPTY
);
1344 if (evt
.Succeeded()) {
1345 if (evt
.IsPaused()) {
1351 AddLogLineN(CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file
->GetFileName() % wxString(UTF82unicode(std::strerror(evt
.GetResult()))));
1355 file
->AllocationFinished();
1358 void CamuleApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
1363 if (theApp
->amuledlg
) {
1370 void CamuleApp::ShutDown()
1373 PlatformSpecific::AllowSleepMode();
1376 AddDebugLogLineN(logGeneral
, wxT("CamuleApp::ShutDown() has started."));
1378 // Signal the hashing thread to terminate
1379 m_app_state
= APP_STATE_SHUTTINGDOWN
;
1382 #ifdef ASIO_SOCKETS // only needed to suppress the log message in non-Asio build
1383 AddDebugLogLineN(logGeneral
, wxT("Terminate ASIO thread."));
1384 m_AsioService
->Stop();
1389 // Kry - Save the sources seeds on app exit
1390 if (thePrefs::GetSrcSeedsOn()) {
1391 downloadqueue
->SaveSourceSeeds();
1394 OnlineSig(true); // Added By Bouc7
1396 // Exit HTTP downloads
1397 CHTTPDownloadThread::StopAll();
1399 // Exit thread scheduler and upload thread
1400 CThreadScheduler::Terminate();
1402 AddDebugLogLineN(logGeneral
, wxT("Terminate upload thread."));
1403 uploadBandwidthThrottler
->EndThread();
1405 // Close sockets to avoid new clients coming in
1407 listensocket
->Close();
1408 listensocket
->KillAllSockets();
1411 if (serverconnect
) {
1412 serverconnect
->Disconnect();
1415 ECServerHandler
->KillAllSockets();
1418 if (thePrefs::GetUPnPEnabled()) {
1420 m_upnp
->DeletePortMappings(m_upnpMappings
);
1425 // saving data & stuff
1432 CPath configFileName
= CPath(thePrefs::GetConfigDir() + m_configFile
);
1433 CPath::BackupFile(configFileName
, wxT(".bak"));
1436 clientlist
->DeleteAll();
1440 AddDebugLogLineN(logGeneral
, wxT("CamuleApp::ShutDown() has ended."));
1444 bool CamuleApp::AddServer(CServer
*srv
, bool fromUser
)
1446 if ( serverlist
->AddServer(srv
, fromUser
) ) {
1447 Notify_ServerAdd(srv
);
1454 uint32
CamuleApp::GetPublicIP(bool ignorelocal
) const
1456 if (m_dwPublicIP
== 0) {
1457 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1458 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1460 return ignorelocal
? 0 : m_localip
;
1464 return m_dwPublicIP
;
1468 void CamuleApp::SetPublicIP(const uint32 dwIP
)
1470 wxASSERT((dwIP
== 0) || !IsLowID(dwIP
));
1472 if (dwIP
!= 0 && dwIP
!= m_dwPublicIP
&& serverlist
!= NULL
) {
1473 m_dwPublicIP
= dwIP
;
1474 serverlist
->CheckForExpiredUDPKeys();
1476 m_dwPublicIP
= dwIP
;
1481 wxString
CamuleApp::GetLog(bool reset
)
1484 logfile
.Open(thePrefs::GetConfigDir() + wxT("logfile"));
1485 if ( !logfile
.IsOpened() ) {
1486 return _("ERROR: can't open logfile");
1488 int len
= logfile
.Length();
1490 return _("WARNING: logfile is empty. Something is wrong.");
1492 char *tmp_buffer
= new char[len
+ sizeof(wxChar
)];
1493 logfile
.Read(tmp_buffer
, len
);
1494 memset(tmp_buffer
+ len
, 0, sizeof(wxChar
));
1496 // try to guess file format
1498 if (tmp_buffer
[0] && tmp_buffer
[1]) {
1499 str
= wxString(UTF82unicode(tmp_buffer
));
1501 str
= wxWCharBuffer((wchar_t *)tmp_buffer
);
1504 delete [] tmp_buffer
;
1506 theLogger
.CloseLogfile();
1507 if (theLogger
.OpenLogfile(thePrefs::GetConfigDir() + wxT("logfile"))) {
1508 AddLogLineN(_("Log has been reset"));
1510 ECServerHandler
->ResetAllLogs();
1516 wxString
CamuleApp::GetServerLog(bool reset
)
1518 wxString ret
= server_msg
;
1525 wxString
CamuleApp::GetDebugLog(bool reset
)
1527 return GetLog(reset
);
1531 void CamuleApp::AddServerMessageLine(wxString
&msg
)
1533 server_msg
+= msg
+ wxT("\n");
1534 AddLogLineN(CFormat(_("ServerMessage: %s")) % msg
);
1539 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
1541 switch (event
.GetInt()) {
1543 ipfilter
->DownloadFinished(event
.GetExtraLong());
1545 case HTTP_ServerMet
:
1546 if (serverlist
->DownloadFinished(event
.GetExtraLong()) && !IsConnectedED2K()) {
1547 // If successfully downloaded a server list, and are not connected at the moment, try to connect.
1548 // This happens when no server met is available on startup.
1549 serverconnect
->ConnectToAnyServer();
1552 case HTTP_ServerMetAuto
:
1553 serverlist
->AutoDownloadFinished(event
.GetExtraLong());
1555 case HTTP_VersionCheck
:
1556 CheckNewVersion(event
.GetExtraLong());
1559 if (event
.GetExtraLong() == HTTP_Success
) {
1561 wxString file
= thePrefs::GetConfigDir() + wxT("nodes.dat");
1562 if (wxFileExists(file
)) {
1566 if ( Kademlia::CKademlia::IsRunning() ) {
1567 Kademlia::CKademlia::Stop();
1570 wxRenameFile(file
+ wxT(".download"),file
);
1572 Kademlia::CKademlia::Start();
1573 theApp
->ShowConnectionState();
1574 // cppcheck-suppress duplicateBranch
1575 } else if (event
.GetExtraLong() == HTTP_Skipped
) {
1576 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1578 AddLogLineC(_("Failed to download the nodes list."));
1581 #ifdef ENABLE_IP2COUNTRY
1583 theApp
->amuledlg
->IP2CountryDownloadFinished(event
.GetExtraLong());
1584 // If we updated, the dialog is already up. Redraw it to show the flags.
1585 theApp
->amuledlg
->Refresh();
1591 void CamuleApp::CheckNewVersion(uint32 result
)
1593 if (result
== HTTP_Success
) {
1594 wxString filename
= thePrefs::GetConfigDir() + wxT("last_version_check");
1597 if (!file
.Open(filename
)) {
1598 AddLogLineC(_("Failed to open the downloaded version check file") );
1600 } else if (!file
.GetLineCount()) {
1601 AddLogLineC(_("Corrupted version check file"));
1603 wxString versionLine
= file
.GetFirstLine();
1604 wxStringTokenizer
tkz(versionLine
, wxT("."));
1606 AddDebugLogLineN(logGeneral
, wxString(wxT("Running: ")) + wxT(VERSION
) + wxT(", Version check: ") + versionLine
);
1608 long fields
[] = {0, 0, 0};
1609 for (int i
= 0; i
< 3; ++i
) {
1610 if (!tkz
.HasMoreTokens()) {
1611 AddLogLineC(_("Corrupted version check file"));
1614 wxString token
= tkz
.GetNextToken();
1616 if (!token
.ToLong(&fields
[i
])) {
1617 AddLogLineC(_("Corrupted version check file"));
1623 long curVer
= make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
);
1624 long newVer
= make_full_ed2k_version(fields
[0], fields
[1], fields
[2]);
1626 if (curVer
< newVer
) {
1627 AddLogLineC(_("You are using an outdated version of aMule!"));
1628 // cppcheck-suppress zerodiv
1629 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]);
1630 AddLogLineN(_("The latest version can always be found at http://www.amule.org"));
1632 AddLogLineCS(CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1633 % VERSION_MJR
% VERSION_MIN
% VERSION_UPDATE
% fields
[0] % fields
[1] % fields
[2]);
1636 AddLogLineN(_("Your copy of aMule is up to date."));
1641 wxRemoveFile(filename
);
1643 AddLogLineC(_("Failed to download the version check file"));
1649 bool CamuleApp::IsConnected() const
1651 return (IsConnectedED2K() || IsConnectedKad());
1655 bool CamuleApp::IsConnectedED2K() const
1657 return serverconnect
&& serverconnect
->IsConnected();
1661 bool CamuleApp::IsConnectedKad() const
1663 return Kademlia::CKademlia::IsConnected();
1667 bool CamuleApp::IsFirewalled() const
1669 if (theApp
->IsConnectedED2K() && !theApp
->serverconnect
->IsLowID()) {
1670 return false; // we have an eD2K HighID -> not firewalled
1673 return IsFirewalledKad(); // If kad says ok, it's ok.
1676 bool CamuleApp::IsFirewalledKad() const
1678 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1679 || Kademlia::CKademlia::IsFirewalled();
1682 bool CamuleApp::IsFirewalledKadUDP() const
1684 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1685 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1688 bool CamuleApp::IsKadRunning() const
1690 return Kademlia::CKademlia::IsRunning();
1693 bool CamuleApp::IsKadRunningInLanMode() const
1695 return Kademlia::CKademlia::IsRunningInLANMode();
1699 uint32
CamuleApp::GetKadUsers() const
1701 return Kademlia::CKademlia::GetKademliaUsers();
1704 uint32
CamuleApp::GetKadFiles() const
1706 return Kademlia::CKademlia::GetKademliaFiles();
1709 uint32
CamuleApp::GetKadIndexedSources() const
1711 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource
;
1714 uint32
CamuleApp::GetKadIndexedKeywords() const
1716 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword
;
1719 uint32
CamuleApp::GetKadIndexedNotes() const
1721 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes
;
1724 uint32
CamuleApp::GetKadIndexedLoad() const
1726 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad
;
1730 // True IP of machine
1731 uint32
CamuleApp::GetKadIPAdress() const
1733 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1737 uint8
CamuleApp::GetBuddyStatus() const
1739 return clientlist
->GetBuddyStatus();
1742 uint32
CamuleApp::GetBuddyIP() const
1744 return clientlist
->GetBuddyIP();
1747 uint32
CamuleApp::GetBuddyPort() const
1749 return clientlist
->GetBuddyPort();
1752 const Kademlia::CUInt128
& CamuleApp::GetKadID() const
1754 return Kademlia::CKademlia::GetKadID();
1757 bool CamuleApp::CanDoCallback(uint32 clientServerIP
, uint16 clientServerPort
)
1759 if (Kademlia::CKademlia::IsConnected()) {
1760 if (IsConnectedED2K()) {
1761 if (serverconnect
->IsLowID()) {
1762 if (Kademlia::CKademlia::IsFirewalled()) {
1763 //Both Connected - Both Firewalled
1766 if (clientServerIP
== theApp
->serverconnect
->GetCurrentServer()->GetIP() &&
1767 clientServerPort
== theApp
->serverconnect
->GetCurrentServer()->GetPort()) {
1768 // Both Connected - Server lowID, Kad Open - Client on same server
1769 // We prevent a callback to the server as this breaks the protocol
1770 // and will get you banned.
1773 // Both Connected - Server lowID, Kad Open - Client on remote server
1778 //Both Connected - Server HighID, Kad don't care
1782 if (Kademlia::CKademlia::IsFirewalled()) {
1783 //Only Kad Connected - Kad Firewalled
1786 //Only Kad Conected - Kad Open
1791 if (IsConnectedED2K()) {
1792 if (serverconnect
->IsLowID()) {
1793 //Only Server Connected - Server LowID
1796 //Only Server Connected - Server HighID
1800 //We are not connected at all!
1806 void CamuleApp::ShowUserCount() {
1807 uint32 totaluser
= 0, totalfile
= 0;
1809 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
1813 static const wxString s_singlenetstatusformat
= _("Users: %s | Files: %s");
1814 static const wxString s_bothnetstatusformat
= _("Users: E: %s K: %s | Files: E: %s K: %s");
1816 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1817 buffer
= CFormat(s_bothnetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile
) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1818 } else if (thePrefs::GetNetworkED2K()) {
1819 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(totalfile
);
1820 } else if (thePrefs::GetNetworkKademlia()) {
1821 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1823 buffer
= _("No networks selected");
1826 Notify_ShowUserCount(buffer
);
1830 #ifndef ASIO_SOCKETS
1831 void CamuleApp::ListenSocketHandler(wxSocketEvent
& event
)
1833 { wxCHECK_RET(listensocket
, wxT("Connection-event for NULL'd listen-socket")); }
1834 { wxCHECK_RET(event
.GetSocketEvent() == wxSOCKET_CONNECTION
,
1835 wxT("Invalid event received for listen-socket")); }
1837 if (m_app_state
== APP_STATE_RUNNING
) {
1838 listensocket
->OnAccept();
1839 } else if (m_app_state
== APP_STATE_STARTING
) {
1840 // When starting up, connection may be made before we are able
1841 // to handle them. However, if these are ignored, no futher
1842 // connection-events will be triggered, so we have to accept it.
1843 CLibSocket
* socket
= listensocket
->Accept(false);
1845 wxCHECK_RET(socket
, wxT("NULL returned by Accept() during startup"));
1853 void CamuleApp::ShowConnectionState(bool forceUpdate
)
1855 static uint8 old_state
= (1<<7); // This flag doesn't exist
1859 if (theApp
->serverconnect
->IsConnected()) {
1860 state
|= CONNECTED_ED2K
;
1863 if (Kademlia::CKademlia::IsRunning()) {
1864 if (Kademlia::CKademlia::IsConnected()) {
1865 if (!Kademlia::CKademlia::IsFirewalled()) {
1866 state
|= CONNECTED_KAD_OK
;
1868 state
|= CONNECTED_KAD_FIREWALLED
;
1871 state
|= CONNECTED_KAD_NOT
;
1875 if (old_state
!= state
) {
1876 // Get the changed value
1877 int changed_flags
= old_state
^ state
;
1879 if (changed_flags
& CONNECTED_ED2K
) {
1880 // ED2K status changed
1881 wxString connected_server
;
1882 CServer
* ed2k_server
= theApp
->serverconnect
->GetCurrentServer();
1884 connected_server
= ed2k_server
->GetListName();
1886 if (state
& CONNECTED_ED2K
) {
1887 // We connected to some server
1888 const wxString id
= theApp
->serverconnect
->IsLowID() ? _("with LowID") : _("with HighID");
1890 AddLogLineC(CFormat(_("Connected to %s %s")) % connected_server
% id
);
1892 // cppcheck-suppress duplicateBranch
1893 if ( theApp
->serverconnect
->IsConnecting() ) {
1894 AddLogLineC(CFormat(_("Connecting to %s")) % connected_server
);
1896 AddLogLineC(_("Disconnected from eD2k"));
1901 if (changed_flags
& CONNECTED_KAD_NOT
) {
1902 // cppcheck-suppress duplicateBranch
1903 if (state
& CONNECTED_KAD_NOT
) {
1904 AddLogLineC(_("Kad started."));
1906 AddLogLineC(_("Kad stopped."));
1910 if (changed_flags
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
1911 if (state
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
1912 // cppcheck-suppress duplicateBranch
1913 if (state
& CONNECTED_KAD_OK
) {
1914 AddLogLineC(_("Connected to Kad (ok)"));
1916 AddLogLineC(_("Connected to Kad (firewalled)"));
1919 AddLogLineC(_("Disconnected from Kad"));
1925 theApp
->downloadqueue
->OnConnectionState(IsConnected());
1929 Notify_ShowConnState(forceUpdate
);
1933 #ifndef ASIO_SOCKETS
1934 void CamuleApp::UDPSocketHandler(wxSocketEvent
& event
)
1936 CMuleUDPSocket
* socket
= reinterpret_cast<CMuleUDPSocket
*>(event
.GetClientData());
1937 wxCHECK_RET(socket
, wxT("No socket owner specified."));
1939 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1942 if (event
.GetSocketEvent() == wxSOCKET_INPUT
) {
1943 // Back to the queue!
1944 theApp
->AddPendingEvent(event
);
1949 switch (event
.GetSocketEvent()) {
1950 case wxSOCKET_INPUT
:
1951 socket
->OnReceive(0);
1954 case wxSOCKET_OUTPUT
:
1959 socket
->OnDisconnected(0);
1970 void CamuleApp::OnUnhandledException()
1972 // Call the generic exception-handler.
1973 fprintf(stderr
, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1974 ::OnUnhandledException();
1977 void CamuleApp::StartKad()
1979 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1980 // Kad makes no sense without the Client-UDP socket.
1981 if (!thePrefs::IsUDPDisabled()) {
1982 if (ipfilter
->IsReady()) {
1983 Kademlia::CKademlia::Start();
1985 ipfilter
->StartKADWhenReady();
1988 AddLogLineC(_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1990 } else if (!thePrefs::GetNetworkKademlia()) {
1991 AddLogLineC(_("Kad network disabled on preferences, not connecting."));
1995 void CamuleApp::StopKad()
1997 // Stop Kad if it's running
1998 if (Kademlia::CKademlia::IsRunning()) {
1999 Kademlia::CKademlia::Stop();
2004 void CamuleApp::BootstrapKad(uint32 ip
, uint16 port
)
2006 if (!Kademlia::CKademlia::IsRunning()) {
2007 Kademlia::CKademlia::Start();
2008 theApp
->ShowConnectionState();
2011 Kademlia::CKademlia::Bootstrap(ip
, port
);
2015 void CamuleApp::UpdateNotesDat(const wxString
& url
)
2017 wxString
strTempFilename(thePrefs::GetConfigDir() + wxT("nodes.dat.download"));
2019 CHTTPDownloadThread
*downloader
= new CHTTPDownloadThread(url
, strTempFilename
, thePrefs::GetConfigDir() + wxT("nodes.dat"), HTTP_NodesDat
, true, false);
2020 downloader
->Create();
2025 void CamuleApp::DisconnectED2K()
2027 // Stop ED2K if it's running
2028 if (IsConnectedED2K()) {
2029 serverconnect
->Disconnect();
2033 bool CamuleApp::CryptoAvailable() const
2035 return clientcredits
&& clientcredits
->CryptoAvailable();
2038 uint32
CamuleApp::GetED2KID() const {
2039 return serverconnect
? serverconnect
->GetClientID() : 0;
2042 uint32
CamuleApp::GetID() const {
2045 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2046 // We trust Kad above ED2K
2047 ID
= ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2048 } else if( theApp
->serverconnect
->IsConnected() ) {
2049 ID
= theApp
->serverconnect
->GetClientID();
2050 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2051 // A firewalled Kad client get's a "1"
2060 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2061 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2062 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2063 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2064 // File_checked_for_headers