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, 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; }
nsresult nsDownload::Cancel() { // Don't cancel if download is already finished or canceled if (GetDownloadState() == FINISHED || GetDownloadState() == CANCELED) return NS_OK; nsresult rv = mCancelable->Cancel(NS_BINDING_ABORTED); if (NS_FAILED(rv)) return rv; SetDownloadState(CANCELED); nsCAutoString path; rv = GetFilePathUTF8(mTarget, path); if (NS_FAILED(rv)) return rv; mDownloadManager->DownloadEnded(path, nsnull); // Dump the temp file. This should really be done when the transfer // is cancelled, but there are other cancellation causes that shouldn't // remove this. We need to improve those bits. if (mTempFile) { PRBool exists; mTempFile->Exists(&exists); if (exists) mTempFile->Remove(PR_FALSE); } // if there's a progress dialog open for the item, // we have to notify it that we're cancelling nsCOMPtr<nsIObserver> observer = do_QueryInterface(GetDialog()); if (observer) { rv = observer->Observe(static_cast<nsIDownload*>(this), "oncancel", nsnull); } return rv; }
CMapiMessage::CMapiMessage(LPMESSAGE lpMsg) : m_lpMsg(lpMsg), m_dldStateHeadersOnly(false), m_msgFlags(0) { nsresult rv; m_pIOService = do_GetService(NS_IOSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) return; FetchHeaders(); if (ValidState()) { BuildFromLine(); FetchFlags(); GetDownloadState(); if (FullMessageDownloaded()) { FetchBody(); ProcessAttachments(); } } }
void CUpDownClient::OnPeerCacheDownSocketClosed(int nErrorCode) { if (nErrorCode) return; // restart PC download if cache just closed the connection without obvious reason if (GetDownloadState() == DS_DOWNLOADING && m_ePeerCacheDownState == PCDS_DOWNLOADING && !m_PendingBlocks_list.IsEmpty()) { if (thePrefs.GetVerbose()) AddDebugLogLine(DLP_HIGH, false, _T("PeerCache: Socket closed unexpedtedly, trying to reestablish connection")); theApp.m_pPeerCache->DownloadAttemptFailed(); TRACE("+++ Restarting PeerCache download - socket closed\n"); ASSERT( m_pPCDownSocket == NULL ); SetPeerCacheDownState(PCDS_NONE); ClearDownloadBlockRequests(); SendPeerCacheFileRequest(); } }
bool CUpDownClient::OnPeerCacheDownSocketTimeout() { // restart PC download if cache just stalls if (GetDownloadState() == DS_DOWNLOADING && m_ePeerCacheDownState == PCDS_DOWNLOADING && !m_PendingBlocks_list.IsEmpty()) { if (thePrefs.GetVerbose()) AddDebugLogLine(DLP_HIGH, false, _T("PeerCache Error: Socket TimeOut, trying to reestablish connection")); theApp.m_pPeerCache->DownloadAttemptFailed(); TRACE("+++ Restarting PeerCache download - socket timeout\n"); if (m_pPCDownSocket) { m_pPCDownSocket->Safe_Delete(); ASSERT( m_pPCDownSocket == NULL ); } SetPeerCacheDownState(PCDS_NONE); ClearDownloadBlockRequests(); return SendPeerCacheFileRequest(); } return false; }
void CUpDownClient::ProcessHttpBlockPacket(const BYTE* pucData, UINT uSize) { if (reqfile == NULL) throw CString(_T("Failed to process HTTP data block - No 'reqfile' attached")); if (reqfile->IsStopped() || (reqfile->GetStatus() != PS_READY && reqfile->GetStatus() != PS_EMPTY)) throw CString(_T("Failed to process HTTP data block - File not ready for receiving data")); if (m_nUrlStartPos == -1) throw CString(_T("Failed to process HTTP data block - Unexpected file data")); uint32 nStartPos = m_nUrlStartPos; uint32 nEndPos = m_nUrlStartPos + uSize; m_nUrlStartPos += uSize; // if (thePrefs.GetDebugClientTCPLevel() > 0) // Debug(" Start=%u End=%u Size=%u %s\n", nStartPos, nEndPos, size, DbgGetFileInfo(reqfile->GetFileHash())); if (!(GetDownloadState() == DS_DOWNLOADING || GetDownloadState() == DS_NONEEDEDPARTS)) throw CString(_T("Failed to process HTTP data block - Invalid download state")); m_dwLastBlockReceived = ::GetTickCount(); if (nEndPos == nStartPos || uSize != nEndPos - nStartPos) throw CString(_T("Failed to process HTTP data block - Invalid block start/end offsets")); thePrefs.Add2SessionTransferData(GetClientSoft(), (GetClientSoft()==SO_URL) ? (UINT)-2 : (UINT)-1, false, false, uSize); m_nDownDataRateMS += uSize; if (credits) credits->AddDownloaded(uSize, GetIP()); nEndPos--; for (POSITION pos = m_PendingBlocks_list.GetHeadPosition(); pos != NULL; ) { POSITION posLast = pos; Pending_Block_Struct *cur_block = m_PendingBlocks_list.GetNext(pos); if (cur_block->block->StartOffset <= nStartPos && nStartPos <= cur_block->block->EndOffset) { if (thePrefs.GetDebugClientTCPLevel() > 0){ // NOTE: 'Left' is only accurate in case we have one(!) request block! void* p = m_pPCDownSocket ? (void*)m_pPCDownSocket : (void*)socket; Debug(_T("%08x Start=%u End=%u Size=%u Left=%u %s\n"), p, nStartPos, nEndPos, uSize, cur_block->block->EndOffset - (nStartPos + uSize) + 1, DbgGetFileInfo(reqfile->GetFileHash())); } m_nLastBlockOffset = nStartPos; uint32 lenWritten = reqfile->WriteToBuffer(uSize, pucData, nStartPos, nEndPos, cur_block->block, this); if (lenWritten > 0) { m_nTransferredDown += uSize; SetTransferredDownMini(); if (nEndPos >= cur_block->block->EndOffset) { reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset); delete cur_block->block; delete cur_block; m_PendingBlocks_list.RemoveAt(posLast); if (m_PendingBlocks_list.IsEmpty()) { if (thePrefs.GetDebugClientTCPLevel() > 0) DebugSend("More block requests", this); m_nUrlStartPos = (UINT)-1; SendHttpBlockRequests(); } } // else // TRACE("%hs - %d bytes missing\n", __FUNCTION__, cur_block->block->EndOffset - nEndPos); } return; } } TRACE("%s - Dropping packet\n", __FUNCTION__); }
bool CUpDownClient::ProcessPeerCacheAnswer(const uchar* packet, UINT size) { const bool bDebug = (thePrefs.GetDebugClientTCPLevel() > 0); ASSERT( GetDownloadState() == DS_DOWNLOADING ); ASSERT( m_ePeerCacheDownState == PCDS_WAIT_CLIENT_REPLY ); if (bDebug) DebugRecv("OP_PeerCacheAnswer", this); if (socket == NULL || reqfile == NULL){ ASSERT(0); return false; } CSafeMemFile dataRecv(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_NONE){ if (thePrefs.GetVerbose()) AddDebugLogLine(false, _T("Client does not support PeerCache; %s"), DbgGetClientInfo()); return false; } if (uPCOpcode != PCOP_RES){ if (bDebug) Debug(_T(" ***Invalid packet opcode: 0x%02x\n"), uPCOpcode); ASSERT(0); return false; } uint32 uPushId = 0; uint32 uRemoteIP = 0; uchar aucFileHash[16]; md4clr(aucFileHash); CString strInfo; UINT uTags = dataRecv.ReadUInt8(); while (uTags--) { CTag tag(&dataRecv, GetUnicodeSupport()!=utf8strNone); if (tag.GetNameID() == PCTAG_PUSHID && tag.IsInt()) { uPushId = tag.GetInt(); if (bDebug) strInfo.AppendFormat(_T(" PushId=%u"), uPushId); } else if (tag.GetNameID() == PCTAG_PUBLICIP && tag.IsInt()) { uRemoteIP = tag.GetInt(); if (bDebug) strInfo.AppendFormat(_T(" RemoteIP=%s"), ipstr(uRemoteIP)); } else if (tag.GetNameID() == PCTAG_FILEID && tag.IsHash() && tag.GetHash() != NULL) { md4cpy(aucFileHash, tag.GetHash()); if (bDebug) strInfo.AppendFormat(_T(" FileId=%s"), md4str(aucFileHash)); } else { if (bDebug) strInfo.AppendFormat(_T(" ***UnkTag: %s"), tag.GetFullInfo()); ASSERT(0); } } if (bDebug) { if (dataRecv.GetPosition() < dataRecv.GetLength()) strInfo.AppendFormat(_T(" ***AddData: %u bytes"), (UINT)(dataRecv.GetLength() - dataRecv.GetPosition())); Debug(_T("%s\n"), strInfo); } if (uPushId == 0 || uRemoteIP == 0 || isnulmd4(aucFileHash)){ if (thePrefs.GetVerbose()) AddDebugLogLine(false, _T("Invalid PeerCacheAnswer; %s"), DbgGetClientInfo()); return false; } if (md4cmp(aucFileHash, reqfile->GetFileHash()) != 0){ if (thePrefs.GetVerbose()) AddDebugLogLine(false, _T("PeerCacheAnswer reqfile does not match ed2k reqfile; %s"), DbgGetClientInfo()); return false; } m_uPeerCacheDownloadPushId = uPushId; m_uPeerCacheRemoteIP = uRemoteIP; if (!SendHttpBlockRequests()) return false; theApp.m_pPeerCache->DownloadAttemptStarted(); ASSERT( m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY ); return true; }
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); SwapToAnotherFile(_T("A4AF for NNP file. CUpDownClient::SendHttpBlockRequests()"), true, false, false, NULL, true, true); 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 = (uint64)-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=%I64u-%I64u\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, 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::ProcessPeerCacheDownHttpResponse(const CStringAArray& astrHeaders) { ASSERT( GetDownloadState() == DS_DOWNLOADING ); ASSERT( m_ePeerCacheDownState == PCDS_WAIT_CACHE_REPLY ); if (reqfile == NULL) throw CString(_T("Failed to process HTTP response - No 'reqfile' attached")); if (GetDownloadState() != DS_DOWNLOADING) throw CString(_T("Failed to process HTTP response - Invalid client download state")); 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; } 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; } uint64 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 = _atoi64((LPCSTR)rstrHdr + 15); if (uContentLength > m_uReqEnd - m_uReqStart + 1){ CString strError; strError.Format(_T("Unexpected HTTP header field \"%hs\""), rstrHdr); throw strError; } } else if (bExpectData && strnicmp(rstrHdr, "Content-Range:", 14) == 0) { uint64 ui64Start = 0, ui64End = 0, ui64Len = 0; if (sscanf((LPCSTR)rstrHdr + 14," bytes %I64u - %I64u / %I64u", &ui64Start, &ui64End, &ui64Len) != 3){ CString strError; strError.Format(_T("Unexpected HTTP header field \"%hs\""), rstrHdr); throw strError; } if (ui64Start > ui64End || ui64Len != reqfile->GetFileSize() || ui64Start < m_uReqStart || ui64Start > m_uReqEnd || ui64End < m_uReqStart || ui64End > m_uReqEnd){ CString strError; strError.Format(_T("Unexpected HTTP header field \"%hs\""), rstrHdr); throw strError; } bValidContentRange = true; m_nUrlStartPos = ui64Start; } 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, 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; }