Upstream tarball 20080414
[amule.git] / src / DownloadQueue.cpp
blob7bf379afc602c846181fcec453bd196bf36aa076
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 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/textfile.h> // Needed for wxTextFile
35 #include <wx/utils.h>
37 #include "Server.h" // Needed for CServer
38 #include "Packet.h" // Needed for CPacket
39 #include "MemFile.h" // Needed for CMemFile
40 #include "ClientList.h" // Needed for CClientList
41 #include "updownclient.h" // Needed for CUpDownClient
42 #include "ServerList.h" // Needed for CServerList
43 #include "ServerConnect.h" // Needed for CServerConnect
44 #include "ED2KLink.h" // Needed for CED2KFileLink
45 #include "SearchList.h" // Needed for CSearchFile
46 #include "SharedFileList.h" // Needed for CSharedFileList
47 #include "PartFile.h" // Needed for CPartFile
48 #include "Preferences.h" // Needed for thePrefs
49 #include "amule.h" // Needed for theApp
50 #include "AsyncDNS.h" // Needed for CAsyncDNS
51 #include "Statistics.h" // Needed for theStats
52 #include "Logger.h"
53 #include <common/Format.h> // Needed for CFormat
54 #include "IPFilter.h"
55 #include <common/FileFunctions.h> // Needed for CDirIterator
56 #include "FileLock.h" // Needed for CFileLock
57 #include "GuiEvents.h" // Needed for Notify_*
58 #include "UserEvents.h"
59 #include "MagnetURI.h" // Needed for CMagnetED2KConverter
60 #include "ScopedPtr.h" // Needed for CScopedPtr
62 #include "kademlia/kademlia/Kademlia.h"
64 #include <string> // Do_not_auto_remove (mingw-gcc-3.4.5)
67 // Max. file IDs per UDP packet
68 // ----------------------------
69 // 576 - 30 bytes of header (28 for UDP, 2 for "E3 9A" edonkey proto) = 546 bytes
70 // 546 / 16 = 34
73 #define MAX_FILES_PER_UDP_PACKET 31 // 2+16*31 = 498 ... is still less than 512 bytes!!
74 #define MAX_REQUESTS_PER_SERVER 35
77 CDownloadQueue::CDownloadQueue()
78 // Needs to be recursive that that is can own an observer assigned to itself
79 : m_mutex( wxMUTEX_RECURSIVE )
81 m_datarate = 0;
82 m_udpserver = 0;
83 m_lastsorttime = 0;
84 m_lastudpsearchtime = 0;
85 m_lastudpstattime = 0;
86 m_udcounter = 0;
87 m_nLastED2KLinkCheck = 0;
88 m_dwNextTCPSrcReq = 0;
89 m_cRequestsSentToServer = 0;
90 m_lastDiskCheck = 0;
91 SetLastKademliaFileRequest();
95 CDownloadQueue::~CDownloadQueue()
97 if ( !m_filelist.empty() ) {
98 for ( unsigned int i = 0; i < m_filelist.size(); i++ ) {
99 printf("\rSaving PartFile %u of %u", i + 1, (unsigned int)m_filelist.size());
100 fflush(stdout);
101 delete m_filelist[i];
103 printf("\nAll PartFiles Saved.\n");
108 void CDownloadQueue::LoadMetFiles(const CPath& path)
110 printf("Loading temp files from %s.\n",
111 (const char *)unicode2char(path.GetPrintable()));
113 std::vector<CPath> files;
115 // Locate part-files to be loaded
116 CDirIterator TempDir(path);
117 CPath fileName = TempDir.GetFirstFile(CDirIterator::File, wxT("*.part.met"));
118 while (fileName.IsOk()) {
119 files.push_back(path.JoinPaths(fileName));
121 fileName = TempDir.GetNextFile();
124 // Loading in order makes it easier to figure which
125 // file is broken in case of crashes, or the like.
126 std::sort(files.begin(), files.end());
128 // Load part-files
129 for ( size_t i = 0; i < files.size(); i++ ) {
130 printf("\rLoading PartFile %u of %u", (unsigned int)(i + 1), (unsigned int)files.size());
132 fileName = files[i].GetFullName();
134 CPartFile* toadd = new CPartFile();
135 bool result = (toadd->LoadPartFile(path, fileName) != 0);
136 if (!result) {
137 // Try from backup
138 result = (toadd->LoadPartFile(path, fileName, true) != 0);
141 if (result && !IsFileExisting(toadd->GetFileHash())) {
143 wxMutexLocker lock(m_mutex);
144 m_filelist.push_back(toadd);
147 NotifyObservers( EventType( EventType::INSERTED, toadd ) );
148 Notify_DownloadCtrlAddFile(toadd);
149 } else {
150 delete toadd;
152 wxString msg;
153 if (result) {
154 msg << CFormat(wxT("WARNING: Duplicate partfile with hash '%s' found, skipping: %s"))
155 % toadd->GetFileHash().Encode() % fileName;
156 } else {
157 // If result is false, then reading of both the primary and the backup .met failed
158 AddLogLineM(false,
159 _("Error: Failed to load backup file. Search http://forum.amule.org for .part.met recovery solutions."));
160 msg << CFormat(wxT("ERROR: Failed to load PartFile '%s'")) % fileName;
163 AddDebugLogLineM(true, logPartFile, msg);
165 // Newline so that the error stays visible.
166 printf(": %s\n", (const char*)unicode2char(msg));
170 printf("\nAll PartFiles Loaded.\n");
172 if ( GetFileCount() == 0 ) {
173 AddLogLineM(false, _("No part files found"));
174 } else {
175 AddLogLineM(false, wxString::Format(wxPLURAL("Found %u part file", "Found %u part files", GetFileCount()), GetFileCount()) );
177 DoSortByPriority();
178 CheckDiskspace( path );
183 uint16 CDownloadQueue::GetFileCount() const
185 wxMutexLocker lock( m_mutex );
187 return m_filelist.size();
191 CServer* CDownloadQueue::GetUDPServer() const
193 wxMutexLocker lock( m_mutex );
195 return m_udpserver;
199 void CDownloadQueue::SetUDPServer( CServer* server )
201 wxMutexLocker lock( m_mutex );
203 m_udpserver = server;
207 void CDownloadQueue::SaveSourceSeeds()
209 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
210 GetFileByIndex( i )->SaveSourceSeeds();
215 void CDownloadQueue::LoadSourceSeeds()
217 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
218 GetFileByIndex( i )->LoadSourceSeeds();
222 //#warning We must add the sources, review CSearchFile constructor.
223 void CDownloadQueue::AddSearchToDownload(CSearchFile* toadd, uint8 category)
225 if ( IsFileExisting(toadd->GetFileHash()) ) {
226 return;
230 CPartFile* newfile = NULL;
231 try {
232 newfile = new CPartFile(toadd);
233 } catch (const CInvalidPacket& WXUNUSED(e)) {
234 AddDebugLogLineM(true, logDownloadQueue, wxT("Search-result contained invalid tags, could not add"));
237 if ( newfile && newfile->GetStatus() != PS_ERROR ) {
238 AddDownload( newfile, thePrefs::AddNewFilesPaused(), category );
239 } else {
240 delete newfile;
245 struct SFindBestPF
247 void operator()(CPartFile* file) {
248 // Check if we should filter out other categories
249 if ((m_category != -1) && (file->GetCategory() != m_category)) {
250 return;
251 } else if (file->GetStatus() != PS_PAUSED) {
252 return;
255 if (!m_result || (file->GetDownPriority() > m_result->GetDownPriority())) {
256 m_result = file;
260 //! The category to look for, or -1 if any category is good
261 int m_category;
262 //! If any acceptable files are found, this variable store their pointer
263 CPartFile* m_result;
267 void CDownloadQueue::StartNextFile(CPartFile* oldfile)
269 if ( thePrefs::StartNextFile() ) {
270 SFindBestPF visitor = { -1, NULL };
273 wxMutexLocker lock(m_mutex);
275 if (thePrefs::StartNextFileSame()) {
276 // Get a download in the same category
277 visitor.m_category = oldfile->GetCategory();
279 visitor = std::for_each(m_filelist.begin(), m_filelist.end(), visitor);
282 if (visitor.m_result == NULL) {
283 // Get a download, regardless of category
284 visitor.m_category = -1;
286 visitor = std::for_each(m_filelist.begin(), m_filelist.end(), visitor);
290 if (visitor.m_result) {
291 visitor.m_result->ResumeFile();
297 void CDownloadQueue::AddDownload(CPartFile* file, bool paused, uint8 category)
299 wxCHECK_RET(!IsFileExisting(file->GetFileHash()), wxT("Adding duplicate part-file"));
301 if ( paused && GetFileCount() ) {
302 file->StopFile();
306 wxMutexLocker lock(m_mutex);
307 m_filelist.push_back( file );
308 DoSortByPriority();
311 NotifyObservers( EventType( EventType::INSERTED, file ) );
313 file->SetCategory(category);
314 Notify_DownloadCtrlAddFile( file );
315 AddLogLineM(true, CFormat(_("Downloading %s")) % file->GetFileName() );
319 bool CDownloadQueue::IsFileExisting( const CMD4Hash& fileid ) const
321 if (CKnownFile* file = theApp->sharedfiles->GetFileByID(fileid)) {
322 if (file->IsPartFile()) {
323 AddLogLineM(true, CFormat( _("You are already trying to download the file '%s'") ) % file->GetFileName());
324 } else {
325 // Check if the file exists, since otherwise the user is forced to
326 // manually reload the shares to download a file again.
327 CPath fullpath = file->GetFilePath().JoinPaths(file->GetFileName());
328 if (!fullpath.FileExists()) {
329 // The file is no longer available, unshare it
330 theApp->sharedfiles->RemoveFile(file);
332 return false;
335 AddLogLineM(true, CFormat( _("You already have the file '%s'") ) % file->GetFileName());
338 return true;
339 } else if ((file = GetFileByID(fileid))) {
340 AddLogLineM(true, CFormat( _("You are already trying to download the file %s") ) % file->GetFileName());
341 return true;
344 return false;
348 void CDownloadQueue::Process()
350 // send src requests to local server
351 ProcessLocalRequests();
354 wxMutexLocker lock(m_mutex);
356 uint32 downspeed = 0;
357 if (thePrefs::GetMaxDownload() != UNLIMITED && m_datarate > 1500) {
358 downspeed = (((uint32)thePrefs::GetMaxDownload())*1024*100)/(m_datarate+1);
359 if (downspeed < 50) {
360 downspeed = 50;
361 } else if (downspeed > 200) {
362 downspeed = 200;
366 m_datarate = 0;
367 m_udcounter++;
368 uint32 cur_datarate = 0;
369 uint32 cur_udcounter = m_udcounter;
371 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
372 CPartFile* file = m_filelist[i];
374 CMutexUnlocker unlocker(m_mutex);
376 if ( file->GetStatus() == PS_READY || file->GetStatus() == PS_EMPTY ){
377 cur_datarate += file->Process( downspeed, cur_udcounter );
378 } else {
379 //This will make sure we don't keep old sources to paused and stoped files..
380 file->StopPausedFile();
384 m_datarate += cur_datarate;
387 if (m_udcounter == 5) {
388 if (theApp->serverconnect->IsUDPSocketAvailable()) {
389 if( (::GetTickCount() - m_lastudpstattime) > UDPSERVERSTATTIME) {
390 m_lastudpstattime = ::GetTickCount();
392 CMutexUnlocker unlocker(m_mutex);
393 theApp->serverlist->ServerStats();
398 if (m_udcounter == 10) {
399 m_udcounter = 0;
400 if (theApp->serverconnect->IsUDPSocketAvailable()) {
401 if ( (::GetTickCount() - m_lastudpsearchtime) > UDPSERVERREASKTIME) {
402 SendNextUDPPacket();
407 if ( (::GetTickCount() - m_lastsorttime) > 10000 ) {
410 DoSortByPriority();
412 // Check if any paused files can be resumed
414 CheckDiskspace(thePrefs::GetTempDir());
418 // Check for new links once per second.
419 if ((::GetTickCount() - m_nLastED2KLinkCheck) >= 1000) {
420 AddLinksFromFile();
421 m_nLastED2KLinkCheck = ::GetTickCount();
426 CPartFile* CDownloadQueue::GetFileByID(const CMD4Hash& filehash) const
428 wxMutexLocker lock( m_mutex );
430 for ( uint16 i = 0; i < m_filelist.size(); ++i ) {
431 if ( filehash == m_filelist[i]->GetFileHash()) {
432 return m_filelist[ i ];
436 return NULL;
440 CPartFile* CDownloadQueue::GetFileByIndex(unsigned int index) const
442 wxMutexLocker lock( m_mutex );
444 if ( index < m_filelist.size() ) {
445 return m_filelist[ index ];
448 wxASSERT( false );
449 return NULL;
453 bool CDownloadQueue::IsPartFile(const CKnownFile* file) const
455 wxMutexLocker lock(m_mutex);
457 for (uint16 i = 0; i < m_filelist.size(); ++i) {
458 if (file == m_filelist[i]) {
459 return true;
463 return false;
467 void CDownloadQueue::OnConnectionState(bool bConnected)
469 wxMutexLocker lock(m_mutex);
471 for (uint16 i = 0; i < m_filelist.size(); ++i) {
472 if ( m_filelist[i]->GetStatus() == PS_READY ||
473 m_filelist[i]->GetStatus() == PS_EMPTY) {
474 m_filelist[i]->SetActive(bConnected);
480 void CDownloadQueue::CheckAndAddSource(CPartFile* sender, CUpDownClient* source)
482 // if we block loopbacks at this point it should prevent us from connecting to ourself
483 if ( source->HasValidHash() ) {
484 if ( source->GetUserHash() == thePrefs::GetUserHash() ) {
485 AddDebugLogLineM( false, logDownloadQueue, wxT("Tried to add source with matching hash to your own.") );
486 source->Safe_Delete();
487 return;
491 if (sender->IsStopped()) {
492 source->Safe_Delete();
493 return;
496 // Filter sources which are known to be dead/useless
497 if ( theApp->clientlist->IsDeadSource( source ) || sender->IsDeadSource(source) ) {
498 source->Safe_Delete();
499 return;
502 // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
503 if ( (source->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source->SupportsCryptLayer() || !source->HasValidHash()))) {
504 source->Safe_Delete();
505 return;
508 // Find all clients with the same hash
509 if ( source->HasValidHash() ) {
510 CClientList::SourceList found = theApp->clientlist->GetClientsByHash( source->GetUserHash() );
512 CClientList::SourceList::iterator it = found.begin();
513 for ( ; it != found.end(); it++ ) {
514 CKnownFile* file = (*it)->GetRequestFile();
516 // Only check files on the download-queue
517 if ( file ) {
518 // Is the found source queued for something else?
519 if ( file != sender ) {
520 // Try to add a request for the other file
521 if ( (*it)->AddRequestForAnotherFile(sender)) {
522 // Add it to downloadlistctrl
523 Notify_DownloadCtrlAddSource(sender, *it, A4AF_SOURCE);
527 source->Safe_Delete();
528 return;
535 // Our new source is real new but maybe it is already uploading to us?
536 // If yes the known client will be attached to the var "source" and the old
537 // source-client will be deleted. However, if the request file of the known
538 // source is NULL, then we have to treat it almost like a new source and if
539 // it isn't NULL and not "sender", then we shouldn't move it, but rather add
540 // a request for the new file.
541 ESourceFrom nSourceFrom = source->GetSourceFrom();
542 if ( theApp->clientlist->AttachToAlreadyKnown(&source, 0) ) {
543 // Already queued for another file?
544 if ( source->GetRequestFile() ) {
545 // If we're already queued for the right file, then there's nothing to do
546 if ( sender != source->GetRequestFile() ) {
547 // Add the new file to the request list
548 source->AddRequestForAnotherFile( sender );
550 } else {
551 // Source was known, but reqfile NULL.
552 source->SetRequestFile( sender );
553 if (source->GetSourceFrom() != nSourceFrom) {
554 if (source->GetSourceFrom() != SF_NONE) {
555 theStats::RemoveSourceOrigin(source->GetSourceFrom());
556 theStats::RemoveFoundSource();
558 source->SetSourceFrom(nSourceFrom);
560 sender->AddSource( source );
561 if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) {
562 sender->UpdateFileRatingCommentAvail();
565 Notify_DownloadCtrlAddSource(sender, source, UNAVAILABLE_SOURCE);
567 } else {
568 // Unknown client, add it to the clients list
569 source->SetRequestFile( sender );
571 theApp->clientlist->AddClient(source);
573 sender->AddSource( source );
574 if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) {
575 sender->UpdateFileRatingCommentAvail();
578 Notify_DownloadCtrlAddSource(sender, source, UNAVAILABLE_SOURCE);
583 void CDownloadQueue::CheckAndAddKnownSource(CPartFile* sender,CUpDownClient* source)
585 // Kad reviewed
587 if (sender->IsStopped()) {
588 return;
591 // Filter sources which are known to be dead/useless
592 if ( sender->IsDeadSource(source) ) {
593 return;
596 // "Filter LAN IPs" -- this may be needed here in case we are connected to the internet and are also connected
597 // to a LAN and some client from within the LAN connected to us. Though this situation may be supported in future
598 // by adding that client to the source list and filtering that client's LAN IP when sending sources to
599 // a client within the internet.
601 // "IPfilter" is not needed here, because that "known" client was already IPfiltered when receiving OP_HELLO.
602 if (!source->HasLowID()) {
603 uint32 nClientIP = wxUINT32_SWAP_ALWAYS(source->GetUserIDHybrid());
604 if (!IsGoodIP(nClientIP, thePrefs::FilterLanIPs())) { // check for 0-IP, localhost and LAN addresses
605 AddDebugLogLineM(false, logIPFilter, wxT("Ignored already known source with IP=%s") + Uint32toStringIP(nClientIP));
606 return;
610 // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
611 if ( (source->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source->SupportsCryptLayer() || !source->HasValidHash())))
613 source->Safe_Delete();
614 return;
617 CPartFile* file = source->GetRequestFile();
619 // Check if the file is already queued for something else
620 if ( file ) {
621 if ( file != sender ) {
622 if ( source->AddRequestForAnotherFile( sender ) ) {
623 Notify_DownloadCtrlAddSource( sender, source, A4AF_SOURCE );
626 } else {
627 source->SetRequestFile( sender );
629 if ( source->GetFileRating() || !source->GetFileComment().IsEmpty() ) {
630 sender->UpdateFileRatingCommentAvail();
633 source->SetSourceFrom(SF_PASSIVE);
634 sender->AddSource( source );
635 Notify_DownloadCtrlAddSource( sender, source, UNAVAILABLE_SOURCE);
640 bool CDownloadQueue::RemoveSource(CUpDownClient* toremove, bool WXUNUSED(updatewindow), bool bDoStatsUpdate)
642 bool removed = false;
643 toremove->DeleteAllFileRequests();
645 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
646 CPartFile* cur_file = GetFileByIndex( i );
648 // Remove from source-list
649 if ( cur_file->DelSource( toremove ) ) {
650 cur_file->RemoveDownloadingSource(toremove);
651 removed = true;
652 if ( bDoStatsUpdate ) {
653 cur_file->UpdatePartsInfo();
657 // Remove from A4AF-list
658 cur_file->RemoveA4AFSource( toremove );
662 if ( !toremove->GetFileComment().IsEmpty() || toremove->GetFileRating()>0) {
663 toremove->GetRequestFile()->UpdateFileRatingCommentAvail();
666 toremove->SetRequestFile( NULL );
667 toremove->SetDownloadState(DS_NONE);
669 // Remove from downloadlist widget
670 Notify_DownloadCtrlRemoveSource(toremove, (CPartFile*)NULL);
671 toremove->ResetFileStatusInfo();
673 return removed;
677 void CDownloadQueue::RemoveFile(CPartFile* file)
679 RemoveLocalServerRequest( file );
681 NotifyObservers( EventType( EventType::REMOVED, file ) );
683 wxMutexLocker lock( m_mutex );
685 EraseValue( m_filelist, file );
689 CUpDownClient* CDownloadQueue::GetDownloadClientByIP_UDP(uint32 dwIP, uint16 nUDPPort) const
691 wxMutexLocker lock( m_mutex );
693 for ( unsigned int i = 0; i < m_filelist.size(); i++ ) {
694 const CPartFile::SourceSet& set = m_filelist[i]->GetSourceList();
696 for ( CPartFile::SourceSet::const_iterator it = set.begin(); it != set.end(); it++ ) {
697 if ( (*it)->GetIP() == dwIP && (*it)->GetUDPPort() == nUDPPort ) {
698 return *it;
702 return NULL;
707 * Checks if the specified server is the one we are connected to.
709 bool IsConnectedServer(const CServer* server)
711 if (server && theApp->serverconnect->GetCurrentServer()) {
712 wxString srvAddr = theApp->serverconnect->GetCurrentServer()->GetAddress();
713 uint16 srvPort = theApp->serverconnect->GetCurrentServer()->GetPort();
715 return server->GetAddress() == srvAddr && server->GetPort() == srvPort;
718 return false;
722 bool CDownloadQueue::SendNextUDPPacket()
724 if ( m_filelist.empty() || !theApp->serverconnect->IsUDPSocketAvailable() || !theApp->IsConnectedED2K()) {
725 return false;
728 // Start monitoring the server and the files list
729 if ( !m_queueServers.IsActive() ) {
730 AddObserver( &m_queueFiles );
732 theApp->serverlist->AddObserver( &m_queueServers );
736 bool packetSent = false;
737 while ( !packetSent ) {
738 // Get max files ids per packet for current server
739 int filesAllowed = GetMaxFilesPerUDPServerPacket();
741 if (filesAllowed < 1 || !m_udpserver || IsConnectedServer(m_udpserver)) {
742 // Select the next server to ask, must not be the connected server
743 do {
744 m_udpserver = m_queueServers.GetNext();
745 } while (IsConnectedServer(m_udpserver));
747 m_cRequestsSentToServer = 0;
748 filesAllowed = GetMaxFilesPerUDPServerPacket();
752 // Check if we have asked all servers, in which case we are done
753 if (m_udpserver == NULL) {
754 DoStopUDPRequests();
756 return false;
759 // Memoryfile containing the hash of every file to request
760 // 28bytes allocation because 16b + 4b + 8b is the worse case scenario.
761 CMemFile hashlist( 28 );
763 CPartFile* file = m_queueFiles.GetNext();
765 while ( file && filesAllowed ) {
766 uint8 status = file->GetStatus();
768 if ( ( status == PS_READY || status == PS_EMPTY ) && file->GetSourceCount() < thePrefs::GetMaxSourcePerFileUDP() ) {
769 if (file->IsLargeFile() && !m_udpserver->SupportsLargeFilesUDP()) {
770 AddDebugLogLineM(false, logDownloadQueue, wxT("UDP Request for sources on a large file ignored: server doesn't support it"));
771 } else {
772 ++m_cRequestsSentToServer;
773 hashlist.WriteHash( file->GetFileHash() );
774 // See the notes on TCP packet
775 if ( m_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2 ) {
776 if (file->IsLargeFile()) {
777 wxASSERT(m_udpserver->SupportsLargeFilesUDP());
778 hashlist.WriteUInt32( 0 );
779 hashlist.WriteUInt64( file->GetFileSize() );
780 } else {
781 hashlist.WriteUInt32( file->GetFileSize() );
784 --filesAllowed;
788 // Avoid skipping a file if we can't send any more currently
789 if ( filesAllowed ) {
790 file = m_queueFiles.GetNext();
794 // See if we have anything to send
795 if ( hashlist.GetLength() ) {
796 packetSent = SendGlobGetSourcesUDPPacket(hashlist);
799 // Check if we've covered every file
800 if ( file == NULL ) {
801 // Reset the list of asked files so that the loop will start over
802 m_queueFiles.Reset();
804 // Unset the server so that the next server will be used
805 m_udpserver = NULL;
809 return true;
813 void CDownloadQueue::StopUDPRequests()
815 wxMutexLocker lock( m_mutex );
817 DoStopUDPRequests();
821 void CDownloadQueue::DoStopUDPRequests()
823 // No need to observe when we wont be using the results
824 theApp->serverlist->RemoveObserver( &m_queueServers );
825 RemoveObserver( &m_queueFiles );
827 m_udpserver = 0;
828 m_lastudpsearchtime = ::GetTickCount();
832 // Comparison function needed by sort. Returns true if file1 preceeds file2
833 bool ComparePartFiles(const CPartFile* file1, const CPartFile* file2) {
834 if (file1->GetDownPriority() != file2->GetDownPriority()) {
835 // To place high-priority files before low priority files we have to
836 // invert this test, since PR_LOW is lower than PR_HIGH, and since
837 // placing a PR_LOW file before a PR_HIGH file would mean that
838 // the PR_LOW file gets sources before the PR_HIGH file ...
839 return (file1->GetDownPriority() > file2->GetDownPriority());
840 } else {
841 int sourcesA = file1->GetSourceCount();
842 int sourcesB = file2->GetSourceCount();
844 int notSourcesA = file1->GetNotCurrentSourcesCount();
845 int notSourcesB = file2->GetNotCurrentSourcesCount();
847 int cmp = CmpAny( sourcesA - notSourcesA, sourcesB - notSourcesB );
849 if ( cmp == 0 ) {
850 cmp = CmpAny( notSourcesA, notSourcesB );
853 return cmp < 0;
858 void CDownloadQueue::DoSortByPriority()
860 m_lastsorttime = ::GetTickCount();
861 sort( m_filelist.begin(), m_filelist.end(), ComparePartFiles );
865 void CDownloadQueue::ResetLocalServerRequests()
867 wxMutexLocker lock( m_mutex );
869 m_dwNextTCPSrcReq = 0;
870 m_localServerReqQueue.clear();
872 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
873 m_filelist[i]->SetLocalSrcRequestQueued(false);
878 void CDownloadQueue::RemoveLocalServerRequest( CPartFile* file )
880 wxMutexLocker lock( m_mutex );
882 EraseValue( m_localServerReqQueue, file );
884 file->SetLocalSrcRequestQueued(false);
888 void CDownloadQueue::ProcessLocalRequests()
890 wxMutexLocker lock( m_mutex );
892 bool bServerSupportsLargeFiles = theApp->serverconnect
893 && theApp->serverconnect->GetCurrentServer()
894 && theApp->serverconnect->GetCurrentServer()->SupportsLargeFilesTCP();
896 if ( (!m_localServerReqQueue.empty()) && (m_dwNextTCPSrcReq < ::GetTickCount()) ) {
897 CMemFile dataTcpFrame(22);
898 const int iMaxFilesPerTcpFrame = 15;
899 int iFiles = 0;
900 while (!m_localServerReqQueue.empty() && iFiles < iMaxFilesPerTcpFrame) {
901 // find the file with the longest waitingtime
902 uint32 dwBestWaitTime = 0xFFFFFFFF;
904 std::list<CPartFile*>::iterator posNextRequest = m_localServerReqQueue.end();
905 std::list<CPartFile*>::iterator it = m_localServerReqQueue.begin();
906 while( it != m_localServerReqQueue.end() ) {
907 CPartFile* cur_file = (*it);
908 if (cur_file->GetStatus() == PS_READY || cur_file->GetStatus() == PS_EMPTY) {
909 uint8 nPriority = cur_file->GetDownPriority();
910 if (nPriority > PR_HIGH) {
911 wxASSERT(0);
912 nPriority = PR_HIGH;
915 if (cur_file->GetLastSearchTime() + (PR_HIGH-nPriority) < dwBestWaitTime ){
916 dwBestWaitTime = cur_file->GetLastSearchTime() + (PR_HIGH - nPriority);
917 posNextRequest = it;
920 it++;
921 } else {
922 it = m_localServerReqQueue.erase(it);
923 cur_file->SetLocalSrcRequestQueued(false);
924 AddDebugLogLineM( false, logDownloadQueue,
925 CFormat(wxT("Local server source request for file '%s' not sent because of status '%s'"))
926 % cur_file->GetFileName() % cur_file->getPartfileStatus());
930 if (posNextRequest != m_localServerReqQueue.end()) {
931 CPartFile* cur_file = (*posNextRequest);
932 cur_file->SetLocalSrcRequestQueued(false);
933 cur_file->SetLastSearchTime(::GetTickCount());
934 m_localServerReqQueue.erase(posNextRequest);
935 iFiles++;
937 if (!bServerSupportsLargeFiles && cur_file->IsLargeFile()) {
938 AddDebugLogLineM(false, logDownloadQueue, wxT("TCP Request for sources on a large file ignored: server doesn't support it"));
939 } else {
940 AddDebugLogLineM(false, logDownloadQueue,
941 CFormat(wxT("Creating local sources request packet for '%s'")) % cur_file->GetFileName());
942 // create request packet
943 CMemFile data(16 + (cur_file->IsLargeFile() ? 8 : 4));
944 data.WriteHash(cur_file->GetFileHash());
945 // Kry - lugdunum extended protocol on 17.3 to handle filesize properly.
946 // There is no need to check anything, old server ignore the extra 4 bytes.
947 // As of 17.9, servers accept a 0 32-bits size and then a 64bits size
948 if (cur_file->IsLargeFile()) {
949 wxASSERT(bServerSupportsLargeFiles);
950 data.WriteUInt32(0);
951 data.WriteUInt64(cur_file->GetFileSize());
952 } else {
953 data.WriteUInt32(cur_file->GetFileSize());
955 uint8 byOpcode = 0;
956 if (thePrefs::IsClientCryptLayerSupported() && theApp->serverconnect->GetCurrentServer() != NULL && theApp->serverconnect->GetCurrentServer()->SupportsGetSourcesObfuscation()) {
957 byOpcode = OP_GETSOURCES_OBFU;
958 } else {
959 byOpcode = OP_GETSOURCES;
961 CPacket packet(data, OP_EDONKEYPROT, byOpcode);
962 dataTcpFrame.Write(packet.GetPacket(), packet.GetRealPacketSize());
967 int iSize = dataTcpFrame.GetLength();
968 if (iSize > 0) {
969 // create one 'packet' which contains all buffered OP_GETSOURCES ED2K packets to be sent with one TCP frame
970 // server credits: (16+4)*regularfiles + (16+4+8)*largefiles +1
971 CPacket* packet = new CPacket(new byte[iSize], dataTcpFrame.GetLength(), true, false);
972 dataTcpFrame.Seek(0, wxFromStart);
973 dataTcpFrame.Read(packet->GetPacket(), iSize);
974 uint32 size = packet->GetPacketSize();
975 theApp->serverconnect->SendPacket(packet, true); // Deletes `packet'.
976 AddDebugLogLineM(false, logDownloadQueue, wxT("Sent local sources request packet."));
977 theStats::AddUpOverheadServer(size);
980 // next TCP frame with up to 15 source requests is allowed to be sent in..
981 m_dwNextTCPSrcReq = ::GetTickCount() + SEC2MS(iMaxFilesPerTcpFrame*(16+4));
987 void CDownloadQueue::SendLocalSrcRequest(CPartFile* sender)
989 wxMutexLocker lock( m_mutex );
991 m_localServerReqQueue.push_back(sender);
995 void CDownloadQueue::AddLinksFromFile()
997 const wxString fullPath = theApp->ConfigDir + wxT("ED2KLinks");
998 if (!wxFile::Exists(fullPath)) {
999 return;
1002 // Attempt to lock the ED2KLinks file.
1003 CFileLock lock((const char*)unicode2char(fullPath));
1005 wxTextFile file(fullPath);
1006 if ( file.Open() ) {
1007 for ( unsigned int i = 0; i < file.GetLineCount(); i++ ) {
1008 wxString line = file.GetLine( i ).Strip( wxString::both );
1010 if ( !line.IsEmpty() ) {
1011 // Special case! used by a secondary running mule to raise this one.
1012 if ( line == wxT("RAISE_DIALOG") ) {
1013 Notify_ShowGUI();
1014 continue;
1017 AddLink( line );
1021 file.Close();
1022 } else {
1023 printf("Failed to open ED2KLinks file.\n");
1026 // Delete the file.
1027 wxRemoveFile(theApp->ConfigDir + wxT("ED2KLinks"));
1031 void CDownloadQueue::ResetCatParts(uint8 cat)
1033 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
1034 CPartFile* file = GetFileByIndex( i );
1036 if ( file->GetCategory() == cat ) {
1037 // Reset the category
1038 file->SetCategory( 0 );
1039 } else if ( file->GetCategory() > cat ) {
1040 // Set to the new position of the original category
1041 file->SetCategory( file->GetCategory() - 1 );
1047 void CDownloadQueue::SetCatPrio(uint8 cat, uint8 newprio)
1049 for ( uint16 i = 0; i < GetFileCount(); i++ ) {
1050 CPartFile* file = GetFileByIndex( i );
1052 if ( !cat || file->GetCategory() == cat ) {
1053 if ( newprio == PR_AUTO ) {
1054 file->SetAutoDownPriority(true);
1055 } else {
1056 file->SetAutoDownPriority(false);
1057 file->SetDownPriority(newprio);
1064 void CDownloadQueue::SetCatStatus(uint8 cat, int newstatus)
1066 std::list<CPartFile*> files;
1069 wxMutexLocker lock(m_mutex);
1071 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
1072 if ( m_filelist[i]->CheckShowItemInGivenCat(cat) ) {
1073 files.push_back( m_filelist[i] );
1078 std::list<CPartFile*>::iterator it = files.begin();
1080 for ( ; it != files.end(); it++ ) {
1081 switch ( newstatus ) {
1082 case MP_CANCEL: (*it)->Delete(); break;
1083 case MP_PAUSE: (*it)->PauseFile(); break;
1084 case MP_STOP: (*it)->StopFile(); break;
1085 case MP_RESUME: (*it)->ResumeFile(); break;
1091 uint16 CDownloadQueue::GetDownloadingFileCount() const
1093 wxMutexLocker lock( m_mutex );
1095 uint16 count = 0;
1096 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
1097 uint8 status = m_filelist[i]->GetStatus();
1098 if ( status == PS_READY || status == PS_EMPTY ) {
1099 count++;
1103 return count;
1107 uint16 CDownloadQueue::GetPausedFileCount() const
1109 wxMutexLocker lock( m_mutex );
1111 uint16 count = 0;
1112 for ( uint16 i = 0; i < m_filelist.size(); i++ ) {
1113 if ( m_filelist[i]->GetStatus() == PS_PAUSED ) {
1114 count++;
1118 return count;
1122 void CDownloadQueue::CheckDiskspace( const CPath& path )
1124 if ( ::GetTickCount() - m_lastDiskCheck < DISKSPACERECHECKTIME ) {
1125 return;
1128 m_lastDiskCheck = ::GetTickCount();
1130 uint64 min = 0;
1131 // Check if the user has set an explicit limit
1132 if ( thePrefs::IsCheckDiskspaceEnabled() ) {
1133 min = thePrefs::GetMinFreeDiskSpace();
1136 // The very least acceptable diskspace is a single PART
1137 if ( min < PARTSIZE ) {
1138 min = PARTSIZE;
1141 uint64 free = CPath::GetFreeSpaceAt(path);
1142 if (free == static_cast<uint64>(wxInvalidOffset)) {
1143 return;
1144 } else if (free < min) {
1145 CUserEvents::ProcessEvent(
1146 CUserEvents::OutOfDiskSpace,
1147 wxT("Temporary partition"));
1150 for (unsigned int i = 0; i < m_filelist.size(); ++i) {
1151 CPartFile* file = m_filelist[i];
1153 switch ( file->GetStatus() ) {
1154 case PS_ERROR:
1155 case PS_COMPLETING:
1156 case PS_COMPLETE:
1157 continue;
1160 if ( free >= min && file->GetInsufficient() ) {
1161 // We'll try to resume files if there is enough free space
1162 if ( free - file->GetNeededSpace() > min ) {
1163 file->ResumeFile();
1165 } else if ( free < min && !file->IsPaused() ) {
1166 // No space left, stop the files.
1167 file->PauseFile( true );
1173 int CDownloadQueue::GetMaxFilesPerUDPServerPacket() const
1175 if ( m_udpserver ) {
1176 if ( m_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES ) {
1177 // get max. file ids per packet
1178 if ( m_cRequestsSentToServer < MAX_REQUESTS_PER_SERVER ) {
1179 return std::min(
1180 MAX_FILES_PER_UDP_PACKET,
1181 MAX_REQUESTS_PER_SERVER - m_cRequestsSentToServer
1184 } else if ( m_cRequestsSentToServer < MAX_REQUESTS_PER_SERVER ) {
1185 return 1;
1189 return 0;
1193 bool CDownloadQueue::SendGlobGetSourcesUDPPacket(CMemFile& data)
1195 if (!m_udpserver) {
1196 return false;
1199 CPacket packet(data, OP_EDONKEYPROT, ((m_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2) ? OP_GLOBGETSOURCES2 : OP_GLOBGETSOURCES));
1201 theStats::AddUpOverheadServer(packet.GetPacketSize());
1202 theApp->serverconnect->SendUDPPacket(&packet,m_udpserver,false);
1204 return true;
1208 void CDownloadQueue::AddToResolve(const CMD4Hash& fileid, const wxString& pszHostname, uint16 port, const wxString& hash, uint8 cryptoptions)
1210 // double checking
1211 if ( !GetFileByID(fileid) ) {
1212 return;
1215 wxMutexLocker lock( m_mutex );
1217 Hostname_Entry entry = { fileid, pszHostname, port, hash, cryptoptions };
1218 m_toresolve.push_front(entry);
1220 // Check if there are other DNS lookups on queue
1221 if (m_toresolve.size() == 1) {
1222 // Check if it is a simple dot address
1223 uint32 ip = StringIPtoUint32(pszHostname);
1225 if (ip) {
1226 OnHostnameResolved(ip);
1227 } else {
1228 CAsyncDNS* dns = new CAsyncDNS(pszHostname, DNS_SOURCE, theApp);
1230 if ((dns->Create() != wxTHREAD_NO_ERROR) || (dns->Run() != wxTHREAD_NO_ERROR)) {
1231 dns->Delete();
1232 m_toresolve.pop_front();
1239 void CDownloadQueue::OnHostnameResolved(uint32 ip)
1241 wxMutexLocker lock( m_mutex );
1243 wxASSERT( m_toresolve.size() );
1245 Hostname_Entry resolved = m_toresolve.front();
1246 m_toresolve.pop_front();
1248 if ( ip ) {
1249 CPartFile* file = GetFileByID( resolved.fileid );
1250 if ( file ) {
1251 CMemFile sources(1+4+2);
1252 sources.WriteUInt8(1); // No. Sources
1253 sources.WriteUInt32(ip);
1254 sources.WriteUInt16(resolved.port);
1255 sources.WriteUInt8(resolved.cryptoptions);
1256 if (resolved.cryptoptions & 0x80) {
1257 wxASSERT(!resolved.hash.IsEmpty());
1258 CMD4Hash sourcehash;
1259 sourcehash.Decode(resolved.hash);
1260 sources.WriteHash(sourcehash);
1262 sources.Seek(0,wxFromStart);
1264 file->AddSources(sources, 0, 0, SF_LINK, true);
1268 while (m_toresolve.size()) {
1269 Hostname_Entry entry = m_toresolve.front();
1271 // Check if it is a simple dot address
1272 uint32 tmpIP = StringIPtoUint32(entry.strHostname);
1274 if (tmpIP) {
1275 OnHostnameResolved(tmpIP);
1276 } else {
1277 CAsyncDNS* dns = new CAsyncDNS(entry.strHostname, DNS_SOURCE, theApp);
1279 if ((dns->Create() != wxTHREAD_NO_ERROR) || (dns->Run() != wxTHREAD_NO_ERROR)) {
1280 dns->Delete();
1281 m_toresolve.pop_front();
1282 } else {
1283 break;
1290 bool CDownloadQueue::AddLink( const wxString& link, int category )
1292 wxString uri(link);
1294 if (link.compare(0, 7, wxT("magnet:")) == 0) {
1295 uri = CMagnetED2KConverter(link);
1296 if (uri.empty()) {
1297 AddLogLineM(true, CFormat(_("Cannot convert magnet link to ed2k: %s")) % link);
1298 return false;
1302 if (uri.compare(0, 7, wxT("ed2k://")) == 0) {
1303 return AddED2KLink(uri, category);
1304 } else {
1305 AddLogLineM(true, CFormat(_("Unknown protocol of link: %s")) % link);
1306 return false;
1311 bool CDownloadQueue::AddED2KLink( const wxString& link, int category )
1313 wxASSERT( !link.IsEmpty() );
1314 wxString URI = link;
1316 // Need the links to end with /, otherwise CreateLinkFromUrl crashes us.
1317 if ( URI.Last() != wxT('/') ) {
1318 URI += wxT("/");
1321 try {
1322 CScopedPtr<CED2KLink> uri(CED2KLink::CreateLinkFromUrl(URI));
1324 return AddED2KLink( uri.get(), category );
1325 } catch ( const wxString& err ) {
1326 AddLogLineM( true, CFormat( _("Invalid ed2k link! Error: %s")) % err);
1329 return false;
1333 bool CDownloadQueue::AddED2KLink( const CED2KLink* link, int category )
1335 switch ( link->GetKind() ) {
1336 case CED2KLink::kFile:
1337 return AddED2KLink( dynamic_cast<const CED2KFileLink*>( link ), category );
1339 case CED2KLink::kServer:
1340 return AddED2KLink( dynamic_cast<const CED2KServerLink*>( link ) );
1342 case CED2KLink::kServerList:
1343 return AddED2KLink( dynamic_cast<const CED2KServerListLink*>( link ) );
1345 default:
1346 return false;
1352 bool CDownloadQueue::AddED2KLink( const CED2KFileLink* link, int category )
1354 CPartFile* file = NULL;
1355 if (IsFileExisting(link->GetHashKey())) {
1356 // Must be a shared file if we are to add hashes or sources
1357 if ((file = GetFileByID(link->GetHashKey())) == NULL) {
1358 return false;
1360 } else {
1361 file = new CPartFile(link);
1363 if (file->GetStatus() == PS_ERROR) {
1364 delete file;
1365 return false;
1368 AddDownload(file, thePrefs::AddNewFilesPaused(), category);
1371 if (link->HasValidAICHHash()) {
1372 CAICHHashSet* hashset = file->GetAICHHashset();
1374 if (!hashset->HasValidMasterHash() || (hashset->GetMasterHash() != link->GetAICHHash())) {
1375 hashset->SetMasterHash(link->GetAICHHash(), AICH_VERIFIED);
1376 hashset->FreeHashSet();
1380 const CED2KFileLink::CED2KLinkSourceList& list = link->m_sources;
1381 CED2KFileLink::CED2KLinkSourceList::const_iterator it = list.begin();
1382 for (; it != list.end(); ++it) {
1383 AddToResolve(link->GetHashKey(), it->addr, it->port, it->hash, it->cryptoptions);
1386 return true;
1390 bool CDownloadQueue::AddED2KLink( const CED2KServerLink* link )
1392 CServer *server = new CServer( link->GetPort(), Uint32toStringIP( link->GetIP() ) );
1394 server->SetListName( Uint32toStringIP( link->GetIP() ) );
1396 theApp->serverlist->AddServer(server);
1398 Notify_ServerAdd(server);
1400 return true;
1404 bool CDownloadQueue::AddED2KLink( const CED2KServerListLink* link )
1406 theApp->serverlist->UpdateServerMetFromURL( link->GetAddress() );
1408 return true;
1412 void CDownloadQueue::ObserverAdded( ObserverType* o )
1414 CObservableQueue<CPartFile*>::ObserverAdded( o );
1416 EventType::ValueList list;
1419 wxMutexLocker lock(m_mutex);
1420 list.reserve( m_filelist.size() );
1421 list.insert( list.begin(), m_filelist.begin(), m_filelist.end() );
1424 NotifyObservers( EventType( EventType::INITIAL, &list ), o );
1427 void CDownloadQueue::KademliaSearchFile(uint32 searchID, const Kademlia::CUInt128* pcontactID, const Kademlia::CUInt128* pbuddyID, uint8 type, uint32 ip, uint16 tcp, uint16 udp, uint32 serverip, uint16 serverport, uint8 byCryptOptions)
1430 AddDebugLogLineM(false, logKadSearch, wxString::Format(wxT("Search result sources (type %i)"),type));
1432 //Safety measure to make sure we are looking for these sources
1433 CPartFile* temp = GetFileByKadFileSearchID(searchID);
1434 if( !temp ) {
1435 AddDebugLogLineM(false, logKadSearch, wxT("This is not the file we're looking for..."));
1436 return;
1439 //Do we need more sources?
1440 if(!(!temp->IsStopped() && thePrefs::GetMaxSourcePerFile() > temp->GetSourceCount())) {
1441 AddDebugLogLineM(false, logKadSearch, wxT("No more sources needed for this file"));
1442 return;
1445 uint32 ED2KID = wxUINT32_SWAP_ALWAYS(ip);
1447 if (theApp->ipfilter->IsFiltered(ED2KID)) {
1448 AddDebugLogLineM(false, logKadSearch, wxT("Source ip got filtered"));
1449 AddDebugLogLineM(false, logIPFilter, CFormat(wxT("IPfiltered source IP=%s received from Kademlia")) % Uint32toStringIP(ED2KID));
1450 return;
1453 if( (ip == Kademlia::CKademlia::GetIPAddress() || ED2KID == theApp->GetED2KID()) && tcp == thePrefs::GetPort()) {
1454 AddDebugLogLineM(false, logKadSearch, wxT("Trying to add myself as source, ignore"));
1455 return;
1458 CUpDownClient* ctemp = NULL;
1459 switch( type ) {
1460 case 4:
1461 case 1: {
1462 //NonFirewalled users
1463 if(!tcp) {
1464 AddDebugLogLineM(false, logKadSearch, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, no tcp port received")) % Uint32toStringIP(ip));
1465 return;
1467 if (!IsGoodIP(ED2KID,thePrefs::FilterLanIPs())) {
1468 AddDebugLogLineM(false, logKadSearch, CFormat(wxT("%s got filtered")) % Uint32toStringIP(ED2KID));
1469 AddDebugLogLineM(false, logIPFilter, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, filtered")) % Uint32toStringIP(ED2KID));
1470 return;
1472 ctemp = new CUpDownClient(tcp,ip,0,0,temp,false, true);
1473 ctemp->SetSourceFrom(SF_KADEMLIA);
1474 ctemp->SetServerIP(serverip);
1475 ctemp->SetServerPort(serverport);
1476 ctemp->SetKadPort(udp);
1477 byte cID[16];
1478 pcontactID->ToByteArray(cID);
1479 ctemp->SetUserHash(CMD4Hash(cID));
1480 break;
1482 case 2: {
1483 //Don't use this type... Some clients will process it wrong..
1484 break;
1486 case 5:
1487 case 3: {
1488 //This will be a firewaled client connected to Kad only.
1489 //We set the clientID to 1 as a Kad user only has 1 buddy.
1490 ctemp = new CUpDownClient(tcp,1,0,0,temp,false, true);
1491 //The only reason we set the real IP is for when we get a callback
1492 //from this firewalled source, the compare method will match them.
1493 ctemp->SetSourceFrom(SF_KADEMLIA);
1494 ctemp->SetKadPort(udp);
1495 byte cID[16];
1496 pcontactID->ToByteArray(cID);
1497 ctemp->SetUserHash(CMD4Hash(cID));
1498 pbuddyID->ToByteArray(cID);
1499 ctemp->SetBuddyID(cID);
1500 ctemp->SetBuddyIP(serverip);
1501 ctemp->SetBuddyPort(serverport);
1502 break;
1506 if (ctemp) {
1507 // add encryption settings
1508 ctemp->SetCryptLayerSupport((byCryptOptions & 0x01) != 0);
1509 ctemp->SetCryptLayerRequest((byCryptOptions & 0x02) != 0);
1510 ctemp->SetCryptLayerRequires((byCryptOptions & 0x04) != 0);
1512 AddDebugLogLineM(false, logKadSearch, CFormat(wxT("Happily adding a source (%s) type %d")) % Uint32_16toStringIP_Port(ip, ctemp->GetUserPort()) % type);
1513 CheckAndAddSource(temp, ctemp);
1517 CPartFile* CDownloadQueue::GetFileByKadFileSearchID(uint32 id) const
1520 wxMutexLocker lock( m_mutex );
1522 for ( uint16 i = 0; i < m_filelist.size(); ++i ) {
1523 if ( id == m_filelist[i]->GetKadFileSearchID()) {
1524 return m_filelist[ i ];
1528 return NULL;
1532 bool CDownloadQueue::DoKademliaFileRequest()
1534 return ((::GetTickCount() - lastkademliafilerequest) > KADEMLIAASKTIME);
1536 // File_checked_for_headers