I2P

Invisible Internet Project


root/src/UploadClient.cpp @ 183e411556713f7079dabf1e90a640900e5fb455

Revision 183e411556713f7079dabf1e90a640900e5fb455, 31.9 KB (checked in by mkvore-commit@…, 16 months ago)

PartFile? merged. Compiled.

Line 
1//
2// This file is part of the imule Project.
3//
4// Copyright (c) 2003-2006 imule Team ( mkvore@mail.i2p / http://www.imule.i2p )
5// Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6//
7// Any parts of this program derived from the xMule, lMule or eMule project,
8// or contributed by third-party developers are copyrighted by their
9// respective authors.
10//
11// This program is free software; you can redistribute it and/or modify
12// it under the terms of the GNU General Public License as published by
13// the Free Software Foundation; either version 2 of the License, or
14// (at your option) any later version.
15//
16// This program is distributed in the hope that it will be useful,
17// but WITHOUT ANY WARRANTY; without even the implied warranty of
18// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19// GNU General Public License for more details.
20//
21// You should have received a copy of the GNU General Public License
22// along with this program; if not, write to the Free Software
23// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
24//
25
26#include <zlib.h>
27#include <cmath>                // Needed for std::exp
28
29#include "OtherFunctions.h"     // Needed for nstrdup
30
31#include "ClientUDPSocket.h"    // Needed for CClientUDPSocket
32#include "ClientCredits.h"      // Needed for CClientCredits
33#include "Packet.h"             // Needed for CPacket
34#include "MemFile.h"            // Needed for CMemFile
35#include "UploadQueue.h"        // Needed for CUploadQueue
36#include "DownloadQueue.h"      // Needed for CDownloadQueue
37#include "Preferences.h"        // Needed for CPreferences
38#include "OtherStructs.h"       // Needed for Requested_Block_Struct
39#include "ServerConnect.h"              // Needed for CServerConnect
40#include "PartFile.h"           // Needed for PR_POWERSHARE
41#include "KnownFile.h"          // Needed for CKnownFile
42#include "KnownFileList.h"              // Needed for CKnownFileLists
43#include "ClientTCPSocket.h"    // Needed for CClientTCPSocket
44#include "SharedFileList.h"     // Needed for CSharedFileList
45#include "imule.h"              // Needed for theApp
46#include "BarShader.h"          // Needed for CBarShader
47#include "updownclient.h"       // Needed for CUpDownClient
48#include "ClientList.h"
49#include "Statistics.h"         // Needed for theStats
50#include "GuiEvents.h"          // Needed for Nofify_... macros
51#include "Logger.h"
52#include <common/Format.h>
53#include "ScopedPtr.h"
54#include <protocol/ed2k/Constants.h>
55#include <protocol/ed2k/Client2Client/TCP.h>
56
57//      members of CUpDownClient
58//      which are mainly used for uploading functions
59
60const uint32_t _average_period = 300 ; // number of seconds for avaraging upload rate per client
61
62void CUpDownClient::SetUploadState(EUploadState eNewState)
63{
64        if (eNewState != m_nUploadState) {
65                if (m_nUploadState == US_UPLOADING) {
66                        // Reset upload data rate computation
67                        m_nUpDatarate = 0;
68                        m_nSumForAvgUpDataRate = 0;
69                        m_AvarageUDR_list.clear();
70                }
71                if (eNewState == US_UPLOADING) {
72                        m_fSentOutOfPartReqs = 0;
73                }
74
75                // don't add any final cleanups for US_NONE here
76                m_nUploadState = eNewState;
77                UpdateDisplayedInfo(true);
78        }
79}
80
81
82#ifndef CLIENT_GUI
83uint32_t CUpDownClient::GetScore(bool sysvalue, bool isdownloading, bool onlybasevalue) const
84{
85        //TODO: complete this (friends, uploadspeed, imuleuser etc etc)
86        if (m_Username.IsEmpty()) {
87                return 0;
88        }
89
90        if (credits == 0) {
91                return 0;
92        }
93
94        const CKnownFile* pFile = GetUploadFile();
95        if ( !pFile ) {
96                return 0;
97        }
98
99        // bad clients (see note in function)
100        if (IsBadGuy()) {
101                return 0;
102        }
103       
104        // friend slot
105        if (IsFriend() && GetFriendSlot() /*&& !HasLowID()*/) {
106                return 0x0FFFFFFF;
107        }
108
109        if (IsBanned())
110                return 0;
111
112        /*if (sysvalue && HasLowID() && !IsConnected()){
113                return 0;
114        }*/     
115
116        // TODO coded by tecxx & herbert, one yet unsolved problem here:
117        // sometimes a client asks for 2 files and there is no way to decide, which file the
118        // client finally gets. so it could happen that he is queued first because of a
119        // high prio file, but then asks for something completely different.
120        int filepriority = 10; // standard
121        if(pFile != NULL){ 
122                switch(pFile->GetUpPriority()) {
123                        case PR_POWERSHARE: //added for powershare (deltaHF)
124                                filepriority = 2500; 
125                                break; //end
126                        case PR_VERYHIGH:
127                                filepriority = 18;
128                                break;
129                        case PR_HIGH:
130                                filepriority = 9;
131                                break;
132                        case PR_LOW:
133                                filepriority = 6;
134                                break;
135                        case PR_VERYLOW:
136                                filepriority = 2;
137                                break;
138                        case PR_NORMAL:
139                        default:
140                                filepriority = 7;
141                                break;
142                }
143        }
144        // calculate score, based on waitingtime and other factors
145        float fBaseValue;
146        if (onlybasevalue) {
147                fBaseValue = 100;
148        } else if (!isdownloading) {
149                fBaseValue = (float)(::GetTickCount()-GetWaitStartTime())/1000;
150        } else {
151                // we dont want one client to download forever
152                // the first 15 min downloadtime counts as 15 min waitingtime and you get
153                // a 15 min bonus while you are in the first 15 min :)
154                // (to avoid 20 sec downloads) after this the score won't raise anymore
155                fBaseValue = (float)(m_dwUploadTime-GetWaitStartTime());
156                wxASSERT( m_dwUploadTime > GetWaitStartTime()); // Obviously
157                fBaseValue += (float)((::GetTickCount() - m_dwUploadTime > 900000)? 900000:1800000);
158                fBaseValue /= 1000;
159        }
160       
161        float modif = GetScoreRatio();
162        fBaseValue *= modif;
163       
164        if (!onlybasevalue) {
165                fBaseValue *= (float(filepriority)/10.0f);
166        }
167        if( (IsEmuleClient() || GetClientSoft() < 10) && m_byEmuleVersion <= 0x19) {
168                fBaseValue *= 0.5f;
169        }
170        return (uint32_t)fBaseValue;
171}
172#endif
173
174// Checks if it is next requested block from another chunk of the actual file or from another file
175//
176// [Returns]
177//   true : Next requested block is from another different chunk or file than last downloaded block
178//   false: Next requested block is from same chunk that last downloaded block
179bool CUpDownClient::IsDifferentPartBlock() const // [Tarod 12/22/2002]
180{ 
181        bool different_part = false;
182       
183        // Check if we have good lists and proceed to check for different chunks
184        if (!m_BlockRequests_queue.empty() && !m_DoneBlocks_list.empty())
185        {
186                Requested_Block_Struct* last_done_block = NULL;
187                Requested_Block_Struct* next_requested_block = NULL;
188                uint64_t last_done_part         = CPartFile::NO_PART;
189                uint64_t next_requested_part    = CPartFile::NO_PART;
190                       
191                       
192                // Get last block and next pending
193        last_done_block = (Requested_Block_Struct*)m_DoneBlocks_list.front();
194        next_requested_block = (Requested_Block_Struct*)m_BlockRequests_queue.front(); 
195                       
196                // Calculate corresponding parts to blocks
197                last_done_part = last_done_block->StartOffset / PARTSIZE;
198                next_requested_part = next_requested_block->StartOffset / PARTSIZE; 
199             
200                // Test is we are asking same file and same part
201                if ( last_done_part != next_requested_part) { 
202                        different_part = true;
203                        AddDebugLogLineM(false, logClient, CFormat(wxT("%x :Session ended due to new chunk.")) % (long) this);
204                }
205       
206                if (md4cmp(last_done_block->FileID, next_requested_block->FileID) != 0) { 
207                        different_part = true;
208                        AddDebugLogLineM(false, logClient, CFormat(wxT("%x :Session ended due to different file.")) % (long) this);
209                }
210        } 
211
212        return different_part; 
213}
214
215
216void CUpDownClient::CreateNextBlockPackage()
217{
218    // See if we can do an early return. There may be no new blocks to load from disk and add to buffer, or buffer may be large enough allready.
219    if(m_BlockRequests_queue.empty() || // There are no new blocks requested
220       m_addedPayloadQueueSession > GetQueueSessionPayloadUp() && m_addedPayloadQueueSession-GetQueueSessionPayloadUp() > 50*1024) { // the buffered data is large enough allready
221        return;
222    }
223
224    CFile file;
225    CPath fullname;
226        try {
227        // Buffer new data if current buffer is less than 100 KBytes
228        while (!m_BlockRequests_queue.empty() &&
229               (m_addedPayloadQueueSession <= GetQueueSessionPayloadUp() || m_addedPayloadQueueSession-GetQueueSessionPayloadUp() < 100*1024)) {
230
231                        Requested_Block_Struct* currentblock = m_BlockRequests_queue.front();
232                        CKnownFile* srcfile = theApp->sharedfiles->GetFileByID(CMD4Hash(currentblock->FileID));
233                       
234                        if (!srcfile) {
235                                throw wxString(wxT("requested file not found"));
236                        }
237
238                        if (srcfile->IsPartFile() && ((CPartFile*)srcfile)->GetStatus() != PS_COMPLETE) {
239//TODO                          #warning This seems a good idea from eMule. We must import this.
240                                #if 0
241                                // Do not access a part file, if it is currently moved into the incoming directory.
242                                // Because the moving of part file into the incoming directory may take a noticable
243                                // amount of time, we can not wait for 'm_FileCompleteMutex' and block the main thread.
244                                if (!((CPartFile*)srcfile)->m_FileCompleteMutex.Lock(0)){ // just do a quick test of the mutex's state and return if it's locked.
245                                        return;
246                                }
247                                lockFile.m_pObject = &((CPartFile*)srcfile)->m_FileCompleteMutex;
248                                // If it's a part file which we are uploading the file remains locked until we've read the
249                                // current block. This way the file completion thread can not (try to) "move" the file into
250                                // the incoming directory.
251                                #endif
252
253                // Get the full path to the '.part' file
254                fullname = dynamic_cast<CPartFile*>(srcfile)->GetFullName().RemoveExt();
255            } else {
256                fullname = srcfile->GetFilePath().JoinPaths(srcfile->GetFileName());
257            }
258               
259                        size_t togo;
260            // THIS EndOffset points BEHIND the last byte requested
261            // (other than the offsets used in the PartFile code)
262            if (currentblock->EndOffset > srcfile->GetFileSize()) {
263                throw wxString(wxT("Asked for data beyond end of file"));
264            } else if (currentblock->StartOffset > currentblock->EndOffset) {
265                throw wxString(wxT("Asked for invalid block (start > end)"));
266            } else {
267                if (currentblock->EndOffset - currentblock->StartOffset >= (1<<sizeof(size_t)))
268                    throw wxString(wxT("Asked for a huge block"));
269               
270                togo = (size_t) (currentblock->EndOffset - currentblock->StartOffset);
271               
272                if (srcfile->IsPartFile() && !((CPartFile*)srcfile)->IsComplete(currentblock->StartOffset,currentblock->EndOffset-1)) {
273                    throw wxString(wxT("Asked for incomplete block "));
274                }
275            }
276
277                        if (togo > (EMBLOCKSIZE * 3)) {
278                                throw wxString(wxT("Client requested too large of a block."));
279                        }
280                       
281            CScopedArray<uint8_t> filedata(NULL);
282            if (!srcfile->IsPartFile()){
283                if ( !file.Open(fullname, CFile::read) ) {
284                    // The file was most likely moved/deleted. However it is likely that the
285                    // same is true for other files, so we recheck all shared files.
286                    AddLogLineM( false, CFormat( _("Failed to open file (%s), removing from list of shared files.") ) % srcfile->GetFileName() );
287                    theApp->sharedfiles->RemoveFile(srcfile);
288                   
289                    throw wxString(wxT("Failed to open requested file: Removing from list of shared files!"));
290                }
291           
292                file.Seek(currentblock->StartOffset, wxFromStart);
293               
294                filedata.reset(new uint8_t[togo + 500]);
295                file.Read(filedata.get(), togo);
296                file.Close();
297            } else {
298                CPartFile* partfile = (CPartFile*)srcfile;
299                partfile->m_hpartfile.Seek(currentblock->StartOffset);
300               
301                filedata.reset(new uint8_t[togo + 500]);
302                partfile->m_hpartfile.Read(filedata.get(), togo);
303                // Partfile should NOT be closed!!!
304            }
305
306
307//TODO                  #warning Part of the above import.
308                        #if 0
309                        if (lockFile.m_pObject){
310                                lockFile.m_pObject->Unlock(); // Unlock the (part) file as soon as we are done with accessing it.
311                                lockFile.m_pObject = NULL;
312                        }
313                        #endif
314       
315                        SetUploadFileID(srcfile);
316
317            // check extention to decide whether to compress or not
318            if (m_byDataCompVer == 1 && GetFiletype(srcfile->GetFileName()) != ftArchive) {
319                CreatePackedPackets(filedata.get(), togo,currentblock);
320            } else {
321                CreateStandartPackets(filedata.get(), togo,currentblock);
322            }
323                       
324                        // file statistic
325                        srcfile->statistic.AddTransferred(togo);
326
327                        m_addedPayloadQueueSession += togo;
328
329            Requested_Block_Struct* block = m_BlockRequests_queue.front();
330           
331            m_BlockRequests_queue.pop_front();
332            m_DoneBlocks_list.push_front(block);
333        }
334
335                return;
336        } catch (const wxString& error) {
337                AddDebugLogLineM(false, logClient, CFormat(wxT("%x :Client '")) % (long) this + GetUserName() + wxT("' caused error while creating packet (") + error + wxT(") - disconnecting client"));
338        } catch (const CIOFailureException& error) {
339                AddDebugLogLineM(true, logClient, CFormat(wxT("%x :IO failure while reading requested file: ")) % (long) this + error.what());
340        } catch (const CEOFException& error) {
341                AddDebugLogLineM(true, logClient, GetClientFullInfo() + wxT(" requested file-data at an invalid position - disconnecting"));
342        }
343       
344        // Error occured.       
345        theApp->uploadqueue->RemoveFromUploadQueue(this);
346}
347
348
349void CUpDownClient::CreateStandartPackets(const uint8_t* buffer, uint32_t togo, Requested_Block_Struct* currentblock)
350{
351        uint32_t nPacketSize;
352
353        CMemFile memfile((uint8_t*)buffer, togo);
354        if (togo > 10240) {
355                nPacketSize = togo/(uint32_t)(togo/10240);
356        } else {
357                nPacketSize = togo;
358        }
359
360        while (togo){
361                if (togo < nPacketSize*2) {
362                        nPacketSize = togo;
363                }
364               
365                wxASSERT(nPacketSize);
366                togo -= nPacketSize;
367               
368                CMemFile data(nPacketSize+32);
369                data.WriteHash(GetUploadFileID());
370                data.WriteUInt64(((currentblock->EndOffset - togo) - nPacketSize));
371                data.WriteUInt64(((currentblock->EndOffset - togo)));
372                char *tempbuf = new char[nPacketSize];
373                memfile.Read(tempbuf, nPacketSize);
374                data.Write(tempbuf, nPacketSize);
375                delete [] tempbuf;
376                CPacket* packet = new CPacket(data,OP_EDONKEYPROT,OP_SENDINGPART);
377       
378                theStats::AddUpOverheadFileRequest(24);
379                theStats::AddUploadToSoft(GetClientSoft(), nPacketSize);
380                m_socket->SendPacket(packet,true,false, nPacketSize);
381        }
382}
383
384
385void CUpDownClient::CreatePackedPackets(const uint8_t* buffer, uint32_t togo, Requested_Block_Struct* currentblock)
386{
387        uint8_t* output = new uint8_t[togo+300];
388        uLongf newsize = togo+300;
389        uint32_t result = compress2(output, &newsize, buffer, togo, 9);
390        wxASSERT( result <= (uint16_t) -1 );
391        if (result != Z_OK || togo <= newsize){
392                delete[] output;
393                CreateStandartPackets(buffer, togo, currentblock);
394                return;
395        }
396       
397        CMemFile memfile(output,newsize);
398       
399        uint32_t totalPayloadSize = 0;
400        uint32_t oldSize = togo;
401        togo = newsize;
402        uint32_t nPacketSize;
403        if (togo > 10240) {
404                nPacketSize = togo/(uint32_t)(togo/10240);
405        } else {
406                nPacketSize = togo;
407        }
408               
409        while (togo) {
410                if (togo < nPacketSize*2) {
411                        nPacketSize = togo;
412                }
413                togo -= nPacketSize;
414
415                CMemFile data(nPacketSize+24);
416                data.WriteHash(GetUploadFileID());
417                data.WriteUInt64(currentblock->StartOffset);
418                data.WriteUInt32(newsize);                     
419                char *tempbuf = new char[nPacketSize];
420                memfile.Read(tempbuf, nPacketSize);
421                data.Write(tempbuf,nPacketSize);
422                delete [] tempbuf;
423                CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_COMPRESSEDPART);
424       
425                // approximate payload size
426                uint32_t payloadSize = nPacketSize*oldSize/newsize;
427
428                if (togo == 0 && totalPayloadSize+payloadSize < oldSize) {
429                        payloadSize = oldSize-totalPayloadSize;
430                }
431               
432                totalPayloadSize += payloadSize;
433
434                // put packet directly on socket
435                theStats::AddUpOverheadFileRequest(24);
436                theStats::AddUploadToSoft(GetClientSoft(), nPacketSize);
437                m_socket->SendPacket(packet,true,false, payloadSize);                   
438        }
439        delete[] output;
440}
441
442
443void CUpDownClient::ProcessExtendedInfo(const CMemFile *data, CKnownFile *tempreqfile)
444{
445        m_uploadingfile->UpdateUpPartsFrequency( this, false ); // Decrement
446        m_upPartStatus.clear();         
447        m_nUpCompleteSourcesCount= 0;
448       
449        if( GetExtendedRequestsVersion() == 0 ) {
450                // Something is coded wrong on this client if he's sending something it doesn't advertise.
451                return;
452        }
453       
454        if (data->GetLength() == 16) {
455                // Wrong again. Advertised >0 but send a 0-type packet.
456                // But this time we'll disconnect it.
457                throw CInvalidPacket(wxT("Wrong size on extended info packet"));
458        }
459       
460        uint64_t nED2KUpPartCount = data->ReadUInt64();
461        if (!nED2KUpPartCount) {
462                m_upPartStatus.resize( tempreqfile->GetPartCount(), 0 );
463        } else {
464                if (tempreqfile->GetED2KPartCount() != nED2KUpPartCount) {
465                        // We already checked if we are talking about the same file.. So if we get here, something really strange happened!
466                        m_upPartStatus.clear();
467                        return;
468                }
469       
470                m_upPartStatus.resize( tempreqfile->GetPartCount(), 0 );
471       
472                try {
473                        uint16_t done = 0;
474                        while (done != m_upPartStatus.size()) {
475                                uint8_t toread = data->ReadUInt8();
476                                for (int32_t i = 0;i != 8;i++){
477                                        m_upPartStatus[done] = (toread>>i)&1;
478                                        //      We may want to use this for another feature..
479                                        //      if (m_upPartStatus[done] && !tempreqfile->IsComplete(done*PARTSIZE,((done+1)*PARTSIZE)-1))
480                                        // bPartsNeeded = true;
481                                        done++;
482                                        if (done == m_upPartStatus.size()) {
483                                                break;
484                                        }
485                                }
486                        }
487                } catch (...) {
488                        // We want the increment the frequency even if we didn't read everything
489                        m_uploadingfile->UpdateUpPartsFrequency( this, true ); // Increment
490                       
491                        throw;
492                }
493
494                if (GetExtendedRequestsVersion() > 1) {
495                        uint16_t nCompleteCountLast = GetUpCompleteSourcesCount();
496                        uint16_t nCompleteCountNew = data->ReadUInt16();
497                        SetUpCompleteSourcesCount(nCompleteCountNew);
498                        if (nCompleteCountLast != nCompleteCountNew) {
499                                tempreqfile->UpdatePartsInfo();
500                        }
501                }
502        }
503       
504        m_uploadingfile->UpdateUpPartsFrequency( this, true ); // Increment
505       
506        Notify_QlistRefreshClient(this);
507}
508
509
510void CUpDownClient::SetUploadFileID(CKnownFile* newreqfile)
511{
512        if (m_uploadingfile == newreqfile) {
513                return;
514        } else if (m_uploadingfile) {
515                m_uploadingfile->RemoveUploadingClient(this);
516                m_uploadingfile->UpdateUpPartsFrequency(this, false); // Decrement
517        }
518       
519        if (newreqfile) {
520                // This is a new file! update info
521                newreqfile->AddUploadingClient(this);
522               
523                if (m_requpfileid != newreqfile->GetFileHash()) {
524                        m_requpfileid = newreqfile->GetFileHash();
525                        m_upPartStatus.clear();
526                        m_upPartStatus.resize( newreqfile->GetPartCount(), 0 );
527                } else {
528                        // this is the same file we already had assigned. Only update data.
529                        newreqfile->UpdateUpPartsFrequency(this, true); // Increment
530                }
531               
532                m_uploadingfile = newreqfile;
533        } else {
534                m_upPartStatus.clear();
535                m_nUpCompleteSourcesCount = 0;
536                // This clears m_uploadingfile and m_requpfileid
537                ClearUploadFileID();
538        }
539}
540
541
542void CUpDownClient::AddReqBlock(Requested_Block_Struct* reqblock)
543{
544        if (GetUploadState() != US_UPLOADING) {
545                AddDebugLogLineM(false, logRemoteClient, wxT("UploadClient: Client tried to add requested block when not in upload slot! Prevented requested blocks from being added."));
546                delete reqblock;
547                return;
548        }
549       
550    {
551        std::list<Requested_Block_Struct*>::iterator it = m_DoneBlocks_list.begin();
552        for (; it != m_DoneBlocks_list.end(); ++it) {
553            if (reqblock->StartOffset == (*it)->StartOffset && reqblock->EndOffset == (*it)->EndOffset) {
554                delete reqblock;
555                return;
556            }
557        }
558    }
559
560    {
561        std::list<Requested_Block_Struct*>::iterator it = m_BlockRequests_queue.begin();
562        for (; it != m_BlockRequests_queue.end(); ++it) {
563            if (reqblock->StartOffset == (*it)->StartOffset && reqblock->EndOffset == (*it)->EndOffset) {
564                delete reqblock;
565                return;
566            }
567        }
568    }
569   
570    m_BlockRequests_queue.push_back(reqblock);
571
572}
573
574uint32_t CUpDownClient::GetWaitStartTime() const
575{
576        uint32_t dwResult = 0;
577       
578        if ( credits ) {
579                dwResult = credits->GetSecureWaitStartTime(GetTCPDest/*IP*/());
580               
581                if (dwResult > m_dwUploadTime && IsDownloading()) {
582                        // This happens only if two clients with invalid securehash are in the queue - if at all
583                        dwResult = m_dwUploadTime - 1;
584                }
585        }
586               
587        return dwResult;
588}
589
590
591void CUpDownClient::SetWaitStartTime()
592{
593        if ( credits ) {
594                credits->SetSecWaitStartTime(GetTCPDest/*IP*/());
595        }
596}
597
598
599void CUpDownClient::ClearWaitStartTime()
600{
601        if ( credits ) {
602                credits->ClearWaitStartTime();
603        }
604}
605
606
607uint32_t CUpDownClient::SendBlockData()
608{
609    uint32_t curTick = ::GetTickCount();
610    uint64_t sentBytesCompleteFile = 0;
611    uint64_t sentBytesPartFile = 0;
612    uint64_t sentBytesPayload = 0;
613
614        if ( m_socket )
615        {
616                CEMSocket* s = m_socket;
617        //              uint32_t uUpStatsPort = GetUserPort();
618       
619                // Extended statistics information based on which client software and which port we sent this data to...
620                // This also updates the grand total for sent bytes, etc.  And where this data came from.
621                sentBytesCompleteFile = s->GetSentBytesCompleteFileSinceLastCallAndReset();
622                sentBytesPartFile = s->GetSentBytesPartFileSinceLastCallAndReset();
623        //              thePrefs.Add2SessionTransferData(GetClientSoft(), uUpStatsPort, false, true, sentBytesCompleteFile, (IsFriend() && GetFriendSlot()));
624        //              thePrefs.Add2SessionTransferData(GetClientSoft(), uUpStatsPort, true, true, sentBytesPartFile, (IsFriend() && GetFriendSlot()));
625       
626                m_nTransferredUp += sentBytesCompleteFile + sentBytesPartFile;
627                credits->AddUploaded ( ( uint32_t ) ( sentBytesCompleteFile + sentBytesPartFile ),
628                                       GetTCPDest/*IP*/(), theApp->CryptoAvailable() );
629       
630                sentBytesPayload = s->GetSentPayloadSinceLastCallAndReset();
631                m_nCurQueueSessionPayloadUp += sentBytesPayload;
632       
633                if ( theApp->uploadqueue->CheckForTimeOver ( this ) )
634                {
635                        theApp->uploadqueue->RemoveFromUploadQueue ( this, true );
636                        SendOutOfPartReqsAndAddToWaitingQueue();
637                }
638                else
639                {
640                        // read blocks from file and put on socket
641                        CreateNextBlockPackage();
642                }
643        }
644       
645        if ( sentBytesCompleteFile + sentBytesPartFile > 0 ||
646                m_AvarageUDR_list.size() == 0 || ( curTick - m_AvarageUDR_list.back().timestamp ) > 1*1000 )
647        {
648                // Store how much data we've transferred this round,
649                // to be able to calculate average speed later
650                // keep sum of all values in list up to date
651                TransferredData newitem = { (uint32_t) (sentBytesCompleteFile + sentBytesPartFile), curTick};
652                m_AvarageUDR_list.push_back ( newitem );
653                m_nSumForAvgUpDataRate += sentBytesCompleteFile + sentBytesPartFile;
654        }
655       
656        // remove too old values in list
657        while ( m_AvarageUDR_list.size() > 0 && ( curTick - m_AvarageUDR_list.front().timestamp ) > _average_period*1000 )
658        {
659                // keep sum of all values in list up to date
660        m_nSumForAvgUpDataRate -= m_AvarageUDR_list.front().datalen;
661        m_AvarageUDR_list.pop_front();
662        }
663       
664        // Calculate average speed for this slot
665        if ( m_AvarageUDR_list.size() > 0 && ( curTick - m_AvarageUDR_list.front().timestamp ) > 0 && GetUpStartTimeDelay() > 2*1000 )
666        {
667                m_nUpDatarate = (uint32_t)
668                                (( m_nSumForAvgUpDataRate * (uint64_t)1000 ) /
669                                (uint64_t) ( curTick-m_AvarageUDR_list.front().timestamp ));
670        }
671        else
672        {
673                // not enough values to calculate trustworthy speed. Use -1 to tell this
674                m_nUpDatarate = 0; //-1;
675        }
676       
677        // Check if it's time to update the display.
678        m_cSendblock++;
679        if ( m_cSendblock == 30 )
680        {
681                m_cSendblock = 0;
682                Notify_UploadCtrlRefreshClient ( this );
683        }
684       
685        return (uint32_t) (sentBytesCompleteFile + sentBytesPartFile);
686        }
687
688
689void CUpDownClient::SendOutOfPartReqsAndAddToWaitingQueue()
690{
691        // Kry - this is actually taken from eMule, but makes a lot of sense ;)
692       
693        //OP_OUTOFPARTREQS will tell the downloading client to go back to OnQueue..
694        //The main reason for this is that if we put the client back on queue and it goes
695        //back to the upload before the socket times out... We get a situation where the
696        //downloader thinks it already sent the requested blocks and the uploader thinks
697        //the downloader didn't send any request blocks. Then the connection times out..
698        //I did some tests with eDonkey also and it seems to work well with them also..
699       
700        AddDebugLogLineM(false, logLocalClient, CFormat(wxT("%x (%s --> %s): Local client %x : Sending OP_OUTOFPARTREQS")) % (long) m_socket % m_socket->GetLocal().humanReadable() % m_socket->GetPeer().humanReadable() % (long) this);
701       
702        // Send this inmediately, don't queue.
703        CPacket* pPacket = new CPacket(OP_OUTOFPARTREQS, 0);
704        theStats::AddUpOverheadFileRequest(pPacket->GetPacketSize());
705        SendPacket(pPacket, true, true);
706       
707        theApp->uploadqueue->AddClientToQueue(this);
708}
709
710
711/**
712 * See description for CEMSocket::TruncateQueues().
713 */
714void CUpDownClient::FlushSendBlocks()
715{
716        // Call this when you stop upload, or the socket might be not able to send
717    if (m_socket) {    //socket may be NULL...
718        m_socket->TruncateQueues();
719        }
720}
721
722
723void CUpDownClient::SendHashsetPacket(const CMD4Hash& forfileid)
724{
725        CKnownFile* file = theApp->sharedfiles->GetFileByID( forfileid );
726        bool from_dq = false;
727        if ( !file ) {
728                from_dq = true;
729                if ((file = theApp->downloadqueue->GetFileByID(forfileid)) == NULL) {
730                        AddLogLineM(false, CFormat( _("Hashset requested for unknown file: %s") ) % forfileid.Encode() );
731               
732                        return;
733                }
734        }
735       
736        if ( !file->GetHashCount() ) {
737                if (from_dq) {
738                        AddDebugLogLineM(false, logRemoteClient, wxT("Requested hashset could not be found")); 
739                        return;
740                } else {
741                        file = theApp->downloadqueue->GetFileByID(forfileid);
742                        if (!(file && file->GetHashCount())) {
743                                AddDebugLogLineM(false, logRemoteClient, wxT("Requested hashset could not be found")); 
744                                return;                         
745                        }
746                }
747        }       
748
749        CMemFile data(1024);
750        data.WriteHash(file->GetFileHash());
751        uint64_t parts = file->GetHashCount();
752        data.WriteUInt64(parts);
753        for (int i = 0; i != parts; i++) {
754                data.WriteHash(file->GetPartHash(i));
755        }
756        CPacket* packet = new CPacket(data);
757        packet->SetOpCode(OP_HASHSETANSWER);
758        theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
759        SendPacket(packet,true,true);
760}
761
762
763void CUpDownClient::ClearUploadBlockRequests()
764{
765    FlushSendBlocks();
766    DeleteContents(m_BlockRequests_queue);
767    DeleteContents(m_DoneBlocks_list);
768}
769
770
771void CUpDownClient::SendRankingInfo(){
772        if (!ExtProtocolAvailable()) {
773                return;
774        }
775
776        uint16_t nRank = theApp->uploadqueue->GetWaitingPosition(this);
777        if (!nRank) {
778                return;
779        }
780               
781        CMemFile data;
782        data.WriteUInt16(nRank);
783        // Kry: what are these zero bytes for. are they really correct?
784        // Kry - Well, eMule does like that. I guess they're ok.
785        data.WriteUInt32(0); 
786        data.WriteUInt32(0); 
787        data.WriteUInt16(0);
788
789        AddDebugLogLineM(false, logLocalClient, CFormat(wxT("%x (%s --> %s): Local client %x : OP_QUEUERANKING ")) % (long) m_socket % m_socket->GetLocal().humanReadable() % m_socket->GetPeer().humanReadable() % (long) this);
790        CPacket* packet = new CPacket(data,OP_EMULEPROT);
791        packet->SetOpCode(OP_QUEUERANKING);
792       
793        theStats::AddUpOverheadOther(packet->GetPacketSize());
794        SendPacket(packet,true,true);
795}
796
797
798void CUpDownClient::SendCommentInfo(CKnownFile* file)
799{
800        if (!m_bCommentDirty || file == NULL || !ExtProtocolAvailable() || m_byAcceptCommentVer < 1) {
801                return;
802        }
803        m_bCommentDirty = false;
804
805        // We used to limit the comment to 50 before, now we do not anymore.
806        const wxString& desc = file->GetFileComment();
807        uint8_t rating = file->GetFileRating();
808       
809        if ( file->GetFileRating() == 0 && desc.IsEmpty() ) {
810                return;
811        }
812       
813        CMemFile data(256);
814        data.WriteUInt8(rating);
815        data.WriteString(desc, GetUnicodeSupport(), 4 /* size it's uint32_t */);
816       
817        AddDebugLogLineM(false, logLocalClient, CFormat(wxT("%x (%s --> %s): Local client %x : OP_FILEDESC")) % (long) m_socket % m_socket->GetLocal().humanReadable() % m_socket->GetPeer().humanReadable() % (long) this);   
818        CPacket* packet = new CPacket(data,OP_EMULEPROT);
819        packet->SetOpCode(OP_FILEDESC);
820        theStats::AddUpOverheadOther(packet->GetPacketSize());
821        SendPacket(packet,true);
822}
823
824void  CUpDownClient::UnBan(){
825        m_Aggressiveness = 0;
826       
827        theApp->clientlist->AddTrackClient(this);
828        theApp->clientlist->RemoveBannedClient( GetTCPDest/*IP*/() );
829        SetUploadState(US_NONE);
830        ClearWaitStartTime();
831       
832        Notify_ShowQueueCount(theStats::GetWaitingUserCount());
833}
834
835void CUpDownClient::Ban(){
836        theApp->clientlist->AddTrackClient(this);
837        theApp->clientlist->AddBannedClient( GetTCPDest/*IP*/() );
838       
839        AddDebugLogLineM( false, logClient, CFormat(wxT("%x :Client '")) % (long) this + GetUserName() + wxT("' seems to be an aggressive client and is banned from the uploadqueue"));
840       
841        SetUploadState(US_BANNED);
842       
843        Notify_ShowQueueCount(theStats::GetWaitingUserCount());
844        Notify_QlistRefreshClient(this);
845}
846
847bool CUpDownClient::IsBanned() const
848{
849        return ( (theApp->clientlist->IsBannedClient(GetTCPDest/*IP*/()) ) && m_nDownloadState != DS_DOWNLOADING);
850}
851
852void CUpDownClient::CheckForAggressive()
853{
854        uint32_t cur_time = ::GetTickCount();
855       
856        // First call, initalize
857        if ( !m_LastFileRequest ) {
858                m_LastFileRequest = cur_time;
859                return;
860        }
861       
862        // Is this an aggressive request?
863        if ( ( cur_time - m_LastFileRequest ) < MIN_REQUESTTIME ) {
864                m_Aggressiveness = (uint16_t) (m_Aggressiveness + 3);
865               
866                // Is the client EVIL?
867                if ( m_Aggressiveness >= 10 && (!IsBanned() && m_nDownloadState != DS_DOWNLOADING )) {
868                        AddDebugLogLineM( false, logClient, CFormat( wxT("Aggressive client banned (score: %d): %s -- %s -- %s") ) 
869                                % m_Aggressiveness
870                                % m_Username
871                                % m_strModVersion
872                                % m_fullClientVerString );
873                        Ban();
874                }
875        } else {
876                // Polite request, reward client
877                if ( m_Aggressiveness )
878                        m_Aggressiveness--;
879        }
880
881        m_LastFileRequest = cur_time;
882}
883
884
885void CUpDownClient::SetUploadFileID(const CMD4Hash& new_id)
886{
887        // Update the uploading file found
888        CKnownFile* uploadingfile = theApp->sharedfiles->GetFileByID(new_id);
889        if ( !uploadingfile ) {
890                // Can this really happen?
891                uploadingfile = theApp->downloadqueue->GetFileByID(new_id);
892        }
893        SetUploadFileID(uploadingfile); // This will update queue count on old and new file.
894}
895
896void CUpDownClient::ProcessRequestPartsPacket(const byte* pachPacket, uint32 nSize, bool largeblocks) {
897       
898        CMemFile data(pachPacket, nSize);
899       
900        CMD4Hash reqfilehash = data.ReadHash();
901       
902        uint64 auStartOffsets[3];
903        uint64 auEndOffsets[3];
904       
905        if (largeblocks) {
906                auStartOffsets[0] = data.ReadUInt64();
907                auStartOffsets[1] = data.ReadUInt64();
908                auStartOffsets[2] = data.ReadUInt64();
909               
910                auEndOffsets[0] = data.ReadUInt64();
911                auEndOffsets[1] = data.ReadUInt64();
912                auEndOffsets[2] = data.ReadUInt64();
913        } else {
914                auStartOffsets[0] = data.ReadUInt32();
915                auStartOffsets[1] = data.ReadUInt32();
916                auStartOffsets[2] = data.ReadUInt32();
917               
918                auEndOffsets[0] = data.ReadUInt32();
919                auEndOffsets[1] = data.ReadUInt32();
920                auEndOffsets[2] = data.ReadUInt32();           
921        }
922       
923        for (unsigned int i = 0; i < itemsof(auStartOffsets); i++) {
924                AddDebugLogLineM(false, logClient,
925                        wxString::Format(wxT("Client requests %u"), i)
926                        + wxT(" ") + wxString::Format(wxT("File block %u-%u (%d bytes):"), auStartOffsets[i], auEndOffsets[i], auEndOffsets[i] - auStartOffsets[i])
927                        + wxT(" ") + GetTCPDest().humanReadable());
928                if (auEndOffsets[i] > auStartOffsets[i]) {
929                        Requested_Block_Struct* reqblock = new Requested_Block_Struct;
930                        reqblock->StartOffset = auStartOffsets[i];
931                        reqblock->EndOffset = auEndOffsets[i];
932                        md4cpy(reqblock->FileID, reqfilehash.GetHash());
933                        reqblock->transferred = 0;
934                        AddReqBlock(reqblock);
935                } else {
936                        if (auEndOffsets[i] != 0 || auStartOffsets[i] != 0) {
937                                AddDebugLogLineM(false, logClient, wxT("Client request is invalid!"));
938                        }
939                }
940        }       
941}
942
943void CUpDownClient::ProcessRequestPartsPacketv2(const CMemFile& data) {
944       
945        CMD4Hash reqfilehash = data.ReadHash();
946       
947        uint8 numblocks = data.ReadUInt8();
948       
949        for (int i = 0; i < numblocks; i++) {           
950                Requested_Block_Struct* reqblock = new Requested_Block_Struct;
951                try {
952                        reqblock->StartOffset = CTag(data).GetInt();
953                        // We have to do +1, because the block matching uses that.
954                        reqblock->EndOffset = CTag(data).GetInt() + 1;
955                        if ((reqblock->StartOffset || reqblock->EndOffset) && (reqblock->StartOffset > reqblock->EndOffset)) {
956                                AddDebugLogLineM(false, logClient, wxString::Format(wxT("Client request is invalid! %i / %i"),reqblock->StartOffset, reqblock->EndOffset));
957                                throw wxString(wxT("Client request is invalid!"));
958                        }
959                       
960                        AddDebugLogLineM(false, logClient,
961                                wxString::Format(wxT("Client requests %u"), i)
962                                + wxT(" ") + wxString::Format(wxT("File block %u-%u (%d bytes):"),reqblock->StartOffset, reqblock->EndOffset, reqblock->EndOffset - reqblock->StartOffset)
963                                += wxT(" ") + GetTCPDest().humanReadable());
964                       
965                        md4cpy(reqblock->FileID, reqfilehash.GetHash());
966                        reqblock->transferred = 0;
967                        AddReqBlock(reqblock);
968                } catch (...) {
969                        delete reqblock;
970                        throw;
971                }
972        }
973}
974// File_checked_for_headers
Note: See TracBrowser for help on using the browser.