📄 udpsocket.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 "UDPSocket.h"
#include "SearchList.h"
#include "DownloadQueue.h"
#include "Statistics.h"
#include "Server.h"
#include "Preferences.h"
#include "OtherFunctions.h"
#include "ServerList.h"
#include "Opcodes.h"
#include "SafeFile.h"
#include "PartFile.h"
#include "Packets.h"
#include "IPFilter.h"
#include "emuledlg.h"
#include "ServerWnd.h"
#include "SearchDlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
#pragma pack(1)
struct SServerUDPPacket
{
uint8* packet;
int size;
uint32 dwIP;
uint16 nPort;
};
#pragma pack()
CUDPSocketWnd::CUDPSocketWnd(){
}
BEGIN_MESSAGE_MAP(CUDPSocketWnd, CWnd)
ON_MESSAGE(WM_DNSLOOKUPDONE, OnDNSLookupDone)
END_MESSAGE_MAP()
LRESULT CUDPSocketWnd::OnDNSLookupDone(WPARAM wParam,LPARAM lParam){
m_pOwner->DnsLookupDone(wParam,lParam);
return true;
};
CUDPSocket::CUDPSocket(){
m_hWndResolveMessage = NULL;
m_sendbuffer = NULL;
m_cur_server = NULL;
m_DnsTaskHandle = NULL;
m_bWouldBlock = false;
}
CUDPSocket::~CUDPSocket(){
theApp.uploadBandwidthThrottler->RemoveFromAllQueues(this); // ZZ:UploadBandWithThrottler (UDP)
delete m_cur_server;
delete[] m_sendbuffer;
POSITION pos = controlpacket_queue.GetHeadPosition();
while (pos){
SServerUDPPacket* p = controlpacket_queue.GetNext(pos);
delete[] p->packet;
delete p;
}
m_udpwnd.DestroyWindow();
}
bool CUDPSocket::Create(){
if (thePrefs.GetServerUDPPort()){
VERIFY( m_udpwnd.CreateEx(0, AfxRegisterWndClass(0),_T("Emule Socket Wnd"),WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL));
m_hWndResolveMessage = m_udpwnd.m_hWnd;
m_udpwnd.m_pOwner = this;
if (!CAsyncSocket::Create(thePrefs.GetServerUDPPort()==0xFFFF ? 0 : thePrefs.GetServerUDPPort(), SOCK_DGRAM, FD_READ | FD_WRITE)){
AddLogLine(true, _T("Error: Server UDP socket: Failed to create server UDP socket on port - %s"), GetErrorMessage(GetLastError()));
return false;
}
//return true;
// VeryCD版
if(thePrefs.GetUPnPNat()){
CString client;
UINT port;
CUPnPNat::UPNPNAT_MAPPING mapping;
GetSockName(client, port);
mapping.internalPort = mapping.externalPort = port;
mapping.protocol = CUPnPNat::UNAT_UDP;
mapping.description = "Server UDP Port";
theApp.AddUPnPNatPort(&mapping, thePrefs.GetUPnPNatTryRandom());
}
return true;
// VeryCD版
}
return false;
}
void CUDPSocket::OnReceive(int nErrorCode){
if (nErrorCode){
if (thePrefs.GetVerbose())
AddDebugLogLine(false, _T("Error: Server UDP socket: Receive failed - %s"), GetErrorMessage(nErrorCode, 1));
}
uint8 buffer[5000];
SOCKADDR_IN sockAddr = {0};
int iSockAddrLen = sizeof sockAddr;
int length = ReceiveFrom(buffer, sizeof buffer, (SOCKADDR*)&sockAddr, &iSockAddrLen);
if (length != SOCKET_ERROR)
{
if (buffer[0] == OP_EDONKEYPROT)
ProcessPacket(buffer+2, length-2, buffer[1], sockAddr.sin_addr.S_un.S_addr, ntohs(sockAddr.sin_port));
else if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T("***NOTE: ServerUDPMessage from %s:%u - Unknown protocol 0x%02x\n"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port)-4, buffer[0]);
}
else
{
DWORD dwError = WSAGetLastError();
if (thePrefs.GetVerbose())
{
// 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 server running there.
//
CString strServerInfo;
if (iSockAddrLen > 0 && sockAddr.sin_addr.S_un.S_addr != 0 && sockAddr.sin_addr.S_un.S_addr != INADDR_NONE)
strServerInfo.Format(_T(" from %s:%u"), ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port));
AddDebugLogLine(false, _T("Error: Server UDP socket, failed to receive data%s: %s"), strServerInfo, GetErrorMessage(dwError, 1));
}
if (dwError == WSAECONNRESET)
{
CServer* pServer = theApp.serverlist->GetServerByAddress(ipstr(sockAddr.sin_addr), ntohs(sockAddr.sin_port)-4);
if (pServer && pServer->GetChallenge()==0)
pServer->AddFailedCount();
}
}
}
bool CUDPSocket::ProcessPacket(uint8* packet, UINT size, UINT opcode, uint32 nIP, uint16 nUDPPort){
try{
theStats.AddDownDataOverheadServer(size);
CServer* update = theApp.serverlist->GetServerByAddress(ipstr(nIP), nUDPPort-4);
if( update ){
update->ResetFailedCount();
theApp.emuledlg->serverwnd->serverlistctrl.RefreshServer( update );
}
switch(opcode){
case OP_GLOBSEARCHRES:{
CSafeMemFile data(packet, size);
// process all search result packets
int iLeft;
int iPacket = 1;
do{
if (thePrefs.GetDebugServerUDPLevel() > 0){
uint32 nClientID = *((uint32*)(packet+16));
uint16 nClientPort = *((uint16*)(packet+20));
Debug(_T("ServerUDPMessage from %s:%u - OP_GlobSearchResult(%u); %s\n"), ipstr(nIP), nUDPPort-4, iPacket++, DbgGetFileInfo((uchar*)packet), DbgGetClientID(nClientID), nClientPort);
}
uint16 uResultCount = theApp.searchlist->ProcessUDPSearchanswer(data, true/*update->GetUnicodeSupport()*/, nIP, nUDPPort-4);
theApp.emuledlg->searchwnd->AddUDPResult(uResultCount);
// check if there is another source packet
iLeft = (int)(data.GetLength() - data.GetPosition());
if (iLeft >= 2){
uint8 protocol = data.ReadUInt8();
iLeft--;
if (protocol != OP_EDONKEYPROT){
data.Seek(-1, SEEK_CUR);
iLeft += 1;
break;
}
uint8 opcode = data.ReadUInt8();
iLeft--;
if (opcode != OP_GLOBSEARCHRES){
data.Seek(-2, SEEK_CUR);
iLeft += 2;
break;
}
}
}
while (iLeft > 0);
if (iLeft > 0 && thePrefs.GetDebugServerUDPLevel() > 0){
Debug(_T("OP_GlobSearchResult contains %d additionl bytes\n"), iLeft);
if (thePrefs.GetDebugServerUDPLevel() > 1)
DebugHexDump(data);
}
break;
}
case OP_GLOBFOUNDSOURCES:{
CSafeMemFile data(packet, size);
// process all source packets
int iLeft;
int iPacket = 1;
do{
uchar fileid[16];
data.ReadHash16(fileid);
if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T("ServerUDPMessage from %s:%u - OP_GlobFoundSources(%u); %s\n"), ipstr(nIP), nUDPPort-4, iPacket++, DbgGetFileInfo(fileid));
if (CPartFile* file = theApp.downloadqueue->GetFileByID(fileid))
file->AddSources(&data, nIP, nUDPPort-4);
else{
// skip sources for that file
UINT count = data.ReadUInt8();
data.Seek(count*(4+2), SEEK_SET);
}
// check if there is another source packet
iLeft = (int)(data.GetLength() - data.GetPosition());
if (iLeft >= 2){
uint8 protocol = data.ReadUInt8();
iLeft--;
if (protocol != OP_EDONKEYPROT){
data.Seek(-1, SEEK_CUR);
iLeft += 1;
break;
}
uint8 opcode = data.ReadUInt8();
iLeft--;
if (opcode != OP_GLOBFOUNDSOURCES){
data.Seek(-2, SEEK_CUR);
iLeft += 2;
break;
}
}
}
while (iLeft > 0);
if (iLeft > 0 && thePrefs.GetDebugServerUDPLevel() > 0){
Debug(_T("OP_GlobFoundSources contains %d additional bytes\n"), iLeft);
if (thePrefs.GetDebugServerUDPLevel() > 1)
DebugHexDump(data);
}
break;
}
case OP_GLOBSERVSTATRES:{
if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T("ServerUDPMessage from %s:%u - OP_GlobServStatRes\n"), ipstr(nIP), nUDPPort-4);
if( size < 12 || update == NULL )
return true;
#define get_uint32(p) *((uint32*)(p))
uint32 challenge = get_uint32(packet);
if (challenge != update->GetChallenge()){
if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T("***NOTE: Received unexpected challenge %08x (waiting on packet with challenge %08x)\n"), challenge, update->GetChallenge());
return true;
}
update->SetChallenge(0);
uint32 cur_user = get_uint32(packet+4);
uint32 cur_files = get_uint32(packet+8);
uint32 cur_maxusers = 0;
uint32 cur_softfiles = 0;
uint32 cur_hardfiles = 0;
uint32 uUDPFlags = 0;
uint32 uLowIDUsers = 0;
if( size >= 16 ){
cur_maxusers = get_uint32(packet+12);
}
if( size >= 24 ){
cur_softfiles = get_uint32(packet+16);
cur_hardfiles = get_uint32(packet+20);
}
if( size >= 28 ){
uUDPFlags = get_uint32(packet+24);
if (thePrefs.GetDebugServerUDPLevel() > 0){
CString strInfo;
strInfo.AppendFormat(_T(" UDP Flags=0x%08x"), uUDPFlags);
const DWORD dwKnownBits = SRV_UDPFLG_EXT_GETSOURCES | SRV_UDPFLG_EXT_GETFILES;
if (uUDPFlags & ~dwKnownBits)
strInfo.AppendFormat(_T(" ***UnkBits=0x%08x"), uUDPFlags & ~dwKnownBits);
if (uUDPFlags & SRV_UDPFLG_EXT_GETSOURCES)
strInfo.AppendFormat(_T(" ExtGetSources=1"));
if (uUDPFlags & SRV_UDPFLG_EXT_GETFILES)
strInfo.AppendFormat(_T(" ExtGetFiles=1"));
Debug(_T("%s\n"), strInfo);
}
}
if( size >= 32 ){
uLowIDUsers = get_uint32(packet+28);
if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T(" LowID users=%u\n"), uLowIDUsers);
}
if (thePrefs.GetDebugServerUDPLevel() > 0){
if( size > 32 ){
Debug(_T("***NOTE: ServerUDPMessage from %s:%u - OP_GlobServStatRes: ***AddData: %s\n"), ipstr(nIP), nUDPPort-4, DbgGetHexDump(packet+24, size-24));
}
}
if( update ){
update->SetPing( ::GetTickCount() - update->GetLastPinged() );
update->SetUserCount( cur_user );
update->SetFileCount( cur_files );
update->SetMaxUsers( cur_maxusers );
update->SetSoftFiles( cur_softfiles );
update->SetHardFiles( cur_hardfiles );
// if the received UDP flags do not match any already stored UDP flags,
// reset the server version string because the version (which was determined by last connecting to
// that server) is most likely not accurat any longer.
// this may also give 'false' results because we don't know the UDP flags when connecting to a server
// with TCP.
//if (update->GetUDPFlags() != uUDPFlags)
// update->SetVersion(_T(""));
update->SetUDPFlags( uUDPFlags );
update->SetLowIDUsers( uLowIDUsers );
theApp.emuledlg->serverwnd->serverlistctrl.RefreshServer( update );
}
#undef get_uint32
break;
}
case OP_SERVER_DESC_RES:{
if (thePrefs.GetDebugServerUDPLevel() > 0)
Debug(_T("ServerUDPMessage from %s:%u - OP_ServerDescRes\n"), ipstr(nIP), nUDPPort-4);
if (!update)
return true;
// old packet: <name_len 2><name name_len><desc_len 2 desc_en>
// new packet: <challenge 4><taglist>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -