2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
30 #include "amule.h" // Interface declarations.
34 #include <wx/process.h>
35 #include <wx/sstream.h>
38 #include "config.h" // Needed for HAVE_GETRLIMIT, HAVE_SETRLIMIT,
39 // HAVE_SYS_RESOURCE_H, HAVE_SYS_STATVFS_H, VERSION
43 #include <common/ClientVersion.h>
45 #include <wx/cmdline.h> // Needed for wxCmdLineParser
46 #include <wx/config.h> // Do_not_auto_remove (win32)
47 #include <wx/fileconf.h>
48 #include <wx/snglinst.h>
49 #include <wx/tokenzr.h>
50 #include <wx/wfstream.h>
53 #include <common/Format.h> // Needed for CFormat
54 #include "kademlia/kademlia/Kademlia.h"
55 #include "kademlia/kademlia/Prefs.h"
56 #include "ClientCreditsList.h" // Needed for CClientCreditsList
57 #include "ClientList.h" // Needed for CClientList
58 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket & CMuleUDPSocket
59 #include "ExternalConn.h" // Needed for ExternalConn & MuleConnection
60 #include <common/FileFunctions.h> // Needed for CDirIterator
61 #include "FriendList.h" // Needed for CFriendList
62 #include "HTTPDownload.h" // Needed for CHTTPDownloadThread
63 #include "InternalEvents.h" // Needed for CMuleInternalEvent
64 #include "IPFilter.h" // Needed for CIPFilter
65 #include "KnownFileList.h" // Needed for CKnownFileList
66 #include "ListenSocket.h" // Needed for CListenSocket
67 #include "Logger.h" // Needed for CLogger // Do_not_auto_remove
68 #include "MagnetURI.h" // Needed for CMagnetURI
69 #include "OtherFunctions.h"
70 #include "PartFile.h" // Needed for CPartFile
71 #include "Preferences.h" // Needed for CPreferences
72 #include "SearchList.h" // Needed for CSearchList
73 #include "Server.h" // Needed for GetListName
74 #include "ServerList.h" // Needed for CServerList
75 #include "ServerConnect.h" // Needed for CServerConnect
76 #include "ServerUDPSocket.h" // Needed for CServerUDPSocket
77 #include "Statistics.h" // Needed for CStatistics
78 #include "TerminationProcessAmuleweb.h" // Needed for CTerminationProcessAmuleweb
79 #include "ThreadTasks.h"
80 #include "updownclient.h" // Needed for CUpDownClient
81 #include "UploadQueue.h" // Needed for CUploadQueue
82 #include "UploadBandwidthThrottler.h"
83 #include "UserEvents.h"
86 #include "UPnP.h" // Needed for UPnP
90 #include <wx/sysopt.h> // Do_not_auto_remove
95 #include <CoreFoundation/CFBundle.h> // Do_not_auto_remove
96 #include <wx/mac/corefoundation/cfstring.h> // Do_not_auto_remove
98 #include <wx/msgdlg.h>
100 #include "amuleDlg.h"
104 #ifdef HAVE_SYS_RESOURCE_H
105 #include <sys/resource.h>
108 #ifdef HAVE_SYS_STATVFS_H
109 #include <sys/statvfs.h> // Do_not_auto_remove
114 # define RLIMIT_RESOURCE __rlimit_resource
116 # define RLIMIT_RESOURCE int
119 static void UnlimitResource(RLIMIT_RESOURCE resType
)
121 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT)
123 getrlimit(resType
, &rl
);
124 rl
.rlim_cur
= rl
.rlim_max
;
125 setrlimit(resType
, &rl
);
130 static void SetResourceLimits()
132 #ifdef HAVE_SYS_RESOURCE_H
133 UnlimitResource(RLIMIT_DATA
);
134 UnlimitResource(RLIMIT_FSIZE
);
135 UnlimitResource(RLIMIT_NOFILE
);
137 UnlimitResource(RLIMIT_RSS
);
142 // We store the received signal in order to avoid race-conditions
143 // in the signal handler.
144 bool g_shutdownSignal
= false;
146 void OnShutdownSignal( int /* sig */ )
148 signal(SIGINT
, SIG_DFL
);
149 signal(SIGTERM
, SIG_DFL
);
151 g_shutdownSignal
= true;
154 theApp
->ExitMainLoop();
159 CamuleApp::CamuleApp()
161 // Madcat - Initialize timer as the VERY FIRST thing to avoid any issues later.
162 // Kry - I love to init the vars on init, even before timer.
166 m_app_state
= APP_STATE_STARTING
;
168 theApp
= &wxGetApp();
174 serverconnect
= NULL
;
178 clientcredits
= NULL
;
180 downloadqueue
= NULL
;
183 ECServerHandler
= NULL
;
184 m_singleInstance
= NULL
;
187 uploadBandwidthThrottler
= NULL
;
190 m_upnpMappings
.resize(4);
199 enable_stdout_log
= false;
200 enable_daemon_fork
= false;
202 strFullMuleVersion
= NULL
;
203 strOSDescription
= NULL
;
205 // Apprently needed for *BSD
209 CamuleApp::~CamuleApp()
211 // Closing the log-file as the very last thing, since
212 // wxWidgets log-events are saved in it as well.
216 free(strFullMuleVersion
);
217 free(strOSDescription
);
220 int CamuleApp::OnExit()
222 if (m_app_state
!=APP_STATE_STARTING
) {
223 printf("Now, exiting main app...\n");
226 // From wxWidgets docs, wxConfigBase:
228 // Note that you must delete this object (usually in wxApp::OnExit)
229 // in order to avoid memory leaks, wxWidgets won't do it automatically.
231 // As it happens, you may even further simplify the procedure described
232 // above: you may forget about calling Set(). When Get() is called and
233 // there is no current object, it will create one using Create() function.
234 // To disable this behaviour DontCreateOnDemand() is provided.
235 delete wxConfigBase::Set((wxConfigBase
*)NULL
);
238 clientcredits
->SaveList();
240 // Kill amuleweb if running
242 printf("Killing amuleweb instance with pid `%ld' ... ", webserver_pid
);
244 wxKill(webserver_pid
, wxSIGTERM
, &rc
);
248 if (m_app_state
!=APP_STATE_STARTING
) {
249 printf("aMule OnExit: Terminating core.\n");
258 delete clientcredits
;
259 clientcredits
= NULL
;
264 // Destroying CDownloadQueue calls destructor for CPartFile
265 // calling CSharedFileList::SafeAddKFile occasionally.
269 delete serverconnect
;
270 serverconnect
= NULL
;
287 delete downloadqueue
;
288 downloadqueue
= NULL
;
298 delete ECServerHandler
;
299 ECServerHandler
= NULL
;
306 CPreferences::EraseItemList();
308 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
309 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
311 delete m_singleInstance
;
313 m_singleInstance
= NULL
;
315 delete uploadBandwidthThrottler
;
316 uploadBandwidthThrottler
= NULL
;
318 if (m_app_state
!=APP_STATE_STARTING
) {
319 printf("aMule shutdown completed.\n");
322 #if wxUSE_MEMORY_TRACING
323 printf("Memory debug results for aMule exit:\n");
324 // Log mem debug mesages to wxLogStderr
325 wxLog
* oldLog
= wxLog::SetActiveTarget(new wxLogStderr
);
327 printf("**************Classes**************\n");
328 wxDebugContext::PrintClasses();
330 //printf("***************Dump***************\n");
331 //wxDebugContext::Dump();
332 printf("***************Stats**************\n");
333 wxDebugContext::PrintStatistics(true);
335 // Set back to wxLogGui
336 delete wxLog::SetActiveTarget(oldLog
);
341 // Return 0 for succesful program termination
342 return AMULE_APP_BASE::OnExit();
346 int CamuleApp::InitGui(bool, wxString
&)
353 * Checks permissions on a aMule directory, creating if needed.
355 * @param desc A description of the directory in question, used for error messages.
356 * @param directory The directory in question.
357 * @param fallback If the dir specified with 'directory' could not be created, try this instead.
358 * @return The bool is false on error. The wxString contains the used path.
360 std::pair
<bool, CPath
> CheckMuleDirectory(const wxString
& desc
, const CPath
& directory
, const wxString
& alternative
)
364 if (directory
.IsDir(CPath::readwritable
)) {
365 return std::pair
<bool, CPath
>(true, directory
);
366 } else if (directory
.DirExists()) {
367 msg
= CFormat(wxT("Permissions on the %s directory too strict!\n")
368 wxT("aMule cannot proceed. To fix this, you must set read/write/exec\n")
369 wxT("permissions for the folder '%s'"))
371 } else if (CPath::MakeDir(directory
)) {
372 return std::pair
<bool, CPath
>(true, directory
);
374 msg
<< CFormat(wxT("Could not create the %s directory at '%s'."))
378 // Attempt to use fallback directory.
379 const CPath fallback
= CPath(alternative
);
380 if (fallback
.IsOk() && (directory
!= fallback
)) {
381 msg
<< wxT("\nAttempting to use default directory at location \n'")
382 << alternative
<< wxT("'.");
383 theApp
->ShowAlert(msg
, wxT("Error accessing directory."), wxICON_ERROR
| wxOK
);
385 return CheckMuleDirectory(desc
, fallback
, wxEmptyString
);
388 theApp
->ShowAlert(msg
, wxT("Fatal error."), wxICON_ERROR
| wxOK
);
389 return std::pair
<bool, wxString
>(false, wxEmptyString
);
394 // Application initialization
396 bool CamuleApp::OnInit()
398 #if wxUSE_MEMORY_TRACING
399 printf("Checkpoint set on app init for memory debug\n");
400 wxDebugContext::SetCheckpoint();
403 // Forward wxLog events to CLogger
404 wxLog::SetActiveTarget(new CLoggerTarget
);
406 m_localip
= StringHosttoUint32(::wxGetFullHostName());
409 // get rid of sigpipe
410 signal(SIGPIPE
, SIG_IGN
);
411 // Handle sigint and sigterm
412 signal(SIGINT
, OnShutdownSignal
);
413 signal(SIGTERM
, OnShutdownSignal
);
417 // For listctrl's to behave on Mac
418 wxSystemOptions::SetOption(wxT("mac.listctrl.always_use_generic"), 1);
421 // This can't be on constructor or wx2.4.2 doesn't set it.
422 #if !wxCHECK_VERSION(2, 9, 0)
423 SetVendorName(wxT("TikuWarez"));
425 SetAppName(wxT("aMule"));
427 wxString FullMuleVersion
= GetFullMuleVersion();
428 wxString OSDescription
= wxGetOsDescription();
429 strFullMuleVersion
= strdup((const char *)unicode2char(FullMuleVersion
));
430 strOSDescription
= strdup((const char *)unicode2char(OSDescription
));
431 OSType
= OSDescription
.BeforeFirst( wxT(' ') );
432 if ( OSType
.IsEmpty() ) {
433 OSType
= wxT("Unknown");
436 // Handle uncaught exceptions
437 InstallMuleExceptionHandler();
439 // Parse cmdline arguments.
440 wxCmdLineParser
cmdline(AMULE_APP_BASE::argc
, AMULE_APP_BASE::argv
);
442 // Handle these arguments.
443 cmdline
.AddSwitch(wxT("v"), wxT("version"), wxT("Displays the current version number."));
444 cmdline
.AddSwitch(wxT("h"), wxT("help"), wxT("Displays this information."));
445 cmdline
.AddSwitch(wxT("i"), wxT("enable-stdin"), wxT("Does not disable stdin."));
447 cmdline
.AddSwitch(wxT("f"), wxT("full-daemon"), wxT("Fork to background."));
448 cmdline
.AddOption(wxT("c"), wxT("config-dir"), wxT("read config from <dir> instead of home"));
449 cmdline
.AddSwitch(wxT("e"), wxT("ec-config"), wxT("Configure EC (External Connections)."));
451 cmdline
.AddOption(wxT("geometry"), wxEmptyString
,
452 wxT("Sets the geometry of the app.\n")
453 wxT("\t\t\t<str> uses the same format as standard X11 apps:\n")
454 wxT("\t\t\t[=][<width>{xX}<height>][{+-}<xoffset>{+-}<yoffset>]"));
456 cmdline
.AddSwitch(wxT("d"), wxT("disable-fatal"), wxT("Does not handle fatal exception."));
457 cmdline
.AddSwitch(wxT("o"), wxT("log-stdout"), wxT("Print log messages to stdout."));
458 cmdline
.AddSwitch(wxT("r"), wxT("reset-config"), wxT("Resets config to default values."));
460 // Show help on --help or invalid commands
461 if ( cmdline
.Parse() ) {
463 } else if ( cmdline
.Found(wxT("help")) ) {
468 bool ec_config
= false;
471 ec_config
= cmdline
.Found(wxT("ec-config"));
472 if ( cmdline
.Found(wxT("config-dir"), &ConfigDir
) ) {
473 if (ConfigDir
.Last() != wxFileName::GetPathSeparator()) {
474 ConfigDir
+= wxFileName::GetPathSeparator();
477 ConfigDir
= GetConfigDir();
480 ConfigDir
= GetConfigDir();
483 if ( !cmdline
.Found(wxT("disable-fatal")) ) {
485 // catch fatal exceptions
486 wxHandleFatalExceptions(true);
490 bool reset_config
= cmdline
.Found(wxT("reset-config"));
492 enable_stdout_log
= cmdline
.Found(wxT("log-stdout"));
494 enable_daemon_fork
= cmdline
.Found(wxT("full-daemon"));
496 enable_daemon_fork
= false;
499 if ( enable_stdout_log
) {
500 if ( enable_daemon_fork
) {
501 printf("Daemon will fork to background - log to stdout disabled\n");
502 enable_stdout_log
= false;
504 printf("Logging to stdout enabled\n");
508 if ( cmdline
.Found(wxT("version")) ) {
509 printf("%s (OS: %s)\n",
510 (const char*)unicode2char(GetFullMuleVersion()),
511 (const char*)unicode2char(OSType
));
516 // Default geometry of the GUI. Can be changed with a cmdline argument...
517 bool geometry_enabled
= false;
518 wxString geom_string
;
520 if ( cmdline
.Found(wxT("geometry"), &geom_string
) ) {
521 geometry_enabled
= true;
526 printf("Initialising aMule\n");
528 // Ensure that "~/.aMule/" is accessible.
529 if (!CheckMuleDirectory(wxT("configuration"), CPath(ConfigDir
), wxEmptyString
).first
) {
534 // Make a backup first.
535 wxRemoveFile(ConfigDir
+ wxT("amule.conf.backup"));
536 wxRenameFile(ConfigDir
+ wxT("amule.conf"), ConfigDir
+ wxT("amule.conf.backup"));
537 printf("Your settings have ben resetted to default values.\nOld config file has been saved as amule.conf.backup\n");
540 #if defined(__WXMAC__) && defined(AMULE_DAEMON)
541 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
542 printf("WARNING: The check for other instances is currently disabled in amuled.\n"
543 "Please make sure that no other instance of aMule is running or your files might be corrupted.\n");
545 printf("Checking if there is an instance already running...\n");
547 m_singleInstance
= new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir
);
548 if (m_singleInstance
->IsAnotherRunning()) {
549 printf("There is an instance of aMule already running\n");
551 // This is very tricky. The most secure way to communicate is via ED2K links file
552 wxTextFile
ed2kFile(ConfigDir
+ wxT("ED2KLinks"));
553 if (!ed2kFile
.Exists()) {
557 if (ed2kFile
.Open()) {
558 ed2kFile
.AddLine(wxT("RAISE_DIALOG"));
561 printf("Raising current running instance.\n");
563 printf("Failed to open 'ED2KFile', cannot signal running instance.\n");
568 printf("No other instances are running.\n");
572 // Close standard-input
573 if ( !cmdline
.Found(wxT("enable-stdin")) ) {
574 // The full daemon will close all std file-descriptors by itself,
575 // so closing it here would lead to the closing on the first open
576 // file, which is the logfile opened below
577 if (!enable_daemon_fork
) {
582 // This creates the CFG file we shall use
583 wxConfigBase
* cfg
= new wxFileConfig( wxEmptyString
, wxEmptyString
, ConfigDir
+ wxT("amule.conf") );
585 // Set the config object as the global cfg file
586 wxConfig::Set( cfg
);
588 // Make a backup of the log file
589 CPath logfileName
= CPath(ConfigDir
+ wxT("logfile"));
590 if (logfileName
.FileExists()) {
591 CPath::BackupFile(logfileName
, wxT(".bak"));
595 applog
= new wxFFileOutputStream(logfileName
.GetRaw());
597 // use std err as last resolt to indicate problem
598 fputs("ERROR: unable to open log file\n", stderr
);
601 // failure to open log is serious problem
606 CPreferences::BuildItemList(ConfigDir
);
607 CPreferences::LoadAllItems( wxConfigBase::Get() );
609 glob_prefs
= new CPreferences();
611 std::pair
<bool, CPath
> checkResult
;
612 checkResult
= CheckMuleDirectory(wxT("temp"), thePrefs::GetTempDir(), ConfigDir
+ wxT("Temp"));
613 if (checkResult
.first
) {
614 thePrefs::SetTempDir(checkResult
.second
);
619 checkResult
= CheckMuleDirectory(wxT("incoming"), thePrefs::GetIncomingDir(), ConfigDir
+ wxT("Incoming"));
620 if (checkResult
.first
) {
621 thePrefs::SetIncomingDir(checkResult
.second
);
627 if (!thePrefs::UseTrayIcon()) {
628 thePrefs::SetMinToTray(false);
631 // Build the filenames for the two OS files
632 SetOSFiles(thePrefs::GetOSDir().GetRaw());
635 // Load localization settings
639 // Configure EC for amuled when invoked with ec-config
641 printf("\nEC configuration\n");
642 thePrefs::SetECPass(GetPassword());
643 thePrefs::EnableExternalConnections(true);
644 printf("Password set and external connections enabled.\n");
647 // Display notification on new version or first run
648 wxTextFile
vfile( ConfigDir
+ wxT("lastversion") );
649 wxString
newMule(wxT( VERSION
));
651 // Test if there's any new version
652 if (thePrefs::CheckNewVersion()) {
653 // We use the thread base because I don't want a dialog to pop up.
654 CHTTPDownloadThread
* version_check
=
655 new CHTTPDownloadThread(wxT("http://amule.sourceforge.net/lastversion"),
656 theApp
->ConfigDir
+ wxT("last_version_check"), HTTP_VersionCheck
, false);
657 version_check
->Create();
658 version_check
->Run();
661 if ( !wxFileExists( vfile
.GetName() ) ) {
668 wxT("Warning! You are running aMule as root.\n")
669 wxT("Doing so is not recommended for security reasons,\n")
670 wxT("and you are advised to run aMule as an normal\n")
671 wxT("user instead.");
673 ShowAlert(msg
, _("Warning"), wxCENTRE
| wxOK
| wxICON_ERROR
);
675 fprintf(stderr
, "\n--------------------------------------------------\n");
676 fprintf(stderr
, "%s", (const char*)unicode2UTF8(msg
));
677 fprintf(stderr
, "\n--------------------------------------------------\n\n");
681 if ( vfile
.Open() ) {
682 // Check if this version has been run before
684 for ( size_t i
= 0; i
< vfile
.GetLineCount(); i
++ ) {
685 // Check if this version has been run before
686 if ( vfile
.GetLine(i
) == newMule
) {
692 // We havent run this version before?
694 // Insert new at top to provide faster searches
695 vfile
.InsertLine( newMule
, 0 );
697 Trigger_New_version( newMule
);
700 // Keep at most 10 entires
701 while ( vfile
.GetLineCount() > 10 )
702 vfile
.RemoveLine( vfile
.GetLineCount() - 1 );
708 // Check if we have the old style locale config
709 wxString langId
= thePrefs::GetLanguageID();
710 if (!langId
.IsEmpty() && (langId
.GetChar(0) >= '0' && langId
.GetChar(0) <= '9')) {
711 wxString
info(_("Your locale has been changed to System Default due to a configuration change. Sorry."));
712 thePrefs::SetLanguageID(wxLang2Str(wxLANGUAGE_DEFAULT
));
713 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
716 m_statistics
= new CStatistics();
718 clientlist
= new CClientList();
719 friendlist
= new CFriendList();
720 searchlist
= new CSearchList();
721 knownfiles
= new CKnownFileList();
722 serverlist
= new CServerList();
724 sharedfiles
= new CSharedFileList(knownfiles
);
725 clientcredits
= new CClientCreditsList();
727 // bugfix - do this before creating the uploadqueue
728 downloadqueue
= new CDownloadQueue();
729 uploadqueue
= new CUploadQueue();
730 ipfilter
= new CIPFilter();
732 // Creates all needed listening sockets
734 if (!ReinitializeNetwork(&msg
)) {
735 printf("\n%s\n", (const char *)unicode2char(msg
));
738 // Create main dialog, or fork to background (daemon).
739 InitGui(geometry_enabled
, geom_string
);
741 #if !defined(__WXMAC__) && defined(AMULE_DAEMON)
742 // Need to refresh wxSingleInstanceChecker after the daemon fork() !
743 if (enable_daemon_fork
) {
744 //#warning TODO: fix wxSingleInstanceChecker for amuled on Mac (wx link problems)
745 delete m_singleInstance
;
746 m_singleInstance
= new wxSingleInstanceChecker(wxT("muleLock"), ConfigDir
);
747 // No need to check IsAnotherRunning() - we've done it before.
751 // Has to be created after the call to InitGui, as fork
752 // (when using posix threads) only replicates the mainthread,
753 // and the UBT constructor creates a thread.
754 uploadBandwidthThrottler
= new UploadBandwidthThrottler();
756 // These must be initialized after the gui is loaded.
758 downloadqueue
->LoadMetFiles(thePrefs::GetTempDir());
759 sharedfiles
->Reload();
761 if (thePrefs::IPFilterAutoLoad()) {
762 ipfilter
->Update(thePrefs::IPFilterURL());
766 // Ensure that the up/down ratio is used
767 CPreferences::CheckUlDlRatio();
769 // The user can start pressing buttons like mad if he feels like it.
770 m_app_state
= APP_STATE_RUNNING
;
772 // Kry - Load the sources seeds on app init
773 if (thePrefs::GetSrcSeedsOn()) {
774 downloadqueue
->LoadSourceSeeds();
777 if (!serverlist
->GetServerCount() && thePrefs::GetNetworkED2K()) {
778 // There are no servers and ED2K active -> ask for download.
779 // As we cannot ask in amuled, we just update there
780 // Kry TODO: Store server.met URL on preferences and use it here and in GUI.
782 if (wxYES
== wxMessageBox(
784 _("You don't have any server in the server list.\nDo you want aMule to download a new list now?")),
785 wxString(_("Server list download")),
787 static_cast<wxWindow
*>(theApp
->amuledlg
)))
790 // workaround amuled crash
792 serverlist
->UpdateServerMetFromURL(
793 wxT("http://gruk.org/server.met.gz"));
799 // Autoconnect if that option is enabled
800 if (thePrefs::DoAutoConnect() && (thePrefs::GetNetworkED2K() || thePrefs::GetNetworkKademlia())) {
801 AddLogLineM(true, _("Connecting"));
802 if (thePrefs::GetNetworkED2K()) {
803 theApp
->serverconnect
->ConnectToAnyServer();
810 // No webserver on Win at all (yet)
813 if (thePrefs::GetWSIsEnabled()) {
814 wxString aMuleConfigFile
= ConfigDir
+ wxT("amule.conf");
815 wxString amulewebPath
= wxT("amuleweb");
817 #if defined(__WXMAC__) && !defined(AMULE_DAEMON)
818 // For the Mac GUI application, look for amuleweb in the bundle
819 CFURLRef amulewebUrl
= CFBundleCopyAuxiliaryExecutableURL(
820 CFBundleGetMainBundle(), CFSTR("amuleweb"));
823 CFURLRef absoluteUrl
= CFURLCopyAbsoluteURL(amulewebUrl
);
824 CFRelease(amulewebUrl
);
827 CFStringRef amulewebCfstr
= CFURLCopyFileSystemPath(absoluteUrl
, kCFURLPOSIXPathStyle
);
828 CFRelease(absoluteUrl
);
829 amulewebPath
= wxMacCFStringHolder(amulewebCfstr
).AsString(wxLocale::GetSystemEncoding());
837 wxT("' '--amule-config-file=") +
840 CTerminationProcessAmuleweb
*p
= new CTerminationProcessAmuleweb(cmd
, &webserver_pid
);
841 webserver_pid
= wxExecute(cmd
, wxEXEC_ASYNC
, p
);
842 bool webserver_ok
= webserver_pid
> 0;
844 AddLogLineM(true, CFormat(_("webserver running on pid %d")) % webserver_pid
);
848 "You requested to run webserver from startup, "
849 "but the amuleweb binary cannot be run. "
850 "Please install the package containing aMule webserver, "
851 "or compile aMule using --enable-webserver and run make install"),
852 _("Error"), wxOK
| wxICON_ERROR
);
855 #endif /* ! __WXMSW__ */
857 // Start performing background tasks
858 CThreadScheduler::Start();
863 bool CamuleApp::ReinitializeNetwork(wxString
* msg
)
866 static bool firstTime
= true;
869 // TODO: Destroy previously created sockets
873 // Some sanity checks first
874 if (thePrefs::ECPort() == thePrefs::GetPort()) {
875 // Select a random usable port in the range 1025 ... 2^16 - 1
876 uint16 port
= thePrefs::ECPort();
877 while ( port
< 1024 || port
== thePrefs::GetPort() ) {
878 port
= (uint16
)rand();
880 thePrefs::SetECPort( port
);
883 wxT("Network configuration failed! You cannot use the same port\n")
884 wxT("for the main TCP port and the External Connections port.\n")
885 wxT("The EC port has been changed to avoid conflict, see the\n")
886 wxT("preferences for the new value.\n");
889 AddLogLineM( false, wxEmptyString
);
890 AddLogLineM( true, err
);
891 AddLogLineM( false, wxEmptyString
);
896 if (thePrefs::GetUDPPort() == thePrefs::GetPort() + 3) {
897 // Select a random usable value in the range 1025 ... 2^16 - 1
898 uint16 port
= thePrefs::GetUDPPort();
899 while ( port
< 1024 || port
== thePrefs::GetPort() + 3 ) {
900 port
= (uint16
)rand();
902 thePrefs::SetUDPPort( port
);
905 wxT("Network configuration failed! You set your UDP port to\n")
906 wxT("the value of the main TCP port plus 3.\n")
907 wxT("This port has been reserved for the Server-UDP port. The\n")
908 wxT("port value has been changed to avoid conflict, see the\n")
909 wxT("preferences for the new value\n");
912 AddLogLineM( false, wxEmptyString
);
913 AddLogLineM( true, err
);
914 AddLogLineM( false, wxEmptyString
);
919 // Create the address where we are going to listen
920 // TODO: read this from configuration file
921 amuleIPV4Address myaddr
[4];
923 // Create the External Connections Socket.
925 // Get ready to handle connections from apps like amulecmd
926 if (thePrefs::GetECAddress().IsEmpty() || !myaddr
[0].Hostname(thePrefs::GetECAddress())) {
927 myaddr
[0].AnyAddress();
929 myaddr
[0].Service(thePrefs::ECPort());
930 ECServerHandler
= new ExternalConn(myaddr
[0], msg
);
932 // Create the UDP socket TCP+3.
933 // Used for source asking on servers.
934 if (thePrefs::GetAddress().IsEmpty()) {
935 myaddr
[1].AnyAddress();
936 } else if (!myaddr
[1].Hostname(thePrefs::GetAddress())) {
937 myaddr
[1].AnyAddress();
938 AddLogLineM(true, CFormat(_("Could not bind ports to the specified address: %s"))
939 % thePrefs::GetAddress());
942 wxString ip
= myaddr
[1].IPAddress();
943 myaddr
[1].Service(thePrefs::GetPort()+3);
944 serverconnect
= new CServerConnect(serverlist
, myaddr
[1]);
945 *msg
<< CFormat( wxT("*** Server UDP socket (TCP+3) at %s:%u\n") )
946 % ip
% ((unsigned int)thePrefs::GetPort() + 3u);
948 // Create the ListenSocket (aMule TCP socket).
949 // Used for Client Port / Connections from other clients,
950 // Client to Client Source Exchange.
952 myaddr
[2] = myaddr
[1];
953 myaddr
[2].Service(thePrefs::GetPort());
954 listensocket
= new CListenSocket(myaddr
[2]);
955 *msg
<< CFormat( wxT("*** TCP socket (TCP) listening on %s:%u\n") )
956 % ip
% (unsigned int)(thePrefs::GetPort());
957 // This command just sets a flag to control maximum number of connections.
958 // Notify(true) has already been called to the ListenSocket, so events may
959 // be already comming in.
960 if (listensocket
->Ok()) {
961 listensocket
->StartListening();
963 // If we wern't able to start listening, we need to warn the user
965 err
= CFormat(_("Port %u is not available. You will be LOWID\n")) %
966 (unsigned int)(thePrefs::GetPort());
968 AddLogLineM(true, err
);
971 _("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.")) %
972 (unsigned int)(thePrefs::GetPort());
973 ShowAlert(err
, _("Error"), wxOK
| wxICON_ERROR
);
976 // Create the UDP socket.
977 // Used for extended eMule protocol, Queue Rating, File Reask Ping.
978 // Also used for Kademlia.
979 // Default is port 4672.
980 myaddr
[3] = myaddr
[1];
981 myaddr
[3].Service(thePrefs::GetUDPPort());
982 clientudp
= new CClientUDPSocket(myaddr
[3], thePrefs::GetProxyData());
983 if (!thePrefs::IsUDPDisabled()) {
984 *msg
<< CFormat( wxT("*** Client UDP socket (extended eMule) at %s:%u") )
985 % ip
% thePrefs::GetUDPPort();
987 *msg
<< wxT("*** Client UDP socket (extended eMule) disabled on preferences");
991 if (thePrefs::GetUPnPEnabled()) {
993 m_upnpMappings
[0] = CUPnPPortMapping(
996 thePrefs::GetUPnPECEnabled(),
997 "aMule TCP External Connections Socket");
998 m_upnpMappings
[1] = CUPnPPortMapping(
1001 thePrefs::GetUPnPEnabled(),
1002 "aMule UDP socket (TCP+3)");
1003 m_upnpMappings
[2] = CUPnPPortMapping(
1004 myaddr
[2].Service(),
1006 thePrefs::GetUPnPEnabled(),
1007 "aMule TCP Listen Socket");
1008 m_upnpMappings
[3] = CUPnPPortMapping(
1009 myaddr
[3].Service(),
1011 thePrefs::GetUPnPEnabled(),
1012 "aMule UDP Extended eMule Socket");
1013 m_upnp
= new CUPnPControlPoint(thePrefs::GetUPnPTCPPort());
1014 m_upnp
->AddPortMappings(m_upnpMappings
);
1015 } catch(CUPnPException
&e
) {
1017 error_msg
<< e
.what();
1018 AddLogLineM(true, error_msg
);
1019 fprintf(stderr
, "%s\n", (const char *)unicode2char(error_msg
));
1027 // Returns a magnet ed2k URI
1028 wxString
CamuleApp::CreateMagnetLink(const CAbstractFile
*f
)
1032 uri
.AddField(wxT("dn"), f
->GetFileName().Cleanup(false).GetPrintable());
1033 uri
.AddField(wxT("xt"), wxString(wxT("urn:ed2k:")) + f
->GetFileHash().Encode().Lower());
1034 uri
.AddField(wxT("xl"), wxString::Format(wxT("%") wxLongLongFmtSpec
wxT("u"), f
->GetFileSize()));
1036 return uri
.GetLink();
1039 // Returns a ed2k file URL
1040 wxString
CamuleApp::CreateED2kLink(const CAbstractFile
*f
, bool add_source
, bool use_hostname
, bool addcryptoptions
)
1042 wxASSERT(!(!add_source
&& (use_hostname
|| addcryptoptions
)));
1043 // Construct URL like this: ed2k://|file|<filename>|<size>|<hash>|/
1044 wxString strURL
= CFormat(wxT("ed2k://|file|%s|%i|%s|/"))
1045 % f
->GetFileName().Cleanup(false)
1046 % f
->GetFileSize() % f
->GetFileHash().Encode();
1048 if (add_source
&& IsConnected() && !IsFirewalled()) {
1049 // Create the first part of the URL
1050 strURL
<< wxT("|sources,");
1052 strURL
<< thePrefs::GetYourHostname();
1054 uint32 clientID
= GetID();
1055 strURL
<< (uint8
) clientID
<< wxT(".") <<
1056 (uint8
)(clientID
>> 8) << wxT(".") <<
1057 (uint8
)(clientID
>> 16) << wxT(".") <<
1058 (uint8
)(clientID
>> 24);
1061 strURL
<< wxT(":") <<
1062 thePrefs::GetPort();
1064 if (addcryptoptions
) {
1065 const uint8 uSupportsCryptLayer
= thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1066 const uint8 uRequestsCryptLayer
= thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1067 const uint8 uRequiresCryptLayer
= thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1068 const uint8 byCryptOptions
= (uRequiresCryptLayer
<< 2) | (uRequestsCryptLayer
<< 1) | (uSupportsCryptLayer
<< 0) | (uSupportsCryptLayer
? 0x80 : 0x00);
1070 strURL
<< wxT(":") << byCryptOptions
;
1072 if (byCryptOptions
& 0x80) {
1073 strURL
<< wxT(":") << thePrefs::GetUserHash().Encode();
1076 strURL
<< wxT("|/");
1077 } else if (add_source
) {
1078 AddLogLineM(true, _("WARNING: You can't add yourself as a source for a ed2k link while being lowid."));
1081 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|sources,[(<ip>|<hostname>):<port>[:cryptoptions[:hash]]]|/"
1085 // Returns a ed2k link with AICH info if available
1086 wxString
CamuleApp::CreateED2kAICHLink(const CKnownFile
* f
)
1088 // Create the first part of the URL
1089 wxString strURL
= CreateED2kLink(f
);
1090 // Append the AICH info
1091 if (f
->HasProperAICHHashSet()) {
1092 strURL
<< wxT("|h=") << f
->GetAICHMasterHash() << wxT("|/");
1095 // Result is "ed2k://|file|<filename>|<size>|<hash>|/|h=<AICH master hash>|/"
1099 /* Original implementation by Bouc7 of the eMule Project.
1100 aMule Signature idea was designed by BigBob and implemented
1101 by Un-Thesis, with design inputs and suggestions from bothie.
1103 void CamuleApp::OnlineSig(bool zero
/* reset stats (used on shutdown) */)
1105 // Do not do anything if online signature is disabled in Preferences
1106 if (!thePrefs::IsOnlineSignatureEnabled() || m_emulesig_path
.IsEmpty()) {
1107 // We do not need to check m_amulesig_path because if m_emulesig_path is empty,
1108 // that means m_amulesig_path is empty too.
1112 // Remove old signature files
1113 if ( wxFileExists( m_emulesig_path
) ) { wxRemoveFile( m_emulesig_path
); }
1114 if ( wxFileExists( m_amulesig_path
) ) { wxRemoveFile( m_amulesig_path
); }
1117 wxTextFile amulesig_out
;
1118 wxTextFile emulesig_out
;
1120 // Open both files if needed
1121 if ( !emulesig_out
.Create( m_emulesig_path
) ) {
1122 AddLogLineM(true, _("Failed to create OnlineSig File"));
1123 // Will never try again.
1124 m_amulesig_path
.Clear();
1125 m_emulesig_path
.Clear();
1129 if ( !amulesig_out
.Create(m_amulesig_path
) ) {
1130 AddLogLineM(true, _("Failed to create aMule OnlineSig File"));
1131 // Will never try again.
1132 m_amulesig_path
.Clear();
1133 m_emulesig_path
.Clear();
1137 wxString emulesig_string
;
1141 emulesig_string
= wxT("0\xA0.0|0.0|0");
1142 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0\n0\n0.0\n0.0\n0\n0"));
1144 if (IsConnectedED2K()) {
1146 temp
= wxString::Format(wxT("%d"),serverconnect
->GetCurrentServer()->GetPort());
1153 + serverconnect
->GetCurrentServer()->GetListName()
1155 // IP and port of the server
1156 + serverconnect
->GetCurrentServer()->GetFullIP()
1161 // Now for amule sig
1163 // Connected. State 1, full info
1164 amulesig_out
.AddLine(wxT("1"));
1166 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetListName());
1168 amulesig_out
.AddLine(serverconnect
->GetCurrentServer()->GetFullIP());
1170 amulesig_out
.AddLine(temp
);
1172 if (serverconnect
->IsLowID()) {
1173 amulesig_out
.AddLine(wxT("L"));
1175 amulesig_out
.AddLine(wxT("H"));
1178 } else if (serverconnect
->IsConnecting()) {
1179 emulesig_string
= wxT("0");
1181 // Connecting. State 2, No info.
1182 amulesig_out
.AddLine(wxT("2\n0\n0\n0\n0"));
1184 // Not connected to a server
1185 emulesig_string
= wxT("0");
1187 // Not connected, state 0, no info
1188 amulesig_out
.AddLine(wxT("0\n0\n0\n0\n0"));
1190 if (IsConnectedKad()) {
1191 if(Kademlia::CKademlia::IsFirewalled()) {
1192 // Connected. Firewalled. State 1.
1193 amulesig_out
.AddLine(wxT("1"));
1195 // Connected. State 2.
1196 amulesig_out
.AddLine(wxT("2"));
1199 // Not connected.State 0.
1200 amulesig_out
.AddLine(wxT("0"));
1202 emulesig_string
+= wxT("\xA");
1204 // Datarate for downloads
1205 temp
= wxString::Format(wxT("%.1f"), theStats::GetDownloadRate() / 1024.0);
1207 emulesig_string
+= temp
+ wxT("|");
1208 amulesig_out
.AddLine(temp
);
1210 // Datarate for uploads
1211 temp
= wxString::Format(wxT("%.1f"), theStats::GetUploadRate() / 1024.0);
1213 emulesig_string
+= temp
+ wxT("|");
1214 amulesig_out
.AddLine(temp
);
1216 // Number of users waiting for upload
1217 temp
= wxString::Format(wxT("%d"), theStats::GetWaitingUserCount());
1219 emulesig_string
+= temp
;
1220 amulesig_out
.AddLine(temp
);
1222 // Number of shared files (not on eMule)
1223 amulesig_out
.AddLine(wxString::Format(wxT("%d"), theStats::GetSharedFileCount()));
1226 // eMule signature finished here. Write the line to the wxTextFile.
1227 emulesig_out
.AddLine(emulesig_string
);
1229 // Now for aMule signature extras
1231 // Nick on the network
1232 amulesig_out
.AddLine(thePrefs::GetUserNick());
1234 // Total received in bytes
1235 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded()) );
1237 // Total sent in bytes
1238 amulesig_out
.AddLine( CFormat( wxT("%llu") ) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded()) );
1242 amulesig_out
.AddLine(wxT(VERSION
" " SVNDATE
));
1244 amulesig_out
.AddLine(wxT(VERSION
));
1248 amulesig_out
.AddLine(wxT("0"));
1249 amulesig_out
.AddLine(wxT("0"));
1250 amulesig_out
.AddLine(wxT("0"));
1252 // Total received bytes in session
1253 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
1254 theStats::GetSessionReceivedBytes() );
1256 // Total sent bytes in session
1257 amulesig_out
.AddLine( CFormat( wxT("%llu") ) %
1258 theStats::GetSessionSentBytes() );
1261 amulesig_out
.AddLine(CFormat(wxT("%llu")) % theStats::GetUptimeSeconds());
1265 emulesig_out
.Write();
1266 amulesig_out
.Write();
1267 } //End Added By Bouc7
1270 // Gracefully handle fatal exceptions and print backtrace if possible
1271 void CamuleApp::OnFatalException()
1273 /* Print the backtrace */
1274 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1275 fprintf(stderr
, "A fatal error has occurred and aMule has crashed.\n");
1276 fprintf(stderr
, "Please assist us in fixing this problem by posting the backtrace below in our\n");
1277 fprintf(stderr
, "'aMule Crashes' forum and include as much information as possible regarding the\n");
1278 fprintf(stderr
, "circumstances of this crash. The forum is located here:\n");
1279 fprintf(stderr
, " http://forum.amule.org/index.php?board=67.0\n");
1280 fprintf(stderr
, "If possible, please try to generate a real backtrace of this crash:\n");
1281 fprintf(stderr
, " http://www.amule.org/wiki/index.php/Backtraces\n\n");
1282 fprintf(stderr
, "----------------------------=| BACKTRACE FOLLOWS: |=----------------------------\n");
1283 fprintf(stderr
, "Current version is: %s\n", strFullMuleVersion
);
1284 fprintf(stderr
, "Running on: %s\n\n", strOSDescription
);
1286 print_backtrace(1); // 1 == skip this function.
1288 fprintf(stderr
, "\n--------------------------------------------------------------------------------\n");
1292 // Sets the localization of aMule
1293 void CamuleApp::Localize_mule()
1295 InitCustomLanguages();
1296 InitLocale(m_locale
, StrLang2wx(thePrefs::GetLanguageID()));
1297 if (!m_locale
.IsOk()) {
1298 AddLogLineM(false,_("The selected locale seems not to be installed on your box. (Note: I'll try to set it anyway)"));
1303 // Displays information related to important changes in aMule.
1304 // Is called when the user runs a new version of aMule
1305 void CamuleApp::Trigger_New_version(wxString new_version
)
1307 wxString info
= wxT(" --- ") + CFormat(_("This is the first time you run aMule %s")) % new_version
+ wxT(" ---\n\n");
1308 if (new_version
== wxT("SVN")) {
1309 info
+= _("This version is a testing version, updated daily, and\n");
1310 info
+= _("we give no warranty it won't break anything, burn your house,\n");
1311 info
+= _("or kill your dog. But it *should* be safe to use anyway.\n");
1312 } else if (new_version
== wxT("2.2.0")) {
1313 thePrefs::SetAddServersFromServer(false);
1314 thePrefs::SetAddServersFromClient(false);
1315 info
+= _("The following options have been changed in this release for security reasons:\n");
1316 info
+= _("\n* Enabled Protocol Obfuscation support for incoming and outgoing connections.\n");
1317 info
+= _("\n* Disabled updating the server list from other server and clients.\n");
1318 info
+= _("\nFor more information on the reason for this changes, seach\nthe aMule wiki at http://wiki.amule.org for \"fake servers\" info.\nIt's important that you clear any fake server from your server list for aMule to work properly.");
1323 info
+= _("More information, support and new releases can found at our homepage,\n");
1324 info
+= _("at www.aMule.org, or in our IRC channel #aMule at irc.freenode.net.\n");
1326 info
+= _("Feel free to report any bugs to http://forum.amule.org");
1328 ShowAlert(info
, _("Info"), wxCENTRE
| wxOK
| wxICON_ERROR
);
1332 void CamuleApp::SetOSFiles(const wxString new_path
)
1334 if ( thePrefs::IsOnlineSignatureEnabled() ) {
1335 if ( ::wxDirExists(new_path
) ) {
1336 m_emulesig_path
= JoinPaths(new_path
, wxT("onlinesig.dat"));
1337 m_amulesig_path
= JoinPaths(new_path
, wxT("amulesig.dat"));
1339 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
);
1340 m_emulesig_path
.Clear();
1341 m_amulesig_path
.Clear();
1344 m_emulesig_path
.Clear();
1345 m_amulesig_path
.Clear();
1351 #ifndef wxUSE_STACKWALKER
1352 #define wxUSE_STACKWALKER 0
1354 void CamuleApp::OnAssertFailure(const wxChar
* file
, int line
,
1355 const wxChar
* func
, const wxChar
* cond
, const wxChar
* msg
)
1357 if (!wxUSE_STACKWALKER
|| !wxThread::IsMain() || !IsRunning()) {
1358 wxString errmsg
= CFormat( wxT("%s:%s:%d: Assertion '%s' failed. %s") )
1359 % file
% func
% line
% cond
% ( msg
? msg
: wxT("") );
1361 fprintf(stderr
, "Assertion failed: %s\n", (const char*)unicode2char(errmsg
));
1363 // Skip the function-calls directly related to the assert call.
1364 fprintf(stderr
, "\nBacktrace follows:\n");
1366 fprintf(stderr
, "\n");
1369 if (wxThread::IsMain() && IsRunning()) {
1370 AMULE_APP_BASE::OnAssertFailure(file
, line
, func
, cond
, msg
);
1372 // Abort, allows gdb to catch the assertion
1379 void CamuleApp::OnUDPDnsDone(CMuleInternalEvent
& evt
)
1381 CServerUDPSocket
* socket
=(CServerUDPSocket
*)evt
.GetClientData();
1382 socket
->OnHostnameResolved(evt
.GetExtraLong());
1386 void CamuleApp::OnSourceDnsDone(CMuleInternalEvent
& evt
)
1388 downloadqueue
->OnHostnameResolved(evt
.GetExtraLong());
1392 void CamuleApp::OnServerDnsDone(CMuleInternalEvent
& evt
)
1394 printf("Server hostname notified\n");
1395 serverconnect
->OnServerHostnameResolved(evt
.GetClientData(), evt
.GetExtraLong());
1399 void CamuleApp::OnTCPTimer(CTimerEvent
& WXUNUSED(evt
))
1404 serverconnect
->StopConnectionTry();
1405 if (IsConnectedED2K() ) {
1408 serverconnect
->ConnectToAnyServer();
1412 void CamuleApp::OnCoreTimer(CTimerEvent
& WXUNUSED(evt
))
1414 // Former TimerProc section
1415 static uint64 msPrev1
, msPrev5
, msPrevSave
, msPrevHist
, msPrevOS
, msPrevKnownMet
;
1416 uint64 msCur
= theStats::GetUptimeMillis();
1422 #ifndef AMULE_DAEMON
1423 // Check if we should terminate the app
1424 if ( g_shutdownSignal
) {
1425 wxWindow
* top
= GetTopWindow();
1430 // No top-window, have to force termination.
1436 CLogger::FlushPendingEntries();
1438 uploadqueue
->Process();
1439 downloadqueue
->Process();
1440 //theApp->clientcredits->Process();
1441 theStats::CalculateRates();
1443 if (msCur
-msPrevHist
> 1000) {
1444 // unlike the other loop counters in this function this one will sometimes
1445 // produce two calls in quick succession (if there was a gap of more than one
1446 // second between calls to TimerProc) - this is intentional! This way the
1447 // history list keeps an average of one node per second and gets thinned out
1448 // correctly as time progresses.
1451 m_statistics
->RecordHistory();
1456 if (msCur
-msPrev1
> 1000) { // approximately every second
1458 clientcredits
->Process();
1459 clientlist
->Process();
1461 // Publish files to server if needed.
1462 sharedfiles
->Process();
1464 if( Kademlia::CKademlia::IsRunning() ) {
1465 Kademlia::CKademlia::Process();
1466 if(Kademlia::CKademlia::GetPrefs()->HasLostConnection()) {
1470 if (thePrefs::Reconnect()) {
1476 if( serverconnect
->IsConnecting() && !serverconnect
->IsSingleConnect() ) {
1477 serverconnect
->TryAnotherConnectionrequest();
1479 if (serverconnect
->IsConnecting()) {
1480 serverconnect
->CheckForTimeout();
1482 listensocket
->UpdateConnectionsStatus();
1487 if (msCur
-msPrev5
> 5000) { // every 5 seconds
1489 listensocket
->Process();
1492 if (msCur
-msPrevSave
>= 60000) {
1496 // Save total upload/download to preferences
1497 wxConfigBase
* cfg
= wxConfigBase::Get();
1498 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionReceivedBytes() + thePrefs::GetTotalDownloaded());
1499 cfg
->Write(wxT("/Statistics/TotalDownloadedBytes"), buffer
);
1501 buffer
= CFormat(wxT("%llu")) % (theStats::GetSessionSentBytes() + thePrefs::GetTotalUploaded());
1502 cfg
->Write(wxT("/Statistics/TotalUploadedBytes"), buffer
);
1504 // Write changes to file
1510 if (msCur
- msPrevOS
>= thePrefs::GetOSUpdate() * 1000ull) {
1511 OnlineSig(); // Added By Bouc7
1515 if (msCur
- msPrevKnownMet
>= 30*60*1000/*There must be a prefs option for this*/) {
1516 // Save Shared Files data
1518 msPrevKnownMet
= msCur
;
1522 // Recomended by lugdunummaster himself - from emule 0.30c
1523 serverconnect
->KeepConnectionAlive();
1528 void CamuleApp::OnFinishedHashing(CHashingEvent
& evt
)
1530 wxCHECK_RET(evt
.GetResult(), wxT("No result of hashing"));
1532 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1533 CKnownFile
* result
= evt
.GetResult();
1536 // Check if the partfile still exists, as it might have
1537 // been deleted in the mean time.
1538 if (downloadqueue
->IsPartFile(owner
)) {
1539 // This cast must not be done before the IsPartFile
1540 // call, as dynamic_cast will barf on dangling pointers.
1541 dynamic_cast<CPartFile
*>(owner
)->PartFileHashFinished(result
);
1544 static int filecount
;
1545 static uint64 bytecount
;
1547 if (knownfiles
->SafeAddKFile(result
)) {
1548 AddDebugLogLineM(false, logKnownFiles
,
1549 CFormat(wxT("Safe adding file to sharedlist: %s")) % result
->GetFileName());
1550 sharedfiles
->SafeAddKFile(result
);
1553 bytecount
+= result
->GetFileSize();
1554 // If we have added 30 files or files with a total size of ~300mb
1555 if ( ( filecount
== 30 ) || ( bytecount
>= 314572800 ) ) {
1556 AddDebugLogLineM(false, logKnownFiles
, wxT("Failsafe for crash on file hashing creation"));
1557 if ( m_app_state
!= APP_STATE_SHUTTINGDOWN
) {
1564 AddDebugLogLineM(false, logKnownFiles
,
1565 CFormat(wxT("File not added to sharedlist: %s")) % result
->GetFileName());
1572 void CamuleApp::OnFinishedAICHHashing(CHashingEvent
& evt
)
1574 wxCHECK_RET(evt
.GetResult(), wxT("No result of AICH-hashing"));
1576 CKnownFile
* owner
= const_cast<CKnownFile
*>(evt
.GetOwner());
1577 std::auto_ptr
<CKnownFile
> result(evt
.GetResult());
1579 // Check that the owner is still valid
1580 if (knownfiles
->IsKnownFile(owner
)) {
1581 if (result
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
) {
1582 CAICHHashSet
* oldSet
= owner
->GetAICHHashset();
1583 CAICHHashSet
* newSet
= result
->GetAICHHashset();
1585 owner
->SetAICHHashset(newSet
);
1586 newSet
->SetOwner(owner
);
1588 result
->SetAICHHashset(oldSet
);
1589 oldSet
->SetOwner(result
.get());
1595 void CamuleApp::OnFinishedCompletion(CCompletionEvent
& evt
)
1597 CPartFile
* completed
= const_cast<CPartFile
*>(evt
.GetOwner());
1598 wxCHECK_RET(completed
, wxT("Completion event sent for unspecified file"));
1599 wxASSERT_MSG(downloadqueue
->IsPartFile(completed
), wxT("CCompletionEvent for unknown partfile."));
1601 completed
->CompleteFileEnded(evt
.ErrorOccured(), evt
.GetFullPath());
1602 if (evt
.ErrorOccured()) {
1603 CUserEvents::ProcessEvent(CUserEvents::ErrorOnCompletion
, completed
);
1606 // Check if we should execute an script/app/whatever.
1607 CUserEvents::ProcessEvent(CUserEvents::DownloadCompleted
, completed
);
1610 void CamuleApp::OnFinishedAllocation(CAllocFinishedEvent
& evt
)
1612 CPartFile
*file
= evt
.GetFile();
1613 wxCHECK_RET(file
, wxT("Allocation finished event sent for unspecified file"));
1614 wxASSERT_MSG(downloadqueue
->IsPartFile(file
), wxT("CAllocFinishedEvent for unknown partfile"));
1616 file
->SetPartFileStatus(PS_EMPTY
);
1618 if (evt
.Succeeded()) {
1619 if (evt
.IsPaused()) {
1625 AddLogLineM(false, CFormat(_("Disk space preallocation for file '%s' failed: %s")) % file
->GetFileName() % wxString(UTF82unicode(std::strerror(evt
.GetResult()))));
1629 file
->AllocationFinished();
1632 void CamuleApp::OnNotifyEvent(CMuleGUIEvent
& evt
)
1634 #if defined(AMULE_DAEMON)
1637 if (theApp
->amuledlg
) {
1644 void CamuleApp::ShutDown()
1647 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has started."));
1649 // Signal the hashing thread to terminate
1650 m_app_state
= APP_STATE_SHUTTINGDOWN
;
1654 // Kry - Save the sources seeds on app exit
1655 if (thePrefs::GetSrcSeedsOn()) {
1656 downloadqueue
->SaveSourceSeeds();
1659 OnlineSig(true); // Added By Bouc7
1661 // Close sockets to avoid new clients coming in
1663 listensocket
->Close();
1664 listensocket
->KillAllSockets();
1667 if (serverconnect
) {
1668 serverconnect
->Disconnect();
1671 ECServerHandler
->KillAllSockets();
1674 if (thePrefs::GetUPnPEnabled()) {
1676 m_upnp
->DeletePortMappings(m_upnpMappings
);
1681 // saving data & stuff
1686 thePrefs::Add2TotalDownloaded(theStats::GetSessionReceivedBytes());
1687 thePrefs::Add2TotalUploaded(theStats::GetSessionSentBytes());
1694 clientlist
->DeleteAll();
1697 CThreadScheduler::Terminate();
1699 theApp
->uploadBandwidthThrottler
->EndThread();
1702 AddDebugLogLineM(false, logGeneral
, wxT("CamuleApp::ShutDown() has ended."));
1706 bool CamuleApp::AddServer(CServer
*srv
, bool fromUser
)
1708 if ( serverlist
->AddServer(srv
, fromUser
) ) {
1709 Notify_ServerAdd(srv
);
1716 void CamuleApp::AddLogLine(const wxString
&msg
)
1718 // At most one trailing new-line, which we add
1719 wxString message
= msg
;
1720 while ( !message
.IsEmpty() && message
.Last() == wxT('\n') ) {
1721 message
.RemoveLast();
1724 wxString full_line
= wxDateTime::Now().FormatISODate() + wxT(" ") +
1725 wxDateTime::Now().FormatISOTime() + wxT(": ") + message
+ wxT("\n");
1727 wxStringInputStream
stream(full_line
);
1729 if (applog
) { // This check is needed, because if we assert before the logger is created, it will crash.
1730 (*applog
) << stream
;
1734 if (enable_stdout_log
) {
1735 printf("%s", (const char*)unicode2char(full_line
));
1740 uint32
CamuleApp::GetPublicIP(bool ignorelocal
) const
1742 if (m_dwPublicIP
== 0) {
1743 if (Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::GetIPAddress() ) {
1744 return wxUINT32_SWAP_ALWAYS(Kademlia::CKademlia::GetIPAddress());
1746 return ignorelocal
? 0 : m_localip
;
1750 return m_dwPublicIP
;
1754 void CamuleApp::SetPublicIP(const uint32 dwIP
)
1756 wxASSERT((dwIP
== 0) || !IsLowID(dwIP
));
1758 if (dwIP
!= 0 && dwIP
!= m_dwPublicIP
&& serverlist
!= NULL
) {
1759 m_dwPublicIP
= dwIP
;
1760 serverlist
->CheckForExpiredUDPKeys();
1762 m_dwPublicIP
= dwIP
;
1767 wxString
CamuleApp::GetLog(bool reset
)
1769 ConfigDir
= GetConfigDir();
1771 logfile
.Open(ConfigDir
+ wxT("logfile"));
1772 if ( !logfile
.IsOpened() ) {
1773 return wxTRANSLATE("ERROR: can't open logfile");
1775 int len
= logfile
.Length();
1777 return wxTRANSLATE("WARNING: logfile is empty. Something is wrong.");
1779 char *tmp_buffer
= new char[len
+ sizeof(wxChar
)];
1780 logfile
.Read(tmp_buffer
, len
);
1781 memset(tmp_buffer
+ len
, 0, sizeof(wxChar
));
1783 // try to guess file format
1785 if (tmp_buffer
[0] && tmp_buffer
[1]) {
1786 str
= wxString(UTF82unicode(tmp_buffer
));
1788 str
= wxString((wxWCharBuffer
&)tmp_buffer
);
1791 delete [] tmp_buffer
;
1794 applog
= new wxFFileOutputStream(ConfigDir
+ wxT("logfile"));
1795 if ( applog
->Ok() ) {
1796 AddLogLine(_("Log has been reset"));
1806 wxString
CamuleApp::GetServerLog(bool reset
)
1808 wxString ret
= server_msg
;
1815 wxString
CamuleApp::GetDebugLog(bool reset
)
1817 return GetLog(reset
);
1821 void CamuleApp::AddServerMessageLine(wxString
&msg
)
1823 server_msg
+= msg
+ wxT("\n");
1824 AddLogLine(CFormat(_("ServerMessage: %s")) % msg
);
1829 void CamuleApp::OnFinishedHTTPDownload(CMuleInternalEvent
& event
)
1831 switch (event
.GetInt()) {
1833 ipfilter
->DownloadFinished(event
.GetExtraLong());
1835 case HTTP_ServerMet
:
1836 serverlist
->DownloadFinished(event
.GetExtraLong());
1838 case HTTP_ServerMetAuto
:
1839 serverlist
->AutoDownloadFinished(event
.GetExtraLong());
1841 case HTTP_VersionCheck
:
1842 CheckNewVersion(event
.GetExtraLong());
1845 if (event
.GetExtraLong() != -1) {
1847 wxString file
= ConfigDir
+ wxT("nodes.dat");
1848 if (wxFileExists(file
)) {
1852 if ( Kademlia::CKademlia::IsRunning() ) {
1853 Kademlia::CKademlia::Stop();
1856 wxRenameFile(file
+ wxT(".download"),file
);
1858 Kademlia::CKademlia::Start();
1859 theApp
->ShowConnectionState();
1862 AddLogLineM(true, _("Failed to download the nodes list."));
1868 void CamuleApp::CheckNewVersion(uint32 result
)
1871 wxString filename
= ConfigDir
+ wxT("last_version_check");
1874 if (!file
.Open(filename
)) {
1875 AddLogLineM(true, _("Failed to open the downloaded version check file") );
1877 } else if (!file
.GetLineCount()) {
1878 AddLogLineM(true, _("Corrupted version check file"));
1880 wxString versionLine
= file
.GetFirstLine();
1881 wxStringTokenizer
tkz(versionLine
, wxT("."));
1883 AddDebugLogLineM(false, logGeneral
, wxString(wxT("Running: ")) + wxT(VERSION
) + wxT(", Version check: ") + versionLine
);
1885 long fields
[] = {0, 0, 0};
1886 for (int i
= 0; i
< 3; ++i
) {
1887 if (!tkz
.HasMoreTokens()) {
1888 AddLogLineM(true, _("Corrupted version check file"));
1891 wxString token
= tkz
.GetNextToken();
1893 if (!token
.ToLong(&fields
[i
])) {
1894 AddLogLineM(true, _("Corrupted version check file"));
1900 long curVer
= make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
);
1901 long newVer
= make_full_ed2k_version(fields
[0], fields
[1], fields
[2]);
1903 if (curVer
< newVer
) {
1904 AddLogLineM(true, _("You are using an outdated version of aMule!"));
1905 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]));
1906 AddLogLineM(false, _("The latest version can always be found at http://www.amule.org"));
1908 printf("%s\n", (const char*)unicode2UTF8(wxString::Format(
1909 _("WARNING: Your aMuled version is outdated: %i.%i.%i < %li.%li.%li"),
1910 VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
, fields
[0], fields
[1], fields
[2])));
1913 AddLogLineM(false, _("Your copy of aMule is up to date."));
1918 wxRemoveFile(filename
);
1920 AddLogLineM(true, _("Failed to download the version check file") );
1926 bool CamuleApp::IsConnected()
1928 return (IsConnectedED2K() || IsConnectedKad());
1932 bool CamuleApp::IsConnectedED2K()
1934 return serverconnect
&& serverconnect
->IsConnected();
1938 bool CamuleApp::IsConnectedKad()
1940 return Kademlia::CKademlia::IsConnected();
1944 bool CamuleApp::IsFirewalled()
1946 if (theApp
->IsConnectedED2K() && !theApp
->serverconnect
->IsLowID()) {
1947 return false; // we have an eD2K HighID -> not firewalled
1950 return IsFirewalledKad(); // If kad says ok, it's ok.
1953 bool CamuleApp::IsFirewalledKad()
1955 if (Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled()) {
1956 return false; // we have an Kad HighID -> not firewalled
1959 return true; // firewalled
1962 bool CamuleApp::IsKadRunning()
1964 return Kademlia::CKademlia::IsRunning();
1967 bool CamuleApp::DoCallback( CUpDownClient
*client
)
1969 if(Kademlia::CKademlia::IsConnected()) {
1970 if(IsConnectedED2K()) {
1971 if(serverconnect
->IsLowID()) {
1972 if(Kademlia::CKademlia::IsFirewalled()) {
1973 //Both Connected - Both Firewalled
1976 if(client
->GetServerIP() == theApp
->serverconnect
->GetCurrentServer()->GetIP() &&
1977 client
->GetServerPort() == theApp
->serverconnect
->GetCurrentServer()->GetPort()) {
1978 // Both Connected - Server lowID, Kad Open - Client on same server
1979 // We prevent a callback to the server as this breaks the protocol
1980 // and will get you banned.
1983 // Both Connected - Server lowID, Kad Open - Client on remote server
1988 //Both Connected - Server HighID, Kad don't care
1992 if(Kademlia::CKademlia::IsFirewalled()) {
1993 //Only Kad Connected - Kad Firewalled
1996 //Only Kad Conected - Kad Open
2001 if( IsConnectedED2K() ) {
2002 if( serverconnect
->IsLowID() ) {
2003 //Only Server Connected - Server LowID
2006 //Only Server Connected - Server HighID
2010 //We are not connected at all!
2016 void CamuleApp::ShowUserCount() {
2017 uint32 totaluser
= 0, totalfile
= 0;
2019 theApp
->serverlist
->GetUserFileStatus( totaluser
, totalfile
);
2023 static const wxString s_singlenetstatusformat
= _("Users: %s | Files: %s");
2024 static const wxString s_bothnetstatusformat
= _("Users: E: %s K: %s | Files: E: %s K: %s");
2026 if (thePrefs::GetNetworkED2K() && thePrefs::GetNetworkKademlia()) {
2027 buffer
= CFormat(s_bothnetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(totalfile
) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2028 } else if (thePrefs::GetNetworkED2K()) {
2029 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(totaluser
) % CastItoIShort(totalfile
);
2030 } else if (thePrefs::GetNetworkKademlia()) {
2031 buffer
= CFormat(s_singlenetstatusformat
) % CastItoIShort(Kademlia::CKademlia::GetKademliaUsers()) % CastItoIShort(Kademlia::CKademlia::GetKademliaFiles());
2033 buffer
= _("No networks selected");
2036 Notify_ShowUserCount(buffer
);
2040 void CamuleApp::ListenSocketHandler(wxSocketEvent
& event
)
2042 wxCHECK_RET(listensocket
, wxT("Connection-event for NULL'd listen-socket"));
2043 wxCHECK_RET(event
.GetSocketEvent() == wxSOCKET_CONNECTION
,
2044 wxT("Invalid event received for listen-socket"));
2046 if (m_app_state
== APP_STATE_RUNNING
) {
2047 listensocket
->OnAccept(0);
2048 } else if (m_app_state
== APP_STATE_STARTING
) {
2049 // When starting up, connection may be made before we are able
2050 // to handle them. However, if these are ignored, no futher
2051 // connection-events will be triggered, so we have to accept it.
2052 wxSocketBase
* socket
= listensocket
->Accept(false);
2054 wxCHECK_RET(socket
, wxT("NULL returned by Accept() during startup"));
2061 void CamuleApp::ShowConnectionState()
2063 static uint8 old_state
= (1<<7); // This flag doesn't exist
2067 if (theApp
->serverconnect
->IsConnected()) {
2068 state
|= CONNECTED_ED2K
;
2071 if (Kademlia::CKademlia::IsRunning()) {
2072 if (Kademlia::CKademlia::IsConnected()) {
2073 if (!Kademlia::CKademlia::IsFirewalled()) {
2074 state
|= CONNECTED_KAD_OK
;
2076 state
|= CONNECTED_KAD_FIREWALLED
;
2079 state
|= CONNECTED_KAD_NOT
;
2083 Notify_ShowConnState(state
);
2085 if (old_state
!= state
) {
2086 // Get the changed value
2087 int changed_flags
= old_state
^ state
;
2089 if (changed_flags
& CONNECTED_ED2K
) {
2090 // ED2K status changed
2091 wxString connected_server
;
2092 CServer
* ed2k_server
= theApp
->serverconnect
->GetCurrentServer();
2094 connected_server
= ed2k_server
->GetListName();
2096 if (state
& CONNECTED_ED2K
) {
2097 // We connected to some server
2098 const wxString id
= theApp
->serverconnect
->IsLowID() ? _("with LowID") : _("with HighID");
2100 AddLogLine(CFormat(_("Connected to %s %s")) % connected_server
% id
);
2102 if ( theApp
->serverconnect
->IsConnecting() ) {
2103 AddLogLine(CFormat(_("Connecting to %s")) % connected_server
);
2105 AddLogLine(_("Disconnected from ED2K"));
2110 if (changed_flags
& CONNECTED_KAD_NOT
) {
2111 if (state
& CONNECTED_KAD_NOT
) {
2112 AddLogLine(_("Kad started."));
2114 AddLogLine(_("Kad stopped."));
2118 if (changed_flags
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
2119 if (state
& (CONNECTED_KAD_OK
| CONNECTED_KAD_FIREWALLED
)) {
2120 if (state
& CONNECTED_KAD_OK
) {
2121 AddLogLine(_("Connected to Kad (ok)"));
2123 AddLogLine(_("Connected to Kad (firewalled)"));
2126 AddLogLine(_("Disconnected from Kad"));
2132 theApp
->downloadqueue
->OnConnectionState(IsConnected());
2136 Notify_ShowConnState(state
);
2140 void CamuleApp::UDPSocketHandler(wxSocketEvent
& event
)
2142 CMuleUDPSocket
* socket
= (CMuleUDPSocket
*)(event
.GetClientData());
2143 wxCHECK_RET(socket
, wxT("No socket owner specified."));
2145 if (IsOnShutDown() || thePrefs::IsUDPDisabled()) return;
2148 if (event
.GetSocketEvent() == wxSOCKET_INPUT
) {
2149 // Back to the queue!
2150 theApp
->AddPendingEvent(event
);
2155 switch (event
.GetSocketEvent()) {
2156 case wxSOCKET_INPUT
:
2157 socket
->OnReceive(0);
2160 case wxSOCKET_OUTPUT
:
2165 socket
->OnDisconnected(0);
2175 void CamuleApp::OnUnhandledException()
2177 // Call the generic exception-handler.
2178 fprintf(stderr
, "\taMule Version: %s\n", (const char*)unicode2char(GetFullMuleVersion()));
2179 ::OnUnhandledException();
2182 void CamuleApp::StartKad()
2184 if (!Kademlia::CKademlia::IsRunning() && thePrefs::GetNetworkKademlia()) {
2185 // Kad makes no sense without the Client-UDP socket.
2186 if (!thePrefs::IsUDPDisabled()) {
2187 Kademlia::CKademlia::Start();
2189 AddLogLineM(true,_("Kad network cannot be used if UDP port is disabled on preferences, not starting."));
2191 } else if (!thePrefs::GetNetworkKademlia()) {
2192 AddLogLineM(true,_("Kad network disabled on preferences, not connecting."));
2196 void CamuleApp::StopKad()
2198 // Stop Kad if it's running
2199 if (Kademlia::CKademlia::IsRunning()) {
2200 Kademlia::CKademlia::Stop();
2205 void CamuleApp::BootstrapKad(uint32 ip
, uint16 port
)
2207 if (!Kademlia::CKademlia::IsRunning()) {
2208 Kademlia::CKademlia::Start();
2209 theApp
->ShowConnectionState();
2212 Kademlia::CKademlia::Bootstrap(ip
, port
, true);
2216 void CamuleApp::UpdateNotesDat(const wxString
& url
)
2218 wxString
strTempFilename(theApp
->ConfigDir
+ wxT("nodes.dat.download"));
2220 CHTTPDownloadThread
*downloader
= new CHTTPDownloadThread(url
, strTempFilename
, HTTP_NodesDat
);
2221 downloader
->Create();
2226 void CamuleApp::DisconnectED2K()
2228 // Stop ED2K if it's running
2229 if (IsConnectedED2K()) {
2230 serverconnect
->Disconnect();
2234 bool CamuleApp::CryptoAvailable() const
2236 return clientcredits
&& clientcredits
->CryptoAvailable();
2239 uint32
CamuleApp::GetED2KID() const {
2240 return serverconnect
? serverconnect
->GetClientID() : 0;
2243 uint32
CamuleApp::GetID() const {
2246 if( Kademlia::CKademlia::IsConnected() && !Kademlia::CKademlia::IsFirewalled() ) {
2247 // We trust Kad above ED2K
2248 ID
= ENDIAN_NTOHL(Kademlia::CKademlia::GetIPAddress());
2249 } else if( theApp
->serverconnect
->IsConnected() ) {
2250 ID
= theApp
->serverconnect
->GetClientID();
2251 } else if ( Kademlia::CKademlia::IsConnected() && Kademlia::CKademlia::IsFirewalled() ) {
2252 // A firewalled Kad client get's a "1"
2261 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_FINISHED_HTTP_DOWNLOAD
)
2262 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SOURCE_DNS_DONE
)
2263 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_UDP_DNS_DONE
)
2264 DEFINE_LOCAL_EVENT_TYPE(wxEVT_CORE_SERVER_DNS_DONE
)
2265 // File_checked_for_headers