www.pudn.com > NetPaw.rar > DownloadFile.cpp


#include "StdAfx.h" 
#include "NetPaw.h" 
#include "mainfrm.h" 
#include "netpawview.h" 
#include ".\downloadfile.h" 
 
// 构造及析构函数 
CDownloadFile::CDownloadFile(DLFILEITEM_S *pstDlFileIt) 
	: m_nConnections(pstDlFileIt->wBlocksToDo) 
	, m_nStoppedSockets(pstDlFileIt->wBlocksToDo) 
	, m_nFileLength(pstDlFileIt->nFileLength) 
	, m_nBytesReceived(pstDlFileIt->nBytesDone) 
	, m_sDownloadUrl(pstDlFileIt->szUrl) 
	, m_sReferer(pstDlFileIt->szReferer) 
	, m_sWebInfo(pstDlFileIt->szWebInfo) 
	, m_dUsedTime(pstDlFileIt->dUsedTime) 
	, m_sFileName(_T("")) 
	, m_hFrameWnd(NULL) 
	, m_dwRecvBytesOld(0) 
	, m_bStopDownld(TRUE) // default is stop 
	, m_bRestart(FALSE) 
{ 
	// create a sniffer socket to trace file length 
	m_pSnifferSock = new CHttpSocket(this); 
 
	// set download parameter 
	SEGMENT_S stSeg; 
	ZeroMemory( &stSeg, sizeof(SEGMENT_S) ); 
	m_pSnifferSock->NewSegment( &stSeg ); 
} 
 
CDownloadFile::~CDownloadFile(void) 
{ 
	Destroy(); 
} 
 
 
// 类方法实现 
void CDownloadFile::AddSocket(void) 
{ 
	try 
	{ 
		CHttpSocket *pSocket = new CHttpSocket(this); 
 
		if( pSocket->Connect() ) 
		{ 
			CSingleLock sl(&m_csDataAccess); 
			sl.Lock(); 
 
			m_nConnections++; 
			m_lstSocket.push_back(pSocket); 
		} 
		else 
		{ 
			delete pSocket; 
		} 
	} 
	catch(...) 
	{ 
		AtlTrace("CDownloadFile::AddSocket Error.\n"); 
	} 
} 
 
void CDownloadFile::DeleteSocket(CHttpSocket *pSocket) 
{ 
	// lock the data 
	m_csDataAccess.Lock(); 
 
	// decrease connections 
	m_nConnections--; 
 
	// get the last element 
	m_lstSocket.remove(pSocket); 
 
	// unlock data 
	m_csDataAccess.Unlock(); 
 
	// delete the object 
	delete pSocket; 
} 
 
// because several threads write this file concurrently, 
// each thread should be allocated a segment of the file to download. 
// nOffset is the offset of a segment 
void CDownloadFile::Write(char *pBuffer, DWORD dwBytes, LONGLONG nOffset) 
{ 
	ASSERT( m_hFile != CFile::hFileNull ); 
 
	// before write the file, lock it 
	CSingleLock sl(&m_csFileAccess); 
	sl.Lock(); 
 
	// now write the data 
	Seek(nOffset, CFile::begin); 
 
	// write the data 
	CFile::Write(pBuffer, dwBytes); 
} 
 
void CDownloadFile::Destroy(void) 
{ 
	list::iterator itor; 
	CHttpSocket *pSocket; 
 
	// we can delete sniffer socket now 
	DelSniffSocket(); 
 
	// lock the data 
	m_csDataAccess.Lock(); 
 
	// delete all the downloading sockets 
	for(itor = m_lstSocket.begin(); itor != m_lstSocket.end(); itor++) 
	{ 
		pSocket = *itor; 
		delete pSocket; 
	} 
	m_lstSocket.clear(); 
 
	// unlock here 
	m_csDataAccess.Unlock(); 
 
	// close the file 
	CloseFile(); 
 
	// for debug use 
	AtlTrace("DownloadFile closed and destroyed\n"); 
} 
 
// downloading sockets begin to connect server 
void CDownloadFile::MassConnect() 
{ 
	list::iterator itor; 
	CHttpSocket *pSocket; 
 
	// lock the data 
	CSingleLock sl(&m_csDataAccess); 
	sl.Lock(); 
 
	for( itor = m_lstSocket.begin(); itor != m_lstSocket.end(); itor++ ) 
	{ 
		pSocket = *itor; 
 
		pSocket->m_sHostName = m_pSnifferSock->m_sHostName; 
		pSocket->m_sFileObj = m_pSnifferSock->m_sFileObj; 
		pSocket->m_nPort = m_pSnifferSock->m_nPort; 
 
		// should create the socket before connect 
		if( !pSocket->Connect() ) 
		{ 
			AtlTrace("Start connection failed\n"); 
		} 
	} 
} 
 
void CDownloadFile::NotifyConnected(CHttpSocket *pSocket) 
{ 
	if( (SOCKET)pSocket == GetSnifferSock() ) 
	{ 
		// start time counter 
		m_obTimer.Start(); 
 
		// set status bar information 
		NotifyStatus(STATUS_CONNECTED); 
	} 
} 
 
// a file data block is arrived, not including header 
void CDownloadFile::NotifyRcvData(CHttpSocket *pSocket, char *pBuffer, DWORD dwBytesRcvd) 
{ 
	DWORD dwBytesWrite; 
	LONGLONG nOffset; 
 
	// lock the socket 
	pSocket->m_csSockAccess.Lock(); 
 
	// get the file-writing parameters 
	dwBytesWrite = (DWORD)min((LONGLONG)dwBytesRcvd, pSocket->m_nDataToRead); 
	nOffset = pSocket->m_nFileOffset; 
 
	// move forward file pointer 
	pSocket->m_nFileOffset += dwBytesWrite; 
	pSocket->m_nDataToRead -= dwBytesWrite; 
 
	// set segment data 
	SEGMENT_S *pstSeg; 
	if( !pSocket->m_lstSegments.empty() ) 
	{ 
		pstSeg = pSocket->m_lstSegments.back(); 
 
		pstSeg->nBytesDone += dwBytesWrite; 
	} 
 
	// unlock the socket 
	pSocket->m_csSockAccess.Unlock(); 
 
	// write the buffer to the file 
	Write(pBuffer, dwBytesWrite, nOffset); 
 
	// increase received file data 
	m_csDataAccess.Lock(); 
	m_nBytesReceived += dwBytesWrite; 
	m_csDataAccess.Unlock(); 
} 
 
void CDownloadFile::NotifyFileLen(LONGLONG nFileLen) 
{ 
	AtlTrace("Notify FileLen\n"); 
 
	// lock the data 
	m_csDataAccess.Lock(); 
 
	// total file length 
	m_nFileLength = nFileLen; 
	m_nStoppedSockets = 0; 
	if( !m_bRestart ) 
	{ 
		m_nBytesReceived = 0; 
	} 
	m_dwRecvBytesOld = m_nBytesReceived; 
 
	m_csDataAccess.Unlock(); 
 
	// assign task to sockets 
	if( !m_bRestart ) 
	{ 
		// Notify file length is available 
		NotifyStatus( STATUS_ADDFILE, this ); 
 
		AssignTask(); 
	} 
 
	// begin to download file 
	MassConnect(); 
 
	// we can close sniffer socket now 
	m_pSnifferSock->Close(); 
} 
 
// a socket has just finished its task 
void CDownloadFile::NotifyFinished(CHttpSocket* pSocket) 
{ 
	// re-assign task to this socket 
	if( !ReAssignTask(pSocket) ) 
	{ 
		m_csDataAccess.Lock(); 
		m_nStoppedSockets++; 
		m_csDataAccess.Unlock(); 
 
		// for debug use 
		AtlTrace("Socket: %08X finished work.\n", pSocket); 
	} 
	else 
	{ 
		AtlTrace( "Socket: %08X is re-assigned work.\n", pSocket ); 
	} 
 
	// the whole file is done, close the file and stop all sockets 
	if( IsStopped() ) 
	{ 
		m_dUsedTime += m_obTimer.Stop(); 
 
		// close the file 
		CloseFile(); 
 
		if( IsFinished() ) 
		{ 
			AtlTrace( "All sockets have finished work.\n" ); 
			NotifyStatus( STATUS_FINISHED, this ); 
		} 
		else 
		{ 
			// just stop the connection 
			CloseSockets(); 
 
			AtlTrace( "All sockets are stopped.\n" ); 
			NotifyStatus( STATUS_STOPDOWNLD ); 
		} 
	} 
} 
 
BOOL CDownloadFile::ReAssignTask(CHttpSocket* pSocket) 
{ 
	LONGLONG nNewData; 
	SEGMENT_S *pstSeg, stNewSeg; 
 
	// if it is shutdown, don't assign task 
	if( IsStopDownld() ) 
	{ 
		return FALSE; 
	} 
 
	// if one socket doesn't finish its work by itself, 
	// it has no ability to help others (system limit?) 
	pSocket->m_csSockAccess.Lock(); 
	if( pSocket->m_nFileOffset != (pSocket->m_nRequestTo + 1) ) 
	{ 
		pSocket->m_csSockAccess.Unlock(); 
		return FALSE; 
	} 
	pSocket->m_csSockAccess.Unlock(); 
 
	// get the first heavy task socket 
	CHttpSocket *pSlowSocket = GetSlowSocket(); 
	if( !pSlowSocket ) 
	{ 
		return FALSE; 
	} 
 
	AtlTrace("Slow socket: %08X has: %I64d bytes left.\n", pSlowSocket, pSlowSocket->m_nDataToRead ); 
 
	// lock slow socket 
	pSlowSocket->m_csSockAccess.Lock(); 
 
	// recalculate the download length,  
	if( pSlowSocket->IsActive() ) 
	{ 
		// don't let slow socket exit too early 
		nNewData = pSlowSocket->m_nDataToRead * 2 / 3; 
	} 
	else 
	{ 
		// the slow socket is dead, it can do nothing 
		nNewData = 0; 
	} 
 
	// for new joined socket 
	stNewSeg.nDataFrom = pSlowSocket->m_nFileOffset + nNewData; 
	stNewSeg.nDataTo = pSlowSocket->m_nFileOffset + pSlowSocket->m_nDataToRead - 1; 
	stNewSeg.nBytesDone = 0; 
 
	// adjust the parameter of slow socket 
	pSlowSocket->m_nDataToRead = nNewData; 
	if( !pSlowSocket->m_lstSegments.empty() ) 
	{ 
		pstSeg = pSlowSocket->m_lstSegments.back(); 
 
		// readjust slow socket right bound 
		pstSeg->nDataTo = stNewSeg.nDataFrom - 1; 
	} 
	pSlowSocket->m_csSockAccess.Unlock(); 
 
	// now allocate a download range block 
	pSocket->NewSegment(&stNewSeg); 
 
	// although this socket is aready connected, but its work is 
	// done, we should re-connect for some server, otherwise it doesn't work:) 
	if( !pSocket->Connect() ) 
	{ 
		return FALSE; 
	} 
	//pSocket->SendHttpRequest(); 
 
	return TRUE; 
} 
 
void CDownloadFile::GetPerfData(PERFITEM_S* pstPerfIT) 
{ 
	// should zero the structure at first 
	ZeroMemory( pstPerfIT, sizeof(PERFITEM_S) ); 
 
	// lock the data 
	m_csDataAccess.Lock(); 
 
	// get data of download file 
	pstPerfIT->nFileLength = m_nFileLength; 
	pstPerfIT->nConnects = m_nConnections - m_nStoppedSockets; 
	pstPerfIT->fSpeed = (float)( (double)(m_nBytesReceived - m_dwRecvBytesOld) * 1000 / (TIMER_INTERVAL * 1024) ); 
	if( m_nFileLength > 0 ) 
	{ 
		pstPerfIT->fRatio = (float)( (double)m_nBytesReceived / (double)m_nFileLength * 100.0 ); 
	} 
 
	// get average speed 
	if( IsStopped() ) 
		pstPerfIT->dUsedTime = m_dUsedTime; 
	else 
		pstPerfIT->dUsedTime = m_obTimer.Stop() + m_dUsedTime; 
 
	if( pstPerfIT->dUsedTime > 0 ) 
	{ 
		pstPerfIT->fMeanSpeed = (float)( (double)m_nBytesReceived / (pstPerfIT->dUsedTime * 1024) ); 
	} 
 
	// save for the next time 
	m_dwRecvBytesOld = m_nBytesReceived; 
 
	m_csDataAccess.Unlock(); 
 
	// get file name from full path name 
	CString sFileName = GetFileName(); 
	StrCopy(pstPerfIT->szFileName, sFileName, MAX_PATH/2); 
} 
 
CHttpSocket* CDownloadFile::GetSlowSocket(void) 
{ 
	list::iterator itor; 
	CHttpSocket *pSlowSocket = NULL, *pSocket; 
	LONGLONG nMaxLeft = 0; 
 
	// lock the data 
	CSingleLock sl(&m_csDataAccess); 
	sl.Lock(); 
 
	// loop to find first slow socket 
	for( itor = m_lstSocket.begin(); itor != m_lstSocket.end(); itor++ ) 
	{ 
		pSocket = *itor; 
 
		// lock the socket 
		CSingleLock sl(&pSocket->m_csSockAccess); 
		sl.Lock(); 
 
		// find a slow socket, join it 
		if( pSocket->m_nDataToRead > nMaxLeft ) 
		{ 
			nMaxLeft = pSocket->m_nDataToRead; 
			pSlowSocket = pSocket; 
		} 
	} 
 
	// if block is too small, skip splitting 
	if( nMaxLeft < 2 * MAX_BUFF_SIZE ) 
	{ 
		return NULL; 
	} 
 
	return pSlowSocket; 
} 
 
void CDownloadFile::DrawDownldFile(CDC* pDC, CRect& rectDC, CNetPawView *pView) 
{ 
	list::iterator itor; 
	CHttpSocket *pSocket; 
 
	list::iterator itor2; 
	SEGMENT_S *pstSeg; 
	int nFromCell, nToCell, nDoneCells; 
 
	// loop all downloading sockets 
	CSingleLock sl(&m_csDataAccess); 
	sl.Lock(); 
	for( itor = m_lstSocket.begin(); itor != m_lstSocket.end(); itor++ ) 
	{ 
		pSocket = *itor; 
		if( !pSocket ) 
		{ 
			continue; 
		} 
 
		// draw all segments of this socket done 
		pSocket->m_csSockAccess.Lock(); 
		for( itor2 = pSocket->m_lstSegments.begin(); itor2 != pSocket->m_lstSegments.end(); itor2++ ) 
		{ 
			pstSeg = *itor2; 
			nFromCell = (int)( pstSeg->nDataFrom / 1024 ); 
			nToCell = (int)( pstSeg->nDataTo / 1024 ); 
			nDoneCells = (int)( (pstSeg->nBytesDone + 1023) / 1024 ); 
 
			pView->DrawOneSegment(pDC, rectDC, nFromCell, nToCell, nDoneCells); 
		} 
 
		pSocket->m_csSockAccess.Unlock(); 
	} 
} 
 
void CDownloadFile::Stop(void) 
{ 
	m_csDataAccess.Lock(); 
	m_bStopDownld = TRUE; 
	m_csDataAccess.Unlock(); 
} 
 
void CDownloadFile::CloseSockets(void) 
{ 
	list::iterator itor; 
	CHttpSocket *pSocket; 
 
	m_csDataAccess.Lock(); 
	// stop all the downloading sockets 
	for(itor = m_lstSocket.begin(); itor != m_lstSocket.end(); itor++) 
	{ 
		pSocket = *itor; 
		pSocket->Close(); 
	} 
	m_csDataAccess.Unlock(); 
} 
 
BOOL CDownloadFile::IsStopDownld(void) 
{ 
	BOOL bStop; 
 
	// lock the data 
	m_csDataAccess.Lock(); 
	bStop = m_bStopDownld; 
	m_csDataAccess.Unlock(); 
 
	return bStop; 
} 
 
SOCKET CDownloadFile::GetSnifferSock(void) 
{ 
	return (SOCKET)m_pSnifferSock; 
} 
 
BOOL CDownloadFile::IsStopped(void) 
{ 
	BOOL bStopped = FALSE; 
 
	m_csDataAccess.Lock(); 
	if( m_nStoppedSockets >= (long)m_lstSocket.size() ) 
	{ 
		bStopped = TRUE; 
	} 
	m_csDataAccess.Unlock(); 
 
	return bStopped; 
} 
 
void CDownloadFile::Restart(HWND hMainWnd) 
{ 
	m_csDataAccess.Lock(); 
	m_bRestart = TRUE; 
	m_csDataAccess.Unlock(); 
 
	// start to connect server 
	Start(hMainWnd); 
} 
 
BOOL CDownloadFile::ParseFileName() 
{ 
	// save the parameter at first 
	if( !m_pSnifferSock->ParseUrl(m_sDownloadUrl) ) 
	{ 
		return FALSE; 
	} 
 
	// get download file name 
	CString sFileName = m_pSnifferSock->m_sFileObj; 
 
	// get rid of remote folder 
	int nIndex = sFileName.ReverseFind('/'); 
	if( nIndex != -1 ) 
	{ 
		sFileName = sFileName.Mid(nIndex + 1); 
	} 
 
	// get rid of log in parameters 
	nIndex = sFileName.Find('&'); 
	if( nIndex != -1 ) 
	{ 
		sFileName = sFileName.Left(nIndex); 
	} 
 
	if( sFileName.IsEmpty() ) 
	{ 
		return FALSE; 
	} 
	m_sFileName = sFileName; 
 
	return TRUE; 
} 
 
void CDownloadFile::NewSocket(SEGMENT_S *pstSeg) 
{ 
	CHttpSocket *pSocket; 
	pSocket = new CHttpSocket(this); 
 
	// set download parameter 
	pSocket->NewSegment( pstSeg ); 
 
	// lock the list 
	m_csDataAccess.Lock(); 
	m_lstSocket.push_back(pSocket); 
	m_csDataAccess.Unlock(); 
} 
 
void CDownloadFile::AssignTask(void) 
{ 
	int nConnects; 
 
	// lock the data 
	m_csDataAccess.Lock(); 
	nConnects = m_nConnections; 
	m_csDataAccess.Unlock(); 
 
	// many sockets download a very short file is avoided 
	LONGLONG nMeanLen; 
	while( (nMeanLen = m_nFileLength / nConnects) < MAX_BUFF_SIZE ) 
	{ 
		if( nConnects <= 1 ) 
		{ 
			break; 
		} 
 
		nConnects /= 2; 
	} 
 
	// lock the data 
	m_csDataAccess.Lock(); 
	m_nConnections = nConnects; 
	m_csDataAccess.Unlock(); 
 
	// split the file and assign task for each socket 
	LONGLONG nSegLength; 
	LONGLONG nOffset = 0; 
	SEGMENT_S stBlock; 
	for( int i = 0; i < nConnects; i++ ) 
	{ 
		nSegLength = nMeanLen; 
		if( i == 0 ) 
		{ 
			// this a little larger block assigned to the first socket 
			nSegLength += m_nFileLength % nConnects; 
		} 
 
		// assign file block to each socket 
		stBlock.nDataFrom = nOffset; 
		stBlock.nDataTo = nOffset + nSegLength - 1; 
		stBlock.nBytesDone = 0; 
 
		// create a socket to finish the task 
		NewSocket( &stBlock ); 
 
		nOffset += nSegLength; 
	} 
} 
 
void CDownloadFile::Start(HWND hMainWnd) 
{ 
	// open a file to receive data 
	if( m_hFile == CFile::hFileNull ) 
	{ 
		CString sPathName; 
 
		// local file name, use .npf as suffix 
		CNetPawApp *pApp = (CNetPawApp *)AfxGetApp(); 
		if( pApp ) 
		{ 
			sPathName = pApp->m_sSavePath + '\\' + m_sFileName; 
			sPathName += _T(".npf"); 
		} 
 
		// open a file to receive data 
		if( !Open( sPathName, CFile::modeCreate | CFile::modeWrite | CFile::modeNoTruncate | CFile::shareExclusive ) ) 
		{ 
			NotifyStatus(STATUS_OPENFILEFAILED); 
			return; 
		} 
	} 
 
	// lock the data 
	m_csDataAccess.Lock(); 
 
	// clear stop flag 
	m_bStopDownld = FALSE; 
	if( hMainWnd ) 
	{ 
		m_hFrameWnd = hMainWnd; 
	} 
	m_csDataAccess.Unlock(); 
 
	// now connect the server 
	if( !m_pSnifferSock->Connect() ) 
	{ 
		DelSniffSocket(); 
 
		NotifyStatus( STATUS_CONNECTFAIL ); 
		return; 
	} 
 
	// set status bar information 
	NotifyStatus( STATUS_CONNECTING ); 
} 
 
BOOL CDownloadFile::IsFinished(void) 
{ 
	BOOL bFinished = FALSE; 
 
	m_csDataAccess.Lock(); 
	if( m_nBytesReceived >= m_nFileLength ) 
	{ 
		bFinished = TRUE; 
	} 
	m_csDataAccess.Unlock(); 
 
	return bFinished; 
} 
 
void CDownloadFile::SaveDlFileData(CFile *pFile) 
{ 
	int nLefts = 0; 
 
	// get unfinished blocks 
	list lstUndone; 
	nLefts = GetLeftSegments(lstUndone); 
 
	// download file structure 
	DLFILEITEM_S stDlFile; 
	ZeroMemory( &stDlFile, sizeof(DLFILEITEM_S) ); 
 
	// lock the data 
	CSingleLock sl(&m_csDataAccess); 
	sl.Lock(); 
 
	// the last piece is a finished one, but we have to record it 
	LONGLONG nMaxBound = GetMaxBound(lstUndone); 
	if( (nMaxBound > 0) && (nMaxBound < m_nFileLength) ) 
	{ 
		nLefts++; 
	} 
 
	// fill download file item 
	stDlFile.wSeperator = 0x0A0D; 
	stDlFile.wBlocksToDo = nLefts; 
	stDlFile.nFileLength = m_nFileLength; 
	stDlFile.nBytesDone = m_nBytesReceived; 
	stDlFile.dUsedTime = m_dUsedTime; 
 
	StrCopy( stDlFile.szUrl, m_sDownloadUrl, MAX_PATH ); 
	StrCopy( stDlFile.szReferer, m_sReferer, MAX_PATH ); 
	StrCopy( stDlFile.szWebInfo, m_sWebInfo, MAX_PATH/2 ); 
 
	// save the download file item 
	pFile->Write( &stDlFile, sizeof(DLFILEITEM_S) ); 
 
	// save the unfinished block in increase-order 
	LONGLONG nOffset = 0; 
	SEGMENT_S *pstSeg; 
	while( (pstSeg = GetMinOffset(lstUndone)) != NULL ) 
	{ 
		pstSeg->nBytesDone = pstSeg->nDataFrom + pstSeg->nBytesDone - nOffset; 
		pstSeg->nDataFrom = nOffset; 
 
		pFile->Write( pstSeg, sizeof(SEGMENT_S) ); 
		nOffset = pstSeg->nDataTo + 1; 
	} 
 
	// last block is a finished one 
	if( nOffset < m_nFileLength ) 
	{ 
		SEGMENT_S stSegLast; 
		stSegLast.nDataFrom = nOffset; 
		stSegLast.nDataTo = m_nFileLength - 1; 
		stSegLast.nBytesDone = m_nFileLength - nOffset; 
 
		pFile->Write( &stSegLast, sizeof(SEGMENT_S) ); 
	} 
} 
 
int CDownloadFile::GetLeftSegments( list& lstUndone ) 
{ 
	list::iterator itor; 
	CHttpSocket *pSocket; 
	SEGMENT_S *pstSeg; 
 
	// save blocks at first 
	m_csDataAccess.Lock(); 
 
	// save blocks at first 
	for( itor = m_lstSocket.begin(); itor != m_lstSocket.end(); itor++ ) 
	{ 
		pSocket = *itor; 
		if( !pSocket ) 
		{ 
			continue; 
		} 
 
		if( !pSocket->m_lstSegments.empty() ) 
		{ 
			pstSeg = pSocket->m_lstSegments.back(); 
 
			if( (pstSeg->nDataFrom + pstSeg->nBytesDone) < (pstSeg->nDataTo + 1) ) 
			{ 
				lstUndone.push_back(pstSeg); 
			} 
		} 
	} 
 
	m_csDataAccess.Unlock(); 
 
	return (int)lstUndone.size(); 
} 
 
SEGMENT_S* CDownloadFile::GetMinOffset( list& lstUndone ) 
{ 
	list::iterator itor; 
	SEGMENT_S *pstSeg = NULL, *pstTemp; 
 
	// get the first element 
	if( !lstUndone.empty() ) 
	{ 
		pstSeg = lstUndone.front(); 
	} 
 
	for( itor = ++lstUndone.begin(); itor != lstUndone.end(); itor++ ) 
	{ 
		pstTemp = *itor; 
		if( pstTemp->nDataFrom < pstSeg->nDataFrom ) 
		{ 
			pstSeg = pstTemp; 
		} 
	} 
 
	// remove this segment from the list 
	lstUndone.remove(pstSeg); 
 
	return pstSeg; 
} 
 
LONGLONG CDownloadFile::GetMaxBound(list& lstUndone) 
{ 
	list::iterator itor; 
	SEGMENT_S *pstSeg; 
	LONGLONG nMaxBound = 0; 
 
	// get the maximum right bound 
	for( itor = lstUndone.begin(); itor != lstUndone.end(); itor++ ) 
	{ 
		pstSeg = *itor; 
		if( nMaxBound < pstSeg->nDataTo + 1 ) 
		{ 
			nMaxBound = pstSeg->nDataTo + 1; 
		} 
	} 
 
	return nMaxBound; 
} 
 
void CDownloadFile::DelSniffSocket(void) 
{ 
	if( GetSnifferSock() != INVALID_SOCKET ) 
	{ 
		delete m_pSnifferSock; 
		m_pSnifferSock = NULL; 
	} 
} 
 
void CDownloadFile::NotifyStatus(int nCode, LPVOID pParam) 
{ 
	if( IsWindow(m_hFrameWnd) ) 
	{ 
		CWnd *pWnd = CWnd::FromHandle(m_hFrameWnd); 
		pWnd->PostMessage(WM_USER_STATUSNOTIFY, nCode, (LPARAM)pParam); 
	} 
} 
 
void CDownloadFile::CloseSocket(CHttpSocket* pSocket) 
{ 
	pSocket->Close(); 
 
	m_csDataAccess.Lock(); 
	m_nStoppedSockets++; 
	m_csDataAccess.Unlock(); 
 
	AtlTrace("Socket: %08X is closed.\n", pSocket); 
}