⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 peercacheclient.cpp

📁 eMule0.44b的原代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
				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 + -