void AsioTcpSocket::Send(ptr<File> file, ptr<SendHandler> sendHandler) { BEGIN_TRY(); CriticalCode cc(cs); // если запланировано закрытие передачи, то больше в очередь добавлять ничего нельзя if(sendClosed) THROW("Sending closed"); bool queueWasEmpty = sendQueue.empty(); // добавить элемент в очередь sendQueue.push_back(SendItem(file, sendHandler)); // сбросить количество переданных данных в первом элементе, // если очередь была пуста (то есть первый элемент как раз // был добавлен) // также, если очередь была пуста, начать отправку if(queueWasEmpty) { firstItemSent = 0; StartSending(); } END_TRY("Can't send data to Asio TCP socket"); }
void AsioTcpSocket::End() { CriticalCode cc(cs); if(!sendClosed) { sendClosed = true; if(sendQueue.empty()) StartSending(); } }
BOOL CUploadTransferDC::RequestTigerTree(CLibraryFile* pFile, QWORD nOffset, QWORD nLength) { m_pXML.Clear(); if ( ! RequestComplete( pFile ) ) { ASSERT( FALSE ); return FALSE; } theApp.Message( MSG_INFO, IDS_UPLOAD_TIGER_SEND, (LPCTSTR)m_sName, (LPCTSTR)m_sAddress ); CAutoPtr< CTigerTree > pTigerTree( pFile->GetTigerTree() ); if ( ! pTigerTree ) return FALSE; BYTE* pSerialTree = NULL; DWORD nSerialTree = 0; if ( ! pTigerTree->ToBytesLevel1( &pSerialTree, &nSerialTree ) ) return FALSE; if ( nOffset >= nSerialTree ) nLength = SIZE_UNKNOWN; else nLength = min( ( ( nLength == SIZE_UNKNOWN ) ? nSerialTree : nLength ), nSerialTree - nOffset ); if ( nLength > nSerialTree || nOffset + nLength > nSerialTree ) { GlobalFree( pSerialTree ); return FALSE; } CString strAnswer; strAnswer.Format( _T("$ADCSND tthl TTH/%s %I64u %I64u|"), m_oTiger.toString(), nOffset, nLength ); m_pClient->SendCommand( strAnswer ); m_pClient->Write( pSerialTree + nOffset, nLength ); // Start uploading m_nOffset = nOffset; m_nLength = nLength; m_nPosition = 0; StartSending( upsTigerTree ); GlobalFree( pSerialTree ); return TRUE; }
BOOL CUploadTransferDC::SendFile() { if ( ! OpenFile() ) { theApp.Message( MSG_ERROR, IDS_UPLOAD_CANTOPEN, (LPCTSTR)m_sName, (LPCTSTR)m_sAddress ); m_pClient->SendCommand( FILE_NOT_AVAILABLE ); return FALSE; } if ( m_bGet ) { m_bGet = FALSE; } else { CString strAnswer; strAnswer.Format( _T("$ADCSND file TTH/%s %I64u %I64u|"), m_oTiger.toString(), m_nOffset, m_nLength ); m_pClient->SendCommand( strAnswer ); } StartSending( upsUploading ); if ( m_pBaseFile->m_nRequests++ == 0 ) { theApp.Message( MSG_NOTICE, IDS_UPLOAD_FILE, (LPCTSTR)m_sName, (LPCTSTR)m_sAddress ); //ASSERT( m_pBaseFile->m_sPath.GetLength() ); PostMainWndMessage( WM_NOWUPLOADING, 0, (LPARAM)new CString( m_pBaseFile->m_sPath ) ); } theApp.Message( MSG_INFO, IDS_UPLOAD_CONTENT, m_nOffset, m_nOffset + m_nLength - 1, (LPCTSTR)m_sName, (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent ); return TRUE; }
void AsioTcpSocket::Sent(const boost::system::error_code& error, size_t transferred) { // если произошла ошибка if(error) { ptr<Exception> exception = AsioService::ConvertError(error); // отправить её всем элементам в очереди, и очистить очередь // скопируем обработчики в вектор, чтобы вызывать их // вне блокировки, и обеспечить реентрантность std::vector<ptr<SendHandler> > handlers; { CriticalCode cc(cs); handlers.resize(sendQueue.size()); size_t j = 0; for(std::deque<SendItem>::iterator i = sendQueue.begin(); i != sendQueue.end(); ++i) handlers[j++] = i->handler; sendQueue.clear(); } for(size_t j = 0; j < handlers.size(); ++j) if(handlers[j]) handlers[j]->FireError(exception); return; } // ошибки нет else { // уведомить все завершившиеся файлы, и удалить их из очереди // скопируем обработчики в вектор, чтобы вызывать их // вне блокировки, и обеспечить реентрантность std::vector<ptr<SendHandler> > handlers; { CriticalCode cc(cs); std::deque<SendItem>::iterator i; for(i = sendQueue.begin(); i != sendQueue.end(); ++i) { const SendItem& item = *i; // если элемент не передался полностью, закончить size_t itemDataSkip = i == sendQueue.begin() ? firstItemSent : 0; size_t itemSize = item.data->GetSize() - itemDataSkip; if(itemSize > transferred) { // этот элемент теперь будет первым, выставить новое смещение firstItemSent = itemDataSkip + transferred; break; } // иначе передался полностью transferred -= itemSize; // добавить обработчик в массив if(item.handler) handlers.push_back(item.handler); } // теперь i указывает на первый элемент, который ещё не передался // удалить всё, что до него sendQueue.erase(sendQueue.begin(), i); // если в очереди что-то есть, запустить отправку снова StartSending(); } for(size_t j = 0; j < handlers.size(); ++j) handlers[j]->FireSuccess(); } }
BOOL CUploadTransferDC::RequestFileList(BOOL bFile, BOOL bZip, const std::string& strFilename, QWORD nOffset, QWORD nLength) { m_pXML.Clear(); theApp.Message( MSG_NOTICE, IDS_UPLOAD_BROWSE, (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent ); BOOL bBZip = bFile && ( strFilename == "files.xml.bz2" ); m_sName = ( bFile ? "/" : strFilename.c_str() ); // Create library file list CAutoPtr< CXMLElement > pXML( LibraryFolders.CreateXML( m_sName, TRUE, xmlDC ) ); if ( ! pXML ) return FALSE; // Out of memory m_pXML.Print( pXML->ToString( TRUE, TRUE, TRUE, TRI_TRUE ), CP_UTF8 ); // ToDo: Implement partial request of file list nOffset = 0; nLength = m_pXML.m_nLength; if ( bBZip ) { // BZip it if ( ! m_pXML.BZip() ) return FALSE; // Out of memory bZip = FALSE; nLength = m_pXML.m_nLength; } if ( bZip ) { // Zip it if ( ! m_pXML.Deflate() ) return FALSE; // Out of memory } m_nOffset = nOffset; m_nLength = m_pXML.m_nLength; m_nPosition = 0; if ( m_bGet ) { CString strAnswer; strAnswer.Format( _T("$FileLength %I64u|"), nLength ); m_pClient->SendCommand( strAnswer ); return TRUE; } CString strAnswer; strAnswer.Format( _T("$ADCSND %hs %hs %I64u %I64u%hs|"), ( bFile ? "file" : "list" ), strFilename.c_str(), nOffset, nLength, ( bZip ? " ZL1" : "") ); m_pClient->SendCommand( strAnswer ); StartSending( upsBrowse ); m_pClient->Write( &m_pXML ); m_pXML.Clear(); return TRUE; }
BOOL CUploadTransferDC::RequestFile(CLibraryFile* pFile, QWORD nOffset, QWORD nLength) { m_pXML.Clear(); if ( ! RequestComplete( pFile ) ) { ASSERT( FALSE ); return FALSE; } if ( ! UploadQueues.CanUpload( PROTOCOL_DC, pFile, FALSE ) ) { theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress, (LPCTSTR)m_sName ); m_pClient->SendCommand( FILE_NOT_AVAILABLE ); return TRUE; } m_nOffset = nOffset; if ( m_nOffset >= m_nSize ) m_nLength = SIZE_UNKNOWN; else m_nLength = min( ( ( nLength == SIZE_UNKNOWN ) ? m_nSize : nLength ), m_nSize - m_nOffset ); m_nPosition = 0; if ( m_nLength > m_nSize || m_nOffset + m_nLength > m_nSize ) { theApp.Message( MSG_ERROR, IDS_UPLOAD_BAD_RANGE, (LPCTSTR)m_sAddress, (LPCTSTR)m_sName ); m_pClient->SendCommand( FILE_NOT_AVAILABLE ); return TRUE; } AllocateBaseFile(); if ( m_bStopTransfer ) { m_tRotateTime = 0; m_bStopTransfer = FALSE; CUploadQueue* pQueue = m_pQueue; if ( pQueue ) pQueue->Dequeue( this ); } int nPosition = UploadQueues.GetPosition( this, TRUE ); if ( nPosition < 0 && UploadQueues.Enqueue( this ) ) { nPosition = UploadQueues.GetPosition( this, TRUE ); } if ( nPosition == 0 ) { // Ready to send if ( m_bGet ) return TRUE; // Wait for $Send return SendFile(); } else if ( nPosition > 0 ) { // Queued theApp.Message( MSG_INFO, IDS_UPLOAD_QUEUED, (LPCTSTR)m_sName, (LPCTSTR)m_sAddress, nPosition, m_pQueue->GetQueuedCount(), (LPCTSTR)m_pQueue->m_sName ); CString strQueued; strQueued.Format( UPLOAD_QUEUE, nPosition ); m_pClient->SendCommand( strQueued ); StartSending( upsPreQueue ); m_tRankingCheck = GetTickCount(); return TRUE; } else { // Unable to queue anywhere UploadQueues.Dequeue( this ); ASSERT( m_pQueue == NULL ); theApp.Message( MSG_ERROR, IDS_UPLOAD_BUSY_QUEUE, (LPCTSTR)m_sName, (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent ); m_pClient->SendCommand( UPLOAD_BUSY ); return TRUE; } }
BOOL CUploadTransferDC::OnUpload(const std::string& strType, const std::string& strFilename, QWORD nOffset, QWORD nLength, const std::string& strOptions) { ASSERT( m_pClient ); if ( m_nState >= upsUploading ) { // Drop unsent data CLockedBuffer pOutput( m_pClient->GetOutput() ); pOutput->Clear(); m_nState = upsRequest; } ClearRequest(); m_sUserAgent = m_pClient->GetUserAgent(); m_pHost = m_pClient->m_pHost; m_sAddress = m_pClient->m_sAddress; UpdateCountry(); m_pClient->m_mInput.pLimit = &Settings.Bandwidth.Request; m_pClient->m_mOutput.pLimit = &m_nBandwidth; m_tRequest = GetTickCount(); BOOL bZip = ( strOptions.find("ZL1") != std::string::npos ); if ( strType == "tthl" ) { m_bGet = FALSE; if ( strFilename.substr( 0, 4 ) == "TTH/" ) { Hashes::TigerHash oTiger; if ( oTiger.fromString( CA2W( strFilename.substr( 4 ).c_str() ) ) ) { CSingleLock oLock( &Library.m_pSection ); if ( oLock.Lock( 1000 ) ) { if ( CLibraryFile* pFile = LibraryMaps.LookupFileByTiger( oTiger, TRUE, TRUE ) ) { if ( RequestTigerTree( pFile, nOffset, nLength ) ) return TRUE; } } } } } else if ( strType == "file" || strType =="get" ) { m_bGet = ( strType == "get" ); if ( strFilename == "files.xml" || strFilename == "files.xml.bz2" ) { if ( RequestFileList( TRUE, bZip, strFilename, nOffset, nLength ) ) return TRUE; } else if ( strFilename.substr( 0, 4 ) == "TTH/" ) { Hashes::TigerHash oTiger; if ( oTiger.fromString( CA2W( strFilename.substr( 4 ).c_str() ) ) ) { CSingleLock oLock( &Library.m_pSection ); if ( oLock.Lock( 1000 ) ) { if ( CLibraryFile* pFile = LibraryMaps.LookupFileByTiger( oTiger, TRUE, TRUE ) ) { if ( RequestFile( pFile, nOffset, nLength ) ) return TRUE; } } } } } else if ( strType == "list" ) { m_bGet = FALSE; if ( RequestFileList( FALSE, bZip, strFilename, nOffset, nLength ) ) return TRUE; } else if ( strType == "send" ) { if ( m_bGet ) { if ( m_pXML.GetCount() ) { // Send cached file list m_bGet = FALSE; StartSending( upsBrowse ); m_pClient->Write( &m_pXML ); m_pXML.Clear(); return TRUE; } else if ( SendFile() ) { // Send already requested file return TRUE; } } // else $Send without $Get } else { // Invalid request type theApp.Message( MSG_ERROR, _T("DC++ Invalid request type from %s"), (LPCTSTR)m_sAddress ); return FALSE; } theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress, (LPCTSTR)CA2CT( strFilename.c_str() ) ); m_pClient->SendCommand( FILE_NOT_AVAILABLE ); return TRUE; }