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
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
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
53 #include <common/Format.h> // Needed for CFormat
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
61 #include "PlatformSpecific.h" // Needed for CanFSHandleLargeFiles
63 #include "kademlia/kademlia/Kademlia.h"
65 #include <string> // Do_not_auto_remove (mingw-gcc-3.4.5)
68 // Max. file IDs per UDP packet
69 // ----------------------------
70 // 576 - 30 bytes of header (28 for UDP, 2 for "E3 9A" edonkey proto) = 546 bytes
74 #define MAX_FILES_PER_UDP_PACKET 31 // 2+16*31 = 498 ... is still less than 512 bytes!!
75 #define MAX_REQUESTS_PER_SERVER 35
78 CDownloadQueue::CDownloadQueue()
79 // Needs to be recursive that that is can own an observer assigned to itself
80 : m_mutex( wxMUTEX_RECURSIVE
)
85 m_lastudpsearchtime
= 0;
86 m_lastudpstattime
= 0;
88 m_nLastED2KLinkCheck
= 0;
89 m_dwNextTCPSrcReq
= 0;
90 m_cRequestsSentToServer
= 0;
92 SetLastKademliaFileRequest();
96 CDownloadQueue::~CDownloadQueue()
98 if ( !m_filelist
.empty() ) {
99 for ( unsigned int i
= 0; i
< m_filelist
.size(); i
++ ) {
100 printf("\rSaving PartFile %u of %u", i
+ 1, (unsigned int)m_filelist
.size());
102 delete m_filelist
[i
];
104 printf("\nAll PartFiles Saved.\n");
109 void CDownloadQueue::LoadMetFiles(const CPath
& path
)
111 printf("Loading temp files from %s.\n",
112 (const char *)unicode2char(path
.GetPrintable()));
114 std::vector
<CPath
> files
;
116 // Locate part-files to be loaded
117 CDirIterator
TempDir(path
);
118 CPath fileName
= TempDir
.GetFirstFile(CDirIterator::File
, wxT("*.part.met"));
119 while (fileName
.IsOk()) {
120 files
.push_back(path
.JoinPaths(fileName
));
122 fileName
= TempDir
.GetNextFile();
125 // Loading in order makes it easier to figure which
126 // file is broken in case of crashes, or the like.
127 std::sort(files
.begin(), files
.end());
130 for ( size_t i
= 0; i
< files
.size(); i
++ ) {
131 printf("\rLoading PartFile %u of %u", (unsigned int)(i
+ 1), (unsigned int)files
.size());
133 fileName
= files
[i
].GetFullName();
135 CPartFile
* toadd
= new CPartFile();
136 bool result
= (toadd
->LoadPartFile(path
, fileName
) != 0);
139 result
= (toadd
->LoadPartFile(path
, fileName
, true) != 0);
142 if (result
&& !IsFileExisting(toadd
->GetFileHash())) {
144 wxMutexLocker
lock(m_mutex
);
145 m_filelist
.push_back(toadd
);
148 NotifyObservers( EventType( EventType::INSERTED
, toadd
) );
149 Notify_DownloadCtrlAddFile(toadd
);
155 msg
<< CFormat(wxT("WARNING: Duplicate partfile with hash '%s' found, skipping: %s"))
156 % toadd
->GetFileHash().Encode() % fileName
;
158 // If result is false, then reading of both the primary and the backup .met failed
160 _("ERROR: Failed to load backup file. Search http://forum.amule.org for .part.met recovery solutions."));
161 msg
<< CFormat(wxT("ERROR: Failed to load PartFile '%s'")) % fileName
;
164 AddDebugLogLineM(true, logPartFile
, msg
);
166 // Newline so that the error stays visible.
167 printf(": %s\n", (const char*)unicode2char(msg
));
171 printf("\nAll PartFiles Loaded.\n");
173 if ( GetFileCount() == 0 ) {
174 AddLogLineM(false, _("No part files found"));
176 AddLogLineM(false, wxString::Format(wxPLURAL("Found %u part file", "Found %u part files", GetFileCount()), GetFileCount()) );
179 CheckDiskspace( path
);
184 uint16
CDownloadQueue::GetFileCount() const
186 wxMutexLocker
lock( m_mutex
);
188 return m_filelist
.size();
192 CServer
* CDownloadQueue::GetUDPServer() const
194 wxMutexLocker
lock( m_mutex
);
200 void CDownloadQueue::SetUDPServer( CServer
* server
)
202 wxMutexLocker
lock( m_mutex
);
204 m_udpserver
= server
;
208 void CDownloadQueue::SaveSourceSeeds()
210 for ( uint16 i
= 0; i
< GetFileCount(); i
++ ) {
211 GetFileByIndex( i
)->SaveSourceSeeds();
216 void CDownloadQueue::LoadSourceSeeds()
218 for ( uint16 i
= 0; i
< GetFileCount(); i
++ ) {
219 GetFileByIndex( i
)->LoadSourceSeeds();
223 //#warning We must add the sources, review CSearchFile constructor.
224 void CDownloadQueue::AddSearchToDownload(CSearchFile
* toadd
, uint8 category
)
226 if ( IsFileExisting(toadd
->GetFileHash()) ) {
230 if (toadd
->GetFileSize() > OLD_MAX_FILE_SIZE
) {
231 if (!PlatformSpecific::CanFSHandleLargeFiles(thePrefs::GetTempDir())) {
232 AddLogLineM(true, _("Filesystem for Temp directory cannot handle large files."));
234 } else if (!PlatformSpecific::CanFSHandleLargeFiles(theApp
->glob_prefs
->GetCatPath(category
))) {
235 AddLogLineM(true, _("Filesystem for Incoming directory cannot handle large files."));
240 CPartFile
* newfile
= NULL
;
242 newfile
= new CPartFile(toadd
);
243 } catch (const CInvalidPacket
& WXUNUSED(e
)) {
244 AddDebugLogLineM(true, logDownloadQueue
, wxT("Search-result contained invalid tags, could not add"));
247 if ( newfile
&& newfile
->GetStatus() != PS_ERROR
) {
248 AddDownload( newfile
, thePrefs::AddNewFilesPaused(), category
);
257 void operator()(CPartFile
* file
) {
258 // Check if we should filter out other categories
259 if ((m_category
!= -1) && (file
->GetCategory() != m_category
)) {
261 } else if (file
->GetStatus() != PS_PAUSED
) {
265 if (!m_result
|| (file
->GetDownPriority() > m_result
->GetDownPriority())) {
270 //! The category to look for, or -1 if any category is good
272 //! If any acceptable files are found, this variable store their pointer
277 void CDownloadQueue::StartNextFile(CPartFile
* oldfile
)
279 if ( thePrefs::StartNextFile() ) {
280 SFindBestPF visitor
= { -1, NULL
};
283 wxMutexLocker
lock(m_mutex
);
285 if (thePrefs::StartNextFileSame()) {
286 // Get a download in the same category
287 visitor
.m_category
= oldfile
->GetCategory();
289 visitor
= std::for_each(m_filelist
.begin(), m_filelist
.end(), visitor
);
292 if (visitor
.m_result
== NULL
) {
293 // Get a download, regardless of category
294 visitor
.m_category
= -1;
296 visitor
= std::for_each(m_filelist
.begin(), m_filelist
.end(), visitor
);
300 if (visitor
.m_result
) {
301 visitor
.m_result
->ResumeFile();
307 void CDownloadQueue::AddDownload(CPartFile
* file
, bool paused
, uint8 category
)
309 wxCHECK_RET(!IsFileExisting(file
->GetFileHash()), wxT("Adding duplicate part-file"));
311 if (file
->GetStatus(true) == PS_ALLOCATING
) {
313 } else if (paused
&& GetFileCount()) {
318 wxMutexLocker
lock(m_mutex
);
319 m_filelist
.push_back( file
);
323 NotifyObservers( EventType( EventType::INSERTED
, file
) );
325 file
->SetCategory(category
);
326 Notify_DownloadCtrlAddFile( file
);
327 AddLogLineM(true, CFormat(_("Downloading %s")) % file
->GetFileName() );
331 bool CDownloadQueue::IsFileExisting( const CMD4Hash
& fileid
) const
333 if (CKnownFile
* file
= theApp
->sharedfiles
->GetFileByID(fileid
)) {
334 if (file
->IsPartFile()) {
335 AddLogLineM(true, CFormat( _("You are already trying to download the file '%s'") ) % file
->GetFileName());
337 // Check if the file exists, since otherwise the user is forced to
338 // manually reload the shares to download a file again.
339 CPath fullpath
= file
->GetFilePath().JoinPaths(file
->GetFileName());
340 if (!fullpath
.FileExists()) {
341 // The file is no longer available, unshare it
342 theApp
->sharedfiles
->RemoveFile(file
);
347 AddLogLineM(true, CFormat( _("You already have the file '%s'") ) % file
->GetFileName());
351 } else if ((file
= GetFileByID(fileid
))) {
352 AddLogLineM(true, CFormat( _("You are already trying to download the file %s") ) % file
->GetFileName());
360 void CDownloadQueue::Process()
362 // send src requests to local server
363 ProcessLocalRequests();
366 wxMutexLocker
lock(m_mutex
);
368 uint32 downspeed
= 0;
369 if (thePrefs::GetMaxDownload() != UNLIMITED
&& m_datarate
> 1500) {
370 downspeed
= (((uint32
)thePrefs::GetMaxDownload())*1024*100)/(m_datarate
+1);
371 if (downspeed
< 50) {
373 } else if (downspeed
> 200) {
380 uint32 cur_datarate
= 0;
381 uint32 cur_udcounter
= m_udcounter
;
383 for ( uint16 i
= 0; i
< m_filelist
.size(); i
++ ) {
384 CPartFile
* file
= m_filelist
[i
];
386 CMutexUnlocker
unlocker(m_mutex
);
388 if ( file
->GetStatus() == PS_READY
|| file
->GetStatus() == PS_EMPTY
){
389 cur_datarate
+= file
->Process( downspeed
, cur_udcounter
);
391 //This will make sure we don't keep old sources to paused and stoped files..
392 file
->StopPausedFile();
396 m_datarate
+= cur_datarate
;
399 if (m_udcounter
== 5) {
400 if (theApp
->serverconnect
->IsUDPSocketAvailable()) {
401 if( (::GetTickCount() - m_lastudpstattime
) > UDPSERVERSTATTIME
) {
402 m_lastudpstattime
= ::GetTickCount();
404 CMutexUnlocker
unlocker(m_mutex
);
405 theApp
->serverlist
->ServerStats();
410 if (m_udcounter
== 10) {
412 if (theApp
->serverconnect
->IsUDPSocketAvailable()) {
413 if ( (::GetTickCount() - m_lastudpsearchtime
) > UDPSERVERREASKTIME
) {
419 if ( (::GetTickCount() - m_lastsorttime
) > 10000 ) {
424 // Check if any paused files can be resumed
426 CheckDiskspace(thePrefs::GetTempDir());
430 // Check for new links once per second.
431 if ((::GetTickCount() - m_nLastED2KLinkCheck
) >= 1000) {
433 m_nLastED2KLinkCheck
= ::GetTickCount();
438 CPartFile
* CDownloadQueue::GetFileByID(const CMD4Hash
& filehash
) const
440 wxMutexLocker
lock( m_mutex
);
442 for ( uint16 i
= 0; i
< m_filelist
.size(); ++i
) {
443 if ( filehash
== m_filelist
[i
]->GetFileHash()) {
444 return m_filelist
[ i
];
452 CPartFile
* CDownloadQueue::GetFileByIndex(unsigned int index
) const
454 wxMutexLocker
lock( m_mutex
);
456 if ( index
< m_filelist
.size() ) {
457 return m_filelist
[ index
];
465 bool CDownloadQueue::IsPartFile(const CKnownFile
* file
) const
467 wxMutexLocker
lock(m_mutex
);
469 for (uint16 i
= 0; i
< m_filelist
.size(); ++i
) {
470 if (file
== m_filelist
[i
]) {
479 void CDownloadQueue::OnConnectionState(bool bConnected
)
481 wxMutexLocker
lock(m_mutex
);
483 for (uint16 i
= 0; i
< m_filelist
.size(); ++i
) {
484 if ( m_filelist
[i
]->GetStatus() == PS_READY
||
485 m_filelist
[i
]->GetStatus() == PS_EMPTY
) {
486 m_filelist
[i
]->SetActive(bConnected
);
492 void CDownloadQueue::CheckAndAddSource(CPartFile
* sender
, CUpDownClient
* source
)
494 // if we block loopbacks at this point it should prevent us from connecting to ourself
495 if ( source
->HasValidHash() ) {
496 if ( source
->GetUserHash() == thePrefs::GetUserHash() ) {
497 AddDebugLogLineM( false, logDownloadQueue
, wxT("Tried to add source with matching hash to your own.") );
498 source
->Safe_Delete();
503 if (sender
->IsStopped()) {
504 source
->Safe_Delete();
508 // Filter sources which are known to be dead/useless
509 if ( theApp
->clientlist
->IsDeadSource( source
) || sender
->IsDeadSource(source
) ) {
510 source
->Safe_Delete();
514 // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
515 if ( (source
->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source
->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source
->SupportsCryptLayer() || !source
->HasValidHash()))) {
516 source
->Safe_Delete();
520 // Find all clients with the same hash
521 if ( source
->HasValidHash() ) {
522 CClientList::SourceList found
= theApp
->clientlist
->GetClientsByHash( source
->GetUserHash() );
524 CClientList::SourceList::iterator it
= found
.begin();
525 for ( ; it
!= found
.end(); it
++ ) {
526 CKnownFile
* file
= (*it
)->GetRequestFile();
528 // Only check files on the download-queue
530 // Is the found source queued for something else?
531 if ( file
!= sender
) {
532 // Try to add a request for the other file
533 if ( (*it
)->AddRequestForAnotherFile(sender
)) {
534 // Add it to downloadlistctrl
535 Notify_DownloadCtrlAddSource(sender
, *it
, A4AF_SOURCE
);
539 source
->Safe_Delete();
547 // Our new source is real new but maybe it is already uploading to us?
548 // If yes the known client will be attached to the var "source" and the old
549 // source-client will be deleted. However, if the request file of the known
550 // source is NULL, then we have to treat it almost like a new source and if
551 // it isn't NULL and not "sender", then we shouldn't move it, but rather add
552 // a request for the new file.
553 ESourceFrom nSourceFrom
= source
->GetSourceFrom();
554 if ( theApp
->clientlist
->AttachToAlreadyKnown(&source
, 0) ) {
555 // Already queued for another file?
556 if ( source
->GetRequestFile() ) {
557 // If we're already queued for the right file, then there's nothing to do
558 if ( sender
!= source
->GetRequestFile() ) {
559 // Add the new file to the request list
560 source
->AddRequestForAnotherFile( sender
);
563 // Source was known, but reqfile NULL.
564 source
->SetRequestFile( sender
);
565 if (source
->GetSourceFrom() != nSourceFrom
) {
566 if (source
->GetSourceFrom() != SF_NONE
) {
567 theStats::RemoveSourceOrigin(source
->GetSourceFrom());
568 theStats::RemoveFoundSource();
570 source
->SetSourceFrom(nSourceFrom
);
572 sender
->AddSource( source
);
573 if ( source
->GetFileRating() || !source
->GetFileComment().IsEmpty() ) {
574 sender
->UpdateFileRatingCommentAvail();
577 Notify_DownloadCtrlAddSource(sender
, source
, UNAVAILABLE_SOURCE
);
580 // Unknown client, add it to the clients list
581 source
->SetRequestFile( sender
);
583 theApp
->clientlist
->AddClient(source
);
585 sender
->AddSource( source
);
586 if ( source
->GetFileRating() || !source
->GetFileComment().IsEmpty() ) {
587 sender
->UpdateFileRatingCommentAvail();
590 Notify_DownloadCtrlAddSource(sender
, source
, UNAVAILABLE_SOURCE
);
595 void CDownloadQueue::CheckAndAddKnownSource(CPartFile
* sender
,CUpDownClient
* source
)
599 if (sender
->IsStopped()) {
603 // Filter sources which are known to be dead/useless
604 if ( sender
->IsDeadSource(source
) ) {
608 // "Filter LAN IPs" -- this may be needed here in case we are connected to the internet and are also connected
609 // to a LAN and some client from within the LAN connected to us. Though this situation may be supported in future
610 // by adding that client to the source list and filtering that client's LAN IP when sending sources to
611 // a client within the internet.
613 // "IPfilter" is not needed here, because that "known" client was already IPfiltered when receiving OP_HELLO.
614 if (!source
->HasLowID()) {
615 uint32 nClientIP
= wxUINT32_SWAP_ALWAYS(source
->GetUserIDHybrid());
616 if (!IsGoodIP(nClientIP
, thePrefs::FilterLanIPs())) { // check for 0-IP, localhost and LAN addresses
617 AddDebugLogLineM(false, logIPFilter
, wxT("Ignored already known source with IP=%s") + Uint32toStringIP(nClientIP
));
622 // Filter sources which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
623 if ( (source
->RequiresCryptLayer() && (!thePrefs::IsClientCryptLayerSupported() || !source
->HasValidHash())) || (thePrefs::IsClientCryptLayerRequired() && (!source
->SupportsCryptLayer() || !source
->HasValidHash())))
625 source
->Safe_Delete();
629 CPartFile
* file
= source
->GetRequestFile();
631 // Check if the file is already queued for something else
633 if ( file
!= sender
) {
634 if ( source
->AddRequestForAnotherFile( sender
) ) {
635 Notify_DownloadCtrlAddSource( sender
, source
, A4AF_SOURCE
);
639 source
->SetRequestFile( sender
);
641 if ( source
->GetFileRating() || !source
->GetFileComment().IsEmpty() ) {
642 sender
->UpdateFileRatingCommentAvail();
645 source
->SetSourceFrom(SF_PASSIVE
);
646 sender
->AddSource( source
);
647 Notify_DownloadCtrlAddSource( sender
, source
, UNAVAILABLE_SOURCE
);
652 bool CDownloadQueue::RemoveSource(CUpDownClient
* toremove
, bool WXUNUSED(updatewindow
), bool bDoStatsUpdate
)
654 bool removed
= false;
655 toremove
->DeleteAllFileRequests();
657 for ( uint16 i
= 0; i
< GetFileCount(); i
++ ) {
658 CPartFile
* cur_file
= GetFileByIndex( i
);
660 // Remove from source-list
661 if ( cur_file
->DelSource( toremove
) ) {
662 cur_file
->RemoveDownloadingSource(toremove
);
664 if ( bDoStatsUpdate
) {
665 cur_file
->UpdatePartsInfo();
669 // Remove from A4AF-list
670 cur_file
->RemoveA4AFSource( toremove
);
674 if ( !toremove
->GetFileComment().IsEmpty() || toremove
->GetFileRating()>0) {
675 toremove
->GetRequestFile()->UpdateFileRatingCommentAvail();
678 toremove
->SetRequestFile( NULL
);
679 toremove
->SetDownloadState(DS_NONE
);
681 // Remove from downloadlist widget
682 Notify_DownloadCtrlRemoveSource(toremove
, (CPartFile
*)NULL
);
683 toremove
->ResetFileStatusInfo();
689 void CDownloadQueue::RemoveFile(CPartFile
* file
)
691 RemoveLocalServerRequest( file
);
693 NotifyObservers( EventType( EventType::REMOVED
, file
) );
695 wxMutexLocker
lock( m_mutex
);
697 EraseValue( m_filelist
, file
);
701 CUpDownClient
* CDownloadQueue::GetDownloadClientByIP_UDP(uint32 dwIP
, uint16 nUDPPort
) const
703 wxMutexLocker
lock( m_mutex
);
705 for ( unsigned int i
= 0; i
< m_filelist
.size(); i
++ ) {
706 const CPartFile::SourceSet
& set
= m_filelist
[i
]->GetSourceList();
708 for ( CPartFile::SourceSet::const_iterator it
= set
.begin(); it
!= set
.end(); it
++ ) {
709 if ( (*it
)->GetIP() == dwIP
&& (*it
)->GetUDPPort() == nUDPPort
) {
719 * Checks if the specified server is the one we are connected to.
721 bool IsConnectedServer(const CServer
* server
)
723 if (server
&& theApp
->serverconnect
->GetCurrentServer()) {
724 wxString srvAddr
= theApp
->serverconnect
->GetCurrentServer()->GetAddress();
725 uint16 srvPort
= theApp
->serverconnect
->GetCurrentServer()->GetPort();
727 return server
->GetAddress() == srvAddr
&& server
->GetPort() == srvPort
;
734 bool CDownloadQueue::SendNextUDPPacket()
736 if ( m_filelist
.empty() || !theApp
->serverconnect
->IsUDPSocketAvailable() || !theApp
->IsConnectedED2K()) {
740 // Start monitoring the server and the files list
741 if ( !m_queueServers
.IsActive() ) {
742 AddObserver( &m_queueFiles
);
744 theApp
->serverlist
->AddObserver( &m_queueServers
);
748 bool packetSent
= false;
749 while ( !packetSent
) {
750 // Get max files ids per packet for current server
751 int filesAllowed
= GetMaxFilesPerUDPServerPacket();
753 if (filesAllowed
< 1 || !m_udpserver
|| IsConnectedServer(m_udpserver
)) {
754 // Select the next server to ask, must not be the connected server
756 m_udpserver
= m_queueServers
.GetNext();
757 } while (IsConnectedServer(m_udpserver
));
759 m_cRequestsSentToServer
= 0;
760 filesAllowed
= GetMaxFilesPerUDPServerPacket();
764 // Check if we have asked all servers, in which case we are done
765 if (m_udpserver
== NULL
) {
771 // Memoryfile containing the hash of every file to request
772 // 28bytes allocation because 16b + 4b + 8b is the worse case scenario.
773 CMemFile
hashlist( 28 );
775 CPartFile
* file
= m_queueFiles
.GetNext();
777 while ( file
&& filesAllowed
) {
778 uint8 status
= file
->GetStatus();
780 if ( ( status
== PS_READY
|| status
== PS_EMPTY
) && file
->GetSourceCount() < thePrefs::GetMaxSourcePerFileUDP() ) {
781 if (file
->IsLargeFile() && !m_udpserver
->SupportsLargeFilesUDP()) {
782 AddDebugLogLineM(false, logDownloadQueue
, wxT("UDP Request for sources on a large file ignored: server doesn't support it"));
784 ++m_cRequestsSentToServer
;
785 hashlist
.WriteHash( file
->GetFileHash() );
786 // See the notes on TCP packet
787 if ( m_udpserver
->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2
) {
788 if (file
->IsLargeFile()) {
789 wxASSERT(m_udpserver
->SupportsLargeFilesUDP());
790 hashlist
.WriteUInt32( 0 );
791 hashlist
.WriteUInt64( file
->GetFileSize() );
793 hashlist
.WriteUInt32( file
->GetFileSize() );
800 // Avoid skipping a file if we can't send any more currently
801 if ( filesAllowed
) {
802 file
= m_queueFiles
.GetNext();
806 // See if we have anything to send
807 if ( hashlist
.GetLength() ) {
808 packetSent
= SendGlobGetSourcesUDPPacket(hashlist
);
811 // Check if we've covered every file
812 if ( file
== NULL
) {
813 // Reset the list of asked files so that the loop will start over
814 m_queueFiles
.Reset();
816 // Unset the server so that the next server will be used
825 void CDownloadQueue::StopUDPRequests()
827 wxMutexLocker
lock( m_mutex
);
833 void CDownloadQueue::DoStopUDPRequests()
835 // No need to observe when we wont be using the results
836 theApp
->serverlist
->RemoveObserver( &m_queueServers
);
837 RemoveObserver( &m_queueFiles
);
840 m_lastudpsearchtime
= ::GetTickCount();
844 // Comparison function needed by sort. Returns true if file1 preceeds file2
845 bool ComparePartFiles(const CPartFile
* file1
, const CPartFile
* file2
) {
846 if (file1
->GetDownPriority() != file2
->GetDownPriority()) {
847 // To place high-priority files before low priority files we have to
848 // invert this test, since PR_LOW is lower than PR_HIGH, and since
849 // placing a PR_LOW file before a PR_HIGH file would mean that
850 // the PR_LOW file gets sources before the PR_HIGH file ...
851 return (file1
->GetDownPriority() > file2
->GetDownPriority());
853 int sourcesA
= file1
->GetSourceCount();
854 int sourcesB
= file2
->GetSourceCount();
856 int notSourcesA
= file1
->GetNotCurrentSourcesCount();
857 int notSourcesB
= file2
->GetNotCurrentSourcesCount();
859 int cmp
= CmpAny( sourcesA
- notSourcesA
, sourcesB
- notSourcesB
);
862 cmp
= CmpAny( notSourcesA
, notSourcesB
);
870 void CDownloadQueue::DoSortByPriority()
872 m_lastsorttime
= ::GetTickCount();
873 sort( m_filelist
.begin(), m_filelist
.end(), ComparePartFiles
);
877 void CDownloadQueue::ResetLocalServerRequests()
879 wxMutexLocker
lock( m_mutex
);
881 m_dwNextTCPSrcReq
= 0;
882 m_localServerReqQueue
.clear();
884 for ( uint16 i
= 0; i
< m_filelist
.size(); i
++ ) {
885 m_filelist
[i
]->SetLocalSrcRequestQueued(false);
890 void CDownloadQueue::RemoveLocalServerRequest( CPartFile
* file
)
892 wxMutexLocker
lock( m_mutex
);
894 EraseValue( m_localServerReqQueue
, file
);
896 file
->SetLocalSrcRequestQueued(false);
900 void CDownloadQueue::ProcessLocalRequests()
902 wxMutexLocker
lock( m_mutex
);
904 bool bServerSupportsLargeFiles
= theApp
->serverconnect
905 && theApp
->serverconnect
->GetCurrentServer()
906 && theApp
->serverconnect
->GetCurrentServer()->SupportsLargeFilesTCP();
908 if ( (!m_localServerReqQueue
.empty()) && (m_dwNextTCPSrcReq
< ::GetTickCount()) ) {
909 CMemFile
dataTcpFrame(22);
910 const int iMaxFilesPerTcpFrame
= 15;
912 while (!m_localServerReqQueue
.empty() && iFiles
< iMaxFilesPerTcpFrame
) {
913 // find the file with the longest waitingtime
914 uint32 dwBestWaitTime
= 0xFFFFFFFF;
916 std::list
<CPartFile
*>::iterator posNextRequest
= m_localServerReqQueue
.end();
917 std::list
<CPartFile
*>::iterator it
= m_localServerReqQueue
.begin();
918 while( it
!= m_localServerReqQueue
.end() ) {
919 CPartFile
* cur_file
= (*it
);
920 if (cur_file
->GetStatus() == PS_READY
|| cur_file
->GetStatus() == PS_EMPTY
) {
921 uint8 nPriority
= cur_file
->GetDownPriority();
922 if (nPriority
> PR_HIGH
) {
927 if (cur_file
->GetLastSearchTime() + (PR_HIGH
-nPriority
) < dwBestWaitTime
){
928 dwBestWaitTime
= cur_file
->GetLastSearchTime() + (PR_HIGH
- nPriority
);
934 it
= m_localServerReqQueue
.erase(it
);
935 cur_file
->SetLocalSrcRequestQueued(false);
936 AddDebugLogLineM( false, logDownloadQueue
,
937 CFormat(wxT("Local server source request for file '%s' not sent because of status '%s'"))
938 % cur_file
->GetFileName() % cur_file
->getPartfileStatus());
942 if (posNextRequest
!= m_localServerReqQueue
.end()) {
943 CPartFile
* cur_file
= (*posNextRequest
);
944 cur_file
->SetLocalSrcRequestQueued(false);
945 cur_file
->SetLastSearchTime(::GetTickCount());
946 m_localServerReqQueue
.erase(posNextRequest
);
949 if (!bServerSupportsLargeFiles
&& cur_file
->IsLargeFile()) {
950 AddDebugLogLineM(false, logDownloadQueue
, wxT("TCP Request for sources on a large file ignored: server doesn't support it"));
952 AddDebugLogLineM(false, logDownloadQueue
,
953 CFormat(wxT("Creating local sources request packet for '%s'")) % cur_file
->GetFileName());
954 // create request packet
955 CMemFile
data(16 + (cur_file
->IsLargeFile() ? 8 : 4));
956 data
.WriteHash(cur_file
->GetFileHash());
957 // Kry - lugdunum extended protocol on 17.3 to handle filesize properly.
958 // There is no need to check anything, old server ignore the extra 4 bytes.
959 // As of 17.9, servers accept a 0 32-bits size and then a 64bits size
960 if (cur_file
->IsLargeFile()) {
961 wxASSERT(bServerSupportsLargeFiles
);
963 data
.WriteUInt64(cur_file
->GetFileSize());
965 data
.WriteUInt32(cur_file
->GetFileSize());
968 if (thePrefs::IsClientCryptLayerSupported() && theApp
->serverconnect
->GetCurrentServer() != NULL
&& theApp
->serverconnect
->GetCurrentServer()->SupportsGetSourcesObfuscation()) {
969 byOpcode
= OP_GETSOURCES_OBFU
;
971 byOpcode
= OP_GETSOURCES
;
973 CPacket
packet(data
, OP_EDONKEYPROT
, byOpcode
);
974 dataTcpFrame
.Write(packet
.GetPacket(), packet
.GetRealPacketSize());
979 int iSize
= dataTcpFrame
.GetLength();
981 // create one 'packet' which contains all buffered OP_GETSOURCES ED2K packets to be sent with one TCP frame
982 // server credits: (16+4)*regularfiles + (16+4+8)*largefiles +1
983 CPacket
* packet
= new CPacket(new byte
[iSize
], dataTcpFrame
.GetLength(), true, false);
984 dataTcpFrame
.Seek(0, wxFromStart
);
985 dataTcpFrame
.Read(packet
->GetPacket(), iSize
);
986 uint32 size
= packet
->GetPacketSize();
987 theApp
->serverconnect
->SendPacket(packet
, true); // Deletes `packet'.
988 AddDebugLogLineM(false, logDownloadQueue
, wxT("Sent local sources request packet."));
989 theStats::AddUpOverheadServer(size
);
992 // next TCP frame with up to 15 source requests is allowed to be sent in..
993 m_dwNextTCPSrcReq
= ::GetTickCount() + SEC2MS(iMaxFilesPerTcpFrame
*(16+4));
999 void CDownloadQueue::SendLocalSrcRequest(CPartFile
* sender
)
1001 wxMutexLocker
lock( m_mutex
);
1003 m_localServerReqQueue
.push_back(sender
);
1007 void CDownloadQueue::AddLinksFromFile()
1009 const wxString fullPath
= theApp
->ConfigDir
+ wxT("ED2KLinks");
1010 if (!wxFile::Exists(fullPath
)) {
1014 // Attempt to lock the ED2KLinks file.
1015 CFileLock
lock((const char*)unicode2char(fullPath
));
1017 wxTextFile
file(fullPath
);
1018 if ( file
.Open() ) {
1019 for ( unsigned int i
= 0; i
< file
.GetLineCount(); i
++ ) {
1020 wxString line
= file
.GetLine( i
).Strip( wxString::both
);
1022 if ( !line
.IsEmpty() ) {
1023 // Special case! used by a secondary running mule to raise this one.
1024 if ( line
== wxT("RAISE_DIALOG") ) {
1035 printf("Failed to open ED2KLinks file.\n");
1039 wxRemoveFile(theApp
->ConfigDir
+ wxT("ED2KLinks"));
1043 void CDownloadQueue::ResetCatParts(uint8 cat
)
1045 for ( uint16 i
= 0; i
< GetFileCount(); i
++ ) {
1046 CPartFile
* file
= GetFileByIndex( i
);
1048 if ( file
->GetCategory() == cat
) {
1049 // Reset the category
1050 file
->SetCategory( 0 );
1051 } else if ( file
->GetCategory() > cat
) {
1052 // Set to the new position of the original category
1053 file
->SetCategory( file
->GetCategory() - 1 );
1059 void CDownloadQueue::SetCatPrio(uint8 cat
, uint8 newprio
)
1061 for ( uint16 i
= 0; i
< GetFileCount(); i
++ ) {
1062 CPartFile
* file
= GetFileByIndex( i
);
1064 if ( !cat
|| file
->GetCategory() == cat
) {
1065 if ( newprio
== PR_AUTO
) {
1066 file
->SetAutoDownPriority(true);
1068 file
->SetAutoDownPriority(false);
1069 file
->SetDownPriority(newprio
);
1076 void CDownloadQueue::SetCatStatus(uint8 cat
, int newstatus
)
1078 std::list
<CPartFile
*> files
;
1081 wxMutexLocker
lock(m_mutex
);
1083 for ( uint16 i
= 0; i
< m_filelist
.size(); i
++ ) {
1084 if ( m_filelist
[i
]->CheckShowItemInGivenCat(cat
) ) {
1085 files
.push_back( m_filelist
[i
] );
1090 std::list
<CPartFile
*>::iterator it
= files
.begin();
1092 for ( ; it
!= files
.end(); it
++ ) {
1093 switch ( newstatus
) {
1094 case MP_CANCEL
: (*it
)->Delete(); break;
1095 case MP_PAUSE
: (*it
)->PauseFile(); break;
1096 case MP_STOP
: (*it
)->StopFile(); break;
1097 case MP_RESUME
: (*it
)->ResumeFile(); break;
1103 uint16
CDownloadQueue::GetDownloadingFileCount() const
1105 wxMutexLocker
lock( m_mutex
);
1108 for ( uint16 i
= 0; i
< m_filelist
.size(); i
++ ) {
1109 uint8 status
= m_filelist
[i
]->GetStatus();
1110 if ( status
== PS_READY
|| status
== PS_EMPTY
) {
1119 uint16
CDownloadQueue::GetPausedFileCount() const
1121 wxMutexLocker
lock( m_mutex
);
1124 for ( uint16 i
= 0; i
< m_filelist
.size(); i
++ ) {
1125 if ( m_filelist
[i
]->GetStatus() == PS_PAUSED
) {
1134 void CDownloadQueue::CheckDiskspace( const CPath
& path
)
1136 if ( ::GetTickCount() - m_lastDiskCheck
< DISKSPACERECHECKTIME
) {
1140 m_lastDiskCheck
= ::GetTickCount();
1143 // Check if the user has set an explicit limit
1144 if ( thePrefs::IsCheckDiskspaceEnabled() ) {
1145 min
= thePrefs::GetMinFreeDiskSpace();
1148 // The very least acceptable diskspace is a single PART
1149 if ( min
< PARTSIZE
) {
1153 uint64 free
= CPath::GetFreeSpaceAt(path
);
1154 if (free
== static_cast<uint64
>(wxInvalidOffset
)) {
1156 } else if (free
< min
) {
1157 CUserEvents::ProcessEvent(
1158 CUserEvents::OutOfDiskSpace
,
1159 wxT("Temporary partition"));
1162 for (unsigned int i
= 0; i
< m_filelist
.size(); ++i
) {
1163 CPartFile
* file
= m_filelist
[i
];
1165 switch ( file
->GetStatus() ) {
1172 if ( free
>= min
&& file
->GetInsufficient() ) {
1173 // We'll try to resume files if there is enough free space
1174 if ( free
- file
->GetNeededSpace() > min
) {
1177 } else if ( free
< min
&& !file
->IsPaused() ) {
1178 // No space left, stop the files.
1179 file
->PauseFile( true );
1185 int CDownloadQueue::GetMaxFilesPerUDPServerPacket() const
1187 if ( m_udpserver
) {
1188 if ( m_udpserver
->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES
) {
1189 // get max. file ids per packet
1190 if ( m_cRequestsSentToServer
< MAX_REQUESTS_PER_SERVER
) {
1192 MAX_FILES_PER_UDP_PACKET
,
1193 MAX_REQUESTS_PER_SERVER
- m_cRequestsSentToServer
1196 } else if ( m_cRequestsSentToServer
< MAX_REQUESTS_PER_SERVER
) {
1205 bool CDownloadQueue::SendGlobGetSourcesUDPPacket(CMemFile
& data
)
1211 CPacket
packet(data
, OP_EDONKEYPROT
, ((m_udpserver
->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES2
) ? OP_GLOBGETSOURCES2
: OP_GLOBGETSOURCES
));
1213 theStats::AddUpOverheadServer(packet
.GetPacketSize());
1214 theApp
->serverconnect
->SendUDPPacket(&packet
,m_udpserver
,false);
1220 void CDownloadQueue::AddToResolve(const CMD4Hash
& fileid
, const wxString
& pszHostname
, uint16 port
, const wxString
& hash
, uint8 cryptoptions
)
1223 if ( !GetFileByID(fileid
) ) {
1227 wxMutexLocker
lock( m_mutex
);
1229 Hostname_Entry entry
= { fileid
, pszHostname
, port
, hash
, cryptoptions
};
1230 m_toresolve
.push_front(entry
);
1232 // Check if there are other DNS lookups on queue
1233 if (m_toresolve
.size() == 1) {
1234 // Check if it is a simple dot address
1235 uint32 ip
= StringIPtoUint32(pszHostname
);
1238 OnHostnameResolved(ip
);
1240 CAsyncDNS
* dns
= new CAsyncDNS(pszHostname
, DNS_SOURCE
, theApp
);
1242 if ((dns
->Create() != wxTHREAD_NO_ERROR
) || (dns
->Run() != wxTHREAD_NO_ERROR
)) {
1244 m_toresolve
.pop_front();
1251 void CDownloadQueue::OnHostnameResolved(uint32 ip
)
1253 wxMutexLocker
lock( m_mutex
);
1255 wxASSERT( m_toresolve
.size() );
1257 Hostname_Entry resolved
= m_toresolve
.front();
1258 m_toresolve
.pop_front();
1261 CPartFile
* file
= GetFileByID( resolved
.fileid
);
1263 CMemFile
sources(1+4+2);
1264 sources
.WriteUInt8(1); // No. Sources
1265 sources
.WriteUInt32(ip
);
1266 sources
.WriteUInt16(resolved
.port
);
1267 sources
.WriteUInt8(resolved
.cryptoptions
);
1268 if (resolved
.cryptoptions
& 0x80) {
1269 wxASSERT(!resolved
.hash
.IsEmpty());
1270 CMD4Hash sourcehash
;
1271 sourcehash
.Decode(resolved
.hash
);
1272 sources
.WriteHash(sourcehash
);
1274 sources
.Seek(0,wxFromStart
);
1276 file
->AddSources(sources
, 0, 0, SF_LINK
, true);
1280 while (m_toresolve
.size()) {
1281 Hostname_Entry entry
= m_toresolve
.front();
1283 // Check if it is a simple dot address
1284 uint32 tmpIP
= StringIPtoUint32(entry
.strHostname
);
1287 OnHostnameResolved(tmpIP
);
1289 CAsyncDNS
* dns
= new CAsyncDNS(entry
.strHostname
, DNS_SOURCE
, theApp
);
1291 if ((dns
->Create() != wxTHREAD_NO_ERROR
) || (dns
->Run() != wxTHREAD_NO_ERROR
)) {
1293 m_toresolve
.pop_front();
1302 bool CDownloadQueue::AddLink( const wxString
& link
, int category
)
1306 if (link
.compare(0, 7, wxT("magnet:")) == 0) {
1307 uri
= CMagnetED2KConverter(link
);
1309 AddLogLineM(true, CFormat(_("Cannot convert magnet link to eD2k: %s")) % link
);
1314 if (uri
.compare(0, 7, wxT("ed2k://")) == 0) {
1315 return AddED2KLink(uri
, category
);
1317 AddLogLineM(true, CFormat(_("Unknown protocol of link: %s")) % link
);
1323 bool CDownloadQueue::AddED2KLink( const wxString
& link
, int category
)
1325 wxASSERT( !link
.IsEmpty() );
1326 wxString URI
= link
;
1328 // Need the links to end with /, otherwise CreateLinkFromUrl crashes us.
1329 if ( URI
.Last() != wxT('/') ) {
1334 CScopedPtr
<CED2KLink
> uri(CED2KLink::CreateLinkFromUrl(URI
));
1336 return AddED2KLink( uri
.get(), category
);
1337 } catch ( const wxString
& err
) {
1338 AddLogLineM( true, CFormat( _("Invalid eD2k link! ERROR: %s")) % err
);
1345 bool CDownloadQueue::AddED2KLink( const CED2KLink
* link
, int category
)
1347 switch ( link
->GetKind() ) {
1348 case CED2KLink::kFile
:
1349 return AddED2KLink( dynamic_cast<const CED2KFileLink
*>( link
), category
);
1351 case CED2KLink::kServer
:
1352 return AddED2KLink( dynamic_cast<const CED2KServerLink
*>( link
) );
1354 case CED2KLink::kServerList
:
1355 return AddED2KLink( dynamic_cast<const CED2KServerListLink
*>( link
) );
1364 bool CDownloadQueue::AddED2KLink( const CED2KFileLink
* link
, int category
)
1366 CPartFile
* file
= NULL
;
1367 if (IsFileExisting(link
->GetHashKey())) {
1368 // Must be a shared file if we are to add hashes or sources
1369 if ((file
= GetFileByID(link
->GetHashKey())) == NULL
) {
1373 if (link
->GetSize() > OLD_MAX_FILE_SIZE
) {
1374 if (!PlatformSpecific::CanFSHandleLargeFiles(thePrefs::GetTempDir())) {
1375 AddLogLineM(true, _("Filesystem for Temp directory cannot handle large files."));
1377 } else if (!PlatformSpecific::CanFSHandleLargeFiles(theApp
->glob_prefs
->GetCatPath(category
))) {
1378 AddLogLineM(true, _("Filesystem for Incoming directory cannot handle large files."));
1383 file
= new CPartFile(link
);
1385 if (file
->GetStatus() == PS_ERROR
) {
1390 AddDownload(file
, thePrefs::AddNewFilesPaused(), category
);
1393 if (link
->HasValidAICHHash()) {
1394 CAICHHashSet
* hashset
= file
->GetAICHHashset();
1396 if (!hashset
->HasValidMasterHash() || (hashset
->GetMasterHash() != link
->GetAICHHash())) {
1397 hashset
->SetMasterHash(link
->GetAICHHash(), AICH_VERIFIED
);
1398 hashset
->FreeHashSet();
1402 const CED2KFileLink::CED2KLinkSourceList
& list
= link
->m_sources
;
1403 CED2KFileLink::CED2KLinkSourceList::const_iterator it
= list
.begin();
1404 for (; it
!= list
.end(); ++it
) {
1405 AddToResolve(link
->GetHashKey(), it
->addr
, it
->port
, it
->hash
, it
->cryptoptions
);
1412 bool CDownloadQueue::AddED2KLink( const CED2KServerLink
* link
)
1414 CServer
*server
= new CServer( link
->GetPort(), Uint32toStringIP( link
->GetIP() ) );
1416 server
->SetListName( Uint32toStringIP( link
->GetIP() ) );
1418 theApp
->serverlist
->AddServer(server
);
1420 Notify_ServerAdd(server
);
1426 bool CDownloadQueue::AddED2KLink( const CED2KServerListLink
* link
)
1428 theApp
->serverlist
->UpdateServerMetFromURL( link
->GetAddress() );
1434 void CDownloadQueue::ObserverAdded( ObserverType
* o
)
1436 CObservableQueue
<CPartFile
*>::ObserverAdded( o
);
1438 EventType::ValueList list
;
1441 wxMutexLocker
lock(m_mutex
);
1442 list
.reserve( m_filelist
.size() );
1443 list
.insert( list
.begin(), m_filelist
.begin(), m_filelist
.end() );
1446 NotifyObservers( EventType( EventType::INITIAL
, &list
), o
);
1449 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
)
1452 AddDebugLogLineM(false, logKadSearch
, wxString::Format(wxT("Search result sources (type %i)"),type
));
1454 //Safety measure to make sure we are looking for these sources
1455 CPartFile
* temp
= GetFileByKadFileSearchID(searchID
);
1457 AddDebugLogLineM(false, logKadSearch
, wxT("This is not the file we're looking for..."));
1461 //Do we need more sources?
1462 if(!(!temp
->IsStopped() && thePrefs::GetMaxSourcePerFile() > temp
->GetSourceCount())) {
1463 AddDebugLogLineM(false, logKadSearch
, wxT("No more sources needed for this file"));
1467 uint32 ED2KID
= wxUINT32_SWAP_ALWAYS(ip
);
1469 if (theApp
->ipfilter
->IsFiltered(ED2KID
)) {
1470 AddDebugLogLineM(false, logKadSearch
, wxT("Source ip got filtered"));
1471 AddDebugLogLineM(false, logIPFilter
, CFormat(wxT("IPfiltered source IP=%s received from Kademlia")) % Uint32toStringIP(ED2KID
));
1475 if( (ip
== Kademlia::CKademlia::GetIPAddress() || ED2KID
== theApp
->GetED2KID()) && tcp
== thePrefs::GetPort()) {
1476 AddDebugLogLineM(false, logKadSearch
, wxT("Trying to add myself as source, ignore"));
1480 CUpDownClient
* ctemp
= NULL
;
1484 //NonFirewalled users
1486 AddDebugLogLineM(false, logKadSearch
, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, no tcp port received")) % Uint32toStringIP(ip
));
1489 if (!IsGoodIP(ED2KID
,thePrefs::FilterLanIPs())) {
1490 AddDebugLogLineM(false, logKadSearch
, CFormat(wxT("%s got filtered")) % Uint32toStringIP(ED2KID
));
1491 AddDebugLogLineM(false, logIPFilter
, CFormat(wxT("Ignored source (IP=%s) received from Kademlia, filtered")) % Uint32toStringIP(ED2KID
));
1494 ctemp
= new CUpDownClient(tcp
,ip
,0,0,temp
,false, true);
1495 ctemp
->SetSourceFrom(SF_KADEMLIA
);
1496 ctemp
->SetServerIP(serverip
);
1497 ctemp
->SetServerPort(serverport
);
1498 ctemp
->SetKadPort(udp
);
1500 pcontactID
->ToByteArray(cID
);
1501 ctemp
->SetUserHash(CMD4Hash(cID
));
1505 //Don't use this type... Some clients will process it wrong..
1510 //This will be a firewaled client connected to Kad only.
1511 //We set the clientID to 1 as a Kad user only has 1 buddy.
1512 ctemp
= new CUpDownClient(tcp
,1,0,0,temp
,false, true);
1513 //The only reason we set the real IP is for when we get a callback
1514 //from this firewalled source, the compare method will match them.
1515 ctemp
->SetSourceFrom(SF_KADEMLIA
);
1516 ctemp
->SetKadPort(udp
);
1518 pcontactID
->ToByteArray(cID
);
1519 ctemp
->SetUserHash(CMD4Hash(cID
));
1520 pbuddyID
->ToByteArray(cID
);
1521 ctemp
->SetBuddyID(cID
);
1522 ctemp
->SetBuddyIP(serverip
);
1523 ctemp
->SetBuddyPort(serverport
);
1527 // firewalled source which supports direct udp callback
1528 // if we are firewalled ourself, the source is useless to us
1529 if (theApp
->IsFirewalled()) {
1533 if ((byCryptOptions
& 0x08) == 0){
1534 AddDebugLogLineM(false, logKadSearch
, CFormat(wxT("Received Kad source type 6 (direct callback) which has the direct callback flag not set (%s)")) % Uint32toStringIP(ED2KID
));
1538 ctemp
= new CUpDownClient(tcp
, 1, 0, 0, temp
, false, true);
1539 ctemp
->SetSourceFrom(SF_KADEMLIA
);
1540 ctemp
->SetKadPort(udp
);
1541 ctemp
->SetIP(ED2KID
); // need to set the Ip address, which cannot be used for TCP but for UDP
1543 pcontactID
->ToByteArray(cID
);
1544 ctemp
->SetUserHash(CMD4Hash(cID
));
1545 pbuddyID
->ToByteArray(cID
);
1550 // add encryption settings
1551 ctemp
->SetConnectOptions(byCryptOptions
);
1553 AddDebugLogLineM(false, logKadSearch
, CFormat(wxT("Happily adding a source (%s) type %d")) % Uint32_16toStringIP_Port(ED2KID
, ctemp
->GetUserPort()) % type
);
1554 CheckAndAddSource(temp
, ctemp
);
1558 CPartFile
* CDownloadQueue::GetFileByKadFileSearchID(uint32 id
) const
1561 wxMutexLocker
lock( m_mutex
);
1563 for ( uint16 i
= 0; i
< m_filelist
.size(); ++i
) {
1564 if ( id
== m_filelist
[i
]->GetKadFileSearchID()) {
1565 return m_filelist
[ i
];
1573 bool CDownloadQueue::DoKademliaFileRequest()
1575 return ((::GetTickCount() - lastkademliafilerequest
) > KADEMLIAASKTIME
);
1577 // File_checked_for_headers