📄 uploadqueue.cpp
字号:
//this file is part of eMule
//Copyright (C)2002 Merkur ( merkur-@users.sourceforge.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 "emule.h"
#include "UploadQueue.h"
#include "Packets.h"
#include "KnownFile.h"
#include "ListenSocket.h"
#include "Exceptions.h"
#include "Scheduler.h"
#include "PerfLog.h"
#include "UploadBandwidthThrottler.h"
#include "ClientList.h"
#include "LastCommonRouteFinder.h"
#include "DownloadQueue.h"
#include "FriendList.h"
#include "Statistics.h"
#include "MMServer.h"
#include "OtherFunctions.h"
#include "UpDownClient.h"
#include "SharedFileList.h"
#include "KnownFileList.h"
#include "Sockets.h"
#include "ClientCredits.h"
#include "Server.h"
#include "ServerList.h"
#include "WebServer.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "TransferWnd.h"
#include "SearchDlg.h"
#include "StatisticsDlg.h"
#include "Kademlia/Kademlia/Kademlia.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
static uint32 counter, sec, statsave;
static UINT _uSaveStatistics = 0;
// -khaos--+++> Added iupdateconnstats...
static uint32 igraph, istats, iupdateconnstats;
// <-----khaos-
//TODO rewrite the whole networkcode, use overlapped sockets.. sure....
CUploadQueue::CUploadQueue()
{
VERIFY( (h_timer = SetTimer(0,0,100,UploadTimer)) != NULL );
if (thePrefs.GetVerbose() && !h_timer)
AddDebugLogLine(true,_T("Failed to create 'upload queue' timer - %s"),GetErrorMessage(GetLastError()));
datarate = 0;
dataratems = 0;
counter=0;
successfullupcount = 0;
failedupcount = 0;
totaluploadtime = 0;
m_nLastStartUpload = 0;
statsave=0;
// -khaos--+++>
iupdateconnstats=0;
// <-----khaos-
m_bRemovedClientByScore = false;
}
void CUploadQueue::AddUpNextClient(CUpDownClient* directadd){
POSITION toadd = 0;
POSITION toaddlow = 0;
uint32 bestscore = 0;
uint32 bestlowscore = 0;
CUpDownClient* newclient;
// select next client or use given client
if (!directadd)
{
POSITION pos1, pos2;
for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;)
{
waitinglist.GetNext(pos1);
CUpDownClient* cur_client = waitinglist.GetAt(pos2);
// clear dead clients
ASSERT ( cur_client->GetLastUpRequest() );
if ((::GetTickCount() - cur_client->GetLastUpRequest() > MAX_PURGEQUEUETIME) || !theApp.sharedfiles->GetFileByID(cur_client->GetUploadFileID()) )
{
cur_client->ClearWaitStartTime();
RemoveFromWaitingQueue(pos2,true);
continue;
}
// finished clearing
uint32 cur_score = cur_client->GetScore(true);
if ( cur_score > bestscore)
{
bestscore = cur_score;
toadd = pos2;
}
else
{
cur_score = cur_client->GetScore(false);
if ((cur_score > bestlowscore) && !cur_client->m_bAddNextConnect)
{
bestlowscore = cur_score;
toaddlow = pos2;
}
}
}
if (bestlowscore > bestscore)
{
newclient = waitinglist.GetAt(toaddlow);
newclient->m_bAddNextConnect = true;
}
if (!toadd)
return;
newclient = waitinglist.GetAt(toadd);
lastupslotHighID = true; // VQB LowID alternate
//AddLogLine(true,"Added High ID: %s", newclient->GetUserName()); // VQB: perhaps only add to debug log?
RemoveFromWaitingQueue(toadd, true);
theApp.emuledlg->transferwnd->ShowQueueCount(waitinglist.GetCount());
}
else
{
newclient = directadd;
/*if (!IsDownloading(newclient)){
if (newclient->HasLowID())
AddLogLine(true,"DirectAdd: LowID: %s", newclient->GetUserName());
else
AddLogLine(true,"DirectAdd: HighID: %s", newclient->GetUserName());
}*/
}
if (!thePrefs.TransferFullChunks())
UpdateMaxClientScore(); // refresh score caching, now that the highest score is removed
if (IsDownloading(newclient))
{
return;
}
// tell the client that we are now ready to upload
if (!newclient->socket || !newclient->socket->IsConnected())
{
newclient->SetUploadState(US_CONNECTING);
if (!newclient->TryToConnect(true))
return;
}
else
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__AcceptUploadReq", newclient);
Packet* packet = new Packet(OP_ACCEPTUPLOADREQ,0);
theStats.AddUpDataOverheadFileRequest(packet->size);
newclient->socket->SendPacket(packet,true);
newclient->SetUploadState(US_UPLOADING);
}
newclient->SetUpStartTime();
newclient->ResetSessionUp();
theApp.uploadBandwidthThrottler->AddToStandardList(uploadinglist.GetCount(), newclient->socket);
uploadinglist.AddTail(newclient);
// statistic
CKnownFile* reqfile = theApp.sharedfiles->GetFileByID((uchar*)newclient->GetUploadFileID());
if (reqfile){
reqfile->statistic.AddAccepted();
}
theApp.emuledlg->transferwnd->uploadlistctrl.AddClient(newclient);
}
void CUploadQueue::Process() {
theApp.sharedfiles->Publish();
while ( avarage_dr_list.GetCount()>150)
dataratems-=avarage_dr_list.RemoveHead().datalen;
uint32 tick_avg = 100;
if (avarage_dr_list.GetCount() >2) {
uint32 deltat=(avarage_dr_list.GetTail().timestamp - avarage_dr_list.GetHead().timestamp);
if (deltat>0) datarate = (1000i64*(dataratems-avarage_dr_list.GetHead().datalen)) / deltat;
tick_avg = deltat / avarage_dr_list.GetCount();
} else
datarate = 0;
if (AcceptNewClient() && waitinglist.GetCount()){
m_nLastStartUpload = ::GetTickCount();
AddUpNextClient();
}
if (!uploadinglist.GetCount()) {
return;
}
m_bRemovedClientByScore = false;
POSITION pos = uploadinglist.GetHeadPosition();
while(pos != 0){
CUpDownClient* cur_client = uploadinglist.GetNext(pos);
if (thePrefs.m_iDbgHeap >= 2)
ASSERT_VALID(cur_client);
//It seems chatting or friend slots can get stuck at times in upload.. This needs looked into..
if (!cur_client->socket)
{
RemoveFromUploadQueue(cur_client, _T("Uploading to client without socket? (CUploadQueue::Process)"));
if(cur_client->Disconnected(_T("CUploadQueue::Process"))){
delete cur_client;
}
} else {
cur_client->SendBlockData();
}
}
uint64 sentBytes = theApp.uploadBandwidthThrottler->GetNumberOfSentBytesSinceLastCallAndReset();
TransferredData newitem = {sentBytes, ::GetTickCount()}; // theApp.stat_sessionSentBytes
avarage_dr_list.AddTail(newitem);
dataratems+=sentBytes;
};
bool CUploadQueue::AcceptNewClient(){
// check if we can allow a new client to start downloading from us
if (::GetTickCount() - m_nLastStartUpload < 1000 && datarate < 102400 )
return false;
uint16 MaxSpeed;
if (thePrefs.IsDynUpEnabled())
MaxSpeed = theApp.lastCommonRouteFinder->GetUpload()/1024;
else
MaxSpeed = thePrefs.GetMaxUpload();
uint32 upPerClient = UPLOAD_CLIENT_DATARATE;
uint32 curUploadSlots = (uint32)uploadinglist.GetCount();
if (curUploadSlots < MIN_UP_CLIENTS_ALLOWED)
return true;
else if (curUploadSlots >= MAX_UP_CLIENTS_ALLOWED ||
curUploadSlots >= 4 &&
(
curUploadSlots >= (datarate/UPLOAD_CHECK_CLIENT_DR) ||
curUploadSlots >= ((uint32)MaxSpeed)*1024/UPLOAD_CLIENT_DATARATE ||
!theApp.lastCommonRouteFinder->AcceptNewClient() || // upload speed sense can veto a new slot if USS enabled
(
thePrefs.GetMaxUpload() == UNLIMITED &&
!thePrefs.IsDynUpEnabled() &&
thePrefs.GetMaxGraphUploadRate() > 0 &&
curUploadSlots >= ((uint32)thePrefs.GetMaxGraphUploadRate())*1024/UPLOAD_CLIENT_DATARATE
)
)
) // max number of clients to allow for all circumstances
return false;
if(theApp.uploadBandwidthThrottler->GetHighestNumberOfFullyActivatedSlotsSinceLastCallAndReset() > (uint32)uploadinglist.GetSize()) {
// uploadThrottler requests another slot. If throttler says it needs another slot, we will allow more slots
// than what we require ourself. Never allow more slots than to give each slot high enough average transfer speed, though (checked above).
return true;
}
// if throttler doesn't require another slot, go with a slightly more restrictive method
if( MaxSpeed > 20 || MaxSpeed == UNLIMITED)
upPerClient += datarate/43;
if( upPerClient > 7680 )
upPerClient = 7680;
//now the final check
if ( MaxSpeed == UNLIMITED )
{
if (curUploadSlots < (datarate/upPerClient))
return true;
}
else{
uint16 nMaxSlots;
if (MaxSpeed > 12)
nMaxSlots = (uint16)(((float)(MaxSpeed*1024)) / upPerClient);
else if (MaxSpeed > 7)
nMaxSlots = MIN_UP_CLIENTS_ALLOWED + 2;
else if (MaxSpeed > 3)
nMaxSlots = MIN_UP_CLIENTS_ALLOWED + 1;
else
nMaxSlots = MIN_UP_CLIENTS_ALLOWED;
// AddLogLine(true,"maxslots=%u, upPerClient=%u, datarateslot=%u|%u|%u",nMaxSlots,upPerClient,datarate/UPLOAD_CHECK_CLIENT_DR, datarate, UPLOAD_CHECK_CLIENT_DR);
if ( curUploadSlots < nMaxSlots )
{
return true;
}
}
//nope
return false;
}
CUploadQueue::~CUploadQueue(){
if (h_timer)
KillTimer(0,h_timer);
}
CUpDownClient* CUploadQueue::GetWaitingClientByIP_UDP(uint32 dwIP, uint16 nUDPPort){
for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;){
CUpDownClient* cur_client = waitinglist.GetNext(pos);
if (dwIP == cur_client->GetIP() && nUDPPort == cur_client->GetUDPPort())
return cur_client;
}
return 0;
}
CUpDownClient* CUploadQueue::GetWaitingClientByIP(uint32 dwIP){
for (POSITION pos = waitinglist.GetHeadPosition();pos != 0;){
CUpDownClient* cur_client = waitinglist.GetNext(pos);
if (dwIP == cur_client->GetIP())
return cur_client;
}
return 0;
}
void CUploadQueue::AddClientToQueue(CUpDownClient* client, bool bIgnoreTimelimit)
{
if (theApp.serverconnect->IsConnected() && theApp.serverconnect->IsLowID() //This may need to be changed with the Kad now being used.
&& !theApp.serverconnect->IsLocalServer(client->GetServerIP(),client->GetServerPort())
&& client->GetDownloadState() == DS_NONE && !client->IsFriend()
&& GetWaitingUserCount() > 50)
return;
client->AddAskedCount();
client->SetLastUpRequest();
if (!bIgnoreTimelimit)
{
client->AddRequestCount(client->GetUploadFileID());
}
if (client->IsBanned())
return;
uint16 cSameIP = 0;
// check for double
POSITION pos1, pos2;
for (pos1 = waitinglist.GetHeadPosition();( pos2 = pos1 ) != NULL;)
{
waitinglist.GetNext(pos1);
CUpDownClient* cur_client= waitinglist.GetAt(pos2);
if (cur_client == client)
{
//already on queue
// VQB LowID Slot Patch -- note: should add limit so only if #slots < UL -or- UL+1 for Low UL (?)
if (client->m_bAddNextConnect && (uploadinglist.GetCount() < thePrefs.GetMaxUpload()))
{
if (lastupslotHighID)
{
client->m_bAddNextConnect = false;
RemoveFromWaitingQueue(client, true);
AddUpNextClient(client);
lastupslotHighID = false; // LowID alternate
return;
}
}
// VQB end
client->SendRankingInfo();
theApp.emuledlg->transferwnd->queuelistctrl.RefreshClient(client);
return;
}
else if ( client->Compare(cur_client) )
{
theApp.clientlist->AddTrackClient(client); // in any case keep track of this client
// another client with same ip:port or hash
// this happens only in rare cases, because same userhash / ip:ports are assigned to the right client on connecting in most cases
if (cur_client->credits != NULL && cur_client->credits->GetCurrentIdentState(cur_client->GetIP()) == IS_IDENTIFIED)
{
//cur_client has a valid secure hash, don't remove him
if (thePrefs.GetVerbose())
AddDebugLogLine(false,CString(GetResString(IDS_SAMEUSERHASH)),client->GetUserName(),cur_client->GetUserName(),client->GetUserName() );
return;
}
if (client->credits != NULL && client->credits->GetCurrentIdentState(client->GetIP()) == IS_IDENTIFIED)
{
//client has a valid secure hash, add him remove other one
if (thePrefs.GetVerbose())
AddDebugLogLine(false,CString(GetResString(IDS_SAMEUSERHASH)),client->GetUserName(),cur_client->GetUserName(),cur_client->GetUserName() );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -