I2P

Invisible Internet Project


root/src/UploadClient.cpp @ 3fb1afe4edce3fd7fcf12e4a975e612089a8aebd

Revision 3fb1afe4edce3fd7fcf12e4a975e612089a8aebd, 31.2 KB (checked in by mkvore-commit@…, 17 months ago)

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