2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 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/tokenzr.h>
46 #include <wx/wfstream.h>
49 #include <common/Format.h> // Needed for CFormat
50 #include "kademlia/kademlia/Kademlia.h"
51 #include "kademlia/kademlia/Prefs.h"
52 #include "kademlia/kademlia/UDPFirewallTester.h"
53 #include "CanceledFileList.h"
54 #include "ClientCreditsList.h" // Needed for CClientCreditsList
55 #include "ClientList.h" // Needed for CClientList
56 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
57 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
58 #include <common/FileFunctions.h> // Needed for CDirIterator
59 #include "FriendList.h" // Needed for CFriendList
60 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
61 #include "InternalEvents.h" // Needed for CMuleInternalEvent
62 #include "IPFilter.h" // Needed for CIPFilter
63 #include "KnownFileList.h" // Needed for CKnownFileList
64 #include "ListenSocket.h" // Needed for CListenSocket
65 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
66 #include "MagnetURI.h" // Needed for CMagnetURI
67 #include "OtherFunctions.h"
68 #include "PartFile.h" // Needed for CPartFile
69 #include "PlatformSpecific.h" // Needed for PlatformSpecific::AllowSleepMode();
70 #include "Preferences.h" // Needed for CPreferences
71 #include "SearchList.h" // Needed for CSearchList
72 #include "Server.h" // Needed for GetListName
73 #include "ServerList.h" // Needed for CServerList
74 #include "ServerConnect.h" // Needed for CServerConnect
75 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
76 #include "Statistics.h" // Needed for CStatistics
77 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
78 #include "ThreadTasks.h"
79 #include "updownclient.h" // Needed for CUpDownClient
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 strFullMuleVersion
= NULL
;
213 strOSDescription
= NULL
;
215 // Apprently needed for *BSD
219 _CrtSetDbgFlag(0); // Disable useless memleak debugging
223 CamuleApp::~CamuleApp()
225 // Closing the log-file as the very last thing, since
226 // wxWidgets log-events are saved in it as well.
227 theLogger
.CloseLogfile();
229 if (strFullMuleVersion
) {
230 free(strFullMuleVersion
);
232 if (strOSDescription
) {
233 free(strOSDescription
);
237 int CamuleApp::OnExit()
239 if (m_app_state
!=APP_STATE_STARTING
) {
240 AddLogLineNS(_("Now, exiting main app..."));
243 // From wxWidgets docs, wxConfigBase:
245 // Note that you must delete this object (usually in wxApp::OnExit)
246 // in order to avoid memory leaks, wxWidgets won't do it automatically.
248 // As it happens, you may even further simplify the procedure described
249 // above: you may forget about calling Set(). When Get() is called and
250 // there is no current object, it will create one using Create() function.
251 // To disable this behaviour DontCreateOnDemand() is provided.
252 delete wxConfigBase::Set((wxConfigBase
*)NULL
);
255 clientcredits
->SaveList();
257 // Kill amuleweb if running
259 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid `%ld' ... ")) % webserver_pid
);
261 if (wxKill(webserver_pid
, wxSIGTERM
, &rc
) == -1) {
262 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid `%ld' ... ")) % webserver_pid
);
263 if (wxKill(webserver_pid
, wxSIGKILL
, &rc
) == -1) {
264 AddLogLineNS(_("Failed"));
269 if (m_app_state
!=APP_STATE_STARTING
) {
270 AddLogLineNS(_("aMule OnExit: Terminating core."));
279 delete clientcredits
;
280 clientcredits
= NULL
;
285 // Destroying CDownloadQueue calls destructor for CPartFile
286 // calling CSharedFileList::SafeAddKFile occasionally.
290 delete serverconnect
;
291 serverconnect
= NULL
;
302 delete canceledfiles
;
303 canceledfiles
= NULL
;
311 delete downloadqueue
;
312 downloadqueue
= NULL
;
322 delete ECServerHandler
;
323 ECServerHandler
= NULL
;
330 CPreferences::EraseItemList();
332 delete uploadBandwidthThrottler
;
333 uploadBandwidthThrottler
= NULL
;
335 if (m_app_state
!=APP_STATE_STARTING
) {
336 AddLogLineNS(_("aMule shutdown completed."));
339 #if wxUSE_MEMORY_TRACING
340 AddLogLineNS(_("Memory debug results for aMule exit:"));
341 // Log mem debug mesages to wxLogStderr
342 wxLog
* oldLog
= wxLog::SetActiveTarget(new wxLogStderr
);
343 //AddLogLineNS(wxT("**************Classes**************");
344 //wxDebugContext::PrintClasses();
345 //AddLogLineNS(wxT("***************Dump***************");
346 //wxDebugContext::Dump();
347 AddLogLineNS(wxT("***************Stats**************"));
348 wxDebugContext::PrintStatistics(true);
350 // Set back to wxLogGui
351 delete wxLog::SetActiveTarget(oldLog
);
356 // Return 0 for succesful program termination
357 return AMULE_APP_BASE::OnExit();
361 int CamuleApp::InitGui(bool, wxString
&)
368 // Application initialization
370 bool CamuleApp::OnInit()
372 #if wxUSE_MEMORY_TRACING
373 // any text before call of Localize_mule needs not to be translated.
374 AddLogLineNS(wxT("Checkpoint set on app init for memory debug"));
375 wxDebugContext::SetCheckpoint();
378 // Forward wxLog events to CLogger
379 wxLog::SetActiveTarget(new CLoggerTarget
);
381 m_localip
= StringHosttoUint32(::wxGetFullHostName());
384 // get rid of sigpipe
385 signal(SIGPIPE
, SIG_IGN
);
388 signal(SIGBREAK
, OnShutdownSignal
);
390 // Handle sigint and sigterm
391 signal(SIGINT
, OnShutdownSignal
);
392 signal(SIGTERM
, OnShutdownSignal
);
395 // For listctrl's to behave on Mac
396 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
399 // Handle uncaught exceptions
400 InstallMuleExceptionHandler();
402 if (!InitCommon(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
)) {
406 glob_prefs
= new CPreferences();
409 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir
+ wxT("Temp"), outDir
)) {
410 thePrefs::SetTempDir(outDir
);
415 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir
+ wxT("Incoming"), outDir
)) {
416 thePrefs::SetIncomingDir(outDir
);
422 if (!thePrefs::UseTrayIcon()) {
423 thePrefs::SetMinToTray(false);
426 // Build the filenames for the two OS files
427 SetOSFiles(thePrefs::GetOSDir().GetRaw());
430 // Load localization settings
434 // Configure EC for amuled when invoked with ec-config
436 AddLogLineNS(_("\nEC configuration"));
437 thePrefs::SetECPass(GetPassword());
438 thePrefs::EnableExternalConnections(true);
439 AddLogLineNS(_("Password set and external connections enabled."));
445 wxT("Warning! You are running aMule as root.\n")
446 wxT("Doing so is not recommended for security reasons,\n")
447 wxT("and you are advised to run aMule as an normal\n")
448 wxT("user instead.");
450 ShowAlert(msg
, _("WARNING"), wxCENTRE
| wxOK
| wxICON_ERROR
);
452 fprintf(stderr
, "\n--------------------------------------------------\n");
453 fprintf(stderr
, "%s", (const char*)unicode2UTF8(msg
));
454 fprintf(stderr
, "\n--------------------------------------------------\n\n");
458 // Display notification on new version or first run
459 wxTextFile
vfile( ConfigDir
+ wxT("lastversion") );
460 wxString
newMule(wxT( VERSION
));
462 if ( !wxFileExists( vfile
.GetName() ) ) {
466 if ( vfile
.Open() ) {
467 // Check if this version has been run before
469 for ( size_t i
= 0; i
< vfile
.GetLineCount(); i
++ ) {
470 // Check if this version has been run before
471 if ( vfile
.GetLine(i
) == newMule
) {
477 // We havent run this version before?
479 // Insert new at top to provide faster searches
480 vfile
.InsertLine( newMule
, 0 );
482 Trigger_New_version( newMule
);
485 // Keep at most 10 entires
486 while ( vfile
.GetLineCount() > 10 )
487 vfile
.RemoveLine( vfile
.GetLineCount() - 1 );
493 // Check if we have the old style locale config
494 wxString langId
= thePrefs::GetLanguageID();
495 if (!langId
.IsEmpty() && (langId
.GetChar(0) >= '0' && langId
.GetChar(0) <= '9')) {
496 wxString
info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
497 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT
));
498 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
501 m_statistics
= new CStatistics();
503 clientlist
= new CClientList();
504 friendlist
= new CFriendList();
505 searchlist
= new CSearchList();
506 knownfiles
= new CKnownFileList();
507 canceledfiles
= new CCanceledFileList
;
508 serverlist
= new CServerList();
510 sharedfiles
= new CSharedFileList(knownfiles
);
511 clientcredits
= new CClientCreditsList();
513 // bugfix - do this before creating the uploadqueue
514 downloadqueue
= new CDownloadQueue();
515 uploadqueue
= new CUploadQueue();
516 ipfilter
= new CIPFilter();
518 // Creates all needed listening sockets
520 if (!ReinitializeNetwork(&msg
)) {
521 AddLogLineNS(wxT("\n"));
525 // Test if there's any new version
526 if (thePrefs::GetCheckNewVersion()) {
527 // We use the thread base because I don't want a dialog to pop up.
528 CHTTPDownloadThread
* version_check
=
529 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
530 theApp
->ConfigDir
+ wxT("last_version_check"), theApp
->ConfigDir
+ wxT("last_version"), HTTP_VersionCheck
, false, true);
531 version_check
->Create();
532 version_check
->Run();
535 // Create main dialog, or fork to background (daemon).
536 InitGui(m_geometryEnabled
, m_geometryString
);
539 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
540 if (enable_daemon_fork
) {
541 RefreshSingleInstanceChecker();
542 // No need to check IsAnotherRunning() - we've done it before.
546 // Has to be created after the call to InitGui, as fork
547 // (when using posix threads) only replicates the mainthread,
548 // and the UBT constructor creates a thread.
549 uploadBandwidthThrottler
= new UploadBandwidthThrottler();
551 // Start performing background tasks
552 // This will start loading the IP filter. It will start right away.
553 // Log is confusing, because log entries from background will only be printed
554 // once foreground becomes idle, and that will only be after loading
555 // of the partfiles has finished.
556 CThreadScheduler::Start();
558 // These must be initialized after the gui is loaded.
559 if (thePrefs::GetNetworkED2K()) {
562 downloadqueue
->LoadMetFiles(thePrefs::GetTempDir());
563 sharedfiles
->Reload();
565 // Ensure that the up/down ratio is used
566 CPreferences::CheckUlDlRatio();
568 // The user can start pressing buttons like mad if he feels like it.
569 m_app_state
= APP_STATE_RUNNING
;
571 if (!serverlist
->GetServerCount() && thePrefs::GetNetworkED2K()) {
572 // There are no servers and ED2K active -> ask for download.
573 // As we cannot ask in amuled, we just update there
574 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
576 if (wxYES
== wxMessageBox(
578 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
579 wxString(_("Server list download")),
581 static_cast<wxWindow
*>(theApp
->amuledlg
)))
584 // workaround amuled crash
586 serverlist
->UpdateServerMetFromURL(
587 wxT("http://gruk.org/server.met.gz"));
593 // Autoconnect if that option is enabled
594 if (thePrefs::DoAutoConnect()) {
595 // IP filter is still loading and will be finished on event.
596 // Tell it to autoconnect.
597 if (thePrefs::GetNetworkED2K()) {
598 ipfilter
->ConnectToAnyServerWhenReady();
600 if (thePrefs::GetNetworkKademlia()) {
601 ipfilter
->StartKADWhenReady();
606 #ifdef ENABLE_IP2COUNTRY
607 theApp
->amuledlg
->EnableIP2Country();
611 if (thePrefs::GetWSIsEnabled()) {
612 wxString aMuleConfigFile
= ConfigDir
+ m_configFile
;
613 wxString amulewebPath
= thePrefs::GetWSPath();
615 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
616 // For the Mac GUI application, look for amuleweb in the bundle
617 CFURLRef amulewebUrl
= CFBundleCopyAuxiliaryExecutableURL(
618 CFBundleGetMainBundle(), CFSTR("amuleweb"));
621 CFURLRef absoluteUrl
= CFURLCopyAbsoluteURL(amulewebUrl
);
622 CFRelease(amulewebUrl
);
625 CFStringRef amulewebCfstr
= CFURLCopyFileSystemPath(absoluteUrl
, kCFURLPOSIXPathStyle
);
626 CFRelease(absoluteUrl
);
627 #if wxCHECK_VERSION(2, 9, 0)
628 amulewebPath
= wxCFStringRef(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
630 amulewebPath
= wxMacCFStringHolder(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
637 # define QUOTE wxT("\"")
639 # define QUOTE wxT("\'")
645 QUOTE
wxT(" ") QUOTE
wxT("--amule-config-file=") +
648 CTerminationProcessAmuleweb
*p
= new CTerminationProcessAmuleweb(cmd
, &webserver_pid
);
649 webserver_pid
= wxExecute(cmd
, wxEXEC_ASYNC
, p
);
650 bool webserver_ok
= webserver_pid
> 0;
652 AddLogLineC(CFormat(_("web server running on pid %d")) % webserver_pid
);
656 "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"),
657 _("ERROR"), wxOK
| wxICON_ERROR
);
664 bool CamuleApp::ReinitializeNetwork(wxString
* msg
)
667 static bool firstTime
= true;
670 // TODO: Destroy previously created sockets
674 // Some sanity checks first
675 if (thePrefs::ECPort() == thePrefs::GetPort()) {
676 // Select a random usable port in the range 1025 ... 2^16 - 1
677 uint16 port
= thePrefs::ECPort();
678 while ( port
< 1024 || port
== thePrefs::GetPort() ) {
679 port
= (uint16
)rand();
681 thePrefs::SetECPort( port
);
684 wxT("Network configuration failed! You cannot use the same port\n")
685 wxT("for the main TCP port and the External Connections port.\n")
686 wxT("The EC port has been changed to avoid conflict, see the\n")
687 wxT("preferences for the new value.\n");
690 AddLogLineN(wxEmptyString
);
692 AddLogLineN(wxEmptyString
);
697 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
698 // Select a random usable value in the range 1025 ... 2^16 - 1
699 uint16 port
= thePrefs::GetUDPPort();
700 while ( port
< 1024 || port
== thePrefs::GetPort() + 3 ) {
701 port
= (uint16
)rand();
703 thePrefs::SetUDPPort( port
);
706 wxT("Network configuration failed! You set your UDP port to\n")
707 wxT("the value of the main TCP port plus 3.\n")
708 wxT("This port has been reserved for the Server-UDP port. The\n")
709 wxT("port value has been changed to avoid conflict, see the\n")
710 wxT("preferences for the new value\n");
713 AddLogLineN(wxEmptyString
);
715 AddLogLineN(wxEmptyString
);
720 // Create the address where we are going to listen
721 // TODO: read this from configuration file
722 amuleIPV4Address myaddr
[4];
724 // Create the External Connections Socket.
726 // Get ready to handle connections from apps like amulecmd
727 if (thePrefs::GetECAddress().IsEmpty() || !myaddr
[0].Hostname(thePrefs::GetECAddress())) {
728 myaddr
[0].AnyAddress();
730 myaddr
[0].Service(thePrefs::ECPort());
731 ECServerHandler
= new ExternalConn(myaddr
[0], msg
);
733 // Create the UDP socket TCP+3.
734 // Used for source asking on servers.
735 if (thePrefs::GetAddress().IsEmpty()) {
736 myaddr
[1].AnyAddress();
737 } else if (!myaddr
[1].Hostname(thePrefs::GetAddress())) {
738 myaddr
[1].AnyAddress();
739 AddLogLineC(CFormat(_("Could not bind ports to the specified address: %s"))
740 % thePrefs::GetAddress());
743 wxString ip
= myaddr
[1].IPAddress();
744 myaddr
[1].Service(thePrefs::GetPort()+3);
745 serverconnect
= new CServerConnect(serverlist
, myaddr
[1]);
746 *msg
<< CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
747 % ip
% ((unsigned int)thePrefs::GetPort() + 3u);
749 // Create the ListenSocket (aMule TCP socket).
750 // Used for Client Port / Connections from other clients,
751 // Client to Client Source Exchange.
753 myaddr
[2] = myaddr
[1];
754 myaddr
[2].Service(thePrefs::GetPort());
755 listensocket
= new CListenSocket(myaddr
[2]);
756 *msg
<< CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
757 % ip
% (unsigned int)(thePrefs::GetPort());
758 // This command just sets a flag to control maximum number of connections.
759 // Notify(true) has already been called to the ListenSocket, so events may
760 // be already comming in.
761 if (listensocket
->Ok()) {
762 listensocket
->StartListening();
764 // If we wern't able to start listening, we need to warn the user
766 err
= CFormat(_("Port %u is not available. You will be LOWID\n")) %
767 (unsigned int)(thePrefs::GetPort());
772 _("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.")) %
773 (unsigned int)(thePrefs::GetPort());
774 ShowAlert(err
, _("ERROR"), wxOK
| wxICON_ERROR
);
777 // Create the UDP socket.
778 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
779 // Also used for Kademlia.
780 // Default is port 4672.
781 myaddr
[3] = myaddr
[1];
782 myaddr
[3].Service(thePrefs::GetUDPPort());
783 clientudp
= new CClientUDPSocket(myaddr
[3], thePrefs::GetProxyData());
784 if (!thePrefs::IsUDPDisabled()) {
785 *msg
<< CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
786 % ip
% thePrefs::GetUDPPort();
788 *msg
<< wxT("*** Client UDP socket (extended eMule) disabled on preferences");
792 if (thePrefs::GetUPnPEnabled()) {
794 m_upnpMappings
[0] = CUPnPPortMapping(
797 thePrefs::GetUPnPECEnabled(),
798 "aMule TCP External Connections Socket");
799 m_upnpMappings
[1] = CUPnPPortMapping(
802 thePrefs::GetUPnPEnabled(),
803 "aMule UDP socket (TCP+3)");
804 m_upnpMappings
[2] = CUPnPPortMapping(
807 thePrefs::GetUPnPEnabled(),
808 "aMule TCP Listen Socket");
809 m_upnpMappings
[3] = CUPnPPortMapping(
812 thePrefs::GetUPnPEnabled(),
813 "aMule UDP Extended eMule Socket");
814 m_upnp
= new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
815 m_upnp
->AddPortMappings(m_upnpMappings
);
816 } catch(CUPnPException
&e
) {
818 error_msg
<< e
.what();
819 AddLogLineC(error_msg
);
820 fprintf(stderr
, "%s\n", (const char *)unicode2char(error_msg
));
828 /* Original implementation by Bouc7 of the eMule Project.
829 aMule Signature idea was designed by BigBob and implemented
830 by Un-Thesis, with design inputs and suggestions from bothie.
832 void CamuleApp::OnlineSig(bool zero
/* reset stats (used on shutdown) */)
834 // Do not do anything if online signature is disabled in Preferences
835 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path
.IsEmpty()) {
836 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
837 // that means m_amulesig_path is empty too.
841 // Remove old signature files
842 if ( wxFileExists( m_emulesig_path
) ) { wxRemoveFile( m_emulesig_path
); }
843 if ( wxFileExists( m_amulesig_path
) ) { wxRemoveFile( m_amulesig_path
); }
846 wxTextFile amulesig_out
;
847 wxTextFile emulesig_out
;
849 // Open both files if needed
850 if ( !emulesig_out
.Create( m_emulesig_path
) ) {
851 AddLogLineC(_("Failed to create OnlineSig File"));
852 // Will never try again.
853 m_amulesig_path
.Clear();
854 m_emulesig_path
.Clear();
858 if ( !amulesig_out
.Create(m_amulesig_path
) ) {
859 AddLogLineC(_("Failed to create aMule OnlineSig File"));
860 // Will never try again.
861 m_amulesig_path
.Clear();
862 m_emulesig_path
.Clear();
866 wxString emulesig_string
;
870 emulesig_string
= wxT("0\xA0.0|0.0|0");
871 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
873 if (IsConnectedED2K()) {
875 temp
= CFormat(wxT("%d")) % serverconnect
->GetCurrentServer()->GetPort();
882 + serverconnect
->GetCurrentServer()->GetListName()
884 // IP and port of the server
885 + serverconnect
->GetCurrentServer()->GetFullIP()
892 // Connected. State 1, full info
893 amulesig_out
.AddLine(wxT("1"));
895 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetListName());
897 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetFullIP());
899 amulesig_out
.AddLine(temp
);
901 if (serverconnect
->IsLowID()) {
902 amulesig_out
.AddLine(wxT("L"));
904 amulesig_out
.AddLine(wxT("H"));
907 } else if (serverconnect
->IsConnecting()) {
908 emulesig_string
= wxT("0");
910 // Connecting. State 2, No info.
911 amulesig_out
.AddLine(wxT("2\n0\n0\n0\n0"));
913 // Not connected to a server
914 emulesig_string
= wxT("0");
916 // Not connected, state 0, no info
917 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0"));
919 if (IsConnectedKad()) {
920 if(Kademlia::CKademlia::IsFirewalled()) {
921 // Connected. Firewalled. State 1.
922 amulesig_out
.AddLine(wxT("1"));
924 // Connected. State 2.
925 amulesig_out
.AddLine(wxT("2"));
928 // Not connected.State 0.
929 amulesig_out
.AddLine(wxT("0"));
931 emulesig_string
+= wxT("\xA");
933 // Datarate for downloads
934 temp
= CFormat(wxT("%.1f")) % (theStats::GetDownloadRate() / 1024.0);
936 emulesig_string
+= temp
+ wxT("|");
937 amulesig_out
.AddLine(temp
);
939 // Datarate for uploads
940 temp
= CFormat(wxT("%.1f")) % (theStats::GetUploadRate() / 1024.0);
942 emulesig_string
+= temp
+ wxT("|");
943 amulesig_out
.AddLine(temp
);
945 // Number of users waiting for upload
946 temp
= CFormat(wxT("%d")) % theStats::GetWaitingUserCount();
948 emulesig_string
+= temp
;
949 amulesig_out
.AddLine(temp
);
951 // Number of shared files (not on eMule)
952 amulesig_out
.AddLine(CFormat(wxT("%d")) % theStats::GetSharedFileCount());
955 // eMule signature finished here. Write the line to the wxTextFile.
956 emulesig_out
.AddLine(emulesig_string
);
958 // Now for aMule signature extras
960 // Nick on the network
961 amulesig_out
.AddLine(thePrefs::GetUserNick());
963 // Total received in bytes
964 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
966 // Total sent in bytes
967 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
971 amulesig_out
.AddLine(wxT(VERSION
) wxT(" ") wxT(SVNDATE
));
973 amulesig_out
.AddLine(wxT(VERSION
));
977 amulesig_out
.AddLine(wxT("0"));
978 amulesig_out
.AddLine(wxT("0"));
979 amulesig_out
.AddLine(wxT("0"));
981 // Total received bytes in session
982 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
983 theStats::GetSessionReceivedBytes() );
985 // Total sent bytes in session
986 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
987 theStats::GetSessionSentBytes() );
990 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
994 emulesig_out
.Write();
995 amulesig_out
.Write();
996 } //End Added By Bouc7
999 // Gracefully handle fatal exceptions and print backtrace if possible
1000 void CamuleApp::OnFatalException()
1002 /* Print the backtrace */
1003 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1004 fprintf(stderr
, "A fatal error has occurred and aMule has crashed.\n");
1005 fprintf(stderr
, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1006 fprintf(stderr
, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1007 fprintf(stderr
, "circumstances of this crash. The forum is located here:\n");
1008 fprintf(stderr
, " http://forum.amule.org/index.php?board=67.0\n");
1009 fprintf(stderr
, "If possible, please try to generate a real backtrace of this crash:\n");
1010 fprintf(stderr
, " http://wiki.amule.org/index.php/Backtraces\n\n");
1011 fprintf(stderr
, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1012 fprintf(stderr
, "Current version is: %s\n", strFullMuleVersion
);
1013 fprintf(stderr
, "Running on: %s\n\n", strOSDescription
);
1015 print_backtrace(1); // 1 == skip this function.
1017 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1021 // Sets the localization of aMule
1022 void CamuleApp::Localize_mule()
1024 InitCustomLanguages();
1025 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
1026 if (!m_locale
.IsOk()) {
1027 AddLogLineN(_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1032 // Displays information related to important changes in aMule.
1033 // Is called when the user runs a new version of aMule
1034 void CamuleApp::Trigger_New_version(wxString new_version
)
1036 wxString info
= wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version
+ wxT(" ---\n\n");
1037 if (new_version
== wxT("SVN")) {
1038 info
+= _("This version is a testing version, updated daily, and\n");
1039 info
+= _("we give no warranty it won't break anything, burn your house,\n");
1040 info
+= _("or kill your dog. But it *should* be safe to use anyway.\n");
1045 info
+= _("More information, support and new releases can found at our homepage,\n");
1046 info
+= _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1048 info
+= _("Feel free to report any bugs to http://forum.amule.org");
1050 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
1054 void CamuleApp::SetOSFiles(const wxString new_path
)
1056 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1057 if ( ::wxDirExists(new_path
) ) {
1058 m_emulesig_path
= JoinPaths(new_path
, wxT("onlinesig.dat"));
1059 m_amulesig_path
= JoinPaths(new_path
, wxT("amulesig.dat"));
1061 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
);
1062 m_emulesig_path
.Clear();
1063 m_amulesig_path
.Clear();
1066 m_emulesig_path
.Clear();
1067 m_amulesig_path
.Clear();
1073 #ifndef wxUSE_STACKWALKER
1074 #define wxUSE_STACKWALKER 0
1076 void CamuleApp::OnAssertFailure(const wxChar
* file
, int line
,
1077 const wxChar
* func
, const wxChar
* cond
, const wxChar
* msg
)
1079 if (!wxUSE_STACKWALKER
|| !wxThread::IsMain() || !IsRunning()) {
1080 wxString errmsg
= CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1081 % file
% func
% line
% cond
% ( msg
? msg
: wxT("") );
1083 fprintf(stderr
, "Assertion failed: %s\n", (const char*)unicode2char(errmsg
));
1085 // Skip the function-calls directly related to the assert call.
1086 fprintf(stderr
, "\nBacktrace follows:\n");
1088 fprintf(stderr
, "\n");
1091 if (wxThread::IsMain() && IsRunning()) {
1092 AMULE_APP_BASE::OnAssertFailure(file
, line
, func
, cond
, msg
);
1094 // Abort, allows gdb to catch the assertion
1101 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent
& evt
)
1103 CServerUDPSocket
* socket
=(CServerUDPSocket
*)evt
.GetClientData();
1104 socket
->OnHostnameResolved(evt
.GetExtraLong());
1108 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent
& evt
)
1110 downloadqueue
->OnHostnameResolved(evt
.GetExtraLong());
1114 void CamuleApp::OnServerDnsDone(CMuleInternalEvent
& evt
)
1116 AddLogLineNS(_("Server hostname notified"));
1117 serverconnect
->OnServerHostnameResolved(evt
.GetClientData(), evt
.GetExtraLong());
1121 void CamuleApp::OnTCPTimer(CTimerEvent
& WXUNUSED(evt
))
1126 serverconnect
->StopConnectionTry();
1127 if (IsConnectedED2K() ) {
1130 serverconnect
->ConnectToAnyServer();
1134 void CamuleApp::OnCoreTimer(CTimerEvent
& WXUNUSED(evt
))
1136 // Former TimerProc section
1137 static uint64 msPrev1
, msPrev5
, msPrevSave
, msPrevHist
, msPrevOS
, msPrevKnownMet
;
1138 uint64 msCur
= theStats::GetUptimeMillis();
1139 TheTime
= msCur
/ 1000;
1145 #ifndef AMULE_DAEMON
1146 // Check if we should terminate the app
1147 if ( g_shutdownSignal
) {
1148 wxWindow
* top
= GetTopWindow();
1153 // No top-window, have to force termination.
1159 // There is a theoretical chance that the core time function can recurse:
1160 // if an event function gets blocked on a mutex (communicating with the
1161 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1162 // If CPU load gets high a new core timer event could be generated before the last
1163 // one was finished and so recursion could occur, which would be bad.
1164 // Detect this and do an early return then.
1165 static bool recurse
= false;
1171 uploadqueue
->Process();
1172 downloadqueue
->Process();
1173 //theApp->clientcredits->Process();
1174 theStats::CalculateRates();
1176 if (msCur
-msPrevHist
> 1000) {
1177 // unlike the other loop counters in this function this one will sometimes
1178 // produce two calls in quick succession (if there was a gap of more than one
1179 // second between calls to TimerProc) - this is intentional! This way the
1180 // history list keeps an average of one node per second and gets thinned out
1181 // correctly as time progresses.
1184 m_statistics
->RecordHistory();
1189 if (msCur
-msPrev1
> 1000) { // approximately every second
1191 clientcredits
->Process();
1192 clientlist
->Process();
1194 // Publish files to server if needed.
1195 sharedfiles
->Process();
1197 if( Kademlia::CKademlia::IsRunning() ) {
1198 Kademlia::CKademlia::Process();
1199 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1203 if (thePrefs::Reconnect()) {
1209 if( serverconnect
->IsConnecting() && !serverconnect
->IsSingleConnect() ) {
1210 serverconnect
->TryAnotherConnectionrequest();
1212 if (serverconnect
->IsConnecting()) {
1213 serverconnect
->CheckForTimeout();
1215 listensocket
->UpdateConnectionsStatus();
1220 if (msCur
-msPrev5
> 5000) { // every 5 seconds
1222 listensocket
->Process();
1225 if (msCur
-msPrevSave
>= 60000) {
1229 // Save total upload/download to preferences
1230 wxConfigBase
* cfg
= wxConfigBase::Get();
1231 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1232 cfg
->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer
);
1234 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1235 cfg
->Write(wxT("/Statistics/TotalUploadedBytes"), buffer
);
1237 // Write changes to file
1243 if (msCur
- msPrevOS
>= thePrefs::GetOSUpdate() * 1000ull) {
1244 OnlineSig(); // Added By Bouc7
1248 if (msCur
- msPrevKnownMet
>= 30*60*1000/*There must be a prefs option for this*/) {
1249 // Save Shared Files data
1251 msPrevKnownMet
= msCur
;
1255 // Recomended by lugdunummaster himself - from emule 0.30c
1256 serverconnect
->KeepConnectionAlive();
1258 // Disarm recursion protection
1263 void CamuleApp::OnFinishedHashing(CHashingEvent
& evt
)
1265 wxCHECK_RET(evt
.GetResult(), wxT("No result of hashing"));
1267 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1268 CKnownFile
* result
= evt
.GetResult();
1271 // Check if the partfile still exists, as it might have
1272 // been deleted in the mean time.
1273 if (downloadqueue
->IsPartFile(owner
)) {
1274 // This cast must not be done before the IsPartFile
1275 // call, as dynamic_cast will barf on dangling pointers.
1276 dynamic_cast<CPartFile
*>(owner
)->PartFileHashFinished(result
);
1279 static int filecount
;
1280 static uint64 bytecount
;
1282 if (knownfiles
->SafeAddKFile(result
)) {
1283 AddDebugLogLineN(logKnownFiles
,
1284 CFormat(wxT("Safe adding file to sharedlist: %s")) % result
->GetFileName());
1285 sharedfiles
->SafeAddKFile(result
);
1288 bytecount
+= result
->GetFileSize();
1289 // If we have added 30 files or files with a total size of ~300mb
1290 if ( ( filecount
== 30 ) || ( bytecount
>= 314572800 ) ) {
1291 AddDebugLogLineN(logKnownFiles
, wxT("Failsafe for crash on file hashing creation"));
1292 if ( m_app_state
!= APP_STATE_SHUTTINGDOWN
) {
1299 AddDebugLogLineN(logKnownFiles
,
1300 CFormat(wxT("File not added to sharedlist: %s")) % result
->GetFileName());
1307 void CamuleApp::OnFinishedAICHHashing(CHashingEvent
& evt
)
1309 wxCHECK_RET(evt
.GetResult(), wxT("No result of AICH-hashing"));
1311 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1312 CScopedPtr
<CKnownFile
> result(evt
.GetResult());
1314 // Check that the owner is still valid
1315 if (knownfiles
->IsKnownFile(owner
)) {
1316 if (result
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
) {
1317 CAICHHashSet
* oldSet
= owner
->GetAICHHashset();
1318 CAICHHashSet
* newSet
= result
->GetAICHHashset();
1320 owner
->SetAICHHashset(newSet
);
1321 newSet
->SetOwner(owner
);
1323 result
->SetAICHHashset(oldSet
);
1324 oldSet
->SetOwner(result
.get());
1330 void CamuleApp::OnFinishedCompletion(CCompletionEvent
& evt
)
1332 CPartFile
* completed
= const_cast<CPartFile
*>(evt
.GetOwner());
1333 wxCHECK_RET(completed
, wxT("Completion event sent for unspecified file"));
1334 wxASSERT_MSG(downloadqueue
->IsPartFile(completed
), wxT("CCompletionEvent for unknown partfile."));
1336 completed
->CompleteFileEnded(evt
.ErrorOccured(), evt
.GetFullPath());
1337 if (evt
.ErrorOccured()) {
1338 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion
, completed
);
1341 // Check if we should execute an script/app/whatever.
1342 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted
, completed
);
1345 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent
& evt
)
1347 CPartFile
*file
= evt
.GetFile();
1348 wxCHECK_RET(file
, wxT("Allocation finished event sent for unspecified file"));
1349 wxASSERT_MSG(downloadqueue
->IsPartFile(file
), wxT("CAllocFinishedEvent for unknown partfile"));
1351 file
->SetStatus(PS_EMPTY
);
1353 if (evt
.Succeeded()) {
1354 if (evt
.IsPaused()) {
1360 AddLogLineN(CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file
->GetFileName() % wxString(UTF82unicode(std::strerror(evt
.GetResult()))));
1364 file
->AllocationFinished();
1367 void CamuleApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
1369 #if defined(AMULE_DAEMON)
1372 if (theApp
->amuledlg
) {
1379 void CamuleApp::ShutDown()
1382 PlatformSpecific::AllowSleepMode();
1385 AddDebugLogLineN(logGeneral
, wxT("CamuleApp::ShutDown() has started."));
1387 // Signal the hashing thread to terminate
1388 m_app_state
= APP_STATE_SHUTTINGDOWN
;
1392 // Kry - Save the sources seeds on app exit
1393 if (thePrefs::GetSrcSeedsOn()) {
1394 downloadqueue
->SaveSourceSeeds();
1397 OnlineSig(true); // Added By Bouc7
1399 // Exit HTTP downloads
1400 CHTTPDownloadThread::StopAll();
1402 // Exit thread scheduler and upload thread
1403 CThreadScheduler::Terminate();
1405 AddDebugLogLineN(logGeneral
, wxT("Terminate upload thread."));
1406 uploadBandwidthThrottler
->EndThread();
1408 // Close sockets to avoid new clients coming in
1410 listensocket
->Close();
1411 listensocket
->KillAllSockets();
1414 if (serverconnect
) {
1415 serverconnect
->Disconnect();
1418 ECServerHandler
->KillAllSockets();
1421 if (thePrefs::GetUPnPEnabled()) {
1423 m_upnp
->DeletePortMappings(m_upnpMappings
);
1428 // saving data & stuff
1433 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1434 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1440 CPath configFileName
= CPath(ConfigDir
+ m_configFile
);
1441 CPath::BackupFile(configFileName
, wxT(".bak"));
1444 clientlist
->DeleteAll();
1448 AddDebugLogLineN(logGeneral
, wxT("CamuleApp::ShutDown() has ended."));
1452 bool CamuleApp::AddServer(CServer
*srv
, bool fromUser
)
1454 if ( serverlist
->AddServer(srv
, fromUser
) ) {
1455 Notify_ServerAdd(srv
);
1462 uint32
CamuleApp::GetPublicIP(bool ignorelocal
) const
1464 if (m_dwPublicIP
== 0) {
1465 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1466 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1468 return ignorelocal
? 0 : m_localip
;
1472 return m_dwPublicIP
;
1476 void CamuleApp::SetPublicIP(const uint32 dwIP
)
1478 wxASSERT((dwIP
== 0) || !IsLowID(dwIP
));
1480 if (dwIP
!= 0 && dwIP
!= m_dwPublicIP
&& serverlist
!= NULL
) {
1481 m_dwPublicIP
= dwIP
;
1482 serverlist
->CheckForExpiredUDPKeys();
1484 m_dwPublicIP
= dwIP
;
1489 wxString
CamuleApp::GetLog(bool reset
)
1492 logfile
.Open(ConfigDir
+ wxT("logfile"));
1493 if ( !logfile
.IsOpened() ) {
1494 return _("ERROR: can't open logfile");
1496 int len
= logfile
.Length();
1498 return _("WARNING: logfile is empty. Something is wrong.");
1500 char *tmp_buffer
= new char[len
+ sizeof(wxChar
)];
1501 logfile
.Read(tmp_buffer
, len
);
1502 memset(tmp_buffer
+ len
, 0, sizeof(wxChar
));
1504 // try to guess file format
1506 if (tmp_buffer
[0] && tmp_buffer
[1]) {
1507 str
= wxString(UTF82unicode(tmp_buffer
));
1509 str
= wxWCharBuffer((wchar_t *)tmp_buffer
);
1512 delete [] tmp_buffer
;
1514 theLogger
.CloseLogfile();
1515 if (theLogger
.OpenLogfile(ConfigDir
+ wxT("logfile"))) {
1516 AddLogLineN(_("Log has been reset"));
1518 ECServerHandler
->ResetAllLogs();
1524 wxString
CamuleApp::GetServerLog(bool reset
)
1526 wxString ret
= server_msg
;
1533 wxString
CamuleApp::GetDebugLog(bool reset
)
1535 return GetLog(reset
);
1539 void CamuleApp::AddServerMessageLine(wxString
&msg
)
1541 server_msg
+= msg
+ wxT("\n");
1542 AddLogLineN(CFormat(_("ServerMessage: %s")) % msg
);
1547 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
1549 switch (event
.GetInt()) {
1551 ipfilter
->DownloadFinished(event
.GetExtraLong());
1553 case HTTP_ServerMet
:
1554 serverlist
->DownloadFinished(event
.GetExtraLong());
1556 case HTTP_ServerMetAuto
:
1557 serverlist
->AutoDownloadFinished(event
.GetExtraLong());
1559 case HTTP_VersionCheck
:
1560 CheckNewVersion(event
.GetExtraLong());
1563 if (event
.GetExtraLong() == HTTP_Success
) {
1565 wxString file
= ConfigDir
+ wxT("nodes.dat");
1566 if (wxFileExists(file
)) {
1570 if ( Kademlia::CKademlia::IsRunning() ) {
1571 Kademlia::CKademlia::Stop();
1574 wxRenameFile(file
+ wxT(".download"),file
);
1576 Kademlia::CKademlia::Start();
1577 theApp
->ShowConnectionState();
1579 } else if (event
.GetExtraLong() == HTTP_Skipped
) {
1580 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1582 AddLogLineC(_("Failed to download the nodes list."));
1585 #ifdef ENABLE_IP2COUNTRY
1587 theApp
->amuledlg
->IP2CountryDownloadFinished(event
.GetExtraLong());
1588 // If we updated, the dialog is already up. Redraw it to show the flags.
1589 theApp
->amuledlg
->Refresh();
1595 void CamuleApp::CheckNewVersion(uint32 result
)
1597 if (result
== HTTP_Success
) {
1598 wxString filename
= ConfigDir
+ wxT("last_version_check");
1601 if (!file
.Open(filename
)) {
1602 AddLogLineC(_("Failed to open the downloaded version check file") );
1604 } else if (!file
.GetLineCount()) {
1605 AddLogLineC(_("Corrupted version check file"));
1607 wxString versionLine
= file
.GetFirstLine();
1608 wxStringTokenizer
tkz(versionLine
, wxT("."));
1610 AddDebugLogLineN(logGeneral
, wxString(wxT("Running: ")) + wxT(VERSION
) + wxT(", Version check: ") + versionLine
);
1612 long fields
[] = {0, 0, 0};
1613 for (int i
= 0; i
< 3; ++i
) {
1614 if (!tkz
.HasMoreTokens()) {
1615 AddLogLineC(_("Corrupted version check file"));
1618 wxString token
= tkz
.GetNextToken();
1620 if (!token
.ToLong(&fields
[i
])) {
1621 AddLogLineC(_("Corrupted version check file"));
1627 long curVer
= make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
);
1628 long newVer
= make_full_ed2k_version(fields
[0], fields
[1], fields
[2]);
1630 if (curVer
< newVer
) {
1631 AddLogLineC(_("You are using an outdated version of aMule!"));
1632 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]);
1633 AddLogLineN(_("The latest version can always be found at http://www.amule.org"));
1635 AddLogLineCS(CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1636 % VERSION_MJR
% VERSION_MIN
% VERSION_UPDATE
% fields
[0] % fields
[1] % fields
[2]);
1639 AddLogLineN(_("Your copy of aMule is up to date."));
1644 wxRemoveFile(filename
);
1646 AddLogLineC(_("Failed to download the version check file"));
1652 bool CamuleApp::IsConnected() const
1654 return (IsConnectedED2K() || IsConnectedKad());
1658 bool CamuleApp::IsConnectedED2K() const
1660 return serverconnect
&& serverconnect
->IsConnected();
1664 bool CamuleApp::IsConnectedKad() const
1666 return Kademlia::CKademlia::IsConnected();
1670 bool CamuleApp::IsFirewalled() const
1672 if (theApp
->IsConnectedED2K() && !theApp
->serverconnect
->IsLowID()) {
1673 return false; // we have an eD2K HighID -> not firewalled
1676 return IsFirewalledKad(); // If kad says ok, it's ok.
1679 bool CamuleApp::IsFirewalledKad() const
1681 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1682 || Kademlia::CKademlia::IsFirewalled();
1685 bool CamuleApp::IsFirewalledKadUDP() const
1687 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1688 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1691 bool CamuleApp::IsKadRunning() const
1693 return Kademlia::CKademlia::IsRunning();
1696 bool CamuleApp::IsKadRunningInLanMode() const
1698 return Kademlia::CKademlia::IsRunningInLANMode();
1702 uint32
CamuleApp::GetKadUsers() const
1704 return Kademlia::CKademlia::GetKademliaUsers();
1707 uint32
CamuleApp::GetKadFiles() const
1709 return Kademlia::CKademlia::GetKademliaFiles();
1712 uint32
CamuleApp::GetKadIndexedSources() const
1714 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource
;
1717 uint32
CamuleApp::GetKadIndexedKeywords() const
1719 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword
;
1722 uint32
CamuleApp::GetKadIndexedNotes() const
1724 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes
;
1727 uint32
CamuleApp::GetKadIndexedLoad() const
1729 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad
;
1733 // True IP of machine
1734 uint32
CamuleApp::GetKadIPAdress() const
1736 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1740 uint8
CamuleApp::GetBuddyStatus() const
1742 return clientlist
->GetBuddyStatus();
1745 uint32
CamuleApp::GetBuddyIP() const
1747 return clientlist
->GetBuddy()->GetIP();
1750 uint32
CamuleApp::GetBuddyPort() const
1752 return clientlist
->GetBuddy()->GetUDPPort();
1755 bool CamuleApp::CanDoCallback(CUpDownClient
*client
)
1757 if (Kademlia::CKademlia::IsConnected()) {
1758 if (IsConnectedED2K()) {
1759 if (serverconnect
->IsLowID()) {
1760 if (Kademlia::CKademlia::IsFirewalled()) {
1761 //Both Connected - Both Firewalled
1764 if (client
->GetServerIP() == theApp
->serverconnect
->GetCurrentServer()->GetIP() &&
1765 client
->GetServerPort() == theApp
->serverconnect
->GetCurrentServer()->GetPort()) {
1766 // Both Connected - Server lowID, Kad Open - Client on same server
1767 // We prevent a callback to the server as this breaks the protocol
1768 // and will get you banned.
1771 // Both Connected - Server lowID, Kad Open - Client on remote server
1776 //Both Connected - Server HighID, Kad don't care
1780 if (Kademlia::CKademlia::IsFirewalled()) {
1781 //Only Kad Connected - Kad Firewalled
1784 //Only Kad Conected - Kad Open
1789 if (IsConnectedED2K()) {
1790 if (serverconnect
->IsLowID()) {
1791 //Only Server Connected - Server LowID
1794 //Only Server Connected - Server HighID
1798 //We are not connected at all!
1804 void CamuleApp::ShowUserCount() {
1805 uint32 totaluser
= 0, totalfile
= 0;
1807 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
1811 static const wxString s_singlenetstatusformat
= _("Users: %s | Files: %s");
1812 static const wxString s_bothnetstatusformat
= _("Users: E: %s K: %s | Files: E: %s K: %s");
1814 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1815 buffer
= CFormat(s_bothnetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile
) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1816 } else if (thePrefs::GetNetworkED2K()) {
1817 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(totalfile
);
1818 } else if (thePrefs::GetNetworkKademlia()) {
1819 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1821 buffer
= _("No networks selected");
1824 Notify_ShowUserCount(buffer
);
1828 void CamuleApp::ListenSocketHandler(wxSocketEvent
& event
)
1830 wxCHECK_RET(listensocket
, wxT("Connection-event for NULL'd listen-socket"));
1831 wxCHECK_RET(event
.GetSocketEvent() == wxSOCKET_CONNECTION
,
1832 wxT("Invalid event received for listen-socket"));
1834 if (m_app_state
== APP_STATE_RUNNING
) {
1835 listensocket
->OnAccept(0);
1836 } else if (m_app_state
== APP_STATE_STARTING
) {
1837 // When starting up, connection may be made before we are able
1838 // to handle them. However, if these are ignored, no futher
1839 // connection-events will be triggered, so we have to accept it.
1840 wxSocketBase
* socket
= listensocket
->Accept(false);
1842 wxCHECK_RET(socket
, wxT("NULL returned by Accept() during startup"));
1849 void CamuleApp::ShowConnectionState(bool forceUpdate
)
1851 static uint8 old_state
= (1<<7); // This flag doesn't exist
1855 if (theApp
->serverconnect
->IsConnected()) {
1856 state
|= CONNECTED_ED2K
;
1859 if (Kademlia::CKademlia::IsRunning()) {
1860 if (Kademlia::CKademlia::IsConnected()) {
1861 if (!Kademlia::CKademlia::IsFirewalled()) {
1862 state
|= CONNECTED_KAD_OK
;
1864 state
|= CONNECTED_KAD_FIREWALLED
;
1867 state
|= CONNECTED_KAD_NOT
;
1871 if (old_state
!= state
) {
1872 // Get the changed value
1873 int changed_flags
= old_state
^ state
;
1875 if (changed_flags
& CONNECTED_ED2K
) {
1876 // ED2K status changed
1877 wxString connected_server
;
1878 CServer
* ed2k_server
= theApp
->serverconnect
->GetCurrentServer();
1880 connected_server
= ed2k_server
->GetListName();
1882 if (state
& CONNECTED_ED2K
) {
1883 // We connected to some server
1884 const wxString id
= theApp
->serverconnect
->IsLowID() ? _("with LowID") : _("with HighID");
1886 AddLogLineC(CFormat(_("Connected to %s %s")) % connected_server
% id
);
1888 if ( theApp
->serverconnect
->IsConnecting() ) {
1889 AddLogLineC(CFormat(_("Connecting to %s")) % connected_server
);
1891 AddLogLineC(_("Disconnected from eD2k"));
1896 if (changed_flags
& CONNECTED_KAD_NOT
) {
1897 if (state
& CONNECTED_KAD_NOT
) {
1898 AddLogLineC(_("Kad started."));
1900 AddLogLineC(_("Kad stopped."));
1904 if (changed_flags
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
1905 if (state
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
1906 if (state
& CONNECTED_KAD_OK
) {
1907 AddLogLineC(_("Connected to Kad (ok)"));
1909 AddLogLineC(_("Connected to Kad (firewalled)"));
1912 AddLogLineC(_("Disconnected from Kad"));
1918 theApp
->downloadqueue
->OnConnectionState(IsConnected());
1922 Notify_ShowConnState(forceUpdate
);
1926 void CamuleApp::UDPSocketHandler(wxSocketEvent
& event
)
1928 CMuleUDPSocket
* socket
= (CMuleUDPSocket
*)(event
.GetClientData());
1929 wxCHECK_RET(socket
, wxT("No socket owner specified."));
1931 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1934 if (event
.GetSocketEvent() == wxSOCKET_INPUT
) {
1935 // Back to the queue!
1936 theApp
->AddPendingEvent(event
);
1941 switch (event
.GetSocketEvent()) {
1942 case wxSOCKET_INPUT
:
1943 socket
->OnReceive(0);
1946 case wxSOCKET_OUTPUT
:
1951 socket
->OnDisconnected(0);
1961 void CamuleApp::OnUnhandledException()
1963 // Call the generic exception-handler.
1964 fprintf(stderr
, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1965 ::OnUnhandledException();
1968 void CamuleApp::StartKad()
1970 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1971 // Kad makes no sense without the Client-UDP socket.
1972 if (!thePrefs::IsUDPDisabled()) {
1973 if (ipfilter
->IsReady()) {
1974 Kademlia::CKademlia::Start();
1976 ipfilter
->StartKADWhenReady();
1979 AddLogLineC(_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1981 } else if (!thePrefs::GetNetworkKademlia()) {
1982 AddLogLineC(_("Kad network disabled on preferences, not connecting."));
1986 void CamuleApp::StopKad()
1988 // Stop Kad if it's running
1989 if (Kademlia::CKademlia::IsRunning()) {
1990 Kademlia::CKademlia::Stop();
1995 void CamuleApp::BootstrapKad(uint32 ip
, uint16 port
)
1997 if (!Kademlia::CKademlia::IsRunning()) {
1998 Kademlia::CKademlia::Start();
1999 theApp
->ShowConnectionState();
2002 Kademlia::CKademlia::Bootstrap(ip
, port
);
2006 void CamuleApp::UpdateNotesDat(const wxString
& url
)
2008 wxString
strTempFilename(theApp
->ConfigDir
+ wxT("nodes.dat.download"));
2010 CHTTPDownloadThread
*downloader
= new CHTTPDownloadThread(url
, strTempFilename
, theApp
->ConfigDir
+ wxT("nodes.dat"), HTTP_NodesDat
, true, false);
2011 downloader
->Create();
2016 void CamuleApp::DisconnectED2K()
2018 // Stop ED2K if it's running
2019 if (IsConnectedED2K()) {
2020 serverconnect
->Disconnect();
2024 bool CamuleApp::CryptoAvailable() const
2026 return clientcredits
&& clientcredits
->CryptoAvailable();
2029 uint32
CamuleApp::GetED2KID() const {
2030 return serverconnect
? serverconnect
->GetClientID() : 0;
2033 uint32
CamuleApp::GetID() const {
2036 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2037 // We trust Kad above ED2K
2038 ID
= ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2039 } else if( theApp
->serverconnect
->IsConnected() ) {
2040 ID
= theApp
->serverconnect
->GetClientID();
2041 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2042 // A firewalled Kad client get's a "1"
2051 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2052 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2053 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2054 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2055 // File_checked_for_headers