📄 downloadqueue.cpp
字号:
CPartFile* cur_file = filelist.GetNext(pos);
if (id == cur_file->GetKadFileSearchID())
return cur_file;
}
return NULL;
}
bool CDownloadQueue::IsPartFile(const CKnownFile* file) const
{
for (POSITION pos = filelist.GetHeadPosition(); pos != 0; )
{
if (file == filelist.GetNext(pos))
return true;
}
return false;
}
// SLUGFILLER: SafeHash
bool CDownloadQueue::IsTempFile(const CString& rstrDirectory, const CString& rstrName) const
{
// do not share a part file from the temp directory, if there is still a corresponding entry in
// the download queue -- because that part file is not yet complete.
CString othername = rstrName + _T(".met");
for (POSITION pos = filelist.GetHeadPosition();pos != 0;){
CPartFile* cur_file = filelist.GetNext(pos);
if (!othername.CompareNoCase(cur_file->GetPartMetFileName()))
return true;
}
return false;
}
// SLUGFILLER: SafeHash
bool CDownloadQueue::CheckAndAddSource(CPartFile* sender,CUpDownClient* source){
if (sender->IsStopped()){
delete source;
return false;
}
if (source->HasValidHash())
{
if(!md4cmp(source->GetUserHash(), thePrefs.GetUserHash()))
{
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Tried to add source with matching hash to your own."));
delete source;
return false;
}
}
// filter sources which are known to be dead/useless
if (theApp.clientlist->m_globDeadSourceList.IsDeadSource(source) || sender->m_DeadSourceList.IsDeadSource(source)){
if (thePrefs.GetLogFilteredIPs())
AddDebugLogLine(DLP_DEFAULT, false, _T("Rejected source because it was found on the DeadSourcesList (%s) for file %s : %s")
,sender->m_DeadSourceList.IsDeadSource(source)? _T("Local") : _T("Global"), sender->GetFileName(), source->DbgGetClientInfo() );
delete source;
return false;
}
// "Filter LAN IPs" and/or "IPfilter" is not required here, because it was already done in parent functions
// uses this only for temp. clients
for (POSITION pos = filelist.GetHeadPosition();pos != 0;){
CPartFile* cur_file = filelist.GetNext(pos);
for (POSITION pos2 = cur_file->srclist.GetHeadPosition();pos2 != 0; ){
CUpDownClient* cur_client = cur_file->srclist.GetNext(pos2);
if (cur_client->Compare(source, true) || cur_client->Compare(source, false)){
if (cur_file == sender){ // this file has already this source
delete source;
return false;
}
// set request for this source
if (cur_client->AddRequestForAnotherFile(sender)){
theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(sender,cur_client,true);
delete source;
if(cur_client->GetDownloadState() != DS_CONNECTED) {
cur_client->SwapToAnotherFile(_T("New A4AF source found. CDownloadQueue::CheckAndAddSource()"), false, false, false, NULL, true, false); // ZZ:DownloadManager
}
return false;
}
else{
delete source;
return false;
}
}
}
}
//our new source is real new but maybe it is already uploading to us?
//if yes the known client will be attached to the var "source"
//and the old sourceclient will be deleted
if (theApp.clientlist->AttachToAlreadyKnown(&source,0)){
#ifdef _DEBUG
if (thePrefs.GetVerbose() && source->GetRequestFile()){
// if a client sent us wrong sources (sources for some other file for which we asked but which we are also
// downloading) we may get a little in trouble here when "moving" this source to some other partfile without
// further checks and updates.
if (md4cmp(source->GetRequestFile()->GetFileHash(), sender->GetFileHash()) != 0)
AddDebugLogLine(false, _T("*** CDownloadQueue::CheckAndAddSource -- added potential wrong source (%u)(diff. filehash) to file \"%s\""), source->GetUserIDHybrid(), sender->GetFileName());
if (source->GetRequestFile()->GetPartCount() != 0 && source->GetRequestFile()->GetPartCount() != sender->GetPartCount())
AddDebugLogLine(false, _T("*** CDownloadQueue::CheckAndAddSource -- added potential wrong source (%u)(diff. partcount) to file \"%s\""), source->GetUserIDHybrid(), sender->GetFileName());
}
#endif
source->SetRequestFile(sender);
}
else{
// here we know that the client instance 'source' is a new created client instance (see callers)
// which is therefor not already in the clientlist, we can avoid the check for duplicate client list entries
// when adding this client
theApp.clientlist->AddClient(source,true);
}
#ifdef _DEBUG
if (thePrefs.GetVerbose() && source->GetPartCount()!=0 && source->GetPartCount()!=sender->GetPartCount()){
DEBUG_ONLY(AddDebugLogLine(false, _T("*** CDownloadQueue::CheckAndAddSource -- New added source (%u, %s) had still value in partcount"), source->GetUserIDHybrid(), sender->GetFileName()));
}
#endif
sender->srclist.AddTail(source);
theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(sender,source,false);
return true;
}
bool CDownloadQueue::CheckAndAddKnownSource(CPartFile* sender,CUpDownClient* source, bool bIgnoreGlobDeadList){
if (sender->IsStopped())
return false;
// filter sources which are known to be dead/useless
if ( (theApp.clientlist->m_globDeadSourceList.IsDeadSource(source) && !bIgnoreGlobDeadList) || sender->m_DeadSourceList.IsDeadSource(source)){
if (thePrefs.GetLogFilteredIPs())
AddDebugLogLine(DLP_DEFAULT, false, _T("Rejected source because it was found on the DeadSourcesList (%s) for file %s : %s")
,sender->m_DeadSourceList.IsDeadSource(source)? _T("Local") : _T("Global"), sender->GetFileName(), source->DbgGetClientInfo() );
return false;
}
// "Filter LAN IPs" -- this may be needed here in case we are connected to the internet and are also connected
// to a LAN and some client from within the LAN connected to us. Though this situation may be supported in future
// by adding that client to the source list and filtering that client's LAN IP when sending sources to
// a client within the internet.
//
// "IPfilter" is not needed here, because that "known" client was already IPfiltered when receiving OP_HELLO.
if (!source->HasLowID()){
uint32 nClientIP = ntohl(source->GetUserIDHybrid());
if (!IsGoodIP(nClientIP)){ // check for 0-IP, localhost and LAN addresses
if (thePrefs.GetLogFilteredIPs())
AddDebugLogLine(false, _T("Ignored already known source with IP=%s"), ipstr(nClientIP));
return false;
}
}
// use this for client which are already know (downloading for example)
for (POSITION pos = filelist.GetHeadPosition();pos != 0;){
CPartFile* cur_file = filelist.GetNext(pos);
if (cur_file->srclist.Find(source)){
if (cur_file == sender)
return false;
if (source->AddRequestForAnotherFile(sender))
theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(sender,source,true);
if(source->GetDownloadState() != DS_CONNECTED) {
source->SwapToAnotherFile(_T("New A4AF source found. CDownloadQueue::CheckAndAddKnownSource()"), false, false, false, NULL, true, false); // ZZ:DownloadManager
}
return false;
}
}
#ifdef _DEBUG
if (thePrefs.GetVerbose() && source->GetRequestFile()){
// if a client sent us wrong sources (sources for some other file for which we asked but which we are also
// downloading) we may get a little in trouble here when "moving" this source to some other partfile without
// further checks and updates.
if (md4cmp(source->GetRequestFile()->GetFileHash(), sender->GetFileHash()) != 0)
AddDebugLogLine(false, _T("*** CDownloadQueue::CheckAndAddKnownSource -- added potential wrong source (%u)(diff. filehash) to file \"%s\""), source->GetUserIDHybrid(), sender->GetFileName());
if (source->GetRequestFile()->GetPartCount() != 0 && source->GetRequestFile()->GetPartCount() != sender->GetPartCount())
AddDebugLogLine(false, _T("*** CDownloadQueue::CheckAndAddKnownSource -- added potential wrong source (%u)(diff. partcount) to file \"%s\""), source->GetUserIDHybrid(), sender->GetFileName());
}
#endif
source->SetRequestFile(sender);
sender->srclist.AddTail(source);
source->SetSourceFrom(SF_PASSIVE);
#ifdef _DEBUG
if (thePrefs.GetVerbose() && source->GetPartCount()!=0 && source->GetPartCount()!=sender->GetPartCount()){
DEBUG_ONLY(AddDebugLogLine(false, _T("*** CDownloadQueue::CheckAndAddKnownSource -- New added source (%u, %s) had still value in partcount"), source->GetUserIDHybrid(), sender->GetFileName()));
}
#endif
theApp.emuledlg->transferwnd->downloadlistctrl.AddSource(sender,source,false);
//UpdateDisplayedInfo();
return true;
}
bool CDownloadQueue::RemoveSource(CUpDownClient* toremove, bool bDoStatsUpdate)
{
bool bRemovedSrcFromPartFile = false;
for (POSITION pos = filelist.GetHeadPosition();pos != 0;){
CPartFile* cur_file = filelist.GetNext(pos);
for (POSITION pos2 = cur_file->srclist.GetHeadPosition();pos2 != 0; cur_file->srclist.GetNext(pos2)){
if (toremove == cur_file->srclist.GetAt(pos2)){
cur_file->srclist.RemoveAt(pos2);
bRemovedSrcFromPartFile = true;
if ( bDoStatsUpdate ){
cur_file->RemoveDownloadingSource(toremove);
cur_file->UpdatePartsInfo();
}
break;
}
}
if ( bDoStatsUpdate )
cur_file->UpdateAvailablePartsCount();
}
// remove this source on all files in the downloadqueue who link this source
// pretty slow but no way arround, maybe using a Map is better, but that's slower on other parts
POSITION pos3, pos4;
for(pos3 = toremove->m_OtherRequests_list.GetHeadPosition();(pos4=pos3)!=NULL;)
{
toremove->m_OtherRequests_list.GetNext(pos3);
POSITION pos5 = toremove->m_OtherRequests_list.GetAt(pos4)->A4AFsrclist.Find(toremove);
if(pos5)
{
toremove->m_OtherRequests_list.GetAt(pos4)->A4AFsrclist.RemoveAt(pos5);
theApp.emuledlg->transferwnd->downloadlistctrl.RemoveSource(toremove,toremove->m_OtherRequests_list.GetAt(pos4));
toremove->m_OtherRequests_list.RemoveAt(pos4);
}
}
for(pos3 = toremove->m_OtherNoNeeded_list.GetHeadPosition();(pos4=pos3)!=NULL;)
{
toremove->m_OtherNoNeeded_list.GetNext(pos3);
POSITION pos5 = toremove->m_OtherNoNeeded_list.GetAt(pos4)->A4AFsrclist.Find(toremove);
if(pos5)
{
toremove->m_OtherNoNeeded_list.GetAt(pos4)->A4AFsrclist.RemoveAt(pos5);
theApp.emuledlg->transferwnd->downloadlistctrl.RemoveSource(toremove,toremove->m_OtherNoNeeded_list.GetAt(pos4));
toremove->m_OtherNoNeeded_list.RemoveAt(pos4);
}
}
if (bRemovedSrcFromPartFile && (toremove->HasFileRating() || !toremove->GetFileComment().IsEmpty()))
toremove->GetRequestFile()->UpdateFileRatingCommentAvail();
toremove->SetDownloadState(DS_NONE);
theApp.emuledlg->transferwnd->downloadlistctrl.RemoveSource(toremove,0);
toremove->SetRequestFile(NULL);
return bRemovedSrcFromPartFile;
}
void CDownloadQueue::RemoveFile(CPartFile* toremove)
{
RemoveLocalServerRequest(toremove);
for (POSITION pos = filelist.GetHeadPosition();pos != 0;filelist.GetNext(pos)){
if (toremove == filelist.GetAt(pos)){
filelist.RemoveAt(pos);
break;
}
}
SortByPriority();
CheckDiskspace(); // SLUGFILLER: checkDiskspace
ExportPartMetFilesOverview();
}
void CDownloadQueue::DeleteAll(){
POSITION pos;
for (pos = filelist.GetHeadPosition();pos != 0;){
CPartFile* cur_file = filelist.GetNext(pos);
cur_file->srclist.RemoveAll();
// Barry - Should also remove all requested blocks
// Don't worry about deleting the blocks, that gets handled
// when CUpDownClient is deleted in CClientList::DeleteAll()
cur_file->RemoveAllRequestedBlocks();
}
}
// Max. file IDs per UDP packet
// ----------------------------
// 576 - 30 bytes of header (28 for UDP, 2 for "E3 9A" edonkey proto) = 546 bytes
// 546 / 16 = 34
#define MAX_FILES_PER_UDP_PACKET 31 // 2+16*31 = 498 ... is still less than 512 bytes!!
#define MAX_REQUESTS_PER_SERVER 35
int CDownloadQueue::GetMaxFilesPerUDPServerPacket() const
{
int iMaxFilesPerPacket;
if (cur_udpserver && cur_udpserver->GetUDPFlags() & SRV_UDPFLG_EXT_GETSOURCES)
{
// get max. file ids per packet
if (m_cRequestsSentToServer < MAX_REQUESTS_PER_SERVER)
iMaxFilesPerPacket = min(MAX_FILES_PER_UDP_PACKET, MAX_REQUESTS_PER_SERVER - m_cRequestsSentToServer);
else{
ASSERT(0);
iMaxFilesPerPacket = 0;
}
}
else
iMaxFilesPerPacket = 1;
return iMaxFilesPerPacket;
}
bool CDownloadQueue::SendGlobGetSourcesUDPPacket(CSafeMemFile* data)
{
bool bSentPacket = false;
if ( cur_udpserver
&& (theApp.serverconnect->GetCurrentServer() == NULL ||
cur_udpserver != theApp.serverlist->GetServerByAddress(theApp.serverconnect->GetCurrentServer()->GetAddress(),theApp.serverconnect->GetCurrentServer()->GetPort())))
{
ASSERT( data->GetLength() > 0 && data->GetLength() % 16 == 0 );
int iFileIDs = data->GetLength() / 16;
if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T(">>> Sending OP__GlobGetSources to server(#%02x) %-15s (%3u of %3u); FileIDs=%u\n"), cur_udpserver->GetUDPFlags(), cur_udpserver->GetAddress(), m_iSearchedServers + 1, theApp.serverlist->GetServerCount(), iFileIDs);
Packet packet(data);
packet.opcode = OP_GLOBGETSOURCES;
theStats.AddUpDataOverheadServer(packet.size);
theApp.serverconnect->SendUDPPacket(&packet,cur_udpserver,false);
m_cRequestsSentToServer += iFileIDs;
bSentPacket = true;
}
return bSentPacket;
}
bool CDownloadQueue::SendNextUDPPacket()
{
if ( filelist.IsEmpty()
|| !theApp.serverconnect->IsUDPSocketAvailable()
|| !theApp.serverconnect->IsConnected())
return false;
if (!cur_udpserver){
if ((cur_udpserver = theApp.serverlist->GetNextServer(cur_udpserver)) == NULL){
TRACE("ERROR:SendNextUDPPacket() no server found\n");
StopUDPRequests();
};
m_cRequestsSentToServer = 0;
}
// get max. file ids per packet for current server
int iMaxFilesPerPacket = GetMaxFilesPerUDPServerPacket();
// loop until the packet is filled or a packet was sent
bool bSentPacket = false;
CSafeMemFile dataGlobGetSources(16);
int iFiles = 0;
while (iFiles < iMaxFilesPerPacket && !bSentPacket)
{
// get next file to search sources for
CPartFile* nextfile = NULL;
while (!bSentPacket && !(nextfile && (nextfile->GetStatus() == PS_READY || nextfile->GetStatus() == PS_EMPTY)))
{
if (lastfile == NULL) // we just started the global source searching or have switched the server
{
// get first file to search sources for
nextfile = filelist.GetHead();
lastfile = nextfile;
}
else
{
POSITION pos = filelist.Find(lastfile);
if (pos == 0) // the last file is no longer in the DL-list (may have been finished or canceld)
{
// get first file to search sources for
nextfile = filelist.GetHead();
lastfile = nextfile;
}
else
{
filelist.GetNext(pos);
if (pos == 0) // finished asking the current server for all files
{
// if there are pending requests for the current server, send them
if (dataGlobGetSources.GetLength() > 0)
{
if (SendGlobGetSourcesUDPPacket(&dataGlobGetSources))
bSentPacket = true;
dataGlobGetSources.SetLength(0);
}
// get next server to ask
cur_udpserver = theApp.serverlist->GetNextServer(cur_udpserver);
m_cRequestsSentToServer = 0;
if (cur_udpserver == NULL)
{
// finished asking all servers for all files
if (thePrefs.GetDebugServerUDPLevel() > 0 && thePrefs.GetDebugServerSourcesLevel() > 0)
Debug(_T("Finished UDP search processing for all servers (%u)\n"), theApp.serverlist->GetServerCount());
lastudpsearchtime = ::GetTickCount();
lastfile = NULL;
m_iSearchedServers = 0;
return false; // finished (processed all file & all servers)
}
m_iSearchedServers++;
// if we already sent a packet, switch to the next file at next function call
if (bSentPacket){
lastfile = NULL;
break;
}
// get max. file ids per packet for current server
iMaxFilesPerPacket = GetMaxFilesPerUDPServerPacket();
// have selected a new server; get first file to search sources for
nextfile = filelist.GetHead();
lastfile = nextfile;
}
else
{
nextfile = filelist.GetAt(pos);
lastfile = nextfile;
}
}
}
}
if (!bSentPacket && nextfile && nextfile->GetSourceCount() < thePrefs.GetMaxSourcePerFileUDP())
{
dataGlobGetSources.WriteHash16(nextfile->GetFileHash());
iFiles++;
if (thePrefs.GetDebugServerUDPLevel() > 0 && thePrefs.GetDebugServerSourcesLevel() > 0)
Debug(_T(">>> Queued OP__GlobGetSources to server(#%02x) %-15s (%3u of %3u); Buff %u=%s\n"), cur_udpserver->GetUDPFlags(), cur_udpserver->GetAddress(), m_iSearchedServers + 1, theApp.serverlist->GetServerCount(), iFiles, DbgGetFileInfo(nextfile->GetFileHash()));
}
}
ASSERT( dataGlobGetSources.GetLength() == 0 || !bSentPacket );
if (!bSentPacket && dataGlobGetSources.GetLength() > 0)
SendGlobGetSourcesUDPPacket(&dataGlobGetSources);
// send max 35 UDP request to one server per interval
// if we have more than 35 files, we rotate the list and use it as queue
if (m_cRequestsSentToServer >= MAX_REQUESTS_PER_SERVER)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -