1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 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"		// Needed for CUpDownClient
27 
28 #include <protocol/Protocols.h>
29 #include <protocol/ed2k/Client2Client/TCP.h>
30 #include <protocol/ed2k/Client2Client/UDP.h>
31 #include <common/EventIDs.h>
32 #include <common/Macros.h>
33 #include <common/Constants.h>
34 
35 #include <zlib.h>
36 #include <cmath>		// Needed for std:exp
37 
38 #include "ClientCredits.h"	// Needed for CClientCredits
39 #include "ClientUDPSocket.h"	// Needed for CClientUDPSocket
40 #include "DownloadQueue.h"	// Needed for CDownloadQueue
41 #include "Preferences.h"	// Needed for thePrefs
42 #include "Packet.h"		// Needed for CPacket
43 #include "MemFile.h"		// Needed for CMemFile
44 #include "ClientTCPSocket.h"// Needed for CClientTCPSocket
45 #include "ListenSocket.h"	// Needed for CListenSocket
46 #include "amule.h"		// Needed for theApp
47 #include "PartFile.h"		// Needed for CPartFile
48 #include "SharedFileList.h"
49 #include "Statistics.h"		// Needed for theStats
50 #include "Logger.h"
51 #include "GuiEvents.h"		// Needed for Notify_*
52 #include "UploadQueue.h"	// Needed for CUploadQueue
53 
54 
55 #ifdef __MULE_UNUSED_CODE__
56 // This function is left as a reminder.
57 // Changes here _must_ be reflected in CClientList::FindMatchingClient.
Compare(const CUpDownClient * tocomp,bool bIgnoreUserhash) const58 bool CUpDownClient::Compare(const CUpDownClient* tocomp, bool bIgnoreUserhash) const
59 {
60 	if (!tocomp) {
61 		// should we wxASSERT here?
62 		return false;
63 	}
64 
65 	//Compare only the user hash..
66 	if(!bIgnoreUserhash && HasValidHash() && tocomp->HasValidHash()) {
67 	    return GetUserHash() == tocomp->GetUserHash();
68 	}
69 
70 	if (HasLowID()) {
71 		//User is firewalled.. Must do two checks..
72 		if (GetIP()!=0	&& GetIP() == tocomp->GetIP()) {
73 			//The IP of both match
74 			if (GetUserPort()!=0 && GetUserPort() == tocomp->GetUserPort()) {
75 				//IP-UserPort matches
76 				return true;
77 			}
78 			if (GetKadPort()!=0	&& GetKadPort() == tocomp->GetKadPort()) {
79 				//IP-KadPort Matches
80 				return true;
81 			}
82 		}
83 
84 		if (GetUserIDHybrid()!=0
85 						&& GetUserIDHybrid() == tocomp->GetUserIDHybrid()
86 						&& GetServerIP()!=0
87 						&& GetServerIP() == tocomp->GetServerIP()
88 						&& GetServerPort()!=0
89 						&& GetServerPort() == tocomp->GetServerPort()) {
90 			//Both have the same lowID, Same serverIP and Port..
91 			return true;
92 		}
93 
94 		//Both IP, and Server do not match..
95 		return false;
96     }
97 
98 	//User is not firewalled.
99 	if (GetUserPort()!=0) {
100 		//User has a Port, lets check the rest.
101 		if (GetIP() != 0 && tocomp->GetIP() != 0) {
102 			//Both clients have a verified IP..
103 			if(GetIP() == tocomp->GetIP() && GetUserPort() == tocomp->GetUserPort()) {
104 				//IP and UserPort match..
105 				return true;
106 			}
107 		} else {
108 			//One of the two clients do not have a verified IP
109 			if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetUserPort() == tocomp->GetUserPort()) {
110 				//ID and Port Match..
111 				return true;
112 			}
113 		}
114     }
115 
116 	if(GetKadPort()!=0) {
117 		//User has a Kad Port.
118 		if(GetIP() != 0 && tocomp->GetIP() != 0) {
119 			//Both clients have a verified IP.
120 			if(GetIP() == tocomp->GetIP() && GetKadPort() == tocomp->GetKadPort()) {
121 				//IP and KadPort Match..
122 				return true;
123 			}
124 		} else {
125 			//One of the users do not have a verified IP.
126 			if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetKadPort() == tocomp->GetKadPort()) {
127 				//ID and KadProt Match..
128 				return true;
129 			}
130 		}
131 	}
132 
133 	//No Matches..
134 	return false;
135 }
136 #endif
137 
138 
AskForDownload()139 bool CUpDownClient::AskForDownload()
140 {
141 	// 0.42e
142 	if (theApp->listensocket->TooManySockets()) {
143 		if (!m_socket) {
144 			if (GetDownloadState() != DS_TOOMANYCONNS) {
145 				SetDownloadState(DS_TOOMANYCONNS);
146 			}
147 			return true;
148 		} else if (!m_socket->IsConnected()) {
149 			if (GetDownloadState() != DS_TOOMANYCONNS) {
150 				SetDownloadState(DS_TOOMANYCONNS);
151 			}
152 			return true;
153 		}
154 	}
155 	m_bUDPPending = false;
156 	m_dwLastAskedTime = ::GetTickCount();
157 	SetDownloadState(DS_CONNECTING);
158 	SetSentCancelTransfer(0);
159 	return TryToConnect();
160 }
161 
162 
SendStartupLoadReq()163 void CUpDownClient::SendStartupLoadReq()
164 {
165 	// 0.42e
166 	if (m_socket==NULL || m_reqfile==NULL) {
167 		return;
168 	}
169 	SetDownloadState(DS_ONQUEUE);
170 	CMemFile dataStartupLoadReq(16);
171 	dataStartupLoadReq.WriteHash(m_reqfile->GetFileHash());
172 	CPacket* packet = new CPacket(dataStartupLoadReq, OP_EDONKEYPROT, OP_STARTUPLOADREQ);
173 	theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
174 	AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_STARTUPLOADREQ to ") + GetFullIP());
175 	SendPacket(packet, true, true);
176 }
177 
178 
IsSourceRequestAllowed()179 bool CUpDownClient::IsSourceRequestAllowed()
180 {
181 	//#warning REWRITE - Source swapping from eMule.
182 	// 0.42e
183 	uint32 dwTickCount = ::GetTickCount() + CONNECTION_LATENCY;
184 	uint32 nTimePassedClient = dwTickCount - GetLastSrcAnswerTime();
185 	uint32 nTimePassedFile   = dwTickCount - m_reqfile->GetLastAnsweredTime();
186 	bool bNeverAskedBefore = (GetLastAskedForSources() == 0);
187 
188 	uint32 uSources = m_reqfile->GetSourceCount();
189 	return (
190 		// if client has the correct extended protocol
191 		ExtProtocolAvailable() && (SupportsSourceExchange2() || GetSourceExchange1Version() > 1) &&
192 		// AND if we need more sources
193 		thePrefs::GetMaxSourcePerFileSoft() > uSources &&
194 		// AND if...
195 		(
196 		//source is not complete and file is very rare
197 			( !m_bCompleteSource
198 			&& (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASKS)
199 			&& (uSources <= RARE_FILE/5)
200 			) ||
201 			//source is not complete and file is rare
202 			( !m_bCompleteSource
203 			&& (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASKS)
204 			&& (uSources <= RARE_FILE || uSources - m_reqfile->GetValidSourcesCount() <= RARE_FILE / 2)
205 			&& (nTimePassedFile > SOURCECLIENTREASKF)
206 			) ||
207 			// OR if file is not rare
208 			( (bNeverAskedBefore || nTimePassedClient > (unsigned)(SOURCECLIENTREASKS * MINCOMMONPENALTY))
209 			&& (nTimePassedFile > (unsigned)(SOURCECLIENTREASKF * MINCOMMONPENALTY))
210 			)
211 		)
212 	);
213 }
214 
215 
SendFileRequest()216 void CUpDownClient::SendFileRequest()
217 {
218 	wxCHECK_RET(m_reqfile, wxT("Cannot request file when no reqfile is set"));
219 
220 	CMemFile dataFileReq(16+16);
221 	dataFileReq.WriteHash(m_reqfile->GetFileHash());
222 
223 	if (SupportMultiPacket()) {
224 		DEBUG_ONLY( wxString sent_opcodes; )
225 
226 		if (SupportExtMultiPacket()) {
227 			dataFileReq.WriteUInt64(m_reqfile->GetFileSize());
228 		}
229 
230 		AddDebugLogLineN(logClient, wxT("Sending file request to client"));
231 
232 		dataFileReq.WriteUInt8(OP_REQUESTFILENAME);
233 		DEBUG_ONLY( sent_opcodes += wxT("|RFNM|"); )
234 		// Extended information
235 		if (GetExtendedRequestsVersion() > 0) {
236 			m_reqfile->WritePartStatus(&dataFileReq);
237 		}
238 		if (GetExtendedRequestsVersion() > 1) {
239 			m_reqfile->WriteCompleteSourcesCount(&dataFileReq);
240 		}
241 		if (m_reqfile->GetPartCount() > 1) {
242 			DEBUG_ONLY( sent_opcodes += wxT("|RFID|"); )
243 			dataFileReq.WriteUInt8(OP_SETREQFILEID);
244 		}
245 		if (IsEmuleClient()) {
246 			SetRemoteQueueFull( true );
247 			SetRemoteQueueRank(0);
248 		}
249 		if (IsSourceRequestAllowed()) {
250 			if (SupportsSourceExchange2()){
251 				DEBUG_ONLY( sent_opcodes += wxT("|RSRC2|"); )
252 				dataFileReq.WriteUInt8(OP_REQUESTSOURCES2);
253 				dataFileReq.WriteUInt8(SOURCEEXCHANGE2_VERSION);
254 				const uint16 nOptions = 0; // 16 ... Reserved
255 				dataFileReq.WriteUInt16(nOptions);
256 			} else {
257 				DEBUG_ONLY( sent_opcodes += wxT("|RSRC|"); )
258 				dataFileReq.WriteUInt8(OP_REQUESTSOURCES);
259 			}
260 			m_reqfile->SetLastAnsweredTimeTimeout();
261 			SetLastAskedForSources();
262 		}
263 		if (IsSupportingAICH()) {
264 			DEBUG_ONLY( sent_opcodes += wxT("|AFHR|"); )
265 			dataFileReq.WriteUInt8(OP_AICHFILEHASHREQ);
266 		}
267 		CPacket* packet = new CPacket(dataFileReq, OP_EMULEPROT, (SupportExtMultiPacket() ? OP_MULTIPACKET_EXT : OP_MULTIPACKET));
268 		theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
269 		AddDebugLogLineN(logLocalClient, CFormat(wxT("Local Client: %s (%s) to %s"))
270 			% (SupportExtMultiPacket() ? wxT("OP_MULTIPACKET_EXT") : wxT("OP_MULTIPACKET")) % sent_opcodes % GetFullIP());
271 		SendPacket(packet, true);
272 	} else {
273 		//This is extended information
274 		if (GetExtendedRequestsVersion() > 0 ) {
275 			m_reqfile->WritePartStatus(&dataFileReq);
276 		}
277 		if (GetExtendedRequestsVersion() > 1 ) {
278 			m_reqfile->WriteCompleteSourcesCount(&dataFileReq);
279 		}
280 		CPacket* packet = new CPacket(dataFileReq, OP_EDONKEYPROT, OP_REQUESTFILENAME);
281 		theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
282 		AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQUESTFILENAME to ") + GetFullIP() );
283 		SendPacket(packet, true);
284 
285 		// 26-Jul-2003: removed requesting the file status for files <= PARTSIZE for better compatibility with ed2k protocol (eDonkeyHybrid).
286 		// if the remote client answers the OP_REQUESTFILENAME with OP_REQFILENAMEANSWER the file is shared by the remote client. if we
287 		// know that the file is shared, we know also that the file is complete and don't need to request the file status.
288 
289 		// Sending the packet could have deleted the client, check m_reqfile
290 		if (m_reqfile && (m_reqfile->GetPartCount() > 1)) {
291 			CMemFile dataSetReqFileID(16);
292 			dataSetReqFileID.WriteHash(m_reqfile->GetFileHash());
293 			packet = new CPacket(dataSetReqFileID, OP_EDONKEYPROT, OP_SETREQFILEID);
294 			theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
295 			AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_SETREQFILEID to ") + GetFullIP());
296 			SendPacket(packet, true);
297 		}
298 
299 		if (IsEmuleClient()) {
300 			SetRemoteQueueFull( true );
301 			SetRemoteQueueRank(0);
302 		}
303 
304 		// Sending the packet could have deleted the client, check m_reqfile
305 		if (m_reqfile && IsSourceRequestAllowed()) {
306 			m_reqfile->SetLastAnsweredTimeTimeout();
307 
308 			CMemFile packetdata;
309 
310 			if (SupportsSourceExchange2()) {
311 				packetdata.WriteUInt8(SOURCEEXCHANGE2_VERSION);
312 				packetdata.WriteUInt16(0 /* Reserved */);
313 			}
314 
315 			packetdata.WriteHash(m_reqfile->GetFileHash());
316 
317 			packet = new CPacket(packetdata, OP_EMULEPROT, SupportsSourceExchange2() ? OP_REQUESTSOURCES2 : OP_REQUESTSOURCES);
318 
319 			theStats::AddUpOverheadSourceExchange(packet->GetPacketSize());
320 			AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQUESTSOURCES to ") + GetFullIP() );
321 			SendPacket(packet,true,true);
322 			SetLastAskedForSources();
323 		}
324 
325 		// Sending the packet could have deleted the client, check m_reqfile
326 		if (m_reqfile && IsSupportingAICH()) {
327 			packet = new CPacket(OP_AICHFILEHASHREQ,16,OP_EMULEPROT);
328 			packet->Copy16ToDataBuffer((const char *)m_reqfile->GetFileHash().GetHash());
329 			theStats::AddUpOverheadOther(packet->GetPacketSize());
330 			AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHFILEHASHREQ to ") + GetFullIP());
331 			SendPacket(packet,true,true);
332 		}
333 	}
334 }
335 
336 
ProcessFileInfo(const CMemFile * data,const CPartFile * file)337 void CUpDownClient::ProcessFileInfo(const CMemFile* data, const CPartFile* file)
338 {
339 	// 0.42e
340 	if (file==NULL) {
341 		throw wxString(wxT("ERROR: Wrong file ID (ProcessFileInfo; file==NULL)"));
342 	}
343 	if (m_reqfile==NULL) {
344 		throw wxString(wxT("ERROR: Wrong file ID (ProcessFileInfo; m_reqfile==NULL)"));
345 	}
346 	if (file != m_reqfile) {
347 		throw wxString(wxT("ERROR: Wrong file ID (ProcessFileInfo; m_reqfile!=file)"));
348 	}
349 
350 	m_clientFilename = data->ReadString((GetUnicodeSupport() != utf8strNone));
351 
352 	// 26-Jul-2003: removed requesting the file status for files <= PARTSIZE for better compatibility with ed2k protocol (eDonkeyHybrid).
353 	// if the remote client answers the OP_REQUESTFILENAME with OP_REQFILENAMEANSWER the file is shared by the remote client. if we
354 	// know that the file is shared, we know also that the file is complete and don't need to request the file status.
355 	if (m_reqfile->GetPartCount() == 1) {
356 		m_nPartCount = m_reqfile->GetPartCount();
357 
358 		m_reqfile->UpdatePartsFrequency( this, false );	// Decrement
359 		m_downPartStatus.setsize( m_nPartCount, 1 );
360 		m_reqfile->UpdatePartsFrequency( this, true );	// Increment
361 
362 		m_bCompleteSource = true;
363 
364 		UpdateDisplayedInfo();
365 		// even if the file is <= PARTSIZE, we _may_ need the hashset for that file (if the file size == PARTSIZE)
366 		if (m_reqfile->IsHashSetNeeded()) {
367 			if (m_socket) {
368 				CPacket* packet = new CPacket(OP_HASHSETREQUEST,16, OP_EDONKEYPROT);
369 				packet->Copy16ToDataBuffer((const char *)m_reqfile->GetFileHash().GetHash());
370 				theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
371 				AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_HASHSETREQUEST to ") + GetFullIP());
372 				SendPacket(packet,true,true);
373 				SetDownloadState(DS_REQHASHSET);
374 				m_fHashsetRequesting = 1;
375 				m_reqfile->SetHashSetNeeded(false);
376 			} else {
377 				wxFAIL;
378 			}
379 		} else {
380 			SendStartupLoadReq();
381 		}
382 		m_reqfile->UpdatePartsInfo();
383 	}
384 }
385 
ProcessFileStatus(bool bUdpPacket,const CMemFile * data,const CPartFile * file)386 void CUpDownClient::ProcessFileStatus(bool bUdpPacket, const CMemFile* data, const CPartFile* file)
387 {
388 	// 0.42e
389 	wxString strReqFileNull(wxT("ERROR: Wrong file ID (ProcessFileStatus; m_reqfile==NULL)"));
390 
391 	if ( !m_reqfile || file != m_reqfile ){
392 		if (!m_reqfile) {
393 			throw strReqFileNull;
394 		}
395 		throw wxString(wxT("ERROR: Wrong file ID (ProcessFileStatus; m_reqfile!=file)"));
396 	}
397 
398 	uint16 nED2KPartCount = data->ReadUInt16();
399 
400 	m_reqfile->UpdatePartsFrequency( this, false );	// Decrement
401 	m_downPartStatus.clear();
402 
403 	bool bPartsNeeded = false;
404 	if (!nED2KPartCount)
405 	{
406 		m_nPartCount = m_reqfile->GetPartCount();
407 		m_downPartStatus.setsize( m_nPartCount, 1);
408 		bPartsNeeded = true;
409 		m_bCompleteSource = true;
410 	}
411 	else
412 	{
413 		// Somehow this happened.
414 		if (!m_reqfile) {
415 			throw strReqFileNull;
416 		}
417 		if (m_reqfile->GetED2KPartCount() != nED2KPartCount)
418 		{
419 			wxString strError;
420 			strError << wxT("ProcessFileStatus - wrong part number recv=") << nED2KPartCount <<
421 				wxT("  expected=") << m_reqfile->GetED2KPartCount() << wxT(" ") <<
422 				m_reqfile->GetFileHash().Encode();
423 			m_nPartCount = 0;
424 			throw strError;
425 		}
426 		m_nPartCount = m_reqfile->GetPartCount();
427 
428 		m_bCompleteSource = false;
429 		m_downPartStatus.setsize( m_nPartCount, 0 );
430 		uint16 done = 0;
431 
432 		try {
433 			while (done != m_nPartCount) {
434 				uint8 toread = data->ReadUInt8();
435 
436 				for ( uint8 i = 0;i < 8; i++ ) {
437 					bool status = ((toread>>i)&1)? 1:0;
438 					m_downPartStatus.set(done, status);
439 
440 					if (status) {
441 						if (!m_reqfile->IsComplete(done)){
442 							bPartsNeeded = true;
443 						}
444 					}
445 					done++;
446 					if (done == m_nPartCount) {
447 						break;
448 					}
449 				}
450 			}
451 		} catch( ... ) {
452 			// We want the counts to be updated, even if we fail to read everything
453 			m_reqfile->UpdatePartsFrequency( this, true );	// Increment
454 
455 			throw;
456 		}
457 	}
458 
459 	m_reqfile->UpdatePartsFrequency( this, true );	// Increment
460 
461 	UpdateDisplayedInfo();
462 
463 	// NOTE: This function is invoked from TCP and UDP socket!
464 	if (!bUdpPacket) {
465 		if (!bPartsNeeded) {
466 			SetDownloadState(DS_NONEEDEDPARTS);
467 		} else if (m_reqfile->IsHashSetNeeded()) {
468 			//If we are using the eMule filerequest packets, this is taken care of in the Multipacket!
469 			if (m_socket) {
470 				CPacket* packet = new CPacket(OP_HASHSETREQUEST,16, OP_EDONKEYPROT);
471 				packet->Copy16ToDataBuffer((const char *)m_reqfile->GetFileHash().GetHash());
472 				theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
473 				AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_HASHSETREQUEST to ") + GetFullIP());
474 				SendPacket(packet, true, true);
475 				SetDownloadState(DS_REQHASHSET);
476 				m_fHashsetRequesting = 1;
477 				m_reqfile->SetHashSetNeeded(false);
478 			} else {
479 				wxFAIL;
480 			}
481 		}
482 		else {
483 			SendStartupLoadReq();
484 		}
485 	}
486 	else {
487 		if (!bPartsNeeded) {
488 			SetDownloadState(DS_NONEEDEDPARTS);
489 		} else {
490 			SetDownloadState(DS_ONQUEUE);
491 		}
492 	}
493 	m_reqfile->UpdatePartsInfo();
494 }
495 
AddRequestForAnotherFile(CPartFile * file)496 bool CUpDownClient::AddRequestForAnotherFile(CPartFile* file)
497 {
498 	if ( m_A4AF_list.find( file ) == m_A4AF_list.end() ) {
499 		// When we access a non-existing entry entry, it will be zeroed by default,
500 		// so we have to set NeededParts. All in one go.
501 		m_A4AF_list[file].NeededParts = true;
502 		file->AddA4AFSource( this );
503 		return true;
504 	} else {
505 		return false;
506 	}
507 }
508 
DeleteFileRequest(CPartFile * file)509 bool CUpDownClient::DeleteFileRequest(CPartFile* file)
510 {
511 	return (m_A4AF_list.erase( file ) > 0);
512 }
513 
DeleteAllFileRequests()514 void CUpDownClient::DeleteAllFileRequests()
515 {
516 	m_A4AF_list.clear();
517 }
518 
519 
520 /* eMule 0.30c implementation, i give it a try (Creteil) BEGIN ... */
SetDownloadState(uint8 byNewState)521 void CUpDownClient::SetDownloadState(uint8 byNewState)
522 {
523 	if (m_nDownloadState != byNewState) {
524 		if (m_reqfile) {
525 			// Notify the client that this source has changed its state
526 			m_reqfile->ClientStateChanged( m_nDownloadState, byNewState );
527 
528 			if (byNewState == DS_DOWNLOADING) {
529 				m_reqfile->AddDownloadingSource(this);
530 			} else if (m_nDownloadState == DS_DOWNLOADING) {
531 				m_reqfile->RemoveDownloadingSource(this);
532 			}
533 		}
534 		if (byNewState == DS_DOWNLOADING) {
535 			msReceivedPrev = GetTickCount();
536 			theStats::AddDownloadingSource();
537 		} else if (m_nDownloadState == DS_DOWNLOADING) {
538 			theStats::RemoveDownloadingSource();
539 		}
540 
541 		if (m_nDownloadState == DS_DOWNLOADING) {
542 			m_nDownloadState = byNewState;
543 			ClearDownloadBlockRequests();
544 
545 			kBpsDown = 0.0;
546 			bytesReceivedCycle = 0;
547 			msReceivedPrev = 0;
548 			if (byNewState == DS_NONE) {
549 				if (m_reqfile) {
550 					m_reqfile->UpdatePartsFrequency( this, false );	// Decrement
551 				}
552 				m_downPartStatus.clear();
553 				m_nPartCount = 0;
554 			}
555 			if (m_socket && byNewState != DS_ERROR) {
556 				m_socket->DisableDownloadLimit();
557 			}
558 		}
559 		m_nDownloadState = byNewState;
560 		if(GetDownloadState() == DS_DOWNLOADING) {
561 			if (IsEmuleClient()) {
562 				SetRemoteQueueFull(false);
563 			}
564 			SetRemoteQueueRank(0); // eMule 0.30c set like this ...
565 		}
566 		UpdateDisplayedInfo(true);
567 	}
568 }
569 /* eMule 0.30c implementation, i give it a try (Creteil) END ... */
570 
ProcessHashSet(const uint8_t * packet,uint32 size)571 void CUpDownClient::ProcessHashSet(const uint8_t* packet, uint32 size)
572 {
573 	if ((!m_reqfile) || md4cmp(packet,m_reqfile->GetFileHash().GetHash())) {
574 		throw wxString(wxT("Wrong fileid sent (ProcessHashSet)"));
575 	}
576 	if (!m_fHashsetRequesting) {
577 		throw wxString(wxT("Received unsolicited hashset, ignoring it."));
578 	}
579 	CMemFile data(packet,size);
580 	if (m_reqfile->LoadHashsetFromFile(&data,true)) {
581 		m_fHashsetRequesting = 0;
582 	} else {
583 		m_reqfile->SetHashSetNeeded(true);
584 		throw wxString(wxT("Corrupted or invalid hashset received"));
585 	}
586 	SendStartupLoadReq();
587 }
588 
SendBlockRequests()589 void CUpDownClient::SendBlockRequests()
590 {
591 	uint32 current_time = ::GetTickCount();
592 	if (GetVBTTags()) {
593 
594 		// Ask new blocks only when all completed
595 		if (!m_PendingBlocks_list.empty()) {
596 			return;
597 		}
598 
599 		if ((m_dwLastBlockReceived + SEC2MS(5)) > current_time) {
600 			// We received last block in less than 5 secs? Let's request faster.
601 			m_MaxBlockRequests = m_MaxBlockRequests << 1;
602 			if ( m_MaxBlockRequests > 0x20) {
603 				m_MaxBlockRequests = 0x20;
604 			}
605 		} else {
606 			m_MaxBlockRequests = m_MaxBlockRequests >> 1;
607 			if ( m_MaxBlockRequests < STANDARD_BLOCKS_REQUEST) {
608 				m_MaxBlockRequests = STANDARD_BLOCKS_REQUEST;
609 			}
610 		}
611 	}
612 
613 	m_dwLastBlockReceived = current_time;
614 
615 	if (!m_reqfile) {
616 		return;
617 	}
618 
619 	if (m_DownloadBlocks_list.empty()) {
620 		// Barry - instead of getting 3, just get how many is needed
621 		uint16 count = m_MaxBlockRequests - m_PendingBlocks_list.size();
622 		std::vector<Requested_Block_Struct*> toadd;
623 		if (m_reqfile->GetNextRequestedBlock(this, toadd, count)) {
624 			for (int i = 0; i != count; i++) {
625 				m_DownloadBlocks_list.push_back(toadd[i]);
626 			}
627 		}
628 	}
629 
630 	// Barry - Why are unfinished blocks requested again, not just new ones?
631 
632 	while (m_PendingBlocks_list.size() < m_MaxBlockRequests && !m_DownloadBlocks_list.empty()) {
633 		Pending_Block_Struct* pblock = new Pending_Block_Struct;
634 		pblock->block = m_DownloadBlocks_list.front();
635 		pblock->zStream = NULL;
636 		pblock->totalUnzipped = 0;
637 		pblock->fZStreamError = 0;
638 		pblock->fRecovered = 0;
639 		m_PendingBlocks_list.push_back(pblock);
640 		m_DownloadBlocks_list.pop_front();
641 	}
642 
643 
644 	if (m_PendingBlocks_list.empty()) {
645 
646 		CUpDownClient* slower_client = NULL;
647 
648 		if (thePrefs::GetDropSlowSources()) {
649 			slower_client = m_reqfile->GetSlowerDownloadingClient(m_lastaverage, this);
650 		}
651 
652 		if (slower_client == NULL) {
653 			slower_client = this;
654 		}
655 
656 		if (!slower_client->GetSentCancelTransfer()) {
657 			CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
658 			theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
659 //			if (slower_client != this) {
660 //				printf("Dropped client %p to allow client %p to download\n",slower_client, this);
661 //			}
662 			slower_client->ClearDownloadBlockRequests();
663 			slower_client->SendPacket(packet,true,true);
664 			slower_client->SetSentCancelTransfer(1);
665 		}
666 
667 		slower_client->SetDownloadState(DS_NONEEDEDPARTS);
668 
669 		if (slower_client != this) {
670 			// Re-request freed blocks.
671 			AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER (faster source eager to transfer) to ") + slower_client->GetFullIP() );
672 			wxASSERT(m_DownloadBlocks_list.empty());
673 			wxASSERT(m_PendingBlocks_list.empty());
674 			uint16 count = m_MaxBlockRequests;
675 			std::vector<Requested_Block_Struct*> toadd;
676 			if (m_reqfile->GetNextRequestedBlock(this, toadd, count)) {
677 				for (int i = 0; i != count; i++) {
678 					Pending_Block_Struct* pblock = new Pending_Block_Struct;
679 					pblock->block = toadd[i];
680 					pblock->zStream = NULL;
681 					pblock->totalUnzipped = 0;
682 					pblock->fZStreamError = 0;
683 					pblock->fRecovered = 0;
684 					m_PendingBlocks_list.push_back(pblock);
685 				}
686 			} else {
687 				// WTF, we just freed blocks.
688 				wxFAIL_MSG(wxT("No free blocks to request after freeing some blocks"));
689 				return;
690 			}
691 		} else {
692 			// Drop this one.
693 			AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER (no free blocks) to ") + GetFullIP() );
694 			//#warning Kry - Would be nice to swap A4AF here.
695 			return;
696 		}
697 	}
698 
699 	CPacket* packet = NULL;
700 
701 	if (GetVBTTags()) {
702 		// ED2Kv2 packet...
703 		// Most common scenario: hash + blocks to request + every one
704 		// having 2 uint32 tags
705 
706 		uint8 nBlocks = m_PendingBlocks_list.size();
707 		if (nBlocks > m_MaxBlockRequests) {
708 			nBlocks = m_MaxBlockRequests;
709 		}
710 
711 		CMemFile data(16 + 1 + nBlocks*((2+4)*2));
712 
713 		data.WriteHash(m_reqfile->GetFileHash());
714 
715 		data.WriteUInt8(nBlocks);
716 
717 		std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin();
718 		while (nBlocks) {
719 			wxASSERT(it != m_PendingBlocks_list.end());
720 			wxASSERT( (*it)->block->StartOffset <= (*it)->block->EndOffset );
721 			(*it)->fZStreamError = 0;
722 			(*it)->fRecovered = 0;
723 			CTagVarInt(/*Noname*/0,(*it)->block->StartOffset).WriteTagToFile(&data);
724 			CTagVarInt(/*Noname*/0,(*it)->block->EndOffset).WriteTagToFile(&data);
725 			++it;
726 			nBlocks--;
727 		}
728 
729 		packet = new CPacket(data, OP_ED2KV2HEADER, OP_REQUESTPARTS);
730 		AddDebugLogLineN( logLocalClient, CFormat(wxT("Local Client ED2Kv2: OP_REQUESTPARTS(%i) to %s"))
731 				  % (m_PendingBlocks_list.size()<m_MaxBlockRequests ? m_PendingBlocks_list.size() : m_MaxBlockRequests) % GetFullIP() );
732 
733 	} else {
734 		wxASSERT(m_MaxBlockRequests == STANDARD_BLOCKS_REQUEST);
735 
736 		//#warning Kry - I dont specially like this approach, we iterate one time too many
737 
738 		bool bHasLongBlocks =  false;
739 
740 		std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin();
741 		for (uint32 i = 0; i != m_MaxBlockRequests; i++){
742 			if (it != m_PendingBlocks_list.end()) {
743 				Pending_Block_Struct* pending = *it++;
744 				wxASSERT( pending->block->StartOffset <= pending->block->EndOffset );
745 				if (pending->block->StartOffset > 0xFFFFFFFF || pending->block->EndOffset > 0xFFFFFFFF){
746 					bHasLongBlocks = true;
747 					if (!SupportsLargeFiles()){
748 						// Requesting a large block from a client that doesn't support large files?
749 						if (!GetSentCancelTransfer()){
750 							CPacket* cancel_packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
751 							theStats::AddUpOverheadFileRequest(cancel_packet->GetPacketSize());
752 							AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + GetFullIP() );
753 							SendPacket(cancel_packet,true,true);
754 							SetSentCancelTransfer(1);
755 						}
756 						SetDownloadState(DS_ERROR);
757 						return;
758 					}
759 					break;
760 				}
761 			}
762 		}
763 
764 		CMemFile data(16 /*Hash*/ + (m_MaxBlockRequests*(bHasLongBlocks ? 8 : 4) /* uint32/64 start*/) + (3*(bHasLongBlocks ? 8 : 4)/* uint32/64 end*/));
765 		data.WriteHash(m_reqfile->GetFileHash());
766 
767 		it = m_PendingBlocks_list.begin();
768 		for (uint32 i = 0; i != m_MaxBlockRequests; i++) {
769 			if (it != m_PendingBlocks_list.end()) {
770 				Pending_Block_Struct* pending = *it++;
771 				wxASSERT( pending->block->StartOffset <= pending->block->EndOffset );
772 				pending->fZStreamError = 0;
773 				pending->fRecovered = 0;
774 				if (bHasLongBlocks) {
775 					data.WriteUInt64(pending->block->StartOffset);
776 				} else {
777 					data.WriteUInt32(pending->block->StartOffset);
778 				}
779 			} else {
780 				if (bHasLongBlocks) {
781 					data.WriteUInt64(0);
782 				} else {
783 					data.WriteUInt32(0);
784 				}
785 			}
786 		}
787 
788 		it = m_PendingBlocks_list.begin();
789 		for (uint32 i = 0; i != m_MaxBlockRequests; i++) {
790 			if (it != m_PendingBlocks_list.end()) {
791 				Requested_Block_Struct* block = (*it++)->block;
792 				if (bHasLongBlocks) {
793 					data.WriteUInt64(block->EndOffset+1);
794 				} else {
795 					data.WriteUInt32(block->EndOffset+1);
796 				}
797 			} else {
798 				if (bHasLongBlocks) {
799 					data.WriteUInt64(0);
800 				} else {
801 					data.WriteUInt32(0);
802 				}
803 			}
804 		}
805 		packet = new CPacket(data, (bHasLongBlocks ? OP_EMULEPROT : OP_EDONKEYPROT), (bHasLongBlocks ? (uint8)OP_REQUESTPARTS_I64 : (uint8)OP_REQUESTPARTS));
806 		AddDebugLogLineN(logLocalClient, CFormat(wxT("Local Client: %s to %s")) % (bHasLongBlocks ? wxT("OP_REQUESTPARTS_I64") : wxT("OP_REQUESTPARTS")) % GetFullIP());
807 	}
808 
809 	if (packet) {
810 		theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
811 		SendPacket(packet, true, true);
812 	}
813 }
814 
815 /*
816 Barry - Originally this only wrote to disk when a full 180k block
817 had been received from a client, and only asked for data in
818 180k blocks.
819 
820 This meant that on average 90k was lost for every connection
821 to a client data source. That is a lot of wasted data.
822 
823 To reduce the lost data, packets are now written to a buffer
824 and flushed to disk regularly regardless of size downloaded.
825 
826 This includes compressed packets.
827 
828 Data is also requested only where gaps are, not in 180k blocks.
829 The requests will still not exceed 180k, but may be smaller to
830 fill a gap.
831 */
832 
ProcessBlockPacket(const uint8_t * packet,uint32 size,bool packed,bool largeblocks)833 void CUpDownClient::ProcessBlockPacket(const uint8_t* packet, uint32 size, bool packed, bool largeblocks)
834 {
835 	// Ignore if no data required
836 	if (!(GetDownloadState() == DS_DOWNLOADING || GetDownloadState() == DS_NONEEDEDPARTS)) {
837 		return;
838 	}
839 
840 	// This vars are defined here to be able to use them on the catch
841 	int header_size = 16;
842 	uint64 nStartPos = 0;
843 	uint64 nEndPos = 0;
844 	uint32 nBlockSize = 0;
845 	uint32 lenUnzipped = 0;
846 
847 	// Update stats
848 	m_dwLastBlockReceived = ::GetTickCount();
849 
850 	try {
851 
852 		// Read data from packet
853 		const CMemFile data(packet, size);
854 
855 		// Check that this data is for the correct file
856 		if ((!m_reqfile) || data.ReadHash() != m_reqfile->GetFileHash()) {
857 			throw wxString(wxT("Wrong fileid sent (ProcessBlockPacket)"));
858 		}
859 
860 		// Find the start & end positions, and size of this chunk of data
861 
862 		if (largeblocks) {
863 			nStartPos = data.ReadUInt64();
864 			header_size += 8;
865 		} else {
866 			nStartPos = data.ReadUInt32();
867 			header_size += 4;
868 		}
869 
870 		if (packed) {
871 			nBlockSize = data.ReadUInt32();
872 			header_size += 4;
873 			nEndPos = nStartPos + (size - header_size);
874 		} else {
875 			if (largeblocks) {
876 				nEndPos = data.ReadUInt64();
877 				header_size += 8;
878 			} else {
879 				nEndPos = data.ReadUInt32();
880 				header_size += 4;
881 			}
882 		}
883 
884 		// Check that packet size matches the declared data size + header size
885 		if ( nEndPos == nStartPos || size != ((nEndPos - nStartPos) + header_size)) {
886 			throw wxString(wxT("Corrupted or invalid DataBlock received (ProcessBlockPacket)"));
887 		}
888 		theStats::AddDownloadFromSoft(GetClientSoft(),size - header_size);
889 		bytesReceivedCycle += size - header_size;
890 
891 		credits->AddDownloaded(size - header_size, GetIP(), theApp->CryptoAvailable());
892 
893 		// Move end back one, should be inclusive
894 		nEndPos--;
895 
896 		// Loop through to find the reserved block that this is within
897 		std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin();
898 		for (; it != m_PendingBlocks_list.end(); ++it) {
899 			Pending_Block_Struct* cur_block = *it;
900 
901 			if ((cur_block->block->StartOffset <= nStartPos) && (cur_block->block->EndOffset >= nStartPos)) {
902 				// Found reserved block
903 
904 				if (cur_block->block->StartOffset == nStartPos) {
905 					// This block just started transfering. Set the start time.
906 					m_last_block_start = ::GetTickCountFullRes();
907 				}
908 
909 				if (cur_block->fZStreamError){
910 					AddDebugLogLineN(logZLib,
911 						CFormat(wxT("Ignoring %u bytes of block %u-%u because of erroneous zstream state for file: %s"))
912 							% (size - header_size) % nStartPos % nEndPos % m_reqfile->GetFileName());
913 					m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
914 					return;
915 				}
916 
917 				// Remember this start pos, used to draw part downloading in list
918 				m_lastDownloadingPart = nStartPos / PARTSIZE;
919 
920 				// Occasionally packets are duplicated, no point writing it twice
921 				// This will be 0 in these cases, or the length written otherwise
922 				uint32 lenWritten = 0;
923 
924 				// Handle differently depending on whether packed or not
925 				if (!packed) {
926 					// security sanitize check
927 					if (nEndPos > cur_block->block->EndOffset) {
928 						AddDebugLogLineN(logRemoteClient, CFormat(wxT("Received Blockpacket exceeds requested boundaries (requested end: %u, Part: %u, received end: %u, Part: %u), file: %s remote IP: %s")) % cur_block->block->EndOffset % (uint32)(cur_block->block->EndOffset / PARTSIZE) % nEndPos % (uint32)(nEndPos / PARTSIZE) % m_reqfile->GetFileName() % Uint32toStringIP(GetIP()));
929 						m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
930 						return;
931 					}
932 					// Write to disk (will be buffered in part file class)
933 					lenWritten = m_reqfile->WriteToBuffer( size - header_size, (uint8_t*)(packet + header_size), nStartPos, nEndPos, cur_block->block, this);
934 				} else {
935 					// Packed
936 					wxASSERT( (long int)size > 0 );
937 					// Create space to store unzipped data, the size is
938 					// only an initial guess, will be resized in unzip()
939 					// if not big enough
940 					lenUnzipped = (size * 2);
941 					// Don't get too big
942 					if (lenUnzipped > (BLOCKSIZE + 300)) {
943 						lenUnzipped = (BLOCKSIZE + 300);
944 					}
945 					uint8_t *unzipped = new uint8_t[lenUnzipped];
946 
947 					// Try to unzip the packet
948 					int result = unzip(cur_block, (uint8_t*)(packet + header_size), (size - header_size), &unzipped, &lenUnzipped);
949 
950 					// no block can be uncompressed to >2GB, 'lenUnzipped' is obviously erroneous.
951 					if (result == Z_OK && ((int)lenUnzipped >= 0)) {
952 
953 						// Write any unzipped data to disk
954 						if (lenUnzipped > 0) {
955 							wxASSERT( (int)lenUnzipped > 0 );
956 
957 							// Use the current start and end positions for the uncompressed data
958 							nStartPos = cur_block->block->StartOffset + cur_block->totalUnzipped - lenUnzipped;
959 							nEndPos = cur_block->block->StartOffset + cur_block->totalUnzipped - 1;
960 
961 							if (nStartPos > cur_block->block->EndOffset || nEndPos > cur_block->block->EndOffset) {
962 								AddDebugLogLineN(logZLib,
963 									CFormat(wxT("Corrupted compressed packet for '%s' received (error 666)")) % m_reqfile->GetFileName());
964 								m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
965 							} else {
966 								// Write uncompressed data to file
967 								lenWritten = m_reqfile->WriteToBuffer( size - header_size,
968 																	   unzipped,
969 																	   nStartPos,
970 																	   nEndPos,
971 																	   cur_block->block,
972 																	   this);
973 							}
974 						}
975 					} else {
976 						wxString strZipError;
977 						if (cur_block->zStream && cur_block->zStream->msg) {
978 							strZipError = wxT(" - ") + wxString::FromAscii(cur_block->zStream->msg);
979 						}
980 
981 						AddDebugLogLineN(logZLib,
982 							CFormat(wxT("Corrupted compressed packet for '%s' received (error %i): %s"))
983 								% m_reqfile->GetFileName() % result % strZipError);
984 
985 						m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
986 
987 						// If we had an zstream error, there is no chance that we could recover from it nor that we
988 						// could use the current zstream (which is in error state) any longer.
989 						if (cur_block->zStream){
990 							inflateEnd(cur_block->zStream);
991 							delete cur_block->zStream;
992 							cur_block->zStream = NULL;
993 						}
994 
995 						// Although we can't further use the current zstream, there is no need to disconnect the sending
996 						// client because the next zstream (a series of 10K-blocks which build a 180K-block) could be
997 						// valid again. Just ignore all further blocks for the current zstream.
998 						cur_block->fZStreamError = 1;
999 						cur_block->totalUnzipped = 0; // bluecow's fix
1000 					}
1001 					delete [] unzipped;
1002 				}
1003 				// These checks only need to be done if any data was written
1004 				if (lenWritten > 0) {
1005 					m_nTransferredDown += lenWritten;
1006 
1007 					// If finished reserved block
1008 					if (nEndPos == cur_block->block->EndOffset) {
1009 
1010 						// Save last average speed based on data and time.
1011 						// This should do bytes/sec.
1012 						uint32 average_time = (::GetTickCountFullRes() - m_last_block_start);
1013 
1014 						// Avoid divide by 0.
1015 						if (average_time == 0) {
1016 							average_time++;
1017 						}
1018 
1019 						m_lastaverage = ((cur_block->block->EndOffset - cur_block->block->StartOffset) * 1000) / average_time;
1020 
1021 						m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset);
1022 						delete cur_block->block;
1023 						// Not always allocated
1024 						if (cur_block->zStream) {
1025 							inflateEnd(cur_block->zStream);
1026 							delete cur_block->zStream;
1027 						}
1028 						delete cur_block;
1029 						m_PendingBlocks_list.erase(it);
1030 
1031 						// Request next block
1032 						SendBlockRequests();
1033 					}
1034 				}
1035 				// Stop looping and exit method
1036 				return;
1037 			}
1038 		}
1039 	} catch (const CEOFException& e) {
1040 		wxString error = wxString(wxT("Error reading "));
1041 		if (packed) error += CFormat(wxT("packed (LU: %i) largeblocks ")) % lenUnzipped;
1042 		error += CFormat(wxT("data packet: RS: %i HS: %i SP: %i EP: %i BS: %i -> "))
1043 					% size % header_size % nStartPos % nEndPos % nBlockSize;
1044 		AddDebugLogLineC(logRemoteClient, error + e.what());
1045 		return;
1046 	}
1047 }
1048 
unzip(Pending_Block_Struct * block,uint8_t * zipped,uint32 lenZipped,uint8_t ** unzipped,uint32 * lenUnzipped,int iRecursion)1049 int CUpDownClient::unzip(Pending_Block_Struct *block, uint8_t *zipped, uint32 lenZipped, uint8_t **unzipped, uint32 *lenUnzipped, int iRecursion)
1050 {
1051 	int err = Z_DATA_ERROR;
1052 
1053 	// Save some typing
1054 	z_stream *zS = block->zStream;
1055 
1056 	// Is this the first time this block has been unzipped
1057 	if (zS == NULL) {
1058 		// Create stream
1059 		block->zStream = new z_stream;
1060 		zS = block->zStream;
1061 
1062 		// Initialise stream values
1063 		zS->zalloc = (alloc_func)0;
1064 		zS->zfree = (free_func)0;
1065 		zS->opaque = (voidpf)0;
1066 
1067 		// Set output data streams, do this here to avoid overwriting on recursive calls
1068 		zS->next_out = (*unzipped);
1069 		zS->avail_out = (*lenUnzipped);
1070 
1071 		// Initialise the z_stream
1072 		err = inflateInit(zS);
1073 		if (err != Z_OK) {
1074 			return err;
1075 		}
1076 	}
1077 
1078 	// Use whatever input is provided
1079 	zS->next_in  = zipped;
1080 	zS->avail_in = lenZipped;
1081 
1082 	// Only set the output if not being called recursively
1083 	if (iRecursion == 0) {
1084 		zS->next_out = (*unzipped);
1085 		zS->avail_out = (*lenUnzipped);
1086 	}
1087 
1088 	// Try to unzip the data
1089 	err = inflate(zS, Z_SYNC_FLUSH);
1090 
1091 	// Is zip finished reading all currently available input and writing
1092 	// all generated output
1093 	if (err == Z_STREAM_END) {
1094 		// Finish up
1095 		err = inflateEnd(zS);
1096 		if (err != Z_OK) {
1097 			return err;
1098 		}
1099 
1100 		// Got a good result, set the size to the amount unzipped in this call
1101 		//  (including all recursive calls)
1102 		(*lenUnzipped) = (zS->total_out - block->totalUnzipped);
1103 		block->totalUnzipped = zS->total_out;
1104 	} else if ((err == Z_OK) && (zS->avail_out == 0) && (zS->avail_in != 0)) {
1105 
1106 		// Output array was not big enough,
1107 		// call recursively until there is enough space
1108 
1109 		// What size should we try next
1110 		uint32 newLength = (*lenUnzipped) *= 2;
1111 		if (newLength == 0) {
1112 			newLength = lenZipped * 2;
1113 		}
1114 		// Copy any data that was successfully unzipped to new array
1115 		uint8_t *temp = new uint8_t[newLength];
1116 		wxASSERT( zS->total_out - block->totalUnzipped <= newLength );
1117 		memcpy(temp, (*unzipped), (zS->total_out - block->totalUnzipped));
1118 		delete [] (*unzipped);
1119 		(*unzipped) = temp;
1120 		(*lenUnzipped) = newLength;
1121 
1122 		// Position stream output to correct place in new array
1123 		zS->next_out = (*unzipped) + (zS->total_out - block->totalUnzipped);
1124 		zS->avail_out = (*lenUnzipped) - (zS->total_out - block->totalUnzipped);
1125 
1126 		// Try again
1127 		err = unzip(block, zS->next_in, zS->avail_in, unzipped, lenUnzipped, iRecursion + 1);
1128 	} else if ((err == Z_OK) && (zS->avail_in == 0)) {
1129 		// All available input has been processed, everything ok.
1130 		// Set the size to the amount unzipped in this call
1131 		// (including all recursive calls)
1132 		(*lenUnzipped) = (zS->total_out - block->totalUnzipped);
1133 		block->totalUnzipped = zS->total_out;
1134 	} else {
1135 		// Should not get here unless input data is corrupt
1136 		wxString strZipError;
1137 
1138 		if ( zS->msg ) {
1139 			strZipError = CFormat(wxT(" %d '%s'")) % err % wxString::FromAscii(zS->msg);
1140 		} else if (err != Z_OK) {
1141 			strZipError = CFormat(wxT(" %d")) % err;
1142 		}
1143 
1144 		AddDebugLogLineN(logZLib,
1145 			CFormat(wxT("Unexpected zip error %s in file '%s'"))
1146 				% strZipError % (m_reqfile ? m_reqfile->GetFileName() : CPath(wxT("?"))));
1147 	}
1148 
1149 	if (err != Z_OK) {
1150 		(*lenUnzipped) = 0;
1151 	}
1152 
1153 	return err;
1154 }
1155 
1156 
1157 // Speed is now updated only when data was received, calculated as
1158 // (data received) / (time since last receiption)
1159 // and slightly filtered (10s average).
1160 // Result is quite precise now and makes the DownloadRateAdjust workaround obsolete.
1161 
CalculateKBpsDown()1162 float CUpDownClient::CalculateKBpsDown()
1163 {
1164 	const	float tAverage = 10.0;
1165 	uint32	msCur = GetTickCount();
1166 
1167 	if (bytesReceivedCycle) {
1168 		float dt = (msCur - msReceivedPrev) / 1000.0; // time since last reception
1169 		if (dt < 0.01) {	// (safeguard against divide-by-zero)
1170 			dt = 0.01f;		//  diff should be 100ms actually
1171 		}
1172 		float kBpsDownCur = bytesReceivedCycle / 1024.0 / dt;
1173 		if (dt >= tAverage) {
1174 			kBpsDown = kBpsDownCur;
1175 		} else {
1176 			kBpsDown = (kBpsDown * (tAverage - dt) + kBpsDownCur * dt) / tAverage;
1177 		}
1178 		//AddDebugLogLineN(logLocalClient, CFormat(wxT("CalculateKBpsDown %p kbps %.1f kbpsCur %.1f dt %.3f rcv %d "))
1179 		//			% this % kBpsDown  % kBpsDownCur % dt % bytesReceivedCycle);
1180 		bytesReceivedCycle = 0;
1181 		msReceivedPrev = msCur;
1182 	}
1183 
1184 	m_cShowDR++;
1185 	if (m_cShowDR == 30){
1186 		m_cShowDR = 0;
1187 		UpdateDisplayedInfo();
1188 	}
1189 	if (msCur - m_dwLastBlockReceived > DOWNLOADTIMEOUT) {
1190 		if (!GetSentCancelTransfer()){
1191 			CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1192 			theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1193 			AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + GetFullIP() );
1194 			SendPacket(packet,true,true);
1195 			SetSentCancelTransfer(1);
1196 		}
1197 		SetDownloadState(DS_ONQUEUE);
1198 	}
1199 
1200 	return kBpsDown;
1201 }
1202 
GetAvailablePartCount() const1203 uint16 CUpDownClient::GetAvailablePartCount() const
1204 {
1205 	uint16 result = 0;
1206 	for (int i = 0;i != m_nPartCount;i++){
1207 		if (IsPartAvailable(i))
1208 			result++;
1209 	}
1210 	return result;
1211 }
1212 
SetRemoteQueueRank(uint16 nr)1213 void CUpDownClient::SetRemoteQueueRank(uint16 nr)
1214 {
1215 	m_nOldRemoteQueueRank = m_nRemoteQueueRank;
1216 	m_nRemoteQueueRank = nr;
1217 	UpdateDisplayedInfo();
1218 }
1219 
UDPReaskACK(uint16 nNewQR)1220 void CUpDownClient::UDPReaskACK(uint16 nNewQR)
1221 {
1222 	// 0.42e
1223 	m_bUDPPending = false;
1224 	SetRemoteQueueRank(nNewQR);
1225 	m_dwLastAskedTime = ::GetTickCount();
1226 }
1227 
UDPReaskFNF()1228 void CUpDownClient::UDPReaskFNF()
1229 {
1230 	m_bUDPPending = false;
1231 
1232 	// avoid premature deletion of 'this' client
1233 	if (GetDownloadState() != DS_DOWNLOADING){
1234 		if (m_reqfile) {
1235 			m_reqfile->AddDeadSource(this);
1236 		}
1237 
1238 		theApp->downloadqueue->RemoveSource(this);
1239 		if (!m_socket) {
1240 			if (Disconnected(wxT("UDPReaskFNF m_socket=NULL"))) {
1241 				Safe_Delete();
1242 			}
1243 		}
1244 	} else {
1245 		AddDebugLogLineN( logRemoteClient, wxT("UDP ANSWER FNF : ") + GetUserName() + wxT(" - did not remove client because of current download state") );
1246 	}
1247 }
1248 
UDPReaskForDownload()1249 void CUpDownClient::UDPReaskForDownload()
1250 {
1251 
1252 	wxASSERT(m_reqfile);
1253 
1254 	if(!m_reqfile || m_bUDPPending ) {
1255 		return;
1256 	}
1257 
1258 	//#warning We should implement the quality tests for udp reliability
1259 	/*
1260 	if( m_nTotalUDPPackets > 3 && ((float)(m_nFailedUDPPackets/m_nTotalUDPPackets) > .3)) {
1261 		return;
1262 	}
1263 	*/
1264 
1265 	if (thePrefs::GetEffectiveUDPPort() == 0) {
1266 		return;
1267 	}
1268 
1269 	if (m_nUDPPort != 0 && !theApp->IsFirewalled() && !IsConnected()) {
1270 		//don't use udp to ask for sources
1271 		if(IsSourceRequestAllowed()) {
1272 			return;
1273 		}
1274 
1275 		m_bUDPPending = true;
1276 
1277 		CMemFile data(128);
1278 		data.WriteHash(m_reqfile->GetFileHash());
1279 
1280 		if (GetUDPVersion() > 3) {
1281 			if (m_reqfile->IsPartFile()) {
1282 				static_cast<CPartFile*>(m_reqfile)->WritePartStatus(&data);
1283 			}
1284 			else {
1285 				data.WriteUInt16(0);
1286 			}
1287 		}
1288 
1289 		if (GetUDPVersion() > 2) {
1290 			data.WriteUInt16(m_reqfile->m_nCompleteSourcesCount);
1291 		}
1292 
1293 		CPacket* response = new CPacket(data, OP_EMULEPROT, OP_REASKFILEPING);
1294 		AddDebugLogLineN( logClientUDP, wxT("Client UDP socket: send OP_REASKFILEPING") );
1295 		theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1296 		theApp->clientudp->SendPacket(response,GetConnectIP(),GetUDPPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0);
1297 	} else  if (HasLowID() && GetBuddyIP() && GetBuddyPort() && HasValidBuddyID()) {
1298 
1299 		m_bUDPPending = true;
1300 
1301 		CMemFile data(128);
1302 
1303 		data.WriteHash(CMD4Hash(GetBuddyID()));
1304 		data.WriteHash(m_reqfile->GetFileHash());
1305 
1306 		if (GetUDPVersion() > 3) {
1307 			if (m_reqfile->IsPartFile()) {
1308 				static_cast<CPartFile*>(m_reqfile)->WritePartStatus(&data);
1309 			} else {
1310 				data.WriteUInt16(0);
1311 			}
1312 		}
1313 
1314 		if (GetUDPVersion() > 2) {
1315 			data.WriteUInt16(m_reqfile->m_nCompleteSourcesCount);
1316 		}
1317 
1318 		CPacket* response = new CPacket(data, OP_EMULEPROT, OP_REASKCALLBACKUDP);
1319 		AddDebugLogLineN( logClientUDP, wxT("Client UDP socket: send OP_REASKCALLBACKUDP") );
1320 		theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1321 		theApp->clientudp->SendPacket(response, GetBuddyIP(), GetBuddyPort(), false, NULL, true, 0 );
1322 	}
1323 }
1324 
1325 
1326 // Get the next part that is requested
GetNextRequestedPart() const1327 uint16 CUpDownClient::GetNextRequestedPart() const
1328 {
1329 	uint16 part = 0xffff;
1330 
1331 	std::list<Pending_Block_Struct*>::const_iterator it = m_PendingBlocks_list.begin();
1332 	for (; it != m_PendingBlocks_list.end(); ++it) {
1333 		part = (*it)->block->StartOffset / PARTSIZE;
1334 		if (part != m_lastDownloadingPart) {
1335 			break;
1336 		}
1337 	}
1338 
1339 	return part;
1340 }
1341 
1342 
UpdateDisplayedInfo(bool force)1343 void CUpDownClient::UpdateDisplayedInfo(bool force)
1344 {
1345 	uint32 curTick = ::GetTickCount();
1346 	if (force || curTick-m_lastRefreshedDLDisplay > MINWAIT_BEFORE_DLDISPLAY_WINDOWUPDATE) {
1347 		// Check if we actually need to notify of changes
1348 		bool update = m_reqfile && m_reqfile->ShowSources();
1349 
1350 		// Check A4AF files only if needed
1351 		if ( !update ) {
1352 			A4AFList::iterator it = m_A4AF_list.begin();
1353 			for ( ; it != m_A4AF_list.end(); ++it ) {
1354 				if ( it->first->ShowSources() ) {
1355 					update = true;
1356 					break;
1357 				}
1358 			}
1359 		}
1360 
1361 		// And finnaly trigger an event if there's any reason
1362 		if ( update ) {
1363 			SourceItemType type;
1364 			switch (GetDownloadState()) {
1365 				case DS_DOWNLOADING:
1366 				case DS_ONQUEUE:
1367 					// We will send A4AF, which will be checked.
1368 					type = A4AF_SOURCE;
1369 					break;
1370 				default:
1371 					type = UNAVAILABLE_SOURCE;
1372 					break;
1373 			}
1374 
1375 			Notify_SourceCtrlUpdateSource(ECID(), type );
1376 		}
1377 
1378 		// Shared files view
1379 		if (m_uploadingfile && m_uploadingfile->ShowPeers()) {
1380 			Notify_SharedCtrlRefreshClient(ECID(), AVAILABLE_SOURCE);
1381 		}
1382 
1383 		m_lastRefreshedDLDisplay = curTick;
1384 	}
1385 }
1386 
GetObfuscationStatus() const1387 uint8 CUpDownClient::GetObfuscationStatus() const
1388 {
1389 	uint8 ret = OBST_UNDEFINED;
1390 	if (thePrefs::IsClientCryptLayerSupported()) {
1391 		if (SupportsCryptLayer()) {
1392 			if ((RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested()) && HasObfuscatedConnectionBeenEstablished()) {
1393 				ret = OBST_ENABLED;
1394 			} else {
1395 				ret = OBST_SUPPORTED;
1396 			}
1397 		} else {
1398 			ret = OBST_NOT_SUPPORTED;
1399 		}
1400 	} else {
1401 		ret = OBST_DISABLED;
1402 	}
1403 	return ret;
1404 }
1405 
1406 // IgnoreNoNeeded = will switch to files of which this source has no needed parts (if no better fiels found)
1407 // ignoreSuspensions = ignore timelimit for A4Af jumping
1408 // bRemoveCompletely = do not readd the file which the source is swapped from to the A4AF lists (needed if deleting or stopping a file)
1409 // toFile = Try to swap to this partfile only
1410 
SwapToAnotherFile(bool bIgnoreNoNeeded,bool ignoreSuspensions,bool bRemoveCompletely,CPartFile * toFile)1411 bool CUpDownClient::SwapToAnotherFile(bool bIgnoreNoNeeded, bool ignoreSuspensions, bool bRemoveCompletely, CPartFile* toFile)
1412 {
1413 	// Fail if m_reqfile is invalid
1414 	if ( m_reqfile == NULL ) {
1415 		return false;
1416 	}
1417 
1418 	// It would be stupid to swap away a downloading source
1419 	if (GetDownloadState() == DS_DOWNLOADING) {
1420 		return false;
1421 	}
1422 
1423 	// The iterator of the final target
1424 	A4AFList::iterator target = m_A4AF_list.end();
1425 
1426 	// Do we want to swap to a specific file?
1427 	if ( toFile != NULL ) {
1428 		A4AFList::iterator it = m_A4AF_list.find( toFile );
1429 		if ( it != m_A4AF_list.end() ) {
1430 
1431 			// We force ignoring of timestamps
1432 			if ( IsValidSwapTarget( it, bIgnoreNoNeeded, true ) ) {
1433 				// Set the target
1434 				target = it;
1435 			}
1436 		}
1437 	} else {
1438 		// We want highest priority possible, but need to start with
1439 		// a value less than any other priority
1440 		char priority = -1;
1441 
1442 		A4AFList::iterator it = m_A4AF_list.begin();
1443 		for ( ; it != m_A4AF_list.end(); ++it ) {
1444 			if ( IsValidSwapTarget( it, bIgnoreNoNeeded, ignoreSuspensions ) ) {
1445 				char cur_priority = it->first->GetDownPriority();
1446 
1447 				// We would prefer to get files with needed parts, thus rate them higher.
1448 				// However, this really only matters if bIgnoreNoNeeded is true.
1449 				if ( it->second.NeededParts )
1450 						cur_priority += 10;
1451 
1452 				// Change target if the current file has a higher rate than the previous
1453 				if ( cur_priority > priority ) {
1454 					priority = cur_priority;
1455 
1456 					// Set the new target
1457 					target = it;
1458 
1459 					// Break on the first High-priority file with needed parts
1460 					if ( priority == PR_HIGH + 10 ) {
1461 						break;
1462 					}
1463 				}
1464 			}
1465 		}
1466 	}
1467 
1468 	// Try to swap if we found a valid target
1469 	if ( target != m_A4AF_list.end() ) {
1470 
1471 		// Sanity check, if reqfile doesn't own the source, then something
1472 		// is wrong and the swap cannot proceed.
1473 		if ( m_reqfile->DelSource( this ) ) {
1474 			CPartFile* SwapTo = target->first;
1475 
1476 			// remove this client from the A4AF list of our new m_reqfile
1477 			if ( SwapTo->RemoveA4AFSource( this ) ) {
1478 				Notify_SourceCtrlRemoveSource(ECID(), SwapTo);
1479 			}
1480 
1481 			m_reqfile->RemoveDownloadingSource( this );
1482 
1483 			// Do we want to remove it completly? Say if the old file is getting deleted
1484 			if ( !bRemoveCompletely ) {
1485 				m_reqfile->AddA4AFSource( this );
1486 
1487 				// Set the status of the old file
1488 				m_A4AF_list[m_reqfile].NeededParts = (GetDownloadState() != DS_NONEEDEDPARTS);
1489 
1490 				// Avoid swapping to this file for a while
1491 				m_A4AF_list[m_reqfile].timestamp = ::GetTickCount();
1492 
1493 				Notify_SourceCtrlAddSource(m_reqfile, CCLIENTREF(this, wxT("CUpDownClient::SwapToAnotherFile Notify_SourceCtrlAddSource 1")), A4AF_SOURCE);
1494 			} else {
1495 				Notify_SourceCtrlRemoveSource(ECID(), m_reqfile);
1496 			}
1497 
1498 			SetDownloadState(DS_NONE);
1499 			ResetFileStatusInfo();
1500 
1501 			m_nRemoteQueueRank = 0;
1502 			m_nOldRemoteQueueRank = 0;
1503 
1504 			m_reqfile->UpdatePartsInfo();
1505 
1506 			SetRequestFile( SwapTo );
1507 
1508 			SwapTo->AddSource( this );
1509 
1510 			Notify_SourceCtrlAddSource(SwapTo, CCLIENTREF(this, wxT("CUpDownClient::SwapToAnotherFile Notify_SourceCtrlAddSource 2")), UNAVAILABLE_SOURCE);
1511 
1512 			// Remove the new reqfile from the list of other files
1513 			m_A4AF_list.erase( target );
1514 
1515 			return true;
1516 		}
1517 	}
1518 
1519 	return false;
1520 }
1521 
1522 
IsValidSwapTarget(A4AFList::iterator it,bool ignorenoneeded,bool ignoresuspended)1523 bool CUpDownClient::IsValidSwapTarget( A4AFList::iterator it, bool ignorenoneeded, bool ignoresuspended )
1524 {
1525 	wxASSERT( it != m_A4AF_list.end() && it->first );
1526 
1527 	// Check if this file has been suspended
1528 	if ( !ignoresuspended ) {
1529 		if ( ::GetTickCount() - it->second.timestamp >= PURGESOURCESWAPSTOP ) {
1530 			// The wait-time has been exceeded and the file is now a valid target
1531 			it->second.timestamp = 0;
1532 		} else {
1533 			// The file was still suspended and we are not ignoring suspensions
1534 			return false;
1535 		}
1536 	}
1537 
1538 	// Check if the client has needed parts
1539 	if ( !ignorenoneeded ) {
1540 		if ( !it->second.NeededParts ) {
1541 			return false;
1542 		}
1543 	}
1544 
1545 	// Final checks to see if the client is a valid target
1546 	CPartFile* cur_file = it->first;
1547 	if ( ( cur_file != m_reqfile && !cur_file->IsStopped() ) &&
1548 	     ( cur_file->GetStatus() == PS_READY || cur_file->GetStatus() == PS_EMPTY ) &&
1549 		 ( cur_file->IsPartFile() ) )
1550 	{
1551 		return true;
1552 	} else {
1553 		return false;
1554 	}
1555 }
1556 
1557 
SetRequestFile(CPartFile * reqfile)1558 void CUpDownClient::SetRequestFile(CPartFile* reqfile)
1559 {
1560 	if ( m_reqfile != reqfile ) {
1561 		// Decrement the source-count of the old request-file
1562 		if ( m_reqfile ) {
1563 			m_reqfile->ClientStateChanged( GetDownloadState(), -1 );
1564 			m_reqfile->UpdatePartsFrequency( this, false );
1565 		}
1566 
1567 		m_nPartCount = 0;
1568 		m_downPartStatus.clear();
1569 
1570 		m_reqfile = reqfile;
1571 
1572 		if ( reqfile ) {
1573 			// Increment the source-count of the new request-file
1574 			m_reqfile->ClientStateChanged( -1, GetDownloadState() );
1575 
1576 			m_nPartCount = reqfile->GetPartCount();
1577 		}
1578 	}
1579 }
1580 
SetReqFileAICHHash(CAICHHash * val)1581 void CUpDownClient::SetReqFileAICHHash(CAICHHash* val){
1582 	if(m_pReqFileAICHHash != NULL && m_pReqFileAICHHash != val)
1583 		delete m_pReqFileAICHHash;
1584 	m_pReqFileAICHHash = val;
1585 }
1586 
SendAICHRequest(CPartFile * pForFile,uint16 nPart)1587 void CUpDownClient::SendAICHRequest(CPartFile* pForFile, uint16 nPart){
1588 	CAICHRequestedData request;
1589 	request.m_nPart = nPart;
1590 	request.m_pClient.Link(this CLIENT_DEBUGSTRING("CUpDownClient::SendAICHRequest"));
1591 	request.m_pPartFile = pForFile;
1592 	CAICHHashSet::m_liRequestedData.push_back(request);
1593 	m_fAICHRequested = TRUE;
1594 	CMemFile data;
1595 	data.WriteHash(pForFile->GetFileHash());
1596 	data.WriteUInt16(nPart);
1597 	pForFile->GetAICHHashset()->GetMasterHash().Write(&data);
1598 	CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_AICHREQUEST);
1599 	theStats::AddUpOverheadOther(packet->GetPacketSize());
1600 	AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHREQUEST to") + GetFullIP());
1601 	SafeSendPacket(packet);
1602 }
1603 
ProcessAICHAnswer(const uint8_t * packet,uint32 size)1604 void CUpDownClient::ProcessAICHAnswer(const uint8_t* packet, uint32 size)
1605 {
1606 	if (m_fAICHRequested == FALSE){
1607 		throw wxString(wxT("Received unrequested AICH Packet"));
1608 	}
1609 	m_fAICHRequested = FALSE;
1610 
1611 	CMemFile data(packet, size);
1612 	if (size <= 16){
1613 		CAICHHashSet::ClientAICHRequestFailed(this);
1614 		return;
1615 	}
1616 
1617 	CMD4Hash hash = data.ReadHash();
1618 	CPartFile* pPartFile = theApp->downloadqueue->GetFileByID(hash);
1619 	CAICHRequestedData request = CAICHHashSet::GetAICHReqDetails(this);
1620 	uint16 nPart = data.ReadUInt16();
1621 	if (pPartFile != NULL && request.m_pPartFile == pPartFile && request.m_pClient.GetClient() == this && nPart == request.m_nPart){
1622 		CAICHHash ahMasterHash(&data);
1623 		if ( (pPartFile->GetAICHHashset()->GetStatus() == AICH_TRUSTED || pPartFile->GetAICHHashset()->GetStatus() == AICH_VERIFIED)
1624 			 && ahMasterHash == pPartFile->GetAICHHashset()->GetMasterHash())
1625 		{
1626 			if(pPartFile->GetAICHHashset()->ReadRecoveryData(request.m_nPart*PARTSIZE, &data)){
1627 				// finally all checks passed, everythings seem to be fine
1628 				AddDebugLogLineN(logAICHTransfer, wxT("AICH Packet Answer: Succeeded to read and validate received recoverydata"));
1629 				CAICHHashSet::RemoveClientAICHRequest(this);
1630 				pPartFile->AICHRecoveryDataAvailable(request.m_nPart);
1631 				return;
1632 			} else {
1633 				AddDebugLogLineN(logAICHTransfer, wxT("AICH Packet Answer: Succeeded to read and validate received recoverydata"));
1634 			}
1635 		} else {
1636 			AddDebugLogLineN( logAICHTransfer, wxT("AICH Packet Answer: Masterhash differs from packethash or hashset has no trusted Masterhash") );
1637 		}
1638 	} else {
1639 		AddDebugLogLineN( logAICHTransfer, wxT("AICH Packet Answer: requested values differ from values in packet") );
1640 	}
1641 
1642 	CAICHHashSet::ClientAICHRequestFailed(this);
1643 }
1644 
1645 
ProcessAICHRequest(const uint8_t * packet,uint32 size)1646 void CUpDownClient::ProcessAICHRequest(const uint8_t* packet, uint32 size)
1647 {
1648 	if (size != 16 + 2 + CAICHHash::GetHashSize()) {
1649 		throw wxString(wxT("Received AICH Request Packet with wrong size"));
1650 	}
1651 
1652 	CMemFile data(packet, size);
1653 
1654 	CMD4Hash hash = data.ReadHash();
1655 	uint16 nPart = data.ReadUInt16();
1656 	CAICHHash ahMasterHash(&data);
1657 	CKnownFile* pKnownFile = theApp->sharedfiles->GetFileByID(hash);
1658 	if (pKnownFile != NULL){
1659 		if (pKnownFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE && pKnownFile->GetAICHHashset()->HasValidMasterHash()
1660 			&& pKnownFile->GetAICHHashset()->GetMasterHash() == ahMasterHash && pKnownFile->GetPartCount() > nPart
1661 			&& pKnownFile->GetFileSize() > EMBLOCKSIZE && pKnownFile->GetFileSize() - PARTSIZE*nPart > EMBLOCKSIZE)
1662 		{
1663 			CMemFile fileResponse;
1664 			fileResponse.WriteHash(pKnownFile->GetFileHash());
1665 			fileResponse.WriteUInt16(nPart);
1666 			pKnownFile->GetAICHHashset()->GetMasterHash().Write(&fileResponse);
1667 			if (pKnownFile->GetAICHHashset()->CreatePartRecoveryData(nPart*PARTSIZE, &fileResponse)){
1668 				AddDebugLogLineN(logAICHTransfer,
1669 					CFormat(wxT("AICH Packet Request: Sucessfully created and send recoverydata for '%s' to %s"))
1670 						% pKnownFile->GetFileName() % GetClientFullInfo());
1671 
1672 				CPacket* packAnswer = new CPacket(fileResponse, OP_EMULEPROT, OP_AICHANSWER);
1673 				theStats::AddUpOverheadOther(packAnswer->GetPacketSize());
1674 				AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHANSWER to") + GetFullIP());
1675 				SafeSendPacket(packAnswer);
1676 				return;
1677 			} else {
1678 				AddDebugLogLineN(logAICHTransfer,
1679 					CFormat(wxT("AICH Packet Request: Failed to create recoverydata for '%s' to %s"))
1680 						% pKnownFile->GetFileName() % GetClientFullInfo());
1681 			}
1682 		} else {
1683 			AddDebugLogLineN(logAICHTransfer,
1684 				CFormat(wxT("AICH Packet Request: Failed to create recoverydata - Hashset not ready or requested Hash differs from Masterhash for '%s' to %s"))
1685 					% pKnownFile->GetFileName() % GetClientFullInfo());
1686 		}
1687 	} else {
1688 		AddDebugLogLineN( logAICHTransfer, wxT("AICH Packet Request: Failed to find requested shared file - ") + GetClientFullInfo() );
1689 	}
1690 
1691 	CPacket* packAnswer = new CPacket(OP_AICHANSWER, 16, OP_EMULEPROT);
1692 	packAnswer->Copy16ToDataBuffer(hash.GetHash());
1693 	theStats::AddUpOverheadOther(packAnswer->GetPacketSize());
1694 	AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHANSWER to") + GetFullIP());
1695 	SafeSendPacket(packAnswer);
1696 }
1697 
ProcessAICHFileHash(CMemFile * data,const CPartFile * file)1698 void CUpDownClient::ProcessAICHFileHash(CMemFile* data, const CPartFile* file){
1699 	CPartFile* pPartFile;
1700 	if (file == NULL){
1701 		pPartFile = theApp->downloadqueue->GetFileByID(data->ReadHash());
1702 	} else {
1703 		pPartFile = const_cast<CPartFile*>(file);
1704 	}
1705 	CAICHHash ahMasterHash(data);
1706 
1707 	if(pPartFile != NULL && pPartFile == GetRequestFile()){
1708 		SetReqFileAICHHash(new CAICHHash(ahMasterHash));
1709 		pPartFile->GetAICHHashset()->UntrustedHashReceived(ahMasterHash, GetConnectIP());
1710 	} else {
1711 		AddDebugLogLineN( logAICHTransfer, wxT("ProcessAICHFileHash(): PartFile not found or Partfile differs from requested file, ") + GetClientFullInfo() );
1712 	}
1713 }
1714 // File_checked_for_headers
1715