//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 "zlib/zlib.h"
#include "UpDownClient.h"
#include "opcodes.h"
#include "packets.h"
#include "emule.h"
#include "uploadqueue.h"
#include "otherstructs.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
if (strstr(m_pszUsername, "hardware") || strstr(m_pszUsername, "hard"))
m_bBanned = true;
m_nDownloadState = false;
// members of CUpDownClient
// which are mainly used for uploading functions
CBarShader CUpDownClient::s_UpStatusBar(16);
void CUpDownClient::DrawUpStatusBar(CDC* dc, RECT* rect, bool onlygreyrect, bool bFlat){
RECT gaprect;
gaprect.top = rect->top + 2;
gaprect.bottom = rect->bottom - 2;
gaprect.left = rect->left;
gaprect.right = rect->right;
dc->FillRect(&gaprect,&CBrush(RGB(220,220,220)));
if( onlygreyrect )
return;
float blockpixel = (float)(rect->right - rect->left)/((float)(PARTSIZE*(m_nUpPartCount))/1024);
for (uint32 i = 0;i != m_nUpPartCount;i++){
if (m_abyUpPartStatus[i]){
gaprect.right = rect->left + (uint32)(((float)PARTSIZE*i/1024)*blockpixel);
gaprect.left = rect->left + (uint32)((float)((float)PARTSIZE*(i+1)/1024)*blockpixel);
dc->FillRect(&gaprect,&CBrush(RGB(0,0,0)));
}
}
}
/*
COLORREF crBoth;
COLORREF crNeither;
COLORREF crClientOnly;
COLORREF crPending;
COLORREF crNextPending;
if(bFlat) {
crBoth = RGB(0, 150, 0);
crNeither = RGB(224, 224, 224);
crClientOnly = RGB(0, 0, 0);
crPending = RGB(255,208,0);
crNextPending = RGB(255,255,100);
} else {
crBoth = RGB(0, 192, 0);
crNeither = RGB(240, 240, 240);
crClientOnly = RGB(104, 104, 104);
crPending = RGB(255, 208, 0);
crNextPending = RGB(255,255,100);
}
s_UpStatusBar.SetFileSize(PARTSIZE*(m_nUpPartCount));
s_UpStatusBar.SetHeight(rect->bottom - rect->top);
s_UpStatusBar.SetWidth(rect->right - rect->left);
s_UpStatusBar.Fill(crNeither);
if (!onlygreyrect && m_abyUpPartStatus) {
for (uint32 i = 0;i != m_nUpPartCount;i++){
if (m_abyUpPartStatus[i]){
s_StatusBar.FillRange(PARTSIZE*(i), PARTSIZE*(i+1), crClientOnly);
}
}
}
s_StatusBar.Draw(dc, rect->left, rect->top, bFlat);
}
*/
uint32 CUpDownClient::GetScore(bool sysvalue, bool isdownloading, bool onlybasevalue){
//TODO: complete this (friends, uploadspeed, emuleuser etc etc)
if (!m_pszUsername)
return 0;
// friend slot
if (IsFriend() && GetFriendSlot())
return 0x0FFFFFFF;
if (IsBanned())
return 0;
if (sysvalue && HasLowID() && !(socket && socket->IsConnected())){
return 0;
}
// TODO coded by tecxx & herbert, one yet unsolved problem here:
// sometimes a client asks for 2 files and there is no way to decide, which file the
// client finally gets. so it could happen that he is queued first because of a
// high prio file, but then asks for something completely different.
int filepriority = 10; // standard
if(reqfileid != NULL){
// Maella -Code Improvement- (Ichi)
CKnownFile *pFile = theApp.sharedfiles->GetFileByID(reqfileid);
if(pFile != NULL){
switch(pFile->GetPriority()){
case PR_VERYHIGH:
if (pFile->IsAutoPrioritized()) {
// Maella end
filepriority = 35;
} else {
filepriority = 50;
}
break;
case PR_HIGH:
filepriority = 20;
break;
case PR_LOW:
filepriority = 5;
break;
case PR_VERYLOW:
filepriority = 2;
break;
case PR_NORMAL:
default:
filepriority = 10;
break;
}
}
}
// calculate score, based on waitingtime and other factors
float fBaseValue;
if (onlybasevalue)
fBaseValue = 100;
else if (!isdownloading)
fBaseValue = (float)(::GetTickCount()-m_dwWaitTime)/1000;
else{
// we dont want one client to download forever
// the first 15 min downloadtime counts as 15 min waitingtime and you get a 15 min bonus while you are in the first 15 min :)
// (to avoid 20 sec downloads) after this the score won't raise anymore
fBaseValue = (float)(m_dwUploadTime-m_dwWaitTime);
ASSERT ( m_dwUploadTime-m_dwWaitTime >= 0 ); //oct 28, 02: changed this from "> 0" to ">= 0"
fBaseValue += (float)(::GetTickCount() - m_dwUploadTime > 900000)? 900000:1800000;
fBaseValue /= 1000;
}
ASSERT(credits != NULL);
fBaseValue *= credits->GetScoreRatio();
if (!onlybasevalue)
fBaseValue *= (float(filepriority)/10.0f);
if (!isdownloading && !onlybasevalue){
if (HasLowID() && !(socket && socket->IsConnected()) ){
if (!theApp.serverconnect->IsConnected() || theApp.serverconnect->IsLowID() || theApp.listensocket->TooManySockets())
return 0;
}
}
return (uint32)fBaseValue;
}
// Checks if it is next requested block from another chunk of the actual file or from another file
//
// [Returns]
// true : Next requested block is from another different chunk or file than last downloaded block
// false: Next requested block is from same chunk that last downloaded block
bool CUpDownClient::IsDifferentPartBlock(void) // [Tarod 12/22/2002]
{
Requested_Block_Struct* last_done_block;
Requested_Block_Struct* next_requested_block;
uint32 last_done_part = 0xffffffff;
uint32 next_requested_part = 0xffffffff;
bool different_part = false;
try {
// Check if we have good lists and proceed to check for different chunks
if (!m_BlockRequests_queue.IsEmpty() && !m_DoneBlocks_list.IsEmpty())
{
// Get last block and next pending
last_done_block = (Requested_Block_Struct*)m_DoneBlocks_list.GetHead();
next_requested_block = (Requested_Block_Struct*)m_BlockRequests_queue.GetHead();
// Calculate corresponding parts to blocks
last_done_part = last_done_block->StartOffset / PARTSIZE;
next_requested_part = next_requested_block->StartOffset / PARTSIZE;
// Test is we are asking same file and same part
if ( last_done_part != next_requested_part)
{
different_part = true;
theApp.emuledlg->AddDebugLogLine(false, "Session ended due to new chunk.");
}
if (memcmp(last_done_block->FileID, next_requested_block->FileID, 16) != 0)
{
different_part = true;
theApp.emuledlg->AddDebugLogLine(false, "Session ended due to different file.");
}
}
}
catch(...)
{
different_part = true;
}
// theApp.emuledlg->AddDebugLogLine(false, "Debug: User %s, last_done_part (%u) %s (%u) next_requested_part, sent %u Kbs.", GetUserName(), last_done_part, different_part? "!=": "==", next_requested_part, this->GetTransferedUp() / 1024);
return different_part;
}
bool CUpDownClient::CreateNextBlockPackage(){
// time critical
// check if we should kick this client
// VQB Full Chunk Trans..
if (theApp.glob_prefs->TransferFullChunks())
{
// VQB to provide full chunk transfers (modified by Tarod)
if ( theApp.uploadqueue->CheckForTimeOver(this) || IsDifferentPartBlock())
{
SetWaitStartTime();
theApp.uploadqueue->RemoveFromUploadQueue(this);
theApp.uploadqueue->AddClientToQueue(this,true);
return false;
}
}
else {
if (theApp.uploadqueue->CheckForTimeOver(this)){
// back on the waitqueue
SetWaitStartTime();
theApp.uploadqueue->RemoveFromUploadQueue(this);
theApp.uploadqueue->AddClientToQueue(this,true);
return false;
}
}
if (m_BlockRequests_queue.IsEmpty()){
return false;
}
CFile file;
byte* filedata = 0;
char* fullname = 0;
try{
while (!m_BlockRequests_queue.IsEmpty()){
Requested_Block_Struct* currentblock = m_BlockRequests_queue.GetHead();
CKnownFile* srcfile = theApp.sharedfiles->GetFileByID(currentblock->FileID);
if (!srcfile)
throw GetResString(IDS_ERR_REQ_FNF);
if (srcfile->IsPartFile() && ((CPartFile*)srcfile)->GetStatus() != PS_COMPLETE){
fullname = nstrdup(((CPartFile*)srcfile)->GetFullName());
fullname[strlen(fullname)-4] = 0;
}
else{
fullname = new char[strlen(srcfile->GetPath())+strlen(srcfile->GetFileName())+10];
sprintf(fullname,"%s\\%s",srcfile->GetPath(),srcfile->GetFileName());
}
uint32 togo;
if (currentblock->StartOffset > currentblock->EndOffset){
togo = currentblock->EndOffset + (srcfile->GetFileSize() - currentblock->StartOffset);
}
else{
togo = currentblock->EndOffset - currentblock->StartOffset;
if (srcfile->IsPartFile() && !((CPartFile*)srcfile)->IsComplete(currentblock->StartOffset,currentblock->EndOffset-1))
throw GetResString(IDS_ERR_INCOMPLETEBLOCK);
}
if( togo > 184320 )
throw GetResString(IDS_ERR_LARGEREQBLOCK);
if (!srcfile->IsPartFile()){
if (!file.Open(fullname,CFile::modeRead|CFile::osSequentialScan|CFile::shareDenyNone))
throw GetResString(IDS_ERR_OPEN);
delete[] fullname;
fullname = 0;
file.Seek(currentblock->StartOffset,0);
filedata = new byte[togo+500];
if (uint32 done = file.Read(filedata,togo) != togo){
file.SeekToBegin();
file.Read(filedata + done,togo-done);
}
file.Close();
}
else{
CPartFile* partfile = (CPartFile*)srcfile;
delete[] fullname;
fullname = 0;
partfile->m_hpartfile.Seek(currentblock->StartOffset,0);
filedata = new byte[togo+500];
if (uint32 done = partfile->m_hpartfile.Read(filedata,togo) != togo){
partfile->m_hpartfile.SeekToBegin();
partfile->m_hpartfile.Read(filedata + done,togo-done);
}
}
memcpy(reqfileid,currentblock->FileID,16);
// Maella => -Check for file name extension- fix for lower/upper case in filename
// Remark: - the function strstr() should not be used, because it is case sensitive
// (e.g. "myFile.ZiP" should not be compressed)
// - a better approach would be to add a tag to the class CKnownFile to avoid
// the repetition of the test below (e.g. bool CKnownFile::isCompressionAllowed())
CString ext = CString(srcfile->GetFileName()).Right(4);
if(m_byDataCompVer == 1 &&
ext.CompareNoCase(".zip") != 0 && ext.CompareNoCase(".rar") != 0 &&
// ext.CompareNoCase(".ogg") != 0 && ext.CompareNoCase(".mp3") != 0 &&
ext.CompareNoCase(".ace") != 0 && ext.CompareNoCase(".jpg") != 0){
// Compression is supported by the remote client
CreatePackedPackets(filedata,togo,currentblock);
}
else {
// Remote client doesn't support compression or
// File already compressed. Don't waste CPU time to recompress it.
CreateStandartPackets(filedata,togo,currentblock);
}
// Maella end
// file statistic
srcfile->statistic.AddTransferd(togo);
m_DoneBlocks_list.AddHead(m_BlockRequests_queue.RemoveHead());
delete[] filedata;
filedata = 0;
}
}
catch(CString error){
//OUTPUT_DEBUG_TRACE();
theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_ERR_CLIENTERRORED),GetUserName(),error.GetBuffer());
theApp.uploadqueue->RemoveFromUploadQueue(this);
if (filedata)
delete filedata;
if (fullname)
delete[] fullname;
return false;
}
// theApp.emuledlg->AddDebugLogLine(false,"Debug: Packet done. Size: %i",blockpack->GetLength());
return true;
}
void CUpDownClient::ProcessUpFileStatus(char* packet,uint32 size){
if (m_abyUpPartStatus) {
delete[] m_abyUpPartStatus;
m_abyUpPartStatus = NULL; // added by jicxicmic
}
m_nUpPartCount = 0;
if( size == 16 )
return;
CSafeMemFile* data = new CSafeMemFile((BYTE*)packet,size);
uchar cfilehash[16];
data->Read(cfilehash,16);
CKnownFile* tempreqfile = theApp.sharedfiles->GetFileByID(cfilehash);
data->Read(&m_nUpPartCount,2);
if (!m_nUpPartCount){
m_nUpPartCount = tempreqfile->GetPartCount();
m_abyUpPartStatus = new uint8[m_nUpPartCount];
memset(m_abyUpPartStatus,0,m_nUpPartCount);
}
else{
if (tempreqfile->GetPartCount() != m_nUpPartCount){
delete data; //mf
m_nUpPartCount = 0;
return;
}
m_abyUpPartStatus = new uint8[m_nUpPartCount];
uint16 done = 0;
while (done != m_nUpPartCount){
uint8 toread;
data->Read(&toread,1);
for (sint32 i = 0;i != 8;i++){
m_abyUpPartStatus[done] = ((toread>>i)&1)? 1:0;
// We may want to use this for another feature..
// if (m_abyUpPartStatus[done] && !tempreqfile->IsComplete(done*PARTSIZE,((done+1)*PARTSIZE)-1))
// bPartsNeeded = true;
done++;
if (done == m_nUpPartCount)
break;
}
}
}
theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(this);
delete data;
}
void CUpDownClient::CreateStandartPackets(byte* data,uint32 togo, Requested_Block_Struct* currentblock){
uint32 nPacketSize;
CMemFile memfile((BYTE*)data,togo);
if (togo > 10240)
nPacketSize = togo/(uint32)(togo/10240);
else
nPacketSize = togo;
while (togo){
if (togo < nPacketSize*2)
nPacketSize = togo;
togo -= nPacketSize;
Packet* packet = new Packet(OP_SENDINGPART,nPacketSize+24);
memcpy(&packet->pBuffer[0],reqfileid,16);
uint32 statpos = (currentblock->EndOffset - togo) - nPacketSize;
memcpy(&packet->pBuffer[16],&statpos,4);
uint32 endpos = (currentblock->EndOffset - togo);
memcpy(&packet->pBuffer[20],&endpos,4);
memfile.Read(&packet->pBuffer[24],nPacketSize);
m_BlockSend_queue.AddTail(packet);
}
}
void CUpDownClient::CreatePackedPackets(byte* data,uint32 togo, Requested_Block_Struct* currentblock){
BYTE* output = new BYTE[togo+300];
uLongf newsize = togo+300;
uint16 result = compress2(output,&newsize,data,togo,9);
if (result != Z_OK || togo <= newsize){
delete[] output;
CreateStandartPackets(data,togo,currentblock);
return;
}
m_bUsedComprUp = true;
CMemFile memfile(output,newsize);
togo = newsize;
uint32 nPacketSize;
if (togo > 10240)
nPacketSize = togo/(uint32)(togo/10240);
else
nPacketSize = togo;
while (togo){
if (togo < nPacketSize*2)
nPacketSize = togo;
togo -= nPacketSize;
Packet* packet = new Packet(OP_COMPRESSEDPART,nPacketSize+24,OP_EMULEPROT);
memcpy(&packet->pBuffer[0],reqfileid,16);
uint32 statpos = currentblock->StartOffset;
memcpy(&packet->pBuffer[16],&statpos,4);
memcpy(&packet->pBuffer[20],&newsize,4);
memfile.Read(&packet->pBuffer[24],nPacketSize);
m_BlockSend_queue.AddTail(packet);
}
delete[] output;
}
// Maella => -New bandwidth control-
void CUpDownClient::SplitAndAddPacket(Packet* packet){
// Maella => -MTU Configuration-
const uint32 MaxFragSize = theApp.glob_prefs->GetMTU() - (20 /*IP*/ + 20 /*TCP*/);
// Maella end
if(packet->GetRealPacketSize() < MaxFragSize){ // see CEMSocket::Send
m_BlockSend_queue.AddTail(packet);
}
else {
// Split packet
const uint32 nSize = packet->GetRealPacketSize();
const char* pBuffer = packet->DetachPacket();
delete packet; packet = NULL;
// Average size of splited packet
uint32 numberPacket = (nSize + (MaxFragSize - 1)) / MaxFragSize;
const uint32 sizePacket = nSize / numberPacket;
// Create n packets of the same size (shall improve the ping)
uint32 nPos = 0;
while(numberPacket-- > 0){
uint32 nNewSize = (numberPacket == 0) ? (nSize-nPos) : sizePacket;
char* pBuffer2 = new char[nNewSize];
memcpy(pBuffer2, pBuffer+nPos, nNewSize);
nPos += nNewSize;
m_BlockSend_queue.AddTail(new Packet(pBuffer2, nNewSize, (numberPacket == 0)));
}
delete[] pBuffer;
}
}
// Maella end
void CUpDownClient::AddReqBlock(Requested_Block_Struct* reqblock){
for (POSITION pos = m_DoneBlocks_list.GetHeadPosition();pos != 0;m_DoneBlocks_list.GetNext(pos)){
if (reqblock->StartOffset == m_DoneBlocks_list.GetAt(pos)->StartOffset && reqblock->EndOffset == m_DoneBlocks_list.GetAt(pos)->EndOffset){
delete reqblock;
return;
}
}
for (POSITION pos = m_BlockRequests_queue.GetHeadPosition();pos != 0;m_BlockRequests_queue.GetNext(pos)){
if (reqblock->StartOffset == m_BlockRequests_queue.GetAt(pos)->StartOffset && reqblock->EndOffset == m_BlockRequests_queue.GetAt(pos)->EndOffset){
delete reqblock;
return;
}
}
m_BlockRequests_queue.AddTail(reqblock);
}
// Maella => -New bandwidth control-
uint32 CUpDownClient::SendBlockData(uint32 nMaxAmmount){
uint32 nSentBytes = 0;
uint32 nSentOverallBytes = 0;
if(socket && socket->IsBusy()== false){
if(m_BlockSend_queue.IsEmpty() == TRUE){
if(CreateNextBlockPackage() == false) return 0;
}
// Splitting packets if necessary
// Remark: - don't use 2*MAXFRAGSIZE (see CEMSocket::Send()), otherwise the
// counter m_nMaxSendAllowed will trigged the sending of two TCP packets
// of 1300 (2*1300) at the same time => increase the ping of the application.
if(m_BlockSend_queue.GetHead()->IsSplitted() == false &&
//m_BlockSend_queue.GetHead()->GetRealPacketSize() > MAXFRAGSIZE){theApp.glob_prefs->GetMTU()
m_BlockSend_queue.GetHead()->GetRealPacketSize() > theApp.glob_prefs->GetMTU() - (20 /*IP*/ + 20 /*TCP*/)){
SplitAndAddPacket(m_BlockSend_queue.RemoveHead());
}
// Check if overhead must be compensated
const uint32 overhead = (theApp.glob_prefs->GetCompensateOverhead() == true) ? (20 /*IP*/ + 20 /*TCP*/) : 0;
while((socket->IsBusy() == false) &&
(m_BlockSend_queue.IsEmpty() == FALSE) &&
(nMaxAmmount >= (m_BlockSend_queue.GetHead()->GetRealPacketSize() + overhead))){
Packet* tosend = m_BlockSend_queue.RemoveHead();
uint32 nPacketSize = tosend->GetRealPacketSize();
bool isHead = (tosend->IsSplitted() == false || tosend->IsLastSplitted() == true);
socket->SendPacket(tosend, true, false);
nMaxAmmount -= nPacketSize + overhead; // edonkey header not compensated here
nSentOverallBytes += nPacketSize + overhead; // edonkey header not compensated here
// edonkey header should not be added to the credit
nSentBytes += nPacketSize;
if(isHead == true){
// header+FileId+StartPos+EndPos => 6+24 bytes
nSentBytes = (nSentBytes > 30) ? (nSentBytes - 30) : 0;
}
}
credits->AddUploaded(nSentBytes); // used for credit system
m_nTransferedUp += nSentBytes; // used for credit system (session upload)
AddUploadRate(nSentBytes); // used for datarate measure
theApp.stat_sentBytes += nSentBytes; // used for statistic (Compression is ignored)
}
return nSentOverallBytes;
}
// Maella end
// Maella => -Accurate measure of bandwidth: IP, TCP or UDP, eDonkey protocol, etc-
void CUpDownClient::CompUpDataRate(){
// Remark: This method is called once every second
TransferredData newItem = {m_nUpDatarateMeasure, ::GetTickCount()};
m_nUpDatarateMeasure = 0;
uint32 deltaTime = newItem.timeStamp - m_upHistory_list.GetHead().timeStamp; // [ms]
m_sumUpHistory += newItem.dataLength;
m_sumUpHistory -= m_upHistory_list.RemoveHead().dataLength;
m_upHistory_list.AddTail(newItem);
m_nUpDatarate = (deltaTime > 0) ? (1000 * m_sumUpHistory / deltaTime) : 0; // [bytes/s]
// Check and then refresh GUI
m_displayUpDatarateCounter++;
if(m_displayUpDatarateCounter >= DISPLAY_REFRESH){ // && GetUploadState() == US_UPLOADING){ => already in upload list
m_displayUpDatarateCounter = 0;
theApp.emuledlg->transferwnd.uploadlistctrl.RefreshClient(this);
}
}
// Maella end
void CUpDownClient::FlushSendBlocks(){ // call this when you stop upload, or the socket might be not able to send
bool bBreak = false;
while (!m_BlockSend_queue.IsEmpty() && m_BlockSend_queue.GetHead()->IsSplitted() && socket && socket->IsConnected() && !bBreak ){
Packet* tosend = m_BlockSend_queue.RemoveHead();
bool bBreak = tosend->IsLastSplitted();
theApp.uploadqueue->AddUpDataOverheadOther(tosend->size);
socket->SendPacket(tosend,true,false);
}
}
void CUpDownClient::SendHashsetPacket(char* forfileid){
CKnownFile* file = theApp.sharedfiles->GetFileByID((uchar*)forfileid);
if (!file)
throw GetResString(IDS_ERR_REQ_FNF)+CString(" (SendHashsetPacket)");
CMemFile* data = new CMemFile();
data->Write(file->GetFileHash(),16);
uint16 parts = file->GetHashCount();
data->Write(&parts,2);
for (int i = 0; i != parts; i++)
data->Write(file->GetPartHash(i),16);
Packet* packet = new Packet(data);
packet->opcode = OP_HASHSETANSWER;
delete data;
theApp.uploadqueue->AddUpDataOverheadFileRequest(packet->size);
socket->SendPacket(packet,true,true);
}
void CUpDownClient::ClearUploadBlockRequests(){
FlushSendBlocks();
for (POSITION pos = m_BlockRequests_queue.GetHeadPosition();pos != 0;m_BlockRequests_queue.GetNext(pos))
delete m_BlockRequests_queue.GetAt(pos);
m_BlockRequests_queue.RemoveAll();
for (POSITION pos = m_DoneBlocks_list.GetHeadPosition();pos != 0;m_DoneBlocks_list.GetNext(pos))
delete m_DoneBlocks_list.GetAt(pos);
m_DoneBlocks_list.RemoveAll();
for (POSITION pos = m_BlockSend_queue.GetHeadPosition();pos != 0;m_BlockSend_queue.GetNext(pos))
delete m_BlockSend_queue.GetAt(pos);
m_BlockSend_queue.RemoveAll();
}
void CUpDownClient::SendRankingInfo(){
if (!ExtProtocolAvailable())
return;
uint16 nRank = theApp.uploadqueue->GetWaitingPosition(this);
if (!nRank)
return;
Packet* packet = new Packet(OP_QUEUERANKING,12,OP_EMULEPROT);
memset(packet->pBuffer,0,12);
memcpy(packet->pBuffer+0,&nRank,2);
theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
socket->SendPacket(packet,true,true);
}
void CUpDownClient::SendCommentInfo(CKnownFile *file) {
if (!m_bCommentDirty || file == NULL || !ExtProtocolAvailable() || m_byAcceptCommentVer < 1)
return;
m_bCommentDirty = false;
int8 rating=file->GetFileRate();
CString desc=file->GetFileComment();
if(file->GetFileRate() == 0 && desc.IsEmpty())
return;
CMemFile *data = new CMemFile();
data->Write(&rating,sizeof(rating));
int length=desc.GetLength();
if (length>128) length=128;
data->Write(&length,sizeof(length));
if (length>0) data->Write(desc.GetBuffer(),length);
Packet *packet = new Packet(data,OP_EMULEPROT);
packet->opcode = OP_FILEDESC;
delete data;
theApp.uploadqueue->AddUpDataOverheadOther(packet->size);
socket->SendPacket(packet,true);
}
void CUpDownClient::AddRequestCount(uchar* fileid){
for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;m_RequestedFiles_list.GetNext(pos)){
Requested_File_Struct* cur_struct = m_RequestedFiles_list.GetAt(pos);
if (!memcmp(cur_struct->fileid,fileid,16)){
if (::GetTickCount() - cur_struct->lastasked < MIN_REQUESTTIME && !GetFriendSlot()){
if (GetDownloadState() != DS_DOWNLOADING)
cur_struct->badrequests++;
if (cur_struct->badrequests == BADCLIENTBAN){
Ban();
}
}
else{
if (cur_struct->badrequests)
cur_struct->badrequests--;
}
cur_struct->lastasked = ::GetTickCount();
return;
}
}
Requested_File_Struct* new_struct = new Requested_File_Struct;
memset(new_struct,0,sizeof(Requested_File_Struct));
memcpy(new_struct->fileid,fileid,16);
new_struct->lastasked = ::GetTickCount();
m_RequestedFiles_list.AddHead(new_struct);
}
void CUpDownClient::UnBan(){
m_bBanned = false;
m_dwBanTime = 0;
SetWaitStartTime();
theApp.uploadqueue->UpdateBanCount();
theApp.emuledlg->transferwnd.ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
for (POSITION pos = m_RequestedFiles_list.GetHeadPosition();pos != 0;m_RequestedFiles_list.GetNext(pos)){
Requested_File_Struct* cur_struct = m_RequestedFiles_list.GetAt(pos);
cur_struct->badrequests = 0;
cur_struct->lastasked = 0;
}
// theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(this, true, true);
}
void CUpDownClient::Ban(){
m_bBanned = true;
theApp.uploadqueue->UpdateBanCount();
theApp.emuledlg->transferwnd.ShowQueueCount(theApp.uploadqueue->GetWaitingUserCount());
m_dwBanTime = ::GetTickCount();
theApp.emuledlg->transferwnd.queuelistctrl.RefreshClient(this);
theApp.emuledlg->AddDebugLogLine(false,GetResString(IDS_CLIENTBLOCKED),GetUserName());
}
void CUpDownClient::UDPFileReasked(){
AddAskedCount();
SetLastUpRequest();
uint16 nRank = theApp.uploadqueue->GetWaitingPosition(this);
Packet* response = new Packet(OP_REASKACK,2,OP_EMULEPROT);
memcpy(response->pBuffer,&nRank,2);
theApp.uploadqueue->AddUpDataOverheadFileRequest(response->size);
theApp.clientudp->SendPacket(response,GetIP(),GetUDPPort());
}