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 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
30 #include "amule.h" // Interface declarations.
33 #include <wx/process.h>
34 #include <wx/sstream.h>
37 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
38 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H and VERSION
41 #include <common/ClientVersion.h>
43 #include <wx/cmdline.h> // Needed for wxCmdLineParser
44 #include <wx/config.h> // Do_not_auto_remove (win32)
45 #include <wx/fileconf.h>
46 #include <wx/snglinst.h>
47 #include <wx/tokenzr.h>
48 #include <wx/wfstream.h>
51 #include <common/Format.h> // Needed for CFormat
52 #include "kademlia/kademlia/Kademlia.h"
53 #include "kademlia/kademlia/Prefs.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"
84 #include "UPnP.h" // Needed for UPnP
88 #include <wx/sysopt.h> // Do_not_auto_remove
93 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
94 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
96 #include <wx/msgdlg.h>
102 #ifdef HAVE_SYS_RESOURCE_H
103 #include <sys/resource.h>
106 #ifdef HAVE_SYS_STATVFS_H
107 #include <sys/statvfs.h> // Do_not_auto_remove
112 # define RLIMIT_RESOURCE __rlimit_resource
114 # define RLIMIT_RESOURCE int
117 static void UnlimitResource(RLIMIT_RESOURCE resType
)
119 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
121 getrlimit(resType
, &rl
);
122 rl
.rlim_cur
= rl
.rlim_max
;
123 setrlimit(resType
, &rl
);
128 static void SetResourceLimits()
130 #ifdef HAVE_SYS_RESOURCE_H
131 UnlimitResource(RLIMIT_DATA
);
132 UnlimitResource(RLIMIT_FSIZE
);
133 UnlimitResource(RLIMIT_NOFILE
);
135 UnlimitResource(RLIMIT_RSS
);
140 // We store the received signal in order to avoid race-conditions
141 // in the signal handler.
142 bool g_shutdownSignal
= false;
144 void OnShutdownSignal( int /* sig */ )
146 signal(SIGINT
, SIG_DFL
);
147 signal(SIGTERM
, SIG_DFL
);
149 g_shutdownSignal
= true;
152 theApp
->ExitMainLoop();
157 CamuleApp::CamuleApp()
159 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
160 // Kry - I love to init the vars on init, even before timer.
164 m_app_state
= APP_STATE_STARTING
;
166 theApp
= &wxGetApp();
172 serverconnect
= NULL
;
176 clientcredits
= NULL
;
178 downloadqueue
= NULL
;
181 ECServerHandler
= NULL
;
182 m_singleInstance
= NULL
;
185 uploadBandwidthThrottler
= NULL
;
188 m_upnpMappings
.resize(4);
197 enable_stdout_log
= false;
198 enable_daemon_fork
= false;
200 strFullMuleVersion
= NULL
;
201 strOSDescription
= NULL
;
203 // Apprently needed for *BSD
207 CamuleApp::~CamuleApp()
209 // Closing the log-file as the very last thing, since
210 // wxWidgets log-events are saved in it as well.
215 int CamuleApp::OnExit()
217 if (m_app_state
!=APP_STATE_STARTING
) {
218 printf("Now, exiting main app...\n");
221 // From wxWidgets docs, wxConfigBase:
223 // Note that you must delete this object (usually in wxApp::OnExit)
224 // in order to avoid memory leaks, wxWidgets won't do it automatically.
226 // As it happens, you may even further simplify the procedure described
227 // above: you may forget about calling Set(). When Get() is called and
228 // there is no current object, it will create one using Create() function.
229 // To disable this behaviour DontCreateOnDemand() is provided.
230 delete wxConfigBase::Set((wxConfigBase
*)NULL
);
233 clientcredits
->SaveList();
235 // Kill amuleweb if running
237 printf("Killing amuleweb instance with pid `%ld' ... ", webserver_pid
);
239 wxKill(webserver_pid
, wxSIGTERM
, &rc
);
243 if (m_app_state
!=APP_STATE_STARTING
) {
244 printf("aMule OnExit: Terminating core.\n");
253 delete clientcredits
;
254 clientcredits
= NULL
;
259 // Destroying CDownloadQueue calls destructor for CPartFile
260 // calling CSharedFileList::SafeAddKFile occasionally.
264 delete serverconnect
;
265 serverconnect
= NULL
;
282 delete downloadqueue
;
283 downloadqueue
= NULL
;
293 delete ECServerHandler
;
294 ECServerHandler
= NULL
;
301 CPreferences::EraseItemList();
303 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
304 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
306 delete m_singleInstance
;
308 m_singleInstance
= NULL
;
310 delete uploadBandwidthThrottler
;
311 uploadBandwidthThrottler
= NULL
;
313 if (m_app_state
!=APP_STATE_STARTING
) {
314 printf("aMule shutdown completed.\n");
317 #if wxUSE_MEMORY_TRACING
318 printf("Memory debug results for aMule exit:\n");
319 // Log mem debug mesages to wxLogStderr
320 wxLog
* oldLog
= wxLog::SetActiveTarget(new wxLogStderr
);
322 printf("**************Classes**************\n");
323 wxDebugContext::PrintClasses();
325 //printf("***************Dump***************\n");
326 //wxDebugContext::Dump();
327 printf("***************Stats**************\n");
328 wxDebugContext::PrintStatistics(true);
330 // Set back to wxLogGui
331 delete wxLog::SetActiveTarget(oldLog
);
336 // Return 0 for succesful program termination
337 return AMULE_APP_BASE::OnExit();
341 int CamuleApp::InitGui(bool, wxString
&)
348 * Checks permissions on a aMule directory, creating if needed.
350 * @param desc A description of the directory in question, used for error messages.
351 * @param directory The directory in question.
352 * @param fallback If the dir specified with 'directory' could not be created, try this instead.
353 * @return The bool is false on error. The wxString contains the used path.
355 std::pair
<bool, CPath
> CheckMuleDirectory(const wxString
& desc
, const CPath
& directory
, const wxString
& alternative
)
359 if (directory
.IsDir(CPath::readwritable
)) {
360 return std::pair
<bool, CPath
>(true, directory
);
361 } else if (directory
.DirExists()) {
362 msg
= CFormat(wxT("Permissions on the %s directory too strict!\n")
363 wxT("aMule cannot proceed. To fix this, you must set read/write/exec\n")
364 wxT("permissions for the folder '%s'"))
366 } else if (CPath::MakeDir(directory
)) {
367 return std::pair
<bool, CPath
>(true, directory
);
369 msg
<< CFormat(wxT("Could not create the %s directory at '%s'."))
373 // Attempt to use fallback directory.
374 const CPath fallback
= CPath(alternative
);
375 if (fallback
.IsOk() && (directory
!= fallback
)) {
376 msg
<< wxT("\nAttempting to use default directory at location \n'")
377 << alternative
<< wxT("'.");
378 theApp
->ShowAlert(msg
, wxT("Error accessing directory."), wxICON_ERROR
| wxOK
);
380 return CheckMuleDirectory(desc
, fallback
, wxEmptyString
);
383 theApp
->ShowAlert(msg
, wxT("Fatal error."), wxICON_ERROR
| wxOK
);
384 return std::pair
<bool, wxString
>(false, wxEmptyString
);
389 // Application initialization
391 bool CamuleApp::OnInit()
393 #if wxUSE_MEMORY_TRACING
394 printf("Checkpoint set on app init for memory debug\n");
395 wxDebugContext::SetCheckpoint();
398 // Forward wxLog events to CLogger
399 wxLog::SetActiveTarget(new CLoggerTarget
);
401 m_localip
= StringHosttoUint32(::wxGetFullHostName());
404 // get rid of sigpipe
405 signal(SIGPIPE
, SIG_IGN
);
406 // Handle sigint and sigterm
407 signal(SIGINT
, OnShutdownSignal
);
408 signal(SIGTERM
, OnShutdownSignal
);
412 // For listctrl's to behave on Mac
413 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
416 // This can't be on constructor or wx2.4.2 doesn't set it.
417 SetVendorName(wxT("TikuWarez"));
418 SetAppName(wxT("aMule"));
420 wxString FullMuleVersion
= GetFullMuleVersion();
421 wxString OSDescription
= wxGetOsDescription();
422 strFullMuleVersion
= strdup((const char *)unicode2char(FullMuleVersion
));
423 strOSDescription
= strdup((const char *)unicode2char(OSDescription
));
424 OSType
= OSDescription
.BeforeFirst( wxT(' ') );
425 if ( OSType
.IsEmpty() ) {
426 OSType
= wxT("Unknown");
429 // Handle uncaught exceptions
430 InstallMuleExceptionHandler();
432 // Parse cmdline arguments.
433 wxCmdLineParser
cmdline(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
);
435 // Handle these arguments.
436 cmdline
.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
437 cmdline
.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
438 cmdline
.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
440 cmdline
.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
441 cmdline
.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
442 cmdline
.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
444 cmdline
.AddOption(wxT("geometry"), wxEmptyString
,
445 wxT("Sets the geometry of the app.\n")
446 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
447 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
449 cmdline
.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
450 cmdline
.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
451 cmdline
.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
453 // Show help on --help or invalid commands
454 if ( cmdline
.Parse() ) {
456 } else if ( cmdline
.Found(wxT("help")) ) {
461 bool ec_config
= false;
464 ec_config
= cmdline
.Found(wxT("ec-config"));
465 if ( cmdline
.Found(wxT("config-dir"), &ConfigDir
) ) {
466 if (ConfigDir
.Last() != wxFileName::GetPathSeparator()) {
467 ConfigDir
+= wxFileName::GetPathSeparator();
470 ConfigDir
= GetConfigDir();
473 ConfigDir
= GetConfigDir();
476 if ( !cmdline
.Found(wxT("disable-fatal")) ) {
478 // catch fatal exceptions
479 wxHandleFatalExceptions(true);
483 bool reset_config
= cmdline
.Found(wxT("reset-config"));
485 enable_stdout_log
= cmdline
.Found(wxT("log-stdout"));
487 enable_daemon_fork
= cmdline
.Found(wxT("full-daemon"));
489 enable_daemon_fork
= false;
492 if ( enable_stdout_log
) {
493 if ( enable_daemon_fork
) {
494 printf("Daemon will fork to background - log to stdout disabled\n");
495 enable_stdout_log
= false;
497 printf("Logging to stdout enabled\n");
501 if ( cmdline
.Found(wxT("version")) ) {
502 printf("%s (OS: %s)\n",
503 (const char*)unicode2char(GetFullMuleVersion()),
504 (const char*)unicode2char(OSType
));
509 // Default geometry of the GUI. Can be changed with a cmdline argument...
510 bool geometry_enabled
= false;
511 wxString geom_string
;
513 if ( cmdline
.Found(wxT("geometry"), &geom_string
) ) {
514 geometry_enabled
= true;
519 printf("Initialising aMule\n");
521 // Ensure that "~/.aMule/" is accessible.
522 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir
), wxEmptyString
).first
) {
527 // Make a backup first.
528 wxRemoveFile(ConfigDir
+ wxT("amule.conf.backup"));
529 wxRenameFile(ConfigDir
+ wxT("amule.conf"), ConfigDir
+ wxT("amule.conf.backup"));
530 printf("Your settings have ben resetted to default values.\nOld config file has been saved as amule.conf.backup\n");
533 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
534 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
535 printf("WARNING: The check for other instances is currently disabled in amuled.\n"
536 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n");
538 printf("Checking if there is an instance already running...\n");
540 m_singleInstance
= new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir
);
541 if (m_singleInstance
->IsAnotherRunning()) {
542 printf("There is an instance of aMule already running\n");
544 // This is very tricky. The most secure way to communicate is via ED2K links file
545 wxTextFile
ed2kFile(ConfigDir
+ wxT("ED2KLinks"));
546 if (!ed2kFile
.Exists()) {
550 if (ed2kFile
.Open()) {
551 ed2kFile
.AddLine(wxT("RAISE_DIALOG"));
554 printf("Raising current running instance.\n");
556 printf("Failed to open 'ED2KFile', cannot signal running instance.\n");
561 printf("No other instances are running.\n");
565 // Close standard-input
566 if ( !cmdline
.Found(wxT("enable-stdin")) ) {
567 // The full daemon will close all std file-descriptors by itself,
568 // so closing it here would lead to the closing on the first open
569 // file, which is the logfile opened below
570 if (!enable_daemon_fork
) {
575 // This creates the CFG file we shall use
576 wxConfigBase
* cfg
= new wxFileConfig( wxEmptyString
, wxEmptyString
, ConfigDir
+ wxT("amule.conf") );
578 // Set the config object as the global cfg file
579 wxConfig::Set( cfg
);
581 // Make a backup of the log file
582 CPath logfileName
= CPath(ConfigDir
+ wxT("logfile"));
583 if (logfileName
.FileExists()) {
584 CPath::BackupFile(logfileName
, wxT(".bak"));
588 applog
= new wxFFileOutputStream(logfileName
.GetRaw());
590 // use std err as last resolt to indicate problem
591 fputs("ERROR: unable to open log file\n", stderr
);
594 // failure to open log is serious problem
599 CPreferences::BuildItemList(ConfigDir
);
600 CPreferences::LoadAllItems( wxConfigBase::Get() );
602 glob_prefs
= new CPreferences();
604 std::pair
<bool, CPath
> checkResult
;
605 checkResult
= CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir
+ wxT("Temp"));
606 if (checkResult
.first
) {
607 thePrefs::SetTempDir(checkResult
.second
);
612 checkResult
= CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir
+ wxT("Incoming"));
613 if (checkResult
.first
) {
614 thePrefs::SetIncomingDir(checkResult
.second
);
620 if (!thePrefs::UseTrayIcon()) {
621 thePrefs::SetMinToTray(false);
624 // Build the filenames for the two OS files
625 SetOSFiles(thePrefs::GetOSDir().GetRaw());
627 // Load localization settings
630 // Configure EC for amuled when invoked with ec-config
632 printf("\nEC configuration\n");
633 thePrefs::SetECPass(GetPassword());
634 thePrefs::EnableExternalConnections(true);
635 printf("Password set and external connections enabled.\n");
638 // Display notification on new version or first run
639 wxTextFile
vfile( ConfigDir
+ wxT("lastversion") );
640 wxString
newMule(wxT( VERSION
));
642 // Test if there's any new version
643 if (thePrefs::CheckNewVersion()) {
644 // We use the thread base because I don't want a dialog to pop up.
645 CHTTPDownloadThread
* version_check
=
646 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
647 theApp
->ConfigDir
+ wxT("last_version_check"), HTTP_VersionCheck
, false);
648 version_check
->Create();
649 version_check
->Run();
652 if ( !wxFileExists( vfile
.GetName() ) ) {
659 wxT("Warning! You are running aMule as root.\n")
660 wxT("Doing so is not recommended for security reasons,\n")
661 wxT("and you are advised to run aMule as an normal\n")
662 wxT("user instead.");
664 ShowAlert(msg
, _("Warning"), wxCENTRE
| wxOK
| wxICON_ERROR
);
666 fprintf(stderr
, "\n--------------------------------------------------\n");
667 fprintf(stderr
, "%s", (const char*)unicode2UTF8(msg
));
668 fprintf(stderr
, "\n--------------------------------------------------\n\n");
672 if ( vfile
.Open() ) {
673 // Check if this version has been run before
675 for ( size_t i
= 0; i
< vfile
.GetLineCount(); i
++ ) {
676 // Check if this version has been run before
677 if ( vfile
.GetLine(i
) == newMule
) {
683 // We havent run this version before?
685 // Insert new at top to provide faster searches
686 vfile
.InsertLine( newMule
, 0 );
688 Trigger_New_version( newMule
);
691 // Keep at most 10 entires
692 while ( vfile
.GetLineCount() > 10 )
693 vfile
.RemoveLine( vfile
.GetLineCount() - 1 );
699 // Check if we have the old style locale config
700 wxString langId
= thePrefs::GetLanguageID();
701 if (!langId
.IsEmpty() && (langId
.GetChar(0) >= '0' && langId
.GetChar(0) <= '9')) {
702 wxString
info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
703 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT
));
704 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
707 m_statistics
= new CStatistics();
709 clientlist
= new CClientList();
710 friendlist
= new CFriendList();
711 searchlist
= new CSearchList();
712 knownfiles
= new CKnownFileList();
713 serverlist
= new CServerList();
715 sharedfiles
= new CSharedFileList(knownfiles
);
716 clientcredits
= new CClientCreditsList();
718 // bugfix - do this before creating the uploadqueue
719 downloadqueue
= new CDownloadQueue();
720 uploadqueue
= new CUploadQueue();
721 ipfilter
= new CIPFilter();
723 // Creates all needed listening sockets
725 if (!ReinitializeNetwork(&msg
)) {
726 printf("\n%s\n", (const char *)unicode2char(msg
));
729 // Create main dialog, or fork to background (daemon).
730 InitGui(geometry_enabled
, geom_string
);
732 // Has to be created after the call to InitGui, as fork
733 // (when using posix threads) only replicates the mainthread,
734 // and the UBT constructor creates a thread.
735 uploadBandwidthThrottler
= new UploadBandwidthThrottler();
737 // These must be initialized after the gui is loaded.
739 downloadqueue
->LoadMetFiles(thePrefs::GetTempDir());
740 sharedfiles
->Reload();
742 if (thePrefs::IPFilterAutoLoad()) {
743 ipfilter
->Update(thePrefs::IPFilterURL());
747 // Ensure that the up/down ratio is used
748 CPreferences::CheckUlDlRatio();
750 // The user can start pressing buttons like mad if he feels like it.
751 m_app_state
= APP_STATE_RUNNING
;
753 // Kry - Load the sources seeds on app init
754 if (thePrefs::GetSrcSeedsOn()) {
755 downloadqueue
->LoadSourceSeeds();
758 if (!serverlist
->GetServerCount() && thePrefs::GetNetworkED2K()) {
759 // There are no servers and ED2K active -> ask for download.
760 // As we cannot ask in amuled, we just update there
761 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
763 if (wxYES
== wxMessageBox(
765 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
766 wxString(_("Server list download")),
768 static_cast<wxWindow
*>(theApp
->amuledlg
)))
771 // workaround amuled crash
773 serverlist
->UpdateServerMetFromURL(
774 wxT("http://gruk.org/server.met.gz"));
780 // Autoconnect if that option is enabled
781 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
782 AddLogLineM(true, _("Connecting"));
783 if (thePrefs::GetNetworkED2K()) {
784 theApp
->serverconnect
->ConnectToAnyServer();
791 // No webserver on Win at all (yet)
794 if (thePrefs::GetWSIsEnabled()) {
795 wxString aMuleConfigFile
= ConfigDir
+ wxT("amule.conf");
796 wxString amulewebPath
= wxT("amuleweb");
798 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
799 // For the Mac GUI application, look for amuleweb in the bundle
800 CFURLRef amulewebUrl
= CFBundleCopyAuxiliaryExecutableURL(
801 CFBundleGetMainBundle(), CFSTR("amuleweb"));
804 CFURLRef absoluteUrl
= CFURLCopyAbsoluteURL(amulewebUrl
);
805 CFRelease(amulewebUrl
);
808 CFStringRef amulewebCfstr
= CFURLCopyFileSystemPath(absoluteUrl
, kCFURLPOSIXPathStyle
);
809 CFRelease(absoluteUrl
);
810 amulewebPath
= wxMacCFStringHolder(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
818 wxT("' '--amule-config-file=") +
821 CTerminationProcessAmuleweb
*p
= new CTerminationProcessAmuleweb(cmd
, &webserver_pid
);
822 webserver_pid
= wxExecute(cmd
, wxEXEC_ASYNC
, p
);
823 bool webserver_ok
= webserver_pid
> 0;
825 AddLogLineM(true, CFormat(_("webserver running on pid %d")) % webserver_pid
);
829 "You requested to run webserver from startup, "
830 "but the amuleweb binary cannot be run. "
831 "Please install the package containing aMule webserver, "
832 "or compile aMule using --enable-webserver and run make install"),
833 _("Error"), wxOK
| wxICON_ERROR
);
836 #endif /* ! __WXMSW__ */
838 // Start performing background tasks
839 CThreadScheduler::Start();
844 bool CamuleApp::ReinitializeNetwork(wxString
* msg
)
847 static bool firstTime
= true;
850 // TODO: Destroy previously created sockets
854 // Some sanity checks first
855 if (thePrefs::ECPort() == thePrefs::GetPort()) {
856 // Select a random usable port in the range 1025 ... 2^16 - 1
857 uint16 port
= thePrefs::ECPort();
858 while ( port
< 1024 || port
== thePrefs::GetPort() ) {
859 port
= (uint16
)rand();
861 thePrefs::SetECPort( port
);
864 wxT("Network configuration failed! You cannot use the same port\n")
865 wxT("for the main TCP port and the External Connections port.\n")
866 wxT("The EC port has been changed to avoid conflict, see the\n")
867 wxT("preferences for the new value.\n");
870 AddLogLineM( false, wxEmptyString
);
871 AddLogLineM( true, err
);
872 AddLogLineM( false, wxEmptyString
);
877 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
878 // Select a random usable value in the range 1025 ... 2^16 - 1
879 uint16 port
= thePrefs::GetUDPPort();
880 while ( port
< 1024 || port
== thePrefs::GetPort() + 3 ) {
881 port
= (uint16
)rand();
883 thePrefs::SetUDPPort( port
);
886 wxT("Network configuration failed! You set your UDP port to\n")
887 wxT("the value of the main TCP port plus 3.\n")
888 wxT("This port has been reserved for the Server-UDP port. The\n")
889 wxT("port value has been changed to avoid conflict, see the\n")
890 wxT("preferences for the new value\n");
893 AddLogLineM( false, wxEmptyString
);
894 AddLogLineM( true, err
);
895 AddLogLineM( false, wxEmptyString
);
900 // Create the address where we are going to listen
901 // TODO: read this from configuration file
902 amuleIPV4Address myaddr
[4];
904 // Create the External Connections Socket.
906 // Get ready to handle connections from apps like amulecmd
907 if (thePrefs::GetECAddress().IsEmpty() || !myaddr
[0].Hostname(thePrefs::GetECAddress())) {
908 myaddr
[0].AnyAddress();
910 myaddr
[0].Service(thePrefs::ECPort());
911 ECServerHandler
= new ExternalConn(myaddr
[0], msg
);
913 // Create the UDP socket TCP+3.
914 // Used for source asking on servers.
915 if (thePrefs::GetAddress().IsEmpty()) {
916 myaddr
[1].AnyAddress();
917 } else if (!myaddr
[1].Hostname(thePrefs::GetAddress())) {
918 myaddr
[1].AnyAddress();
919 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
920 % thePrefs::GetAddress());
923 wxString ip
= myaddr
[1].IPAddress();
924 myaddr
[1].Service(thePrefs::GetPort()+3);
925 serverconnect
= new CServerConnect(serverlist
, myaddr
[1]);
926 *msg
<< CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
927 % ip
% ((unsigned int)thePrefs::GetPort() + 3u);
929 // Create the ListenSocket (aMule TCP socket).
930 // Used for Client Port / Connections from other clients,
931 // Client to Client Source Exchange.
933 myaddr
[2] = myaddr
[1];
934 myaddr
[2].Service(thePrefs::GetPort());
935 listensocket
= new CListenSocket(myaddr
[2]);
936 *msg
<< CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
937 % ip
% (unsigned int)(thePrefs::GetPort());
938 // This command just sets a flag to control maximum number of connections.
939 // Notify(true) has already been called to the ListenSocket, so events may
940 // be already comming in.
941 if (listensocket
->Ok()) {
942 listensocket
->StartListening();
944 // If we wern't able to start listening, we need to warn the user
946 err
= CFormat(_("Port %u is not available. You will be LOWID\n")) %
947 (unsigned int)(thePrefs::GetPort());
949 AddLogLineM(true, err
);
952 _("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.")) %
953 (unsigned int)(thePrefs::GetPort());
954 ShowAlert(err
, _("Error"), wxOK
| wxICON_ERROR
);
957 // Create the UDP socket.
958 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
959 // Also used for Kademlia.
960 // Default is port 4672.
961 myaddr
[3] = myaddr
[1];
962 myaddr
[3].Service(thePrefs::GetUDPPort());
963 clientudp
= new CClientUDPSocket(myaddr
[3], thePrefs::GetProxyData());
964 if (!thePrefs::IsUDPDisabled()) {
965 *msg
<< CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
966 % ip
% thePrefs::GetUDPPort();
968 *msg
<< wxT("*** Client UDP socket (extended eMule) disabled on preferences");
972 if (thePrefs::GetUPnPEnabled()) {
974 m_upnpMappings
[0] = CUPnPPortMapping(
977 thePrefs::GetUPnPECEnabled(),
978 "aMule TCP External Connections Socket");
979 m_upnpMappings
[1] = CUPnPPortMapping(
982 thePrefs::GetUPnPEnabled(),
983 "aMule UDP socket (TCP+3)");
984 m_upnpMappings
[2] = CUPnPPortMapping(
987 thePrefs::GetUPnPEnabled(),
988 "aMule TCP Listen Socket");
989 m_upnpMappings
[3] = CUPnPPortMapping(
992 thePrefs::GetUPnPEnabled(),
993 "aMule UDP Extended eMule Socket");
994 m_upnp
= new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
995 m_upnp
->AddPortMappings(m_upnpMappings
);
996 } catch(CUPnPException
&e
) {
998 error_msg
<< e
.what();
999 AddLogLineM(true, error_msg
);
1000 fprintf(stderr
, "%s\n", (const char *)unicode2char(error_msg
));
1008 // Returns a magnet ed2k URI
1009 wxString
CamuleApp::CreateMagnetLink(const CAbstractFile
*f
)
1013 uri
.AddField(wxT("dn"), f
->GetFileName().Cleanup(false).GetPrintable());
1014 uri
.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f
->GetFileHash().Encode().Lower());
1015 uri
.AddField(wxT("xl"), wxString::Format(wxT("%") wxLongLongFmtSpec
wxT("u"), f
->GetFileSize()));
1017 return uri
.GetLink();
1020 // Returns a ed2k file URL
1021 wxString
CamuleApp::CreateED2kLink(const CAbstractFile
*f
, bool add_source
, bool use_hostname
, bool addcryptoptions
)
1023 wxASSERT(!(!add_source
&& (use_hostname
|| addcryptoptions
)));
1024 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1025 wxString strURL
= CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1026 % f
->GetFileName().Cleanup(false)
1027 % f
->GetFileSize() % f
->GetFileHash().Encode();
1029 if (add_source
&& IsConnected() && !IsFirewalled()) {
1030 // Create the first part of the URL
1031 strURL
<< wxT("|sources,");
1033 strURL
<< thePrefs::GetYourHostname();
1035 uint32 clientID
= GetID();
1036 strURL
<< (uint8
) clientID
<< wxT(".") <<
1037 (uint8
)(clientID
>> 8) << wxT(".") <<
1038 (uint8
)(clientID
>> 16) << wxT(".") <<
1039 (uint8
)(clientID
>> 24);
1042 strURL
<< wxT(":") <<
1043 thePrefs::GetPort();
1045 if (addcryptoptions
) {
1046 const uint8 uSupportsCryptLayer
= thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1047 const uint8 uRequestsCryptLayer
= thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1048 const uint8 uRequiresCryptLayer
= thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1049 const uint8 byCryptOptions
= (uRequiresCryptLayer
<< 2) | (uRequestsCryptLayer
<< 1) | (uSupportsCryptLayer
<< 0) | (uSupportsCryptLayer
? 0x80 : 0x00);
1051 strURL
<< wxT(":") << byCryptOptions
;
1053 if (byCryptOptions
& 0x80) {
1054 strURL
<< wxT(":") << thePrefs::GetUserHash().Encode();
1057 strURL
<< wxT("|/");
1058 } else if (add_source
) {
1059 AddLogLineM(true, _("WARNING: You can't add yourself as a source for a ed2k link while being lowid."));
1062 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1066 // Returns a ed2k link with AICH info if available
1067 wxString
CamuleApp::CreateED2kAICHLink(const CKnownFile
* f
)
1069 // Create the first part of the URL
1070 wxString strURL
= CreateED2kLink(f
);
1071 // Append the AICH info
1072 if (f
->HasProperAICHHashSet()) {
1073 strURL
<< wxT("|h=") << f
->GetAICHMasterHash() << wxT("|/");
1076 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|h=<AICH master hash>|/"
1080 /* Original implementation by Bouc7 of the eMule Project.
1081 aMule Signature idea was designed by BigBob and implemented
1082 by Un-Thesis, with design inputs and suggestions from bothie.
1084 void CamuleApp::OnlineSig(bool zero
/* reset stats (used on shutdown) */)
1086 // Do not do anything if online signature is disabled in Preferences
1087 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path
.IsEmpty()) {
1088 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1089 // that means m_amulesig_path is empty too.
1093 // Remove old signature files
1094 if ( wxFileExists( m_emulesig_path
) ) { wxRemoveFile( m_emulesig_path
); }
1095 if ( wxFileExists( m_amulesig_path
) ) { wxRemoveFile( m_amulesig_path
); }
1098 wxTextFile amulesig_out
;
1099 wxTextFile emulesig_out
;
1101 // Open both files if needed
1102 if ( !emulesig_out
.Create( m_emulesig_path
) ) {
1103 AddLogLineM(true, _("Failed to create OnlineSig File"));
1104 // Will never try again.
1105 m_amulesig_path
.Clear();
1106 m_emulesig_path
.Clear();
1110 if ( !amulesig_out
.Create(m_amulesig_path
) ) {
1111 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1112 // Will never try again.
1113 m_amulesig_path
.Clear();
1114 m_emulesig_path
.Clear();
1118 wxString emulesig_string
;
1122 emulesig_string
= wxT("0\xA0.0|0.0|0");
1123 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1125 if (IsConnectedED2K()) {
1127 temp
= wxString::Format(wxT("%d"),serverconnect
->GetCurrentServer()->GetPort());
1134 + serverconnect
->GetCurrentServer()->GetListName()
1136 // IP and port of the server
1137 + serverconnect
->GetCurrentServer()->GetFullIP()
1142 // Now for amule sig
1144 // Connected. State 1, full info
1145 amulesig_out
.AddLine(wxT("1"));
1147 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetListName());
1149 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetFullIP());
1151 amulesig_out
.AddLine(temp
);
1153 if (serverconnect
->IsLowID()) {
1154 amulesig_out
.AddLine(wxT("L"));
1156 amulesig_out
.AddLine(wxT("H"));
1159 } else if (serverconnect
->IsConnecting()) {
1160 emulesig_string
= wxT("0");
1162 // Connecting. State 2, No info.
1163 amulesig_out
.AddLine(wxT("2\n0\n0\n0\n0"));
1165 // Not connected to a server
1166 emulesig_string
= wxT("0");
1168 // Not connected, state 0, no info
1169 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0"));
1171 if (IsConnectedKad()) {
1172 if(Kademlia::CKademlia::IsFirewalled()) {
1173 // Connected. Firewalled. State 1.
1174 amulesig_out
.AddLine(wxT("1"));
1176 // Connected. State 2.
1177 amulesig_out
.AddLine(wxT("2"));
1180 // Not connected.State 0.
1181 amulesig_out
.AddLine(wxT("0"));
1183 emulesig_string
+= wxT("\xA");
1185 // Datarate for downloads
1186 temp
= wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1188 emulesig_string
+= temp
+ wxT("|");
1189 amulesig_out
.AddLine(temp
);
1191 // Datarate for uploads
1192 temp
= wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1194 emulesig_string
+= temp
+ wxT("|");
1195 amulesig_out
.AddLine(temp
);
1197 // Number of users waiting for upload
1198 temp
= wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1200 emulesig_string
+= temp
;
1201 amulesig_out
.AddLine(temp
);
1203 // Number of shared files (not on eMule)
1204 amulesig_out
.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1207 // eMule signature finished here. Write the line to the wxTextFile.
1208 emulesig_out
.AddLine(emulesig_string
);
1210 // Now for aMule signature extras
1212 // Nick on the network
1213 amulesig_out
.AddLine(thePrefs::GetUserNick());
1215 // Total received in bytes
1216 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1218 // Total sent in bytes
1219 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1223 amulesig_out
.AddLine(wxT(VERSION
" " SVNDATE
));
1225 amulesig_out
.AddLine(wxT(VERSION
));
1229 amulesig_out
.AddLine(wxT("0"));
1230 amulesig_out
.AddLine(wxT("0"));
1231 amulesig_out
.AddLine(wxT("0"));
1233 // Total received bytes in session
1234 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
1235 theStats::GetSessionReceivedBytes() );
1237 // Total sent bytes in session
1238 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
1239 theStats::GetSessionSentBytes() );
1242 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1246 emulesig_out
.Write();
1247 amulesig_out
.Write();
1248 } //End Added By Bouc7
1251 // Gracefully handle fatal exceptions and print backtrace if possible
1252 void CamuleApp::OnFatalException()
1254 /* Print the backtrace */
1255 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1256 fprintf(stderr
, "A fatal error has occurred and aMule has crashed.\n");
1257 fprintf(stderr
, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1258 fprintf(stderr
, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1259 fprintf(stderr
, "circumstances of this crash. The forum is located here:\n");
1260 fprintf(stderr
, " http://forum.amule.org/index.php?board=67.0\n");
1261 fprintf(stderr
, "If possible, please try to generate a real backtrace of this crash:\n");
1262 fprintf(stderr
, " http://www.amule.org/wiki/index.php/Backtraces\n\n");
1263 fprintf(stderr
, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1264 fprintf(stderr
, "Current version is: %s\n", strFullMuleVersion
);
1265 fprintf(stderr
, "Running on: %s\n\n", strOSDescription
);
1267 print_backtrace(1); // 1 == skip this function.
1269 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1273 // Sets the localization of aMule
1274 void CamuleApp::Localize_mule()
1276 InitCustomLanguages();
1277 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
1278 if (!m_locale
.IsOk()) {
1279 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1284 // Displays information related to important changes in aMule.
1285 // Is called when the user runs a new version of aMule
1286 void CamuleApp::Trigger_New_version(wxString new_version
)
1288 wxString info
= wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version
+ wxT(" ---\n\n");
1289 if (new_version
== wxT("SVN")) {
1290 info
+= _("This version is a testing version, updated daily, and\n");
1291 info
+= _("we give no warranty it won't break anything, burn your house,\n");
1292 info
+= _("or kill your dog. But it *should* be safe to use anyway.\n");
1293 } else if (new_version
== wxT("2.2.0")) {
1294 thePrefs::SetAddServersFromServer(false);
1295 thePrefs::SetAddServersFromClient(false);
1296 info
+= _("The following options have been changed in this release for security reasons:\n");
1297 info
+= _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1298 info
+= _("\n* Disabled updating the server list from other server and clients.\n");
1299 info
+= _("\nFor more information on the reason for this changes, seach\nthe aMule wiki at http://wiki.amule.org for \"fake servers\" info.\nIt's important that you clear any fake server from your server list for aMule to work properly.");
1304 info
+= _("More information, support and new releases can found at our homepage,\n");
1305 info
+= _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1307 info
+= _("Feel free to report any bugs to http://forum.amule.org");
1309 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
1313 void CamuleApp::SetOSFiles(const wxString new_path
)
1315 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1316 if ( ::wxDirExists(new_path
) ) {
1317 m_emulesig_path
= JoinPaths(new_path
, wxT("onlinesig.dat"));
1318 m_amulesig_path
= JoinPaths(new_path
, wxT("amulesig.dat"));
1320 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
);
1321 m_emulesig_path
.Clear();
1322 m_amulesig_path
.Clear();
1325 m_emulesig_path
.Clear();
1326 m_amulesig_path
.Clear();
1332 #ifndef wxUSE_STACKWALKER
1333 #define wxUSE_STACKWALKER 0
1335 void CamuleApp::OnAssertFailure(const wxChar
* file
, int line
,
1336 const wxChar
* func
, const wxChar
* cond
, const wxChar
* msg
)
1338 if (!wxUSE_STACKWALKER
|| !wxThread::IsMain() || !IsRunning()) {
1339 wxString errmsg
= CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1340 % file
% func
% line
% cond
% ( msg
? msg
: wxT("") );
1342 fprintf(stderr
, "Assertion failed: %s\n", (const char*)unicode2char(errmsg
));
1344 // Skip the function-calls directly related to the assert call.
1345 fprintf(stderr
, "\nBacktrace follows:\n");
1347 fprintf(stderr
, "\n");
1350 if (wxThread::IsMain() && IsRunning()) {
1351 AMULE_APP_BASE::OnAssertFailure(file
, line
, func
, cond
, msg
);
1353 // Abort, allows gdb to catch the assertion
1360 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent
& evt
)
1362 CServerUDPSocket
* socket
=(CServerUDPSocket
*)evt
.GetClientData();
1363 socket
->OnHostnameResolved(evt
.GetExtraLong());
1367 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent
& evt
)
1369 downloadqueue
->OnHostnameResolved(evt
.GetExtraLong());
1373 void CamuleApp::OnServerDnsDone(CMuleInternalEvent
& evt
)
1375 printf("Server hostname notified\n");
1376 serverconnect
->OnServerHostnameResolved(evt
.GetClientData(), evt
.GetExtraLong());
1380 void CamuleApp::OnTCPTimer(CTimerEvent
& WXUNUSED(evt
))
1385 serverconnect
->StopConnectionTry();
1386 if (IsConnectedED2K() ) {
1389 serverconnect
->ConnectToAnyServer();
1393 void CamuleApp::OnCoreTimer(CTimerEvent
& WXUNUSED(evt
))
1395 // Former TimerProc section
1396 static uint64 msPrev1
, msPrev5
, msPrevSave
, msPrevHist
, msPrevOS
, msPrevKnownMet
;
1397 uint64 msCur
= theStats::GetUptimeMillis();
1403 #ifndef AMULE_DAEMON
1404 // Check if we should terminate the app
1405 if ( g_shutdownSignal
) {
1406 wxWindow
* top
= GetTopWindow();
1411 // No top-window, have to force termination.
1417 CLogger::FlushPendingEntries();
1419 uploadqueue
->Process();
1420 downloadqueue
->Process();
1421 //theApp->clientcredits->Process();
1422 theStats::CalculateRates();
1424 if (msCur
-msPrevHist
> 1000) {
1425 // unlike the other loop counters in this function this one will sometimes
1426 // produce two calls in quick succession (if there was a gap of more than one
1427 // second between calls to TimerProc) - this is intentional! This way the
1428 // history list keeps an average of one node per second and gets thinned out
1429 // correctly as time progresses.
1432 m_statistics
->RecordHistory();
1437 if (msCur
-msPrev1
> 1000) { // approximately every second
1439 clientcredits
->Process();
1440 clientlist
->Process();
1442 // Publish files to server if needed.
1443 sharedfiles
->Process();
1445 if( Kademlia::CKademlia::IsRunning() ) {
1446 Kademlia::CKademlia::Process();
1447 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1451 if (thePrefs::Reconnect()) {
1457 if( serverconnect
->IsConnecting() && !serverconnect
->IsSingleConnect() ) {
1458 serverconnect
->TryAnotherConnectionrequest();
1460 if (serverconnect
->IsConnecting()) {
1461 serverconnect
->CheckForTimeout();
1463 listensocket
->UpdateConnectionsStatus();
1468 if (msCur
-msPrev5
> 5000) { // every 5 seconds
1470 listensocket
->Process();
1473 if (msCur
-msPrevSave
>= 60000) {
1477 // Save total upload/download to preferences
1478 wxConfigBase
* cfg
= wxConfigBase::Get();
1479 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1480 cfg
->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer
);
1482 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1483 cfg
->Write(wxT("/Statistics/TotalUploadedBytes"), buffer
);
1485 // Write changes to file
1491 if (msCur
- msPrevOS
>= thePrefs::GetOSUpdate() * 1000ull) {
1492 OnlineSig(); // Added By Bouc7
1496 if (msCur
- msPrevKnownMet
>= 30*60*1000/*There must be a prefs option for this*/) {
1497 // Save Shared Files data
1499 msPrevKnownMet
= msCur
;
1503 // Recomended by lugdunummaster himself - from emule 0.30c
1504 serverconnect
->KeepConnectionAlive();
1509 void CamuleApp::OnFinishedHashing(CHashingEvent
& evt
)
1511 wxCHECK_RET(evt
.GetResult(), wxT("No result of hashing"));
1513 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1514 CKnownFile
* result
= evt
.GetResult();
1517 // Check if the partfile still exists, as it might have
1518 // been deleted in the mean time.
1519 if (downloadqueue
->IsPartFile(owner
)) {
1520 // This cast must not be done before the IsPartFile
1521 // call, as dynamic_cast will barf on dangling pointers.
1522 dynamic_cast<CPartFile
*>(owner
)->PartFileHashFinished(result
);
1525 static int filecount
;
1526 static uint64 bytecount
;
1528 if (knownfiles
->SafeAddKFile(result
)) {
1529 AddDebugLogLineM(false, logKnownFiles
,
1530 CFormat(wxT("Safe adding file to sharedlist: %s")) % result
->GetFileName());
1531 sharedfiles
->SafeAddKFile(result
);
1534 bytecount
+= result
->GetFileSize();
1535 // If we have added 30 files or files with a total size of ~300mb
1536 if ( ( filecount
== 30 ) || ( bytecount
>= 314572800 ) ) {
1537 AddDebugLogLineM(false, logKnownFiles
, wxT("Failsafe for crash on file hashing creation"));
1538 if ( m_app_state
!= APP_STATE_SHUTTINGDOWN
) {
1545 AddDebugLogLineM(false, logKnownFiles
,
1546 CFormat(wxT("File not added to sharedlist: %s")) % result
->GetFileName());
1553 void CamuleApp::OnFinishedAICHHashing(CHashingEvent
& evt
)
1555 wxCHECK_RET(evt
.GetResult(), wxT("No result of AICH-hashing"));
1557 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1558 std::auto_ptr
<CKnownFile
> result(evt
.GetResult());
1560 // Check that the owner is still valid
1561 if (knownfiles
->IsKnownFile(owner
)) {
1562 if (result
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
) {
1563 CAICHHashSet
* oldSet
= owner
->GetAICHHashset();
1564 CAICHHashSet
* newSet
= result
->GetAICHHashset();
1566 owner
->SetAICHHashset(newSet
);
1567 newSet
->SetOwner(owner
);
1569 result
->SetAICHHashset(oldSet
);
1570 oldSet
->SetOwner(result
.get());
1576 void CamuleApp::OnFinishedCompletion(CCompletionEvent
& evt
)
1578 CPartFile
* completed
= const_cast<CPartFile
*>(evt
.GetOwner());
1579 wxCHECK_RET(completed
, wxT("Completion event sent for unspecified file"));
1580 wxASSERT_MSG(downloadqueue
->IsPartFile(completed
), wxT("CCompletionEvent for unknown partfile."));
1582 completed
->CompleteFileEnded(evt
.ErrorOccured(), evt
.GetFullPath());
1583 if (evt
.ErrorOccured()) {
1584 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion
, completed
);
1587 // Check if we should execute an script/app/whatever.
1588 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted
, completed
);
1592 void CamuleApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
1594 #if defined(AMULE_DAEMON)
1597 if (theApp
->amuledlg
) {
1604 void CamuleApp::ShutDown()
1607 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has started."));
1609 // Signal the hashing thread to terminate
1610 m_app_state
= APP_STATE_SHUTTINGDOWN
;
1614 // Kry - Save the sources seeds on app exit
1615 if (thePrefs::GetSrcSeedsOn()) {
1616 downloadqueue
->SaveSourceSeeds();
1619 OnlineSig(true); // Added By Bouc7
1621 // Close sockets to avoid new clients coming in
1623 listensocket
->Close();
1624 listensocket
->KillAllSockets();
1627 if (serverconnect
) {
1628 serverconnect
->Disconnect();
1631 ECServerHandler
->KillAllSockets();
1634 if (thePrefs::GetUPnPEnabled()) {
1636 m_upnp
->DeletePortMappings(m_upnpMappings
);
1641 // saving data & stuff
1646 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1647 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1654 clientlist
->DeleteAll();
1657 CThreadScheduler::Terminate();
1659 theApp
->uploadBandwidthThrottler
->EndThread();
1662 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has ended."));
1666 bool CamuleApp::AddServer(CServer
*srv
, bool fromUser
)
1668 if ( serverlist
->AddServer(srv
, fromUser
) ) {
1669 Notify_ServerAdd(srv
);
1676 void CamuleApp::AddLogLine(const wxString
&msg
)
1678 // At most one trailing new-line, which we add
1679 wxString message
= msg
;
1680 while ( !message
.IsEmpty() && message
.Last() == wxT('\n') ) {
1681 message
.RemoveLast();
1684 wxString full_line
= wxDateTime::Now().FormatISODate() + wxT(" ") +
1685 wxDateTime::Now().FormatISOTime() + wxT(": ") + message
+ wxT("\n");
1687 wxStringInputStream
stream(full_line
);
1689 if (applog
) { // This check is needed, because if we assert before the logger is created, it will crash.
1690 (*applog
) << stream
;
1694 if (enable_stdout_log
) {
1695 printf("%s", (const char*)unicode2char(full_line
));
1700 uint32
CamuleApp::GetPublicIP(bool ignorelocal
) const
1702 if (m_dwPublicIP
== 0) {
1703 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1704 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1706 return ignorelocal
? 0 : m_localip
;
1710 return m_dwPublicIP
;
1714 void CamuleApp::SetPublicIP(const uint32 dwIP
)
1716 wxASSERT((dwIP
== 0) || !IsLowID(dwIP
));
1718 if (dwIP
!= 0 && dwIP
!= m_dwPublicIP
&& serverlist
!= NULL
) {
1719 m_dwPublicIP
= dwIP
;
1720 serverlist
->CheckForExpiredUDPKeys();
1722 m_dwPublicIP
= dwIP
;
1727 wxString
CamuleApp::GetLog(bool reset
)
1729 ConfigDir
= GetConfigDir();
1731 logfile
.Open(ConfigDir
+ wxT("logfile"));
1732 if ( !logfile
.IsOpened() ) {
1733 return wxTRANSLATE("ERROR: can't open logfile");
1735 int len
= logfile
.Length();
1737 return wxTRANSLATE("WARNING: logfile is empty. Something is wrong.");
1739 char *tmp_buffer
= new char[len
+ sizeof(wxChar
)];
1740 logfile
.Read(tmp_buffer
, len
);
1741 memset(tmp_buffer
+ len
, 0, sizeof(wxChar
));
1743 // try to guess file format
1745 if (tmp_buffer
[0] && tmp_buffer
[1]) {
1746 str
= wxString(UTF82unicode(tmp_buffer
));
1748 str
= wxString((wxWCharBuffer
&)tmp_buffer
);
1751 delete [] tmp_buffer
;
1754 applog
= new wxFFileOutputStream(ConfigDir
+ wxT("logfile"));
1755 if ( applog
->Ok() ) {
1756 AddLogLine(_("Log has been reset"));
1766 wxString
CamuleApp::GetServerLog(bool reset
)
1768 wxString ret
= server_msg
;
1775 wxString
CamuleApp::GetDebugLog(bool reset
)
1777 return GetLog(reset
);
1781 void CamuleApp::AddServerMessageLine(wxString
&msg
)
1783 server_msg
+= msg
+ wxT("\n");
1784 AddLogLine(CFormat(_("ServerMessage: %s")) % msg
);
1789 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
1791 switch (event
.GetInt()) {
1793 ipfilter
->DownloadFinished(event
.GetExtraLong());
1795 case HTTP_ServerMet
:
1796 serverlist
->DownloadFinished(event
.GetExtraLong());
1798 case HTTP_ServerMetAuto
:
1799 serverlist
->AutoDownloadFinished(event
.GetExtraLong());
1801 case HTTP_VersionCheck
:
1802 CheckNewVersion(event
.GetExtraLong());
1805 if (event
.GetExtraLong() != -1) {
1807 wxString file
= ConfigDir
+ wxT("nodes.dat");
1808 if (wxFileExists(file
)) {
1812 if ( Kademlia::CKademlia::IsRunning() ) {
1813 Kademlia::CKademlia::Stop();
1816 wxRenameFile(file
+ wxT(".download"),file
);
1818 Kademlia::CKademlia::Start();
1819 theApp
->ShowConnectionState();
1822 AddLogLineM(true, _("Failed to download the nodes list."));
1828 void CamuleApp::CheckNewVersion(uint32 result
)
1831 wxString filename
= ConfigDir
+ wxT("last_version_check");
1834 if (!file
.Open(filename
)) {
1835 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1837 } else if (!file
.GetLineCount()) {
1838 AddLogLineM(true, _("Corrupted version check file"));
1840 wxString versionLine
= file
.GetFirstLine();
1841 wxStringTokenizer
tkz(versionLine
, wxT("."));
1843 AddDebugLogLineM(false, logGeneral
, wxString(wxT("Running: ")) + wxT(VERSION
) + wxT(", Version check: ") + versionLine
);
1845 long fields
[] = {0, 0, 0};
1846 for (int i
= 0; i
< 3; ++i
) {
1847 if (!tkz
.HasMoreTokens()) {
1848 AddLogLineM(true, _("Corrupted version check file"));
1851 wxString token
= tkz
.GetNextToken();
1853 if (!token
.ToLong(&fields
[i
])) {
1854 AddLogLineM(true, _("Corrupted version check file"));
1860 long curVer
= make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
);
1861 long newVer
= make_full_ed2k_version(fields
[0], fields
[1], fields
[2]);
1863 if (curVer
< newVer
) {
1864 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1865 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]));
1866 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1868 printf("%s\n", (const char*)unicode2UTF8(wxString::Format(
1869 _("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"),
1870 VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
, fields
[0], fields
[1], fields
[2])));
1873 AddLogLineM(false, _("Your copy of aMule is up to date."));
1878 wxRemoveFile(filename
);
1880 AddLogLineM(true, _("Failed to download the version check file") );
1886 bool CamuleApp::IsConnected()
1888 return (IsConnectedED2K() || IsConnectedKad());
1892 bool CamuleApp::IsConnectedED2K()
1894 return serverconnect
&& serverconnect
->IsConnected();
1898 bool CamuleApp::IsConnectedKad()
1900 return Kademlia::CKademlia::IsConnected();
1904 bool CamuleApp::IsFirewalled()
1906 if (theApp
->IsConnectedED2K() && !theApp
->serverconnect
->IsLowID()) {
1907 return false; // we have an eD2K HighID -> not firewalled
1910 return IsFirewalledKad(); // If kad says ok, it's ok.
1913 bool CamuleApp::IsFirewalledKad()
1915 if (Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled()) {
1916 return false; // we have an Kad HighID -> not firewalled
1919 return true; // firewalled
1922 bool CamuleApp::IsKadRunning()
1924 return Kademlia::CKademlia::IsRunning();
1927 bool CamuleApp::DoCallback( CUpDownClient
*client
)
1929 if(Kademlia::CKademlia::IsConnected()) {
1930 if(IsConnectedED2K()) {
1931 if(serverconnect
->IsLowID()) {
1932 if(Kademlia::CKademlia::IsFirewalled()) {
1933 //Both Connected - Both Firewalled
1936 if(client
->GetServerIP() == theApp
->serverconnect
->GetCurrentServer()->GetIP() &&
1937 client
->GetServerPort() == theApp
->serverconnect
->GetCurrentServer()->GetPort()) {
1938 // Both Connected - Server lowID, Kad Open - Client on same server
1939 // We prevent a callback to the server as this breaks the protocol
1940 // and will get you banned.
1943 // Both Connected - Server lowID, Kad Open - Client on remote server
1948 //Both Connected - Server HighID, Kad don't care
1952 if(Kademlia::CKademlia::IsFirewalled()) {
1953 //Only Kad Connected - Kad Firewalled
1956 //Only Kad Conected - Kad Open
1961 if( IsConnectedED2K() ) {
1962 if( serverconnect
->IsLowID() ) {
1963 //Only Server Connected - Server LowID
1966 //Only Server Connected - Server HighID
1970 //We are not connected at all!
1976 void CamuleApp::ShowUserCount() {
1977 uint32 totaluser
= 0, totalfile
= 0;
1979 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
1982 CFormat(_("Users: E: %s K: %s | Files E: %s K: %s")) % CastItoIShort(totaluser
) %
1983 CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile
) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1985 Notify_ShowUserCount(buffer
);
1989 void CamuleApp::ListenSocketHandler(wxSocketEvent
& event
)
1991 wxCHECK_RET(listensocket
, wxT("Connection-event for NULL'd listen-socket"));
1992 wxCHECK_RET(event
.GetSocketEvent() == wxSOCKET_CONNECTION
,
1993 wxT("Invalid event received for listen-socket"));
1995 if (m_app_state
== APP_STATE_RUNNING
) {
1996 listensocket
->OnAccept(0);
1997 } else if (m_app_state
== APP_STATE_STARTING
) {
1998 // When starting up, connection may be made before we are able
1999 // to handle them. However, if these are ignored, no futher
2000 // connection-events will be triggered, so we have to accept it.
2001 wxSocketBase
* socket
= listensocket
->Accept(false);
2003 wxCHECK_RET(socket
, wxT("NULL returned by Accept() during startup"));
2010 void CamuleApp::ShowConnectionState()
2012 static uint8 old_state
= (1<<7); // This flag doesn't exist
2016 if (theApp
->serverconnect
->IsConnected()) {
2017 state
|= CONNECTED_ED2K
;
2020 if (Kademlia::CKademlia::IsRunning()) {
2021 if (Kademlia::CKademlia::IsConnected()) {
2022 if (!Kademlia::CKademlia::IsFirewalled()) {
2023 state
|= CONNECTED_KAD_OK
;
2025 state
|= CONNECTED_KAD_FIREWALLED
;
2028 state
|= CONNECTED_KAD_NOT
;
2032 Notify_ShowConnState(state
);
2034 if (old_state
!= state
) {
2035 // Get the changed value
2036 int changed_flags
= old_state
^ state
;
2038 if (changed_flags
& CONNECTED_ED2K
) {
2039 // ED2K status changed
2040 wxString connected_server
;
2041 CServer
* ed2k_server
= theApp
->serverconnect
->GetCurrentServer();
2043 connected_server
= ed2k_server
->GetListName();
2045 if (state
& CONNECTED_ED2K
) {
2046 // We connected to some server
2047 const wxString id
= theApp
->serverconnect
->IsLowID() ? _("with LowID") : _("with HighID");
2049 AddLogLine(CFormat(_("Connected to %s %s")) % connected_server
% id
);
2051 if ( theApp
->serverconnect
->IsConnecting() ) {
2052 AddLogLine(CFormat(_("Connecting to %s")) % connected_server
);
2054 AddLogLine(_("Disconnected from ED2K"));
2059 if (changed_flags
& CONNECTED_KAD_NOT
) {
2060 if (state
& CONNECTED_KAD_NOT
) {
2061 AddLogLine(_("Kad started."));
2063 AddLogLine(_("Kad stopped."));
2067 if (changed_flags
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
2068 if (state
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
2069 if (state
& CONNECTED_KAD_OK
) {
2070 AddLogLine(_("Connected to Kad (ok)"));
2072 AddLogLine(_("Connected to Kad (firewalled)"));
2075 AddLogLine(_("Disconnected from Kad"));
2081 theApp
->downloadqueue
->OnConnectionState(IsConnected());
2085 Notify_ShowConnState(state
);
2089 void CamuleApp::UDPSocketHandler(wxSocketEvent
& event
)
2091 CMuleUDPSocket
* socket
= (CMuleUDPSocket
*)(event
.GetClientData());
2092 wxCHECK_RET(socket
, wxT("No socket owner specified."));
2094 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2097 if (event
.GetSocketEvent() == wxSOCKET_INPUT
) {
2098 // Back to the queue!
2099 theApp
->AddPendingEvent(event
);
2104 switch (event
.GetSocketEvent()) {
2105 case wxSOCKET_INPUT
:
2106 socket
->OnReceive(0);
2109 case wxSOCKET_OUTPUT
:
2114 socket
->OnDisconnected(0);
2124 void CamuleApp::OnUnhandledException()
2126 // Call the generic exception-handler.
2127 fprintf(stderr
, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2128 ::OnUnhandledException();
2131 void CamuleApp::StartKad()
2133 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2134 // Kad makes no sense without the Client-UDP socket.
2135 if (!thePrefs::IsUDPDisabled()) {
2136 Kademlia::CKademlia::Start();
2138 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2140 } else if (!thePrefs::GetNetworkKademlia()) {
2141 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2145 void CamuleApp::StopKad()
2147 // Stop Kad if it's running
2148 if (Kademlia::CKademlia::IsRunning()) {
2149 Kademlia::CKademlia::Stop();
2154 void CamuleApp::BootstrapKad(uint32 ip
, uint16 port
)
2156 if (!Kademlia::CKademlia::IsRunning()) {
2157 Kademlia::CKademlia::Start();
2158 theApp
->ShowConnectionState();
2161 Kademlia::CKademlia::Bootstrap(ip
, port
);
2165 void CamuleApp::UpdateNotesDat(const wxString
& url
)
2167 wxString
strTempFilename(theApp
->ConfigDir
+ wxT("nodes.dat.download"));
2169 CHTTPDownloadThread
*downloader
= new CHTTPDownloadThread(url
, strTempFilename
, HTTP_NodesDat
);
2170 downloader
->Create();
2175 void CamuleApp::DisconnectED2K()
2177 // Stop Kad if it's running
2178 if (IsConnectedED2K()) {
2179 serverconnect
->Disconnect();
2183 bool CamuleApp::CryptoAvailable() const
2185 return clientcredits
&& clientcredits
->CryptoAvailable();
2188 uint32
CamuleApp::GetED2KID() const {
2189 return serverconnect
? serverconnect
->GetClientID() : 0;
2192 uint32
CamuleApp::GetID() const {
2195 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2196 // We trust Kad above ED2K
2197 ID
= ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2198 } else if( theApp
->serverconnect
->IsConnected() ) {
2199 ID
= theApp
->serverconnect
->GetClientID();
2200 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2201 // A firewalled Kad client get's a "1"
2210 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2211 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2212 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2213 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2214 // File_checked_for_headers