2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 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 "UploadQueue.h" // Interface declarations
28 #include <protocol/Protocols.h>
29 #include <protocol/ed2k/Client2Client/TCP.h>
30 #include <common/Macros.h>
31 #include <common/Constants.h>
35 #include "Types.h" // Do_not_auto_remove (win32)
38 #include <winsock.h> // Do_not_auto_remove
40 #include <sys/types.h> // Do_not_auto_remove
41 #include <netinet/in.h> // Do_not_auto_remove
42 #include <arpa/inet.h> // Do_not_auto_remove
45 #include "ServerConnect.h" // Needed for CServerConnect
46 #include "KnownFile.h" // Needed for CKnownFile
47 #include "Packet.h" // Needed for CPacket
48 #include "ClientTCPSocket.h" // Needed for CClientTCPSocket
49 #include "SharedFileList.h" // Needed for CSharedFileList
50 #include "updownclient.h" // Needed for CUpDownClient
51 #include "amule.h" // Needed for theApp
52 #include "Preferences.h"
53 #include "ClientList.h"
54 #include "Statistics.h" // Needed for theStats
56 #include <common/Format.h>
57 #include "UploadBandwidthThrottler.h"
58 #include "GuiEvents.h" // Needed for Notify_*
59 #include "ListenSocket.h"
60 #include "DownloadQueue.h"
64 //TODO rewrite the whole networkcode, use overlapped sockets
66 CUploadQueue::CUploadQueue()
68 m_nLastStartUpload
= 0;
70 lastupslotHighID
= true;
71 m_allowKicking
= true;
72 m_allUploadingKnownFile
= new CKnownFile
;
76 void CUploadQueue::SortGetBestClient(CClientRef
* bestClient
)
78 uint32 tick
= GetTickCount();
80 CClientRefList::iterator it
= m_waitinglist
.begin();
81 for (; it
!= m_waitinglist
.end(); ) {
82 CClientRefList::iterator it2
= it
++;
83 CUpDownClient
* cur_client
= it2
->GetClient();
86 if (tick
- cur_client
->GetLastUpRequest() > MAX_PURGEQUEUETIME
87 || !theApp
->sharedfiles
->GetFileByID(cur_client
->GetUploadFileID())) {
88 cur_client
->ClearWaitStartTime();
89 RemoveFromWaitingQueue(it2
);
90 if (!cur_client
->GetSocket()) {
91 if (cur_client
->Disconnected(wxT("AddUpNextClient - purged"))) {
92 cur_client
->Safe_Delete();
99 if (cur_client
->IsBanned() || IsSuspended(cur_client
->GetUploadFileID())) { // Banned client or suspended upload ?
100 cur_client
->ClearScore();
105 // Calculate score of current client
106 uint32 cur_score
= cur_client
->CalculateScore();
107 // Check if it's better than that of a previous one, and move it up then.
108 CClientRefList::iterator it1
= it2
;
109 while (it1
!= m_waitinglist
.begin()) {
111 if (cur_score
> it1
->GetClient()->GetScore()) {
113 std::swap(*it2
, *it1
);
116 // no need to check further since list is already sorted
123 // - calculate queue rank
124 // - find best high id client
125 // - mark all better low id clients as enabled for upload
127 bool bestClientFound
= false;
128 for (it
= m_waitinglist
.begin(); it
!= m_waitinglist
.end(); ) {
129 CClientRefList::iterator it2
= it
++;
130 CUpDownClient
* cur_client
= it2
->GetClient();
131 cur_client
->SetUploadQueueWaitingPosition(rank
++);
132 if (bestClientFound
) {
133 // There's a better high id client
134 cur_client
->m_bAddNextConnect
= false;
136 if (cur_client
->HasLowID() && !cur_client
->IsConnected()) {
137 // No better high id client, so start upload to this one once it connects
138 cur_client
->m_bAddNextConnect
= true;
140 // We found a high id client (or a currently connected low id client)
141 bestClientFound
= true;
142 cur_client
->m_bAddNextConnect
= false;
144 bestClient
->Link(cur_client
CLIENT_DEBUGSTRING("CUploadQueue::SortGetBestClient"));
145 RemoveFromWaitingQueue(it2
);
147 lastupslotHighID
= true; // VQB LowID alternate
154 AddDebugLogLineN(logLocalClient
, CFormat(wxT("Current UL queue (%d):")) % (rank
- 1));
155 for (it
= m_waitinglist
.begin(); it
!= m_waitinglist
.end(); it
++) {
156 CUpDownClient
* c
= it
->GetClient();
157 AddDebugLogLineN(logLocalClient
, CFormat(wxT("%4d %7d %s %5d %s"))
158 % c
->GetUploadQueueWaitingPosition()
160 % (c
->HasLowID() ? (c
->IsConnected() ? wxT("LoCon") : wxT("LowId")) : wxT("High "))
169 void CUploadQueue::AddUpNextClient(CUpDownClient
* directadd
)
171 CUpDownClient
* newclient
= NULL
;
172 CClientRef newClientRef
;
173 // select next client or use given client
175 SortGetBestClient(&newClientRef
);
176 newclient
= newClientRef
.GetClient();
177 #if EXTENDED_UPLOADQUEUE
179 // Nothing to upload. Try to find something from the sources.
180 if (PopulatePossiblyWaitingList() > 0) {
181 newClientRef
= * m_possiblyWaitingList
.begin();
182 m_possiblyWaitingList
.pop_front();
183 newclient
= newClientRef
.GetClient();
184 AddDebugLogLineN( logLocalClient
, wxT("Added client from possiblyWaitingList ") + newclient
->GetFullIP() );
192 // Check if requested file is suspended or not shared (maybe deleted recently)
194 if (IsSuspended(directadd
->GetUploadFileID())
195 || !theApp
->sharedfiles
->GetFileByID(directadd
->GetUploadFileID())) {
198 newclient
= directadd
;
202 if (IsDownloading(newclient
)) {
205 // tell the client that we are now ready to upload
206 if (!newclient
->IsConnected()) {
207 newclient
->SetUploadState(US_CONNECTING
);
208 if (!newclient
->TryToConnect(true)) {
212 CPacket
* packet
= new CPacket(OP_ACCEPTUPLOADREQ
, 0, OP_EDONKEYPROT
);
213 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
214 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + newclient
->GetFullIP() );
215 newclient
->SendPacket(packet
,true);
216 newclient
->SetUploadState(US_UPLOADING
);
218 newclient
->SetUpStartTime();
219 newclient
->ResetSessionUp();
221 theApp
->uploadBandwidthThrottler
->AddToStandardList(m_uploadinglist
.size(), newclient
->GetSocket());
222 m_uploadinglist
.push_back(CCLIENTREF(newclient
, wxT("CUploadQueue::AddUpNextClient")));
223 m_allUploadingKnownFile
->AddUploadingClient(newclient
);
224 theStats::AddUploadingClient();
227 CKnownFile
* reqfile
= (CKnownFile
*) newclient
->GetUploadFile();
229 reqfile
->statistic
.AddAccepted();
232 Notify_SharedCtrlRefreshClient(newclient
->ECID(), AVAILABLE_SOURCE
);
235 void CUploadQueue::Process()
237 // Check if someone's waiting, if there is a slot for him,
238 // or if we should try to free a slot for him
239 uint32 tick
= GetTickCount();
240 // Nobody waiting or upload started recently
241 // (Actually instead of "empty" it should check for "no HighID clients queued",
242 // but the cost for that outweights the benefit. As it is, a slot will be freed
243 // even if it can't be taken because all of the queue is LowID. But just one,
244 // and the kicked client will instantly get it back if he has HighID.)
245 // Also, if we are running out of sockets, don't add new clients, but also don't kick existing ones,
246 // or uploading will cease right away.
247 #if EXTENDED_UPLOADQUEUE
248 if (tick
- m_nLastStartUpload
< 1000
250 if (m_waitinglist
.empty() || tick
- m_nLastStartUpload
< 1000
252 || theApp
->listensocket
->TooManySockets()) {
253 m_allowKicking
= false;
254 // Already a slot free, try to fill it
255 } else if (m_uploadinglist
.size() < GetMaxSlots()) {
256 m_allowKicking
= false;
257 m_nLastStartUpload
= tick
;
259 // All slots taken, try to free one
261 m_allowKicking
= true;
264 // The loop that feeds the upload slots with data.
265 CClientRefList::iterator it
= m_uploadinglist
.begin();
266 while (it
!= m_uploadinglist
.end()) {
267 // Get the client. Note! Also updates pos as a side effect.
268 CUpDownClient
* cur_client
= it
++->GetClient();
270 // It seems chatting or friend slots can get stuck at times in upload.. This needs looked into..
271 if (!cur_client
->GetSocket()) {
272 RemoveFromUploadQueue(cur_client
);
273 if(cur_client
->Disconnected(_T("CUploadQueue::Process"))){
274 cur_client
->Safe_Delete();
277 cur_client
->SendBlockData();
281 // Save used bandwidth for speed calculations
282 uint64 sentBytes
= theApp
->uploadBandwidthThrottler
->GetNumberOfSentBytesSinceLastCallAndReset();
283 (void)theApp
->uploadBandwidthThrottler
->GetNumberOfSentBytesOverheadSinceLastCallAndReset();
287 theStats::AddSentBytes(sentBytes
);
290 // Periodically resort queue if it doesn't happen anyway
291 if ((sint32
) (tick
- m_lastSort
) > MIN2MS(2)) {
297 uint16
CUploadQueue::GetMaxSlots() const
299 uint16 nMaxSlots
= 0;
300 float kBpsUpPerClient
= (float)thePrefs::GetSlotAllocation();
301 if (thePrefs::GetMaxUpload() == UNLIMITED
) {
302 float kBpsUp
= theStats::GetUploadRate() / 1024.0f
;
303 nMaxSlots
= (uint16
)(kBpsUp
/ kBpsUpPerClient
) + 2;
305 if (thePrefs::GetMaxUpload() >= 10) {
306 nMaxSlots
= (uint16
)floor((float)thePrefs::GetMaxUpload() / kBpsUpPerClient
+ 0.5);
307 // floor(x + 0.5) is a way of doing round(x) that works with gcc < 3 ...
308 if (nMaxSlots
< MIN_UP_CLIENTS_ALLOWED
) {
309 nMaxSlots
=MIN_UP_CLIENTS_ALLOWED
;
312 nMaxSlots
= MIN_UP_CLIENTS_ALLOWED
;
315 if (nMaxSlots
> MAX_UP_CLIENTS_ALLOWED
) {
316 nMaxSlots
= MAX_UP_CLIENTS_ALLOWED
;
322 CUploadQueue::~CUploadQueue()
324 wxASSERT(m_waitinglist
.empty());
325 wxASSERT(m_uploadinglist
.empty());
326 delete m_allUploadingKnownFile
;
330 bool CUploadQueue::IsOnUploadQueue(const CUpDownClient
* client
) const
332 for (CClientRefList::const_iterator it
= m_waitinglist
.begin(); it
!= m_waitinglist
.end(); it
++) {
333 if (it
->GetClient() == client
) {
341 bool CUploadQueue::IsDownloading(const CUpDownClient
* client
) const
343 for (CClientRefList::const_iterator it
= m_uploadinglist
.begin(); it
!= m_uploadinglist
.end(); it
++) {
344 if (it
->GetClient() == client
) {
352 CUpDownClient
* CUploadQueue::GetWaitingClientByIP_UDP(uint32 dwIP
, uint16 nUDPPort
, bool bIgnorePortOnUniqueIP
, bool* pbMultipleIPs
)
354 CUpDownClient
* pMatchingIPClient
= NULL
;
358 CClientRefList::iterator it
= m_waitinglist
.begin();
359 for (; it
!= m_waitinglist
.end(); ++it
) {
360 CUpDownClient
* cur_client
= it
->GetClient();
362 if ((dwIP
== cur_client
->GetIP()) && (nUDPPort
== cur_client
->GetUDPPort())) {
364 } else if ((dwIP
== cur_client
->GetIP()) && bIgnorePortOnUniqueIP
) {
365 pMatchingIPClient
= cur_client
;
371 *pbMultipleIPs
= cMatches
> 1;
374 if (pMatchingIPClient
&& cMatches
== 1) {
375 return pMatchingIPClient
;
382 void CUploadQueue::AddClientToQueue(CUpDownClient
* client
)
384 if (theApp
->serverconnect
->IsConnected() && theApp
->serverconnect
->IsLowID() && !theApp
->serverconnect
->IsLocalServer(client
->GetServerIP(),client
->GetServerPort()) && client
->GetDownloadState() == DS_NONE
&& !client
->IsFriend() && theStats::GetWaitingUserCount() > 50) {
385 // Well, all that issues finish in the same: don't allow to add to the queue
389 if ( client
->IsBanned() ) {
393 client
->AddAskedCount();
394 client
->SetLastUpRequest();
396 // Find all clients with the same user-hash
397 CClientList::SourceList found
= theApp
->clientlist
->GetClientsByHash( client
->GetUserHash() );
399 CClientList::SourceList::iterator it
= found
.begin();
400 while (it
!= found
.end()) {
401 CUpDownClient
* cur_client
= it
++->GetClient();
403 if ( IsOnUploadQueue( cur_client
) ) {
404 if ( cur_client
== client
) {
405 // This is where LowID clients get their upload slot assigned.
406 // They can't be contacted if they reach top of the queue, so they are just marked for uploading.
407 // When they reconnect next time AddClientToQueue() is called, and they get their slot
408 // through the connection they initiated.
409 // Since at that time no slot is free they get assigned an extra slot,
410 // so then the number of slots exceeds the configured number by one.
411 // To prevent a further increase no more LowID clients get a slot, until
412 // - a HighID client has got one (which happens only after two clients
413 // have been kicked so a slot is free again)
414 // - or there is a free slot, which means there is no HighID client on queue
415 if (client
->m_bAddNextConnect
) {
416 uint16 maxSlots
= GetMaxSlots();
417 if (lastupslotHighID
) {
420 if (m_uploadinglist
.size() < maxSlots
) {
421 client
->m_bAddNextConnect
= false;
422 RemoveFromWaitingQueue(client
);
423 AddUpNextClient(client
);
424 lastupslotHighID
= false; // LowID alternate
429 client
->SendRankingInfo();
430 Notify_SharedCtrlRefreshClient(client
->ECID(), AVAILABLE_SOURCE
);
433 // Hash-clash, remove unidentified clients (possibly both)
435 if ( !cur_client
->IsIdentified() ) {
436 // Cur_client isn't identifed, remove it
437 theApp
->clientlist
->AddTrackClient( cur_client
);
439 RemoveFromWaitingQueue( cur_client
);
440 if ( !cur_client
->GetSocket() ) {
441 if (cur_client
->Disconnected( wxT("AddClientToQueue - same userhash") ) ) {
442 cur_client
->Safe_Delete();
447 if ( !client
->IsIdentified() ) {
448 // New client isn't identified, remove it
449 theApp
->clientlist
->AddTrackClient( client
);
451 if ( !client
->GetSocket() ) {
452 if ( client
->Disconnected( wxT("AddClientToQueue - same userhash") ) ) {
453 client
->Safe_Delete();
463 // Count the number of clients with the same IP-address
464 found
= theApp
->clientlist
->GetClientsByIP( client
->GetIP() );
467 for ( it
= found
.begin(); it
!= found
.end(); it
++ ) {
468 if ( ( it
->GetClient() == client
) || IsOnUploadQueue( it
->GetClient() ) ) {
473 // We do not accept more than 3 clients from the same IP
476 } else if ( theApp
->clientlist
->GetClientsFromIP(client
->GetIP()) >= 3 ) {
481 CKnownFile
* reqfile
= (CKnownFile
*) client
->GetUploadFile();
483 reqfile
->statistic
.AddRequest();
486 if (client
->IsDownloading()) {
487 // he's already downloading and wants probably only another file
488 CPacket
* packet
= new CPacket(OP_ACCEPTUPLOADREQ
, 0, OP_EDONKEYPROT
);
489 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
490 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + client
->GetFullIP() );
491 client
->SendPacket(packet
,true);
495 // TODO find better ways to cap the list
496 if (m_waitinglist
.size() >= (thePrefs::GetQueueSize())) {
500 uint32 tick
= GetTickCount();
501 client
->ClearWaitStartTime();
502 // if possible start upload right away
503 if (m_waitinglist
.empty() && tick
- m_nLastStartUpload
>= 1000
504 && m_uploadinglist
.size() < GetMaxSlots()
505 && !theApp
->listensocket
->TooManySockets()) {
506 AddUpNextClient(client
);
507 m_nLastStartUpload
= tick
;
509 // add to waiting queue
510 m_waitinglist
.push_back(CCLIENTREF(client
, wxT("CUploadQueue::AddClientToQueue m_waitinglist.push_back")));
511 // and sort it to update queue ranks
513 theStats::AddWaitingClient();
514 client
->ClearAskedCount();
515 client
->SetUploadState(US_ONUPLOADQUEUE
);
516 client
->SendRankingInfo();
517 //Notify_QlistAddClient(client);
522 bool CUploadQueue::RemoveFromUploadQueue(CUpDownClient
* client
)
524 // Keep track of this client
525 theApp
->clientlist
->AddTrackClient(client
);
527 CClientRefList::iterator it
= std::find(m_uploadinglist
.begin(),
528 m_uploadinglist
.end(), CCLIENTREF(client
, wxEmptyString
));
530 if (it
!= m_uploadinglist
.end()) {
531 m_uploadinglist
.erase(it
);
532 m_allUploadingKnownFile
->RemoveUploadingClient(client
);
533 theStats::RemoveUploadingClient();
534 if( client
->GetTransferredUp() ) {
535 theStats::AddSuccessfulUpload();
536 theStats::AddUploadTime(client
->GetUpStartTimeDelay() / 1000);
538 theStats::AddFailedUpload();
540 client
->SetUploadState(US_NONE
);
541 client
->ClearUploadBlockRequests();
549 bool CUploadQueue::CheckForTimeOver(CUpDownClient
* client
)
551 // Don't kick anybody if there's no need to
552 if (!m_allowKicking
) {
555 // First, check if it is a VIP slot (friend or Release-Prio).
556 if (client
->GetFriendSlot()) {
557 return false; // never drop the friend
559 // Release-Prio and nobody on queue for it?
560 if (client
->GetUploadFile()->GetUpPriority() == PR_POWERSHARE
) {
561 // Keep it unless half of the UL slots are occupied with friends or Release uploads.
563 for (CClientRefList::iterator it
= m_uploadinglist
.begin(); it
!= m_uploadinglist
.end(); ++it
) {
564 CUpDownClient
* cur_client
= it
->GetClient();
565 if (cur_client
->GetFriendSlot() || cur_client
->GetUploadFile()->GetUpPriority() == PR_POWERSHARE
) {
569 // allow if VIP uploads occupy at most half of the possible upload slots
570 if (vips
<= GetMaxSlots() / 2) {
573 // Otherwise normal rules apply.
577 // "Transfer full chunks": drop client after 10 MB upload, or after an hour.
578 // (so average UL speed should at least be 2.84 kB/s)
579 // We don't track what he is downloading, but if it's all from one chunk he gets it.
580 if (client
->GetUpStartTimeDelay() > 3600000 // time: 1h
581 || client
->GetSessionUp() > 10485760) { // data: 10MB
582 m_allowKicking
= false; // kick max one client per cycle
591 * This function removes a file indicated by filehash from suspended_uploads_list.
593 void CUploadQueue::ResumeUpload( const CMD4Hash
& filehash
)
595 suspendedUploadsSet
.erase(filehash
);
596 AddLogLineN(CFormat( _("Resuming uploads of file: %s" ) )
597 % filehash
.Encode() );
601 * This function stops upload of a file indicated by filehash.
603 * a) teminate == false:
604 * File is suspended while a download completes. Then it is resumed after completion,
605 * so it makes sense to keep the client. Such files are kept in suspendedUploadsSet.
606 * b) teminate == true:
607 * File is deleted. Then the client is not added to the waiting list.
608 * Waiting clients are swept out with next run of AddUpNextClient,
609 * because their file is not shared anymore.
611 uint16
CUploadQueue::SuspendUpload(const CMD4Hash
& filehash
, bool terminate
)
613 AddLogLineN(CFormat( _("Suspending upload of file: %s" ) )
614 % filehash
.Encode() );
617 //Append the filehash to the list.
619 suspendedUploadsSet
.insert(filehash
);
622 CClientRefList::iterator it
= m_uploadinglist
.begin();
623 while (it
!= m_uploadinglist
.end()) {
624 CUpDownClient
*potential
= it
++->GetClient();
625 //check if the client is uploading the file we need to suspend
626 if (potential
->GetUploadFileID() == filehash
) {
627 // remove the unlucky client from the upload queue
628 RemoveFromUploadQueue(potential
);
629 // if suspend isn't permanent add it to the waiting queue
631 potential
->SetUploadState(US_NONE
);
633 m_waitinglist
.push_back(CCLIENTREF(potential
, wxT("CUploadQueue::SuspendUpload")));
634 theStats::AddWaitingClient();
635 potential
->SetUploadState(US_ONUPLOADQUEUE
);
636 potential
->SendRankingInfo();
637 Notify_SharedCtrlRefreshClient(potential
->ECID(), AVAILABLE_SOURCE
);
645 bool CUploadQueue::RemoveFromWaitingQueue(CUpDownClient
* client
)
647 CClientRefList::iterator it
= m_waitinglist
.begin();
650 while (it
!= m_waitinglist
.end()) {
651 CClientRefList::iterator it1
= it
++;
652 if (it1
->GetClient() == client
) {
653 RemoveFromWaitingQueue(it1
);
654 // update ranks of remaining queue
655 while (it
!= m_waitinglist
.end()) {
656 it
->GetClient()->SetUploadQueueWaitingPosition(rank
++);
667 void CUploadQueue::RemoveFromWaitingQueue(CClientRefList::iterator pos
)
669 CUpDownClient
* todelete
= pos
->GetClient();
670 m_waitinglist
.erase(pos
);
671 theStats::RemoveWaitingClient();
672 if( todelete
->IsBanned() ) {
675 //Notify_QlistRemoveClient(todelete);
676 todelete
->SetUploadState(US_NONE
);
677 todelete
->ClearScore();
678 todelete
->SetUploadQueueWaitingPosition(0);
681 #if EXTENDED_UPLOADQUEUE
683 int CUploadQueue::PopulatePossiblyWaitingList()
685 static uint32 lastPopulate
= 0;
686 uint32 tick
= GetTickCount();
687 int ret
= m_possiblyWaitingList
.size();
688 if (tick
- lastPopulate
> MIN2MS(15)) {
689 // repopulate in any case after this time
690 m_possiblyWaitingList
.clear();
691 } else if (ret
|| tick
- lastPopulate
< SEC2MS(30)) {
692 // don't retry too fast if list is empty
698 int nrDownloads
= theApp
->downloadqueue
->GetFileCount();
699 for (int idownload
= 0; idownload
< nrDownloads
; idownload
++) {
700 CPartFile
* download
= theApp
->downloadqueue
->GetFileByIndex(idownload
);
701 if (!download
|| download
->GetAvailablePartCount() == 0) {
704 const CKnownFile::SourceSet
& sources
= download
->GetSourceList();
705 if (sources
.empty()) {
708 // Make a table which parts are available. No need to notify a client
709 // which needs nothing we have.
710 uint16 parts
= download
->GetPartCount();
711 std::vector
<bool> partsAvailable
;
712 partsAvailable
.resize(parts
);
713 for (uint32 i
= parts
; i
--;) {
714 partsAvailable
[i
] = download
->IsComplete(i
);
716 for (CKnownFile::SourceSet::const_iterator it
= sources
.begin(); it
!= sources
.end(); it
++) {
717 // Iterate over our sources, find those where download == upload
718 CUpDownClient
* client
= it
->GetClient();
719 if (!client
|| client
->GetUploadFile() != download
|| client
->HasLowID()) {
722 const BitVector
& partStatus
= client
->GetPartStatus();
723 if (partStatus
.size() != parts
) {
726 // Do we have something for him?
727 bool haveSomething
= false;
728 for (uint32 i
= parts
; i
--;) {
729 if (partsAvailable
[i
] && !partStatus
.get(i
)) {
730 haveSomething
= true;
735 m_possiblyWaitingList
.push_back(*it
);
739 ret
= m_possiblyWaitingList
.size();
740 AddDebugLogLineN(logLocalClient
, CFormat(wxT("Populated PossiblyWaitingList: %d")) % ret
);
744 #endif // EXTENDED_UPLOADQUEUE
746 // File_checked_for_headers