Don't check for change date when downloading latest version file
[amule.git] / src / amule.cpp
blob2db721ff6f05dc7852f8f3b944699d2ba9b95c1a
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.
20 //
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 strFullMuleVersion = NULL;
212 strOSDescription = NULL;
214 // Apprently needed for *BSD
215 SetResourceLimits();
217 #ifdef _MSC_VER
218 _CrtSetDbgFlag(0); // Disable useless memleak debugging
219 #endif
222 CamuleApp::~CamuleApp()
224 // Closing the log-file as the very last thing, since
225 // wxWidgets log-events are saved in it as well.
226 theLogger.CloseLogfile();
228 if (strFullMuleVersion) {
229 free(strFullMuleVersion);
231 if (strOSDescription) {
232 free(strOSDescription);
236 int CamuleApp::OnExit()
238 if (m_app_state!=APP_STATE_STARTING) {
239 AddLogLineNS(_("Now, exiting main app..."));
242 // From wxWidgets docs, wxConfigBase:
243 // ...
244 // Note that you must delete this object (usually in wxApp::OnExit)
245 // in order to avoid memory leaks, wxWidgets won't do it automatically.
247 // As it happens, you may even further simplify the procedure described
248 // above: you may forget about calling Set(). When Get() is called and
249 // there is no current object, it will create one using Create() function.
250 // To disable this behaviour DontCreateOnDemand() is provided.
251 delete wxConfigBase::Set((wxConfigBase *)NULL);
253 // Save credits
254 clientcredits->SaveList();
256 // Kill amuleweb if running
257 if (webserver_pid) {
258 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid '%ld' ... ")) % webserver_pid);
259 wxKillError rc;
260 if (wxKill(webserver_pid, wxSIGTERM, &rc) == -1) {
261 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid '%ld' ... ")) % webserver_pid);
262 if (wxKill(webserver_pid, wxSIGKILL, &rc) == -1) {
263 AddLogLineNS(_("Failed"));
268 if (m_app_state!=APP_STATE_STARTING) {
269 AddLogLineNS(_("aMule OnExit: Terminating core."));
272 delete serverlist;
273 serverlist = NULL;
275 delete searchlist;
276 searchlist = NULL;
278 delete clientcredits;
279 clientcredits = NULL;
281 delete friendlist;
282 friendlist = NULL;
284 // Destroying CDownloadQueue calls destructor for CPartFile
285 // calling CSharedFileList::SafeAddKFile occasionally.
286 delete sharedfiles;
287 sharedfiles = NULL;
289 delete serverconnect;
290 serverconnect = NULL;
292 delete listensocket;
293 listensocket = NULL;
295 delete clientudp;
296 clientudp = NULL;
298 delete knownfiles;
299 knownfiles = NULL;
301 delete canceledfiles;
302 canceledfiles = NULL;
304 delete clientlist;
305 clientlist = NULL;
307 delete uploadqueue;
308 uploadqueue = NULL;
310 delete downloadqueue;
311 downloadqueue = NULL;
313 delete ipfilter;
314 ipfilter = NULL;
316 #ifdef ENABLE_UPNP
317 delete m_upnp;
318 m_upnp = NULL;
319 #endif
321 delete ECServerHandler;
322 ECServerHandler = NULL;
324 delete m_statistics;
325 m_statistics = NULL;
327 delete glob_prefs;
328 glob_prefs = NULL;
329 CPreferences::EraseItemList();
331 delete uploadBandwidthThrottler;
332 uploadBandwidthThrottler = NULL;
334 if (m_app_state!=APP_STATE_STARTING) {
335 AddLogLineNS(_("aMule shutdown completed."));
338 #if wxUSE_MEMORY_TRACING
339 AddLogLineNS(_("Memory debug results for aMule exit:"));
340 // Log mem debug mesages to wxLogStderr
341 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
342 //AddLogLineNS(wxT("**************Classes**************");
343 //wxDebugContext::PrintClasses();
344 //AddLogLineNS(wxT("***************Dump***************");
345 //wxDebugContext::Dump();
346 AddLogLineNS(wxT("***************Stats**************"));
347 wxDebugContext::PrintStatistics(true);
349 // Set back to wxLogGui
350 delete wxLog::SetActiveTarget(oldLog);
351 #endif
353 StopTickTimer();
355 // Return 0 for succesful program termination
356 return AMULE_APP_BASE::OnExit();
360 int CamuleApp::InitGui(bool, wxString &)
362 return 0;
367 // Application initialization
369 bool CamuleApp::OnInit()
371 #if wxUSE_MEMORY_TRACING
372 // any text before call of Localize_mule needs not to be translated.
373 AddLogLineNS(wxT("Checkpoint set on app init for memory debug")); // debug output
374 wxDebugContext::SetCheckpoint();
375 #endif
377 // Forward wxLog events to CLogger
378 wxLog::SetActiveTarget(new CLoggerTarget);
380 m_localip = StringHosttoUint32(::wxGetFullHostName());
382 #ifndef __WXMSW__
383 // get rid of sigpipe
384 signal(SIGPIPE, SIG_IGN);
385 #else
386 // Handle CTRL-Break
387 signal(SIGBREAK, OnShutdownSignal);
388 #endif
389 // Handle sigint and sigterm
390 signal(SIGINT, OnShutdownSignal);
391 signal(SIGTERM, OnShutdownSignal);
393 #ifdef __WXMAC__
394 // For listctrl's to behave on Mac
395 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
396 #endif
398 // Handle uncaught exceptions
399 InstallMuleExceptionHandler();
401 if (!InitCommon(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv)) {
402 return false;
405 glob_prefs = new CPreferences();
407 CPath outDir;
408 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"), outDir)) {
409 thePrefs::SetTempDir(outDir);
410 } else {
411 return false;
414 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"), outDir)) {
415 thePrefs::SetIncomingDir(outDir);
416 } else {
417 return false;
420 // Some sanity check
421 if (!thePrefs::UseTrayIcon()) {
422 thePrefs::SetMinToTray(false);
425 // Build the filenames for the two OS files
426 SetOSFiles(thePrefs::GetOSDir().GetRaw());
428 #ifdef ENABLE_NLS
429 // Load localization settings
430 Localize_mule();
431 #endif
433 // Configure EC for amuled when invoked with ec-config
434 if (ec_config) {
435 AddLogLineNS(_("\nEC configuration"));
436 thePrefs::SetECPass(GetPassword());
437 thePrefs::EnableExternalConnections(true);
438 AddLogLineNS(_("Password set and external connections enabled."));
441 #ifndef __WXMSW__
442 if (getuid() == 0) {
443 wxString msg =
444 wxT("Warning! You are running aMule as root.\n")
445 wxT("Doing so is not recommended for security reasons,\n")
446 wxT("and you are advised to run aMule as an normal\n")
447 wxT("user instead.");
449 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
451 fprintf(stderr, "\n--------------------------------------------------\n");
452 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
453 fprintf(stderr, "\n--------------------------------------------------\n\n");
455 #endif
457 // Display notification on new version or first run
458 wxTextFile vfile( ConfigDir + wxT("lastversion") );
459 wxString newMule(wxT( VERSION ));
461 if ( !wxFileExists( vfile.GetName() ) ) {
462 vfile.Create();
465 if ( vfile.Open() ) {
466 // Check if this version has been run before
467 bool found = false;
468 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
469 // Check if this version has been run before
470 if ( vfile.GetLine(i) == newMule ) {
471 found = true;
472 break;
476 // We havent run this version before?
477 if ( !found ) {
478 // Insert new at top to provide faster searches
479 vfile.InsertLine( newMule, 0 );
481 Trigger_New_version( newMule );
484 // Keep at most 10 entires
485 while ( vfile.GetLineCount() > 10 )
486 vfile.RemoveLine( vfile.GetLineCount() - 1 );
488 vfile.Write();
489 vfile.Close();
492 // Check if we have the old style locale config
493 wxString langId = thePrefs::GetLanguageID();
494 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
495 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
496 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
497 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
500 m_statistics = new CStatistics();
502 clientlist = new CClientList();
503 friendlist = new CFriendList();
504 searchlist = new CSearchList();
505 knownfiles = new CKnownFileList();
506 canceledfiles = new CCanceledFileList;
507 serverlist = new CServerList();
509 sharedfiles = new CSharedFileList(knownfiles);
510 clientcredits = new CClientCreditsList();
512 // bugfix - do this before creating the uploadqueue
513 downloadqueue = new CDownloadQueue();
514 uploadqueue = new CUploadQueue();
515 ipfilter = new CIPFilter();
517 // Creates all needed listening sockets
518 wxString msg;
519 if (!ReinitializeNetwork(&msg)) {
520 AddLogLineNS(wxT("\n"));
521 AddLogLineNS(msg);
524 // Test if there's any new version
525 if (thePrefs::GetCheckNewVersion()) {
526 // We use the thread base because I don't want a dialog to pop up.
527 CHTTPDownloadThread* version_check =
528 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
529 theApp->ConfigDir + wxT("last_version_check"), theApp->ConfigDir + wxT("last_version"), HTTP_VersionCheck, false, false);
530 version_check->Create();
531 version_check->Run();
534 // Create main dialog, or fork to background (daemon).
535 InitGui(m_geometryEnabled, m_geometryString);
537 #ifdef AMULE_DAEMON
538 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
539 if (enable_daemon_fork) {
540 RefreshSingleInstanceChecker();
541 // No need to check IsAnotherRunning() - we've done it before.
543 #endif
545 // Has to be created after the call to InitGui, as fork
546 // (when using posix threads) only replicates the mainthread,
547 // and the UBT constructor creates a thread.
548 uploadBandwidthThrottler = new UploadBandwidthThrottler();
550 // Start performing background tasks
551 // This will start loading the IP filter. It will start right away.
552 // Log is confusing, because log entries from background will only be printed
553 // once foreground becomes idle, and that will only be after loading
554 // of the partfiles has finished.
555 CThreadScheduler::Start();
557 // These must be initialized after the gui is loaded.
558 if (thePrefs::GetNetworkED2K()) {
559 serverlist->Init();
561 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
562 sharedfiles->Reload();
564 // Ensure that the up/down ratio is used
565 CPreferences::CheckUlDlRatio();
567 // Load saved friendlist (now, so it can update in GUI right away)
568 friendlist->LoadList();
570 // The user can start pressing buttons like mad if he feels like it.
571 m_app_state = APP_STATE_RUNNING;
573 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
574 // There are no servers and ED2K active -> ask for download.
575 // As we cannot ask in amuled, we just update there
576 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
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 // workaround amuled crash
587 #ifndef AMULE_DAEMON
588 serverlist->UpdateServerMetFromURL(
589 wxT("http://gruk.org/server.met.gz"));
590 #endif
595 // Autoconnect if that option is enabled
596 if (thePrefs::DoAutoConnect()) {
597 // IP filter is still loading and will be finished on event.
598 // Tell it to autoconnect.
599 if (thePrefs::GetNetworkED2K()) {
600 ipfilter->ConnectToAnyServerWhenReady();
602 if (thePrefs::GetNetworkKademlia()) {
603 ipfilter->StartKADWhenReady();
607 // Enable GeoIP
608 #ifdef ENABLE_IP2COUNTRY
609 theApp->amuledlg->EnableIP2Country();
610 #endif
612 // Run webserver?
613 if (thePrefs::GetWSIsEnabled()) {
614 wxString aMuleConfigFile = ConfigDir + m_configFile;
615 wxString amulewebPath = thePrefs::GetWSPath();
617 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
618 // For the Mac GUI application, look for amuleweb in the bundle
619 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
620 CFBundleGetMainBundle(), CFSTR("amuleweb"));
622 if (amulewebUrl) {
623 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
624 CFRelease(amulewebUrl);
626 if (absoluteUrl) {
627 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
628 CFRelease(absoluteUrl);
629 #if wxCHECK_VERSION(2, 9, 0)
630 amulewebPath = wxCFStringRef(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
631 #else
632 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
633 #endif
636 #endif
638 #ifdef __WXMSW__
639 # define QUOTE wxT("\"")
640 #else
641 # define QUOTE wxT("\'")
642 #endif
644 wxString cmd =
645 QUOTE +
646 amulewebPath +
647 QUOTE wxT(" ") QUOTE wxT("--amule-config-file=") +
648 aMuleConfigFile +
649 QUOTE;
650 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
651 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
652 bool webserver_ok = webserver_pid > 0;
653 if (webserver_ok) {
654 AddLogLineC(CFormat(_("web server running on pid %d")) % webserver_pid);
655 } else {
656 delete p;
657 ShowAlert(_(
658 "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"),
659 _("ERROR"), wxOK | wxICON_ERROR);
663 return true;
666 bool CamuleApp::ReinitializeNetwork(wxString* msg)
668 bool ok = true;
669 static bool firstTime = true;
671 if (!firstTime) {
672 // TODO: Destroy previously created sockets
674 firstTime = false;
676 // Some sanity checks first
677 if (thePrefs::ECPort() == thePrefs::GetPort()) {
678 // Select a random usable port in the range 1025 ... 2^16 - 1
679 uint16 port = thePrefs::ECPort();
680 while ( port < 1024 || port == thePrefs::GetPort() ) {
681 port = (uint16)rand();
683 thePrefs::SetECPort( port );
685 wxString err =
686 wxT("Network configuration failed! You cannot use the same port\n")
687 wxT("for the main TCP port and the External Connections port.\n")
688 wxT("The EC port has been changed to avoid conflict, see the\n")
689 wxT("preferences for the new value.\n");
690 *msg << err;
692 AddLogLineN(wxEmptyString );
693 AddLogLineC(err );
694 AddLogLineN(wxEmptyString );
696 ok = false;
699 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
700 // Select a random usable value in the range 1025 ... 2^16 - 1
701 uint16 port = thePrefs::GetUDPPort();
702 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
703 port = (uint16)rand();
705 thePrefs::SetUDPPort( port );
707 wxString err =
708 wxT("Network configuration failed! You set your UDP port to\n")
709 wxT("the value of the main TCP port plus 3.\n")
710 wxT("This port has been reserved for the Server-UDP port. The\n")
711 wxT("port value has been changed to avoid conflict, see the\n")
712 wxT("preferences for the new value\n");
713 *msg << err;
715 AddLogLineN(wxEmptyString );
716 AddLogLineC(err );
717 AddLogLineN(wxEmptyString );
719 ok = false;
722 // Create the address where we are going to listen
723 // TODO: read this from configuration file
724 amuleIPV4Address myaddr[4];
726 // Create the External Connections Socket.
727 // Default is 4712.
728 // Get ready to handle connections from apps like amulecmd
729 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
730 myaddr[0].AnyAddress();
732 myaddr[0].Service(thePrefs::ECPort());
733 ECServerHandler = new ExternalConn(myaddr[0], msg);
735 // Create the UDP socket TCP+3.
736 // Used for source asking on servers.
737 if (thePrefs::GetAddress().IsEmpty()) {
738 myaddr[1].AnyAddress();
739 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
740 myaddr[1].AnyAddress();
741 AddLogLineC(CFormat(_("Could not bind ports to the specified address: %s"))
742 % thePrefs::GetAddress());
745 wxString ip = myaddr[1].IPAddress();
746 myaddr[1].Service(thePrefs::GetPort()+3);
747 serverconnect = new CServerConnect(serverlist, myaddr[1]);
748 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
749 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
751 // Create the ListenSocket (aMule TCP socket).
752 // Used for Client Port / Connections from other clients,
753 // Client to Client Source Exchange.
754 // Default is 4662.
755 myaddr[2] = myaddr[1];
756 myaddr[2].Service(thePrefs::GetPort());
757 listensocket = new CListenSocket(myaddr[2]);
758 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
759 % ip % (unsigned int)(thePrefs::GetPort());
760 // This command just sets a flag to control maximum number of connections.
761 // Notify(true) has already been called to the ListenSocket, so events may
762 // be already comming in.
763 if (listensocket->Ok()) {
764 listensocket->StartListening();
765 } else {
766 // If we wern't able to start listening, we need to warn the user
767 wxString err;
768 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
769 (unsigned int)(thePrefs::GetPort());
770 *msg << err;
771 AddLogLineC(err);
772 err.Clear();
773 err = CFormat(
774 _("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.")) %
775 (unsigned int)(thePrefs::GetPort());
776 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
779 // Create the UDP socket.
780 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
781 // Also used for Kademlia.
782 // Default is port 4672.
783 myaddr[3] = myaddr[1];
784 myaddr[3].Service(thePrefs::GetUDPPort());
785 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
786 if (!thePrefs::IsUDPDisabled()) {
787 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
788 % ip % thePrefs::GetUDPPort();
789 } else {
790 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
793 #ifdef ENABLE_UPNP
794 if (thePrefs::GetUPnPEnabled()) {
795 try {
796 m_upnpMappings[0] = CUPnPPortMapping(
797 myaddr[0].Service(),
798 "TCP",
799 thePrefs::GetUPnPECEnabled(),
800 "aMule TCP External Connections Socket");
801 m_upnpMappings[1] = CUPnPPortMapping(
802 myaddr[1].Service(),
803 "UDP",
804 thePrefs::GetUPnPEnabled(),
805 "aMule UDP socket (TCP+3)");
806 m_upnpMappings[2] = CUPnPPortMapping(
807 myaddr[2].Service(),
808 "TCP",
809 thePrefs::GetUPnPEnabled(),
810 "aMule TCP Listen Socket");
811 m_upnpMappings[3] = CUPnPPortMapping(
812 myaddr[3].Service(),
813 "UDP",
814 thePrefs::GetUPnPEnabled(),
815 "aMule UDP Extended eMule Socket");
816 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
817 m_upnp->AddPortMappings(m_upnpMappings);
818 } catch(CUPnPException &e) {
819 wxString error_msg;
820 error_msg << e.what();
821 AddLogLineC(error_msg);
822 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
825 #endif
827 return ok;
830 /* Original implementation by Bouc7 of the eMule Project.
831 aMule Signature idea was designed by BigBob and implemented
832 by Un-Thesis, with design inputs and suggestions from bothie.
834 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
836 // Do not do anything if online signature is disabled in Preferences
837 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
838 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
839 // that means m_amulesig_path is empty too.
840 return;
843 // Remove old signature files
844 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
845 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
848 wxTextFile amulesig_out;
849 wxTextFile emulesig_out;
851 // Open both files if needed
852 if ( !emulesig_out.Create( m_emulesig_path) ) {
853 AddLogLineC(_("Failed to create OnlineSig File"));
854 // Will never try again.
855 m_amulesig_path.Clear();
856 m_emulesig_path.Clear();
857 return;
860 if ( !amulesig_out.Create(m_amulesig_path) ) {
861 AddLogLineC(_("Failed to create aMule OnlineSig File"));
862 // Will never try again.
863 m_amulesig_path.Clear();
864 m_emulesig_path.Clear();
865 return;
868 wxString emulesig_string;
869 wxString temp;
871 if (zero) {
872 emulesig_string = wxT("0\xA0.0|0.0|0");
873 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
874 } else {
875 if (IsConnectedED2K()) {
877 temp = CFormat(wxT("%d")) % serverconnect->GetCurrentServer()->GetPort();
879 // We are online
880 emulesig_string =
881 // Connected
882 wxT("1|")
883 //Server name
884 + serverconnect->GetCurrentServer()->GetListName()
885 + wxT("|")
886 // IP and port of the server
887 + serverconnect->GetCurrentServer()->GetFullIP()
888 + wxT("|")
889 + temp;
892 // Now for amule sig
894 // Connected. State 1, full info
895 amulesig_out.AddLine(wxT("1"));
896 // Server Name
897 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
898 // Server IP
899 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
900 // Server Port
901 amulesig_out.AddLine(temp);
903 if (serverconnect->IsLowID()) {
904 amulesig_out.AddLine(wxT("L"));
905 } else {
906 amulesig_out.AddLine(wxT("H"));
909 } else if (serverconnect->IsConnecting()) {
910 emulesig_string = wxT("0");
912 // Connecting. State 2, No info.
913 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
914 } else {
915 // Not connected to a server
916 emulesig_string = wxT("0");
918 // Not connected, state 0, no info
919 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
921 if (IsConnectedKad()) {
922 if(Kademlia::CKademlia::IsFirewalled()) {
923 // Connected. Firewalled. State 1.
924 amulesig_out.AddLine(wxT("1"));
925 } else {
926 // Connected. State 2.
927 amulesig_out.AddLine(wxT("2"));
929 } else {
930 // Not connected.State 0.
931 amulesig_out.AddLine(wxT("0"));
933 emulesig_string += wxT("\xA");
935 // Datarate for downloads
936 temp = CFormat(wxT("%.1f")) % (theStats::GetDownloadRate() / 1024.0);
938 emulesig_string += temp + wxT("|");
939 amulesig_out.AddLine(temp);
941 // Datarate for uploads
942 temp = CFormat(wxT("%.1f")) % (theStats::GetUploadRate() / 1024.0);
944 emulesig_string += temp + wxT("|");
945 amulesig_out.AddLine(temp);
947 // Number of users waiting for upload
948 temp = CFormat(wxT("%d")) % theStats::GetWaitingUserCount();
950 emulesig_string += temp;
951 amulesig_out.AddLine(temp);
953 // Number of shared files (not on eMule)
954 amulesig_out.AddLine(CFormat(wxT("%d")) % theStats::GetSharedFileCount());
957 // eMule signature finished here. Write the line to the wxTextFile.
958 emulesig_out.AddLine(emulesig_string);
960 // Now for aMule signature extras
962 // Nick on the network
963 amulesig_out.AddLine(thePrefs::GetUserNick());
965 // Total received in bytes
966 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalReceivedBytes());
968 // Total sent in bytes
969 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetTotalSentBytes());
971 // amule version
972 #ifdef SVNDATE
973 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
974 #else
975 amulesig_out.AddLine(wxT(VERSION));
976 #endif
978 if (zero) {
979 amulesig_out.AddLine(wxT("0"));
980 amulesig_out.AddLine(wxT("0"));
981 amulesig_out.AddLine(wxT("0"));
982 } else {
983 // Total received bytes in session
984 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
985 theStats::GetSessionReceivedBytes() );
987 // Total sent bytes in session
988 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
989 theStats::GetSessionSentBytes() );
991 // Uptime
992 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
995 // Flush the files
996 emulesig_out.Write();
997 amulesig_out.Write();
998 } //End Added By Bouc7
1001 #if wxUSE_ON_FATAL_EXCEPTION
1002 // Gracefully handle fatal exceptions and print backtrace if possible
1003 void CamuleApp::OnFatalException()
1005 /* Print the backtrace */
1006 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1007 fprintf(stderr, "A fatal error has occurred and aMule has crashed.\n");
1008 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1009 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1010 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
1011 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
1012 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
1013 fprintf(stderr, " http://wiki.amule.org/index.php/Backtraces\n\n");
1014 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1015 fprintf(stderr, "Current version is: %s\n", strFullMuleVersion);
1016 fprintf(stderr, "Running on: %s\n\n", strOSDescription);
1018 print_backtrace(1); // 1 == skip this function.
1020 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
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 if (!wxUSE_STACKWALKER || !wxThread::IsMain() || !IsRunning()) {
1084 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1085 % file % func % line % cond % ( msg ? msg : wxT("") );
1087 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
1089 // Skip the function-calls directly related to the assert call.
1090 fprintf(stderr, "\nBacktrace follows:\n");
1091 print_backtrace(3);
1092 fprintf(stderr, "\n");
1095 if (wxThread::IsMain() && IsRunning()) {
1096 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1097 } else {
1098 // Abort, allows gdb to catch the assertion
1099 raise( SIGABRT );
1102 #endif
1105 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1107 CServerUDPSocket* socket =(CServerUDPSocket*)evt.GetClientData();
1108 socket->OnHostnameResolved(evt.GetExtraLong());
1112 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1114 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1118 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1120 AddLogLineNS(_("Server hostname notified"));
1121 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1125 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1127 if(!IsRunning()) {
1128 return;
1130 serverconnect->StopConnectionTry();
1131 if (IsConnectedED2K() ) {
1132 return;
1134 serverconnect->ConnectToAnyServer();
1138 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1140 // Former TimerProc section
1141 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1142 uint64 msCur = theStats::GetUptimeMillis();
1143 TheTime = msCur / 1000;
1145 if (!IsRunning()) {
1146 return;
1149 #ifndef AMULE_DAEMON
1150 // Check if we should terminate the app
1151 if ( g_shutdownSignal ) {
1152 wxWindow* top = GetTopWindow();
1154 if ( top ) {
1155 top->Close(true);
1156 } else {
1157 // No top-window, have to force termination.
1158 wxExit();
1161 #endif
1163 // There is a theoretical chance that the core time function can recurse:
1164 // if an event function gets blocked on a mutex (communicating with the
1165 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1166 // If CPU load gets high a new core timer event could be generated before the last
1167 // one was finished and so recursion could occur, which would be bad.
1168 // Detect this and do an early return then.
1169 static bool recurse = false;
1170 if (recurse) {
1171 return;
1173 recurse = true;
1175 uploadqueue->Process();
1176 downloadqueue->Process();
1177 //theApp->clientcredits->Process();
1178 theStats::CalculateRates();
1180 if (msCur-msPrevHist > 1000) {
1181 // unlike the other loop counters in this function this one will sometimes
1182 // produce two calls in quick succession (if there was a gap of more than one
1183 // second between calls to TimerProc) - this is intentional! This way the
1184 // history list keeps an average of one node per second and gets thinned out
1185 // correctly as time progresses.
1186 msPrevHist += 1000;
1188 m_statistics->RecordHistory();
1193 if (msCur-msPrev1 > 1000) { // approximately every second
1194 msPrev1 = msCur;
1195 clientcredits->Process();
1196 clientlist->Process();
1198 // Publish files to server if needed.
1199 sharedfiles->Process();
1201 if( Kademlia::CKademlia::IsRunning() ) {
1202 Kademlia::CKademlia::Process();
1203 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1204 StopKad();
1205 clientudp->Close();
1206 clientudp->Open();
1207 if (thePrefs::Reconnect()) {
1208 StartKad();
1213 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1214 serverconnect->TryAnotherConnectionrequest();
1216 if (serverconnect->IsConnecting()) {
1217 serverconnect->CheckForTimeout();
1219 listensocket->UpdateConnectionsStatus();
1224 if (msCur-msPrev5 > 5000) { // every 5 seconds
1225 msPrev5 = msCur;
1226 listensocket->Process();
1229 if (msCur-msPrevSave >= 60000) {
1230 msPrevSave = msCur;
1231 theStats::Save();
1234 // Special
1235 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1236 OnlineSig(); // Added By Bouc7
1237 msPrevOS = msCur;
1240 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1241 // Save Shared Files data
1242 knownfiles->Save();
1243 msPrevKnownMet = msCur;
1247 // Recomended by lugdunummaster himself - from emule 0.30c
1248 serverconnect->KeepConnectionAlive();
1250 // Disarm recursion protection
1251 recurse = false;
1255 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1257 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1259 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1260 CKnownFile* result = evt.GetResult();
1262 if (owner) {
1263 // Check if the partfile still exists, as it might have
1264 // been deleted in the mean time.
1265 if (downloadqueue->IsPartFile(owner)) {
1266 // This cast must not be done before the IsPartFile
1267 // call, as dynamic_cast will barf on dangling pointers.
1268 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1270 } else {
1271 static int filecount;
1272 static uint64 bytecount;
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 filecount++;
1280 bytecount += result->GetFileSize();
1281 // If we have added 30 files or files with a total size of ~300mb
1282 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1283 AddDebugLogLineN(logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1284 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1285 knownfiles->Save();
1286 filecount = 0;
1287 bytecount = 0;
1290 } else {
1291 AddDebugLogLineN(logKnownFiles,
1292 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1293 delete result;
1299 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1301 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1303 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1304 CScopedPtr<CKnownFile> result(evt.GetResult());
1306 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1307 CAICHHashSet* oldSet = owner->GetAICHHashset();
1308 CAICHHashSet* newSet = result->GetAICHHashset();
1310 owner->SetAICHHashset(newSet);
1311 newSet->SetOwner(owner);
1313 result->SetAICHHashset(oldSet);
1314 oldSet->SetOwner(result.get());
1319 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1321 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1322 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1323 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1325 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1326 if (evt.ErrorOccured()) {
1327 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1330 // Check if we should execute an script/app/whatever.
1331 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1334 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1336 CPartFile *file = evt.GetFile();
1337 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1338 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1340 file->SetStatus(PS_EMPTY);
1342 if (evt.Succeeded()) {
1343 if (evt.IsPaused()) {
1344 file->StopFile();
1345 } else {
1346 file->ResumeFile();
1348 } else {
1349 AddLogLineN(CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1350 file->StopFile();
1353 file->AllocationFinished();
1356 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1358 #ifdef AMULE_DAEMON
1359 evt.Notify();
1360 #else
1361 if (theApp->amuledlg) {
1362 evt.Notify();
1364 #endif
1368 void CamuleApp::ShutDown()
1370 // Just in case
1371 PlatformSpecific::AllowSleepMode();
1373 // Log
1374 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has started."));
1376 // Signal the hashing thread to terminate
1377 m_app_state = APP_STATE_SHUTTINGDOWN;
1379 StopKad();
1381 // Kry - Save the sources seeds on app exit
1382 if (thePrefs::GetSrcSeedsOn()) {
1383 downloadqueue->SaveSourceSeeds();
1386 OnlineSig(true); // Added By Bouc7
1388 // Exit HTTP downloads
1389 CHTTPDownloadThread::StopAll();
1391 // Exit thread scheduler and upload thread
1392 CThreadScheduler::Terminate();
1394 AddDebugLogLineN(logGeneral, wxT("Terminate upload thread."));
1395 uploadBandwidthThrottler->EndThread();
1397 // Close sockets to avoid new clients coming in
1398 if (listensocket) {
1399 listensocket->Close();
1400 listensocket->KillAllSockets();
1403 if (serverconnect) {
1404 serverconnect->Disconnect();
1407 ECServerHandler->KillAllSockets();
1409 #ifdef ENABLE_UPNP
1410 if (thePrefs::GetUPnPEnabled()) {
1411 if (m_upnp) {
1412 m_upnp->DeletePortMappings(m_upnpMappings);
1415 #endif
1417 // saving data & stuff
1418 if (knownfiles) {
1419 knownfiles->Save();
1422 theStats::Save();
1424 CPath configFileName = CPath(ConfigDir + m_configFile);
1425 CPath::BackupFile(configFileName, wxT(".bak"));
1427 if (clientlist) {
1428 clientlist->DeleteAll();
1431 // Log
1432 AddDebugLogLineN(logGeneral, wxT("CamuleApp::ShutDown() has ended."));
1436 bool CamuleApp::AddServer(CServer *srv, bool fromUser)
1438 if ( serverlist->AddServer(srv, fromUser) ) {
1439 Notify_ServerAdd(srv);
1440 return true;
1442 return false;
1446 uint32 CamuleApp::GetPublicIP(bool ignorelocal) const
1448 if (m_dwPublicIP == 0) {
1449 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1450 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1451 } else {
1452 return ignorelocal ? 0 : m_localip;
1456 return m_dwPublicIP;
1460 void CamuleApp::SetPublicIP(const uint32 dwIP)
1462 wxASSERT((dwIP == 0) || !IsLowID(dwIP));
1464 if (dwIP != 0 && dwIP != m_dwPublicIP && serverlist != NULL) {
1465 m_dwPublicIP = dwIP;
1466 serverlist->CheckForExpiredUDPKeys();
1467 } else {
1468 m_dwPublicIP = dwIP;
1473 wxString CamuleApp::GetLog(bool reset)
1475 wxFile logfile;
1476 logfile.Open(ConfigDir + wxT("logfile"));
1477 if ( !logfile.IsOpened() ) {
1478 return _("ERROR: can't open logfile");
1480 int len = logfile.Length();
1481 if ( len == 0 ) {
1482 return _("WARNING: logfile is empty. Something is wrong.");
1484 char *tmp_buffer = new char[len + sizeof(wxChar)];
1485 logfile.Read(tmp_buffer, len);
1486 memset(tmp_buffer + len, 0, sizeof(wxChar));
1488 // try to guess file format
1489 wxString str;
1490 if (tmp_buffer[0] && tmp_buffer[1]) {
1491 str = wxString(UTF82unicode(tmp_buffer));
1492 } else {
1493 str = wxWCharBuffer((wchar_t *)tmp_buffer);
1496 delete [] tmp_buffer;
1497 if ( reset ) {
1498 theLogger.CloseLogfile();
1499 if (theLogger.OpenLogfile(ConfigDir + wxT("logfile"))) {
1500 AddLogLineN(_("Log has been reset"));
1502 ECServerHandler->ResetAllLogs();
1504 return str;
1508 wxString CamuleApp::GetServerLog(bool reset)
1510 wxString ret = server_msg;
1511 if ( reset ) {
1512 server_msg.Clear();
1514 return ret;
1517 wxString CamuleApp::GetDebugLog(bool reset)
1519 return GetLog(reset);
1523 void CamuleApp::AddServerMessageLine(wxString &msg)
1525 server_msg += msg + wxT("\n");
1526 AddLogLineN(CFormat(_("ServerMessage: %s")) % msg);
1531 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1533 switch (event.GetInt()) {
1534 case HTTP_IPFilter:
1535 ipfilter->DownloadFinished(event.GetExtraLong());
1536 break;
1537 case HTTP_ServerMet:
1538 serverlist->DownloadFinished(event.GetExtraLong());
1539 break;
1540 case HTTP_ServerMetAuto:
1541 serverlist->AutoDownloadFinished(event.GetExtraLong());
1542 break;
1543 case HTTP_VersionCheck:
1544 CheckNewVersion(event.GetExtraLong());
1545 break;
1546 case HTTP_NodesDat:
1547 if (event.GetExtraLong() == HTTP_Success) {
1549 wxString file = ConfigDir + wxT("nodes.dat");
1550 if (wxFileExists(file)) {
1551 wxRemoveFile(file);
1554 if ( Kademlia::CKademlia::IsRunning() ) {
1555 Kademlia::CKademlia::Stop();
1558 wxRenameFile(file + wxT(".download"),file);
1560 Kademlia::CKademlia::Start();
1561 theApp->ShowConnectionState();
1563 } else if (event.GetExtraLong() == HTTP_Skipped) {
1564 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1565 } else {
1566 AddLogLineC(_("Failed to download the nodes list."));
1568 break;
1569 #ifdef ENABLE_IP2COUNTRY
1570 case HTTP_GeoIP:
1571 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1572 // If we updated, the dialog is already up. Redraw it to show the flags.
1573 theApp->amuledlg->Refresh();
1574 break;
1575 #endif
1579 void CamuleApp::CheckNewVersion(uint32 result)
1581 if (result == HTTP_Success) {
1582 wxString filename = ConfigDir + wxT("last_version_check");
1583 wxTextFile file;
1585 if (!file.Open(filename)) {
1586 AddLogLineC(_("Failed to open the downloaded version check file") );
1587 return;
1588 } else if (!file.GetLineCount()) {
1589 AddLogLineC(_("Corrupted version check file"));
1590 } else {
1591 wxString versionLine = file.GetFirstLine();
1592 wxStringTokenizer tkz(versionLine, wxT("."));
1594 AddDebugLogLineN(logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1596 long fields[] = {0, 0, 0};
1597 for (int i = 0; i < 3; ++i) {
1598 if (!tkz.HasMoreTokens()) {
1599 AddLogLineC(_("Corrupted version check file"));
1600 return;
1601 } else {
1602 wxString token = tkz.GetNextToken();
1604 if (!token.ToLong(&fields[i])) {
1605 AddLogLineC(_("Corrupted version check file"));
1606 return;
1611 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1612 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1614 if (curVer < newVer) {
1615 AddLogLineC(_("You are using an outdated version of aMule!"));
1616 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]);
1617 AddLogLineN(_("The latest version can always be found at http://www.amule.org"));
1618 #ifdef AMULE_DAEMON
1619 AddLogLineCS(CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1620 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1621 #endif
1622 } else {
1623 AddLogLineN(_("Your copy of aMule is up to date."));
1627 file.Close();
1628 wxRemoveFile(filename);
1629 } else {
1630 AddLogLineC(_("Failed to download the version check file"));
1636 bool CamuleApp::IsConnected() const
1638 return (IsConnectedED2K() || IsConnectedKad());
1642 bool CamuleApp::IsConnectedED2K() const
1644 return serverconnect && serverconnect->IsConnected();
1648 bool CamuleApp::IsConnectedKad() const
1650 return Kademlia::CKademlia::IsConnected();
1654 bool CamuleApp::IsFirewalled() const
1656 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1657 return false; // we have an eD2K HighID -> not firewalled
1660 return IsFirewalledKad(); // If kad says ok, it's ok.
1663 bool CamuleApp::IsFirewalledKad() const
1665 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1666 || Kademlia::CKademlia::IsFirewalled();
1669 bool CamuleApp::IsFirewalledKadUDP() const
1671 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1672 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1675 bool CamuleApp::IsKadRunning() const
1677 return Kademlia::CKademlia::IsRunning();
1680 bool CamuleApp::IsKadRunningInLanMode() const
1682 return Kademlia::CKademlia::IsRunningInLANMode();
1685 // Kad stats
1686 uint32 CamuleApp::GetKadUsers() const
1688 return Kademlia::CKademlia::GetKademliaUsers();
1691 uint32 CamuleApp::GetKadFiles() const
1693 return Kademlia::CKademlia::GetKademliaFiles();
1696 uint32 CamuleApp::GetKadIndexedSources() const
1698 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1701 uint32 CamuleApp::GetKadIndexedKeywords() const
1703 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1706 uint32 CamuleApp::GetKadIndexedNotes() const
1708 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1711 uint32 CamuleApp::GetKadIndexedLoad() const
1713 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1717 // True IP of machine
1718 uint32 CamuleApp::GetKadIPAdress() const
1720 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1723 // Buddy status
1724 uint8 CamuleApp::GetBuddyStatus() const
1726 return clientlist->GetBuddyStatus();
1729 uint32 CamuleApp::GetBuddyIP() const
1731 return clientlist->GetBuddyIP();
1734 uint32 CamuleApp::GetBuddyPort() const
1736 return clientlist->GetBuddyPort();
1739 bool CamuleApp::CanDoCallback(uint32 clientServerIP, uint16 clientServerPort)
1741 if (Kademlia::CKademlia::IsConnected()) {
1742 if (IsConnectedED2K()) {
1743 if (serverconnect->IsLowID()) {
1744 if (Kademlia::CKademlia::IsFirewalled()) {
1745 //Both Connected - Both Firewalled
1746 return false;
1747 } else {
1748 if (clientServerIP == theApp->serverconnect->GetCurrentServer()->GetIP() &&
1749 clientServerPort == theApp->serverconnect->GetCurrentServer()->GetPort()) {
1750 // Both Connected - Server lowID, Kad Open - Client on same server
1751 // We prevent a callback to the server as this breaks the protocol
1752 // and will get you banned.
1753 return false;
1754 } else {
1755 // Both Connected - Server lowID, Kad Open - Client on remote server
1756 return true;
1759 } else {
1760 //Both Connected - Server HighID, Kad don't care
1761 return true;
1763 } else {
1764 if (Kademlia::CKademlia::IsFirewalled()) {
1765 //Only Kad Connected - Kad Firewalled
1766 return false;
1767 } else {
1768 //Only Kad Conected - Kad Open
1769 return true;
1772 } else {
1773 if (IsConnectedED2K()) {
1774 if (serverconnect->IsLowID()) {
1775 //Only Server Connected - Server LowID
1776 return false;
1777 } else {
1778 //Only Server Connected - Server HighID
1779 return true;
1781 } else {
1782 //We are not connected at all!
1783 return false;
1788 void CamuleApp::ShowUserCount() {
1789 uint32 totaluser = 0, totalfile = 0;
1791 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
1793 wxString buffer;
1795 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
1796 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
1798 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1799 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1800 } else if (thePrefs::GetNetworkED2K()) {
1801 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
1802 } else if (thePrefs::GetNetworkKademlia()) {
1803 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1804 } else {
1805 buffer = _("No networks selected");
1808 Notify_ShowUserCount(buffer);
1812 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
1814 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
1815 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
1816 wxT("Invalid event received for listen-socket"));
1818 if (m_app_state == APP_STATE_RUNNING) {
1819 listensocket->OnAccept(0);
1820 } else if (m_app_state == APP_STATE_STARTING) {
1821 // When starting up, connection may be made before we are able
1822 // to handle them. However, if these are ignored, no futher
1823 // connection-events will be triggered, so we have to accept it.
1824 wxSocketBase* socket = listensocket->Accept(false);
1826 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
1828 socket->Destroy();
1833 void CamuleApp::ShowConnectionState(bool forceUpdate)
1835 static uint8 old_state = (1<<7); // This flag doesn't exist
1837 uint8 state = 0;
1839 if (theApp->serverconnect->IsConnected()) {
1840 state |= CONNECTED_ED2K;
1843 if (Kademlia::CKademlia::IsRunning()) {
1844 if (Kademlia::CKademlia::IsConnected()) {
1845 if (!Kademlia::CKademlia::IsFirewalled()) {
1846 state |= CONNECTED_KAD_OK;
1847 } else {
1848 state |= CONNECTED_KAD_FIREWALLED;
1850 } else {
1851 state |= CONNECTED_KAD_NOT;
1855 if (old_state != state) {
1856 // Get the changed value
1857 int changed_flags = old_state ^ state;
1859 if (changed_flags & CONNECTED_ED2K) {
1860 // ED2K status changed
1861 wxString connected_server;
1862 CServer* ed2k_server = theApp->serverconnect->GetCurrentServer();
1863 if (ed2k_server) {
1864 connected_server = ed2k_server->GetListName();
1866 if (state & CONNECTED_ED2K) {
1867 // We connected to some server
1868 const wxString id = theApp->serverconnect->IsLowID() ? _("with LowID") : _("with HighID");
1870 AddLogLineC(CFormat(_("Connected to %s %s")) % connected_server % id);
1871 } else {
1872 if ( theApp->serverconnect->IsConnecting() ) {
1873 AddLogLineC(CFormat(_("Connecting to %s")) % connected_server);
1874 } else {
1875 AddLogLineC(_("Disconnected from eD2k"));
1880 if (changed_flags & CONNECTED_KAD_NOT) {
1881 if (state & CONNECTED_KAD_NOT) {
1882 AddLogLineC(_("Kad started."));
1883 } else {
1884 AddLogLineC(_("Kad stopped."));
1888 if (changed_flags & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1889 if (state & (CONNECTED_KAD_OK | CONNECTED_KAD_FIREWALLED)) {
1890 if (state & CONNECTED_KAD_OK) {
1891 AddLogLineC(_("Connected to Kad (ok)"));
1892 } else {
1893 AddLogLineC(_("Connected to Kad (firewalled)"));
1895 } else {
1896 AddLogLineC(_("Disconnected from Kad"));
1900 old_state = state;
1902 theApp->downloadqueue->OnConnectionState(IsConnected());
1905 ShowUserCount();
1906 Notify_ShowConnState(forceUpdate);
1910 void CamuleApp::UDPSocketHandler(wxSocketEvent& event)
1912 CMuleUDPSocket* socket = (CMuleUDPSocket*)(event.GetClientData());
1913 wxCHECK_RET(socket, wxT("No socket owner specified."));
1915 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
1917 if (!IsRunning()) {
1918 if (event.GetSocketEvent() == wxSOCKET_INPUT) {
1919 // Back to the queue!
1920 theApp->AddPendingEvent(event);
1921 return;
1925 switch (event.GetSocketEvent()) {
1926 case wxSOCKET_INPUT:
1927 socket->OnReceive(0);
1928 break;
1930 case wxSOCKET_OUTPUT:
1931 socket->OnSend(0);
1932 break;
1934 case wxSOCKET_LOST:
1935 socket->OnDisconnected(0);
1936 break;
1938 default:
1939 wxFAIL;
1940 break;
1945 void CamuleApp::OnUnhandledException()
1947 // Call the generic exception-handler.
1948 fprintf(stderr, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
1949 ::OnUnhandledException();
1952 void CamuleApp::StartKad()
1954 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
1955 // Kad makes no sense without the Client-UDP socket.
1956 if (!thePrefs::IsUDPDisabled()) {
1957 if (ipfilter->IsReady()) {
1958 Kademlia::CKademlia::Start();
1959 } else {
1960 ipfilter->StartKADWhenReady();
1962 } else {
1963 AddLogLineC(_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1965 } else if (!thePrefs::GetNetworkKademlia()) {
1966 AddLogLineC(_("Kad network disabled on preferences, not connecting."));
1970 void CamuleApp::StopKad()
1972 // Stop Kad if it's running
1973 if (Kademlia::CKademlia::IsRunning()) {
1974 Kademlia::CKademlia::Stop();
1979 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
1981 if (!Kademlia::CKademlia::IsRunning()) {
1982 Kademlia::CKademlia::Start();
1983 theApp->ShowConnectionState();
1986 Kademlia::CKademlia::Bootstrap(ip, port);
1990 void CamuleApp::UpdateNotesDat(const wxString& url)
1992 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
1994 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, theApp->ConfigDir + wxT("nodes.dat"), HTTP_NodesDat, true, false);
1995 downloader->Create();
1996 downloader->Run();
2000 void CamuleApp::DisconnectED2K()
2002 // Stop ED2K if it's running
2003 if (IsConnectedED2K()) {
2004 serverconnect->Disconnect();
2008 bool CamuleApp::CryptoAvailable() const
2010 return clientcredits && clientcredits->CryptoAvailable();
2013 uint32 CamuleApp::GetED2KID() const {
2014 return serverconnect ? serverconnect->GetClientID() : 0;
2017 uint32 CamuleApp::GetID() const {
2018 uint32 ID;
2020 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2021 // We trust Kad above ED2K
2022 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2023 } else if( theApp->serverconnect->IsConnected() ) {
2024 ID = theApp->serverconnect->GetClientID();
2025 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2026 // A firewalled Kad client get's a "1"
2027 ID = 1;
2028 } else {
2029 ID = 0;
2032 return ID;
2035 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2036 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2037 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2038 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2039 // File_checked_for_headers