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 "Preferences.h" // Needed for CPreferences
70 #include "SearchList.h" // Needed for CSearchList
71 #include "Server.h" // Needed for GetListName
72 #include "ServerList.h" // Needed for CServerList
73 #include "ServerConnect.h" // Needed for CServerConnect
74 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
75 #include "Statistics.h" // Needed for CStatistics
76 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
77 #include "ThreadTasks.h"
78 #include "updownclient.h" // Needed for CUpDownClient
79 #include "UploadQueue.h" // Needed for CUploadQueue
80 #include "UploadBandwidthThrottler.h"
81 #include "UserEvents.h"
82 #include "ScopedPtr.h"
85 #include "UPnPBase.h" // Needed for UPnP
89 #include <wx/sysopt.h> // Do_not_auto_remove
94 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
95 #if wxCHECK_VERSION(2, 9, 0)
96 #include <wx/osx/core/cfstring.h> // Do_not_auto_remove
98 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
101 #include <wx/msgdlg.h>
103 #include "amuleDlg.h"
107 #ifdef HAVE_SYS_RESOURCE_H
108 #include <sys/resource.h>
111 #ifdef HAVE_SYS_STATVFS_H
112 #include <sys/statvfs.h> // Do_not_auto_remove
117 # define RLIMIT_RESOURCE __rlimit_resource
119 # define RLIMIT_RESOURCE int
123 CamuleDaemonApp
*theApp
;
125 CamuleGuiApp
*theApp
;
128 static void UnlimitResource(RLIMIT_RESOURCE resType
)
130 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
132 getrlimit(resType
, &rl
);
133 rl
.rlim_cur
= rl
.rlim_max
;
134 setrlimit(resType
, &rl
);
139 static void SetResourceLimits()
141 #ifdef HAVE_SYS_RESOURCE_H
142 UnlimitResource(RLIMIT_DATA
);
144 UnlimitResource(RLIMIT_FSIZE
);
146 UnlimitResource(RLIMIT_NOFILE
);
148 UnlimitResource(RLIMIT_RSS
);
153 // We store the received signal in order to avoid race-conditions
154 // in the signal handler.
155 bool g_shutdownSignal
= false;
157 void OnShutdownSignal( int /* sig */ )
159 signal(SIGINT
, SIG_DFL
);
160 signal(SIGTERM
, SIG_DFL
);
162 g_shutdownSignal
= true;
165 theApp
->ExitMainLoop();
170 CamuleApp::CamuleApp()
172 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
173 // Kry - I love to init the vars on init, even before timer.
177 m_app_state
= APP_STATE_STARTING
;
179 theApp
= &wxGetApp();
184 canceledfiles
= NULL
;
186 serverconnect
= NULL
;
190 clientcredits
= NULL
;
192 downloadqueue
= NULL
;
195 ECServerHandler
= NULL
;
198 uploadBandwidthThrottler
= NULL
;
201 m_upnpMappings
.resize(4);
209 enable_daemon_fork
= false;
211 strFullMuleVersion
= NULL
;
212 strOSDescription
= NULL
;
214 // Apprently needed for *BSD
218 _CrtSetDbgFlag(0); // Disable useless memleak debugging
222 CamuleApp::~CamuleApp()
224 // Closing the log-file as the very last thing, since
225 // wxWidgets log-events are saved in it as well.
226 theLogger
.CloseLogfile();
228 if (strFullMuleVersion
) {
229 free(strFullMuleVersion
);
231 if (strOSDescription
) {
232 free(strOSDescription
);
236 int CamuleApp::OnExit()
238 if (m_app_state
!=APP_STATE_STARTING
) {
239 AddLogLineMS(false, _("Now, exiting main app..."));
242 // From wxWidgets docs, wxConfigBase:
244 // Note that you must delete this object (usually in wxApp::OnExit)
245 // in order to avoid memory leaks, wxWidgets won't do it automatically.
247 // As it happens, you may even further simplify the procedure described
248 // above: you may forget about calling Set(). When Get() is called and
249 // there is no current object, it will create one using Create() function.
250 // To disable this behaviour DontCreateOnDemand() is provided.
251 delete wxConfigBase::Set((wxConfigBase
*)NULL
);
254 clientcredits
->SaveList();
256 // Kill amuleweb if running
258 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid `%ld' ... ")) % webserver_pid
);
260 if (wxKill(webserver_pid
, wxSIGTERM
, &rc
) == -1) {
261 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid `%ld' ... ")) % webserver_pid
);
262 if (wxKill(webserver_pid
, wxSIGKILL
, &rc
) == -1) {
263 AddLogLineNS(_("Failed"));
268 if (m_app_state
!=APP_STATE_STARTING
) {
269 AddLogLineMS(false, _("aMule OnExit: Terminating core."));
278 delete clientcredits
;
279 clientcredits
= NULL
;
284 // Destroying CDownloadQueue calls destructor for CPartFile
285 // calling CSharedFileList::SafeAddKFile occasionally.
289 delete serverconnect
;
290 serverconnect
= NULL
;
301 delete canceledfiles
;
302 canceledfiles
= NULL
;
310 delete downloadqueue
;
311 downloadqueue
= NULL
;
321 delete ECServerHandler
;
322 ECServerHandler
= NULL
;
329 CPreferences::EraseItemList();
331 delete uploadBandwidthThrottler
;
332 uploadBandwidthThrottler
= NULL
;
334 if (m_app_state
!=APP_STATE_STARTING
) {
335 AddLogLineNS(_("aMule shutdown completed."));
338 #if wxUSE_MEMORY_TRACING
339 AddLogLineNS(_("Memory debug results for aMule exit:"));
340 // Log mem debug mesages to wxLogStderr
341 wxLog
* oldLog
= wxLog::SetActiveTarget(new wxLogStderr
);
342 //AddLogLineNS(wxT("**************Classes**************");
343 //wxDebugContext::PrintClasses();
344 //AddLogLineNS(wxT("***************Dump***************");
345 //wxDebugContext::Dump();
346 AddLogLineNS(wxT("***************Stats**************"));
347 wxDebugContext::PrintStatistics(true);
349 // Set back to wxLogGui
350 delete wxLog::SetActiveTarget(oldLog
);
355 // Return 0 for succesful program termination
356 return AMULE_APP_BASE::OnExit();
360 int CamuleApp::InitGui(bool, wxString
&)
367 // Application initialization
369 bool CamuleApp::OnInit()
371 #if wxUSE_MEMORY_TRACING
372 // any text before call of Localize_mule needs not to be translated.
373 AddLogLineMS(false, wxT("Checkpoint set on app init for memory debug"));
374 wxDebugContext::SetCheckpoint();
377 // Forward wxLog events to CLogger
378 wxLog::SetActiveTarget(new CLoggerTarget
);
380 m_localip
= StringHosttoUint32(::wxGetFullHostName());
383 // get rid of sigpipe
384 signal(SIGPIPE
, SIG_IGN
);
387 signal(SIGBREAK
, OnShutdownSignal
);
389 // Handle sigint and sigterm
390 signal(SIGINT
, OnShutdownSignal
);
391 signal(SIGTERM
, OnShutdownSignal
);
394 // For listctrl's to behave on Mac
395 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
398 // Handle uncaught exceptions
399 InstallMuleExceptionHandler();
401 if (!InitCommon(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
)) {
405 glob_prefs
= new CPreferences();
408 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir
+ wxT("Temp"), outDir
)) {
409 thePrefs::SetTempDir(outDir
);
414 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir
+ wxT("Incoming"), outDir
)) {
415 thePrefs::SetIncomingDir(outDir
);
421 if (!thePrefs::UseTrayIcon()) {
422 thePrefs::SetMinToTray(false);
425 // Build the filenames for the two OS files
426 SetOSFiles(thePrefs::GetOSDir().GetRaw());
429 // Load localization settings
433 // Configure EC for amuled when invoked with ec-config
435 AddLogLineMS(false, _("\nEC configuration"));
436 thePrefs::SetECPass(GetPassword());
437 thePrefs::EnableExternalConnections(true);
438 AddLogLineMS(false, _("Password set and external connections enabled."));
444 wxT("Warning! You are running aMule as root.\n")
445 wxT("Doing so is not recommended for security reasons,\n")
446 wxT("and you are advised to run aMule as an normal\n")
447 wxT("user instead.");
449 ShowAlert(msg
, _("WARNING"), wxCENTRE
| wxOK
| wxICON_ERROR
);
451 fprintf(stderr
, "\n--------------------------------------------------\n");
452 fprintf(stderr
, "%s", (const char*)unicode2UTF8(msg
));
453 fprintf(stderr
, "\n--------------------------------------------------\n\n");
457 // Display notification on new version or first run
458 wxTextFile
vfile( ConfigDir
+ wxT("lastversion") );
459 wxString
newMule(wxT( VERSION
));
461 if ( !wxFileExists( vfile
.GetName() ) ) {
465 if ( vfile
.Open() ) {
466 // Check if this version has been run before
468 for ( size_t i
= 0; i
< vfile
.GetLineCount(); i
++ ) {
469 // Check if this version has been run before
470 if ( vfile
.GetLine(i
) == newMule
) {
476 // We havent run this version before?
478 // Insert new at top to provide faster searches
479 vfile
.InsertLine( newMule
, 0 );
481 Trigger_New_version( newMule
);
484 // Keep at most 10 entires
485 while ( vfile
.GetLineCount() > 10 )
486 vfile
.RemoveLine( vfile
.GetLineCount() - 1 );
492 // Check if we have the old style locale config
493 wxString langId
= thePrefs::GetLanguageID();
494 if (!langId
.IsEmpty() && (langId
.GetChar(0) >= '0' && langId
.GetChar(0) <= '9')) {
495 wxString
info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
496 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT
));
497 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
500 m_statistics
= new CStatistics();
502 clientlist
= new CClientList();
503 friendlist
= new CFriendList();
504 searchlist
= new CSearchList();
505 knownfiles
= new CKnownFileList();
506 canceledfiles
= new CCanceledFileList
;
507 serverlist
= new CServerList();
509 sharedfiles
= new CSharedFileList(knownfiles
);
510 clientcredits
= new CClientCreditsList();
512 // bugfix - do this before creating the uploadqueue
513 downloadqueue
= new CDownloadQueue();
514 uploadqueue
= new CUploadQueue();
515 ipfilter
= new CIPFilter();
517 // Creates all needed listening sockets
519 if (!ReinitializeNetwork(&msg
)) {
520 AddLogLineMS(false, wxT("\n"));
521 AddLogLineMS(false, msg
);
524 // Test if there's any new version
525 if (thePrefs::GetCheckNewVersion()) {
526 // We use the thread base because I don't want a dialog to pop up.
527 CHTTPDownloadThread
* version_check
=
528 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
529 theApp
->ConfigDir
+ wxT("last_version_check"), theApp
->ConfigDir
+ wxT("last_version"), HTTP_VersionCheck
, false);
530 version_check
->Create();
531 version_check
->Run();
534 // Create main dialog, or fork to background (daemon).
535 InitGui(m_geometryEnabled
, m_geometryString
);
538 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
539 if (enable_daemon_fork
) {
540 RefreshSingleInstanceChecker();
541 // No need to check IsAnotherRunning() - we've done it before.
545 // Has to be created after the call to InitGui, as fork
546 // (when using posix threads) only replicates the mainthread,
547 // and the UBT constructor creates a thread.
548 uploadBandwidthThrottler
= new UploadBandwidthThrottler();
550 // Start performing background tasks
551 // This will start loading the IP filter. It will start right away.
552 // Log is confusing, because log entries from background will only be printed
553 // once foreground becomes idle, and that will only be after loading
554 // of the partfiles has finished.
555 CThreadScheduler::Start();
557 // These must be initialized after the gui is loaded.
558 if (thePrefs::GetNetworkED2K()) {
561 downloadqueue
->LoadMetFiles(thePrefs::GetTempDir());
562 sharedfiles
->Reload();
564 // Ensure that the up/down ratio is used
565 CPreferences::CheckUlDlRatio();
567 // The user can start pressing buttons like mad if he feels like it.
568 m_app_state
= APP_STATE_RUNNING
;
570 // Kry - Load the sources seeds on app init
571 if (thePrefs::GetSrcSeedsOn() && ipfilter
->IsReady()) {
572 downloadqueue
->LoadSourceSeeds();
575 if (!serverlist
->GetServerCount() && thePrefs::GetNetworkED2K()) {
576 // There are no servers and ED2K active -> ask for download.
577 // As we cannot ask in amuled, we just update there
578 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
580 if (wxYES
== wxMessageBox(
582 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
583 wxString(_("Server list download")),
585 static_cast<wxWindow
*>(theApp
->amuledlg
)))
588 // workaround amuled crash
590 serverlist
->UpdateServerMetFromURL(
591 wxT("http://gruk.org/server.met.gz"));
597 // Autoconnect if that option is enabled
598 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
599 if (ipfilter
->IsReady()) {
600 // If it's not ready it will connect later, so don't print it now.
601 AddLogLineC(_("Connecting"));
603 if (thePrefs::GetNetworkED2K()) {
604 theApp
->serverconnect
->ConnectToAnyServer();
612 #ifdef ENABLE_IP2COUNTRY
613 theApp
->amuledlg
->EnableIP2Country();
617 if (thePrefs::GetWSIsEnabled()) {
618 wxString aMuleConfigFile
= ConfigDir
+ m_configFile
;
619 wxString amulewebPath
= thePrefs::GetWSPath();
621 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
622 // For the Mac GUI application, look for amuleweb in the bundle
623 CFURLRef amulewebUrl
= CFBundleCopyAuxiliaryExecutableURL(
624 CFBundleGetMainBundle(), CFSTR("amuleweb"));
627 CFURLRef absoluteUrl
= CFURLCopyAbsoluteURL(amulewebUrl
);
628 CFRelease(amulewebUrl
);
631 CFStringRef amulewebCfstr
= CFURLCopyFileSystemPath(absoluteUrl
, kCFURLPOSIXPathStyle
);
632 CFRelease(absoluteUrl
);
633 #if wxCHECK_VERSION(2, 9, 0)
634 amulewebPath
= wxCFStringRef(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
636 amulewebPath
= wxMacCFStringHolder(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
643 # define QUOTE wxT("\"")
645 # define QUOTE wxT("\'")
651 QUOTE
wxT(" ") QUOTE
wxT("--amule-config-file=") +
654 CTerminationProcessAmuleweb
*p
= new CTerminationProcessAmuleweb(cmd
, &webserver_pid
);
655 webserver_pid
= wxExecute(cmd
, wxEXEC_ASYNC
, p
);
656 bool webserver_ok
= webserver_pid
> 0;
658 AddLogLineM(true, CFormat(_("web server running on pid %d")) % webserver_pid
);
662 "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"),
663 _("ERROR"), wxOK
| wxICON_ERROR
);
670 bool CamuleApp::ReinitializeNetwork(wxString
* msg
)
673 static bool firstTime
= true;
676 // TODO: Destroy previously created sockets
680 // Some sanity checks first
681 if (thePrefs::ECPort() == thePrefs::GetPort()) {
682 // Select a random usable port in the range 1025 ... 2^16 - 1
683 uint16 port
= thePrefs::ECPort();
684 while ( port
< 1024 || port
== thePrefs::GetPort() ) {
685 port
= (uint16
)rand();
687 thePrefs::SetECPort( port
);
690 wxT("Network configuration failed! You cannot use the same port\n")
691 wxT("for the main TCP port and the External Connections port.\n")
692 wxT("The EC port has been changed to avoid conflict, see the\n")
693 wxT("preferences for the new value.\n");
696 AddLogLineM( false, wxEmptyString
);
697 AddLogLineM( true, err
);
698 AddLogLineM( false, wxEmptyString
);
703 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
704 // Select a random usable value in the range 1025 ... 2^16 - 1
705 uint16 port
= thePrefs::GetUDPPort();
706 while ( port
< 1024 || port
== thePrefs::GetPort() + 3 ) {
707 port
= (uint16
)rand();
709 thePrefs::SetUDPPort( port
);
712 wxT("Network configuration failed! You set your UDP port to\n")
713 wxT("the value of the main TCP port plus 3.\n")
714 wxT("This port has been reserved for the Server-UDP port. The\n")
715 wxT("port value has been changed to avoid conflict, see the\n")
716 wxT("preferences for the new value\n");
719 AddLogLineM( false, wxEmptyString
);
720 AddLogLineM( true, err
);
721 AddLogLineM( false, wxEmptyString
);
726 // Create the address where we are going to listen
727 // TODO: read this from configuration file
728 amuleIPV4Address myaddr
[4];
730 // Create the External Connections Socket.
732 // Get ready to handle connections from apps like amulecmd
733 if (thePrefs::GetECAddress().IsEmpty() || !myaddr
[0].Hostname(thePrefs::GetECAddress())) {
734 myaddr
[0].AnyAddress();
736 myaddr
[0].Service(thePrefs::ECPort());
737 ECServerHandler
= new ExternalConn(myaddr
[0], msg
);
739 // Create the UDP socket TCP+3.
740 // Used for source asking on servers.
741 if (thePrefs::GetAddress().IsEmpty()) {
742 myaddr
[1].AnyAddress();
743 } else if (!myaddr
[1].Hostname(thePrefs::GetAddress())) {
744 myaddr
[1].AnyAddress();
745 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
746 % thePrefs::GetAddress());
749 wxString ip
= myaddr
[1].IPAddress();
750 myaddr
[1].Service(thePrefs::GetPort()+3);
751 serverconnect
= new CServerConnect(serverlist
, myaddr
[1]);
752 *msg
<< CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
753 % ip
% ((unsigned int)thePrefs::GetPort() + 3u);
755 // Create the ListenSocket (aMule TCP socket).
756 // Used for Client Port / Connections from other clients,
757 // Client to Client Source Exchange.
759 myaddr
[2] = myaddr
[1];
760 myaddr
[2].Service(thePrefs::GetPort());
761 listensocket
= new CListenSocket(myaddr
[2]);
762 *msg
<< CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
763 % ip
% (unsigned int)(thePrefs::GetPort());
764 // This command just sets a flag to control maximum number of connections.
765 // Notify(true) has already been called to the ListenSocket, so events may
766 // be already comming in.
767 if (listensocket
->Ok()) {
768 listensocket
->StartListening();
770 // If we wern't able to start listening, we need to warn the user
772 err
= CFormat(_("Port %u is not available. You will be LOWID\n")) %
773 (unsigned int)(thePrefs::GetPort());
775 AddLogLineM(true, err
);
778 _("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.")) %
779 (unsigned int)(thePrefs::GetPort());
780 ShowAlert(err
, _("ERROR"), wxOK
| wxICON_ERROR
);
783 // Create the UDP socket.
784 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
785 // Also used for Kademlia.
786 // Default is port 4672.
787 myaddr
[3] = myaddr
[1];
788 myaddr
[3].Service(thePrefs::GetUDPPort());
789 clientudp
= new CClientUDPSocket(myaddr
[3], thePrefs::GetProxyData());
790 if (!thePrefs::IsUDPDisabled()) {
791 *msg
<< CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
792 % ip
% thePrefs::GetUDPPort();
794 *msg
<< wxT("*** Client UDP socket (extended eMule) disabled on preferences");
798 if (thePrefs::GetUPnPEnabled()) {
800 m_upnpMappings
[0] = CUPnPPortMapping(
803 thePrefs::GetUPnPECEnabled(),
804 "aMule TCP External Connections Socket");
805 m_upnpMappings
[1] = CUPnPPortMapping(
808 thePrefs::GetUPnPEnabled(),
809 "aMule UDP socket (TCP+3)");
810 m_upnpMappings
[2] = CUPnPPortMapping(
813 thePrefs::GetUPnPEnabled(),
814 "aMule TCP Listen Socket");
815 m_upnpMappings
[3] = CUPnPPortMapping(
818 thePrefs::GetUPnPEnabled(),
819 "aMule UDP Extended eMule Socket");
820 m_upnp
= new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
821 m_upnp
->AddPortMappings(m_upnpMappings
);
822 } catch(CUPnPException
&e
) {
824 error_msg
<< e
.what();
825 AddLogLineM(true, error_msg
);
826 fprintf(stderr
, "%s\n", (const char *)unicode2char(error_msg
));
834 /* Original implementation by Bouc7 of the eMule Project.
835 aMule Signature idea was designed by BigBob and implemented
836 by Un-Thesis, with design inputs and suggestions from bothie.
838 void CamuleApp::OnlineSig(bool zero
/* reset stats (used on shutdown) */)
840 // Do not do anything if online signature is disabled in Preferences
841 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path
.IsEmpty()) {
842 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
843 // that means m_amulesig_path is empty too.
847 // Remove old signature files
848 if ( wxFileExists( m_emulesig_path
) ) { wxRemoveFile( m_emulesig_path
); }
849 if ( wxFileExists( m_amulesig_path
) ) { wxRemoveFile( m_amulesig_path
); }
852 wxTextFile amulesig_out
;
853 wxTextFile emulesig_out
;
855 // Open both files if needed
856 if ( !emulesig_out
.Create( m_emulesig_path
) ) {
857 AddLogLineM(true, _("Failed to create OnlineSig File"));
858 // Will never try again.
859 m_amulesig_path
.Clear();
860 m_emulesig_path
.Clear();
864 if ( !amulesig_out
.Create(m_amulesig_path
) ) {
865 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
866 // Will never try again.
867 m_amulesig_path
.Clear();
868 m_emulesig_path
.Clear();
872 wxString emulesig_string
;
876 emulesig_string
= wxT("0\xA0.0|0.0|0");
877 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
879 if (IsConnectedED2K()) {
881 temp
= wxString::Format(wxT("%d"),serverconnect
->GetCurrentServer()->GetPort());
888 + serverconnect
->GetCurrentServer()->GetListName()
890 // IP and port of the server
891 + serverconnect
->GetCurrentServer()->GetFullIP()
898 // Connected. State 1, full info
899 amulesig_out
.AddLine(wxT("1"));
901 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetListName());
903 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetFullIP());
905 amulesig_out
.AddLine(temp
);
907 if (serverconnect
->IsLowID()) {
908 amulesig_out
.AddLine(wxT("L"));
910 amulesig_out
.AddLine(wxT("H"));
913 } else if (serverconnect
->IsConnecting()) {
914 emulesig_string
= wxT("0");
916 // Connecting. State 2, No info.
917 amulesig_out
.AddLine(wxT("2\n0\n0\n0\n0"));
919 // Not connected to a server
920 emulesig_string
= wxT("0");
922 // Not connected, state 0, no info
923 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0"));
925 if (IsConnectedKad()) {
926 if(Kademlia::CKademlia::IsFirewalled()) {
927 // Connected. Firewalled. State 1.
928 amulesig_out
.AddLine(wxT("1"));
930 // Connected. State 2.
931 amulesig_out
.AddLine(wxT("2"));
934 // Not connected.State 0.
935 amulesig_out
.AddLine(wxT("0"));
937 emulesig_string
+= wxT("\xA");
939 // Datarate for downloads
940 temp
= wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
942 emulesig_string
+= temp
+ wxT("|");
943 amulesig_out
.AddLine(temp
);
945 // Datarate for uploads
946 temp
= wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
948 emulesig_string
+= temp
+ wxT("|");
949 amulesig_out
.AddLine(temp
);
951 // Number of users waiting for upload
952 temp
= wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
954 emulesig_string
+= temp
;
955 amulesig_out
.AddLine(temp
);
957 // Number of shared files (not on eMule)
958 amulesig_out
.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
961 // eMule signature finished here. Write the line to the wxTextFile.
962 emulesig_out
.AddLine(emulesig_string
);
964 // Now for aMule signature extras
966 // Nick on the network
967 amulesig_out
.AddLine(thePrefs::GetUserNick());
969 // Total received in bytes
970 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
972 // Total sent in bytes
973 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
977 amulesig_out
.AddLine(wxT(VERSION
) wxT(" ") wxT(SVNDATE
));
979 amulesig_out
.AddLine(wxT(VERSION
));
983 amulesig_out
.AddLine(wxT("0"));
984 amulesig_out
.AddLine(wxT("0"));
985 amulesig_out
.AddLine(wxT("0"));
987 // Total received bytes in session
988 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
989 theStats::GetSessionReceivedBytes() );
991 // Total sent bytes in session
992 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
993 theStats::GetSessionSentBytes() );
996 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1000 emulesig_out
.Write();
1001 amulesig_out
.Write();
1002 } //End Added By Bouc7
1005 // Gracefully handle fatal exceptions and print backtrace if possible
1006 void CamuleApp::OnFatalException()
1008 /* Print the backtrace */
1009 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1010 fprintf(stderr
, "A fatal error has occurred and aMule has crashed.\n");
1011 fprintf(stderr
, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1012 fprintf(stderr
, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1013 fprintf(stderr
, "circumstances of this crash. The forum is located here:\n");
1014 fprintf(stderr
, " http://forum.amule.org/index.php?board=67.0\n");
1015 fprintf(stderr
, "If possible, please try to generate a real backtrace of this crash:\n");
1016 fprintf(stderr
, " http://wiki.amule.org/index.php/Backtraces\n\n");
1017 fprintf(stderr
, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1018 fprintf(stderr
, "Current version is: %s\n", strFullMuleVersion
);
1019 fprintf(stderr
, "Running on: %s\n\n", strOSDescription
);
1021 print_backtrace(1); // 1 == skip this function.
1023 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1027 // Sets the localization of aMule
1028 void CamuleApp::Localize_mule()
1030 InitCustomLanguages();
1031 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
1032 if (!m_locale
.IsOk()) {
1033 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1038 // Displays information related to important changes in aMule.
1039 // Is called when the user runs a new version of aMule
1040 void CamuleApp::Trigger_New_version(wxString new_version
)
1042 wxString info
= wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version
+ wxT(" ---\n\n");
1043 if (new_version
== wxT("SVN")) {
1044 info
+= _("This version is a testing version, updated daily, and\n");
1045 info
+= _("we give no warranty it won't break anything, burn your house,\n");
1046 info
+= _("or kill your dog. But it *should* be safe to use anyway.\n");
1051 info
+= _("More information, support and new releases can found at our homepage,\n");
1052 info
+= _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1054 info
+= _("Feel free to report any bugs to http://forum.amule.org");
1056 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
1060 void CamuleApp::SetOSFiles(const wxString new_path
)
1062 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1063 if ( ::wxDirExists(new_path
) ) {
1064 m_emulesig_path
= JoinPaths(new_path
, wxT("onlinesig.dat"));
1065 m_amulesig_path
= JoinPaths(new_path
, wxT("amulesig.dat"));
1067 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
);
1068 m_emulesig_path
.Clear();
1069 m_amulesig_path
.Clear();
1072 m_emulesig_path
.Clear();
1073 m_amulesig_path
.Clear();
1079 #ifndef wxUSE_STACKWALKER
1080 #define wxUSE_STACKWALKER 0
1082 void CamuleApp::OnAssertFailure(const wxChar
* file
, int line
,
1083 const wxChar
* func
, const wxChar
* cond
, const wxChar
* msg
)
1085 if (!wxUSE_STACKWALKER
|| !wxThread::IsMain() || !IsRunning()) {
1086 wxString errmsg
= CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1087 % file
% func
% line
% cond
% ( msg
? msg
: wxT("") );
1089 fprintf(stderr
, "Assertion failed: %s\n", (const char*)unicode2char(errmsg
));
1091 // Skip the function-calls directly related to the assert call.
1092 fprintf(stderr
, "\nBacktrace follows:\n");
1094 fprintf(stderr
, "\n");
1097 if (wxThread::IsMain() && IsRunning()) {
1098 AMULE_APP_BASE::OnAssertFailure(file
, line
, func
, cond
, msg
);
1100 // Abort, allows gdb to catch the assertion
1107 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent
& evt
)
1109 CServerUDPSocket
* socket
=(CServerUDPSocket
*)evt
.GetClientData();
1110 socket
->OnHostnameResolved(evt
.GetExtraLong());
1114 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent
& evt
)
1116 downloadqueue
->OnHostnameResolved(evt
.GetExtraLong());
1120 void CamuleApp::OnServerDnsDone(CMuleInternalEvent
& evt
)
1122 AddLogLineMS(false, _("Server hostname notified"));
1123 serverconnect
->OnServerHostnameResolved(evt
.GetClientData(), evt
.GetExtraLong());
1127 void CamuleApp::OnTCPTimer(CTimerEvent
& WXUNUSED(evt
))
1132 serverconnect
->StopConnectionTry();
1133 if (IsConnectedED2K() ) {
1136 serverconnect
->ConnectToAnyServer();
1140 void CamuleApp::OnCoreTimer(CTimerEvent
& WXUNUSED(evt
))
1142 // Former TimerProc section
1143 static uint64 msPrev1
, msPrev5
, msPrevSave
, msPrevHist
, msPrevOS
, msPrevKnownMet
;
1144 uint64 msCur
= theStats::GetUptimeMillis();
1145 TheTime
= msCur
/ 1000;
1151 #ifndef AMULE_DAEMON
1152 // Check if we should terminate the app
1153 if ( g_shutdownSignal
) {
1154 wxWindow
* top
= GetTopWindow();
1159 // No top-window, have to force termination.
1165 // There is a theoretical chance that the core time function can recurse:
1166 // if an event function gets blocked on a mutex (communicating with the
1167 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1168 // If CPU load gets high a new core timer event could be generated before the last
1169 // one was finished and so recursion could occur, which would be bad.
1170 // Detect this and do an early return then.
1171 static bool recurse
= false;
1177 uploadqueue
->Process();
1178 downloadqueue
->Process();
1179 //theApp->clientcredits->Process();
1180 theStats::CalculateRates();
1182 if (msCur
-msPrevHist
> 1000) {
1183 // unlike the other loop counters in this function this one will sometimes
1184 // produce two calls in quick succession (if there was a gap of more than one
1185 // second between calls to TimerProc) - this is intentional! This way the
1186 // history list keeps an average of one node per second and gets thinned out
1187 // correctly as time progresses.
1190 m_statistics
->RecordHistory();
1195 if (msCur
-msPrev1
> 1000) { // approximately every second
1197 clientcredits
->Process();
1198 clientlist
->Process();
1200 // Publish files to server if needed.
1201 sharedfiles
->Process();
1203 if( Kademlia::CKademlia::IsRunning() ) {
1204 Kademlia::CKademlia::Process();
1205 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1209 if (thePrefs::Reconnect()) {
1215 if( serverconnect
->IsConnecting() && !serverconnect
->IsSingleConnect() ) {
1216 serverconnect
->TryAnotherConnectionrequest();
1218 if (serverconnect
->IsConnecting()) {
1219 serverconnect
->CheckForTimeout();
1221 listensocket
->UpdateConnectionsStatus();
1226 if (msCur
-msPrev5
> 5000) { // every 5 seconds
1228 listensocket
->Process();
1231 if (msCur
-msPrevSave
>= 60000) {
1235 // Save total upload/download to preferences
1236 wxConfigBase
* cfg
= wxConfigBase::Get();
1237 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1238 cfg
->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer
);
1240 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1241 cfg
->Write(wxT("/Statistics/TotalUploadedBytes"), buffer
);
1243 // Write changes to file
1249 if (msCur
- msPrevOS
>= thePrefs::GetOSUpdate() * 1000ull) {
1250 OnlineSig(); // Added By Bouc7
1254 if (msCur
- msPrevKnownMet
>= 30*60*1000/*There must be a prefs option for this*/) {
1255 // Save Shared Files data
1257 msPrevKnownMet
= msCur
;
1261 // Recomended by lugdunummaster himself - from emule 0.30c
1262 serverconnect
->KeepConnectionAlive();
1264 // Disarm recursion protection
1269 void CamuleApp::OnFinishedHashing(CHashingEvent
& evt
)
1271 wxCHECK_RET(evt
.GetResult(), wxT("No result of hashing"));
1273 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1274 CKnownFile
* result
= evt
.GetResult();
1277 // Check if the partfile still exists, as it might have
1278 // been deleted in the mean time.
1279 if (downloadqueue
->IsPartFile(owner
)) {
1280 // This cast must not be done before the IsPartFile
1281 // call, as dynamic_cast will barf on dangling pointers.
1282 dynamic_cast<CPartFile
*>(owner
)->PartFileHashFinished(result
);
1285 static int filecount
;
1286 static uint64 bytecount
;
1288 if (knownfiles
->SafeAddKFile(result
)) {
1289 AddDebugLogLineM(false, logKnownFiles
,
1290 CFormat(wxT("Safe adding file to sharedlist: %s")) % result
->GetFileName());
1291 sharedfiles
->SafeAddKFile(result
);
1294 bytecount
+= result
->GetFileSize();
1295 // If we have added 30 files or files with a total size of ~300mb
1296 if ( ( filecount
== 30 ) || ( bytecount
>= 314572800 ) ) {
1297 AddDebugLogLineM(false, logKnownFiles
, wxT("Failsafe for crash on file hashing creation"));
1298 if ( m_app_state
!= APP_STATE_SHUTTINGDOWN
) {
1305 AddDebugLogLineM(false, logKnownFiles
,
1306 CFormat(wxT("File not added to sharedlist: %s")) % result
->GetFileName());
1313 void CamuleApp::OnFinishedAICHHashing(CHashingEvent
& evt
)
1315 wxCHECK_RET(evt
.GetResult(), wxT("No result of AICH-hashing"));
1317 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1318 CScopedPtr
<CKnownFile
> result(evt
.GetResult());
1320 // Check that the owner is still valid
1321 if (knownfiles
->IsKnownFile(owner
)) {
1322 if (result
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
) {
1323 CAICHHashSet
* oldSet
= owner
->GetAICHHashset();
1324 CAICHHashSet
* newSet
= result
->GetAICHHashset();
1326 owner
->SetAICHHashset(newSet
);
1327 newSet
->SetOwner(owner
);
1329 result
->SetAICHHashset(oldSet
);
1330 oldSet
->SetOwner(result
.get());
1336 void CamuleApp::OnFinishedCompletion(CCompletionEvent
& evt
)
1338 CPartFile
* completed
= const_cast<CPartFile
*>(evt
.GetOwner());
1339 wxCHECK_RET(completed
, wxT("Completion event sent for unspecified file"));
1340 wxASSERT_MSG(downloadqueue
->IsPartFile(completed
), wxT("CCompletionEvent for unknown partfile."));
1342 completed
->CompleteFileEnded(evt
.ErrorOccured(), evt
.GetFullPath());
1343 if (evt
.ErrorOccured()) {
1344 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion
, completed
);
1347 // Check if we should execute an script/app/whatever.
1348 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted
, completed
);
1351 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent
& evt
)
1353 CPartFile
*file
= evt
.GetFile();
1354 wxCHECK_RET(file
, wxT("Allocation finished event sent for unspecified file"));
1355 wxASSERT_MSG(downloadqueue
->IsPartFile(file
), wxT("CAllocFinishedEvent for unknown partfile"));
1357 file
->SetPartFileStatus(PS_EMPTY
);
1359 if (evt
.Succeeded()) {
1360 if (evt
.IsPaused()) {
1366 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file
->GetFileName() % wxString(UTF82unicode(std::strerror(evt
.GetResult()))));
1370 file
->AllocationFinished();
1373 void CamuleApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
1375 #if defined(AMULE_DAEMON)
1378 if (theApp
->amuledlg
) {
1385 void CamuleApp::ShutDown()
1388 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has started."));
1390 // Signal the hashing thread to terminate
1391 m_app_state
= APP_STATE_SHUTTINGDOWN
;
1395 // Kry - Save the sources seeds on app exit
1396 if (thePrefs::GetSrcSeedsOn()) {
1397 downloadqueue
->SaveSourceSeeds();
1400 OnlineSig(true); // Added By Bouc7
1402 // Exit HTTP downloads
1403 CHTTPDownloadThread::StopAll();
1405 // Exit thread scheduler and upload thread
1406 CThreadScheduler::Terminate();
1408 AddDebugLogLineN(logGeneral
, wxT("Terminate upload thread."));
1409 uploadBandwidthThrottler
->EndThread();
1411 // Close sockets to avoid new clients coming in
1413 listensocket
->Close();
1414 listensocket
->KillAllSockets();
1417 if (serverconnect
) {
1418 serverconnect
->Disconnect();
1421 ECServerHandler
->KillAllSockets();
1424 if (thePrefs::GetUPnPEnabled()) {
1426 m_upnp
->DeletePortMappings(m_upnpMappings
);
1431 // saving data & stuff
1436 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1437 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1443 CPath configFileName
= CPath(ConfigDir
+ m_configFile
);
1444 CPath::BackupFile(configFileName
, wxT(".bak"));
1447 clientlist
->DeleteAll();
1451 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has ended."));
1455 bool CamuleApp::AddServer(CServer
*srv
, bool fromUser
)
1457 if ( serverlist
->AddServer(srv
, fromUser
) ) {
1458 Notify_ServerAdd(srv
);
1465 uint32
CamuleApp::GetPublicIP(bool ignorelocal
) const
1467 if (m_dwPublicIP
== 0) {
1468 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1469 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1471 return ignorelocal
? 0 : m_localip
;
1475 return m_dwPublicIP
;
1479 void CamuleApp::SetPublicIP(const uint32 dwIP
)
1481 wxASSERT((dwIP
== 0) || !IsLowID(dwIP
));
1483 if (dwIP
!= 0 && dwIP
!= m_dwPublicIP
&& serverlist
!= NULL
) {
1484 m_dwPublicIP
= dwIP
;
1485 serverlist
->CheckForExpiredUDPKeys();
1487 m_dwPublicIP
= dwIP
;
1492 wxString
CamuleApp::GetLog(bool reset
)
1495 logfile
.Open(ConfigDir
+ wxT("logfile"));
1496 if ( !logfile
.IsOpened() ) {
1497 return _("ERROR: can't open logfile");
1499 int len
= logfile
.Length();
1501 return _("WARNING: logfile is empty. Something is wrong.");
1503 char *tmp_buffer
= new char[len
+ sizeof(wxChar
)];
1504 logfile
.Read(tmp_buffer
, len
);
1505 memset(tmp_buffer
+ len
, 0, sizeof(wxChar
));
1507 // try to guess file format
1509 if (tmp_buffer
[0] && tmp_buffer
[1]) {
1510 str
= wxString(UTF82unicode(tmp_buffer
));
1512 str
= wxWCharBuffer((wchar_t *)tmp_buffer
);
1515 delete [] tmp_buffer
;
1517 theLogger
.CloseLogfile();
1518 if (theLogger
.OpenLogfile(ConfigDir
+ wxT("logfile"))) {
1519 AddLogLineM(false, _("Log has been reset"));
1526 wxString
CamuleApp::GetServerLog(bool reset
)
1528 wxString ret
= server_msg
;
1535 wxString
CamuleApp::GetDebugLog(bool reset
)
1537 return GetLog(reset
);
1541 void CamuleApp::AddServerMessageLine(wxString
&msg
)
1543 server_msg
+= msg
+ wxT("\n");
1544 AddLogLineM(false, CFormat(_("ServerMessage: %s")) % msg
);
1549 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
1551 switch (event
.GetInt()) {
1553 ipfilter
->DownloadFinished(event
.GetExtraLong());
1555 case HTTP_ServerMet
:
1556 serverlist
->DownloadFinished(event
.GetExtraLong());
1558 case HTTP_ServerMetAuto
:
1559 serverlist
->AutoDownloadFinished(event
.GetExtraLong());
1561 case HTTP_VersionCheck
:
1562 CheckNewVersion(event
.GetExtraLong());
1565 if (event
.GetExtraLong() == HTTP_Success
) {
1567 wxString file
= ConfigDir
+ wxT("nodes.dat");
1568 if (wxFileExists(file
)) {
1572 if ( Kademlia::CKademlia::IsRunning() ) {
1573 Kademlia::CKademlia::Stop();
1576 wxRenameFile(file
+ wxT(".download"),file
);
1578 Kademlia::CKademlia::Start();
1579 theApp
->ShowConnectionState();
1581 } else if (event
.GetExtraLong() == HTTP_Skipped
) {
1582 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1584 AddLogLineC(_("Failed to download the nodes list."));
1587 #ifdef ENABLE_IP2COUNTRY
1589 theApp
->amuledlg
->IP2CountryDownloadFinished(event
.GetExtraLong());
1590 // If we updated, the dialog is already up. Redraw it to show the flags.
1591 theApp
->amuledlg
->Refresh();
1597 void CamuleApp::CheckNewVersion(uint32 result
)
1599 if (result
== HTTP_Success
) {
1600 wxString filename
= ConfigDir
+ wxT("last_version_check");
1603 if (!file
.Open(filename
)) {
1604 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1606 } else if (!file
.GetLineCount()) {
1607 AddLogLineM(true, _("Corrupted version check file"));
1609 wxString versionLine
= file
.GetFirstLine();
1610 wxStringTokenizer
tkz(versionLine
, wxT("."));
1612 AddDebugLogLineM(false, logGeneral
, wxString(wxT("Running: ")) + wxT(VERSION
) + wxT(", Version check: ") + versionLine
);
1614 long fields
[] = {0, 0, 0};
1615 for (int i
= 0; i
< 3; ++i
) {
1616 if (!tkz
.HasMoreTokens()) {
1617 AddLogLineM(true, _("Corrupted version check file"));
1620 wxString token
= tkz
.GetNextToken();
1622 if (!token
.ToLong(&fields
[i
])) {
1623 AddLogLineM(true, _("Corrupted version check file"));
1629 long curVer
= make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
);
1630 long newVer
= make_full_ed2k_version(fields
[0], fields
[1], fields
[2]);
1632 if (curVer
< newVer
) {
1633 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1634 AddLogLineM(false, wxString::Format(_("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]));
1635 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1637 AddLogLineMS(true, CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1638 % VERSION_MJR
% VERSION_MIN
% VERSION_UPDATE
% fields
[0] % fields
[1] % fields
[2]);
1641 AddLogLineM(false, _("Your copy of aMule is up to date."));
1646 wxRemoveFile(filename
);
1648 AddLogLineM(true, _("Failed to download the version check file"));
1654 bool CamuleApp::IsConnected() const
1656 return (IsConnectedED2K() || IsConnectedKad());
1660 bool CamuleApp::IsConnectedED2K() const
1662 return serverconnect
&& serverconnect
->IsConnected();
1666 bool CamuleApp::IsConnectedKad() const
1668 return Kademlia::CKademlia::IsConnected();
1672 bool CamuleApp::IsFirewalled() const
1674 if (theApp
->IsConnectedED2K() && !theApp
->serverconnect
->IsLowID()) {
1675 return false; // we have an eD2K HighID -> not firewalled
1678 return IsFirewalledKad(); // If kad says ok, it's ok.
1681 bool CamuleApp::IsFirewalledKad() const
1683 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1684 || Kademlia::CKademlia::IsFirewalled();
1687 bool CamuleApp::IsFirewalledKadUDP() const
1689 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1690 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1693 bool CamuleApp::IsKadRunning() const
1695 return Kademlia::CKademlia::IsRunning();
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
->GetBuddy()->GetIP();
1747 uint32
CamuleApp::GetBuddyPort() const
1749 return clientlist
->GetBuddy()->GetUDPPort();
1752 bool CamuleApp::CanDoCallback(CUpDownClient
*client
)
1754 if (Kademlia::CKademlia::IsConnected()) {
1755 if (IsConnectedED2K()) {
1756 if (serverconnect
->IsLowID()) {
1757 if (Kademlia::CKademlia::IsFirewalled()) {
1758 //Both Connected - Both Firewalled
1761 if (client
->GetServerIP() == theApp
->serverconnect
->GetCurrentServer()->GetIP() &&
1762 client
->GetServerPort() == theApp
->serverconnect
->GetCurrentServer()->GetPort()) {
1763 // Both Connected - Server lowID, Kad Open - Client on same server
1764 // We prevent a callback to the server as this breaks the protocol
1765 // and will get you banned.
1768 // Both Connected - Server lowID, Kad Open - Client on remote server
1773 //Both Connected - Server HighID, Kad don't care
1777 if (Kademlia::CKademlia::IsFirewalled()) {
1778 //Only Kad Connected - Kad Firewalled
1781 //Only Kad Conected - Kad Open
1786 if (IsConnectedED2K()) {
1787 if (serverconnect
->IsLowID()) {
1788 //Only Server Connected - Server LowID
1791 //Only Server Connected - Server HighID
1795 //We are not connected at all!
1801 void CamuleApp::ShowUserCount() {
1802 uint32 totaluser
= 0, totalfile
= 0;
1804 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
1808 static const wxString s_singlenetstatusformat
= _("Users: %s | Files: %s");
1809 static const wxString s_bothnetstatusformat
= _("Users: E: %s K: %s | Files: E: %s K: %s");
1811 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1812 buffer
= CFormat(s_bothnetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile
) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1813 } else if (thePrefs::GetNetworkED2K()) {
1814 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(totalfile
);
1815 } else if (thePrefs::GetNetworkKademlia()) {
1816 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1818 buffer
= _("No networks selected");
1821 Notify_ShowUserCount(buffer
);
1825 void CamuleApp::ListenSocketHandler(wxSocketEvent
& event
)
1827 wxCHECK_RET(listensocket
, wxT("Connection-event for NULL'd listen-socket"));
1828 wxCHECK_RET(event
.GetSocketEvent() == wxSOCKET_CONNECTION
,
1829 wxT("Invalid event received for listen-socket"));
1831 if (m_app_state
== APP_STATE_RUNNING
) {
1832 listensocket
->OnAccept(0);
1833 } else if (m_app_state
== APP_STATE_STARTING
) {
1834 // When starting up, connection may be made before we are able
1835 // to handle them. However, if these are ignored, no futher
1836 // connection-events will be triggered, so we have to accept it.
1837 wxSocketBase
* socket
= listensocket
->Accept(false);
1839 wxCHECK_RET(socket
, wxT("NULL returned by Accept() during startup"));
1846 void CamuleApp::ShowConnectionState()
1848 static uint8 old_state
= (1<<7); // This flag doesn't exist
1852 if (theApp
->serverconnect
->IsConnected()) {
1853 state
|= CONNECTED_ED2K
;
1856 if (Kademlia::CKademlia::IsRunning()) {
1857 if (Kademlia::CKademlia::IsConnected()) {
1858 if (!Kademlia::CKademlia::IsFirewalled()) {
1859 state
|= CONNECTED_KAD_OK
;
1861 state
|= CONNECTED_KAD_FIREWALLED
;
1864 state
|= CONNECTED_KAD_NOT
;
1868 Notify_ShowConnState(state
);
1870 if (old_state
!= state
) {
1871 // Get the changed value
1872 int changed_flags
= old_state
^ state
;
1874 if (changed_flags
& CONNECTED_ED2K
) {
1875 // ED2K status changed
1876 wxString connected_server
;
1877 CServer
* ed2k_server
= theApp
->serverconnect
->GetCurrentServer();
1879 connected_server
= ed2k_server
->GetListName();
1881 if (state
& CONNECTED_ED2K
) {
1882 // We connected to some server
1883 const wxString id
= theApp
->serverconnect
->IsLowID() ? _("with LowID") : _("with HighID");
1885 AddLogLineM(true, CFormat(_("Connected to %s %s")) % connected_server
% id
);
1887 if ( theApp
->serverconnect
->IsConnecting() ) {
1888 AddLogLineM(true, CFormat(_("Connecting to %s")) % connected_server
);
1890 AddLogLineM(true, _("Disconnected from eD2k"));
1895 if (changed_flags
& CONNECTED_KAD_NOT
) {
1896 if (state
& CONNECTED_KAD_NOT
) {
1897 AddLogLineM(true, _("Kad started."));
1899 AddLogLineM(true, _("Kad stopped."));
1903 if (changed_flags
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
1904 if (state
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
1905 if (state
& CONNECTED_KAD_OK
) {
1906 AddLogLineM(true, _("Connected to Kad (ok)"));
1908 AddLogLineM(true, _("Connected to Kad (firewalled)"));
1911 AddLogLineM(true, _("Disconnected from Kad"));
1917 theApp
->downloadqueue
->OnConnectionState(IsConnected());
1921 Notify_ShowConnState(state
);
1925 void CamuleApp::UDPSocketHandler(wxSocketEvent
& event
)
1927 CMuleUDPSocket
* socket
= (CMuleUDPSocket
*)(event
.GetClientData());
1928 wxCHECK_RET(socket
, wxT("No socket owner specified."));
1930 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1933 if (event
.GetSocketEvent() == wxSOCKET_INPUT
) {
1934 // Back to the queue!
1935 theApp
->AddPendingEvent(event
);
1940 switch (event
.GetSocketEvent()) {
1941 case wxSOCKET_INPUT
:
1942 socket
->OnReceive(0);
1945 case wxSOCKET_OUTPUT
:
1950 socket
->OnDisconnected(0);
1960 void CamuleApp::OnUnhandledException()
1962 // Call the generic exception-handler.
1963 fprintf(stderr
, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1964 ::OnUnhandledException();
1967 void CamuleApp::StartKad()
1969 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1970 // Kad makes no sense without the Client-UDP socket.
1971 if (!thePrefs::IsUDPDisabled()) {
1972 if (ipfilter
->IsReady()) {
1973 Kademlia::CKademlia::Start();
1975 ipfilter
->StartKADWhenReady();
1978 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1980 } else if (!thePrefs::GetNetworkKademlia()) {
1981 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
1985 void CamuleApp::StopKad()
1987 // Stop Kad if it's running
1988 if (Kademlia::CKademlia::IsRunning()) {
1989 Kademlia::CKademlia::Stop();
1994 void CamuleApp::BootstrapKad(uint32 ip
, uint16 port
)
1996 if (!Kademlia::CKademlia::IsRunning()) {
1997 Kademlia::CKademlia::Start();
1998 theApp
->ShowConnectionState();
2001 Kademlia::CKademlia::Bootstrap(ip
, port
, true);
2005 void CamuleApp::UpdateNotesDat(const wxString
& url
)
2007 wxString
strTempFilename(theApp
->ConfigDir
+ wxT("nodes.dat.download"));
2009 CHTTPDownloadThread
*downloader
= new CHTTPDownloadThread(url
, strTempFilename
, theApp
->ConfigDir
+ wxT("nodes.dat"), HTTP_NodesDat
);
2010 downloader
->Create();
2015 void CamuleApp::DisconnectED2K()
2017 // Stop ED2K if it's running
2018 if (IsConnectedED2K()) {
2019 serverconnect
->Disconnect();
2023 bool CamuleApp::CryptoAvailable() const
2025 return clientcredits
&& clientcredits
->CryptoAvailable();
2028 uint32
CamuleApp::GetED2KID() const {
2029 return serverconnect
? serverconnect
->GetClientID() : 0;
2032 uint32
CamuleApp::GetID() const {
2035 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2036 // We trust Kad above ED2K
2037 ID
= ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2038 } else if( theApp
->serverconnect
->IsConnected() ) {
2039 ID
= theApp
->serverconnect
->GetClientID();
2040 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2041 // A firewalled Kad client get's a "1"
2050 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2051 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2052 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2053 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2054 // File_checked_for_headers