📄 downloadqueue.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
//
//This program is free software; you can redistribute it and/or
//modify it under the terms of the GNU General Public License
//as published by the Free Software Foundation; either
//version 2 of the License, or (at your option) any later version.
//
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU General Public License for more details.
//
//You should have received a copy of the GNU General Public License
//along with this program; if not, write to the Free Software
//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include "stdafx.h"
#include <io.h>
#include "emule.h"
#include "DownloadQueue.h"
#include "UpDownClient.h"
#include "PartFile.h"
#include "ed2kLink.h"
#include "SearchList.h"
#include "ClientList.h"
#include "Statistics.h"
#include "SharedFileList.h"
#include "OtherFunctions.h"
#include "SafeFile.h"
#include "Sockets.h"
#include "ServerList.h"
#include "Server.h"
#include "Packets.h"
#include "Kademlia/Kademlia/Kademlia.h"
#include "kademlia/utils/uint128.h"
#include "ipfilter.h"
#include "emuledlg.h"
#include "TransferWnd.h"
#include "TaskbarNotifier.h"
#include "MenuCmds.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
CDownloadQueue::CDownloadQueue(CSharedFileList* in_sharedfilelist)
{
sharedfilelist = in_sharedfilelist;
filesrdy = 0;
datarate = 0;
cur_udpserver = 0;
lastfile = 0;
lastcheckdiskspacetime = 0; // SLUGFILLER: checkDiskspace
lastudpsearchtime = 0;
lastudpstattime = 0;
SetLastKademliaFileRequest();
udcounter = 0;
m_iSearchedServers = 0;
m_datarateMS=0;
m_nUDPFileReasks = 0;
m_nFailedUDPFileReasks = 0;
m_dwNextTCPSrcReq = 0;
m_cRequestsSentToServer = 0;
m_dwLastA4AFtime = 0; // ZZ:DownloadManager
}
void CDownloadQueue::AddPartFilesToShare()
{
for (POSITION pos = filelist.GetHeadPosition(); pos != 0; )
{
CPartFile* cur_file = filelist.GetNext(pos);
if (cur_file->GetStatus(true) == PS_READY)
sharedfilelist->SafeAddKFile(cur_file,true);
}
}
void CDownloadQueue::Init(){
// find all part files, read & hash them if needed and store into a list
CFileFind ff;
int count = 0;
CString searchPath(thePrefs.GetTempDir());
searchPath += "\\*.part.met";
//check all part.met files
bool end = !ff.FindFile(searchPath, 0);
while (!end){
end = !ff.FindNextFile();
if (ff.IsDirectory())
continue;
CPartFile* toadd = new CPartFile();
if (toadd->LoadPartFile(thePrefs.GetTempDir(),ff.GetFileName().GetBuffer())){
count++;
filelist.AddTail(toadd); // to downloadqueue
if (toadd->GetStatus(true) == PS_READY)
sharedfilelist->SafeAddKFile(toadd); // part files are always shared files
theApp.emuledlg->transferwnd->downloadlistctrl.AddFile(toadd);// show in downloadwindow
}
else
delete toadd;
}
ff.Close();
//try recovering any part.met files
searchPath += ".backup";
end = !ff.FindFile(searchPath, 0);
while (!end){
end = !ff.FindNextFile();
if (ff.IsDirectory())
continue;
CPartFile* toadd = new CPartFile();
if (toadd->LoadPartFile(thePrefs.GetTempDir(),ff.GetFileName().GetBuffer())){
toadd->SavePartFile(); // resave backup
count++;
filelist.AddTail(toadd); // to downloadqueue
if (toadd->GetStatus(true) == PS_READY)
sharedfilelist->SafeAddKFile(toadd); // part files are always shared files
theApp.emuledlg->transferwnd->downloadlistctrl.AddFile(toadd);// show in downloadwindow
AddLogLine(false, GetResString(IDS_RECOVERED_PARTMET), toadd->GetFileName());
}
else {
delete toadd;
}
}
ff.Close();
if(count == 0) {
AddLogLine(false,GetResString(IDS_NOPARTSFOUND));
} else {
AddLogLine(false,GetResString(IDS_FOUNDPARTS),count);
SortByPriority();
CheckDiskspace(); // SLUGFILLER: checkDiskspace
}
VERIFY( m_srcwnd.CreateEx(0, AfxRegisterWndClass(0),_T("Hostname Resolve Wnd"),WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL));
ExportPartMetFilesOverview();
}
CDownloadQueue::~CDownloadQueue(){
for (POSITION pos = filelist.GetHeadPosition();pos != 0;)
delete filelist.GetNext(pos);
m_srcwnd.DestroyWindow(); // just to avoid a MFC warning
}
void CDownloadQueue::AddSearchToDownload(CSearchFile* toadd,uint8 paused,uint8 cat){
if (IsFileExisting(toadd->GetFileHash()))
return;
CPartFile* newfile = new CPartFile(toadd);
if (newfile->GetStatus() == PS_ERROR){
delete newfile;
return;
}
newfile->SetCategory(cat);
if (paused == 2)
paused = (uint8)thePrefs.AddNewFilesPaused();
AddDownload(newfile, (paused==1));
// If the search result is from OP_GLOBSEARCHRES there may also be a source
if (toadd->GetClientID() && toadd->GetClientPort()){
CSafeMemFile sources(1+4+2);
try{
sources.WriteUInt8(1);
sources.WriteUInt32(toadd->GetClientID());
sources.WriteUInt16(toadd->GetClientPort());
sources.SeekToBegin();
newfile->AddSources(&sources, toadd->GetClientServerIP(), toadd->GetClientServerPort());
}
catch(CFileException* error){
ASSERT(0);
error->Delete();
}
}
// Add more sources which were found via global UDP search
const CSimpleArray<CSearchFile::SClient>& aClients = toadd->GetClients();
for (int i = 0; i < aClients.GetSize(); i++){
CSafeMemFile sources(1+4+2);
try{
sources.WriteUInt8(1);
sources.WriteUInt32(aClients[i].m_nIP);
sources.WriteUInt16(aClients[i].m_nPort);
sources.SeekToBegin();
newfile->AddSources(&sources,aClients[i].m_nServerIP, aClients[i].m_nServerPort);
}
catch(CFileException* error){
ASSERT(0);
error->Delete();
break;
}
}
}
void CDownloadQueue::AddSearchToDownload(CString link,uint8 paused, uint8 cat){
CPartFile* newfile = new CPartFile(link);
if (newfile->GetStatus() == PS_ERROR){
delete newfile;
return;
}
newfile->SetCategory(cat);
if (paused == 2)
paused = (uint8)thePrefs.AddNewFilesPaused();
AddDownload(newfile, (paused==1));
}
void CDownloadQueue::StartNextFileIfPrefs(int cat) {
if (thePrefs.StartNextFile()) {
int catTemp = thePrefs.StartNextFile() > 1?cat:-1;
bool force = thePrefs.StartNextFile()==3?false:true;
StartNextFile(catTemp, force);
}
}
void CDownloadQueue::StartNextFile(int cat, bool force){
CPartFile* pfile = NULL;
CPartFile* cur_file ;
POSITION pos;
if (cat != -1) {
// try to find in specified category
for (pos = filelist.GetHeadPosition();pos != 0;){
cur_file = filelist.GetNext(pos);
if (cur_file->GetStatus()==PS_PAUSED &&
(
cur_file->GetCategory()==cat ||
cat==0 && thePrefs.GetAllcatType()==0 && cur_file->GetCategory()>0
) &&
CPartFile::RightFileHasHigherPrio(pfile, cur_file)
) {
pfile = cur_file;
}
}
if (pfile == NULL && !force)
return;
}
if(cat == -1 || pfile == NULL && force) {
for (pos = filelist.GetHeadPosition();pos != 0;){
cur_file = filelist.GetNext(pos);
if (cur_file->GetStatus() == PS_PAUSED &&
CPartFile::RightFileHasHigherPrio(pfile, cur_file))
{
// pick first found matching file, since they are sorted in prio order with most important file first.
pfile = cur_file;
}
}
}
if (pfile) pfile->ResumeFile();
}
void CDownloadQueue::AddFileLinkToDownload(CED2KFileLink* pLink,uint8 cat)
{
CPartFile* newfile = new CPartFile(pLink);
if (newfile->GetStatus() == PS_ERROR){
delete newfile;
newfile=NULL;
}
else {
newfile->SetCategory(cat);
AddDownload(newfile,thePrefs.AddNewFilesPaused());
}
CPartFile* partfile = newfile;
if (partfile == NULL)
partfile = GetFileByID(pLink->GetHashKey());
if (partfile)
{
if (pLink->HasValidSources())
partfile->AddClientSources(pLink->SourcesList,1);
if (pLink->HasValidAICHHash() ){
if ( !(partfile->GetAICHHashset()->HasValidMasterHash() && partfile->GetAICHHashset()->GetMasterHash() == pLink->GetAICHHash())){
partfile->GetAICHHashset()->SetMasterHash(pLink->GetAICHHash(), AICH_VERIFIED);
partfile->GetAICHHashset()->FreeHashSet();
}
}
}
if (pLink->HasHostnameSources())
{
POSITION pos = pLink->m_HostnameSourcesList.GetHeadPosition();
while (pos != NULL)
{
const SUnresolvedHostname* pUnresHost = pLink->m_HostnameSourcesList.GetNext(pos);
m_srcwnd.AddToResolve(pLink->GetHashKey(), pUnresHost->strHostname, pUnresHost->nPort, pUnresHost->strURL);
}
}
}
void CDownloadQueue::AddToResolved( CPartFile* pFile, SUnresolvedHostname* pUH )
{
if( pFile && pUH )
m_srcwnd.AddToResolve( pFile->GetFileHash(), pUH->strHostname, pUH->nPort, pUH->strURL);
}
void CDownloadQueue::AddDownload(CPartFile* newfile,bool paused) {
// Barry - Add in paused mode if required
if (paused)
newfile->PauseFile();
SetAutoCat(newfile);// HoaX_69 / Slugfiller: AutoCat
filelist.AddTail(newfile);
SortByPriority();
CheckDiskspace(); // SLUGFILLER: checkDiskspace
theApp.emuledlg->transferwnd->downloadlistctrl.AddFile(newfile);
AddLogLine(true,GetResString(IDS_NEWDOWNLOAD),newfile->GetFileName());
CString msgTemp;
msgTemp.Format(GetResString(IDS_NEWDOWNLOAD) + _T("\n"), newfile->GetFileName());
theApp.emuledlg->ShowNotifier(msgTemp, TBN_DLOADADDED);
ExportPartMetFilesOverview();
}
bool CDownloadQueue::IsFileExisting(const uchar* fileid, bool bLogWarnings)
{
const CKnownFile* file = sharedfilelist->GetFileByID(fileid);
if (file){
if (bLogWarnings){
if (file->IsPartFile())
AddLogLine(true, GetResString(IDS_ERR_ALREADY_DOWNLOADING), file->GetFileName());
else
AddLogLine(true, GetResString(IDS_ERR_ALREADY_DOWNLOADED), file->GetFileName());
}
return true;
}
else if ((file = GetFileByID(fileid)) != NULL){
if (bLogWarnings)
AddLogLine(true, GetResString(IDS_ERR_ALREADY_DOWNLOADING), file->GetFileName());
return true;
}
return false;
}
void CDownloadQueue::Process(){
ProcessLocalRequests(); // send src requests to local server
uint32 downspeed = 0;
uint64 maxDownload = thePrefs.GetMaxDownloadInBytesPerSec(true);
if (maxDownload != UNLIMITED && datarate > 1500){
downspeed = (maxDownload*100)/(datarate+1);
if (downspeed < 50)
downspeed = 50;
else if (downspeed > 200)
downspeed = 200;
}
while(avarage_dr_list.GetCount()>0 && (GetTickCount() - avarage_dr_list.GetHead().timestamp > 10*1000) )
m_datarateMS-=avarage_dr_list.RemoveHead().datalen;
if (avarage_dr_list.GetCount()>1){
datarate = m_datarateMS / avarage_dr_list.GetCount();
} else {
datarate = 0;
}
uint32 datarateX=0;
udcounter++;
//filelist is already sorted by prio, therefore I removed all the extra loops..
for (POSITION pos = filelist.GetHeadPosition();pos != 0;){
CPartFile* cur_file = filelist.GetNext(pos);
if (cur_file->GetStatus() == PS_READY || cur_file->GetStatus() == PS_EMPTY){
datarateX += cur_file->Process(downspeed,udcounter);
}
else{
//This will make sure we don't keep old sources to paused and stoped files..
cur_file->StopPausedFile();
}
}
TransferredData newitem = {datarateX, ::GetTickCount()};
avarage_dr_list.AddTail(newitem);
m_datarateMS+=datarateX;
if (udcounter == 5){
if (theApp.serverconnect->IsUDPSocketAvailable()){
if((!lastudpstattime) || (::GetTickCount() - lastudpstattime) > UDPSERVERSTATTIME){
lastudpstattime = ::GetTickCount();
theApp.serverlist->ServerStats();
}
}
}
if (udcounter == 10){
udcounter = 0;
if (theApp.serverconnect->IsUDPSocketAvailable()){
if ((!lastudpsearchtime) || (::GetTickCount() - lastudpsearchtime) > UDPSERVERREASKTIME)
SendNextUDPPacket();
}
}
CheckDiskspaceTimed();
// ZZ:DownloadManager -->
//if((!m_dwLastA4AFtime) || (::GetTickCount() - m_dwLastA4AFtime) > 2*60*1000) {
// theApp.clientlist->ProcessA4AFClients();
// m_dwLastA4AFtime = ::GetTickCount();
//}
// <-- ZZ:DownloadManager
}
CPartFile* CDownloadQueue::GetFileByIndex(int index) const
{
POSITION pos = filelist.FindIndex(index);
if (pos)
return filelist.GetAt(pos);
return NULL;
}
CPartFile* CDownloadQueue::GetFileByID(const uchar* filehash) const
{
for (POSITION pos = filelist.GetHeadPosition(); pos != 0; )
{
CPartFile* cur_file = filelist.GetNext(pos);
if (!md4cmp(filehash, cur_file->GetFileHash()))
return cur_file;
}
return NULL;
}
CPartFile* CDownloadQueue::GetFileByKadFileSearchID(uint32 id) const
{
for (POSITION pos = filelist.GetHeadPosition(); pos != 0; )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -