📄 peercacheclient.cpp
字号:
throw strError;
}
}
else if (bExpectData && strnicmp(rstrHdr, "Content-Range:", 14) == 0)
{
DWORD dwStart = 0, dwEnd = 0, dwLen = 0;
if (sscanf((LPCSTR)rstrHdr + 14," bytes %u - %u / %u", &dwStart, &dwEnd, &dwLen) != 3){
CString strError;
strError.Format(_T("Unexpected HTTP header field \"%hs\""), rstrHdr);
throw strError;
}
if (dwStart > dwEnd
|| dwLen != reqfile->GetFileSize()
|| dwStart < m_uReqStart || dwStart > m_uReqEnd
|| dwEnd < m_uReqStart || dwEnd > m_uReqEnd){
CString strError;
strError.Format(_T("Unexpected HTTP header field \"%hs\""), rstrHdr);
throw strError;
}
bValidContentRange = true;
m_nUrlStartPos = dwStart;
}
else if (strnicmp(rstrHdr, "Server:", 7) == 0)
{
if (m_strClientSoftware.IsEmpty())
m_strClientSoftware = rstrHdr.Mid(7).Trim();
}
else if (bExpectData && strnicmp(rstrHdr, "X-Cache: MISS", 13) == 0)
{
bCacheHit = false;
}
else if (bExpectData && strnicmp(rstrHdr, "X-Cache: HIT", 12) == 0)
{
bCacheHit = true;
}
}
// we either get a 'Content-Range' or (for very small files) just a 'Content-Length' for the entire file
if (!bValidContentRange && uContentLength == reqfile->GetFileSize())
{
bValidContentRange = true;
m_nUrlStartPos = 0;
}
if (!bValidContentRange){
if (thePrefs.GetDebugClientTCPLevel() <= 0)
DebugHttpHeaders(astrHeaders);
CString strError;
strError.Format(_T("Unexpected HTTP response - No valid HTTP content range found"));
throw strError;
}
if (m_pPCDownSocket)
{
CSafeMemFile dataAck(128);
dataAck.WriteUInt8( bCacheHit ? 1 : 0 );
if (thePrefs.GetDebugClientTCPLevel() > 0){
DebugSend("OP__PeerCacheAck", this, (char*)reqfile->GetFileHash());
Debug(_T(" %s\n"), bCacheHit ? _T("CacheHit") : _T("CacheMiss"));
}
Packet* pEd2kPacket = new Packet(&dataAck, OP_EMULEPROT, OP_PEERCACHE_ACK);
theStats.AddUpDataOverheadFileRequest(pEd2kPacket->size);
socket->SendPacket(pEd2kPacket);
}
// SetDownloadState(DS_DOWNLOADING);
//PC-TODO: Where does this flag need to be cleared again?
// When client is allowed to send more block requests?
// Also, we have to support both type of downloads within in the same connection.
SetPeerCacheDownState(PCDS_DOWNLOADING);
m_bPeerCacheDownHit = bCacheHit;
return true;
}
bool CUpDownClient::ProcessPeerCacheDownHttpResponseBody(const BYTE* pucData, UINT uSize)
{
ProcessHttpBlockPacket(pucData, uSize);
return true;
}
UINT CUpDownClient::ProcessPeerCacheUpHttpRequest(const CStringAArray& astrHeaders)
{
ASSERT( m_ePeerCacheUpState == PCUS_WAIT_CACHE_REPLY );
if (astrHeaders.GetCount() == 0)
return HTTP_STATUS_BAD_REQUEST;
const CStringA& rstrHdr = astrHeaders.GetAt(0);
char szUrl[1024];
UINT uHttpMajVer, uHttpMinVer;
if (sscanf(rstrHdr, "GET %1023s HTTP/%u.%u", szUrl, &uHttpMajVer, &uHttpMinVer) != 3){
DebugHttpHeaders(astrHeaders);
return HTTP_STATUS_BAD_REQUEST;
}
if (uHttpMajVer != 1 || (uHttpMinVer != 0 && uHttpMinVer != 1)){
DebugHttpHeaders(astrHeaders);
return HTTP_STATUS_BAD_REQUEST;
}
char szFileHash[33];
if (sscanf(szUrl, "/.ed2khash=%32s", szFileHash) != 1){
DebugHttpHeaders(astrHeaders);
return HTTP_STATUS_BAD_REQUEST;
}
uchar aucUploadFileID[16];
if (!strmd4(szFileHash, aucUploadFileID)){
DebugHttpHeaders(astrHeaders);
return HTTP_STATUS_BAD_REQUEST;
}
CKnownFile* pUploadFile = theApp.sharedfiles->GetFileByID(aucUploadFileID);
if (pUploadFile == NULL){
DebugHttpHeaders(astrHeaders);
return HTTP_STATUS_NOT_FOUND;
}
bool bValidRange = false;
DWORD dwRangeStart = 0;
DWORD dwRangeEnd = 0;
DWORD dwPushID = 0;
for (int i = 1; i < astrHeaders.GetCount(); i++)
{
const CStringA& rstrHdr = astrHeaders.GetAt(i);
if (strnicmp(rstrHdr, "Range:", 6) == 0)
{
int iParams;
if ( (iParams = sscanf((LPCSTR)rstrHdr+6," bytes = %u - %u", &dwRangeStart, &dwRangeEnd)) != 2
&& (iParams = sscanf((LPCSTR)rstrHdr+6," bytes = %u -", &dwRangeStart)) != 1){
DebugHttpHeaders(astrHeaders);
TRACE("*** Unexpected HTTP %hs\n", rstrHdr);
return HTTP_STATUS_BAD_REQUEST;
}
if (iParams == 1)
dwRangeEnd = pUploadFile->GetFileSize() - 1;
if (dwRangeEnd < dwRangeStart){
DebugHttpHeaders(astrHeaders);
TRACE("*** Unexpected HTTP %hs\n", rstrHdr);
return HTTP_STATUS_INV_RANGE;
}
bValidRange = true;
}
else if (strnicmp(rstrHdr, "X-ED2K-PushId:", 14) == 0)
{
if (sscanf((LPCSTR)rstrHdr+14, "%u", &dwPushID) != 1){
DebugHttpHeaders(astrHeaders);
TRACE("*** Unexpected HTTP %hs\n", rstrHdr);
return HTTP_STATUS_BAD_REQUEST;
}
}
}
if (!bValidRange){
DebugHttpHeaders(astrHeaders);
return HTTP_STATUS_LENGTH_REQUIRED;
}
m_uPeerCacheUploadPushId = dwPushID;
//PC-TODO: Where does this flag need to be cleared again?
// When client is removed from uploading list?
// When client is allowed to send more block requests?
// everything is setup for uploading with PeerCache.
SetPeerCacheUpState(PCUS_UPLOADING);
Requested_Block_Struct* reqblock = new Requested_Block_Struct;
reqblock->StartOffset = dwRangeStart;
reqblock->EndOffset = dwRangeEnd + 1;
md4cpy(reqblock->FileID, aucUploadFileID);
reqblock->transferred = 0;
AddReqBlock(reqblock);
return HTTP_STATUS_OK;
}
bool CUpDownClient::ProcessPeerCacheUpHttpResponse(const CStringAArray& astrHeaders)
{
ASSERT( m_ePeerCacheUpState == PCUS_WAIT_CACHE_REPLY );
if (astrHeaders.GetCount() == 0)
throw CString(_T("Unexpected HTTP response - No headers available"));
const CStringA& rstrHdr = astrHeaders.GetAt(0);
UINT uHttpMajVer, uHttpMinVer, uHttpStatusCode;
if (sscanf(rstrHdr, "HTTP/%u.%u %u", &uHttpMajVer, &uHttpMinVer, &uHttpStatusCode) != 3){
CString strError;
strError.Format(_T("Unexpected HTTP response: \"%hs\""), rstrHdr);
throw strError;
}
if (uHttpMajVer != 1 || (uHttpMinVer != 0 && uHttpMinVer != 1)){
CString strError;
strError.Format(_T("Unexpected HTTP version: \"%hs\""), rstrHdr);
throw strError;
}
CString strError;
strError.Format(_T("Unexpected HTTP status code \"%u\""), uHttpStatusCode);
throw strError;
return false;
}
bool CUpDownClient::SendHttpBlockRequests()
{
USES_CONVERSION;
ASSERT( GetDownloadState() == DS_DOWNLOADING );
ASSERT( m_ePeerCacheDownState == PCDS_WAIT_CLIENT_REPLY || m_ePeerCacheDownState == PCDS_DOWNLOADING );
m_bPeerCacheDownHit = false;
m_dwLastBlockReceived = ::GetTickCount();
if (reqfile == NULL)
throw CString(_T("Failed to send block requests - No 'reqfile' attached"));
CreateBlockRequests(1);
if (m_PendingBlocks_list.IsEmpty()){
if (m_pPCDownSocket != NULL){
m_pPCDownSocket->Safe_Delete();
ASSERT( m_pPCDownSocket == NULL );
SetPeerCacheDownState(PCDS_NONE);
}
SetDownloadState(DS_NONEEDEDPARTS);
return false;
}
// PeerCache does not support persistant HTTP connections
if (m_pPCDownSocket != NULL)
{
m_pPCDownSocket->Safe_Delete();
ASSERT( m_pPCDownSocket == NULL );
SetPeerCacheDownState(PCDS_NONE);
return SendPeerCacheFileRequest();
}
ASSERT( m_pPCDownSocket == NULL );
m_pPCDownSocket = new CPeerCacheDownSocket(this);
m_pPCDownSocket->SetTimeOut(GetPeerCacheSocketDownloadTimeout());
if (!m_pPCDownSocket->Create()){
m_pPCDownSocket->Safe_Delete();
ASSERT( m_pPCDownSocket == NULL );
return false;
}
ASSERT( !m_pPCDownSocket->IsConnected() );
SOCKADDR_IN sockAddr = {0};
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons( theApp.m_pPeerCache->GetCachePort() );
sockAddr.sin_addr.S_un.S_addr = theApp.m_pPeerCache->GetCacheIP();
//Try to always tell the socket to WaitForOnConnect before you call Connect.
m_pPCDownSocket->WaitForOnConnect();
m_pPCDownSocket->Connect((SOCKADDR*)&sockAddr, sizeof sockAddr);
POSITION pos = m_PendingBlocks_list.GetHeadPosition();
Pending_Block_Struct* pending = m_PendingBlocks_list.GetNext(pos);
ASSERT( pending->block->StartOffset <= pending->block->EndOffset );
m_uReqStart = pending->block->StartOffset;
m_uReqEnd = pending->block->EndOffset;
m_nUrlStartPos = -1;
CStringA strPCRequest;
strPCRequest.AppendFormat("GET http://%s/.ed2khash=%s HTTP/1.0\r\n", ipstrA(m_uPeerCacheRemoteIP), md4strA(reqfile->GetFileHash()));
strPCRequest.AppendFormat("X-ED2K-PushId: %u\r\n", m_uPeerCacheDownloadPushId);
strPCRequest.AppendFormat("Range: bytes=%u-%u\r\n", m_uReqStart, m_uReqEnd);
strPCRequest.AppendFormat("User-Agent: eMule/%s\r\n", T2CA(theApp.m_strCurVersionLong));
strPCRequest.AppendFormat("X-Network: eDonkey,Kademlia\r\n");
strPCRequest.AppendFormat("\r\n");
if (thePrefs.GetDebugClientTCPLevel() > 0){
DebugSend("PeerCache-GET", this, (char*)reqfile->GetFileHash());
Debug(_T(" %hs\n"), strPCRequest);
}
CRawPacket* pHttpPacket = new CRawPacket(strPCRequest);
theStats.AddUpDataOverheadFileRequest(pHttpPacket->size);
m_pPCDownSocket->SendPacket(pHttpPacket);
m_pPCDownSocket->SetHttpState(HttpStateRecvExpected);
SetPeerCacheDownState(PCDS_WAIT_CACHE_REPLY);
return true;
}
bool CUpDownClient::SendPeerCacheFileRequest()
{
if (GetDownloadState() == DS_ONQUEUE){
ASSERT( m_ePeerCacheDownState == PCDS_NONE );
ASSERT( m_pPCDownSocket == NULL );
}
else if (GetDownloadState() == DS_DOWNLOADING){
ASSERT( m_ePeerCacheDownState == PCDS_NONE );
ASSERT( m_pPCDownSocket == NULL );
}
else{
ASSERT(0);
}
if (!SupportPeerCache() || socket == NULL){
ASSERT(0);
return false;
}
m_uPeerCacheDownloadPushId = GetRandomUInt32();
CSafeMemFile data(128);
data.WriteUInt8(PCPCK_VERSION);
data.WriteUInt8(PCOP_REQ);
data.WriteUInt8(5);
CTag tagCacheIP(PCTAG_CACHEIP, theApp.m_pPeerCache->GetCacheIP());
tagCacheIP.WriteNewEd2kTag(&data);
CTag tagPushId(PCTAG_PUSHID, m_uPeerCacheDownloadPushId);
tagPushId.WriteNewEd2kTag(&data);
CTag tagFileId(PCTAG_FILEID, (uchar*)reqfile->GetFileHash());
tagFileId.WriteNewEd2kTag(&data);
CTag tagPublicIP(PCTAG_PUBLICIP, theApp.GetPublicIP());
tagPublicIP.WriteNewEd2kTag(&data);
CTag tagCachePort(PCTAG_CACHEPORT, theApp.m_pPeerCache->GetCachePort());
tagCachePort.WriteNewEd2kTag(&data);
if (thePrefs.GetDebugClientTCPLevel() > 0){
DebugSend("OP__PeerCacheQuery", this, (char*)reqfile->GetFileHash());
Debug(_T(" CacheIP=%s PushId=%u PublicIP=%s FileId=%s\n"), ipstr(tagCacheIP.GetInt()), tagPushId.GetInt(), ipstr(tagPublicIP.GetInt()), md4str(tagFileId.GetHash()));
}
Packet* pEd2kPacket = new Packet(&data, OP_EMULEPROT, OP_PEERCACHE_QUERY);
theStats.AddUpDataOverheadFileRequest(pEd2kPacket->size);
socket->SendPacket(pEd2kPacket);
SetDownloadState(DS_DOWNLOADING);
m_dwLastBlockReceived = ::GetTickCount();
SetPeerCacheDownState(PCDS_WAIT_CLIENT_REPLY);
return true;
}
bool CUpDownClient::ProcessPeerCacheQuery(const char* packet, UINT size)
{
const bool bDebug = (thePrefs.GetDebugClientTCPLevel() > 0);
if (bDebug)
DebugRecv("OP_PeerCacheQuery", this);
if (socket == NULL){
ASSERT(0);
return false;
}
CSafeMemFile dataRecv((const BYTE*)packet, size);
uint8 uPCVersion = dataRecv.ReadUInt8();
if (uPCVersion != PCPCK_VERSION){
if (bDebug)
Debug(_T(" ***Invalid packet version: 0x%02x\n"), uPCVersion);
ASSERT(0);
return false;
}
uint8 uPCOpcode = dataRecv.ReadUInt8();
if (uPCOpcode != PCOP_REQ){
if (bDebug)
Debug(_T(" ***Invalid packet opcode: 0x%02x\n"), uPCOpcode);
ASSERT(0);
return false;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -