📄 clientudpsocket.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 "emule.h"
#include "ClientUDPSocket.h"
#include "Packets.h"
#include "DownloadQueue.h"
#include "Statistics.h"
#include "PartFile.h"
#include "SharedFileList.h"
#include "UploadQueue.h"
#include "UpDownClient.h"
#include "Preferences.h"
#include "OtherFunctions.h"
#include "SafeFile.h"
#include "ClientList.h"
#include "Listensocket.h"
#include <zlib/zlib.h>
#include "kademlia/kademlia/Kademlia.h"
#include "kademlia/net/KademliaUDPListener.h"
#include "kademlia/io/IOException.h"
#include "IPFilter.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
// CClientUDPSocket
CClientUDPSocket::CClientUDPSocket()
{
m_bWouldBlock = false;
m_port=0;
}
CClientUDPSocket::~CClientUDPSocket()
{
theApp.uploadBandwidthThrottler->RemoveFromAllQueues(this); // ZZ:UploadBandWithThrottler (UDP)
POSITION pos = controlpacket_queue.GetHeadPosition();
while (pos){
UDPPack* p = controlpacket_queue.GetNext(pos);
delete p->packet;
delete p;
}
}
void CClientUDPSocket::OnReceive(int nErrorCode)
{
if (nErrorCode)
{
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Error: Client UDP socket, error on receive event: %s"), GetErrorMessage(nErrorCode, 1));
}
BYTE buffer[5000];
SOCKADDR_IN sockAddr = {0};
int iSockAddrLen = sizeof sockAddr;
int length = ReceiveFrom(buffer, sizeof buffer, (SOCKADDR*)&sockAddr, &iSockAddrLen);
if (length >= 1 && !(theApp.ipfilter->IsFiltered(sockAddr.sin_addr.S_un.S_addr) || theApp.clientlist->IsBannedClient(sockAddr.sin_addr.S_un.S_addr)))
{
CString strError;
try
{
switch (buffer[0])
{
case OP_EMULEPROT:
{
if (length >= 2)
ProcessPacket(buffer+2, length-2, buffer[1], sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
else
throw CString(_T("Packet too short"));
break;
}
case OP_KADEMLIAPACKEDPROT:
{
theStats.AddDownDataOverheadKad(length);
if (length >= 2)
{
uint32 nNewSize = length*10+300;
byte* unpack = new byte[nNewSize];
uLongf unpackedsize = nNewSize-2;
uint16 result = uncompress(unpack+2, &unpackedsize, buffer+2, length-2);
if (result == Z_OK)
{
unpack[0] = OP_KADEMLIAHEADER;
unpack[1] = buffer[1];
try
{
Kademlia::CKademlia::processPacket(unpack, unpackedsize+2, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port));
}
catch(...)
{
delete[] unpack;
throw;
}
}
else
{
delete[] unpack;
throw CString(_T("Failed to uncompress Kademlia packet"));
}
delete[] unpack;
}
else
throw CString(_T("Packet too short"));
break;
}
case OP_KADEMLIAHEADER:
{
theStats.AddDownDataOverheadKad(length);
if (length >= 2) {
Kademlia::CKademlia::processPacket(buffer, length, ntohl(sockAddr.sin_addr.S_un.S_addr), ntohs(sockAddr.sin_port));
}
else
throw CString(_T("Packet too short"));
break;
}
default:
{
CString strError;
strError.Format(_T("Unknown protocol %02x"), buffer[0]);
throw strError;
}
}
}
catch(CFileException* error)
{
error->Delete();
strError = _T("Invalid packet received");
}
catch(CMemoryException* error)
{
error->Delete();
strError = _T("Memory exception");
}
catch(CString error)
{
strError = error;
}
catch(Kademlia::CIOException* error)
{
error->Delete();
strError = _T("Invalid packet received");
}
catch(...)
{
strError = _T("Unknown exception");
ASSERT(0);
}
if (thePrefs.GetVerbose() && !strError.IsEmpty())
{
CString strClientInfo;
CUpDownClient* client;
if (buffer[0] == OP_EMULEPROT)
client = theApp.clientlist->FindClientByIP_UDP(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
else
client = theApp.clientlist->FindClientByIP_KadPort(sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
if (client)
strClientInfo = client->DbgGetClientInfo();
else
strClientInfo.Format(_T("%s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port));
AddDebugLogLine(false, _T("Client UDP socket: prot=%02x opcode=%02x %s: %s"), buffer[0], buffer[1], strError, strClientInfo);
}
}
else if (length == SOCKET_ERROR)
{
if (thePrefs.GetVerbose())
{
DWORD dwError = WSAGetLastError();
if (dwError == WSAECONNRESET)
{
// Depending on local and remote OS and depending on used local (remote?) router we may receive
// WSAECONNRESET errors. According some KB articels, this is a special way of winsock to report
// that a sent UDP packet was not received by the remote host because it was not listening on
// the specified port -> no eMule running there.
//
// TODO: So, actually we should to something with this information and drop the related Kad node
// or eMule client...
;
}
else
{
CString strClientInfo;
if (iSockAddrLen > 0 && sockAddr.sin_addr.S_un.S_addr != 0 && sockAddr.sin_addr.S_un.S_addr != INADDR_NONE)
strClientInfo.Format(_T(" from %s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port));
AddDebugLogLine(false, _T("Error: Client UDP socket, failed to receive data%s: %s"), strClientInfo, GetErrorMessage(dwError, 1));
}
}
}
}
bool CClientUDPSocket::ProcessPacket(BYTE* packet, uint16 size, uint8 opcode, uint32 ip, uint16 port)
{
switch(opcode)
{
case OP_REASKCALLBACKUDP:
{
theStats.AddDownDataOverheadOther(size);
CUpDownClient* buddy = theApp.clientlist->GetBuddy();
if( buddy )
{
if( size < 17 || buddy->socket == NULL )
break;
//AddDebugLogLine(false, _T("Found buddy in OP_REASKCALLBACKUDP"));
uchar check[16];
memcpy(&check, packet, 16);
if( !memcmp(&check, buddy->GetBuddyID(), 16) )
{
//AddDebugLogLine(false, _T("Match Hash - buddy in OP_REASKCALLBACKUDP"));
memcpy(packet+10, &ip, 4);
memcpy(packet+14, &port, 2);
Packet* response = new Packet(OP_EMULEPROT);
response->opcode = OP_REASKCALLBACKTCP;
response->pBuffer = new char[size];
memcpy(response->pBuffer, packet+10, size-10);
response->size = size-10;
buddy->socket->SendPacket(response);
}
// else
// AddDebugLogLine(false, _T("No Matched Hash - buddy in OP_REASKCALLBACKUDP"));
}
break;
}
case OP_REASKFILEPING:
{
theStats.AddDownDataOverheadFileRequest(size);
CSafeMemFile data_in(packet, size);
uchar reqfilehash[16];
data_in.ReadHash16(reqfilehash);
CKnownFile* reqfile = theApp.sharedfiles->GetFileByID(reqfilehash);
if (!reqfile)
{
if (thePrefs.GetDebugClientUDPLevel() > 0)
{
DebugRecv("OP_ReaskFilePing", NULL, (char*)reqfilehash, ip);
DebugSend("OP__FileNotFound", NULL);
}
Packet* response = new Packet(OP_FILENOTFOUND,0,OP_EMULEPROT);
theStats.AddUpDataOverheadFileRequest(response->size);
SendPacket(response, ip, port);
break;
}
CUpDownClient* sender = theApp.uploadqueue->GetWaitingClientByIP_UDP(ip, port);
if (sender)
{
if (thePrefs.GetDebugClientUDPLevel() > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -