00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include <algorithm>
00024 #include "Shareaza.h"
00025 #include "Settings.h"
00026 #include "BTClient.h"
00027 #include "BTPacket.h"
00028 #include "Download.h"
00029 #include "DownloadTransferBT.h"
00030 #include "Uploads.h"
00031 #include "UploadFile.h"
00032 #include "UploadFiles.h"
00033 #include "UploadTransferBT.h"
00034 #include "FragmentedFile.h"
00035 #include "TransferFile.h"
00036 #include "Statistics.h"
00037 #include "Buffer.h"
00038
00039 #ifdef _DEBUG
00040 #undef THIS_FILE
00041 static char THIS_FILE[]=__FILE__;
00042 #define new DEBUG_NEW
00043 #endif
00044
00045
00047
00048
00049 CUploadTransferBT::CUploadTransferBT(CBTClient* pClient, CDownload* pDownload) : CUploadTransfer( PROTOCOL_BT )
00050 {
00051 ASSERT( pClient != NULL );
00052 ASSERT( pDownload != NULL );
00053
00054 m_pDownload = pDownload;
00055 m_pClient = pClient;
00056 m_pHost = pClient->m_pHost;
00057 m_sAddress = pClient->m_sAddress;
00058 m_sUserAgent = _T("BitTorrent");
00059
00060 m_nState = upsReady;
00061 m_bInterested = FALSE;
00062 m_bChoked = TRUE;
00063 m_nRandomUnchoke = 0;
00064
00065 RequestPartial( m_pDownload );
00066 m_pDownload->AddUpload( this );
00067 }
00068
00069 CUploadTransferBT::~CUploadTransferBT()
00070 {
00071 ASSERT( m_pClient == NULL );
00072 ASSERT( m_pDownload == NULL );
00073 }
00074
00076
00077
00078 void CUploadTransferBT::SetChoke(BOOL bChoke)
00079 {
00080
00081 if ( ! bChoke ) UploadFiles.MoveToHead( this );
00082
00083
00084 if ( m_bChoked == bChoke ) return;
00085
00086
00087 m_bChoked = bChoke;
00088
00089 m_oRequested.clear();
00090 m_oServed.clear();
00091
00092 if ( bChoke )
00093 {
00094 m_nState = upsReady;
00095 UploadFiles.MoveToTail( this );
00096 }
00097
00098 m_pClient->Send( CBTPacket::New( bChoke ? BT_PACKET_CHOKE : BT_PACKET_UNCHOKE ) );
00099
00100 theApp.Message( MSG_DEBUG, _T("%s upload to %s"),
00101 bChoke ? _T("Choking") : _T("Unchoking"), (LPCTSTR)m_sAddress );
00102 }
00103
00105
00106
00107 void CUploadTransferBT::Close(BOOL bMessage)
00108 {
00109 if ( m_pClient != NULL )
00110 {
00111 m_pClient->m_pUpload = NULL;
00112 m_pClient->Close();
00113 m_pClient = NULL;
00114 }
00115
00116 if ( m_pDiskFile != NULL ) CloseFile();
00117
00118 if ( m_pDownload != NULL ) m_pDownload->RemoveUpload( this );
00119 m_pDownload = NULL;
00120
00121 m_oRequested.clear();
00122 m_oServed.clear();
00123
00124 CUploadTransfer::Close( bMessage );
00125 }
00126
00128
00129
00130 DWORD CUploadTransferBT::GetMeasuredSpeed()
00131 {
00132 if ( m_pClient == NULL ) return 0;
00133 m_pClient->Measure();
00134 return m_pClient->m_mOutput.nMeasure;
00135 }
00136
00138
00139
00140 BOOL CUploadTransferBT::OnConnected()
00141 {
00142 m_pClient->m_mOutput.pLimit = &Uploads.m_nTorrentSpeed;
00143 return TRUE;
00144 }
00145
00147
00148
00149 BOOL CUploadTransferBT::OnRun()
00150 {
00151 if ( m_nState >= upsRequest && ! m_bChoked ) return ServeRequests();
00152 return TRUE;
00153 }
00154
00156
00157
00158 BOOL CUploadTransferBT::OnInterested(CBTPacket* pPacket)
00159 {
00160 if ( m_bInterested ) return TRUE;
00161 m_bInterested = TRUE;
00162 return TRUE;
00163 }
00164
00165 BOOL CUploadTransferBT::OnUninterested(CBTPacket* pPacket)
00166 {
00167 if ( ! m_bInterested ) return TRUE;
00168 m_bInterested = FALSE;
00169 m_nState = upsReady;
00170 return TRUE;
00171 }
00172
00174
00175
00176 BOOL CUploadTransferBT::OnRequest(CBTPacket* pPacket)
00177 {
00178 if ( pPacket->GetRemaining() < 4 * 3 ) return TRUE;
00179 if ( m_bChoked ) return TRUE;
00180
00181 QWORD nIndex = pPacket->ReadLongBE();
00182 QWORD nOffset = pPacket->ReadLongBE();
00183 QWORD nLength = pPacket->ReadLongBE();
00184
00185 nOffset += nIndex * m_pDownload->m_pTorrent.m_nBlockSize;
00186
00187 if ( nLength > Settings.BitTorrent.RequestLimit )
00188 {
00189
00190 theApp.Message( MSG_DEBUG, _T("CUploadTransferBT::OnRequest(): Request size %I64i is too large"), nLength );
00191 Close();
00192 return FALSE;
00193 }
00194
00195 if ( nOffset + nLength > m_nFileSize )
00196 {
00197
00198 theApp.Message( MSG_DEBUG, _T("CUploadTransferBT::OnRequest(): Request through %I64i > %I64i"), nLength, m_nFileSize );
00199 Close();
00200 return FALSE;
00201 }
00202
00203 if ( ::std::find_first_of( m_oRequested.begin(), m_oRequested.end(), m_oServed.begin(), m_oServed.end() )
00204 != m_oRequested.end() ) return TRUE;
00205
00206 m_oRequested.pushBack( FF::SimpleFragment( nOffset, nOffset + nLength ) );
00207
00208 if ( m_nState == upsReady )
00209 {
00210 m_nState = upsRequest;
00211 AllocateBaseFile();
00212 theApp.Message( MSG_SYSTEM, IDS_UPLOAD_FILE,
00213 (LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress );
00214 }
00215
00216 return ServeRequests();
00217 }
00218
00219 BOOL CUploadTransferBT::OnCancel(CBTPacket* pPacket)
00220 {
00221 if ( pPacket->GetRemaining() < 4 * 3 ) return TRUE;
00222
00223 QWORD nIndex = pPacket->ReadLongBE();
00224 QWORD nOffset = pPacket->ReadLongBE();
00225 QWORD nLength = pPacket->ReadLongBE();
00226
00227 nOffset += nIndex * m_pDownload->m_pTorrent.m_nBlockSize;
00228
00229 m_oRequested.erase( FF::SimpleFragment( nOffset, nOffset + nLength ) );
00230
00231 return TRUE;
00232 }
00233
00235
00236
00237 BOOL CUploadTransferBT::OpenFile()
00238 {
00239 ASSERT( m_nState == upsRequest || m_nState == upsUploading );
00240 ASSERT( m_pBaseFile != NULL );
00241
00242 if ( m_pDiskFile != NULL ) return TRUE;
00243 m_pDiskFile = TransferFiles.Open( m_sFilePath, FALSE, FALSE );
00244 if ( m_pDiskFile != NULL ) return TRUE;
00245
00246 theApp.Message( MSG_ERROR, IDS_UPLOAD_CANTOPEN, (LPCTSTR)m_sFileName , (LPCTSTR)m_sAddress);
00247
00248 Close();
00249 return FALSE;
00250 }
00251
00253
00254
00255 BOOL CUploadTransferBT::ServeRequests()
00256 {
00257 ASSERT( m_nState == upsRequest || m_nState == upsUploading );
00258 ASSERT( m_pBaseFile != NULL );
00259 ASSERT( m_nLength == SIZE_UNKNOWN );
00260
00261 if ( m_bChoked ) return TRUE;
00262 if ( m_pClient->m_pOutput->m_nLength > Settings.BitTorrent.RequestSize / 3 ) return TRUE;
00263
00264 while ( !m_oRequested.empty() && m_nLength == SIZE_UNKNOWN )
00265 {
00266 if ( ::std::find( m_oServed.begin(), m_oServed.end(), *m_oRequested.begin() )
00267 == m_oServed.end()
00268
00269 && m_oRequested.begin()->begin() < m_nFileSize
00270 && m_oRequested.begin()->end() <= m_nFileSize )
00271 {
00272 m_nOffset = m_oRequested.begin()->begin();
00273 m_nLength = m_oRequested.begin()->length();
00274 m_nPosition = 0;
00275 }
00276 m_oRequested.popFront();
00277 }
00278
00279 if ( m_nLength < SIZE_UNKNOWN )
00280 {
00281 if ( ! OpenFile() ) return FALSE;
00282
00283 theApp.Message( MSG_DEBUG, IDS_UPLOAD_CONTENT,
00284 m_nOffset, m_nOffset + m_nLength - 1,
00285 (LPCTSTR)m_sFileName, (LPCTSTR)m_sAddress, _T("BT") );
00286
00287 CBuffer* pBuffer = m_pClient->m_pOutput;
00288 pBuffer->EnsureBuffer( sizeof(BT_PIECE_HEADER) + (DWORD)m_nLength );
00289
00290 BT_PIECE_HEADER* pHeader = (BT_PIECE_HEADER*)( pBuffer->m_pBuffer + pBuffer->m_nLength );
00291
00292 if ( ! m_pDiskFile->Read( m_nOffset + m_nPosition, &pHeader[1], m_nLength, &m_nLength ) ) return FALSE;
00293
00294 pHeader->nLength = SWAP_LONG( 1 + 8 + (DWORD)m_nLength );
00295 pHeader->nType = BT_PACKET_PIECE;
00296 pHeader->nPiece = (DWORD)( m_nOffset / m_pDownload->m_pTorrent.m_nBlockSize );
00297 pHeader->nOffset = (DWORD)( m_nOffset % m_pDownload->m_pTorrent.m_nBlockSize );
00298 pHeader->nPiece = SWAP_LONG( pHeader->nPiece );
00299 pHeader->nOffset = SWAP_LONG( pHeader->nOffset );
00300
00301 pBuffer->m_nLength += sizeof(BT_PIECE_HEADER) + (DWORD)m_nLength;
00302 m_pClient->Send( NULL );
00303
00304 m_nPosition += m_nLength;
00305 m_nUploaded += m_nLength;
00306 m_pDownload->m_nTorrentUploaded += m_nLength;
00307 Statistics.Current.Uploads.Volume += ( m_nLength / 1024 );
00308
00309 m_oServed.pushBack( FF::SimpleFragment( m_nOffset, m_nOffset + m_nLength ) );
00310 m_pBaseFile->AddFragment( m_nOffset, m_nLength );
00311
00312 m_nState = upsUploading;
00313 m_nLength = SIZE_UNKNOWN;
00314 }
00315 else
00316 {
00317 m_nState = upsRequest;
00318 }
00319
00320 return TRUE;
00321 }
00322