📄 listensocket.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 "DebugHelpers.h"
#include "emule.h"
#include "ListenSocket.h"
#include "PeerCacheSocket.h"
#include "opcodes.h"
#include "UpDownClient.h"
#include "ClientList.h"
#include "OtherFunctions.h"
#include "DownloadQueue.h"
#include "Statistics.h"
#include "IPFilter.h"
#include "SharedFileList.h"
#include "PartFile.h"
#include "SafeFile.h"
#include "Packets.h"
#include "UploadQueue.h"
#include "ServerList.h"
#include "Server.h"
#include "Sockets.h"
#include "emuledlg.h"
#include "TransferWnd.h"
#include "ClientListCtrl.h"
#include "ChatWnd.h"
#include "PeerCacheFinder.h"
#include "Exceptions.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// CClientReqSocket
IMPLEMENT_DYNCREATE(CClientReqSocket, CEMSocket)
CClientReqSocket::CClientReqSocket(CUpDownClient* in_client)
{
SetClient(in_client);
theApp.listensocket->AddSocket(this);
ResetTimeOutTimer();
deletethis = false;
deltimer = 0;
}
CClientReqSocket::~CClientReqSocket(){
if (client)
client->socket = 0;
client = 0;
theApp.listensocket->RemoveSocket(this);
DEBUG_ONLY (theApp.clientlist->Debug_SocketDeleted(this));
}
void CClientReqSocket::SetClient(CUpDownClient* pClient)
{
client = pClient;
if (client)
client->socket = this;
}
void CClientReqSocket::ResetTimeOutTimer(){
timeout_timer = ::GetTickCount();
}
UINT CClientReqSocket::GetTimeOut()
{
// PC-TODO
// the PC socket may even already be disconnected and deleted and we still need to keep the
// ed2k socket open because remote client may still be downloading from cache.
if (client && client->IsUploadingToPeerCache() && (client->m_pPCUpSocket == NULL || !client->m_pPCUpSocket->IsConnected()))
{
// we are uploading (or at least allow uploading) but currently no socket
return max(CEMSocket::GetTimeOut(), GetPeerCacheSocketUploadTimeout());
}
else if (client && client->m_pPCUpSocket && client->m_pPCUpSocket->IsConnected())
{
// we have an uploading PC socket, but that socket is not used (nor can it be closed)
return max(CEMSocket::GetTimeOut(), client->m_pPCUpSocket->GetTimeOut());
}
else if (client && client->m_pPCDownSocket && client->m_pPCDownSocket->IsConnected())
{
// we have a downloading PC socket
return max(CEMSocket::GetTimeOut(), client->m_pPCDownSocket->GetTimeOut());
}
else
return CEMSocket::GetTimeOut();
}
bool CClientReqSocket::CheckTimeOut()
{
UINT uTimeout = GetTimeOut();
if(client)
{
if (client->GetKadState() == KS_CONNECTED_BUDDY)
return false;
if (client->GetChatState()!=MS_NONE)
uTimeout += CONNECTION_TIMEOUT;
}
if (::GetTickCount() - timeout_timer > uTimeout){
timeout_timer = ::GetTickCount();
Disconnect(_T("Timeout"));
return true;
}
return false;
}
void CClientReqSocket::OnClose(int nErrorCode){
ASSERT (theApp.listensocket->IsValidSocket(this));
CEMSocket::OnClose(nErrorCode);
LPCTSTR pszReason;
CString* pstrReason = NULL;
if (nErrorCode == 0)
pszReason = _T("Close");
else if (thePrefs.GetVerbose()){
pstrReason = new CString;
*pstrReason = GetErrorMessage(nErrorCode, 1);
pszReason = *pstrReason;
}
else
pszReason = NULL;
Disconnect(pszReason);
delete pstrReason;
}
void CClientReqSocket::Disconnect(LPCTSTR pszReason){
AsyncSelect(0);
byConnected = ES_DISCONNECTED;
if (!client)
Safe_Delete();
else
if(client->Disconnected(pszReason, true)){
CUpDownClient* temp = client;
client->socket = NULL;
client = NULL;
delete temp;
Safe_Delete();
}
else{
client = NULL;
Safe_Delete();
}
};
void CClientReqSocket::Delete_Timed(){
// it seems that MFC Sockets call socketfunctions after they are deleted, even if the socket is closed
// and select(0) is set. So we need to wait some time to make sure this doesn't happens
if (::GetTickCount() - deltimer > 10000)
delete this;
}
void CClientReqSocket::Safe_Delete()
{
ASSERT (theApp.listensocket->IsValidSocket(this));
AsyncSelect(0);
deltimer = ::GetTickCount();
if (m_SocketData.hSocket != INVALID_SOCKET) // deadlake PROXYSUPPORT - changed to AsyncSocketEx
ShutDown(SD_BOTH);
if (client)
client->socket = 0;
client = 0;
byConnected = ES_DISCONNECTED;
deletethis = true;
}
bool CClientReqSocket::ProcessPacket(char* packet, uint32 size, UINT opcode)
{
try
{
try
{
if (!client && opcode != OP_HELLO)
{
theStats.AddDownDataOverheadOther(size);
throw GetResString(IDS_ERR_NOHELLO);
}
else if (client && opcode != OP_HELLO && opcode != OP_HELLOANSWER)
client->CheckHandshakeFinished(OP_EDONKEYPROT, opcode);
switch(opcode)
{
case OP_HELLOANSWER:
{
theStats.AddDownDataOverheadOther(size);
client->ProcessHelloAnswer(packet,size);
if (thePrefs.GetDebugClientTCPLevel() > 0){
DebugRecv("OP_HelloAnswer", client);
Debug(_T(" %s\n"), client->DbgGetHelloInfo());
}
// start secure identification, if
// - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
// - we have received eMule-OP_HELLOANSWER (new eMule)
if (client->GetInfoPacketsReceived() == IP_BOTH)
client->InfoPacketsReceived();
if (client)
{
client->ConnectionEstablished();
theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(client);
}
break;
}
case OP_HELLO:
{
theStats.AddDownDataOverheadOther(size);
bool bNewClient = !client;
if (bNewClient)
{
// create new client to save standart informations
client = new CUpDownClient(this);
}
bool bIsMuleHello = false;
try
{
bIsMuleHello = client->ProcessHelloPacket(packet,size);
}
catch(...)
{
if (bNewClient)
{
// Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
delete client;
client = NULL;
}
throw;
}
if (thePrefs.GetDebugClientTCPLevel() > 0){
DebugRecv("OP_Hello", client);
Debug(_T(" %s\n"), client->DbgGetHelloInfo());
}
// now we check if we know this client already. if yes this socket will
// be attached to the known client, the new client will be deleted
// and the var. "client" will point to the known client.
// if not we keep our new-constructed client ;)
if (theApp.clientlist->AttachToAlreadyKnown(&client,this))
{
// update the old client informations
bIsMuleHello = client->ProcessHelloPacket(packet,size);
}
else
{
theApp.clientlist->AddClient(client);
client->SetCommentDirty();
}
theApp.emuledlg->transferwnd->clientlistctrl.RefreshClient(client);
// send a response packet with standart informations
if (client->GetHashType() == SO_EMULE && !bIsMuleHello)
client->SendMuleInfoPacket(false);
client->SendHelloAnswer();
if (client)
client->ConnectionEstablished();
// start secure identification, if
// - we have received eMule-OP_HELLO (new eMule)
if (client->GetInfoPacketsReceived() == IP_BOTH)
client->InfoPacketsReceived();
break;
}
case OP_REQUESTFILENAME:
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugRecv("OP_FileRequest", client, packet);
theStats.AddDownDataOverheadFileRequest(size);
// IP banned, no answer for this request
if (client->IsBanned()){
client->CheckFailedFileIdReqs(NULL);
break;
}
if (size >= 16)
{
if (!client->GetWaitStartTime())
client->SetWaitStartTime();
CSafeMemFile data_in((BYTE*)packet,size);
uchar reqfilehash[16];
data_in.ReadHash16(reqfilehash);
CKnownFile* reqfile;
if ( (reqfile = theApp.sharedfiles->GetFileByID(reqfilehash)) == NULL ){
if ( !((reqfile = theApp.downloadqueue->GetFileByID(reqfilehash)) != NULL
&& reqfile->GetFileSize() > PARTSIZE ) )
{
client->CheckFailedFileIdReqs(reqfilehash);
break;
}
}
// if we are downloading this file, this could be a new source
// no passive adding of files with only one part
if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE)
{
if (thePrefs.GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount())
theApp.downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, client);
}
// check to see if this is a new file they are asking for
if (md4cmp(client->GetUploadFileID(), reqfilehash) != 0)
client->SetCommentDirty();
client->SetUploadFileID(reqfile);
client->ProcessExtendedInfo(&data_in, reqfile);
// send filename etc
CSafeMemFile data_out(128);
data_out.WriteHash16(reqfile->GetFileHash());
data_out.WriteString(reqfile->GetFileName());
Packet* packet = new Packet(&data_out);
packet->opcode = OP_REQFILENAMEANSWER;
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__FileReqAnswer", client, (char*)reqfile->GetFileHash());
theStats.AddUpDataOverheadFileRequest(packet->size);
SendPacket(packet, true);
client->SendCommentInfo(reqfile);
break;
}
throw GetResString(IDS_ERR_WRONGPACKAGESIZE);
break;
}
case OP_SETREQFILEID:
{
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugRecv("OP_SetReqFileID", client, (size == 16) ? packet : NULL);
theStats.AddDownDataOverheadFileRequest(size);
// IP banned, no answer for this request
if (client->IsBanned()){
client->CheckFailedFileIdReqs(NULL);
break;
}
if (size == 16){
if (!client->GetWaitStartTime())
client->SetWaitStartTime();
CKnownFile* reqfile;
if ( (reqfile = theApp.sharedfiles->GetFileByID((uchar*)packet)) == NULL ){
if ( !((reqfile = theApp.downloadqueue->GetFileByID((uchar*)packet)) != NULL
&& reqfile->GetFileSize() > PARTSIZE ) )
{
// send file request no such file packet (0x48)
if (thePrefs.GetDebugClientTCPLevel() > 0)
DebugSend("OP__FileReqAnsNoFil", client, packet);
Packet* replypacket = new Packet(OP_FILEREQANSNOFIL, 16);
md4cpy(replypacket->pBuffer, packet);
theStats.AddUpDataOverheadFileRequest(replypacket->size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -