Add code to resume next file alphabetically, keeping in mind categories and priority.
[amule.git] / src / DownloadQueue.cpp
blob1fe6f774c6b74a08ef705a9a993a1a51a569de06
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
26 #include "DownloadQueue.h" // Interface declarations
28 #include <protocol/Protocols.h>
29 #include <protocol/kad/Constants.h>
30 #include <common/Macros.h>
31 #include <common/MenuIDs.h>
32 #include <common/Constants.h>
34 #include <wx/utils.h>
36 #include "Server.h" // Needed for CServer
37 #include "Packet.h" // Needed for CPacket
38 #include "MemFile.h" // Needed for CMemFile
39 #include "ClientList.h" // Needed for CClientList
40 #include "updownclient.h" // Needed for CUpDownClient
41 #include "ServerList.h" // Needed for CServerList
42 #include "ServerConnect.h" // Needed for CServerConnect
43 #include "ED2KLink.h" // Needed for CED2KFileLink
44 #include "SearchList.h" // Needed for CSearchFile
45 #include "SharedFileList.h" // Needed for CSharedFileList
46 #include "PartFile.h" // Needed for CPartFile
47 #include "Preferences.h" // Needed for thePrefs
48 #include "amule.h" // Needed for theApp
49 #include "AsyncDNS.h" // Needed for CAsyncDNS
50 #include "Statistics.h" // Needed for theStats
51 #include "Logger.h"
52 #include <common/Format.h> // Needed for CFormat
53 #include "IPFilter.h"
54 #include <common/FileFunctions.h> // Needed for CDirIterator
55 #include "GuiEvents.h" // Needed for Notify_*
56 #include "UserEvents.h"
57 #include "MagnetURI.h" // Needed for CMagnetED2KConverter
58 #include "ScopedPtr.h" // Needed for CScopedPtr
59 #include "PlatformSpecific.h" // Needed for CanFSHandleLargeFiles
61 #include "kademlia/kademlia/Kademlia.h"
63 #include <string> // Do_not_auto_remove (mingw-gcc-3.4.5)
66 // Max. file IDs per UDP packet
67 // ----------------------------
68 // 576 - 30 bytes of header (28 for UDP, 2 for "E3 9A" edonkey proto) = 546 bytes
69 // 546 / 16 = 34
72 #define MAX_FILES_PER_UDP_PACKET 31 // 2+16*31 = 498 ... is still less than 512 bytes!!
73 #define MAX_REQUESTS_PER_SERVER 35
76 CDownloadQueue::CDownloadQueue()
77 // Needs to be recursive that that is can own an observer assigned to itself
78 : m_mutex( wxMUTEX_RECURSIVE )
80 m_datarate = 0;
81 m_udpserver = 0;
82 m_lastsorttime = 0;
83 m_lastudpsearchtime = 0;
84 m_lastudpstattime = 0;
85 m_udcounter = 0;
86 m_nLastED2KLinkCheck = 0;
87 m_dwNextTCPSrcReq = 0;
88 m_cRequestsSentToServer = 0;
89 m_lastDiskCheck = 0;
90 SetLastKademliaFileRequest();
94 CDownloadQueue::~CDownloadQueue()
96 if ( !m_filelist.empty() ) {
97 for ( unsigned int i = 0; i < m_filelist.size(); i++ ) {
98 AddLogLineNS(CFormat(_("Saving PartFile %u of %u")) % (i + 1) % m_filelist.size());
99 delete m_filelist[i];
101 AddLogLineNS(_("All PartFiles Saved."));
106 void CDownloadQueue::LoadMetFiles(const CPath& path)
108 AddLogLineNS(CFormat(_("Loading temp files from %s.")) % path.GetPrintable());
110 std::vector<CPath> files;
112 // Locate part-files to be loaded
113 CDirIterator TempDir(path);
114 CPath fileName = TempDir.GetFirstFile(CDirIterator::File, wxT("*.part.met"));
115 while (fileName.IsOk()) {
116 files.push_back(path.JoinPaths(fileName));
118 fileName = TempDir.GetNextFile();
121 // Loading in order makes it easier to figure which
122 // file is broken in case of crashes, or the like.
123 std::sort(files.begin(), files.end());
125 // Load part-files
126 for ( size_t i = 0; i < files.size(); i++ ) {
127 AddLogLineNS(CFormat(_("Loading PartFile %u of %u")) % (i + 1) % files.size());
128 fileName = files[i].GetFullName();
129 CPartFile *toadd = new CPartFile();
130 bool result = toadd->LoadPartFile(path, fileName) != 0;
131 if (!result) {
132 // Try from backup
133 result = toadd->LoadPartFile(path, fileName, true) != 0;
135 if (result && !IsFileExisting(toadd->GetFileHash())) {
137 wxMutexLocker lock(m_mutex);
138 m_filelist.push_back(toadd);
140 NotifyObservers(EventType(EventType::INSERTED, toadd));
141 Notify_DownloadCtrlAddFile(toadd);
142 } else {
143 wxString msg;
144 if (result) {
145 msg << CFormat(wxT("WARNING: Duplicate partfile with hash '%s' found, skipping: %s"))
146 % toadd->GetFileHash().Encode() % fileName;
147 } else {
148 // If result is false, then reading of both the primary and the backup .met failed
149 AddLogLineN(_("ERROR: Failed to load backup file. Search http://forum.amule.org for .part.met recovery solutions."));
150 msg << CFormat(wxT("ERROR: Failed to load PartFile '%s'")) % fileName;
152 AddLogLineCS(msg);
154 // Delete the partfile object in the end.
155 delete toadd;
158 AddLogLineNS(_("All PartFiles Loaded."));
160 if ( GetFileCount() == 0 ) {
161 AddLogLineN(_("No part files found"));
162 } else {
163 AddLogLineN(CFormat(wxPLURAL("Found %u part file", "Found %u part files", GetFileCount())) % GetFileCount());
165 DoSortByPriority();
166 CheckDiskspace( path );
171 uint16 CDownloadQueue::GetFileCount() const
173 wxMutexLocker lock( m_mutex );
175 return m_filelist.size();
179 void CDownloadQueue::CopyFileList(std::vector<CPartFile*>& out_list) const
181 wxMutexLocker lock(m_mutex);
183 out_list.reserve(m_filelist.size());
184 for (FileQueue::const_iterator it = m_filelist.begin(); it != m_filelist.end(); ++it) {
185 out_list.push_back(*it);
190 CServer* CDownloadQueue::GetUDPServer() const
192 wxMutexLocker lock( m_mutex );
194 return m_udpserver;
198 void CDownloadQueue::SetUDPServer( CServer* server )
200 wxMutexLocker lock( m_mutex );
202 m_udpserver = server;
206 void CDownloadQueue::SaveSourceSeeds()
208 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
209 GetFileByIndex( i )->SaveSourceSeeds();
214 void CDownloadQueue::LoadSourceSeeds()
216 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
217 GetFileByIndex( i )->LoadSourceSeeds();
222 void CDownloadQueue::AddSearchToDownload(CSearchFile* toadd, uint8 category)
224 if ( IsFileExisting(toadd->GetFileHash()) ) {
225 return;
228 if (toadd->GetFileSize() > OLD_MAX_FILE_SIZE) {
229 if (!PlatformSpecific::CanFSHandleLargeFiles(thePrefs::GetTempDir())) {
230 AddLogLineC(_("Filesystem for Temp directory cannot handle large files."));
231 return;
232 } else if (!PlatformSpecific::CanFSHandleLargeFiles(theApp->glob_prefs->GetCatPath(category))) {
233 AddLogLineC(_("Filesystem for Incoming directory cannot handle large files."));
234 return;
238 CPartFile* newfile = NULL;
239 try {
240 newfile = new CPartFile(toadd);
241 } catch (const CInvalidPacket& WXUNUSED(e)) {
242 AddDebugLogLineC(logDownloadQueue, wxT("Search-result contained invalid tags, could not add"));
245 if ( newfile && newfile->GetStatus() != PS_ERROR ) {
246 AddDownload( newfile, thePrefs::AddNewFilesPaused(), category );
247 // Add any possible sources
248 if (toadd->GetClientID() && toadd->GetClientPort()) {
249 CMemFile sources(1+4+2);
250 sources.WriteUInt8(1);
251 sources.WriteUInt32(toadd->GetClientID());
252 sources.WriteUInt16(toadd->GetClientPort());
253 sources.Reset();
254 newfile->AddSources(sources, toadd->GetClientServerIP(), toadd->GetClientServerPort(), SF_SEARCH_RESULT, false);
256 for (std::list<CSearchFile::ClientStruct>::const_iterator it = toadd->GetClients().begin(); it != toadd->GetClients().end(); ++it) {
257 CMemFile sources(1+4+2);
258 sources.WriteUInt8(1);
259 sources.WriteUInt32(it->m_ip);
260 sources.WriteUInt16(it->m_port);
261 sources.Reset();
262 newfile->AddSources(sources, it->m_serverIP, it->m_serverPort, SF_SEARCH_RESULT, false);
264 } else {
265 delete newfile;
270 struct SFindBestPF
272 void operator()(CPartFile* file) {
273 // Check if we should filter out other categories
274 int alphaorder = 0;
276 if ((m_category != -1) && (file->GetCategory() != m_category)) {
277 return;
278 } else if (file->GetStatus() != PS_PAUSED) {
279 return;
280 } else if (m_alpha && m_result && ((alphaorder = file->GetFileName().GetPrintable().CmpNoCase(m_result->GetFileName().GetPrintable())) > 0)) {
281 return;
284 if (!m_result) {
285 m_result = file;
286 } else {
287 if (m_alpha && (alphaorder < 0)) {
288 m_result = file;
289 } else if (file->GetDownPriority() > m_result->GetDownPriority()) {
290 // Either not alpha ordered, or they have the same alpha ordering (could happen if they have same name)
291 m_result = file;
292 } else {
293 // Lower priority file
298 //! The category to look for, or -1 if any category is good
299 int m_category;
300 //! If any acceptable files are found, this variable store their pointer
301 CPartFile* m_result;
302 //! If we should order alphabetically
303 bool m_alpha;
307 void CDownloadQueue::StartNextFile(CPartFile* oldfile)
309 if ( thePrefs::StartNextFile() ) {
310 SFindBestPF visitor = { -1, NULL, thePrefs::StartNextFileAlpha() };
313 wxMutexLocker lock(m_mutex);
315 if (thePrefs::StartNextFileSame()) {
316 // Get a download in the same category
317 visitor.m_category = oldfile->GetCategory();
319 visitor = std::for_each(m_filelist.begin(), m_filelist.end(), visitor);
322 if (visitor.m_result == NULL) {
323 // Get a download, regardless of category
324 visitor.m_category = -1;
326 visitor = std::for_each(m_filelist.begin(), m_filelist.end(), visitor);
329 // Alpha doesn't need special cases
332 if (visitor.m_result) {
333 visitor.m_result->ResumeFile();
339 void CDownloadQueue::AddDownload(CPartFile* file, bool paused, uint8 category)
341 wxCHECK_RET(!IsFileExisting(file->GetFileHash()), wxT("Adding duplicate part-file"));
343 if (file->GetStatus(true) == PS_ALLOCATING) {
344 file->PauseFile();
345 } else if (paused && GetFileCount()) {
346 file->StopFile();
350 wxMutexLocker lock(m_mutex);
351 m_filelist.push_back( file );
352 DoSortByPriority();
355 NotifyObservers( EventType( EventType::INSERTED, file ) );
356 if (category < theApp->glob_prefs->GetCatCount()) {
357 file->SetCategory(category);
358 } else {
359 AddDebugLogLineN( logDownloadQueue, wxT("Tried to add download into invalid category.") );
361 Notify_DownloadCtrlAddFile( file );
362 theApp->searchlist->UpdateSearchFileByHash(file->GetFileHash()); // Update file in the search dialog if it's still open
363 AddLogLineC(CFormat(_("Downloading %s")) % file->GetFileName() );
367 bool CDownloadQueue::IsFileExisting( const CMD4Hash& fileid ) const
369 if (CKnownFile* file = theApp->sharedfiles->GetFileByID(fileid)) {
370 if (file->IsPartFile()) {
371 AddLogLineC(CFormat( _("You are already trying to download the file '%s'") ) % file->GetFileName());
372 } else {
373 // Check if the file exists, since otherwise the user is forced to
374 // manually reload the shares to download a file again.
375 CPath fullpath = file->GetFilePath().JoinPaths(file->GetFileName());
376 if (!fullpath.FileExists()) {
377 // The file is no longer available, unshare it
378 theApp->sharedfiles->RemoveFile(file);
380 return false;
383 AddLogLineC(CFormat( _("You already have the file '%s'") ) % file->GetFileName());
386 return true;
387 } else if ((file = GetFileByID(fileid))) {
388 AddLogLineC(CFormat( _("You are already trying to download the file %s") ) % file->GetFileName());
389 return true;
392 return false;
396 void CDownloadQueue::Process()
398 // send src requests to local server
399 ProcessLocalRequests();
402 wxMutexLocker lock(m_mutex);
404 uint32 downspeed = 0;
405 if (thePrefs::GetMaxDownload() != UNLIMITED && m_datarate > 1500) {
406 downspeed = (((uint32)thePrefs::GetMaxDownload())*1024*100)/(m_datarate+1);
407 if (downspeed < 50) {
408 downspeed = 50;
409 } else if (downspeed > 200) {
410 downspeed = 200;
414 m_datarate = 0;
415 m_udcounter++;
416 uint32 cur_datarate = 0;
417 uint32 cur_udcounter = m_udcounter;
419 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
420 CPartFile* file = m_filelist[i];
422 CMutexUnlocker unlocker(m_mutex);
424 if ( file->GetStatus() == PS_READY || file->GetStatus() == PS_EMPTY ){
425 cur_datarate += file->Process( downspeed, cur_udcounter );
426 } else {
427 //This will make sure we don't keep old sources to paused and stoped files..
428 file->StopPausedFile();
432 m_datarate += cur_datarate;
435 if (m_udcounter == 5) {
436 if (theApp->serverconnect->IsUDPSocketAvailable()) {
437 if( (::GetTickCount() - m_lastudpstattime) > UDPSERVERSTATTIME) {
438 m_lastudpstattime = ::GetTickCount();
440 CMutexUnlocker unlocker(m_mutex);
441 theApp->serverlist->ServerStats();
446 if (m_udcounter == 10) {
447 m_udcounter = 0;
448 if (theApp->serverconnect->IsUDPSocketAvailable()) {
449 if ( (::GetTickCount() - m_lastudpsearchtime) > UDPSERVERREASKTIME) {
450 SendNextUDPPacket();
455 if ( (::GetTickCount() - m_lastsorttime) > 10000 ) {
458 DoSortByPriority();
460 // Check if any paused files can be resumed
462 CheckDiskspace(thePrefs::GetTempDir());
466 // Check for new links once per second.
467 if ((::GetTickCount() - m_nLastED2KLinkCheck) >= 1000) {
468 theApp->AddLinksFromFile();
469 m_nLastED2KLinkCheck = ::GetTickCount();
474 CPartFile* CDownloadQueue::GetFileByID(const CMD4Hash& filehash) const
476 wxMutexLocker lock( m_mutex );
478 for ( uint16 i = 0; i < m_filelist.size(); ++i ) {
479 if ( filehash == m_filelist[i]->GetFileHash()) {
480 return m_filelist[ i ];
484 return NULL;
488 CPartFile* CDownloadQueue::GetFileByIndex(unsigned int index) const
490 wxMutexLocker lock( m_mutex );
492 if ( index < m_filelist.size() ) {
493 return m_filelist[ index ];
496 wxFAIL;
497 return NULL;
501 bool CDownloadQueue::IsPartFile(const CKnownFile* file) const
503 wxMutexLocker lock(m_mutex);
505 for (uint16 i = 0; i < m_filelist.size(); ++i) {
506 if (file == m_filelist[i]) {
507 return true;
511 return false;
515 void CDownloadQueue::OnConnectionState(bool bConnected)
517 wxMutexLocker lock(m_mutex);
519 for (uint16 i = 0; i < m_filelist.size(); ++i) {
520 if ( m_filelist[i]->GetStatus() == PS_READY ||
521 m_filelist[i]->GetStatus() == PS_EMPTY) {
522 m_filelist[i]->SetActive(bConnected);
528 void CDownloadQueue::CheckAndAddSource(CPartFile* sender, CUpDownClient* source)
530 // if we block loopbacks at this point it should prevent us from connecting to ourself
531 if ( source->HasValidHash() ) {
532 if ( source->GetUserHash() == thePrefs::GetUserHash() ) {
533 AddDebugLogLineN( logDownloadQueue, wxT("Tried to add source with matching hash to your own.") );
534 source->Safe_Delete();
535 return;
539 if (sender->IsStopped()) {
540 source->Safe_Delete();
541 return;
544 // Filter sources which are known to be dead/useless
545 if ( theApp->clientlist->IsDeadSource( source ) || sender->IsDeadSource(source) ) {
546 source->Safe_Delete();
547 return;
550 // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
551 if ( (source->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source->SupportsCryptLayer() || !source->HasValidHash()))) {
552 source->Safe_Delete();
553 return;
556 // Find all clients with the same hash
557 if ( source->HasValidHash() ) {
558 CClientList::SourceList found = theApp->clientlist->GetClientsByHash( source->GetUserHash() );
560 CClientList::SourceList::iterator it = found.begin();
561 for ( ; it != found.end(); it++ ) {
562 CKnownFile* file = (*it)->GetRequestFile();
564 // Only check files on the download-queue
565 if ( file ) {
566 // Is the found source queued for something else?
567 if ( file != sender ) {
568 // Try to add a request for the other file
569 if ( (*it)->AddRequestForAnotherFile(sender)) {
570 // Add it to downloadlistctrl
571 Notify_SourceCtrlAddSource(sender, *it, A4AF_SOURCE);
575 source->Safe_Delete();
576 return;
583 // Our new source is real new but maybe it is already uploading to us?
584 // If yes the known client will be attached to the var "source" and the old
585 // source-client will be deleted. However, if the request file of the known
586 // source is NULL, then we have to treat it almost like a new source and if
587 // it isn't NULL and not "sender", then we shouldn't move it, but rather add
588 // a request for the new file.
589 ESourceFrom nSourceFrom = source->GetSourceFrom();
590 if ( theApp->clientlist->AttachToAlreadyKnown(&source, 0) ) {
591 // Already queued for another file?
592 if ( source->GetRequestFile() ) {
593 // If we're already queued for the right file, then there's nothing to do
594 if ( sender != source->GetRequestFile() ) {
595 // Add the new file to the request list
596 source->AddRequestForAnotherFile( sender );
598 } else {
599 // Source was known, but reqfile NULL.
600 source->SetRequestFile( sender );
601 source->SetSourceFrom(nSourceFrom);
602 sender->AddSource( source );
603 if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) {
604 sender->UpdateFileRatingCommentAvail();
607 Notify_SourceCtrlAddSource(sender, source, UNAVAILABLE_SOURCE);
609 } else {
610 // Unknown client, add it to the clients list
611 source->SetRequestFile( sender );
613 theApp->clientlist->AddClient(source);
615 sender->AddSource( source );
616 if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) {
617 sender->UpdateFileRatingCommentAvail();
620 Notify_SourceCtrlAddSource(sender, source, UNAVAILABLE_SOURCE);
625 void CDownloadQueue::CheckAndAddKnownSource(CPartFile* sender,CUpDownClient* source)
627 // Kad reviewed
629 if (sender->IsStopped()) {
630 return;
633 // Filter sources which are known to be dead/useless
634 if ( sender->IsDeadSource(source) ) {
635 return;
638 // "Filter LAN IPs" -- this may be needed here in case we are connected to the internet and are also connected
639 // to a LAN and some client from within the LAN connected to us. Though this situation may be supported in future
640 // by adding that client to the source list and filtering that client's LAN IP when sending sources to
641 // a client within the internet.
643 // "IPfilter" is not needed here, because that "known" client was already IPfiltered when receiving OP_HELLO.
644 if (!source->HasLowID()) {
645 uint32 nClientIP = wxUINT32_SWAP_ALWAYS(source->GetUserIDHybrid());
646 if (!IsGoodIP(nClientIP, thePrefs::FilterLanIPs())) { // check for 0-IP, localhost and LAN addresses
647 AddDebugLogLineN(logIPFilter, wxT("Ignored already known source with IP=%s") + Uint32toStringIP(nClientIP));
648 return;
652 // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
653 if ( (source->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source->SupportsCryptLayer() || !source->HasValidHash())))
655 source->Safe_Delete();
656 return;
659 CPartFile* file = source->GetRequestFile();
661 // Check if the file is already queued for something else
662 if ( file ) {
663 if ( file != sender ) {
664 if ( source->AddRequestForAnotherFile( sender ) ) {
665 Notify_SourceCtrlAddSource( sender, source, A4AF_SOURCE );
668 } else {
669 source->SetRequestFile( sender );
671 if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) {
672 sender->UpdateFileRatingCommentAvail();
675 source->SetSourceFrom(SF_PASSIVE);
676 sender->AddSource( source );
677 Notify_SourceCtrlAddSource( sender, source, UNAVAILABLE_SOURCE);
682 bool CDownloadQueue::RemoveSource(CUpDownClient* toremove, bool WXUNUSED(updatewindow), bool bDoStatsUpdate)
684 bool removed = false;
685 toremove->DeleteAllFileRequests();
687 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
688 CPartFile* cur_file = GetFileByIndex( i );
690 // Remove from source-list
691 if ( cur_file->DelSource( toremove ) ) {
693 // Remove from sourcelist widget
694 Notify_SourceCtrlRemoveSource(toremove, cur_file);
696 cur_file->RemoveDownloadingSource(toremove);
697 removed = true;
698 if ( bDoStatsUpdate ) {
699 cur_file->UpdatePartsInfo();
703 // Remove from A4AF-list
704 cur_file->RemoveA4AFSource( toremove );
708 if ( !toremove->GetFileComment().IsEmpty() || toremove->GetFileRating()>0) {
709 toremove->GetRequestFile()->UpdateFileRatingCommentAvail();
712 toremove->SetRequestFile( NULL );
713 toremove->SetDownloadState(DS_NONE);
714 toremove->ResetFileStatusInfo();
716 return removed;
720 void CDownloadQueue::RemoveFile(CPartFile* file)
722 RemoveLocalServerRequest( file );
724 NotifyObservers( EventType( EventType::REMOVED, file ) );
726 wxMutexLocker lock( m_mutex );
728 EraseValue( m_filelist, file );
732 CUpDownClient* CDownloadQueue::GetDownloadClientByIP_UDP(uint32 dwIP, uint16 nUDPPort) const
734 wxMutexLocker lock( m_mutex );
736 for ( unsigned int i = 0; i < m_filelist.size(); i++ ) {
737 const CKnownFile::SourceSet& set = m_filelist[i]->GetSourceList();
739 for ( CKnownFile::SourceSet::const_iterator it = set.begin(); it != set.end(); it++ ) {
740 if ( (*it)->GetIP() == dwIP && (*it)->GetUDPPort() == nUDPPort ) {
741 return *it;
745 return NULL;
750 * Checks if the specified server is the one we are connected to.
752 bool IsConnectedServer(const CServer* server)
754 if (server && theApp->serverconnect->GetCurrentServer()) {
755 wxString srvAddr = theApp->serverconnect->GetCurrentServer()->GetAddress();
756 uint16 srvPort = theApp->serverconnect->GetCurrentServer()->GetPort();
758 return server->GetAddress() == srvAddr && server->GetPort() == srvPort;
761 return false;
765 bool CDownloadQueue::SendNextUDPPacket()
767 if ( m_filelist.empty() || !theApp->serverconnect->IsUDPSocketAvailable() || !theApp->IsConnectedED2K()) {
768 return false;
771 // Start monitoring the server and the files list
772 if ( !m_queueServers.IsActive() ) {
773 AddObserver( &m_queueFiles );
775 theApp->serverlist->AddObserver( &m_queueServers );
779 bool packetSent = false;
780 while ( !packetSent ) {
781 // Get max files ids per packet for current server
782 int filesAllowed = GetMaxFilesPerUDPServerPacket();
784 if (filesAllowed < 1 || !m_udpserver || IsConnectedServer(m_udpserver)) {
785 // Select the next server to ask, must not be the connected server
786 do {
787 m_udpserver = m_queueServers.GetNext();
788 } while (IsConnectedServer(m_udpserver));
790 m_cRequestsSentToServer = 0;
791 filesAllowed = GetMaxFilesPerUDPServerPacket();
795 // Check if we have asked all servers, in which case we are done
796 if (m_udpserver == NULL) {
797 DoStopUDPRequests();
799 return false;
802 // Memoryfile containing the hash of every file to request
803 // 28bytes allocation because 16b + 4b + 8b is the worse case scenario.
804 CMemFile hashlist( 28 );
806 CPartFile* file = m_queueFiles.GetNext();
808 while ( file && filesAllowed ) {
809 uint8 status = file->GetStatus();
811 if ( ( status == PS_READY || status == PS_EMPTY ) && file->GetSourceCount() < thePrefs::GetMaxSourcePerFileUDP() ) {
812 if (file->IsLargeFile() && !m_udpserver->SupportsLargeFilesUDP()) {
813 AddDebugLogLineN(logDownloadQueue, wxT("UDP Request for sources on a large file ignored: server doesn't support it"));
814 } else {
815 ++m_cRequestsSentToServer;
816 hashlist.WriteHash( file->GetFileHash() );
817 // See the notes on TCP packet
818 if ( m_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2 ) {
819 if (file->IsLargeFile()) {
820 wxASSERT(m_udpserver->SupportsLargeFilesUDP());
821 hashlist.WriteUInt32( 0 );
822 hashlist.WriteUInt64( file->GetFileSize() );
823 } else {
824 hashlist.WriteUInt32( file->GetFileSize() );
827 --filesAllowed;
831 // Avoid skipping a file if we can't send any more currently
832 if ( filesAllowed ) {
833 file = m_queueFiles.GetNext();
837 // See if we have anything to send
838 if ( hashlist.GetLength() ) {
839 packetSent = SendGlobGetSourcesUDPPacket(hashlist);
842 // Check if we've covered every file
843 if ( file == NULL ) {
844 // Reset the list of asked files so that the loop will start over
845 m_queueFiles.Reset();
847 // Unset the server so that the next server will be used
848 m_udpserver = NULL;
852 return true;
856 void CDownloadQueue::StopUDPRequests()
858 wxMutexLocker lock( m_mutex );
860 DoStopUDPRequests();
864 void CDownloadQueue::DoStopUDPRequests()
866 // No need to observe when we wont be using the results
867 theApp->serverlist->RemoveObserver( &m_queueServers );
868 RemoveObserver( &m_queueFiles );
870 m_udpserver = 0;
871 m_lastudpsearchtime = ::GetTickCount();
875 // Comparison function needed by sort. Returns true if file1 preceeds file2
876 bool ComparePartFiles(const CPartFile* file1, const CPartFile* file2) {
877 if (file1->GetDownPriority() != file2->GetDownPriority()) {
878 // To place high-priority files before low priority files we have to
879 // invert this test, since PR_LOW is lower than PR_HIGH, and since
880 // placing a PR_LOW file before a PR_HIGH file would mean that
881 // the PR_LOW file gets sources before the PR_HIGH file ...
882 return (file1->GetDownPriority() > file2->GetDownPriority());
883 } else {
884 int sourcesA = file1->GetSourceCount();
885 int sourcesB = file2->GetSourceCount();
887 int notSourcesA = file1->GetNotCurrentSourcesCount();
888 int notSourcesB = file2->GetNotCurrentSourcesCount();
890 int cmp = CmpAny( sourcesA - notSourcesA, sourcesB - notSourcesB );
892 if ( cmp == 0 ) {
893 cmp = CmpAny( notSourcesA, notSourcesB );
896 return cmp < 0;
901 void CDownloadQueue::DoSortByPriority()
903 m_lastsorttime = ::GetTickCount();
904 sort( m_filelist.begin(), m_filelist.end(), ComparePartFiles );
908 void CDownloadQueue::ResetLocalServerRequests()
910 wxMutexLocker lock( m_mutex );
912 m_dwNextTCPSrcReq = 0;
913 m_localServerReqQueue.clear();
915 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
916 m_filelist[i]->SetLocalSrcRequestQueued(false);
921 void CDownloadQueue::RemoveLocalServerRequest( CPartFile* file )
923 wxMutexLocker lock( m_mutex );
925 EraseValue( m_localServerReqQueue, file );
927 file->SetLocalSrcRequestQueued(false);
931 void CDownloadQueue::ProcessLocalRequests()
933 wxMutexLocker lock( m_mutex );
935 bool bServerSupportsLargeFiles = theApp->serverconnect
936 && theApp->serverconnect->GetCurrentServer()
937 && theApp->serverconnect->GetCurrentServer()->SupportsLargeFilesTCP();
939 if ( (!m_localServerReqQueue.empty()) && (m_dwNextTCPSrcReq < ::GetTickCount()) ) {
940 CMemFile dataTcpFrame(22);
941 const int iMaxFilesPerTcpFrame = 15;
942 int iFiles = 0;
943 while (!m_localServerReqQueue.empty() && iFiles < iMaxFilesPerTcpFrame) {
944 // find the file with the longest waitingtime
945 uint32 dwBestWaitTime = 0xFFFFFFFF;
947 std::list<CPartFile*>::iterator posNextRequest = m_localServerReqQueue.end();
948 std::list<CPartFile*>::iterator it = m_localServerReqQueue.begin();
949 while( it != m_localServerReqQueue.end() ) {
950 CPartFile* cur_file = (*it);
951 if (cur_file->GetStatus() == PS_READY || cur_file->GetStatus() == PS_EMPTY) {
952 uint8 nPriority = cur_file->GetDownPriority();
953 if (nPriority > PR_HIGH) {
954 wxFAIL;
955 nPriority = PR_HIGH;
958 if (cur_file->GetLastSearchTime() + (PR_HIGH-nPriority) < dwBestWaitTime ){
959 dwBestWaitTime = cur_file->GetLastSearchTime() + (PR_HIGH - nPriority);
960 posNextRequest = it;
963 it++;
964 } else {
965 it = m_localServerReqQueue.erase(it);
966 cur_file->SetLocalSrcRequestQueued(false);
967 AddDebugLogLineN(logDownloadQueue,
968 CFormat(wxT("Local server source request for file '%s' not sent because of status '%s'"))
969 % cur_file->GetFileName() % cur_file->getPartfileStatus());
973 if (posNextRequest != m_localServerReqQueue.end()) {
974 CPartFile* cur_file = (*posNextRequest);
975 cur_file->SetLocalSrcRequestQueued(false);
976 cur_file->SetLastSearchTime(::GetTickCount());
977 m_localServerReqQueue.erase(posNextRequest);
978 iFiles++;
980 if (!bServerSupportsLargeFiles && cur_file->IsLargeFile()) {
981 AddDebugLogLineN(logDownloadQueue, wxT("TCP Request for sources on a large file ignored: server doesn't support it"));
982 } else {
983 AddDebugLogLineN(logDownloadQueue,
984 CFormat(wxT("Creating local sources request packet for '%s'")) % cur_file->GetFileName());
985 // create request packet
986 CMemFile data(16 + (cur_file->IsLargeFile() ? 8 : 4));
987 data.WriteHash(cur_file->GetFileHash());
988 // Kry - lugdunum extended protocol on 17.3 to handle filesize properly.
989 // There is no need to check anything, old server ignore the extra 4 bytes.
990 // As of 17.9, servers accept a 0 32-bits size and then a 64bits size
991 if (cur_file->IsLargeFile()) {
992 wxASSERT(bServerSupportsLargeFiles);
993 data.WriteUInt32(0);
994 data.WriteUInt64(cur_file->GetFileSize());
995 } else {
996 data.WriteUInt32(cur_file->GetFileSize());
998 uint8 byOpcode = 0;
999 if (thePrefs::IsClientCryptLayerSupported() && theApp->serverconnect->GetCurrentServer() != NULL && theApp->serverconnect->GetCurrentServer()->SupportsGetSourcesObfuscation()) {
1000 byOpcode = OP_GETSOURCES_OBFU;
1001 } else {
1002 byOpcode = OP_GETSOURCES;
1004 CPacket packet(data, OP_EDONKEYPROT, byOpcode);
1005 dataTcpFrame.Write(packet.GetPacket(), packet.GetRealPacketSize());
1010 int iSize = dataTcpFrame.GetLength();
1011 if (iSize > 0) {
1012 // create one 'packet' which contains all buffered OP_GETSOURCES ED2K packets to be sent with one TCP frame
1013 // server credits: (16+4)*regularfiles + (16+4+8)*largefiles +1
1014 CScopedPtr<CPacket> packet(new CPacket(new byte[iSize], dataTcpFrame.GetLength(), true, false));
1015 dataTcpFrame.Seek(0, wxFromStart);
1016 dataTcpFrame.Read(packet->GetPacket(), iSize);
1017 uint32 size = packet->GetPacketSize();
1018 theApp->serverconnect->SendPacket(packet.release(), true); // Deletes `packet'.
1019 AddDebugLogLineN(logDownloadQueue, wxT("Sent local sources request packet."));
1020 theStats::AddUpOverheadServer(size);
1023 // next TCP frame with up to 15 source requests is allowed to be sent in..
1024 m_dwNextTCPSrcReq = ::GetTickCount() + SEC2MS(iMaxFilesPerTcpFrame*(16+4));
1030 void CDownloadQueue::SendLocalSrcRequest(CPartFile* sender)
1032 wxMutexLocker lock( m_mutex );
1034 m_localServerReqQueue.push_back(sender);
1038 void CDownloadQueue::ResetCatParts(uint8 cat)
1040 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
1041 CPartFile* file = GetFileByIndex( i );
1043 if ( file->GetCategory() == cat ) {
1044 // Reset the category
1045 file->SetCategory( 0 );
1046 } else if ( file->GetCategory() > cat ) {
1047 // Set to the new position of the original category
1048 file->SetCategory( file->GetCategory() - 1 );
1054 void CDownloadQueue::SetCatPrio(uint8 cat, uint8 newprio)
1056 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
1057 CPartFile* file = GetFileByIndex( i );
1059 if ( !cat || file->GetCategory() == cat ) {
1060 if ( newprio == PR_AUTO ) {
1061 file->SetAutoDownPriority(true);
1062 } else {
1063 file->SetAutoDownPriority(false);
1064 file->SetDownPriority(newprio);
1071 void CDownloadQueue::SetCatStatus(uint8 cat, int newstatus)
1073 std::list<CPartFile*> files;
1076 wxMutexLocker lock(m_mutex);
1078 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
1079 if ( m_filelist[i]->CheckShowItemInGivenCat(cat) ) {
1080 files.push_back( m_filelist[i] );
1085 std::list<CPartFile*>::iterator it = files.begin();
1087 for ( ; it != files.end(); it++ ) {
1088 switch ( newstatus ) {
1089 case MP_CANCEL: (*it)->Delete(); break;
1090 case MP_PAUSE: (*it)->PauseFile(); break;
1091 case MP_STOP: (*it)->StopFile(); break;
1092 case MP_RESUME: (*it)->ResumeFile(); break;
1098 uint16 CDownloadQueue::GetDownloadingFileCount() const
1100 wxMutexLocker lock( m_mutex );
1102 uint16 count = 0;
1103 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
1104 uint8 status = m_filelist[i]->GetStatus();
1105 if ( status == PS_READY || status == PS_EMPTY ) {
1106 count++;
1110 return count;
1114 uint16 CDownloadQueue::GetPausedFileCount() const
1116 wxMutexLocker lock( m_mutex );
1118 uint16 count = 0;
1119 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
1120 if ( m_filelist[i]->GetStatus() == PS_PAUSED ) {
1121 count++;
1125 return count;
1129 void CDownloadQueue::CheckDiskspace( const CPath& path )
1131 if ( ::GetTickCount() - m_lastDiskCheck < DISKSPACERECHECKTIME ) {
1132 return;
1135 m_lastDiskCheck = ::GetTickCount();
1137 uint64 min = 0;
1138 // Check if the user has set an explicit limit
1139 if ( thePrefs::IsCheckDiskspaceEnabled() ) {
1140 min = thePrefs::GetMinFreeDiskSpace();
1143 // The very least acceptable diskspace is a single PART
1144 if ( min < PARTSIZE ) {
1145 min = PARTSIZE;
1148 uint64 free = CPath::GetFreeSpaceAt(path);
1149 if (free == static_cast<uint64>(wxInvalidOffset)) {
1150 return;
1151 } else if (free < min) {
1152 CUserEvents::ProcessEvent(
1153 CUserEvents::OutOfDiskSpace,
1154 wxT("Temporary partition"));
1157 for (unsigned int i = 0; i < m_filelist.size(); ++i) {
1158 CPartFile* file = m_filelist[i];
1160 switch ( file->GetStatus() ) {
1161 case PS_ERROR:
1162 case PS_COMPLETING:
1163 case PS_COMPLETE:
1164 continue;
1167 if ( free >= min && file->GetInsufficient() ) {
1168 // We'll try to resume files if there is enough free space
1169 if ( free - file->GetNeededSpace() > min ) {
1170 file->ResumeFile();
1172 } else if ( free < min && !file->IsPaused() ) {
1173 // No space left, stop the files.
1174 file->PauseFile( true );
1180 int CDownloadQueue::GetMaxFilesPerUDPServerPacket() const
1182 if ( m_udpserver ) {
1183 if ( m_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES ) {
1184 // get max. file ids per packet
1185 if ( m_cRequestsSentToServer < MAX_REQUESTS_PER_SERVER ) {
1186 return std::min(
1187 MAX_FILES_PER_UDP_PACKET,
1188 MAX_REQUESTS_PER_SERVER - m_cRequestsSentToServer
1191 } else if ( m_cRequestsSentToServer < MAX_REQUESTS_PER_SERVER ) {
1192 return 1;
1196 return 0;
1200 bool CDownloadQueue::SendGlobGetSourcesUDPPacket(CMemFile& data)
1202 if (!m_udpserver) {
1203 return false;
1206 CPacket packet(data, OP_EDONKEYPROT, ((m_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2) ? OP_GLOBGETSOURCES2 : OP_GLOBGETSOURCES));
1208 theStats::AddUpOverheadServer(packet.GetPacketSize());
1209 theApp->serverconnect->SendUDPPacket(&packet,m_udpserver,false);
1211 return true;
1215 void CDownloadQueue::AddToResolve(const CMD4Hash& fileid, const wxString& pszHostname, uint16 port, const wxString& hash, uint8 cryptoptions)
1217 // double checking
1218 if ( !GetFileByID(fileid) ) {
1219 return;
1222 wxMutexLocker lock( m_mutex );
1224 Hostname_Entry entry = { fileid, pszHostname, port, hash, cryptoptions };
1225 m_toresolve.push_front(entry);
1227 // Check if there are other DNS lookups on queue
1228 if (m_toresolve.size() == 1) {
1229 // Check if it is a simple dot address
1230 uint32 ip = StringIPtoUint32(pszHostname);
1232 if (ip) {
1233 OnHostnameResolved(ip);
1234 } else {
1235 CAsyncDNS* dns = new CAsyncDNS(pszHostname, DNS_SOURCE, theApp);
1237 if ((dns->Create() != wxTHREAD_NO_ERROR) || (dns->Run() != wxTHREAD_NO_ERROR)) {
1238 dns->Delete();
1239 m_toresolve.pop_front();
1246 void CDownloadQueue::OnHostnameResolved(uint32 ip)
1248 wxMutexLocker lock( m_mutex );
1250 wxASSERT( m_toresolve.size() );
1252 Hostname_Entry resolved = m_toresolve.front();
1253 m_toresolve.pop_front();
1255 if ( ip ) {
1256 CPartFile* file = GetFileByID( resolved.fileid );
1257 if ( file ) {
1258 CMemFile sources(1+4+2);
1259 sources.WriteUInt8(1); // No. Sources
1260 sources.WriteUInt32(ip);
1261 sources.WriteUInt16(resolved.port);
1262 sources.WriteUInt8(resolved.cryptoptions);
1263 if (resolved.cryptoptions & 0x80) {
1264 wxASSERT(!resolved.hash.IsEmpty());
1265 CMD4Hash sourcehash;
1266 sourcehash.Decode(resolved.hash);
1267 sources.WriteHash(sourcehash);
1269 sources.Seek(0,wxFromStart);
1271 file->AddSources(sources, 0, 0, SF_LINK, true);
1275 while (m_toresolve.size()) {
1276 Hostname_Entry entry = m_toresolve.front();
1278 // Check if it is a simple dot address
1279 uint32 tmpIP = StringIPtoUint32(entry.strHostname);
1281 if (tmpIP) {
1282 OnHostnameResolved(tmpIP);
1283 } else {
1284 CAsyncDNS* dns = new CAsyncDNS(entry.strHostname, DNS_SOURCE, theApp);
1286 if ((dns->Create() != wxTHREAD_NO_ERROR) || (dns->Run() != wxTHREAD_NO_ERROR)) {
1287 dns->Delete();
1288 m_toresolve.pop_front();
1289 } else {
1290 break;
1297 bool CDownloadQueue::AddLink( const wxString& link, uint8 category )
1299 wxString uri(link);
1301 if (link.compare(0, 7, wxT("magnet:")) == 0) {
1302 uri = CMagnetED2KConverter(link);
1303 if (uri.empty()) {
1304 AddLogLineC(CFormat(_("Cannot convert magnet link to eD2k: %s")) % link);
1305 return false;
1309 if (uri.compare(0, 7, wxT("ed2k://")) == 0) {
1310 return AddED2KLink(uri, category);
1311 } else {
1312 AddLogLineC(CFormat(_("Unknown protocol of link: %s")) % link);
1313 return false;
1318 bool CDownloadQueue::AddED2KLink( const wxString& link, uint8 category )
1320 wxASSERT( !link.IsEmpty() );
1321 wxString URI = link;
1323 // Need the links to end with /, otherwise CreateLinkFromUrl crashes us.
1324 if ( URI.Last() != wxT('/') ) {
1325 URI += wxT("/");
1328 try {
1329 CScopedPtr<CED2KLink> uri(CED2KLink::CreateLinkFromUrl(URI));
1331 return AddED2KLink( uri.get(), category );
1332 } catch ( const wxString& err ) {
1333 AddLogLineC(CFormat( _("Invalid eD2k link! ERROR: %s")) % err);
1336 return false;
1340 bool CDownloadQueue::AddED2KLink( const CED2KLink* link, uint8 category )
1342 switch ( link->GetKind() ) {
1343 case CED2KLink::kFile:
1344 return AddED2KLink( dynamic_cast<const CED2KFileLink*>( link ), category );
1346 case CED2KLink::kServer:
1347 return AddED2KLink( dynamic_cast<const CED2KServerLink*>( link ) );
1349 case CED2KLink::kServerList:
1350 return AddED2KLink( dynamic_cast<const CED2KServerListLink*>( link ) );
1352 default:
1353 return false;
1359 bool CDownloadQueue::AddED2KLink( const CED2KFileLink* link, uint8 category )
1361 CPartFile* file = NULL;
1362 if (IsFileExisting(link->GetHashKey())) {
1363 // Must be a shared file if we are to add hashes or sources
1364 if ((file = GetFileByID(link->GetHashKey())) == NULL) {
1365 return false;
1367 } else {
1368 if (link->GetSize() > OLD_MAX_FILE_SIZE) {
1369 if (!PlatformSpecific::CanFSHandleLargeFiles(thePrefs::GetTempDir())) {
1370 AddLogLineC(_("Filesystem for Temp directory cannot handle large files."));
1371 return false;
1372 } else if (!PlatformSpecific::CanFSHandleLargeFiles(theApp->glob_prefs->GetCatPath(category))) {
1373 AddLogLineC(_("Filesystem for Incoming directory cannot handle large files."));
1374 return false;
1378 file = new CPartFile(link);
1380 if (file->GetStatus() == PS_ERROR) {
1381 delete file;
1382 return false;
1385 AddDownload(file, thePrefs::AddNewFilesPaused(), category);
1388 if (link->HasValidAICHHash()) {
1389 CAICHHashSet* hashset = file->GetAICHHashset();
1391 if (!hashset->HasValidMasterHash() || (hashset->GetMasterHash() != link->GetAICHHash())) {
1392 hashset->SetMasterHash(link->GetAICHHash(), AICH_VERIFIED);
1393 hashset->FreeHashSet();
1397 const CED2KFileLink::CED2KLinkSourceList& list = link->m_sources;
1398 CED2KFileLink::CED2KLinkSourceList::const_iterator it = list.begin();
1399 for (; it != list.end(); ++it) {
1400 AddToResolve(link->GetHashKey(), it->addr, it->port, it->hash, it->cryptoptions);
1403 return true;
1407 bool CDownloadQueue::AddED2KLink( const CED2KServerLink* link )
1409 CServer *server = new CServer( link->GetPort(), Uint32toStringIP( link->GetIP() ) );
1411 server->SetListName( Uint32toStringIP( link->GetIP() ) );
1413 theApp->serverlist->AddServer(server);
1415 Notify_ServerAdd(server);
1417 return true;
1421 bool CDownloadQueue::AddED2KLink( const CED2KServerListLink* link )
1423 theApp->serverlist->UpdateServerMetFromURL( link->GetAddress() );
1425 return true;
1429 void CDownloadQueue::ObserverAdded( ObserverType* o )
1431 CObservableQueue<CPartFile*>::ObserverAdded( o );
1433 EventType::ValueList list;
1436 wxMutexLocker lock(m_mutex);
1437 list.reserve( m_filelist.size() );
1438 list.insert( list.begin(), m_filelist.begin(), m_filelist.end() );
1441 NotifyObservers( EventType( EventType::INITIAL, &list ), o );
1444 void CDownloadQueue::KademliaSearchFile(uint32_t searchID, const Kademlia::CUInt128* pcontactID, const Kademlia::CUInt128* pbuddyID, uint8_t type, uint32_t ip, uint16_t tcp, uint16_t udp, uint32_t buddyip, uint16_t buddyport, uint8_t byCryptOptions)
1446 AddDebugLogLineN(logKadSearch, CFormat(wxT("Search result sources (type %i)")) % type);
1448 //Safety measure to make sure we are looking for these sources
1449 CPartFile* temp = GetFileByKadFileSearchID(searchID);
1450 if( !temp ) {
1451 AddDebugLogLineN(logKadSearch, wxT("This is not the file we're looking for..."));
1452 return;
1455 //Do we need more sources?
1456 if(!(!temp->IsStopped() && thePrefs::GetMaxSourcePerFile() > temp->GetSourceCount())) {
1457 AddDebugLogLineN(logKadSearch, wxT("No more sources needed for this file"));
1458 return;
1461 uint32_t ED2KID = wxUINT32_SWAP_ALWAYS(ip);
1463 if (theApp->ipfilter->IsFiltered(ED2KID)) {
1464 AddDebugLogLineN(logKadSearch, wxT("Source ip got filtered"));
1465 AddDebugLogLineN(logIPFilter, CFormat(wxT("IPfiltered source IP=%s received from Kademlia")) % Uint32toStringIP(ED2KID));
1466 return;
1469 if( (ip == Kademlia::CKademlia::GetIPAddress() || ED2KID == theApp->GetED2KID()) && tcp == thePrefs::GetPort()) {
1470 AddDebugLogLineN(logKadSearch, wxT("Trying to add myself as source, ignore"));
1471 return;
1474 CUpDownClient* ctemp = NULL;
1475 switch (type) {
1476 case 4:
1477 case 1: {
1478 // NonFirewalled users
1479 if(!tcp) {
1480 AddDebugLogLineN(logKadSearch, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, no tcp port received")) % Uint32toStringIP(ip));
1481 return;
1483 if (!IsGoodIP(ED2KID,thePrefs::FilterLanIPs())) {
1484 AddDebugLogLineN(logKadSearch, CFormat(wxT("%s got filtered")) % Uint32toStringIP(ED2KID));
1485 AddDebugLogLineN(logIPFilter, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, filtered")) % Uint32toStringIP(ED2KID));
1486 return;
1488 ctemp = new CUpDownClient(tcp, ip, 0, 0, temp, false, true);
1489 ctemp->SetSourceFrom(SF_KADEMLIA);
1490 // not actually sent or needed for HighID sources
1491 //ctemp->SetServerIP(serverip);
1492 //ctemp->SetServerPort(serverport);
1493 ctemp->SetKadPort(udp);
1494 byte cID[16];
1495 pcontactID->ToByteArray(cID);
1496 ctemp->SetUserHash(CMD4Hash(cID));
1497 break;
1499 case 2: {
1500 // Don't use this type... Some clients will process it wrong..
1501 break;
1503 case 5:
1504 case 3: {
1505 // This will be a firewalled client connected to Kad only.
1506 // We set the clientID to 1 as a Kad user only has 1 buddy.
1507 ctemp = new CUpDownClient(tcp, 1, 0, 0, temp, false, true);
1508 // The only reason we set the real IP is for when we get a callback
1509 // from this firewalled source, the compare method will match them.
1510 ctemp->SetSourceFrom(SF_KADEMLIA);
1511 ctemp->SetKadPort(udp);
1512 byte cID[16];
1513 pcontactID->ToByteArray(cID);
1514 ctemp->SetUserHash(CMD4Hash(cID));
1515 pbuddyID->ToByteArray(cID);
1516 ctemp->SetBuddyID(cID);
1517 ctemp->SetBuddyIP(buddyip);
1518 ctemp->SetBuddyPort(buddyport);
1519 break;
1521 case 6: {
1522 // firewalled source which supports direct UDP callback
1523 // if we are firewalled ourself, the source is useless to us
1524 if (theApp->IsFirewalled()) {
1525 break;
1528 if ((byCryptOptions & 0x08) == 0){
1529 AddDebugLogLineN(logKadSearch, CFormat(wxT("Received Kad source type 6 (direct callback) which has the direct callback flag not set (%s)")) % Uint32toStringIP(ED2KID));
1530 break;
1533 ctemp = new CUpDownClient(tcp, 1, 0, 0, temp, false, true);
1534 ctemp->SetSourceFrom(SF_KADEMLIA);
1535 ctemp->SetKadPort(udp);
1536 ctemp->SetIP(ED2KID); // need to set the IP address, which cannot be used for TCP but for UDP
1537 byte cID[16];
1538 pcontactID->ToByteArray(cID);
1539 ctemp->SetUserHash(CMD4Hash(cID));
1543 if (ctemp) {
1544 // add encryption settings
1545 ctemp->SetConnectOptions(byCryptOptions);
1547 AddDebugLogLineN(logKadSearch, CFormat(wxT("Happily adding a source (%s) type %d")) % Uint32_16toStringIP_Port(ED2KID, ctemp->GetUserPort()) % type);
1548 CheckAndAddSource(temp, ctemp);
1552 CPartFile* CDownloadQueue::GetFileByKadFileSearchID(uint32 id) const
1554 wxMutexLocker lock( m_mutex );
1556 for ( uint16 i = 0; i < m_filelist.size(); ++i ) {
1557 if ( id == m_filelist[i]->GetKadFileSearchID()) {
1558 return m_filelist[ i ];
1562 return NULL;
1565 bool CDownloadQueue::DoKademliaFileRequest()
1567 return ((::GetTickCount() - lastkademliafilerequest) > KADEMLIAASKTIME);
1569 // File_checked_for_headers