Fix checking for old-style locale config entry
[amule.git] / src / amule.cpp
blob2ff5c31a18d81f79a8c4cc77b0057c92aa7ae997
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(), thePrefs::GetConfigDir() + wxT("Temp"), outDir)) {
404 thePrefs::SetTempDir(outDir);
405 } else {
406 return false;
409 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), thePrefs::GetConfigDir() + 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 // Check if we have the old style locale config
427 bool old_localedef = false;
428 wxString langId = thePrefs::GetLanguageID();
429 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
430 old_localedef = true;
431 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
432 glob_prefs->Save();
435 #ifdef ENABLE_NLS
436 // Load localization settings
437 Localize_mule();
439 if (old_localedef) {
440 ShowAlert(_("Your locale has been changed to System Default due to a configuration change. Sorry."), _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
442 #endif
444 // Configure EC for amuled when invoked with ec-config
445 if (ec_config) {
446 AddLogLineNS(_("\nEC configuration"));
447 thePrefs::SetECPass(GetPassword(false).Encode());
448 thePrefs::EnableExternalConnections(true);
449 AddLogLineNS(_("Password set and external connections enabled."));
452 #ifndef __WINDOWS__
453 if (getuid() == 0) {
454 wxString msg =
455 wxT("Warning! You are running aMule as root.\n")
456 wxT("Doing so is not recommended for security reasons,\n")
457 wxT("and you are advised to run aMule as an normal\n")
458 wxT("user instead.");
460 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
462 fprintf(stderr, "\n--------------------------------------------------\n");
463 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
464 fprintf(stderr, "\n--------------------------------------------------\n\n");
466 #endif
468 // Display notification on new version or first run
469 wxTextFile vfile( thePrefs::GetConfigDir() + wxT("lastversion") );
470 wxString newMule(wxT( VERSION ));
472 if ( !wxFileExists( vfile.GetName() ) ) {
473 vfile.Create();
476 if ( vfile.Open() ) {
477 // Check if this version has been run before
478 bool found = false;
479 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
480 // Check if this version has been run before
481 if ( vfile.GetLine(i) == newMule ) {
482 found = true;
483 break;
487 // We havent run this version before?
488 if ( !found ) {
489 // Insert new at top to provide faster searches
490 vfile.InsertLine( newMule, 0 );
492 Trigger_New_version( newMule );
495 // Keep at most 10 entires
496 while ( vfile.GetLineCount() > 10 )
497 vfile.RemoveLine( vfile.GetLineCount() - 1 );
499 vfile.Write();
500 vfile.Close();
503 m_statistics = new CStatistics();
505 clientlist = new CClientList();
506 friendlist = new CFriendList();
507 searchlist = new CSearchList();
508 knownfiles = new CKnownFileList();
509 canceledfiles = new CCanceledFileList;
510 serverlist = new CServerList();
512 sharedfiles = new CSharedFileList(knownfiles);
513 clientcredits = new CClientCreditsList();
515 // bugfix - do this before creating the uploadqueue
516 downloadqueue = new CDownloadQueue();
517 uploadqueue = new CUploadQueue();
518 ipfilter = new CIPFilter();
520 // Creates all needed listening sockets
521 wxString msg;
522 if (!ReinitializeNetwork(&msg)) {
523 AddLogLineNS(wxT("\n"));
524 AddLogLineNS(msg);
527 // Test if there's any new version
528 if (thePrefs::GetCheckNewVersion()) {
529 // We use the thread base because I don't want a dialog to pop up.
530 CHTTPDownloadThread* version_check =
531 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
532 thePrefs::GetConfigDir() + wxT("last_version_check"), thePrefs::GetConfigDir() + wxT("last_version"), HTTP_VersionCheck, false, false);
533 version_check->Create();
534 version_check->Run();
537 // Create main dialog, or fork to background (daemon).
538 InitGui(m_geometryEnabled, m_geometryString);
540 #ifdef AMULE_DAEMON
541 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
542 if (enable_daemon_fork) {
543 RefreshSingleInstanceChecker();
544 // No need to check IsAnotherRunning() - we've done it before.
546 #endif
548 // Has to be created after the call to InitGui, as fork
549 // (when using posix threads) only replicates the mainthread,
550 // and the UBT constructor creates a thread.
551 uploadBandwidthThrottler = new UploadBandwidthThrottler();
553 m_AsioService = new CAsioService;
556 // Start performing background tasks
557 // This will start loading the IP filter. It will start right away.
558 // Log is confusing, because log entries from background will only be printed
559 // once foreground becomes idle, and that will only be after loading
560 // of the partfiles has finished.
561 CThreadScheduler::Start();
563 // These must be initialized after the gui is loaded.
564 if (thePrefs::GetNetworkED2K()) {
565 serverlist->Init();
567 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
568 sharedfiles->Reload();
570 // Ensure that the up/down ratio is used
571 CPreferences::CheckUlDlRatio();
573 // Load saved friendlist (now, so it can update in GUI right away)
574 friendlist->LoadList();
576 // The user can start pressing buttons like mad if he feels like it.
577 m_app_state = APP_STATE_RUNNING;
579 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
580 // There are no servers and ED2K active -> ask for download.
581 // As we cannot ask in amuled, we just update there
582 #ifndef AMULE_DAEMON
583 if (wxYES == wxMessageBox(
584 wxString(
585 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
586 wxString(_("Server list download")),
587 wxYES_NO,
588 static_cast<wxWindow*>(theApp->amuledlg)))
589 #endif
591 serverlist->UpdateServerMetFromURL(thePrefs::GetEd2kServersUrl());
596 // Autoconnect if that option is enabled
597 if (thePrefs::DoAutoConnect()) {
598 // IP filter is still loading and will be finished on event.
599 // Tell it to autoconnect.
600 if (thePrefs::GetNetworkED2K()) {
601 ipfilter->ConnectToAnyServerWhenReady();
603 if (thePrefs::GetNetworkKademlia()) {
604 ipfilter->StartKADWhenReady();
608 // Enable GeoIP
609 #ifdef ENABLE_IP2COUNTRY
610 theApp->amuledlg->EnableIP2Country();
611 #endif
613 // Run webserver?
614 if (thePrefs::GetWSIsEnabled()) {
615 wxString aMuleConfigFile = thePrefs::GetConfigDir() + m_configFile;
616 wxString amulewebPath = thePrefs::GetWSPath();
618 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
619 // For the Mac GUI application, look for amuleweb in the bundle
620 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
621 CFBundleGetMainBundle(), CFSTR("amuleweb"));
623 if (amulewebUrl) {
624 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
625 CFRelease(amulewebUrl);
627 if (absoluteUrl) {
628 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
629 CFRelease(absoluteUrl);
630 #if wxCHECK_VERSION(2, 9, 0)
631 amulewebPath = wxCFStringRef(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
632 #else
633 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
634 #endif
637 #endif
639 #ifdef __WINDOWS__
640 # define QUOTE wxT("\"")
641 #else
642 # define QUOTE wxT("\'")
643 #endif
645 wxString cmd =
646 QUOTE +
647 amulewebPath +
648 QUOTE wxT(" ") QUOTE wxT("--amule-config-file=") +
649 aMuleConfigFile +
650 QUOTE;
651 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
652 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
653 bool webserver_ok = webserver_pid > 0;
654 if (webserver_ok) {
655 AddLogLineC(CFormat(_("web server running on pid %d")) % webserver_pid);
656 } else {
657 delete p;
658 ShowAlert(_(
659 "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"),
660 _("ERROR"), wxOK | wxICON_ERROR);
664 return true;
667 bool CamuleApp::ReinitializeNetwork(wxString* msg)
669 bool ok = true;
670 static bool firstTime = true;
672 if (!firstTime) {
673 // TODO: Destroy previously created sockets
675 firstTime = false;
677 // Some sanity checks first
678 if (thePrefs::ECPort() == thePrefs::GetPort()) {
679 // Select a random usable port in the range 1025 ... 2^16 - 1
680 uint16 port = thePrefs::ECPort();
681 while ( port < 1024 || port == thePrefs::GetPort() ) {
682 port = (uint16)rand();
684 thePrefs::SetECPort( port );
686 wxString err =
687 wxT("Network configuration failed! You cannot use the same port\n")
688 wxT("for the main TCP port and the External Connections port.\n")
689 wxT("The EC port has been changed to avoid conflict, see the\n")
690 wxT("preferences for the new value.\n");
691 *msg << err;
693 AddLogLineN(wxEmptyString );
694 AddLogLineC(err );
695 AddLogLineN(wxEmptyString );
697 ok = false;
700 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
701 // Select a random usable value in the range 1025 ... 2^16 - 1
702 uint16 port = thePrefs::GetUDPPort();
703 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
704 port = (uint16)rand();
706 thePrefs::SetUDPPort( port );
708 wxString err =
709 wxT("Network configuration failed! You set your UDP port to\n")
710 wxT("the value of the main TCP port plus 3.\n")
711 wxT("This port has been reserved for the Server-UDP port. The\n")
712 wxT("port value has been changed to avoid conflict, see the\n")
713 wxT("preferences for the new value\n");
714 *msg << err;
716 AddLogLineN(wxEmptyString );
717 AddLogLineC(err );
718 AddLogLineN(wxEmptyString );
720 ok = false;
723 // Create the address where we are going to listen
724 // TODO: read this from configuration file
725 amuleIPV4Address myaddr[4];
727 // Create the External Connections Socket.
728 // Default is 4712.
729 // Get ready to handle connections from apps like amulecmd
730 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
731 myaddr[0].AnyAddress();
733 myaddr[0].Service(thePrefs::ECPort());
734 ECServerHandler = new ExternalConn(myaddr[0], msg);
736 // Create the UDP socket TCP+3.
737 // Used for source asking on servers.
738 if (thePrefs::GetAddress().IsEmpty()) {
739 myaddr[1].AnyAddress();
740 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
741 myaddr[1].AnyAddress();
742 AddLogLineC(CFormat(_("Could not bind ports to the specified address: %s"))
743 % thePrefs::GetAddress());
746 wxString ip = myaddr[1].IPAddress();
747 myaddr[1].Service(thePrefs::GetPort()+3);
748 serverconnect = new CServerConnect(serverlist, myaddr[1]);
749 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
750 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
752 // Create the ListenSocket (aMule TCP socket).
753 // Used for Client Port / Connections from other clients,
754 // Client to Client Source Exchange.
755 // Default is 4662.
756 myaddr[2] = myaddr[1];
757 myaddr[2].Service(thePrefs::GetPort());
758 listensocket = new CListenSocket(myaddr[2]);
759 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
760 % ip % (unsigned int)(thePrefs::GetPort());
761 // Notify(true) has already been called to the ListenSocket, so events may
762 // be already comming in.
763 if (!listensocket->IsOk()) {
764 // If we wern't able to start listening, we need to warn the user
765 wxString err;
766 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
767 (unsigned int)(thePrefs::GetPort());
768 *msg << err;
769 AddLogLineC(err);
770 err.Clear();
771 err = CFormat(
772 _("Port %u is not available!\n\nThis means that you will be LOWID.\n\nCheck your network to make sure the port is open for output and input.")) %
773 (unsigned int)(thePrefs::GetPort());
774 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
777 // Create the UDP socket.
778 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
779 // Also used for Kademlia.
780 // Default is port 4672.
781 myaddr[3] = myaddr[1];
782 myaddr[3].Service(thePrefs::GetUDPPort());
783 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
784 if (!thePrefs::IsUDPDisabled()) {
785 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
786 % ip % thePrefs::GetUDPPort();
787 } else {
788 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
791 #ifdef ENABLE_UPNP
792 if (thePrefs::GetUPnPEnabled()) {
793 try {
794 m_upnpMappings[0] = CUPnPPortMapping(
795 myaddr[0].Service(),
796 "TCP",
797 thePrefs::GetUPnPECEnabled(),
798 "aMule TCP External Connections Socket");
799 m_upnpMappings[1] = CUPnPPortMapping(
800 myaddr[1].Service(),
801 "UDP",
802 thePrefs::GetUPnPEnabled(),
803 "aMule UDP socket (TCP+3)");
804 m_upnpMappings[2] = CUPnPPortMapping(
805 myaddr[2].Service(),
806 "TCP",
807 thePrefs::GetUPnPEnabled(),
808 "aMule TCP Listen Socket");
809 m_upnpMappings[3] = CUPnPPortMapping(
810 myaddr[3].Service(),
811 "UDP",
812 thePrefs::GetUPnPEnabled(),
813 "aMule UDP Extended eMule Socket");
814 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
815 m_upnp->AddPortMappings(m_upnpMappings);
816 } catch(CUPnPException &e) {
817 wxString error_msg;
818 error_msg << e.what();
819 AddLogLineC(error_msg);
820 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
823 #endif
825 return ok;
828 /* Original implementation by Bouc7 of the eMule Project.
829 aMule Signature idea was designed by BigBob and implemented
830 by Un-Thesis, with design inputs and suggestions from bothie.
832 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
834 // Do not do anything if online signature is disabled in Preferences
835 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
836 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
837 // that means m_amulesig_path is empty too.
838 return;
841 // Remove old signature files
842 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
843 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
846 wxTextFile amulesig_out;
847 wxTextFile emulesig_out;
849 // Open both files if needed
850 if ( !emulesig_out.Create( m_emulesig_path) ) {
851 AddLogLineC(_("Failed to create OnlineSig File"));
852 // Will never try again.
853 m_amulesig_path.Clear();
854 m_emulesig_path.Clear();
855 return;
858 if ( !amulesig_out.Create(m_amulesig_path) ) {
859 AddLogLineC(_("Failed to create aMule OnlineSig File"));
860 // Will never try again.
861 m_amulesig_path.Clear();
862 m_emulesig_path.Clear();
863 return;
866 wxString emulesig_string;
867 wxString temp;
869 if (zero) {
870 emulesig_string = wxT("0\xA0.0|0.0|0");
871 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
872 } else {
873 if (IsConnectedED2K()) {
875 temp = CFormat(wxT("%d")) % serverconnect->GetCurrentServer()->GetPort();
877 // We are online
878 emulesig_string =
879 // Connected
880 wxT("1|")
881 //Server name
882 + serverconnect->GetCurrentServer()->GetListName()
883 + wxT("|")
884 // IP and port of the server
885 + serverconnect->GetCurrentServer()->GetFullIP()
886 + wxT("|")
887 + temp;
890 // Now for amule sig
892 // Connected. State 1, full info
893 amulesig_out.AddLine(wxT("1"));
894 // Server Name
895 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
896 // Server IP
897 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
898 // Server Port
899 amulesig_out.AddLine(temp);
901 if (serverconnect->IsLowID()) {
902 amulesig_out.AddLine(wxT("L"));
903 } else {
904 amulesig_out.AddLine(wxT("H"));
907 } else if (serverconnect->IsConnecting()) {
908 emulesig_string = wxT("0");
910 // Connecting. State 2, No info.
911 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
912 } else {
913 // Not connected to a server
914 emulesig_string = wxT("0");
916 // Not connected, state 0, no info
917 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
919 if (IsConnectedKad()) {
920 if(Kademlia::CKademlia::IsFirewalled()) {
921 // Connected. Firewalled. State 1.
922 amulesig_out.AddLine(wxT("1"));
923 } else {
924 // Connected. State 2.
925 amulesig_out.AddLine(wxT("2"));
927 } else {
928 // Not connected.State 0.
929 amulesig_out.AddLine(wxT("0"));
931 emulesig_string += wxT("\xA");
933 // Datarate for downloads
934 temp = CFormat(wxT("%.1f")) % (theStats::GetDownloadRate() / 1024.0);
936 emulesig_string += temp + wxT("|");
937 amulesig_out.AddLine(temp);
939 // Datarate for uploads
940 temp = CFormat(wxT("%.1f")) % (theStats::GetUploadRate() / 1024.0);
942 emulesig_string += temp + wxT("|");
943 amulesig_out.AddLine(temp);
945 // Number of users waiting for upload
946 temp = CFormat(wxT("%d")) % theStats::GetWaitingUserCount();
948 emulesig_string += temp;
949 amulesig_out.AddLine(temp);
951 // Number of shared files (not on eMule)
952 amulesig_out.AddLine(CFormat(wxT("%d")) % theStats::GetSharedFileCount());
955 // eMule signature finished here. Write the line to the wxTextFile.
956 emulesig_out.AddLine(emulesig_string);
958 // Now for aMule signature extras
960 // Nick on the network
961 amulesig_out.AddLine(thePrefs::GetUserNick());
963 // Total received in bytes
964 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalReceivedBytes());
966 // Total sent in bytes
967 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalSentBytes());
969 // amule version
970 #ifdef SVNDATE
971 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
972 #else
973 amulesig_out.AddLine(wxT(VERSION));
974 #endif
976 if (zero) {
977 amulesig_out.AddLine(wxT("0"));
978 amulesig_out.AddLine(wxT("0"));
979 amulesig_out.AddLine(wxT("0"));
980 } else {
981 // Total received bytes in session
982 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
983 theStats::GetSessionReceivedBytes() );
985 // Total sent bytes in session
986 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
987 theStats::GetSessionSentBytes() );
989 // Uptime
990 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
993 // Flush the files
994 emulesig_out.Write();
995 amulesig_out.Write();
996 } //End Added By Bouc7
999 #if wxUSE_ON_FATAL_EXCEPTION
1000 // Gracefully handle fatal exceptions and print backtrace if possible
1001 void CamuleApp::OnFatalException()
1003 /* Print the backtrace */
1004 wxString msg;
1005 msg << wxT("\n--------------------------------------------------------------------------------\n")
1006 << wxT("A fatal error has occurred and aMule has crashed.\n")
1007 << wxT("Please assist us in fixing this problem by posting the backtrace below in our\n")
1008 << wxT("'aMule Crashes' forum and include as much information as possible regarding the\n")
1009 << wxT("circumstances of this crash. The forum is located here:\n")
1010 << wxT(" http://forum.amule.org/index.php?board=67.0\n")
1011 << wxT("If possible, please try to generate a real backtrace of this crash:\n")
1012 << wxT(" http://wiki.amule.org/wiki/Backtraces\n\n")
1013 << wxT("----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n")
1014 << wxT("Current version is: ") << FullMuleVersion
1015 << wxT("\nRunning on: ") << OSDescription
1016 << wxT("\n\n")
1017 << get_backtrace(1) // 1 == skip this function.
1018 << wxT("\n--------------------------------------------------------------------------------\n");
1020 theLogger.EmergencyLog(msg, true);
1022 #endif
1025 // Sets the localization of aMule
1026 void CamuleApp::Localize_mule()
1028 InitCustomLanguages();
1029 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1030 if (!m_locale.IsOk()) {
1031 AddLogLineN(_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1036 // Displays information related to important changes in aMule.
1037 // Is called when the user runs a new version of aMule
1038 void CamuleApp::Trigger_New_version(wxString new_version)
1040 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1041 if (new_version == wxT("SVN")) {
1042 info += _("This version is a testing version, updated daily, and\n");
1043 info += _("we give no warranty it won't break anything, burn your house,\n");
1044 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1047 // General info
1048 info += wxT("\n");
1049 info += _("More information, support and new releases can found at our homepage,\n");
1050 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1051 info += wxT("\n");
1052 info += _("Feel free to report any bugs to http://forum.amule.org");
1054 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1058 void CamuleApp::SetOSFiles(const wxString& new_path)
1060 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1061 if ( ::wxDirExists(new_path) ) {
1062 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1063 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1064 } else {
1065 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);
1066 m_emulesig_path.Clear();
1067 m_amulesig_path.Clear();
1069 } else {
1070 m_emulesig_path.Clear();
1071 m_amulesig_path.Clear();
1076 #ifdef __WXDEBUG__
1077 #ifndef wxUSE_STACKWALKER
1078 #define wxUSE_STACKWALKER 0
1079 #endif
1080 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1081 const wxChar* func, const wxChar* cond, const wxChar* msg)
1083 wxString errmsg = CFormat( wxT("Assertion failed: %s:%s:%d: Assertion '%s' failed. %s\nBacktrace follows:\n%s\n") )
1084 % file % func % line % cond % ( msg ? msg : wxT("") )
1085 % get_backtrace(2); // Skip the function-calls directly related to the assert call.
1086 theLogger.EmergencyLog(errmsg, false);
1088 if (wxThread::IsMain() && IsRunning()) {
1089 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1090 } else {
1091 #ifdef _MSC_VER
1092 wxString s = CFormat(wxT("%s in %s")) % cond % func;
1093 if (msg) {
1094 s << wxT(" : ") << msg;
1096 _wassert(s.wc_str(), file, line);
1097 #else
1098 // Abort, allows gdb to catch the assertion
1099 raise( SIGABRT );
1100 #endif
1103 #endif
1106 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1108 CServerUDPSocket* socket =reinterpret_cast<CServerUDPSocket*>(evt.GetClientData());
1109 socket->OnHostnameResolved(evt.GetExtraLong());
1113 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1115 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1119 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1121 AddLogLineNS(_("Server hostname notified"));
1122 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1126 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1128 if(!IsRunning()) {
1129 return;
1131 serverconnect->StopConnectionTry();
1132 if (IsConnectedED2K() ) {
1133 return;
1135 serverconnect->ConnectToAnyServer();
1139 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1141 // Former TimerProc section
1142 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1143 uint64 msCur = theStats::GetUptimeMillis();
1144 TheTime = msCur / 1000;
1146 if (!IsRunning()) {
1147 return;
1150 #ifndef AMULE_DAEMON
1151 // Check if we should terminate the app
1152 if ( g_shutdownSignal ) {
1153 wxWindow* top = GetTopWindow();
1155 if ( top ) {
1156 top->Close(true);
1157 } else {
1158 // No top-window, have to force termination.
1159 wxExit();
1162 #endif
1164 // There is a theoretical chance that the core time function can recurse:
1165 // if an event function gets blocked on a mutex (communicating with the
1166 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1167 // If CPU load gets high a new core timer event could be generated before the last
1168 // one was finished and so recursion could occur, which would be bad.
1169 // Detect this and do an early return then.
1170 static bool recurse = false;
1171 if (recurse) {
1172 return;
1174 recurse = true;
1176 uploadqueue->Process();
1177 downloadqueue->Process();
1178 //theApp->clientcredits->Process();
1179 theStats::CalculateRates();
1181 if (msCur-msPrevHist > 1000) {
1182 // unlike the other loop counters in this function this one will sometimes
1183 // produce two calls in quick succession (if there was a gap of more than one
1184 // second between calls to TimerProc) - this is intentional! This way the
1185 // history list keeps an average of one node per second and gets thinned out
1186 // correctly as time progresses.
1187 msPrevHist += 1000;
1189 m_statistics->RecordHistory();
1194 if (msCur-msPrev1 > 1000) { // approximately every second
1195 msPrev1 = msCur;
1196 clientcredits->Process();
1197 clientlist->Process();
1199 // Publish files to server if needed.
1200 sharedfiles->Process();
1202 if( Kademlia::CKademlia::IsRunning() ) {
1203 Kademlia::CKademlia::Process();
1204 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1205 StopKad();
1206 clientudp->Close();
1207 clientudp->Open();
1208 if (thePrefs::Reconnect()) {
1209 StartKad();
1214 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1215 serverconnect->TryAnotherConnectionrequest();
1217 if (serverconnect->IsConnecting()) {
1218 serverconnect->CheckForTimeout();
1220 listensocket->UpdateConnectionsStatus();
1225 if (msCur-msPrev5 > 5000) { // every 5 seconds
1226 msPrev5 = msCur;
1227 listensocket->Process();
1230 if (msCur-msPrevSave >= 60000) {
1231 msPrevSave = msCur;
1232 theStats::Save();
1235 // Special
1236 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1237 OnlineSig(); // Added By Bouc7
1238 msPrevOS = msCur;
1241 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1242 // Save Shared Files data
1243 knownfiles->Save();
1244 msPrevKnownMet = msCur;
1248 // Recomended by lugdunummaster himself - from emule 0.30c
1249 serverconnect->KeepConnectionAlive();
1251 // Disarm recursion protection
1252 recurse = false;
1256 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1258 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1260 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1261 CKnownFile* result = evt.GetResult();
1263 if (owner) {
1264 // Check if the partfile still exists, as it might have
1265 // been deleted in the mean time.
1266 if (downloadqueue->IsPartFile(owner)) {
1267 // This cast must not be done before the IsPartFile
1268 // call, as dynamic_cast will barf on dangling pointers.
1269 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1271 } else {
1272 static uint64 bytecount = 0;
1274 if (knownfiles->SafeAddKFile(result, true)) {
1275 AddDebugLogLineN(logKnownFiles,
1276 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1277 sharedfiles->SafeAddKFile(result);
1279 bytecount += result->GetFileSize();
1280 // If we have added files with a total size of ~3000mb
1281 if (bytecount >= wxULL(3145728000)) {
1282 AddDebugLogLineN(logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1283 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1284 knownfiles->Save();
1285 bytecount = 0;
1288 } else {
1289 AddDebugLogLineN(logKnownFiles,
1290 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1291 delete result;
1297 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1299 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1301 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1302 CScopedPtr<CKnownFile> result(evt.GetResult());
1304 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1305 CAICHHashSet* oldSet = owner->GetAICHHashset();
1306 CAICHHashSet* newSet = result->GetAICHHashset();
1308 owner->SetAICHHashset(newSet);
1309 newSet->SetOwner(owner);
1311 result->SetAICHHashset(oldSet);
1312 oldSet->SetOwner(result.get());
1317 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1319 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1320 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1321 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1323 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1324 if (evt.ErrorOccured()) {
1325 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1328 // Check if we should execute an script/app/whatever.
1329 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1332 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1334 CPartFile *file = evt.GetFile();
1335 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1336 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1338 file->SetStatus(PS_EMPTY);
1340 if (evt.Succeeded()) {
1341 if (evt.IsPaused()) {
1342 file->StopFile();
1343 } else {
1344 file->ResumeFile();
1346 } else {
1347 AddLogLineN(CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1348 file->StopFile();
1351 file->AllocationFinished();
1354 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1356 #ifdef AMULE_DAEMON
1357 evt.Notify();
1358 #else
1359 if (theApp->amuledlg) {
1360 evt.Notify();
1362 #endif
1366 void CamuleApp::ShutDown()
1368 // Just in case
1369 PlatformSpecific::AllowSleepMode();
1371 // Log
1372 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has started."));
1374 // Signal the hashing thread to terminate
1375 m_app_state = APP_STATE_SHUTTINGDOWN;
1377 // Stop ASIO thread
1378 #ifdef ASIO_SOCKETS // only needed to suppress the log message in non-Asio build
1379 AddDebugLogLineN(logGeneral, wxT("Terminate ASIO thread."));
1380 m_AsioService->Stop();
1381 #endif
1383 StopKad();
1385 // Kry - Save the sources seeds on app exit
1386 if (thePrefs::GetSrcSeedsOn()) {
1387 downloadqueue->SaveSourceSeeds();
1390 OnlineSig(true); // Added By Bouc7
1392 // Exit HTTP downloads
1393 CHTTPDownloadThread::StopAll();
1395 // Exit thread scheduler and upload thread
1396 CThreadScheduler::Terminate();
1398 AddDebugLogLineN(logGeneral, wxT("Terminate upload thread."));
1399 uploadBandwidthThrottler->EndThread();
1401 // Close sockets to avoid new clients coming in
1402 if (listensocket) {
1403 listensocket->Close();
1404 listensocket->KillAllSockets();
1407 if (serverconnect) {
1408 serverconnect->Disconnect();
1411 ECServerHandler->KillAllSockets();
1413 #ifdef ENABLE_UPNP
1414 if (thePrefs::GetUPnPEnabled()) {
1415 if (m_upnp) {
1416 m_upnp->DeletePortMappings(m_upnpMappings);
1419 #endif
1421 // saving data & stuff
1422 if (knownfiles) {
1423 knownfiles->Save();
1426 theStats::Save();
1428 CPath configFileName = CPath(thePrefs::GetConfigDir() + m_configFile);
1429 CPath::BackupFile(configFileName, wxT(".bak"));
1431 if (clientlist) {
1432 clientlist->DeleteAll();
1435 // Log
1436 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1440 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1442 if ( serverlist->AddServer(srv, fromUser) ) {
1443 Notify_ServerAdd(srv);
1444 return true;
1446 return false;
1450 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1452 if (m_dwPublicIP == 0) {
1453 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1454 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1455 } else {
1456 return ignorelocal ? 0 : m_localip;
1460 return m_dwPublicIP;
1464 void CamuleApp::SetPublicIP(const uint32 dwIP)
1466 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1468 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1469 m_dwPublicIP = dwIP;
1470 serverlist->CheckForExpiredUDPKeys();
1471 } else {
1472 m_dwPublicIP = dwIP;
1477 wxString CamuleApp::GetLog(bool reset)
1479 wxFile logfile;
1480 logfile.Open(thePrefs::GetConfigDir() + wxT("logfile"));
1481 if ( !logfile.IsOpened() ) {
1482 return _("ERROR: can't open logfile");
1484 int len = logfile.Length();
1485 if ( len == 0 ) {
1486 return _("WARNING: logfile is empty. Something is wrong.");
1488 char *tmp_buffer = new char[len + sizeof(wxChar)];
1489 logfile.Read(tmp_buffer, len);
1490 memset(tmp_buffer + len, 0, sizeof(wxChar));
1492 // try to guess file format
1493 wxString str;
1494 if (tmp_buffer[0] && tmp_buffer[1]) {
1495 str = wxString(UTF82unicode(tmp_buffer));
1496 } else {
1497 str = wxWCharBuffer((wchar_t *)tmp_buffer);
1500 delete [] tmp_buffer;
1501 if ( reset ) {
1502 theLogger.CloseLogfile();
1503 if (theLogger.OpenLogfile(thePrefs::GetConfigDir() + wxT("logfile"))) {
1504 AddLogLineN(_("Log has been reset"));
1506 ECServerHandler->ResetAllLogs();
1508 return str;
1512 wxString CamuleApp::GetServerLog(bool reset)
1514 wxString ret = server_msg;
1515 if ( reset ) {
1516 server_msg.Clear();
1518 return ret;
1521 wxString CamuleApp::GetDebugLog(bool reset)
1523 return GetLog(reset);
1527 void CamuleApp::AddServerMessageLine(wxString &msg)
1529 server_msg += msg + wxT("\n");
1530 AddLogLineN(CFormat(_("ServerMessage: %s")) % msg);
1535 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1537 switch (event.GetInt()) {
1538 case HTTP_IPFilter:
1539 ipfilter->DownloadFinished(event.GetExtraLong());
1540 break;
1541 case HTTP_ServerMet:
1542 if (serverlist->DownloadFinished(event.GetExtraLong()) && !IsConnectedED2K()) {
1543 // If successfully downloaded a server list, and are not connected at the moment, try to connect.
1544 // This happens when no server met is available on startup.
1545 serverconnect->ConnectToAnyServer();
1547 break;
1548 case HTTP_ServerMetAuto:
1549 serverlist->AutoDownloadFinished(event.GetExtraLong());
1550 break;
1551 case HTTP_VersionCheck:
1552 CheckNewVersion(event.GetExtraLong());
1553 break;
1554 case HTTP_NodesDat:
1555 if (event.GetExtraLong() == HTTP_Success) {
1557 wxString file = thePrefs::GetConfigDir() + wxT("nodes.dat");
1558 if (wxFileExists(file)) {
1559 wxRemoveFile(file);
1562 if ( Kademlia::CKademlia::IsRunning() ) {
1563 Kademlia::CKademlia::Stop();
1566 wxRenameFile(file + wxT(".download"),file);
1568 Kademlia::CKademlia::Start();
1569 theApp->ShowConnectionState();
1570 // cppcheck-suppress duplicateBranch
1571 } else if (event.GetExtraLong() == HTTP_Skipped) {
1572 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1573 } else {
1574 AddLogLineC(_("Failed to download the nodes list."));
1576 break;
1577 #ifdef ENABLE_IP2COUNTRY
1578 case HTTP_GeoIP:
1579 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1580 // If we updated, the dialog is already up. Redraw it to show the flags.
1581 theApp->amuledlg->Refresh();
1582 break;
1583 #endif
1587 void CamuleApp::CheckNewVersion(uint32 result)
1589 if (result == HTTP_Success) {
1590 wxString filename = thePrefs::GetConfigDir() + wxT("last_version_check");
1591 wxTextFile file;
1593 if (!file.Open(filename)) {
1594 AddLogLineC(_("Failed to open the downloaded version check file") );
1595 return;
1596 } else if (!file.GetLineCount()) {
1597 AddLogLineC(_("Corrupted version check file"));
1598 } else {
1599 wxString versionLine = file.GetFirstLine();
1600 wxStringTokenizer tkz(versionLine, wxT("."));
1602 AddDebugLogLineN(logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1604 long fields[] = {0, 0, 0};
1605 for (int i = 0; i < 3; ++i) {
1606 if (!tkz.HasMoreTokens()) {
1607 AddLogLineC(_("Corrupted version check file"));
1608 return;
1609 } else {
1610 wxString token = tkz.GetNextToken();
1612 if (!token.ToLong(&fields[i])) {
1613 AddLogLineC(_("Corrupted version check file"));
1614 return;
1619 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1620 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1622 if (curVer < newVer) {
1623 AddLogLineC(_("You are using an outdated version of aMule!"));
1624 // cppcheck-suppress zerodiv
1625 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]);
1626 AddLogLineN(_("The latest version can always be found at http://www.amule.org"));
1627 #ifdef AMULE_DAEMON
1628 AddLogLineCS(CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1629 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1630 #endif
1631 } else {
1632 AddLogLineN(_("Your copy of aMule is up to date."));
1636 file.Close();
1637 wxRemoveFile(filename);
1638 } else {
1639 AddLogLineC(_("Failed to download the version check file"));
1645 bool CamuleApp::IsConnected() const
1647 return (IsConnectedED2K() || IsConnectedKad());
1651 bool CamuleApp::IsConnectedED2K() const
1653 return serverconnect && serverconnect->IsConnected();
1657 bool CamuleApp::IsConnectedKad() const
1659 return Kademlia::CKademlia::IsConnected();
1663 bool CamuleApp::IsFirewalled() const
1665 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1666 return false; // we have an eD2K HighID -> not firewalled
1669 return IsFirewalledKad(); // If kad says ok, it's ok.
1672 bool CamuleApp::IsFirewalledKad() const
1674 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1675 || Kademlia::CKademlia::IsFirewalled();
1678 bool CamuleApp::IsFirewalledKadUDP() const
1680 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1681 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1684 bool CamuleApp::IsKadRunning() const
1686 return Kademlia::CKademlia::IsRunning();
1689 bool CamuleApp::IsKadRunningInLanMode() const
1691 return Kademlia::CKademlia::IsRunningInLANMode();
1694 // Kad stats
1695 uint32 CamuleApp::GetKadUsers() const
1697 return Kademlia::CKademlia::GetKademliaUsers();
1700 uint32 CamuleApp::GetKadFiles() const
1702 return Kademlia::CKademlia::GetKademliaFiles();
1705 uint32 CamuleApp::GetKadIndexedSources() const
1707 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1710 uint32 CamuleApp::GetKadIndexedKeywords() const
1712 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1715 uint32 CamuleApp::GetKadIndexedNotes() const
1717 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1720 uint32 CamuleApp::GetKadIndexedLoad() const
1722 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1726 // True IP of machine
1727 uint32 CamuleApp::GetKadIPAdress() const
1729 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1732 // Buddy status
1733 uint8 CamuleApp::GetBuddyStatus() const
1735 return clientlist->GetBuddyStatus();
1738 uint32 CamuleApp::GetBuddyIP() const
1740 return clientlist->GetBuddyIP();
1743 uint32 CamuleApp::GetBuddyPort() const
1745 return clientlist->GetBuddyPort();
1748 bool CamuleApp::CanDoCallback(uint32 clientServerIP, uint16 clientServerPort)
1750 if (Kademlia::CKademlia::IsConnected()) {
1751 if (IsConnectedED2K()) {
1752 if (serverconnect->IsLowID()) {
1753 if (Kademlia::CKademlia::IsFirewalled()) {
1754 //Both Connected - Both Firewalled
1755 return false;
1756 } else {
1757 if (clientServerIP == theApp->serverconnect->GetCurrentServer()->GetIP() &&
1758 clientServerPort == theApp->serverconnect->GetCurrentServer()->GetPort()) {
1759 // Both Connected - Server lowID, Kad Open - Client on same server
1760 // We prevent a callback to the server as this breaks the protocol
1761 // and will get you banned.
1762 return false;
1763 } else {
1764 // Both Connected - Server lowID, Kad Open - Client on remote server
1765 return true;
1768 } else {
1769 //Both Connected - Server HighID, Kad don't care
1770 return true;
1772 } else {
1773 if (Kademlia::CKademlia::IsFirewalled()) {
1774 //Only Kad Connected - Kad Firewalled
1775 return false;
1776 } else {
1777 //Only Kad Conected - Kad Open
1778 return true;
1781 } else {
1782 if (IsConnectedED2K()) {
1783 if (serverconnect->IsLowID()) {
1784 //Only Server Connected - Server LowID
1785 return false;
1786 } else {
1787 //Only Server Connected - Server HighID
1788 return true;
1790 } else {
1791 //We are not connected at all!
1792 return false;
1797 void CamuleApp::ShowUserCount() {
1798 uint32 totaluser = 0, totalfile = 0;
1800 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
1802 wxString buffer;
1804 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
1805 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
1807 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1808 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1809 } else if (thePrefs::GetNetworkED2K()) {
1810 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
1811 } else if (thePrefs::GetNetworkKademlia()) {
1812 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1813 } else {
1814 buffer = _("No networks selected");
1817 Notify_ShowUserCount(buffer);
1821 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
1823 { wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket")); }
1824 { wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
1825 wxT("Invalid event received for listen-socket")); }
1827 if (m_app_state == APP_STATE_RUNNING) {
1828 listensocket->OnAccept();
1829 } else if (m_app_state == APP_STATE_STARTING) {
1830 // When starting up, connection may be made before we are able
1831 // to handle them. However, if these are ignored, no futher
1832 // connection-events will be triggered, so we have to accept it.
1833 CLibSocket* socket = listensocket->Accept(false);
1835 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
1837 socket->Destroy();
1842 void CamuleApp::ShowConnectionState(bool forceUpdate)
1844 static uint8 old_state = (1<<7); // This flag doesn't exist
1846 uint8 state = 0;
1848 if (theApp->serverconnect->IsConnected()) {
1849 state |= CONNECTED_ED2K;
1852 if (Kademlia::CKademlia::IsRunning()) {
1853 if (Kademlia::CKademlia::IsConnected()) {
1854 if (!Kademlia::CKademlia::IsFirewalled()) {
1855 state |= CONNECTED_KAD_OK;
1856 } else {
1857 state |= CONNECTED_KAD_FIREWALLED;
1859 } else {
1860 state |= CONNECTED_KAD_NOT;
1864 if (old_state != state) {
1865 // Get the changed value
1866 int changed_flags = old_state ^ state;
1868 if (changed_flags & CONNECTED_ED2K) {
1869 // ED2K status changed
1870 wxString connected_server;
1871 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
1872 if (ed2k_server) {
1873 connected_server = ed2k_server->GetListName();
1875 if (state & CONNECTED_ED2K) {
1876 // We connected to some server
1877 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
1879 AddLogLineC(CFormat(_("Connected to %s %s")) % connected_server % id);
1880 } else {
1881 // cppcheck-suppress duplicateBranch
1882 if ( theApp->serverconnect->IsConnecting() ) {
1883 AddLogLineC(CFormat(_("Connecting to %s")) % connected_server);
1884 } else {
1885 AddLogLineC(_("Disconnected from eD2k"));
1890 if (changed_flags & CONNECTED_KAD_NOT) {
1891 // cppcheck-suppress duplicateBranch
1892 if (state & CONNECTED_KAD_NOT) {
1893 AddLogLineC(_("Kad started."));
1894 } else {
1895 AddLogLineC(_("Kad stopped."));
1899 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1900 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1901 // cppcheck-suppress duplicateBranch
1902 if (state & CONNECTED_KAD_OK) {
1903 AddLogLineC(_("Connected to Kad (ok)"));
1904 } else {
1905 AddLogLineC(_("Connected to Kad (firewalled)"));
1907 } else {
1908 AddLogLineC(_("Disconnected from Kad"));
1912 old_state = state;
1914 theApp->downloadqueue->OnConnectionState(IsConnected());
1917 ShowUserCount();
1918 Notify_ShowConnState(forceUpdate);
1922 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
1924 CMuleUDPSocket* socket = reinterpret_cast<CMuleUDPSocket*>(event.GetClientData());
1925 wxCHECK_RET(socket, wxT("No socket owner specified."));
1927 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1929 if (!IsRunning()) {
1930 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
1931 // Back to the queue!
1932 theApp->AddPendingEvent(event);
1933 return;
1937 switch (event.GetSocketEvent()) {
1938 case wxSOCKET_INPUT:
1939 socket->OnReceive(0);
1940 break;
1942 case wxSOCKET_OUTPUT:
1943 socket->OnSend(0);
1944 break;
1946 case wxSOCKET_LOST:
1947 socket->OnDisconnected(0);
1948 break;
1950 default:
1951 wxFAIL;
1952 break;
1957 void CamuleApp::OnUnhandledException()
1959 // Call the generic exception-handler.
1960 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1961 ::OnUnhandledException();
1964 void CamuleApp::StartKad()
1966 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1967 // Kad makes no sense without the Client-UDP socket.
1968 if (!thePrefs::IsUDPDisabled()) {
1969 if (ipfilter->IsReady()) {
1970 Kademlia::CKademlia::Start();
1971 } else {
1972 ipfilter->StartKADWhenReady();
1974 } else {
1975 AddLogLineC(_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1977 } else if (!thePrefs::GetNetworkKademlia()) {
1978 AddLogLineC(_("Kad network disabled on preferences, not connecting."));
1982 void CamuleApp::StopKad()
1984 // Stop Kad if it's running
1985 if (Kademlia::CKademlia::IsRunning()) {
1986 Kademlia::CKademlia::Stop();
1991 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
1993 if (!Kademlia::CKademlia::IsRunning()) {
1994 Kademlia::CKademlia::Start();
1995 theApp->ShowConnectionState();
1998 Kademlia::CKademlia::Bootstrap(ip, port);
2002 void CamuleApp::UpdateNotesDat(const wxString& url)
2004 wxString strTempFilename(thePrefs::GetConfigDir() + wxT("nodes.dat.download"));
2006 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, thePrefs::GetConfigDir() + wxT("nodes.dat"), HTTP_NodesDat, true, false);
2007 downloader->Create();
2008 downloader->Run();
2012 void CamuleApp::DisconnectED2K()
2014 // Stop ED2K if it's running
2015 if (IsConnectedED2K()) {
2016 serverconnect->Disconnect();
2020 bool CamuleApp::CryptoAvailable() const
2022 return clientcredits && clientcredits->CryptoAvailable();
2025 uint32 CamuleApp::GetED2KID() const {
2026 return serverconnect ? serverconnect->GetClientID() : 0;
2029 uint32 CamuleApp::GetID() const {
2030 uint32 ID;
2032 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2033 // We trust Kad above ED2K
2034 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2035 } else if( theApp->serverconnect->IsConnected() ) {
2036 ID = theApp->serverconnect->GetClientID();
2037 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2038 // A firewalled Kad client get's a "1"
2039 ID = 1;
2040 } else {
2041 ID = 0;
2044 return ID;
2047 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2048 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2049 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2050 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2051 // File_checked_for_headers