CTransferSocket::~CTransferSocket() { if (m_transferEndReason == none) m_transferEndReason = successful; delete m_pProxyBackend; if (m_pTlsSocket) delete m_pTlsSocket; else delete m_pBackend; delete m_pSocketServer; m_pSocketServer = 0; delete m_pSocket; m_pSocket = 0; if (m_pControlSocket) { if (m_transferMode == upload || m_transferMode == download) { CFtpFileTransferOpData *pData = static_cast<CFtpFileTransferOpData *>(static_cast<CRawTransferOpData *>(m_pControlSocket->m_pCurOpData)->pOldData); if (pData && pData->pIOThread) { if (m_transferMode == download) FinalizeWrite(); pData->pIOThread->SetEventHandler(0); } } } }
CTransferSocket::~CTransferSocket() { remove_handler(); if (m_transferEndReason == TransferEndReason::none) { m_transferEndReason = TransferEndReason::successful; } ResetSocket(); if (m_transferMode == TransferMode::upload || m_transferMode == TransferMode::download) { if (ioThread_) { if (m_transferMode == TransferMode::download) { FinalizeWrite(); } ioThread_->SetEventHandler(0); } } }
CTransferSocket::~CTransferSocket() { if (m_transferEndReason == none) m_transferEndReason = successful; ResetSocket(); if (m_pControlSocket) { if (m_transferMode == upload || m_transferMode == download) { CFtpFileTransferOpData *pData = static_cast<CFtpFileTransferOpData *>(static_cast<CRawTransferOpData *>(m_pControlSocket->m_pCurOpData)->pOldData); if (pData && pData->pIOThread) { if (m_transferMode == download) FinalizeWrite(); pData->pIOThread->SetEventHandler(0); } } } }
boost::shared_ptr<std::ostream> StringDataBlob::write() { return boost::shared_ptr<std::ostringstream>(new std::ostringstream, FinalizeWrite(m_data)); }
void CTransferSocket::OnReceive() { m_pControlSocket->LogMessage(::Debug_Debug, _T("CTransferSocket::OnReceive(), m_transferMode=%d"), m_transferMode); if (!m_pBackend) { m_pControlSocket->LogMessage(::Debug_Verbose, _T("Postponing receive, m_pBackend was false.")); m_postponedReceive = true; return; } if (!m_bActive) { m_pControlSocket->LogMessage(::Debug_Verbose, _T("Postponing receive, m_bActive was false.")); m_postponedReceive = true; return; } if (m_transferMode == list) { for (;;) { char *pBuffer = new char[4096]; int error; int numread = m_pBackend->Read(pBuffer, 4096, error); if (numread < 0) { delete [] pBuffer; if (error != EAGAIN) { m_pControlSocket->LogMessage(::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error).c_str()); TransferEnd(transfer_failure); } else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) TransferEnd(successful); return; } if (numread > 0) { if (!m_pDirectoryListingParser->AddData(pBuffer, numread)) { TransferEnd(transfer_failure); return; } m_pEngine->SetActive(CFileZillaEngine::recv); if (!m_madeProgress) { m_madeProgress = 2; m_pControlSocket->SetTransferStatusMadeProgress(); } m_pControlSocket->UpdateTransferStatus(numread); } else { delete [] pBuffer; TransferEnd(successful); return; } } } else if (m_transferMode == download) { for (;;) { if (!CheckGetNextWriteBuffer()) return; int error; int numread = m_pBackend->Read(m_pTransferBuffer, m_transferBufferLen, error); if (numread < 0) { if (error != EAGAIN) { m_pControlSocket->LogMessage(::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error).c_str()); TransferEnd(transfer_failure); } else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) TransferEnd(successful); return; } if (numread > 0) { m_pEngine->SetActive(CFileZillaEngine::recv); if (!m_madeProgress) { m_madeProgress = 2; m_pControlSocket->SetTransferStatusMadeProgress(); } m_pControlSocket->UpdateTransferStatus(numread); m_pTransferBuffer += numread; m_transferBufferLen -= numread; if (!CheckGetNextWriteBuffer()) return; } else //!numread { FinalizeWrite(); break; } } } else if (m_transferMode == resumetest) { for (;;) { char buffer[2]; int error; int numread = m_pBackend->Read(buffer, 2, error); if (numread < 0) { if (error != EAGAIN) { m_pControlSocket->LogMessage(::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error).c_str()); TransferEnd(transfer_failure); } else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) { if (m_transferBufferLen == 1) TransferEnd(successful); else { m_pControlSocket->LogMessage(::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen); TransferEnd(failed_resumetest); } } return; } if (!numread) { if (m_transferBufferLen == 1) TransferEnd(successful); else { m_pControlSocket->LogMessage(::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen); TransferEnd(failed_resumetest); } return; } m_transferBufferLen += numread; if (m_transferBufferLen > 1) { m_pControlSocket->LogMessage(::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen); TransferEnd(failed_resumetest); return; } } } }
void CTransferSocket::OnClose(int error) { controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("CTransferSocket::OnClose(%d)"), error); m_onCloseCalled = true; if (m_transferEndReason != TransferEndReason::none) return; if (!m_pBackend) { if (!InitBackend()) { TransferEnd(TransferEndReason::transfer_failure); return; } } if (m_transferMode == TransferMode::upload) { if (m_shutdown && m_pTlsSocket) { if (m_pTlsSocket->Shutdown() != 0) TransferEnd(TransferEndReason::transfer_failure); else TransferEnd(TransferEndReason::successful); } else TransferEnd(TransferEndReason::transfer_failure); return; } if (error) { controlSocket_.LogMessage(MessageType::Error, _("Transfer connection interrupted: %s"), CSocket::GetErrorDescription(error)); TransferEnd(TransferEndReason::transfer_failure); return; } char buffer[100]; int numread = m_pBackend->Peek(&buffer, 100, error); if (numread > 0) { #ifndef FZ_WINDOWS wxFAIL_MSG(_T("Peek isn't supposed to return data after close notification")); #endif // MSDN says this: // FD_CLOSE being posted after all data is read from a socket. // An application should check for remaining data upon receipt // of FD_CLOSE to avoid any possibility of losing data. // First half is actually plain wrong. OnReceive(); return; } else if (numread < 0 && error != EAGAIN) { controlSocket_.LogMessage(MessageType::Error, _("Transfer connection interrupted: %s"), CSocket::GetErrorDescription(error)); TransferEnd(TransferEndReason::transfer_failure); return; } if (m_transferMode == TransferMode::resumetest) { if (m_transferBufferLen != 1) { TransferEnd(TransferEndReason::failed_resumetest); return; } } if (m_transferMode == TransferMode::download) { FinalizeWrite(); } else { TransferEnd(TransferEndReason::successful); } }
void CTransferSocket::OnReceive() { controlSocket_.LogMessage(MessageType::Debug_Debug, _T("CTransferSocket::OnReceive(), m_transferMode=%d"), m_transferMode); if (!m_pBackend) { controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Postponing receive, m_pBackend was false.")); m_postponedReceive = true; return; } if (!m_bActive) { controlSocket_.LogMessage(MessageType::Debug_Verbose, _T("Postponing receive, m_bActive was false.")); m_postponedReceive = true; return; } if (m_transferMode == TransferMode::list) { for (;;) { char *pBuffer = new char[4096]; int error; int numread = m_pBackend->Read(pBuffer, 4096, error); if (numread < 0) { delete [] pBuffer; if (error != EAGAIN) { controlSocket_.LogMessage(MessageType::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error)); TransferEnd(TransferEndReason::transfer_failure); } else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) { TransferEnd(TransferEndReason::successful); } return; } if (numread > 0) { if (!m_pDirectoryListingParser->AddData(pBuffer, numread)) { TransferEnd(TransferEndReason::transfer_failure); return; } controlSocket_.SetActive(CFileZillaEngine::recv); if (!m_madeProgress) { m_madeProgress = 2; engine_.transfer_status_.SetMadeProgress(); } engine_.transfer_status_.Update(numread); } else { delete [] pBuffer; TransferEnd(TransferEndReason::successful); return; } } } else if (m_transferMode == TransferMode::download) { int error; int numread; // Only do a certain number of iterations in one go to keep the event loop going. // Otherwise this behaves like a livelock on very large files written to a very fast // SSD downloaded from a very fast server. for (int i = 0; i < 100; ++i) { if (!CheckGetNextWriteBuffer()) { return; } numread = m_pBackend->Read(m_pTransferBuffer, m_transferBufferLen, error); if (numread <= 0) { break; } controlSocket_.SetActive(CFileZillaEngine::recv); if (!m_madeProgress) { m_madeProgress = 2; engine_.transfer_status_.SetMadeProgress(); } engine_.transfer_status_.Update(numread); m_pTransferBuffer += numread; m_transferBufferLen -= numread; } if (numread < 0) { if (error != EAGAIN) { controlSocket_.LogMessage(MessageType::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error)); TransferEnd(TransferEndReason::transfer_failure); } else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) { FinalizeWrite(); } } else if (!numread) { FinalizeWrite(); } else { send_event<CSocketEvent>(m_pBackend, SocketEventType::read, 0); } } else if (m_transferMode == TransferMode::resumetest) { for (;;) { char buffer[2]; int error; int numread = m_pBackend->Read(buffer, 2, error); if (numread < 0) { if (error != EAGAIN) { controlSocket_.LogMessage(MessageType::Error, _T("Could not read from transfer socket: %s"), CSocket::GetErrorDescription(error)); TransferEnd(TransferEndReason::transfer_failure); } else if (m_onCloseCalled && !m_pBackend->IsWaiting(CRateLimiter::inbound)) { if (m_transferBufferLen == 1) { TransferEnd(TransferEndReason::successful); } else { controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen); TransferEnd(TransferEndReason::failed_resumetest); } } return; } if (!numread) { if (m_transferBufferLen == 1) TransferEnd(TransferEndReason::successful); else { controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen); TransferEnd(TransferEndReason::failed_resumetest); } return; } m_transferBufferLen += numread; if (m_transferBufferLen > 1) { controlSocket_.LogMessage(MessageType::Debug_Warning, _T("Server incorrectly sent %d bytes"), m_transferBufferLen); TransferEnd(TransferEndReason::failed_resumetest); return; } } } }