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

📄 peercacheclient.cpp

📁 eMule0.44b的原代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//this file is part of eMule
//Copyright (C)2004 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 <wininet.h>
#include "emule.h"
#include "UrlClient.h"
#include "PartFile.h"
#include "SafeFile.h"
#include "Statistics.h"
#include "Packets.h"
#include "ListenSocket.h"
#include "Preferences.h"
#include "OtherFunctions.h"
#include "SharedFileList.h"
#include "PeerCacheSocket.h"
#include "UploadBandwidthThrottler.h"
#include "PeerCacheFinder.h"
#include "UploadQueue.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

#define HTTP_STATUS_INV_RANGE	416

UINT GetPeerCacheSocketUploadTimeout()
{
	return SEC2MS(DOWNLOADTIMEOUT + 20 + 30);
}

UINT GetPeerCacheSocketDownloadTimeout()
{
	return SEC2MS(DOWNLOADTIMEOUT + 20);	// must be lower than Upload timeout
}


///////////////////////////////////////////////////////////////////////////////
// CPeerCacheSocket

IMPLEMENT_DYNCREATE(CPeerCacheSocket, CHttpClientReqSocket)

CPeerCacheSocket::CPeerCacheSocket(CUpDownClient* pClient)
{
	ASSERT( client == NULL );
	client = NULL;
	m_client = pClient;
}

CPeerCacheSocket::~CPeerCacheSocket()
{
	DetachFromClient();
}

void CPeerCacheSocket::DetachFromClient()
{
	if (GetClient())
	{
		// faile safe, should never be needed
		if (GetClient()->m_pPCDownSocket == this){
			ASSERT(0);
			GetClient()->m_pPCDownSocket = NULL;
		}
		if (GetClient()->m_pPCUpSocket == this){
			ASSERT(0);
			GetClient()->m_pPCUpSocket = NULL;
		}
	}
}

void CPeerCacheSocket::Safe_Delete()
{
	DetachFromClient();
	CClientReqSocket::Safe_Delete();
	m_client = NULL;
	ASSERT( GetClient() == NULL );
	ASSERT( client == NULL );
}

void CPeerCacheSocket::OnSend(int nErrorCode)
{
//	Debug("%08x %hs\n", this, __FUNCTION__);
	// PC-TODO: We have to keep the ed2k connection of a client as long active as we are using
	// the associated PeerCache connection -> Update the timeout of the ed2k socket.
	if (nErrorCode == 0 && GetClient() && GetClient()->socket)
		GetClient()->socket->ResetTimeOutTimer();
	CHttpClientReqSocket::OnSend(nErrorCode);
}

void CPeerCacheSocket::OnReceive(int nErrorCode)
{
//	Debug("%08x %hs\n", this, __FUNCTION__);
	// PC-TODO: We have to keep the ed2k connection of a client as long active as we are using
	// the associated PeerCache connection -> Update the timeout of the ed2k socket.
	if (nErrorCode == 0 && GetClient() && GetClient()->socket)
		GetClient()->socket->ResetTimeOutTimer();
	CHttpClientReqSocket::OnReceive(nErrorCode);
}

void CPeerCacheSocket::OnError(int nErrorCode)
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
	CHttpClientReqSocket::OnError(nErrorCode);
}

bool CPeerCacheSocket::ProcessHttpResponse()
{
	ASSERT(0);
	return false;
}

bool CPeerCacheSocket::ProcessHttpResponseBody(const BYTE* pucData, UINT size)
{
	ASSERT(0);
	return false;
}

bool CPeerCacheSocket::ProcessHttpRequest()
{
	ASSERT(0);
	return false;
}


///////////////////////////////////////////////////////////////////////////////
// CPeerCacheDownSocket

IMPLEMENT_DYNCREATE(CPeerCacheDownSocket, CPeerCacheSocket)

CPeerCacheDownSocket::CPeerCacheDownSocket(CUpDownClient* pClient)
	: CPeerCacheSocket(pClient)
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
}

CPeerCacheDownSocket::~CPeerCacheDownSocket()
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
	DetachFromClient();
}

void CPeerCacheDownSocket::DetachFromClient()
{
	if (GetClient())
	{
		if (GetClient()->m_pPCDownSocket == this)
			GetClient()->m_pPCDownSocket = NULL;
	}
}

void CPeerCacheDownSocket::OnClose(int nErrorCode)
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );

	DisableDownloadLimit(); // receive pending data
	CUpDownClient* pCurClient = GetClient();
	if (pCurClient && pCurClient->m_pPCDownSocket != this)
		pCurClient = NULL;

	CPeerCacheSocket::OnClose(nErrorCode);

	if (pCurClient)
	{
		ASSERT( pCurClient->m_pPCDownSocket == NULL );

		// this callback is only invoked if that closed socket was(!) currently attached to the client
		pCurClient->OnPeerCacheDownSocketClosed(nErrorCode);
	}
}

bool CPeerCacheDownSocket::ProcessHttpResponse()
{
	if (GetClient() == NULL)
		throw CString(__FUNCTION__ " - No client attached to HTTP socket");

	if (!GetClient()->ProcessPeerCacheDownHttpResponse(m_astrHttpHeaders))
		return false;

	return true;
}

bool CPeerCacheDownSocket::ProcessHttpResponseBody(const BYTE* pucData, UINT uSize)
{
	if (GetClient() == NULL)
		throw CString(__FUNCTION__ " - No client attached to HTTP socket");

	GetClient()->ProcessPeerCacheDownHttpResponseBody(pucData, uSize);

	return true;
}

bool CPeerCacheDownSocket::ProcessHttpRequest()
{
	throw CString("Unexpected HTTP request received");
	return false;
}


///////////////////////////////////////////////////////////////////////////////
// CPeerCacheUpSocket

IMPLEMENT_DYNCREATE(CPeerCacheUpSocket, CPeerCacheSocket)

CPeerCacheUpSocket::CPeerCacheUpSocket(CUpDownClient* pClient)
	: CPeerCacheSocket(pClient)
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
}

CPeerCacheUpSocket::~CPeerCacheUpSocket()
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
    theApp.uploadBandwidthThrottler->RemoveFromAllQueues(this);
	DetachFromClient();
}

void CPeerCacheUpSocket::DetachFromClient()
{
	if (GetClient())
	{
        if (GetClient()->m_pPCUpSocket == this) {
			GetClient()->m_pPCUpSocket = NULL;
            theApp.uploadBandwidthThrottler->RemoveFromStandardList(this);
        }
	}
}

void CPeerCacheUpSocket::OnSend(int nErrorCode)
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
	CPeerCacheSocket::OnSend(nErrorCode);
}

void CPeerCacheUpSocket::OnClose(int nErrorCode)
{
	DEBUG_ONLY( Debug(_T("%08x %hs\n"), this, __FUNCTION__) );
	CPeerCacheSocket::OnClose(nErrorCode);
	if (GetClient())
	{
		if (GetClient()->m_pPCUpSocket == this)
		{
			DetachFromClient();

			// this callback is only invoked if that closed socket was(!) currently attached to the client
			//GetClient()->OnPeerCacheUpSocketClosed(nErrorCode);
		}
	}
}

bool CPeerCacheUpSocket::ProcessHttpResponse()
{
	if (GetClient() == NULL)
		throw CString(__FUNCTION__ " - No client attached to HTTP socket");

	if (!GetClient()->ProcessPeerCacheUpHttpResponse(m_astrHttpHeaders))
		return false;

	return true;
}

bool CPeerCacheUpSocket::ProcessHttpResponseBody(const BYTE* pucData, UINT uSize)
{
	throw CString("Unexpected HTTP body in response received");
	return false;
}

bool CPeerCacheUpSocket::ProcessHttpRequest()
{
	if (GetClient() == NULL)
		throw CString(__FUNCTION__ " - No client attached to HTTP socket");

	UINT uHttpRes = GetClient()->ProcessPeerCacheUpHttpRequest(m_astrHttpHeaders);
	if (uHttpRes != HTTP_STATUS_OK){
		CStringA strResponse;
		strResponse.AppendFormat("HTTP/1.0 %u\r\n", uHttpRes);
		strResponse.AppendFormat("Content-Length: 0\r\n");
		strResponse.AppendFormat("\r\n");

		if (thePrefs.GetDebugClientTCPLevel() > 0)
			Debug(_T("Sending PeerCache HTTP respone:\n%hs"), strResponse);
		CRawPacket* pHttpPacket = new CRawPacket(strResponse);
		theStats.AddUpDataOverheadFileRequest(pHttpPacket->size);
		SendPacket(pHttpPacket);
		SetHttpState(HttpStateUnknown);

		// PC-TODO: Problem, the packet which was queued for sending will not be sent, if we immediatly
		// close that socket. Currently I just let it timeout.
		//return false;
		SetTimeOut(SEC2MS(30));
		return true;
	}
	GetClient()->m_iHttpSendState = 0;

	SetHttpState(HttpStateRecvExpected);
	GetClient()->SetUploadState(US_UPLOADING);
	
	return true;
}


///////////////////////////////////////////////////////////////////////////////
// PeerCache client

bool CUpDownClient::ProcessPeerCacheDownHttpResponse(const CStringAArray& astrHeaders)
{
	ASSERT( GetDownloadState() == DS_DOWNLOADING );
	ASSERT( m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY );

	if (reqfile == NULL)
		throw CString("Failed to process HTTP response - No 'reqfile' attached");
	if (GetDownloadState() != DS_DOWNLOADING)
		throw CString("Failed to process HTTP response - Invalid client download state");
	if (astrHeaders.GetCount() == 0)
		throw CString("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;
	}
	bool bExpectData = uHttpStatusCode == HTTP_STATUS_OK || uHttpStatusCode == HTTP_STATUS_PARTIAL_CONTENT;
	if (!bExpectData){
		CString strError;
		strError.Format(_T("Unexpected HTTP status code \"%u\""), uHttpStatusCode);
		throw strError;
	}

	UINT uContentLength = 0;
	bool bCacheHit = false;
	bool bValidContentRange = false;
	for (int i = 1; i < astrHeaders.GetCount(); i++)
	{
		const CStringA& rstrHdr = astrHeaders.GetAt(i);
		if (bExpectData && strnicmp(rstrHdr, "Content-Length:", 15) == 0)
		{
			uContentLength = atoi((LPCSTR)rstrHdr + 15);
			if (uContentLength > m_uReqEnd - m_uReqStart + 1){
				CString strError;
				strError.Format(_T("Unexpected HTTP header field \"%hs\""), rstrHdr);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -