Fixed compilation with wx 3.0 STL build
[amule.git] / src / amule.cpp
blobc92f033e9b03a70749c5929307413a29443881c9
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "amule.h" // Interface declarations.
29 #include <csignal>
30 #include <cstring>
31 #include <wx/process.h>
32 #include <wx/sstream.h>
34 #ifdef HAVE_CONFIG_H
35 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
36 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
37 // and ENABLE_NLS
38 #endif
40 #include <common/ClientVersion.h>
42 #include <wx/cmdline.h> // Needed for wxCmdLineParser
43 #include <wx/config.h> // Do_not_auto_remove (win32)
44 #include <wx/fileconf.h>
45 #include <wx/tokenzr.h>
46 #include <wx/wfstream.h>
49 #include <common/Format.h> // Needed for CFormat
50 #include "kademlia/kademlia/Kademlia.h"
51 #include "kademlia/kademlia/Prefs.h"
52 #include "kademlia/kademlia/UDPFirewallTester.h"
53 #include "CanceledFileList.h"
54 #include "ClientCreditsList.h" // Needed for CClientCreditsList
55 #include "ClientList.h" // Needed for CClientList
56 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
57 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
58 #include <common/FileFunctions.h> // Needed for CDirIterator
59 #include "FriendList.h" // Needed for CFriendList
60 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
61 #include "InternalEvents.h" // Needed for CMuleInternalEvent
62 #include "IPFilter.h" // Needed for CIPFilter
63 #include "KnownFileList.h" // Needed for CKnownFileList
64 #include "ListenSocket.h" // Needed for CListenSocket
65 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
66 #include "MagnetURI.h" // Needed for CMagnetURI
67 #include "OtherFunctions.h"
68 #include "PartFile.h" // Needed for CPartFile
69 #include "PlatformSpecific.h" // Needed for PlatformSpecific::AllowSleepMode();
70 #include "Preferences.h" // Needed for CPreferences
71 #include "SearchList.h" // Needed for CSearchList
72 #include "Server.h" // Needed for GetListName
73 #include "ServerList.h" // Needed for CServerList
74 #include "ServerConnect.h" // Needed for CServerConnect
75 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
76 #include "Statistics.h" // Needed for CStatistics
77 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
78 #include "ThreadTasks.h"
79 #include "UploadQueue.h" // Needed for CUploadQueue
80 #include "UploadBandwidthThrottler.h"
81 #include "UserEvents.h"
82 #include "ScopedPtr.h"
84 #ifdef ENABLE_UPNP
85 #include "UPnPBase.h" // Needed for UPnP
86 #endif
88 #ifdef __WXMAC__
89 #include <wx/sysopt.h> // Do_not_auto_remove
90 #endif
92 #ifndef AMULE_DAEMON
93 #ifdef __WXMAC__
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
97 #else
98 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
99 #endif
100 #endif
101 #include <wx/msgdlg.h>
103 #include "amuleDlg.h"
104 #endif
107 #ifdef HAVE_SYS_RESOURCE_H
108 #include <sys/resource.h>
109 #endif
111 #ifdef HAVE_SYS_STATVFS_H
112 #include <sys/statvfs.h> // Do_not_auto_remove
113 #endif
116 #ifdef __GLIBC__
117 # define RLIMIT_RESOURCE __rlimit_resource
118 #else
119 # define RLIMIT_RESOURCE int
120 #endif
122 #ifdef AMULE_DAEMON
123 CamuleDaemonApp *theApp;
124 #else
125 CamuleGuiApp *theApp;
126 #endif
128 static void UnlimitResource(RLIMIT_RESOURCE resType)
130 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
131 struct rlimit rl;
132 getrlimit(resType, &rl);
133 rl.rlim_cur = rl.rlim_max;
134 setrlimit(resType, &rl);
135 #endif
139 static void SetResourceLimits()
141 #ifdef HAVE_SYS_RESOURCE_H
142 UnlimitResource(RLIMIT_DATA);
143 #ifndef __UCLIBC__
144 UnlimitResource(RLIMIT_FSIZE);
145 #endif
146 UnlimitResource(RLIMIT_NOFILE);
147 #ifdef RLIMIT_RSS
148 UnlimitResource(RLIMIT_RSS);
149 #endif
150 #endif
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;
164 #ifdef AMULE_DAEMON
165 theApp->ExitMainLoop();
166 #endif
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.
174 StartTickTimer();
176 // Initialization
177 m_app_state = APP_STATE_STARTING;
179 theApp = &wxGetApp();
181 clientlist = NULL;
182 searchlist = NULL;
183 knownfiles = NULL;
184 canceledfiles = NULL;
185 serverlist = NULL;
186 serverconnect = NULL;
187 sharedfiles = NULL;
188 listensocket = NULL;
189 clientudp = NULL;
190 clientcredits = NULL;
191 friendlist = NULL;
192 downloadqueue = NULL;
193 uploadqueue = NULL;
194 ipfilter = NULL;
195 ECServerHandler = NULL;
196 glob_prefs = NULL;
197 m_statistics = NULL;
198 uploadBandwidthThrottler = NULL;
199 #ifdef ENABLE_UPNP
200 m_upnp = NULL;
201 m_upnpMappings.resize(4);
202 #endif
203 core_timer = NULL;
205 m_localip = 0;
206 m_dwPublicIP = 0;
207 webserver_pid = 0;
209 enable_daemon_fork = false;
211 // Apprently needed for *BSD
212 SetResourceLimits();
214 #ifdef _MSC_VER
215 _CrtSetDbgFlag(0); // Disable useless memleak debugging
216 #endif
219 CamuleApp::~CamuleApp()
221 // Closing the log-file as the very last thing, since
222 // wxWidgets log-events are saved in it as well.
223 theLogger.CloseLogfile();
226 int CamuleApp::OnExit()
228 if (m_app_state!=APP_STATE_STARTING) {
229 AddLogLineNS(_("Now, exiting main app..."));
232 // From wxWidgets docs, wxConfigBase:
233 // ...
234 // Note that you must delete this object (usually in wxApp::OnExit)
235 // in order to avoid memory leaks, wxWidgets won't do it automatically.
237 // As it happens, you may even further simplify the procedure described
238 // above: you may forget about calling Set(). When Get() is called and
239 // there is no current object, it will create one using Create() function.
240 // To disable this behaviour DontCreateOnDemand() is provided.
241 delete wxConfigBase::Set((wxConfigBase *)NULL);
243 // Save credits
244 clientcredits->SaveList();
246 // Kill amuleweb if running
247 if (webserver_pid) {
248 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid '%ld' ... ")) % webserver_pid);
249 wxKillError rc;
250 if (wxKill(webserver_pid, wxSIGTERM, &rc) == -1) {
251 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid '%ld' ... ")) % webserver_pid);
252 if (wxKill(webserver_pid, wxSIGKILL, &rc) == -1) {
253 AddLogLineNS(_("Failed"));
258 if (m_app_state!=APP_STATE_STARTING) {
259 AddLogLineNS(_("aMule OnExit: Terminating core."));
262 delete serverlist;
263 serverlist = NULL;
265 delete searchlist;
266 searchlist = NULL;
268 delete clientcredits;
269 clientcredits = NULL;
271 delete friendlist;
272 friendlist = NULL;
274 // Destroying CDownloadQueue calls destructor for CPartFile
275 // calling CSharedFileList::SafeAddKFile occasionally.
276 delete sharedfiles;
277 sharedfiles = NULL;
279 delete serverconnect;
280 serverconnect = NULL;
282 delete listensocket;
283 listensocket = NULL;
285 delete clientudp;
286 clientudp = NULL;
288 delete knownfiles;
289 knownfiles = NULL;
291 delete canceledfiles;
292 canceledfiles = NULL;
294 delete clientlist;
295 clientlist = NULL;
297 delete uploadqueue;
298 uploadqueue = NULL;
300 delete downloadqueue;
301 downloadqueue = NULL;
303 delete ipfilter;
304 ipfilter = NULL;
306 #ifdef ENABLE_UPNP
307 delete m_upnp;
308 m_upnp = NULL;
309 #endif
311 delete ECServerHandler;
312 ECServerHandler = NULL;
314 delete m_statistics;
315 m_statistics = NULL;
317 delete glob_prefs;
318 glob_prefs = NULL;
319 CPreferences::EraseItemList();
321 delete uploadBandwidthThrottler;
322 uploadBandwidthThrottler = NULL;
324 delete m_AsioService;
325 m_AsioService = NULL;
327 wxSocketBase::Shutdown(); // needed because we also called Initialize() manually
329 if (m_app_state!=APP_STATE_STARTING) {
330 AddLogLineNS(_("aMule shutdown completed."));
333 #if wxUSE_MEMORY_TRACING
334 AddLogLineNS(_("Memory debug results for aMule exit:"));
335 // Log mem debug mesages to wxLogStderr
336 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
337 //AddLogLineNS(wxT("**************Classes**************");
338 //wxDebugContext::PrintClasses();
339 //AddLogLineNS(wxT("***************Dump***************");
340 //wxDebugContext::Dump();
341 AddLogLineNS(wxT("***************Stats**************"));
342 wxDebugContext::PrintStatistics(true);
344 // Set back to wxLogGui
345 delete wxLog::SetActiveTarget(oldLog);
346 #endif
348 StopTickTimer();
350 // Return 0 for succesful program termination
351 return AMULE_APP_BASE::OnExit();
355 int CamuleApp::InitGui(bool, wxString &)
357 return 0;
362 // Application initialization
364 bool CamuleApp::OnInit()
366 #if wxUSE_MEMORY_TRACING
367 // any text before call of Localize_mule needs not to be translated.
368 AddLogLineNS(wxT("Checkpoint set on app init for memory debug")); // debug output
369 wxDebugContext::SetCheckpoint();
370 #endif
372 // Forward wxLog events to CLogger
373 wxLog::SetActiveTarget(new CLoggerTarget);
375 m_localip = StringHosttoUint32(::wxGetFullHostName());
377 #ifndef __WINDOWS__
378 // get rid of sigpipe
379 signal(SIGPIPE, SIG_IGN);
380 #else
381 // Handle CTRL-Break
382 signal(SIGBREAK, OnShutdownSignal);
383 #endif
384 // Handle sigint and sigterm
385 signal(SIGINT, OnShutdownSignal);
386 signal(SIGTERM, OnShutdownSignal);
388 #ifdef __WXMAC__
389 // For listctrl's to behave on Mac
390 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
391 #endif
393 // Handle uncaught exceptions
394 InstallMuleExceptionHandler();
396 if (!InitCommon(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv)) {
397 return false;
400 glob_prefs = new CPreferences();
402 CPath outDir;
403 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"), outDir)) {
404 thePrefs::SetTempDir(outDir);
405 } else {
406 return false;
409 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"), outDir)) {
410 thePrefs::SetIncomingDir(outDir);
411 } else {
412 return false;
415 // Initialize wx sockets (needed for http download in background with Asio sockets)
416 wxSocketBase::Initialize();
418 // Some sanity check
419 if (!thePrefs::UseTrayIcon()) {
420 thePrefs::SetMinToTray(false);
423 // Build the filenames for the two OS files
424 SetOSFiles(thePrefs::GetOSDir().GetRaw());
426 #ifdef ENABLE_NLS
427 // Load localization settings
428 Localize_mule();
429 #endif
431 // Configure EC for amuled when invoked with ec-config
432 if (ec_config) {
433 AddLogLineNS(_("\nEC configuration"));
434 thePrefs::SetECPass(GetPassword(false).Encode());
435 thePrefs::EnableExternalConnections(true);
436 AddLogLineNS(_("Password set and external connections enabled."));
439 #ifndef __WINDOWS__
440 if (getuid() == 0) {
441 wxString msg =
442 wxT("Warning! You are running aMule as root.\n")
443 wxT("Doing so is not recommended for security reasons,\n")
444 wxT("and you are advised to run aMule as an normal\n")
445 wxT("user instead.");
447 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
449 fprintf(stderr, "\n--------------------------------------------------\n");
450 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
451 fprintf(stderr, "\n--------------------------------------------------\n\n");
453 #endif
455 // Display notification on new version or first run
456 wxTextFile vfile( ConfigDir + wxT("lastversion") );
457 wxString newMule(wxT( VERSION ));
459 if ( !wxFileExists( vfile.GetName() ) ) {
460 vfile.Create();
463 if ( vfile.Open() ) {
464 // Check if this version has been run before
465 bool found = false;
466 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
467 // Check if this version has been run before
468 if ( vfile.GetLine(i) == newMule ) {
469 found = true;
470 break;
474 // We havent run this version before?
475 if ( !found ) {
476 // Insert new at top to provide faster searches
477 vfile.InsertLine( newMule, 0 );
479 Trigger_New_version( newMule );
482 // Keep at most 10 entires
483 while ( vfile.GetLineCount() > 10 )
484 vfile.RemoveLine( vfile.GetLineCount() - 1 );
486 vfile.Write();
487 vfile.Close();
490 // Check if we have the old style locale config
491 wxString langId = thePrefs::GetLanguageID();
492 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
493 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
494 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
495 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
498 m_statistics = new CStatistics();
500 clientlist = new CClientList();
501 friendlist = new CFriendList();
502 searchlist = new CSearchList();
503 knownfiles = new CKnownFileList();
504 canceledfiles = new CCanceledFileList;
505 serverlist = new CServerList();
507 sharedfiles = new CSharedFileList(knownfiles);
508 clientcredits = new CClientCreditsList();
510 // bugfix - do this before creating the uploadqueue
511 downloadqueue = new CDownloadQueue();
512 uploadqueue = new CUploadQueue();
513 ipfilter = new CIPFilter();
515 // Creates all needed listening sockets
516 wxString msg;
517 if (!ReinitializeNetwork(&msg)) {
518 AddLogLineNS(wxT("\n"));
519 AddLogLineNS(msg);
522 // Test if there's any new version
523 if (thePrefs::GetCheckNewVersion()) {
524 // We use the thread base because I don't want a dialog to pop up.
525 CHTTPDownloadThread* version_check =
526 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
527 theApp->ConfigDir + wxT("last_version_check"), theApp->ConfigDir + wxT("last_version"), HTTP_VersionCheck, false, false);
528 version_check->Create();
529 version_check->Run();
532 // Create main dialog, or fork to background (daemon).
533 InitGui(m_geometryEnabled, m_geometryString);
535 #ifdef AMULE_DAEMON
536 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
537 if (enable_daemon_fork) {
538 RefreshSingleInstanceChecker();
539 // No need to check IsAnotherRunning() - we've done it before.
541 #endif
543 // Has to be created after the call to InitGui, as fork
544 // (when using posix threads) only replicates the mainthread,
545 // and the UBT constructor creates a thread.
546 uploadBandwidthThrottler = new UploadBandwidthThrottler();
548 m_AsioService = new CAsioService;
551 // Start performing background tasks
552 // This will start loading the IP filter. It will start right away.
553 // Log is confusing, because log entries from background will only be printed
554 // once foreground becomes idle, and that will only be after loading
555 // of the partfiles has finished.
556 CThreadScheduler::Start();
558 // These must be initialized after the gui is loaded.
559 if (thePrefs::GetNetworkED2K()) {
560 serverlist->Init();
562 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
563 sharedfiles->Reload();
565 // Ensure that the up/down ratio is used
566 CPreferences::CheckUlDlRatio();
568 // Load saved friendlist (now, so it can update in GUI right away)
569 friendlist->LoadList();
571 // The user can start pressing buttons like mad if he feels like it.
572 m_app_state = APP_STATE_RUNNING;
574 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
575 // There are no servers and ED2K active -> ask for download.
576 // As we cannot ask in amuled, we just update there
577 #ifndef AMULE_DAEMON
578 if (wxYES == wxMessageBox(
579 wxString(
580 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
581 wxString(_("Server list download")),
582 wxYES_NO,
583 static_cast<wxWindow*>(theApp->amuledlg)))
584 #endif
586 serverlist->UpdateServerMetFromURL(thePrefs::GetEd2kServersUrl());
591 // Autoconnect if that option is enabled
592 if (thePrefs::DoAutoConnect()) {
593 // IP filter is still loading and will be finished on event.
594 // Tell it to autoconnect.
595 if (thePrefs::GetNetworkED2K()) {
596 ipfilter->ConnectToAnyServerWhenReady();
598 if (thePrefs::GetNetworkKademlia()) {
599 ipfilter->StartKADWhenReady();
603 // Enable GeoIP
604 #ifdef ENABLE_IP2COUNTRY
605 theApp->amuledlg->EnableIP2Country();
606 #endif
608 // Run webserver?
609 if (thePrefs::GetWSIsEnabled()) {
610 wxString aMuleConfigFile = ConfigDir + m_configFile;
611 wxString amulewebPath = thePrefs::GetWSPath();
613 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
614 // For the Mac GUI application, look for amuleweb in the bundle
615 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
616 CFBundleGetMainBundle(), CFSTR("amuleweb"));
618 if (amulewebUrl) {
619 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
620 CFRelease(amulewebUrl);
622 if (absoluteUrl) {
623 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
624 CFRelease(absoluteUrl);
625 #if wxCHECK_VERSION(2, 9, 0)
626 amulewebPath = wxCFStringRef(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
627 #else
628 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
629 #endif
632 #endif
634 #ifdef __WINDOWS__
635 # define QUOTE wxT("\"")
636 #else
637 # define QUOTE wxT("\'")
638 #endif
640 wxString cmd =
641 QUOTE +
642 amulewebPath +
643 QUOTE wxT(" ") QUOTE wxT("--amule-config-file=") +
644 aMuleConfigFile +
645 QUOTE;
646 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
647 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
648 bool webserver_ok = webserver_pid > 0;
649 if (webserver_ok) {
650 AddLogLineC(CFormat(_("web server running on pid %d")) % webserver_pid);
651 } else {
652 delete p;
653 ShowAlert(_(
654 "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"),
655 _("ERROR"), wxOK | wxICON_ERROR);
659 return true;
662 bool CamuleApp::ReinitializeNetwork(wxString* msg)
664 bool ok = true;
665 static bool firstTime = true;
667 if (!firstTime) {
668 // TODO: Destroy previously created sockets
670 firstTime = false;
672 // Some sanity checks first
673 if (thePrefs::ECPort() == thePrefs::GetPort()) {
674 // Select a random usable port in the range 1025 ... 2^16 - 1
675 uint16 port = thePrefs::ECPort();
676 while ( port < 1024 || port == thePrefs::GetPort() ) {
677 port = (uint16)rand();
679 thePrefs::SetECPort( port );
681 wxString err =
682 wxT("Network configuration failed! You cannot use the same port\n")
683 wxT("for the main TCP port and the External Connections port.\n")
684 wxT("The EC port has been changed to avoid conflict, see the\n")
685 wxT("preferences for the new value.\n");
686 *msg << err;
688 AddLogLineN(wxEmptyString );
689 AddLogLineC(err );
690 AddLogLineN(wxEmptyString );
692 ok = false;
695 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
696 // Select a random usable value in the range 1025 ... 2^16 - 1
697 uint16 port = thePrefs::GetUDPPort();
698 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
699 port = (uint16)rand();
701 thePrefs::SetUDPPort( port );
703 wxString err =
704 wxT("Network configuration failed! You set your UDP port to\n")
705 wxT("the value of the main TCP port plus 3.\n")
706 wxT("This port has been reserved for the Server-UDP port. The\n")
707 wxT("port value has been changed to avoid conflict, see the\n")
708 wxT("preferences for the new value\n");
709 *msg << err;
711 AddLogLineN(wxEmptyString );
712 AddLogLineC(err );
713 AddLogLineN(wxEmptyString );
715 ok = false;
718 // Create the address where we are going to listen
719 // TODO: read this from configuration file
720 amuleIPV4Address myaddr[4];
722 // Create the External Connections Socket.
723 // Default is 4712.
724 // Get ready to handle connections from apps like amulecmd
725 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
726 myaddr[0].AnyAddress();
728 myaddr[0].Service(thePrefs::ECPort());
729 ECServerHandler = new ExternalConn(myaddr[0], msg);
731 // Create the UDP socket TCP+3.
732 // Used for source asking on servers.
733 if (thePrefs::GetAddress().IsEmpty()) {
734 myaddr[1].AnyAddress();
735 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
736 myaddr[1].AnyAddress();
737 AddLogLineC(CFormat(_("Could not bind ports to the specified address: %s"))
738 % thePrefs::GetAddress());
741 wxString ip = myaddr[1].IPAddress();
742 myaddr[1].Service(thePrefs::GetPort()+3);
743 serverconnect = new CServerConnect(serverlist, myaddr[1]);
744 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
745 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
747 // Create the ListenSocket (aMule TCP socket).
748 // Used for Client Port / Connections from other clients,
749 // Client to Client Source Exchange.
750 // Default is 4662.
751 myaddr[2] = myaddr[1];
752 myaddr[2].Service(thePrefs::GetPort());
753 listensocket = new CListenSocket(myaddr[2]);
754 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
755 % ip % (unsigned int)(thePrefs::GetPort());
756 // Notify(true) has already been called to the ListenSocket, so events may
757 // be already comming in.
758 if (!listensocket->IsOk()) {
759 // If we wern't able to start listening, we need to warn the user
760 wxString err;
761 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
762 (unsigned int)(thePrefs::GetPort());
763 *msg << err;
764 AddLogLineC(err);
765 err.Clear();
766 err = CFormat(
767 _("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.")) %
768 (unsigned int)(thePrefs::GetPort());
769 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
772 // Create the UDP socket.
773 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
774 // Also used for Kademlia.
775 // Default is port 4672.
776 myaddr[3] = myaddr[1];
777 myaddr[3].Service(thePrefs::GetUDPPort());
778 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
779 if (!thePrefs::IsUDPDisabled()) {
780 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
781 % ip % thePrefs::GetUDPPort();
782 } else {
783 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
786 #ifdef ENABLE_UPNP
787 if (thePrefs::GetUPnPEnabled()) {
788 try {
789 m_upnpMappings[0] = CUPnPPortMapping(
790 myaddr[0].Service(),
791 "TCP",
792 thePrefs::GetUPnPECEnabled(),
793 "aMule TCP External Connections Socket");
794 m_upnpMappings[1] = CUPnPPortMapping(
795 myaddr[1].Service(),
796 "UDP",
797 thePrefs::GetUPnPEnabled(),
798 "aMule UDP socket (TCP+3)");
799 m_upnpMappings[2] = CUPnPPortMapping(
800 myaddr[2].Service(),
801 "TCP",
802 thePrefs::GetUPnPEnabled(),
803 "aMule TCP Listen Socket");
804 m_upnpMappings[3] = CUPnPPortMapping(
805 myaddr[3].Service(),
806 "UDP",
807 thePrefs::GetUPnPEnabled(),
808 "aMule UDP Extended eMule Socket");
809 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
810 m_upnp->AddPortMappings(m_upnpMappings);
811 } catch(CUPnPException &e) {
812 wxString error_msg;
813 error_msg << e.what();
814 AddLogLineC(error_msg);
815 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
818 #endif
820 return ok;
823 /* Original implementation by Bouc7 of the eMule Project.
824 aMule Signature idea was designed by BigBob and implemented
825 by Un-Thesis, with design inputs and suggestions from bothie.
827 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
829 // Do not do anything if online signature is disabled in Preferences
830 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
831 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
832 // that means m_amulesig_path is empty too.
833 return;
836 // Remove old signature files
837 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
838 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
841 wxTextFile amulesig_out;
842 wxTextFile emulesig_out;
844 // Open both files if needed
845 if ( !emulesig_out.Create( m_emulesig_path) ) {
846 AddLogLineC(_("Failed to create OnlineSig File"));
847 // Will never try again.
848 m_amulesig_path.Clear();
849 m_emulesig_path.Clear();
850 return;
853 if ( !amulesig_out.Create(m_amulesig_path) ) {
854 AddLogLineC(_("Failed to create aMule OnlineSig File"));
855 // Will never try again.
856 m_amulesig_path.Clear();
857 m_emulesig_path.Clear();
858 return;
861 wxString emulesig_string;
862 wxString temp;
864 if (zero) {
865 emulesig_string = wxT("0\xA0.0|0.0|0");
866 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
867 } else {
868 if (IsConnectedED2K()) {
870 temp = CFormat(wxT("%d")) % serverconnect->GetCurrentServer()->GetPort();
872 // We are online
873 emulesig_string =
874 // Connected
875 wxT("1|")
876 //Server name
877 + serverconnect->GetCurrentServer()->GetListName()
878 + wxT("|")
879 // IP and port of the server
880 + serverconnect->GetCurrentServer()->GetFullIP()
881 + wxT("|")
882 + temp;
885 // Now for amule sig
887 // Connected. State 1, full info
888 amulesig_out.AddLine(wxT("1"));
889 // Server Name
890 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
891 // Server IP
892 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
893 // Server Port
894 amulesig_out.AddLine(temp);
896 if (serverconnect->IsLowID()) {
897 amulesig_out.AddLine(wxT("L"));
898 } else {
899 amulesig_out.AddLine(wxT("H"));
902 } else if (serverconnect->IsConnecting()) {
903 emulesig_string = wxT("0");
905 // Connecting. State 2, No info.
906 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
907 } else {
908 // Not connected to a server
909 emulesig_string = wxT("0");
911 // Not connected, state 0, no info
912 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
914 if (IsConnectedKad()) {
915 if(Kademlia::CKademlia::IsFirewalled()) {
916 // Connected. Firewalled. State 1.
917 amulesig_out.AddLine(wxT("1"));
918 } else {
919 // Connected. State 2.
920 amulesig_out.AddLine(wxT("2"));
922 } else {
923 // Not connected.State 0.
924 amulesig_out.AddLine(wxT("0"));
926 emulesig_string += wxT("\xA");
928 // Datarate for downloads
929 temp = CFormat(wxT("%.1f")) % (theStats::GetDownloadRate() / 1024.0);
931 emulesig_string += temp + wxT("|");
932 amulesig_out.AddLine(temp);
934 // Datarate for uploads
935 temp = CFormat(wxT("%.1f")) % (theStats::GetUploadRate() / 1024.0);
937 emulesig_string += temp + wxT("|");
938 amulesig_out.AddLine(temp);
940 // Number of users waiting for upload
941 temp = CFormat(wxT("%d")) % theStats::GetWaitingUserCount();
943 emulesig_string += temp;
944 amulesig_out.AddLine(temp);
946 // Number of shared files (not on eMule)
947 amulesig_out.AddLine(CFormat(wxT("%d")) % theStats::GetSharedFileCount());
950 // eMule signature finished here. Write the line to the wxTextFile.
951 emulesig_out.AddLine(emulesig_string);
953 // Now for aMule signature extras
955 // Nick on the network
956 amulesig_out.AddLine(thePrefs::GetUserNick());
958 // Total received in bytes
959 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalReceivedBytes());
961 // Total sent in bytes
962 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalSentBytes());
964 // amule version
965 #ifdef SVNDATE
966 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
967 #else
968 amulesig_out.AddLine(wxT(VERSION));
969 #endif
971 if (zero) {
972 amulesig_out.AddLine(wxT("0"));
973 amulesig_out.AddLine(wxT("0"));
974 amulesig_out.AddLine(wxT("0"));
975 } else {
976 // Total received bytes in session
977 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
978 theStats::GetSessionReceivedBytes() );
980 // Total sent bytes in session
981 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
982 theStats::GetSessionSentBytes() );
984 // Uptime
985 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
988 // Flush the files
989 emulesig_out.Write();
990 amulesig_out.Write();
991 } //End Added By Bouc7
994 #if wxUSE_ON_FATAL_EXCEPTION
995 // Gracefully handle fatal exceptions and print backtrace if possible
996 void CamuleApp::OnFatalException()
998 /* Print the backtrace */
999 wxString msg;
1000 msg << wxT("\n--------------------------------------------------------------------------------\n")
1001 << wxT("A fatal error has occurred and aMule has crashed.\n")
1002 << wxT("Please assist us in fixing this problem by posting the backtrace below in our\n")
1003 << wxT("'aMule Crashes' forum and include as much information as possible regarding the\n")
1004 << wxT("circumstances of this crash. The forum is located here:\n")
1005 << wxT(" http://forum.amule.org/index.php?board=67.0\n")
1006 << wxT("If possible, please try to generate a real backtrace of this crash:\n")
1007 << wxT(" http://wiki.amule.org/index.php/Backtraces\n\n")
1008 << wxT("----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n")
1009 << wxT("Current version is: ") << FullMuleVersion
1010 << wxT("\nRunning on: ") << OSDescription
1011 << wxT("\n\n")
1012 << get_backtrace(1) // 1 == skip this function.
1013 << wxT("\n--------------------------------------------------------------------------------\n");
1015 theLogger.EmergencyLog(msg, true);
1017 #endif
1020 // Sets the localization of aMule
1021 void CamuleApp::Localize_mule()
1023 InitCustomLanguages();
1024 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1025 if (!m_locale.IsOk()) {
1026 AddLogLineN(_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1031 // Displays information related to important changes in aMule.
1032 // Is called when the user runs a new version of aMule
1033 void CamuleApp::Trigger_New_version(wxString new_version)
1035 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1036 if (new_version == wxT("SVN")) {
1037 info += _("This version is a testing version, updated daily, and\n");
1038 info += _("we give no warranty it won't break anything, burn your house,\n");
1039 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1042 // General info
1043 info += wxT("\n");
1044 info += _("More information, support and new releases can found at our homepage,\n");
1045 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1046 info += wxT("\n");
1047 info += _("Feel free to report any bugs to http://forum.amule.org");
1049 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1053 void CamuleApp::SetOSFiles(const wxString& new_path)
1055 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1056 if ( ::wxDirExists(new_path) ) {
1057 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1058 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1059 } else {
1060 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);
1061 m_emulesig_path.Clear();
1062 m_amulesig_path.Clear();
1064 } else {
1065 m_emulesig_path.Clear();
1066 m_amulesig_path.Clear();
1071 #ifdef __WXDEBUG__
1072 #ifndef wxUSE_STACKWALKER
1073 #define wxUSE_STACKWALKER 0
1074 #endif
1075 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1076 const wxChar* func, const wxChar* cond, const wxChar* msg)
1078 wxString errmsg = CFormat( wxT("Assertion failed: %s:%s:%d: Assertion '%s' failed. %s\nBacktrace follows:\n%s\n") )
1079 % file % func % line % cond % ( msg ? msg : wxT("") )
1080 % get_backtrace(2); // Skip the function-calls directly related to the assert call.
1081 theLogger.EmergencyLog(errmsg, false);
1083 if (wxThread::IsMain() && IsRunning()) {
1084 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1085 } else {
1086 #ifdef _MSC_VER
1087 wxString s = CFormat(wxT("%s in %s")) % cond % func;
1088 if (msg) {
1089 s << wxT(" : ") << msg;
1091 _wassert(s.wc_str(), file, line);
1092 #else
1093 // Abort, allows gdb to catch the assertion
1094 raise( SIGABRT );
1095 #endif
1098 #endif
1101 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1103 CServerUDPSocket* socket =reinterpret_cast<CServerUDPSocket*>(evt.GetClientData());
1104 socket->OnHostnameResolved(evt.GetExtraLong());
1108 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1110 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1114 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1116 AddLogLineNS(_("Server hostname notified"));
1117 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1121 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1123 if(!IsRunning()) {
1124 return;
1126 serverconnect->StopConnectionTry();
1127 if (IsConnectedED2K() ) {
1128 return;
1130 serverconnect->ConnectToAnyServer();
1134 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1136 // Former TimerProc section
1137 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1138 uint64 msCur = theStats::GetUptimeMillis();
1139 TheTime = msCur / 1000;
1141 if (!IsRunning()) {
1142 return;
1145 #ifndef AMULE_DAEMON
1146 // Check if we should terminate the app
1147 if ( g_shutdownSignal ) {
1148 wxWindow* top = GetTopWindow();
1150 if ( top ) {
1151 top->Close(true);
1152 } else {
1153 // No top-window, have to force termination.
1154 wxExit();
1157 #endif
1159 // There is a theoretical chance that the core time function can recurse:
1160 // if an event function gets blocked on a mutex (communicating with the
1161 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1162 // If CPU load gets high a new core timer event could be generated before the last
1163 // one was finished and so recursion could occur, which would be bad.
1164 // Detect this and do an early return then.
1165 static bool recurse = false;
1166 if (recurse) {
1167 return;
1169 recurse = true;
1171 uploadqueue->Process();
1172 downloadqueue->Process();
1173 //theApp->clientcredits->Process();
1174 theStats::CalculateRates();
1176 if (msCur-msPrevHist > 1000) {
1177 // unlike the other loop counters in this function this one will sometimes
1178 // produce two calls in quick succession (if there was a gap of more than one
1179 // second between calls to TimerProc) - this is intentional! This way the
1180 // history list keeps an average of one node per second and gets thinned out
1181 // correctly as time progresses.
1182 msPrevHist += 1000;
1184 m_statistics->RecordHistory();
1189 if (msCur-msPrev1 > 1000) { // approximately every second
1190 msPrev1 = msCur;
1191 clientcredits->Process();
1192 clientlist->Process();
1194 // Publish files to server if needed.
1195 sharedfiles->Process();
1197 if( Kademlia::CKademlia::IsRunning() ) {
1198 Kademlia::CKademlia::Process();
1199 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1200 StopKad();
1201 clientudp->Close();
1202 clientudp->Open();
1203 if (thePrefs::Reconnect()) {
1204 StartKad();
1209 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1210 serverconnect->TryAnotherConnectionrequest();
1212 if (serverconnect->IsConnecting()) {
1213 serverconnect->CheckForTimeout();
1215 listensocket->UpdateConnectionsStatus();
1220 if (msCur-msPrev5 > 5000) { // every 5 seconds
1221 msPrev5 = msCur;
1222 listensocket->Process();
1225 if (msCur-msPrevSave >= 60000) {
1226 msPrevSave = msCur;
1227 theStats::Save();
1230 // Special
1231 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1232 OnlineSig(); // Added By Bouc7
1233 msPrevOS = msCur;
1236 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1237 // Save Shared Files data
1238 knownfiles->Save();
1239 msPrevKnownMet = msCur;
1243 // Recomended by lugdunummaster himself - from emule 0.30c
1244 serverconnect->KeepConnectionAlive();
1246 // Disarm recursion protection
1247 recurse = false;
1251 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1253 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1255 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1256 CKnownFile* result = evt.GetResult();
1258 if (owner) {
1259 // Check if the partfile still exists, as it might have
1260 // been deleted in the mean time.
1261 if (downloadqueue->IsPartFile(owner)) {
1262 // This cast must not be done before the IsPartFile
1263 // call, as dynamic_cast will barf on dangling pointers.
1264 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1266 } else {
1267 static uint64 bytecount = 0;
1269 if (knownfiles->SafeAddKFile(result, true)) {
1270 AddDebugLogLineN(logKnownFiles,
1271 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1272 sharedfiles->SafeAddKFile(result);
1274 bytecount += result->GetFileSize();
1275 // If we have added files with a total size of ~3000mb
1276 if (bytecount >= 3145728000) {
1277 AddDebugLogLineN(logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1278 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1279 knownfiles->Save();
1280 bytecount = 0;
1283 } else {
1284 AddDebugLogLineN(logKnownFiles,
1285 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1286 delete result;
1292 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1294 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1296 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1297 CScopedPtr<CKnownFile> result(evt.GetResult());
1299 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1300 CAICHHashSet* oldSet = owner->GetAICHHashset();
1301 CAICHHashSet* newSet = result->GetAICHHashset();
1303 owner->SetAICHHashset(newSet);
1304 newSet->SetOwner(owner);
1306 result->SetAICHHashset(oldSet);
1307 oldSet->SetOwner(result.get());
1312 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1314 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1315 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1316 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1318 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1319 if (evt.ErrorOccured()) {
1320 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1323 // Check if we should execute an script/app/whatever.
1324 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1327 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1329 CPartFile *file = evt.GetFile();
1330 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1331 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1333 file->SetStatus(PS_EMPTY);
1335 if (evt.Succeeded()) {
1336 if (evt.IsPaused()) {
1337 file->StopFile();
1338 } else {
1339 file->ResumeFile();
1341 } else {
1342 AddLogLineN(CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1343 file->StopFile();
1346 file->AllocationFinished();
1349 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1351 #ifdef AMULE_DAEMON
1352 evt.Notify();
1353 #else
1354 if (theApp->amuledlg) {
1355 evt.Notify();
1357 #endif
1361 void CamuleApp::ShutDown()
1363 // Just in case
1364 PlatformSpecific::AllowSleepMode();
1366 // Log
1367 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has started."));
1369 // Signal the hashing thread to terminate
1370 m_app_state = APP_STATE_SHUTTINGDOWN;
1372 // Stop ASIO thread
1373 #ifdef ASIO_SOCKETS // only needed to suppress the log message in non-Asio build
1374 AddDebugLogLineN(logGeneral, wxT("Terminate ASIO thread."));
1375 m_AsioService->Stop();
1376 #endif
1378 StopKad();
1380 // Kry - Save the sources seeds on app exit
1381 if (thePrefs::GetSrcSeedsOn()) {
1382 downloadqueue->SaveSourceSeeds();
1385 OnlineSig(true); // Added By Bouc7
1387 // Exit HTTP downloads
1388 CHTTPDownloadThread::StopAll();
1390 // Exit thread scheduler and upload thread
1391 CThreadScheduler::Terminate();
1393 AddDebugLogLineN(logGeneral, wxT("Terminate upload thread."));
1394 uploadBandwidthThrottler->EndThread();
1396 // Close sockets to avoid new clients coming in
1397 if (listensocket) {
1398 listensocket->Close();
1399 listensocket->KillAllSockets();
1402 if (serverconnect) {
1403 serverconnect->Disconnect();
1406 ECServerHandler->KillAllSockets();
1408 #ifdef ENABLE_UPNP
1409 if (thePrefs::GetUPnPEnabled()) {
1410 if (m_upnp) {
1411 m_upnp->DeletePortMappings(m_upnpMappings);
1414 #endif
1416 // saving data & stuff
1417 if (knownfiles) {
1418 knownfiles->Save();
1421 theStats::Save();
1423 CPath configFileName = CPath(ConfigDir + m_configFile);
1424 CPath::BackupFile(configFileName, wxT(".bak"));
1426 if (clientlist) {
1427 clientlist->DeleteAll();
1430 // Log
1431 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1435 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1437 if ( serverlist->AddServer(srv, fromUser) ) {
1438 Notify_ServerAdd(srv);
1439 return true;
1441 return false;
1445 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1447 if (m_dwPublicIP == 0) {
1448 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1449 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1450 } else {
1451 return ignorelocal ? 0 : m_localip;
1455 return m_dwPublicIP;
1459 void CamuleApp::SetPublicIP(const uint32 dwIP)
1461 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1463 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1464 m_dwPublicIP = dwIP;
1465 serverlist->CheckForExpiredUDPKeys();
1466 } else {
1467 m_dwPublicIP = dwIP;
1472 wxString CamuleApp::GetLog(bool reset)
1474 wxFile logfile;
1475 logfile.Open(ConfigDir + wxT("logfile"));
1476 if ( !logfile.IsOpened() ) {
1477 return _("ERROR: can't open logfile");
1479 int len = logfile.Length();
1480 if ( len == 0 ) {
1481 return _("WARNING: logfile is empty. Something is wrong.");
1483 char *tmp_buffer = new char[len + sizeof(wxChar)];
1484 logfile.Read(tmp_buffer, len);
1485 memset(tmp_buffer + len, 0, sizeof(wxChar));
1487 // try to guess file format
1488 wxString str;
1489 if (tmp_buffer[0] && tmp_buffer[1]) {
1490 str = wxString(UTF82unicode(tmp_buffer));
1491 } else {
1492 str = wxWCharBuffer((wchar_t *)tmp_buffer);
1495 delete [] tmp_buffer;
1496 if ( reset ) {
1497 theLogger.CloseLogfile();
1498 if (theLogger.OpenLogfile(ConfigDir + wxT("logfile"))) {
1499 AddLogLineN(_("Log has been reset"));
1501 ECServerHandler->ResetAllLogs();
1503 return str;
1507 wxString CamuleApp::GetServerLog(bool reset)
1509 wxString ret = server_msg;
1510 if ( reset ) {
1511 server_msg.Clear();
1513 return ret;
1516 wxString CamuleApp::GetDebugLog(bool reset)
1518 return GetLog(reset);
1522 void CamuleApp::AddServerMessageLine(wxString &msg)
1524 server_msg += msg + wxT("\n");
1525 AddLogLineN(CFormat(_("ServerMessage: %s")) % msg);
1530 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1532 switch (event.GetInt()) {
1533 case HTTP_IPFilter:
1534 ipfilter->DownloadFinished(event.GetExtraLong());
1535 break;
1536 case HTTP_ServerMet:
1537 if (serverlist->DownloadFinished(event.GetExtraLong()) && !IsConnectedED2K()) {
1538 // If successfully downloaded a server list, and are not connected at the moment, try to connect.
1539 // This happens when no server met is available on startup.
1540 serverconnect->ConnectToAnyServer();
1542 break;
1543 case HTTP_ServerMetAuto:
1544 serverlist->AutoDownloadFinished(event.GetExtraLong());
1545 break;
1546 case HTTP_VersionCheck:
1547 CheckNewVersion(event.GetExtraLong());
1548 break;
1549 case HTTP_NodesDat:
1550 if (event.GetExtraLong() == HTTP_Success) {
1552 wxString file = ConfigDir + wxT("nodes.dat");
1553 if (wxFileExists(file)) {
1554 wxRemoveFile(file);
1557 if ( Kademlia::CKademlia::IsRunning() ) {
1558 Kademlia::CKademlia::Stop();
1561 wxRenameFile(file + wxT(".download"),file);
1563 Kademlia::CKademlia::Start();
1564 theApp->ShowConnectionState();
1565 // cppcheck-suppress duplicateBranch
1566 } else if (event.GetExtraLong() == HTTP_Skipped) {
1567 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1568 } else {
1569 AddLogLineC(_("Failed to download the nodes list."));
1571 break;
1572 #ifdef ENABLE_IP2COUNTRY
1573 case HTTP_GeoIP:
1574 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1575 // If we updated, the dialog is already up. Redraw it to show the flags.
1576 theApp->amuledlg->Refresh();
1577 break;
1578 #endif
1582 void CamuleApp::CheckNewVersion(uint32 result)
1584 if (result == HTTP_Success) {
1585 wxString filename = ConfigDir + wxT("last_version_check");
1586 wxTextFile file;
1588 if (!file.Open(filename)) {
1589 AddLogLineC(_("Failed to open the downloaded version check file") );
1590 return;
1591 } else if (!file.GetLineCount()) {
1592 AddLogLineC(_("Corrupted version check file"));
1593 } else {
1594 wxString versionLine = file.GetFirstLine();
1595 wxStringTokenizer tkz(versionLine, wxT("."));
1597 AddDebugLogLineN(logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1599 long fields[] = {0, 0, 0};
1600 for (int i = 0; i < 3; ++i) {
1601 if (!tkz.HasMoreTokens()) {
1602 AddLogLineC(_("Corrupted version check file"));
1603 return;
1604 } else {
1605 wxString token = tkz.GetNextToken();
1607 if (!token.ToLong(&fields[i])) {
1608 AddLogLineC(_("Corrupted version check file"));
1609 return;
1614 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1615 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1617 if (curVer < newVer) {
1618 AddLogLineC(_("You are using an outdated version of aMule!"));
1619 // cppcheck-suppress zerodiv
1620 AddLogLineN(CFormat(_("Your aMule version is %i.%i.%i and the latest version is %li.%li.%li")) % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1621 AddLogLineN(_("The latest version can always be found at http://www.amule.org"));
1622 #ifdef AMULE_DAEMON
1623 AddLogLineCS(CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1624 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1625 #endif
1626 } else {
1627 AddLogLineN(_("Your copy of aMule is up to date."));
1631 file.Close();
1632 wxRemoveFile(filename);
1633 } else {
1634 AddLogLineC(_("Failed to download the version check file"));
1640 bool CamuleApp::IsConnected() const
1642 return (IsConnectedED2K() || IsConnectedKad());
1646 bool CamuleApp::IsConnectedED2K() const
1648 return serverconnect && serverconnect->IsConnected();
1652 bool CamuleApp::IsConnectedKad() const
1654 return Kademlia::CKademlia::IsConnected();
1658 bool CamuleApp::IsFirewalled() const
1660 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1661 return false; // we have an eD2K HighID -> not firewalled
1664 return IsFirewalledKad(); // If kad says ok, it's ok.
1667 bool CamuleApp::IsFirewalledKad() const
1669 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1670 || Kademlia::CKademlia::IsFirewalled();
1673 bool CamuleApp::IsFirewalledKadUDP() const
1675 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1676 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1679 bool CamuleApp::IsKadRunning() const
1681 return Kademlia::CKademlia::IsRunning();
1684 bool CamuleApp::IsKadRunningInLanMode() const
1686 return Kademlia::CKademlia::IsRunningInLANMode();
1689 // Kad stats
1690 uint32 CamuleApp::GetKadUsers() const
1692 return Kademlia::CKademlia::GetKademliaUsers();
1695 uint32 CamuleApp::GetKadFiles() const
1697 return Kademlia::CKademlia::GetKademliaFiles();
1700 uint32 CamuleApp::GetKadIndexedSources() const
1702 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1705 uint32 CamuleApp::GetKadIndexedKeywords() const
1707 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1710 uint32 CamuleApp::GetKadIndexedNotes() const
1712 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1715 uint32 CamuleApp::GetKadIndexedLoad() const
1717 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1721 // True IP of machine
1722 uint32 CamuleApp::GetKadIPAdress() const
1724 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1727 // Buddy status
1728 uint8 CamuleApp::GetBuddyStatus() const
1730 return clientlist->GetBuddyStatus();
1733 uint32 CamuleApp::GetBuddyIP() const
1735 return clientlist->GetBuddyIP();
1738 uint32 CamuleApp::GetBuddyPort() const
1740 return clientlist->GetBuddyPort();
1743 bool CamuleApp::CanDoCallback(uint32 clientServerIP, uint16 clientServerPort)
1745 if (Kademlia::CKademlia::IsConnected()) {
1746 if (IsConnectedED2K()) {
1747 if (serverconnect->IsLowID()) {
1748 if (Kademlia::CKademlia::IsFirewalled()) {
1749 //Both Connected - Both Firewalled
1750 return false;
1751 } else {
1752 if (clientServerIP == theApp->serverconnect->GetCurrentServer()->GetIP() &&
1753 clientServerPort == theApp->serverconnect->GetCurrentServer()->GetPort()) {
1754 // Both Connected - Server lowID, Kad Open - Client on same server
1755 // We prevent a callback to the server as this breaks the protocol
1756 // and will get you banned.
1757 return false;
1758 } else {
1759 // Both Connected - Server lowID, Kad Open - Client on remote server
1760 return true;
1763 } else {
1764 //Both Connected - Server HighID, Kad don't care
1765 return true;
1767 } else {
1768 if (Kademlia::CKademlia::IsFirewalled()) {
1769 //Only Kad Connected - Kad Firewalled
1770 return false;
1771 } else {
1772 //Only Kad Conected - Kad Open
1773 return true;
1776 } else {
1777 if (IsConnectedED2K()) {
1778 if (serverconnect->IsLowID()) {
1779 //Only Server Connected - Server LowID
1780 return false;
1781 } else {
1782 //Only Server Connected - Server HighID
1783 return true;
1785 } else {
1786 //We are not connected at all!
1787 return false;
1792 void CamuleApp::ShowUserCount() {
1793 uint32 totaluser = 0, totalfile = 0;
1795 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
1797 wxString buffer;
1799 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
1800 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
1802 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1803 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1804 } else if (thePrefs::GetNetworkED2K()) {
1805 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
1806 } else if (thePrefs::GetNetworkKademlia()) {
1807 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1808 } else {
1809 buffer = _("No networks selected");
1812 Notify_ShowUserCount(buffer);
1816 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
1818 { wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket")); }
1819 { wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
1820 wxT("Invalid event received for listen-socket")); }
1822 if (m_app_state == APP_STATE_RUNNING) {
1823 listensocket->OnAccept();
1824 } else if (m_app_state == APP_STATE_STARTING) {
1825 // When starting up, connection may be made before we are able
1826 // to handle them. However, if these are ignored, no futher
1827 // connection-events will be triggered, so we have to accept it.
1828 CLibSocket* socket = listensocket->Accept(false);
1830 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
1832 socket->Destroy();
1837 void CamuleApp::ShowConnectionState(bool forceUpdate)
1839 static uint8 old_state = (1<<7); // This flag doesn't exist
1841 uint8 state = 0;
1843 if (theApp->serverconnect->IsConnected()) {
1844 state |= CONNECTED_ED2K;
1847 if (Kademlia::CKademlia::IsRunning()) {
1848 if (Kademlia::CKademlia::IsConnected()) {
1849 if (!Kademlia::CKademlia::IsFirewalled()) {
1850 state |= CONNECTED_KAD_OK;
1851 } else {
1852 state |= CONNECTED_KAD_FIREWALLED;
1854 } else {
1855 state |= CONNECTED_KAD_NOT;
1859 if (old_state != state) {
1860 // Get the changed value
1861 int changed_flags = old_state ^ state;
1863 if (changed_flags & CONNECTED_ED2K) {
1864 // ED2K status changed
1865 wxString connected_server;
1866 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
1867 if (ed2k_server) {
1868 connected_server = ed2k_server->GetListName();
1870 if (state & CONNECTED_ED2K) {
1871 // We connected to some server
1872 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
1874 AddLogLineC(CFormat(_("Connected to %s %s")) % connected_server % id);
1875 } else {
1876 // cppcheck-suppress duplicateBranch
1877 if ( theApp->serverconnect->IsConnecting() ) {
1878 AddLogLineC(CFormat(_("Connecting to %s")) % connected_server);
1879 } else {
1880 AddLogLineC(_("Disconnected from eD2k"));
1885 if (changed_flags & CONNECTED_KAD_NOT) {
1886 // cppcheck-suppress duplicateBranch
1887 if (state & CONNECTED_KAD_NOT) {
1888 AddLogLineC(_("Kad started."));
1889 } else {
1890 AddLogLineC(_("Kad stopped."));
1894 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1895 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1896 // cppcheck-suppress duplicateBranch
1897 if (state & CONNECTED_KAD_OK) {
1898 AddLogLineC(_("Connected to Kad (ok)"));
1899 } else {
1900 AddLogLineC(_("Connected to Kad (firewalled)"));
1902 } else {
1903 AddLogLineC(_("Disconnected from Kad"));
1907 old_state = state;
1909 theApp->downloadqueue->OnConnectionState(IsConnected());
1912 ShowUserCount();
1913 Notify_ShowConnState(forceUpdate);
1917 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
1919 CMuleUDPSocket* socket = reinterpret_cast<CMuleUDPSocket*>(event.GetClientData());
1920 wxCHECK_RET(socket, wxT("No socket owner specified."));
1922 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1924 if (!IsRunning()) {
1925 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
1926 // Back to the queue!
1927 theApp->AddPendingEvent(event);
1928 return;
1932 switch (event.GetSocketEvent()) {
1933 case wxSOCKET_INPUT:
1934 socket->OnReceive(0);
1935 break;
1937 case wxSOCKET_OUTPUT:
1938 socket->OnSend(0);
1939 break;
1941 case wxSOCKET_LOST:
1942 socket->OnDisconnected(0);
1943 break;
1945 default:
1946 wxFAIL;
1947 break;
1952 void CamuleApp::OnUnhandledException()
1954 // Call the generic exception-handler.
1955 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1956 ::OnUnhandledException();
1959 void CamuleApp::StartKad()
1961 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1962 // Kad makes no sense without the Client-UDP socket.
1963 if (!thePrefs::IsUDPDisabled()) {
1964 if (ipfilter->IsReady()) {
1965 Kademlia::CKademlia::Start();
1966 } else {
1967 ipfilter->StartKADWhenReady();
1969 } else {
1970 AddLogLineC(_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1972 } else if (!thePrefs::GetNetworkKademlia()) {
1973 AddLogLineC(_("Kad network disabled on preferences, not connecting."));
1977 void CamuleApp::StopKad()
1979 // Stop Kad if it's running
1980 if (Kademlia::CKademlia::IsRunning()) {
1981 Kademlia::CKademlia::Stop();
1986 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
1988 if (!Kademlia::CKademlia::IsRunning()) {
1989 Kademlia::CKademlia::Start();
1990 theApp->ShowConnectionState();
1993 Kademlia::CKademlia::Bootstrap(ip, port);
1997 void CamuleApp::UpdateNotesDat(const wxString& url)
1999 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
2001 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, theApp->ConfigDir + wxT("nodes.dat"), HTTP_NodesDat, true, false);
2002 downloader->Create();
2003 downloader->Run();
2007 void CamuleApp::DisconnectED2K()
2009 // Stop ED2K if it's running
2010 if (IsConnectedED2K()) {
2011 serverconnect->Disconnect();
2015 bool CamuleApp::CryptoAvailable() const
2017 return clientcredits && clientcredits->CryptoAvailable();
2020 uint32 CamuleApp::GetED2KID() const {
2021 return serverconnect ? serverconnect->GetClientID() : 0;
2024 uint32 CamuleApp::GetID() const {
2025 uint32 ID;
2027 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2028 // We trust Kad above ED2K
2029 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2030 } else if( theApp->serverconnect->IsConnected() ) {
2031 ID = theApp->serverconnect->GetClientID();
2032 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2033 // A firewalled Kad client get's a "1"
2034 ID = 1;
2035 } else {
2036 ID = 0;
2039 return ID;
2042 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2043 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2044 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2045 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2046 // File_checked_for_headers