📄 edclient.cpp
字号:
if ( pPacket->GetRemaining() < sizeof(GUID) + 6 + 4 + 6 )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
GGUID pGUID;
pPacket->Read( &pGUID, sizeof(GUID) );
/*
if ( m_bGUID )
{
if ( pGUID != m_pGUID )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_WRONG_GUID, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
}
*/
m_bGUID = TRUE;
m_pGUID = pGUID;
m_nClientID = pPacket->ReadLongLE();
m_pHost.sin_port = htons( pPacket->ReadShortLE() );
DWORD nCount = pPacket->ReadLongLE();
while ( nCount-- > 0 && pPacket->GetRemaining() > 0 )
{
CEDTag pTag;
if ( ! pTag.Read( pPacket ) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
if ( pTag.m_nKey == ED2K_CT_NAME && pTag.m_nType == ED2K_TAG_STRING )
{
m_sNick = pTag.m_sValue;
}
else if ( pTag.m_nKey == ED2K_CT_VERSION && pTag.m_nType == ED2K_TAG_INT )
{
m_nVersion = pTag.m_nValue;
}
else if ( pTag.m_nKey == ED2K_CT_PORT && pTag.m_nType == ED2K_TAG_INT )
{
m_pHost.sin_port = htons( (WORD)pTag.m_nValue );
}
}
if ( pPacket->GetRemaining() < 6 )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
m_pServer.sin_addr.S_un.S_addr = pPacket->ReadLongLE();
m_pServer.sin_port = htons( pPacket->ReadShortLE() );
if ( Settings.eDonkey.LearnNewServers && ! Network.IsFirewalledAddress( &m_pServer.sin_addr ) )
{
HostCache.eDonkey.Add( &m_pServer.sin_addr, htons( m_pServer.sin_port ) );
}
DeriveVersion();
if ( pPacket->m_nType == ED2K_C2C_HELLO )
{
if ( m_bEmule ) SendEmuleInfo( ED2K_C2C_EMULEINFO );
SendHello( ED2K_C2C_HELLOANSWER );
}
if ( m_bLogin )
return TRUE;
else
return OnLoggedIn();
}
//////////////////////////////////////////////////////////////////////
// CEDClient EMULE INFO packet exchange
void CEDClient::SendEmuleInfo(BYTE nType)
{
CEDPacket* pPacket = CEDPacket::New( nType, ED2K_PROTOCOL_EMULE );
// BYTE nVersion = ( theApp.m_nVersion[0] << 4 ) + ( theApp.m_nVersion[1] & 7 );
pPacket->WriteByte( 0x30 ); // eMule version
pPacket->WriteByte( 0x01 ); // eMule protocol
pPacket->WriteLongLE( Settings.eDonkey.ExtendedRequest ? 6 : 5 ); // Tags
CEDTag( ED2K_ET_COMPATIBLECLIENT, 4 ).Write( pPacket );
CEDTag( ED2K_ET_COMPRESSION, 1 ).Write( pPacket );
CEDTag( ED2K_ET_SOURCEEXCHANGE, 2 ).Write( pPacket );
if ( Settings.eDonkey.ExtendedRequest ) CEDTag( ED2K_ET_EXTENDEDREQUEST, 1 ).Write( pPacket );
CEDTag( ED2K_ET_UDPVER, 2 ).Write( pPacket );
CEDTag( ED2K_ET_UDPPORT, htons( Network.m_pHost.sin_port ) ).Write( pPacket );
// CEDTag( ED2K_ET_COMMENTS, 1 ).Write( pPacket );
Send( pPacket );
}
BOOL CEDClient::OnEmuleInfo(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < 5 )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
m_nEmVersion = pPacket->ReadByte();
BYTE nProtocol = pPacket->ReadByte();
if ( nProtocol != 1 ) return TRUE;
if ( m_nEmVersion > 0x22 && m_nEmVersion < 0x25 ) m_bEmSources = 1;
if ( m_nEmVersion == 0x24 ) m_bEmComments = 1;
DWORD nCount = pPacket->ReadLongLE();
while ( nCount-- > 0 && pPacket->GetRemaining() > 0 )
{
CEDTag pTag;
if ( ! pTag.Read( pPacket ) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_HANDSHAKE_FAIL, (LPCTSTR)m_sAddress );
Close();
return FALSE;
}
if ( pTag.m_nType != ED2K_TAG_INT ) continue;
switch ( pTag.m_nKey )
{
case ED2K_ET_SOURCEEXCHANGE:
m_bEmSources = pTag.m_nValue;
break;
case ED2K_ET_COMMENTS:
m_bEmComments = pTag.m_nValue;
break;
case ED2K_ET_EXTENDEDREQUEST:
m_bEmRequest = pTag.m_nValue;
break;
case ED2K_ET_COMPRESSION:
m_bEmDeflate = pTag.m_nValue;
break;
case ED2K_ET_UDPPORT:
m_nUDP = (WORD)pTag.m_nValue;
break;
case ED2K_ET_COMPATIBLECLIENT:
m_nEmCompatible = pTag.m_nValue;
break;
}
}
m_bEmule = TRUE;
if ( pPacket->m_nType == ED2K_C2C_EMULEINFO ) SendEmuleInfo( ED2K_C2C_EMULEINFOANSWER );
DeriveVersion();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient client version
void CEDClient::DeriveVersion()
{
if ( m_pGUID.n[5] == 13 && m_pGUID.n[14] == 110 )
{
m_bEmule = TRUE;
m_sUserAgent.Format( _T("eMule v%i"), m_nVersion );
}
else if ( m_pGUID.n[5] == 14 && m_pGUID.n[14] == 111 )
{
m_bEmule = TRUE;
m_sUserAgent.Format( _T("eMule v%i"), m_nVersion );
}
else if ( m_pGUID.n[5] == 'M' && m_pGUID.n[14] == 'L' )
{
m_sUserAgent.Format( _T("mlDonkey v%i"), m_nVersion );
}
else
{
m_sUserAgent.Format( _T("eDonkey v1.%i"), m_nVersion - 1000 );
}
if ( m_bEmule && m_nEmVersion > 0 )
{
switch ( m_nEmCompatible )
{
case 0:
m_sUserAgent.Format( _T("eMule v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
break;
case 1:
m_sUserAgent.Format( _T("cDonkey v%i.%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
break;
case 4:
m_sUserAgent.Format( _T("Shareaza"), m_nEmVersion >> 4, m_nEmVersion & 15 );
break;
default:
m_sUserAgent.Format( _T("eMule/c v0.%i%i"), m_nEmVersion >> 4, m_nEmVersion & 15 );
break;
}
}
}
//////////////////////////////////////////////////////////////////////
// CEDClient FILE REQUEST handler
BOOL CEDClient::OnFileRequest(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < sizeof(MD4) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
return TRUE;
}
CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILEREQANSWER );
pPacket->Read( &m_pUpMD4, sizeof(MD4) );
pReply->Write( &m_pUpMD4, sizeof(MD4) );
m_bUpMD4 = TRUE;
if ( CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( &m_pUpMD4, TRUE, TRUE, TRUE ) )
{
pReply->WriteEDString( pFile->m_sName );
Library.Unlock();
Send( pReply );
return TRUE;
}
else if ( CDownload* pDownload = Downloads.FindByED2K( &m_pUpMD4, TRUE ) )
{
pReply->WriteEDString( pDownload->m_sRemoteName );
Send( pReply );
return TRUE;
}
pReply->m_nType = ED2K_C2C_FILENOTFOUND;
Send( pReply );
theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress,
(LPCTSTR)CED2K::HashToString( &m_pUpMD4, TRUE ) );
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient file status request
BOOL CEDClient::OnFileStatusRequest(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < sizeof(MD4) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
return TRUE;
}
CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILESTATUS );
pPacket->Read( &m_pUpMD4, sizeof(MD4) );
pReply->Write( &m_pUpMD4, sizeof(MD4) );
m_bUpMD4 = TRUE;
if ( CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( &m_pUpMD4, TRUE, TRUE, TRUE ) )
{
pReply->WriteShortLE( 0 );
pReply->WriteByte( 0 );
m_nUpSize = pFile->GetSize();
if ( ! CEDPacket::IsLowID( m_nClientID ) )
pFile->AddAlternateSource( GetSourceURL() );
Library.Unlock();
Send( pReply );
return TRUE;
}
else if ( CDownload* pDownload = Downloads.FindByED2K( &m_pUpMD4, TRUE ) )
{
WritePartStatus( pReply, pDownload );
m_nUpSize = pDownload->m_nSize;
pDownload->AddSourceED2K( m_nClientID, htons( m_pHost.sin_port ),
m_pServer.sin_addr.S_un.S_addr, htons( m_pServer.sin_port ), &m_pGUID );
Send( pReply );
return TRUE;
}
m_bUpMD4 = FALSE;
pReply->m_nType = ED2K_C2C_FILENOTFOUND;
Send( pReply );
theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress,
(LPCTSTR)CED2K::HashToString( &m_pUpMD4, TRUE ) );
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient hash set request
BOOL CEDClient::OnHashsetRequest(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < sizeof(MD4) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
return TRUE;
}
MD4 pHash;
pPacket->Read( &pHash, sizeof(MD4) );
CED2K* pHashset = NULL;
BOOL bDelete = FALSE;
CString strName;
if ( CLibraryFile* pFile = LibraryMaps.LookupFileByED2K( &pHash, TRUE, TRUE, TRUE ) )
{
strName = pFile->m_sName;
pHashset = pFile->GetED2K();
bDelete = TRUE;
Library.Unlock();
}
else if ( CDownload* pDownload = Downloads.FindByED2K( &pHash, TRUE ) )
{
if ( pHashset = pDownload->GetHashset() )
{
strName = pDownload->m_sRemoteName;
bDelete = FALSE;
}
}
if ( pHashset != NULL )
{
CEDPacket* pReply = CEDPacket::New( ED2K_C2C_HASHSETANSWER );
pReply->Write( &pHash, sizeof(MD4) );
int nBlocks = pHashset->GetBlockCount();
if ( nBlocks <= 1 ) nBlocks = 0;
pReply->WriteShortLE( (WORD)nBlocks );
pReply->Write( pHashset->GetRawPtr(), sizeof(MD4) * nBlocks );
if ( bDelete ) delete pHashset;
Send( pReply );
theApp.Message( MSG_DEFAULT, IDS_ED2K_CLIENT_SENT_HASHSET,
(LPCTSTR)strName, (LPCTSTR)m_sAddress );
}
else
{
CEDPacket* pReply = CEDPacket::New( ED2K_C2C_FILENOTFOUND );
pReply->Write( &pHash, sizeof(MD4) );
Send( pReply );
theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress,
(LPCTSTR)CED2K::HashToString( &pHash, TRUE ) );
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient queue request
BOOL CEDClient::OnQueueRequest(CEDPacket* pPacket)
{
if ( m_bUpMD4 == FALSE )
{
// MESSAGE: File not requested yet
return TRUE;
}
if ( m_pUpload != NULL && m_pUpload->m_pED2K != m_pUpMD4 )
DetachUpload();
if ( m_pUpload == NULL )
m_pUpload = new CUploadTransferED2K( this );
m_pUpload->Request( &m_pUpMD4 );
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient source request
BOOL CEDClient::OnSourceRequest(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < sizeof(MD4) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
return TRUE;
}
MD4 pHash;
pPacket->Read( &pHash, sizeof(MD4) );
CEDPacket* pReply = CEDPacket::New( ED2K_C2C_ANSWERSOURCES, ED2K_PROTOCOL_EMULE );
int nCount = 0;
if ( CDownload* pDownload = Downloads.FindByED2K( &pHash, TRUE ))
{
for ( CDownloadSource* pSource = pDownload->GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
{
if ( pSource->m_nProtocol == PROTOCOL_ED2K && pSource->m_bReadContent )
{
pReply->WriteLongLE( pSource->m_pAddress.S_un.S_addr );
pReply->WriteShortLE( pSource->m_nPort );
pReply->WriteLongLE( pSource->m_pServerAddress.S_un.S_addr );
pReply->WriteShortLE( (WORD)pSource->m_nServerPort );
if ( m_bEmSources >= 2 ) pReply->Write( &pSource->m_pGUID, sizeof(GGUID) );
nCount++;
}
}
}
if ( pReply->m_nLength > 0 )
{
BYTE* pStart = pReply->WriteGetPointer( sizeof(MD4) + 2, 0 );
CopyMemory( pStart, &pHash, sizeof(MD4) );
pStart += sizeof(MD4);
*(WORD*)pStart = nCount;
Send( pReply, FALSE );
}
pReply->Release();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient source answer
BOOL CEDClient::OnSourceAnswer(CEDPacket* pPacket)
{
if ( Settings.Library.SourceMesh == FALSE ) return TRUE;
if ( pPacket->GetRemaining() < sizeof(MD4) + 2 )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
return TRUE;
}
MD4 pHash;
pPacket->Read( &pHash, sizeof(MD4) );
int nCount = pPacket->ReadShortLE();
if ( pPacket->GetRemaining() < nCount * ( m_bEmSources >= 2 ? 12+16 : 12 ) )
{
theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_BAD_PACKET, (LPCTSTR)m_sAddress, pPacket->m_nType );
return TRUE;
}
if ( CDownload* pDownload = Downloads.FindByED2K( &pHash ))
{
while ( nCount-- > 0 )
{
GGUID pGUID;
DWORD nClientID = pPacket->ReadLongLE();
WORD nClientPort = pPacket->ReadShortLE();
DWORD nServerIP = pPacket->ReadLongLE();
WORD nServerPort = pPacket->ReadShortLE();
if ( m_bEmSources >= 2 )
{
pPacket->Read( &pGUID, sizeof(GGUID) );
pDownload->AddSourceED2K( nClientID, nClientPort, nServerIP, nServerPort, &pGUID );
}
else
{
pDownload->AddSourceED2K( nClientID, nClientPort, nServerIP, nServerPort );
}
}
}
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CEDClient source URL utility
CString CEDClient::GetSourceURL()
{
ASSERT( m_bGUID );
ASSERT( m_bUpMD4 );
CString str;
if ( CEDPacket::IsLowID( m_nClientID ) )
{
str.Format( _T("ed2kftp://%lu@%s:%i/%s/%I64i/"),
m_nClientID,
(LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ),
htons( m_pHost.sin_port ),
(LPCTSTR)CED2K::HashToString( &m_pUpMD4 ), m_nUpSize );
}
else
{
str.Format( _T("ed2kftp://%s:%lu/%s/%I64i/"),
(LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ),
htons( m_pHost.sin_port ),
(LPCTSTR)CED2K::HashToString( &m_pUpMD4 ), m_nUpSize );
}
return str;
}
//////////////////////////////////////////////////////////////////////
// CEDClient part status utility
void CEDClient::WritePartStatus(CEDPacket* pPacket, CDownload* pDownload)
{
QWORD nParts = ( pDownload->m_nSize + ED2K_PART_SIZE - 1 ) / ED2K_PART_SIZE;
pPacket->WriteShortLE( (WORD)nParts );
if ( pDownload->m_pHashsetBlock != NULL && pDownload->m_nHashsetBlock == nParts )
{
for ( QWORD nPart = 0 ; nPart < nParts ; )
{
BYTE nByte = 0;
for ( DWORD nBit = 0 ; nBit < 8 && nPart < nParts ; nBit++, nPart++ )
{
if ( pDownload->m_pHashsetBlock[ nPart ] == TS_TRUE )
{
nByte |= ( 1 << nBit );
}
}
pPacket->WriteByte( nByte );
}
}
else
{
for ( QWORD nPart = 0 ; nPart < nParts ; )
{
BYTE nByte = 0;
for ( DWORD nBit = 0 ; nBit < 8 && nPart < nParts ; nBit++, nPart++ )
{
QWORD nOffset = nPart * ED2K_PART_SIZE;
QWORD nLength = min( ED2K_PART_SIZE, pDownload->m_nSize - nOffset );
if ( pDownload->IsRangeUseful( nOffset, nLength ) == FALSE )
{
nByte |= ( 1 << nBit );
}
}
pPacket->WriteByte( nByte );
}
}
}
//////////////////////////////////////////////////////////////////////
// CEDClient UDP packet handlers
BOOL CEDClient::OnUdpReask(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < sizeof(MD4) ) return FALSE;
if ( m_bUpMD4 == FALSE || m_pUpload == NULL ) return FALSE;
MD4 pMD4;
pPacket->Read( &pMD4, sizeof(MD4) );
if ( pMD4 != m_pUpMD4 ) return FALSE;
return m_pUpload->OnReask();
}
BOOL CEDClient::OnUdpReaskAck(CEDPacket* pPacket)
{
if ( pPacket->GetRemaining() < 2 ) return FALSE;
if ( m_pDownload == NULL ) return FALSE;
int nRank = pPacket->ReadShortLE();
m_pDownload->SetQueueRank( nRank );
return TRUE;
}
BOOL CEDClient::OnUdpQueueFull(CEDPacket* pPacket)
{
if ( m_pDownload != NULL )
{
m_pDownload->m_pSource->m_tAttempt = GetTickCount() + Settings.eDonkey.ReAskTime * 1000;
m_pDownload->Close( TS_UNKNOWN );
}
return TRUE;
}
BOOL CEDClient::OnUdpFileNotFound(CEDPacket* pPacket)
{
if ( m_pDownload != NULL ) m_pDownload->Close( TS_FALSE );
return TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -