Upstream tarball 10013
[amule.git] / src / amule.cpp
blob01e78d9a609009a3476504aa733154f08f895699
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
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 "Preferences.h" // Needed for CPreferences
70 #include "SearchList.h" // Needed for CSearchList
71 #include "Server.h" // Needed for GetListName
72 #include "ServerList.h" // Needed for CServerList
73 #include "ServerConnect.h" // Needed for CServerConnect
74 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
75 #include "Statistics.h" // Needed for CStatistics
76 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
77 #include "ThreadTasks.h"
78 #include "updownclient.h" // Needed for CUpDownClient
79 #include "UploadQueue.h" // Needed for CUploadQueue
80 #include "UploadBandwidthThrottler.h"
81 #include "UserEvents.h"
82 #include "ScopedPtr.h"
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();
218 CamuleApp::~CamuleApp()
220 // Closing the log-file as the very last thing, since
221 // wxWidgets log-events are saved in it as well.
222 theLogger.CloseLogfile();
224 free(strFullMuleVersion);
225 free(strOSDescription);
228 int CamuleApp::OnExit()
230 if (m_app_state!=APP_STATE_STARTING) {
231 AddLogLineMS(false, _("Now, exiting main app..."));
234 // From wxWidgets docs, wxConfigBase:
235 // ...
236 // Note that you must delete this object (usually in wxApp::OnExit)
237 // in order to avoid memory leaks, wxWidgets won't do it automatically.
239 // As it happens, you may even further simplify the procedure described
240 // above: you may forget about calling Set(). When Get() is called and
241 // there is no current object, it will create one using Create() function.
242 // To disable this behaviour DontCreateOnDemand() is provided.
243 delete wxConfigBase::Set((wxConfigBase *)NULL);
245 // Save credits
246 clientcredits->SaveList();
248 // Kill amuleweb if running
249 if (webserver_pid) {
250 AddLogLineNS(CFormat(_("Terminating amuleweb instance with pid `%ld' ... ")) % webserver_pid);
251 wxKillError rc;
252 if (wxKill(webserver_pid, wxSIGTERM, &rc) == -1) {
253 AddLogLineNS(CFormat(_("Killing amuleweb instance with pid `%ld' ... ")) % webserver_pid);
254 if (wxKill(webserver_pid, wxSIGKILL, &rc) == -1) {
255 AddLogLineNS(_("Failed"));
260 if (m_app_state!=APP_STATE_STARTING) {
261 AddLogLineMS(false, _("aMule OnExit: Terminating core."));
264 delete serverlist;
265 serverlist = NULL;
267 delete searchlist;
268 searchlist = NULL;
270 delete clientcredits;
271 clientcredits = NULL;
273 delete friendlist;
274 friendlist = NULL;
276 // Destroying CDownloadQueue calls destructor for CPartFile
277 // calling CSharedFileList::SafeAddKFile occasionally.
278 delete sharedfiles;
279 sharedfiles = NULL;
281 delete serverconnect;
282 serverconnect = NULL;
284 delete listensocket;
285 listensocket = NULL;
287 delete clientudp;
288 clientudp = NULL;
290 delete knownfiles;
291 knownfiles = NULL;
293 delete canceledfiles;
294 canceledfiles = NULL;
296 delete clientlist;
297 clientlist = NULL;
299 delete uploadqueue;
300 uploadqueue = NULL;
302 delete downloadqueue;
303 downloadqueue = NULL;
305 delete ipfilter;
306 ipfilter = NULL;
308 #ifdef ENABLE_UPNP
309 delete m_upnp;
310 m_upnp = NULL;
311 #endif
313 delete ECServerHandler;
314 ECServerHandler = NULL;
316 delete m_statistics;
317 m_statistics = NULL;
319 delete glob_prefs;
320 glob_prefs = NULL;
321 CPreferences::EraseItemList();
323 delete uploadBandwidthThrottler;
324 uploadBandwidthThrottler = NULL;
326 if (m_app_state!=APP_STATE_STARTING) {
327 AddLogLineNS(_("aMule shutdown completed."));
330 #if wxUSE_MEMORY_TRACING
331 AddLogLineNS(_("Memory debug results for aMule exit:"));
332 // Log mem debug mesages to wxLogStderr
333 wxLog* oldLog = wxLog::SetActiveTarget(new wxLogStderr);
334 //AddLogLineNS(wxT("**************Classes**************");
335 //wxDebugContext::PrintClasses();
336 //AddLogLineNS(wxT("***************Dump***************");
337 //wxDebugContext::Dump();
338 AddLogLineNS(wxT("***************Stats**************"));
339 wxDebugContext::PrintStatistics(true);
341 // Set back to wxLogGui
342 delete wxLog::SetActiveTarget(oldLog);
343 #endif
345 StopTickTimer();
347 // Return 0 for succesful program termination
348 return AMULE_APP_BASE::OnExit();
352 int CamuleApp::InitGui(bool, wxString &)
354 return 0;
359 // Application initialization
361 bool CamuleApp::OnInit()
363 #if wxUSE_MEMORY_TRACING
364 // any text before call of Localize_mule needs not to be translated.
365 AddLogLineMS(false, wxT("Checkpoint set on app init for memory debug"));
366 wxDebugContext::SetCheckpoint();
367 #endif
369 // Forward wxLog events to CLogger
370 wxLog::SetActiveTarget(new CLoggerTarget);
372 m_localip = StringHosttoUint32(::wxGetFullHostName());
374 #ifndef __WXMSW__
375 // get rid of sigpipe
376 signal(SIGPIPE, SIG_IGN);
377 #else
378 // Handle CTRL-Break
379 signal(SIGBREAK, OnShutdownSignal);
380 #endif
381 // Handle sigint and sigterm
382 signal(SIGINT, OnShutdownSignal);
383 signal(SIGTERM, OnShutdownSignal);
385 #ifdef __WXMAC__
386 // For listctrl's to behave on Mac
387 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
388 #endif
390 // Handle uncaught exceptions
391 InstallMuleExceptionHandler();
393 if (!InitCommon(AMULE_APP_BASE::argc, AMULE_APP_BASE::argv)) {
394 return false;
397 glob_prefs = new CPreferences();
399 CPath outDir;
400 if (CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir + wxT("Temp"), outDir)) {
401 thePrefs::SetTempDir(outDir);
402 } else {
403 return false;
406 if (CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir + wxT("Incoming"), outDir)) {
407 thePrefs::SetIncomingDir(outDir);
408 } else {
409 return false;
412 // Some sanity check
413 if (!thePrefs::UseTrayIcon()) {
414 thePrefs::SetMinToTray(false);
417 // Build the filenames for the two OS files
418 SetOSFiles(thePrefs::GetOSDir().GetRaw());
420 #ifdef ENABLE_NLS
421 // Load localization settings
422 Localize_mule();
423 #endif
425 // Configure EC for amuled when invoked with ec-config
426 if (ec_config) {
427 AddLogLineMS(false, _("\nEC configuration"));
428 thePrefs::SetECPass(GetPassword());
429 thePrefs::EnableExternalConnections(true);
430 AddLogLineMS(false, _("Password set and external connections enabled."));
433 #ifndef __WXMSW__
434 if (getuid() == 0) {
435 wxString msg =
436 wxT("Warning! You are running aMule as root.\n")
437 wxT("Doing so is not recommended for security reasons,\n")
438 wxT("and you are advised to run aMule as an normal\n")
439 wxT("user instead.");
441 ShowAlert(msg, _("WARNING"), wxCENTRE | wxOK | wxICON_ERROR);
443 fprintf(stderr, "\n--------------------------------------------------\n");
444 fprintf(stderr, "%s", (const char*)unicode2UTF8(msg));
445 fprintf(stderr, "\n--------------------------------------------------\n\n");
447 #endif
449 // Display notification on new version or first run
450 wxTextFile vfile( ConfigDir + wxT("lastversion") );
451 wxString newMule(wxT( VERSION ));
453 if ( !wxFileExists( vfile.GetName() ) ) {
454 vfile.Create();
457 if ( vfile.Open() ) {
458 // Check if this version has been run before
459 bool found = false;
460 for ( size_t i = 0; i < vfile.GetLineCount(); i++ ) {
461 // Check if this version has been run before
462 if ( vfile.GetLine(i) == newMule ) {
463 found = true;
464 break;
468 // We havent run this version before?
469 if ( !found ) {
470 // Insert new at top to provide faster searches
471 vfile.InsertLine( newMule, 0 );
473 Trigger_New_version( newMule );
476 // Keep at most 10 entires
477 while ( vfile.GetLineCount() > 10 )
478 vfile.RemoveLine( vfile.GetLineCount() - 1 );
480 vfile.Write();
481 vfile.Close();
484 // Check if we have the old style locale config
485 wxString langId = thePrefs::GetLanguageID();
486 if (!langId.IsEmpty() && (langId.GetChar(0) >= '0' && langId.GetChar(0) <= '9')) {
487 wxString info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
488 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT));
489 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
492 m_statistics = new CStatistics();
494 clientlist = new CClientList();
495 friendlist = new CFriendList();
496 searchlist = new CSearchList();
497 knownfiles = new CKnownFileList();
498 canceledfiles = new CCanceledFileList;
499 serverlist = new CServerList();
501 sharedfiles = new CSharedFileList(knownfiles);
502 clientcredits = new CClientCreditsList();
504 // bugfix - do this before creating the uploadqueue
505 downloadqueue = new CDownloadQueue();
506 uploadqueue = new CUploadQueue();
507 ipfilter = new CIPFilter();
509 // Creates all needed listening sockets
510 wxString msg;
511 if (!ReinitializeNetwork(&msg)) {
512 AddLogLineMS(false, wxT("\n"));
513 AddLogLineMS(false, msg);
516 // Test if there's any new version
517 if (thePrefs::GetCheckNewVersion()) {
518 // We use the thread base because I don't want a dialog to pop up.
519 CHTTPDownloadThread* version_check =
520 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
521 theApp->ConfigDir + wxT("last_version_check"), theApp->ConfigDir + wxT("last_version"), HTTP_VersionCheck, false);
522 version_check->Create();
523 version_check->Run();
526 // Create main dialog, or fork to background (daemon).
527 InitGui(m_geometryEnabled, m_geometryString);
529 #ifdef AMULE_DAEMON
530 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
531 if (enable_daemon_fork) {
532 RefreshSingleInstanceChecker();
533 // No need to check IsAnotherRunning() - we've done it before.
535 #endif
537 // Has to be created after the call to InitGui, as fork
538 // (when using posix threads) only replicates the mainthread,
539 // and the UBT constructor creates a thread.
540 uploadBandwidthThrottler = new UploadBandwidthThrottler();
542 // These must be initialized after the gui is loaded.
543 serverlist->Init();
544 downloadqueue->LoadMetFiles(thePrefs::GetTempDir());
545 sharedfiles->Reload();
547 if (thePrefs::IPFilterAutoLoad()) {
548 ipfilter->Update(thePrefs::IPFilterURL());
552 // Ensure that the up/down ratio is used
553 CPreferences::CheckUlDlRatio();
555 // The user can start pressing buttons like mad if he feels like it.
556 m_app_state = APP_STATE_RUNNING;
558 // Kry - Load the sources seeds on app init
559 if (thePrefs::GetSrcSeedsOn()) {
560 downloadqueue->LoadSourceSeeds();
563 if (!serverlist->GetServerCount() && thePrefs::GetNetworkED2K()) {
564 // There are no servers and ED2K active -> ask for download.
565 // As we cannot ask in amuled, we just update there
566 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
567 #ifndef AMULE_DAEMON
568 if (wxYES == wxMessageBox(
569 wxString(
570 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
571 wxString(_("Server list download")),
572 wxYES_NO,
573 static_cast<wxWindow*>(theApp->amuledlg)))
574 #endif
576 // workaround amuled crash
577 #ifndef AMULE_DAEMON
578 serverlist->UpdateServerMetFromURL(
579 wxT("http://gruk.org/server.met.gz"));
580 #endif
585 // Autoconnect if that option is enabled
586 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
587 AddLogLineM(true, _("Connecting"));
588 if (thePrefs::GetNetworkED2K()) {
589 theApp->serverconnect->ConnectToAnyServer();
592 StartKad();
596 // Enable GeoIP
597 #ifdef ENABLE_IP2COUNTRY
598 theApp->amuledlg->EnableIP2Country();
599 #endif
601 // Run webserver?
602 if (thePrefs::GetWSIsEnabled()) {
603 wxString aMuleConfigFile = ConfigDir + m_configFile;
604 wxString amulewebPath = thePrefs::GetWSPath();
606 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
607 // For the Mac GUI application, look for amuleweb in the bundle
608 CFURLRef amulewebUrl = CFBundleCopyAuxiliaryExecutableURL(
609 CFBundleGetMainBundle(), CFSTR("amuleweb"));
611 if (amulewebUrl) {
612 CFURLRef absoluteUrl = CFURLCopyAbsoluteURL(amulewebUrl);
613 CFRelease(amulewebUrl);
615 if (absoluteUrl) {
616 CFStringRef amulewebCfstr = CFURLCopyFileSystemPath(absoluteUrl, kCFURLPOSIXPathStyle);
617 CFRelease(absoluteUrl);
618 #if wxCHECK_VERSION(2, 9, 0)
619 amulewebPath = wxCFStringRef(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
620 #else
621 amulewebPath = wxMacCFStringHolder(amulewebCfstr).AsString(wxLocale::GetSystemEncoding());
622 #endif
625 #endif
627 #ifdef __WXMSW__
628 # define QUOTE wxT("\"")
629 #else
630 # define QUOTE wxT("\'")
631 #endif
633 wxString cmd =
634 QUOTE +
635 amulewebPath +
636 QUOTE wxT(" ") QUOTE wxT("--amule-config-file=") +
637 aMuleConfigFile +
638 QUOTE;
639 CTerminationProcessAmuleweb *p = new CTerminationProcessAmuleweb(cmd, &webserver_pid);
640 webserver_pid = wxExecute(cmd, wxEXEC_ASYNC, p);
641 bool webserver_ok = webserver_pid > 0;
642 if (webserver_ok) {
643 AddLogLineM(true, CFormat(_("web server running on pid %d")) % webserver_pid);
644 } else {
645 delete p;
646 ShowAlert(_(
647 "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"),
648 _("ERROR"), wxOK | wxICON_ERROR);
652 // Start performing background tasks
653 CThreadScheduler::Start();
655 return true;
658 bool CamuleApp::ReinitializeNetwork(wxString* msg)
660 bool ok = true;
661 static bool firstTime = true;
663 if (!firstTime) {
664 // TODO: Destroy previously created sockets
666 firstTime = false;
668 // Some sanity checks first
669 if (thePrefs::ECPort() == thePrefs::GetPort()) {
670 // Select a random usable port in the range 1025 ... 2^16 - 1
671 uint16 port = thePrefs::ECPort();
672 while ( port < 1024 || port == thePrefs::GetPort() ) {
673 port = (uint16)rand();
675 thePrefs::SetECPort( port );
677 wxString err =
678 wxT("Network configuration failed! You cannot use the same port\n")
679 wxT("for the main TCP port and the External Connections port.\n")
680 wxT("The EC port has been changed to avoid conflict, see the\n")
681 wxT("preferences for the new value.\n");
682 *msg << err;
684 AddLogLineM( false, wxEmptyString );
685 AddLogLineM( true, err );
686 AddLogLineM( false, wxEmptyString );
688 ok = false;
691 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
692 // Select a random usable value in the range 1025 ... 2^16 - 1
693 uint16 port = thePrefs::GetUDPPort();
694 while ( port < 1024 || port == thePrefs::GetPort() + 3 ) {
695 port = (uint16)rand();
697 thePrefs::SetUDPPort( port );
699 wxString err =
700 wxT("Network configuration failed! You set your UDP port to\n")
701 wxT("the value of the main TCP port plus 3.\n")
702 wxT("This port has been reserved for the Server-UDP port. The\n")
703 wxT("port value has been changed to avoid conflict, see the\n")
704 wxT("preferences for the new value\n");
705 *msg << err;
707 AddLogLineM( false, wxEmptyString );
708 AddLogLineM( true, err );
709 AddLogLineM( false, wxEmptyString );
711 ok = false;
714 // Create the address where we are going to listen
715 // TODO: read this from configuration file
716 amuleIPV4Address myaddr[4];
718 // Create the External Connections Socket.
719 // Default is 4712.
720 // Get ready to handle connections from apps like amulecmd
721 if (thePrefs::GetECAddress().IsEmpty() || !myaddr[0].Hostname(thePrefs::GetECAddress())) {
722 myaddr[0].AnyAddress();
724 myaddr[0].Service(thePrefs::ECPort());
725 ECServerHandler = new ExternalConn(myaddr[0], msg);
727 // Create the UDP socket TCP+3.
728 // Used for source asking on servers.
729 if (thePrefs::GetAddress().IsEmpty()) {
730 myaddr[1].AnyAddress();
731 } else if (!myaddr[1].Hostname(thePrefs::GetAddress())) {
732 myaddr[1].AnyAddress();
733 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
734 % thePrefs::GetAddress());
737 wxString ip = myaddr[1].IPAddress();
738 myaddr[1].Service(thePrefs::GetPort()+3);
739 serverconnect = new CServerConnect(serverlist, myaddr[1]);
740 *msg << CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
741 % ip % ((unsigned int)thePrefs::GetPort() + 3u);
743 // Create the ListenSocket (aMule TCP socket).
744 // Used for Client Port / Connections from other clients,
745 // Client to Client Source Exchange.
746 // Default is 4662.
747 myaddr[2] = myaddr[1];
748 myaddr[2].Service(thePrefs::GetPort());
749 listensocket = new CListenSocket(myaddr[2]);
750 *msg << CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
751 % ip % (unsigned int)(thePrefs::GetPort());
752 // This command just sets a flag to control maximum number of connections.
753 // Notify(true) has already been called to the ListenSocket, so events may
754 // be already comming in.
755 if (listensocket->Ok()) {
756 listensocket->StartListening();
757 } else {
758 // If we wern't able to start listening, we need to warn the user
759 wxString err;
760 err = CFormat(_("Port %u is not available. You will be LOWID\n")) %
761 (unsigned int)(thePrefs::GetPort());
762 *msg << err;
763 AddLogLineM(true, err);
764 err.Clear();
765 err = CFormat(
766 _("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.")) %
767 (unsigned int)(thePrefs::GetPort());
768 ShowAlert(err, _("ERROR"), wxOK | wxICON_ERROR);
771 // Create the UDP socket.
772 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
773 // Also used for Kademlia.
774 // Default is port 4672.
775 myaddr[3] = myaddr[1];
776 myaddr[3].Service(thePrefs::GetUDPPort());
777 clientudp = new CClientUDPSocket(myaddr[3], thePrefs::GetProxyData());
778 if (!thePrefs::IsUDPDisabled()) {
779 *msg << CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
780 % ip % thePrefs::GetUDPPort();
781 } else {
782 *msg << wxT("*** Client UDP socket (extended eMule) disabled on preferences");
785 #ifdef ENABLE_UPNP
786 if (thePrefs::GetUPnPEnabled()) {
787 try {
788 m_upnpMappings[0] = CUPnPPortMapping(
789 myaddr[0].Service(),
790 "TCP",
791 thePrefs::GetUPnPECEnabled(),
792 "aMule TCP External Connections Socket");
793 m_upnpMappings[1] = CUPnPPortMapping(
794 myaddr[1].Service(),
795 "UDP",
796 thePrefs::GetUPnPEnabled(),
797 "aMule UDP socket (TCP+3)");
798 m_upnpMappings[2] = CUPnPPortMapping(
799 myaddr[2].Service(),
800 "TCP",
801 thePrefs::GetUPnPEnabled(),
802 "aMule TCP Listen Socket");
803 m_upnpMappings[3] = CUPnPPortMapping(
804 myaddr[3].Service(),
805 "UDP",
806 thePrefs::GetUPnPEnabled(),
807 "aMule UDP Extended eMule Socket");
808 m_upnp = new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
809 m_upnp->AddPortMappings(m_upnpMappings);
810 } catch(CUPnPException &e) {
811 wxString error_msg;
812 error_msg << e.what();
813 AddLogLineM(true, error_msg);
814 fprintf(stderr, "%s\n", (const char *)unicode2char(error_msg));
817 #endif
819 return ok;
822 /* Original implementation by Bouc7 of the eMule Project.
823 aMule Signature idea was designed by BigBob and implemented
824 by Un-Thesis, with design inputs and suggestions from bothie.
826 void CamuleApp::OnlineSig(bool zero /* reset stats (used on shutdown) */)
828 // Do not do anything if online signature is disabled in Preferences
829 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path.IsEmpty()) {
830 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
831 // that means m_amulesig_path is empty too.
832 return;
835 // Remove old signature files
836 if ( wxFileExists( m_emulesig_path ) ) { wxRemoveFile( m_emulesig_path ); }
837 if ( wxFileExists( m_amulesig_path ) ) { wxRemoveFile( m_amulesig_path ); }
840 wxTextFile amulesig_out;
841 wxTextFile emulesig_out;
843 // Open both files if needed
844 if ( !emulesig_out.Create( m_emulesig_path) ) {
845 AddLogLineM(true, _("Failed to create OnlineSig File"));
846 // Will never try again.
847 m_amulesig_path.Clear();
848 m_emulesig_path.Clear();
849 return;
852 if ( !amulesig_out.Create(m_amulesig_path) ) {
853 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
854 // Will never try again.
855 m_amulesig_path.Clear();
856 m_emulesig_path.Clear();
857 return;
860 wxString emulesig_string;
861 wxString temp;
863 if (zero) {
864 emulesig_string = wxT("0\xA0.0|0.0|0");
865 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
866 } else {
867 if (IsConnectedED2K()) {
869 temp = wxString::Format(wxT("%d"),serverconnect->GetCurrentServer()->GetPort());
871 // We are online
872 emulesig_string =
873 // Connected
874 wxT("1|")
875 //Server name
876 + serverconnect->GetCurrentServer()->GetListName()
877 + wxT("|")
878 // IP and port of the server
879 + serverconnect->GetCurrentServer()->GetFullIP()
880 + wxT("|")
881 + temp;
884 // Now for amule sig
886 // Connected. State 1, full info
887 amulesig_out.AddLine(wxT("1"));
888 // Server Name
889 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetListName());
890 // Server IP
891 amulesig_out.AddLine(serverconnect->GetCurrentServer()->GetFullIP());
892 // Server Port
893 amulesig_out.AddLine(temp);
895 if (serverconnect->IsLowID()) {
896 amulesig_out.AddLine(wxT("L"));
897 } else {
898 amulesig_out.AddLine(wxT("H"));
901 } else if (serverconnect->IsConnecting()) {
902 emulesig_string = wxT("0");
904 // Connecting. State 2, No info.
905 amulesig_out.AddLine(wxT("2\n0\n0\n0\n0"));
906 } else {
907 // Not connected to a server
908 emulesig_string = wxT("0");
910 // Not connected, state 0, no info
911 amulesig_out.AddLine(wxT("0\n0\n0\n0\n0"));
913 if (IsConnectedKad()) {
914 if(Kademlia::CKademlia::IsFirewalled()) {
915 // Connected. Firewalled. State 1.
916 amulesig_out.AddLine(wxT("1"));
917 } else {
918 // Connected. State 2.
919 amulesig_out.AddLine(wxT("2"));
921 } else {
922 // Not connected.State 0.
923 amulesig_out.AddLine(wxT("0"));
925 emulesig_string += wxT("\xA");
927 // Datarate for downloads
928 temp = wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
930 emulesig_string += temp + wxT("|");
931 amulesig_out.AddLine(temp);
933 // Datarate for uploads
934 temp = wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
936 emulesig_string += temp + wxT("|");
937 amulesig_out.AddLine(temp);
939 // Number of users waiting for upload
940 temp = wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
942 emulesig_string += temp;
943 amulesig_out.AddLine(temp);
945 // Number of shared files (not on eMule)
946 amulesig_out.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
949 // eMule signature finished here. Write the line to the wxTextFile.
950 emulesig_out.AddLine(emulesig_string);
952 // Now for aMule signature extras
954 // Nick on the network
955 amulesig_out.AddLine(thePrefs::GetUserNick());
957 // Total received in bytes
958 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
960 // Total sent in bytes
961 amulesig_out.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
963 // amule version
964 #ifdef SVNDATE
965 amulesig_out.AddLine(wxT(VERSION) wxT(" ") wxT(SVNDATE));
966 #else
967 amulesig_out.AddLine(wxT(VERSION));
968 #endif
970 if (zero) {
971 amulesig_out.AddLine(wxT("0"));
972 amulesig_out.AddLine(wxT("0"));
973 amulesig_out.AddLine(wxT("0"));
974 } else {
975 // Total received bytes in session
976 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
977 theStats::GetSessionReceivedBytes() );
979 // Total sent bytes in session
980 amulesig_out.AddLine( CFormat( wxT("%llu") ) %
981 theStats::GetSessionSentBytes() );
983 // Uptime
984 amulesig_out.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
987 // Flush the files
988 emulesig_out.Write();
989 amulesig_out.Write();
990 } //End Added By Bouc7
993 // Gracefully handle fatal exceptions and print backtrace if possible
994 void CamuleApp::OnFatalException()
996 /* Print the backtrace */
997 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
998 fprintf(stderr, "A fatal error has occurred and aMule has crashed.\n");
999 fprintf(stderr, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1000 fprintf(stderr, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1001 fprintf(stderr, "circumstances of this crash. The forum is located here:\n");
1002 fprintf(stderr, " http://forum.amule.org/index.php?board=67.0\n");
1003 fprintf(stderr, "If possible, please try to generate a real backtrace of this crash:\n");
1004 fprintf(stderr, " http://wiki.amule.org/index.php/Backtraces\n\n");
1005 fprintf(stderr, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1006 fprintf(stderr, "Current version is: %s\n", strFullMuleVersion);
1007 fprintf(stderr, "Running on: %s\n\n", strOSDescription);
1009 print_backtrace(1); // 1 == skip this function.
1011 fprintf(stderr, "\n--------------------------------------------------------------------------------\n");
1015 // Sets the localization of aMule
1016 void CamuleApp::Localize_mule()
1018 InitCustomLanguages();
1019 InitLocale(m_locale, StrLang2wx(thePrefs::GetLanguageID()));
1020 if (!m_locale.IsOk()) {
1021 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1026 // Displays information related to important changes in aMule.
1027 // Is called when the user runs a new version of aMule
1028 void CamuleApp::Trigger_New_version(wxString new_version)
1030 wxString info = wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version + wxT(" ---\n\n");
1031 if (new_version == wxT("SVN")) {
1032 info += _("This version is a testing version, updated daily, and\n");
1033 info += _("we give no warranty it won't break anything, burn your house,\n");
1034 info += _("or kill your dog. But it *should* be safe to use anyway.\n");
1037 // General info
1038 info += wxT("\n");
1039 info += _("More information, support and new releases can found at our homepage,\n");
1040 info += _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1041 info += wxT("\n");
1042 info += _("Feel free to report any bugs to http://forum.amule.org");
1044 ShowAlert(info, _("Info"), wxCENTRE | wxOK | wxICON_ERROR);
1048 void CamuleApp::SetOSFiles(const wxString new_path)
1050 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1051 if ( ::wxDirExists(new_path) ) {
1052 m_emulesig_path = JoinPaths(new_path, wxT("onlinesig.dat"));
1053 m_amulesig_path = JoinPaths(new_path, wxT("amulesig.dat"));
1054 } else {
1055 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);
1056 m_emulesig_path.Clear();
1057 m_amulesig_path.Clear();
1059 } else {
1060 m_emulesig_path.Clear();
1061 m_amulesig_path.Clear();
1066 #ifdef __WXDEBUG__
1067 #ifndef wxUSE_STACKWALKER
1068 #define wxUSE_STACKWALKER 0
1069 #endif
1070 void CamuleApp::OnAssertFailure(const wxChar* file, int line,
1071 const wxChar* func, const wxChar* cond, const wxChar* msg)
1073 if (!wxUSE_STACKWALKER || !wxThread::IsMain() || !IsRunning()) {
1074 wxString errmsg = CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1075 % file % func % line % cond % ( msg ? msg : wxT("") );
1077 fprintf(stderr, "Assertion failed: %s\n", (const char*)unicode2char(errmsg));
1079 // Skip the function-calls directly related to the assert call.
1080 fprintf(stderr, "\nBacktrace follows:\n");
1081 print_backtrace(3);
1082 fprintf(stderr, "\n");
1085 if (wxThread::IsMain() && IsRunning()) {
1086 AMULE_APP_BASE::OnAssertFailure(file, line, func, cond, msg);
1087 } else {
1088 // Abort, allows gdb to catch the assertion
1089 raise( SIGABRT );
1092 #endif
1095 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent& evt)
1097 CServerUDPSocket* socket =(CServerUDPSocket*)evt.GetClientData();
1098 socket->OnHostnameResolved(evt.GetExtraLong());
1102 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent& evt)
1104 downloadqueue->OnHostnameResolved(evt.GetExtraLong());
1108 void CamuleApp::OnServerDnsDone(CMuleInternalEvent& evt)
1110 AddLogLineMS(false, _("Server hostname notified"));
1111 serverconnect->OnServerHostnameResolved(evt.GetClientData(), evt.GetExtraLong());
1115 void CamuleApp::OnTCPTimer(CTimerEvent& WXUNUSED(evt))
1117 if(!IsRunning()) {
1118 return;
1120 serverconnect->StopConnectionTry();
1121 if (IsConnectedED2K() ) {
1122 return;
1124 serverconnect->ConnectToAnyServer();
1128 void CamuleApp::OnCoreTimer(CTimerEvent& WXUNUSED(evt))
1130 // Former TimerProc section
1131 static uint64 msPrev1, msPrev5, msPrevSave, msPrevHist, msPrevOS, msPrevKnownMet;
1132 uint64 msCur = theStats::GetUptimeMillis();
1133 TheTime = msCur / 1000;
1135 if (!IsRunning()) {
1136 return;
1139 #ifndef AMULE_DAEMON
1140 // Check if we should terminate the app
1141 if ( g_shutdownSignal ) {
1142 wxWindow* top = GetTopWindow();
1144 if ( top ) {
1145 top->Close(true);
1146 } else {
1147 // No top-window, have to force termination.
1148 wxExit();
1151 #endif
1153 // There is a theoretical chance that the core time function can recurse:
1154 // if an event function gets blocked on a mutex (communicating with the
1155 // UploadBandwidthThrottler) wx spawns a new event loop and processes more events.
1156 // If CPU load gets high a new core timer event could be generated before the last
1157 // one was finished and so recursion could occur, which would be bad.
1158 // Detect this and do an early return then.
1159 static bool recurse = false;
1160 if (recurse) {
1161 return;
1163 recurse = true;
1165 uploadqueue->Process();
1166 downloadqueue->Process();
1167 //theApp->clientcredits->Process();
1168 theStats::CalculateRates();
1170 if (msCur-msPrevHist > 1000) {
1171 // unlike the other loop counters in this function this one will sometimes
1172 // produce two calls in quick succession (if there was a gap of more than one
1173 // second between calls to TimerProc) - this is intentional! This way the
1174 // history list keeps an average of one node per second and gets thinned out
1175 // correctly as time progresses.
1176 msPrevHist += 1000;
1178 m_statistics->RecordHistory();
1183 if (msCur-msPrev1 > 1000) { // approximately every second
1184 msPrev1 = msCur;
1185 clientcredits->Process();
1186 clientlist->Process();
1188 // Publish files to server if needed.
1189 sharedfiles->Process();
1191 if( Kademlia::CKademlia::IsRunning() ) {
1192 Kademlia::CKademlia::Process();
1193 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1194 StopKad();
1195 clientudp->Close();
1196 clientudp->Open();
1197 if (thePrefs::Reconnect()) {
1198 StartKad();
1203 if( serverconnect->IsConnecting() && !serverconnect->IsSingleConnect() ) {
1204 serverconnect->TryAnotherConnectionrequest();
1206 if (serverconnect->IsConnecting()) {
1207 serverconnect->CheckForTimeout();
1209 listensocket->UpdateConnectionsStatus();
1214 if (msCur-msPrev5 > 5000) { // every 5 seconds
1215 msPrev5 = msCur;
1216 listensocket->Process();
1219 if (msCur-msPrevSave >= 60000) {
1220 msPrevSave = msCur;
1221 wxString buffer;
1223 // Save total upload/download to preferences
1224 wxConfigBase* cfg = wxConfigBase::Get();
1225 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1226 cfg->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer);
1228 buffer = CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1229 cfg->Write(wxT("/Statistics/TotalUploadedBytes"), buffer);
1231 // Write changes to file
1232 cfg->Flush();
1236 // Special
1237 if (msCur - msPrevOS >= thePrefs::GetOSUpdate() * 1000ull) {
1238 OnlineSig(); // Added By Bouc7
1239 msPrevOS = msCur;
1242 if (msCur - msPrevKnownMet >= 30*60*1000/*There must be a prefs option for this*/) {
1243 // Save Shared Files data
1244 knownfiles->Save();
1245 msPrevKnownMet = msCur;
1249 // Recomended by lugdunummaster himself - from emule 0.30c
1250 serverconnect->KeepConnectionAlive();
1252 // Disarm recursion protection
1253 recurse = false;
1257 void CamuleApp::OnFinishedHashing(CHashingEvent& evt)
1259 wxCHECK_RET(evt.GetResult(), wxT("No result of hashing"));
1261 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1262 CKnownFile* result = evt.GetResult();
1264 if (owner) {
1265 // Check if the partfile still exists, as it might have
1266 // been deleted in the mean time.
1267 if (downloadqueue->IsPartFile(owner)) {
1268 // This cast must not be done before the IsPartFile
1269 // call, as dynamic_cast will barf on dangling pointers.
1270 dynamic_cast<CPartFile*>(owner)->PartFileHashFinished(result);
1272 } else {
1273 static int filecount;
1274 static uint64 bytecount;
1276 if (knownfiles->SafeAddKFile(result)) {
1277 AddDebugLogLineM(false, logKnownFiles,
1278 CFormat(wxT("Safe adding file to sharedlist: %s")) % result->GetFileName());
1279 sharedfiles->SafeAddKFile(result);
1281 filecount++;
1282 bytecount += result->GetFileSize();
1283 // If we have added 30 files or files with a total size of ~300mb
1284 if ( ( filecount == 30 ) || ( bytecount >= 314572800 ) ) {
1285 AddDebugLogLineM(false, logKnownFiles, wxT("Failsafe for crash on file hashing creation"));
1286 if ( m_app_state != APP_STATE_SHUTTINGDOWN ) {
1287 knownfiles->Save();
1288 filecount = 0;
1289 bytecount = 0;
1292 } else {
1293 AddDebugLogLineM(false, logKnownFiles,
1294 CFormat(wxT("File not added to sharedlist: %s")) % result->GetFileName());
1295 delete result;
1301 void CamuleApp::OnFinishedAICHHashing(CHashingEvent& evt)
1303 wxCHECK_RET(evt.GetResult(), wxT("No result of AICH-hashing"));
1305 CKnownFile* owner = const_cast<CKnownFile*>(evt.GetOwner());
1306 CScopedPtr<CKnownFile> result(evt.GetResult());
1308 // Check that the owner is still valid
1309 if (knownfiles->IsKnownFile(owner)) {
1310 if (result->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE) {
1311 CAICHHashSet* oldSet = owner->GetAICHHashset();
1312 CAICHHashSet* newSet = result->GetAICHHashset();
1314 owner->SetAICHHashset(newSet);
1315 newSet->SetOwner(owner);
1317 result->SetAICHHashset(oldSet);
1318 oldSet->SetOwner(result.get());
1324 void CamuleApp::OnFinishedCompletion(CCompletionEvent& evt)
1326 CPartFile* completed = const_cast<CPartFile*>(evt.GetOwner());
1327 wxCHECK_RET(completed, wxT("Completion event sent for unspecified file"));
1328 wxASSERT_MSG(downloadqueue->IsPartFile(completed), wxT("CCompletionEvent for unknown partfile."));
1330 completed->CompleteFileEnded(evt.ErrorOccured(), evt.GetFullPath());
1331 if (evt.ErrorOccured()) {
1332 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion, completed);
1335 // Check if we should execute an script/app/whatever.
1336 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted, completed);
1339 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent& evt)
1341 CPartFile *file = evt.GetFile();
1342 wxCHECK_RET(file, wxT("Allocation finished event sent for unspecified file"));
1343 wxASSERT_MSG(downloadqueue->IsPartFile(file), wxT("CAllocFinishedEvent for unknown partfile"));
1345 file->SetPartFileStatus(PS_EMPTY);
1347 if (evt.Succeeded()) {
1348 if (evt.IsPaused()) {
1349 file->StopFile();
1350 } else {
1351 file->ResumeFile();
1353 } else {
1354 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file->GetFileName() % wxString(UTF82unicode(std::strerror(evt.GetResult()))));
1355 file->StopFile();
1358 file->AllocationFinished();
1361 void CamuleApp::OnNotifyEvent(CMuleGUIEvent& evt)
1363 #if defined(AMULE_DAEMON)
1364 evt.Notify();
1365 #else
1366 if (theApp->amuledlg) {
1367 evt.Notify();
1369 #endif
1373 void CamuleApp::ShutDown()
1375 // Log
1376 AddDebugLogLineM(false, logGeneral, wxT("CamuleApp::ShutDown() has started."));
1378 // Signal the hashing thread to terminate
1379 m_app_state = APP_STATE_SHUTTINGDOWN;
1381 StopKad();
1383 // Kry - Save the sources seeds on app exit
1384 if (thePrefs::GetSrcSeedsOn()) {
1385 downloadqueue->SaveSourceSeeds();
1388 OnlineSig(true); // Added By Bouc7
1390 // Exit thread scheduler and upload thread
1391 CThreadScheduler::Terminate();
1393 AddDebugLogLineN(logGeneral, wxT("Terminate upload thread."));
1394 uploadBandwidthThrottler->EndThread();
1396 // Close sockets to avoid new clients coming in
1397 if (listensocket) {
1398 listensocket->Close();
1399 listensocket->KillAllSockets();
1402 if (serverconnect) {
1403 serverconnect->Disconnect();
1406 ECServerHandler->KillAllSockets();
1408 #ifdef ENABLE_UPNP
1409 if (thePrefs::GetUPnPEnabled()) {
1410 if (m_upnp) {
1411 m_upnp->DeletePortMappings(m_upnpMappings);
1414 #endif
1416 // saving data & stuff
1417 if (knownfiles) {
1418 knownfiles->Save();
1421 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1422 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1424 if (glob_prefs) {
1425 glob_prefs->Save();
1428 CPath configFileName = CPath(ConfigDir + m_configFile);
1429 CPath::BackupFile(configFileName, wxT(".bak"));
1431 if (clientlist) {
1432 clientlist->DeleteAll();
1435 // Log
1436 AddDebugLogLineM(false, 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(ConfigDir + 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(ConfigDir + wxT("logfile"))) {
1504 AddLogLineM(false, _("Log has been reset"));
1507 return str;
1511 wxString CamuleApp::GetServerLog(bool reset)
1513 wxString ret = server_msg;
1514 if ( reset ) {
1515 server_msg.Clear();
1517 return ret;
1520 wxString CamuleApp::GetDebugLog(bool reset)
1522 return GetLog(reset);
1526 void CamuleApp::AddServerMessageLine(wxString &msg)
1528 server_msg += msg + wxT("\n");
1529 AddLogLineM(false, CFormat(_("ServerMessage: %s")) % msg);
1534 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent& event)
1536 switch (event.GetInt()) {
1537 case HTTP_IPFilter:
1538 ipfilter->DownloadFinished(event.GetExtraLong());
1539 break;
1540 case HTTP_ServerMet:
1541 serverlist->DownloadFinished(event.GetExtraLong());
1542 break;
1543 case HTTP_ServerMetAuto:
1544 serverlist->AutoDownloadFinished(event.GetExtraLong());
1545 break;
1546 case HTTP_VersionCheck:
1547 CheckNewVersion(event.GetExtraLong());
1548 break;
1549 case HTTP_NodesDat:
1550 if (event.GetExtraLong() == HTTP_Success) {
1552 wxString file = ConfigDir + wxT("nodes.dat");
1553 if (wxFileExists(file)) {
1554 wxRemoveFile(file);
1557 if ( Kademlia::CKademlia::IsRunning() ) {
1558 Kademlia::CKademlia::Stop();
1561 wxRenameFile(file + wxT(".download"),file);
1563 Kademlia::CKademlia::Start();
1564 theApp->ShowConnectionState();
1566 } else if (event.GetExtraLong() == HTTP_Skipped) {
1567 AddLogLineN(CFormat(_("Skipped download of %s, because requested file is not newer.")) % wxT("nodes.dat"));
1568 } else {
1569 AddLogLineC(_("Failed to download the nodes list."));
1571 break;
1572 #ifdef ENABLE_IP2COUNTRY
1573 case HTTP_GeoIP:
1574 theApp->amuledlg->IP2CountryDownloadFinished(event.GetExtraLong());
1575 // If we updated, the dialog is already up. Redraw it to show the flags.
1576 theApp->amuledlg->Refresh();
1577 break;
1578 #endif
1582 void CamuleApp::CheckNewVersion(uint32 result)
1584 if (result == HTTP_Success) {
1585 wxString filename = ConfigDir + wxT("last_version_check");
1586 wxTextFile file;
1588 if (!file.Open(filename)) {
1589 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1590 return;
1591 } else if (!file.GetLineCount()) {
1592 AddLogLineM(true, _("Corrupted version check file"));
1593 } else {
1594 wxString versionLine = file.GetFirstLine();
1595 wxStringTokenizer tkz(versionLine, wxT("."));
1597 AddDebugLogLineM(false, logGeneral, wxString(wxT("Running: ")) + wxT(VERSION) + wxT(", Version check: ") + versionLine);
1599 long fields[] = {0, 0, 0};
1600 for (int i = 0; i < 3; ++i) {
1601 if (!tkz.HasMoreTokens()) {
1602 AddLogLineM(true, _("Corrupted version check file"));
1603 return;
1604 } else {
1605 wxString token = tkz.GetNextToken();
1607 if (!token.ToLong(&fields[i])) {
1608 AddLogLineM(true, _("Corrupted version check file"));
1609 return;
1614 long curVer = make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE);
1615 long newVer = make_full_ed2k_version(fields[0], fields[1], fields[2]);
1617 if (curVer < newVer) {
1618 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1619 AddLogLineM(false, wxString::Format(_("Your aMule version is %i.%i.%i and the latest version is %li.%li.%li"), VERSION_MJR, VERSION_MIN, VERSION_UPDATE, fields[0], fields[1], fields[2]));
1620 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1621 #ifdef AMULE_DAEMON
1622 AddLogLineMS(true, CFormat(_("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"))
1623 % VERSION_MJR % VERSION_MIN % VERSION_UPDATE % fields[0] % fields[1] % fields[2]);
1624 #endif
1625 } else {
1626 AddLogLineM(false, _("Your copy of aMule is up to date."));
1630 file.Close();
1631 wxRemoveFile(filename);
1632 } else {
1633 AddLogLineM(true, _("Failed to download the version check file"));
1639 bool CamuleApp::IsConnected() const
1641 return (IsConnectedED2K() || IsConnectedKad());
1645 bool CamuleApp::IsConnectedED2K() const
1647 return serverconnect && serverconnect->IsConnected();
1651 bool CamuleApp::IsConnectedKad() const
1653 return Kademlia::CKademlia::IsConnected();
1657 bool CamuleApp::IsFirewalled() const
1659 if (theApp->IsConnectedED2K() && !theApp->serverconnect->IsLowID()) {
1660 return false; // we have an eD2K HighID -> not firewalled
1663 return IsFirewalledKad(); // If kad says ok, it's ok.
1666 bool CamuleApp::IsFirewalledKad() const
1668 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1669 || Kademlia::CKademlia::IsFirewalled();
1672 bool CamuleApp::IsFirewalledKadUDP() const
1674 return !Kademlia::CKademlia::IsConnected() // not connected counts as firewalled
1675 || Kademlia::CUDPFirewallTester::IsFirewalledUDP(true);
1678 bool CamuleApp::IsKadRunning() const
1680 return Kademlia::CKademlia::IsRunning();
1683 // Kad stats
1684 uint32 CamuleApp::GetKadUsers() const
1686 return Kademlia::CKademlia::GetKademliaUsers();
1689 uint32 CamuleApp::GetKadFiles() const
1691 return Kademlia::CKademlia::GetKademliaFiles();
1694 uint32 CamuleApp::GetKadIndexedSources() const
1696 return Kademlia::CKademlia::GetIndexed()->m_totalIndexSource;
1699 uint32 CamuleApp::GetKadIndexedKeywords() const
1701 return Kademlia::CKademlia::GetIndexed()->m_totalIndexKeyword;
1704 uint32 CamuleApp::GetKadIndexedNotes() const
1706 return Kademlia::CKademlia::GetIndexed()->m_totalIndexNotes;
1709 uint32 CamuleApp::GetKadIndexedLoad() const
1711 return Kademlia::CKademlia::GetIndexed()->m_totalIndexLoad;
1715 // True IP of machine
1716 uint32 CamuleApp::GetKadIPAdress() const
1718 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetPrefs()->GetIPAddress());
1721 // Buddy status
1722 uint8 CamuleApp::GetBuddyStatus() const
1724 return clientlist->GetBuddyStatus();
1727 uint32 CamuleApp::GetBuddyIP() const
1729 return clientlist->GetBuddy()->GetIP();
1732 uint32 CamuleApp::GetBuddyPort() const
1734 return clientlist->GetBuddy()->GetUDPPort();
1737 bool CamuleApp::CanDoCallback(CUpDownClient *client)
1739 if (Kademlia::CKademlia::IsConnected()) {
1740 if (IsConnectedED2K()) {
1741 if (serverconnect->IsLowID()) {
1742 if (Kademlia::CKademlia::IsFirewalled()) {
1743 //Both Connected - Both Firewalled
1744 return false;
1745 } else {
1746 if (client->GetServerIP() == theApp->serverconnect->GetCurrentServer()->GetIP() &&
1747 client->GetServerPort() == theApp->serverconnect->GetCurrentServer()->GetPort()) {
1748 // Both Connected - Server lowID, Kad Open - Client on same server
1749 // We prevent a callback to the server as this breaks the protocol
1750 // and will get you banned.
1751 return false;
1752 } else {
1753 // Both Connected - Server lowID, Kad Open - Client on remote server
1754 return true;
1757 } else {
1758 //Both Connected - Server HighID, Kad don't care
1759 return true;
1761 } else {
1762 if (Kademlia::CKademlia::IsFirewalled()) {
1763 //Only Kad Connected - Kad Firewalled
1764 return false;
1765 } else {
1766 //Only Kad Conected - Kad Open
1767 return true;
1770 } else {
1771 if (IsConnectedED2K()) {
1772 if (serverconnect->IsLowID()) {
1773 //Only Server Connected - Server LowID
1774 return false;
1775 } else {
1776 //Only Server Connected - Server HighID
1777 return true;
1779 } else {
1780 //We are not connected at all!
1781 return false;
1786 void CamuleApp::ShowUserCount() {
1787 uint32 totaluser = 0, totalfile = 0;
1789 theApp->serverlist->GetUserFileStatus( totaluser, totalfile );
1791 wxString buffer;
1793 static const wxString s_singlenetstatusformat = _("Users: %s | Files: %s");
1794 static const wxString s_bothnetstatusformat = _("Users: E: %s K: %s | Files: E: %s K: %s");
1796 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
1797 buffer = CFormat(s_bothnetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1798 } else if (thePrefs::GetNetworkED2K()) {
1799 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(totaluser) % CastItoIShort(totalfile);
1800 } else if (thePrefs::GetNetworkKademlia()) {
1801 buffer = CFormat(s_singlenetstatusformat) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
1802 } else {
1803 buffer = _("No networks selected");
1806 Notify_ShowUserCount(buffer);
1810 void CamuleApp::ListenSocketHandler(wxSocketEvent& event)
1812 wxCHECK_RET(listensocket, wxT("Connection-event for NULL'd listen-socket"));
1813 wxCHECK_RET(event.GetSocketEvent() == wxSOCKET_CONNECTION,
1814 wxT("Invalid event received for listen-socket"));
1816 if (m_app_state == APP_STATE_RUNNING) {
1817 listensocket->OnAccept(0);
1818 } else if (m_app_state == APP_STATE_STARTING) {
1819 // When starting up, connection may be made before we are able
1820 // to handle them. However, if these are ignored, no futher
1821 // connection-events will be triggered, so we have to accept it.
1822 wxSocketBase* socket = listensocket->Accept(false);
1824 wxCHECK_RET(socket, wxT("NULL returned by Accept() during startup"));
1826 socket->Destroy();
1831 void CamuleApp::ShowConnectionState()
1833 static uint8 old_state = (1<<7); // This flag doesn't exist
1835 uint8 state = 0;
1837 if (theApp->serverconnect->IsConnected()) {
1838 state |= CONNECTED_ED2K;
1841 if (Kademlia::CKademlia::IsRunning()) {
1842 if (Kademlia::CKademlia::IsConnected()) {
1843 if (!Kademlia::CKademlia::IsFirewalled()) {
1844 state |= CONNECTED_KAD_OK;
1845 } else {
1846 state |= CONNECTED_KAD_FIREWALLED;
1848 } else {
1849 state |= CONNECTED_KAD_NOT;
1853 Notify_ShowConnState(state);
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 AddLogLineM(true, CFormat(_("Connected to %s %s")) % connected_server % id);
1871 } else {
1872 if ( theApp->serverconnect->IsConnecting() ) {
1873 AddLogLineM(true, CFormat(_("Connecting to %s")) % connected_server);
1874 } else {
1875 AddLogLineM(true, _("Disconnected from eD2k"));
1880 if (changed_flags & CONNECTED_KAD_NOT) {
1881 if (state & CONNECTED_KAD_NOT) {
1882 AddLogLineM(true, _("Kad started."));
1883 } else {
1884 AddLogLineM(true, _("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 AddLogLineM(true, _("Connected to Kad (ok)"));
1892 } else {
1893 AddLogLineM(true, _("Connected to Kad (firewalled)"));
1895 } else {
1896 AddLogLineM(true, _("Disconnected from Kad"));
1900 old_state = state;
1902 theApp->downloadqueue->OnConnectionState(IsConnected());
1905 ShowUserCount();
1906 Notify_ShowConnState(state);
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 Kademlia::CKademlia::Start();
1958 } else {
1959 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
1961 } else if (!thePrefs::GetNetworkKademlia()) {
1962 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
1966 void CamuleApp::StopKad()
1968 // Stop Kad if it's running
1969 if (Kademlia::CKademlia::IsRunning()) {
1970 Kademlia::CKademlia::Stop();
1975 void CamuleApp::BootstrapKad(uint32 ip, uint16 port)
1977 if (!Kademlia::CKademlia::IsRunning()) {
1978 Kademlia::CKademlia::Start();
1979 theApp->ShowConnectionState();
1982 Kademlia::CKademlia::Bootstrap(ip, port, true);
1986 void CamuleApp::UpdateNotesDat(const wxString& url)
1988 wxString strTempFilename(theApp->ConfigDir + wxT("nodes.dat.download"));
1990 CHTTPDownloadThread *downloader = new CHTTPDownloadThread(url, strTempFilename, theApp->ConfigDir + wxT("nodes.dat"), HTTP_NodesDat);
1991 downloader->Create();
1992 downloader->Run();
1996 void CamuleApp::DisconnectED2K()
1998 // Stop ED2K if it's running
1999 if (IsConnectedED2K()) {
2000 serverconnect->Disconnect();
2004 bool CamuleApp::CryptoAvailable() const
2006 return clientcredits && clientcredits->CryptoAvailable();
2009 uint32 CamuleApp::GetED2KID() const {
2010 return serverconnect ? serverconnect->GetClientID() : 0;
2013 uint32 CamuleApp::GetID() const {
2014 uint32 ID;
2016 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2017 // We trust Kad above ED2K
2018 ID = ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2019 } else if( theApp->serverconnect->IsConnected() ) {
2020 ID = theApp->serverconnect->GetClientID();
2021 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2022 // A firewalled Kad client get's a "1"
2023 ID = 1;
2024 } else {
2025 ID = 0;
2028 return ID;
2031 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD)
2032 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE)
2033 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE)
2034 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE)
2035 // File_checked_for_headers