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// Any parts of this program derived from the xMule, lMule or eMule project,
7// or contributed by third-party developers are copyrighted by their
8// respective authors.
9//
10// This program is free software; you can redistribute it and/or modify
11// it under the terms of the GNU General Public License as published by
12// the Free Software Foundation; either version 2 of the License, or
13// (at your option) any later version.
14//
15// This program is distributed in the hope that it will be useful,
16// but WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with this program; if not, write to the Free Software
22// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301, USA
23//
24
25#include "ClientTCPSocket.h"	// Interface declarations
26
27#include <protocol/Protocols.h>
28#include <protocol/ed2k/Client2Client/TCP.h>
29#include <protocol/ed2k/Client2Client/UDP.h> // Sometimes we reply with UDP packets.
30#include <protocol/ed2k/ClientSoftware.h>
31#include <protocol/kad2/Client2Client/TCP.h>
32#include <common/EventIDs.h>
33
34#include "Preferences.h"	// Needed for thePrefs
35#include "Packet.h"		// Needed for CPacket
36#include "Statistics.h"		// Needed for theStats
37#include "Logger.h"		// Neeed for logRemoteClient
38#include "updownclient.h"	// Needed for CUpDownClient
39#include <common/Format.h>	// Needed for CFormat
40#include "amule.h"		// Needed for theApp
41#include "SharedFileList.h"	// Needed for CSharedFileList
42#include "ClientList.h"		// Needed for CClientList
43#include "UploadQueue.h"	// Needed for CUploadQueue
44#include "ClientUDPSocket.h"	// Needed for CClientUDPSocket
45#include "PartFile.h"		// Needed for CPartFile
46#include "MemFile.h"		// Needed for CMemFile
47#include "kademlia/kademlia/Kademlia.h" // Needed for CKademlia::Kademlia
48#include "kademlia/kademlia/Prefs.h"	// Needed for CKademlia::CPrefs
49#include "DownloadQueue.h"	// Needed for CDownloadQueue
50#include "Server.h"		// Needed for CServer
51#include "ServerList.h"		// Needed for CServerList
52#include "IPFilter.h"		// Needed for CIPFilter
53#include "ListenSocket.h"	// Needed for CListenSocket
54#include "GuiEvents.h"		// Needed for Notify_*
55
56
57//#define __PACKET_RECV_DUMP__
58
59//------------------------------------------------------------------------------
60// CClientTCPSocketHandler
61//------------------------------------------------------------------------------
62
63class CClientTCPSocketHandler: public wxEvtHandler
64{
65public:
66	CClientTCPSocketHandler() {};
67
68private:
69	void ClientTCPSocketHandler(wxSocketEvent& event);
70	DECLARE_EVENT_TABLE()
71};
72
73BEGIN_EVENT_TABLE(CClientTCPSocketHandler, wxEvtHandler)
74	EVT_SOCKET(ID_CLIENTTCPSOCKET_EVENT, CClientTCPSocketHandler::ClientTCPSocketHandler)
75END_EVENT_TABLE()
76
77void CClientTCPSocketHandler::ClientTCPSocketHandler(wxSocketEvent& event)
78{
79	wxSocketBase* baseSocket = event.GetSocket();
80//	wxASSERT(baseSocket);	// Rather want a log message right now. Enough other wx problems. >:(
81	if (!baseSocket) {		// WTF?
82		AddDebugLogLineN(logClient, wxT("received bad wxSocketEvent"));
83		return;
84	}
85
86	CClientTCPSocket *socket = dynamic_cast<CClientTCPSocket *>(baseSocket);
87	wxASSERT(socket);
88	if (!socket) {
89		return;
90	}
91
92	if (socket->OnDestroy() || socket->ForDeletion()) {
93		return;
94	}
95
96	switch(event.GetSocketEvent()) {
97		case wxSOCKET_LOST:
98			socket->OnError(0xFEFF /* SOCKET_LOST is not an error */);
99			break;
100		case wxSOCKET_INPUT:
101			socket->OnReceive(0);
102			break;
103		case wxSOCKET_OUTPUT:
104			socket->OnSend(0);
105			break;
106		case wxSOCKET_CONNECTION:
107			// connection stablished, nothing to do about it?
108			socket->OnConnect(socket->Error() ? socket->LastError() : 0);
109			break;
110		default:
111			// Nothing should arrive here...
112			wxFAIL;
113			break;
114	}
115}
116
117//
118// There can be only one. :)
119//
120static CClientTCPSocketHandler g_clientReqSocketHandler;
121
122
123//------------------------------------------------------------------------------
124// CClientTCPSocket
125//------------------------------------------------------------------------------
126
127CClientTCPSocket::CClientTCPSocket(CUpDownClient* in_client, const CProxyData *ProxyData)
128	: CEMSocket(ProxyData)
129{
130	SetClient(in_client);
131	if (in_client) {
132		m_remoteip = wxUINT32_SWAP_ALWAYS(in_client->GetUserIDHybrid());
133	} else {
134		m_remoteip = 0;
135	}
136
137	ResetTimeOutTimer();
138	m_ForDeletion = false;
139
140	SetEventHandler(g_clientReqSocketHandler, ID_CLIENTTCPSOCKET_EVENT);
141	SetNotify(
142		wxSOCKET_CONNECTION_FLAG |
143		wxSOCKET_INPUT_FLAG |
144		wxSOCKET_OUTPUT_FLAG |
145		wxSOCKET_LOST_FLAG);
146	Notify(true);
147
148	theApp->listensocket->AddSocket(this);
149	theApp->listensocket->AddConnection();
150}
151
152CClientTCPSocket::~CClientTCPSocket()
153{
154	// remove event handler
155	SetNotify(0);
156	Notify(false);
157
158	if (m_client) {
159		m_client->SetSocket( NULL );
160	}
161	m_client = NULL;
162
163	if (theApp->listensocket && !theApp->listensocket->OnShutdown()) {
164		theApp->listensocket->RemoveSocket(this);
165	}
166}
167
168bool CClientTCPSocket::InitNetworkData()
169{
170	wxASSERT(!m_remoteip);
171	wxASSERT(!m_client);
172	amuleIPV4Address addr;
173	GetPeer(addr);
174	m_remoteip = StringIPtoUint32(addr.IPAddress());
175
176	MULE_CHECK(m_remoteip, false);
177
178	if (theApp->ipfilter->IsFiltered(m_remoteip)) {
179		AddDebugLogLineN(logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Filtered IP)"));
180		return false;
181	} else if (theApp->clientlist->IsBannedClient(m_remoteip)) {
182		AddDebugLogLineN(logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Banned IP)"));
183		return false;
184	} else {
185		AddDebugLogLineN(logClient, wxT("Accepted connection from ") + addr.IPAddress());
186		return true;
187	}
188}
189
190void CClientTCPSocket::ResetTimeOutTimer()
191{
192	timeout_timer = ::GetTickCount();
193}
194
195
196bool CClientTCPSocket::CheckTimeOut()
197{
198	// 0.42x
199	uint32 uTimeout = GetTimeOut();
200	if (m_client) {
201
202		if (m_client->GetKadState() == KS_CONNECTED_BUDDY) {
203			//We originally ignored the timeout here for buddies.
204			//This was a stupid idea on my part. There is now a ping/pong system
205			//for buddies. This ping/pong system now prevents timeouts.
206			//This release will allow lowID clients with KadVersion 0 to remain connected.
207			//But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
208			//JOHNTODO: Don't forget to remove backward support in a future release.
209			if ( m_client->GetKadVersion() == 0 ) {
210				return false;
211			}
212
213			uTimeout += MIN2MS(15);
214		}
215
216		if (m_client->GetChatState() != MS_NONE) {
217			uTimeout += CONNECTION_TIMEOUT;
218		}
219	}
220
221	if (::GetTickCount() - timeout_timer > uTimeout){
222		timeout_timer = ::GetTickCount();
223		Disconnect(wxT("Timeout"));
224		return true;
225	}
226
227	return false;
228}
229
230
231void CClientTCPSocket::SetClient(CUpDownClient* pClient)
232{
233	m_client = pClient;
234	if (m_client) {
235		m_client->SetSocket( this );
236	}
237}
238
239
240void CClientTCPSocket::OnClose(int nErrorCode)
241{
242	// 0.42x
243	wxASSERT(theApp->listensocket->IsValidSocket(this));
244	CEMSocket::OnClose(nErrorCode);
245	if (nErrorCode) {
246		Disconnect(CFormat(wxT("Closed: %u")) % nErrorCode);
247	} else {
248		Disconnect(wxT("Close"));
249	}
250}
251
252
253void CClientTCPSocket::Disconnect(const wxString& strReason)
254{
255	byConnected = ES_DISCONNECTED;
256	if (m_client) {
257		if (m_client->Disconnected(strReason, true)) {
258			// Somehow, Safe_Delete() is beeing called by Disconnected(),
259			// or any other function that sets m_client to NULL,
260			// so we must check m_client first.
261			if (m_client) {
262				m_client->SetSocket( NULL );
263				m_client->Safe_Delete();
264			}
265		}
266		m_client = NULL;
267	}
268
269	Safe_Delete();
270}
271
272
273void CClientTCPSocket::Safe_Delete()
274{
275	// More paranoia - make sure client is unlinked in any case
276	if (m_client) {
277		m_client->SetSocket( NULL );
278		m_client = NULL;
279	}
280
281	if ( !ForDeletion() && !OnDestroy() ) {
282		// Paranoia is back.
283		SetNotify(0);
284		Notify(false);
285		// lfroen: first of all - stop handler
286		m_ForDeletion = true;
287
288		byConnected = ES_DISCONNECTED;
289		Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
290		Destroy();
291	}
292}
293
294
295void CClientTCPSocket::Safe_Delete_Client()
296{
297	if (m_client) {
298		m_client->Safe_Delete();
299		m_client = NULL;
300	}
301}
302
303
304bool CClientTCPSocket::ProcessPacket(const byte* buffer, uint32 size, uint8 opcode)
305{
306	#ifdef __PACKET_RECV_DUMP__
307	//printf("Rec: OPCODE %x \n",opcode);
308	DumpMem(buffer, size);
309	#endif
310	if (!m_client && opcode != OP_HELLO) {
311		throw wxString(wxT("Asks for something without saying hello"));
312	} else if (m_client && opcode != OP_HELLO && opcode != OP_HELLOANSWER) {
313		m_client->CheckHandshakeFinished();
314	}
315
316	switch(opcode) {
317		case OP_HELLOANSWER: {	// 0.43b
318			AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_HELLOANSWER from ") + m_client->GetFullIP());
319			theStats::AddDownOverheadOther(size);
320			m_client->ProcessHelloAnswer(buffer, size);
321
322			// start secure identification, if
323			//  - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
324			//	- we have received eMule-OP_HELLOANSWER (new eMule)
325			if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
326				m_client->InfoPacketsReceived();
327			}
328
329			// Socket might die because of sending in InfoPacketsReceived, so check
330			if (m_client) {
331				m_client->ConnectionEstablished();
332			}
333
334			// Socket might die on ConnectionEstablished somehow. Check it.
335			if (m_client) {
336				Notify_SharedCtrlRefreshClient( m_client->ECID() , AVAILABLE_SOURCE);
337			}
338
339			break;
340		}
341		case OP_HELLO: {	// 0.43b
342
343			theStats::AddDownOverheadOther(size);
344			bool bNewClient = !m_client;
345			if (bNewClient) {
346				// create new client to save standart informations
347				m_client = new CUpDownClient(this);
348			}
349
350			// Do not move up!
351			AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_HELLO from ") + m_client->GetFullIP() );
352
353			bool bIsMuleHello = false;
354
355			try{
356				bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
357			} catch(...) {
358				if (bNewClient && m_client) {
359					// Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
360					m_client->Safe_Delete();
361					m_client = NULL;
362				}
363				throw;
364			}
365
366			if (thePrefs::ParanoidFilter() && !IsLowID(m_client->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid()))) {
367				wxString reason = wxT("Client claims a different IP from the one we received the hello packet from: ");
368				reason += Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
369				AddDebugLogLineN(logClient, reason);
370				if (bNewClient) {
371					m_client->Safe_Delete();
372					m_client = NULL;
373				}
374				Disconnect(wxT("Paranoid disconecting: ") + reason);
375				return false;
376			}
377
378			// if IP is filtered, dont reply but disconnect...
379			if (theApp->ipfilter->IsFiltered(m_client->GetIP())) {
380				if (bNewClient) {
381					m_client->Safe_Delete();
382					m_client = NULL;
383				}
384				Disconnect(wxT("IPFilter"));
385				return false;
386			}
387
388			wxASSERT(m_client);
389
390			// now we check if we know this client already. if yes this socket will
391			// be attached to the known client, the new client will be deleted
392			// and the var. "client" will point to the known client.
393			// if not we keep our new-constructed client ;)
394			if (theApp->clientlist->AttachToAlreadyKnown(&m_client,this)) {
395				// update the old client informations
396				bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
397			} else {
398				theApp->clientlist->AddClient(m_client);
399				m_client->SetCommentDirty();
400			}
401			Notify_SharedCtrlRefreshClient( m_client->ECID(), AVAILABLE_SOURCE );
402			// send a response packet with standart informations
403			if ((m_client->GetHashType() == SO_EMULE) && !bIsMuleHello) {
404				m_client->SendMuleInfoPacket(false);
405			}
406
407			// Client might die from Sending in SendMuleInfoPacket, so check
408			if ( m_client ) {
409				m_client->SendHelloAnswer();
410			}
411
412			// Kry - If the other side supports it, send OS_INFO
413			// Client might die from Sending in SendHelloAnswer, so check
414			if (m_client && m_client->GetOSInfoSupport()) {
415				m_client->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
416			}
417
418			// Client might die from Sending in SendMuleInfoPacket, so check
419			if ( m_client ) {
420				m_client->ConnectionEstablished();
421			}
422
423			// start secure identification, if
424			//	- we have received eMule-OP_HELLO (new eMule)
425			if (m_client && m_client->GetInfoPacketsReceived() == IP_BOTH) {
426					m_client->InfoPacketsReceived();
427			}
428
429			break;
430		}
431		case OP_REQUESTFILENAME: {	// 0.43b
432			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client->GetFullIP() );
433
434			theStats::AddDownOverheadFileRequest(size);
435			// IP banned, no answer for this request
436			if (m_client->IsBanned()) {
437				break;
438			}
439			if (size >= 16) {
440				if (!m_client->GetWaitStartTime()) {
441					m_client->SetWaitStartTime();
442				}
443				CMemFile data_in(buffer, size);
444				CMD4Hash reqfilehash = data_in.ReadHash();
445				CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
446				if ( reqfile == NULL ) {
447					reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
448					if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
449						break;
450					}
451				}
452				// if we are downloading this file, this could be a new source
453				// no passive adding of files with only one part
454				if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
455					if (thePrefs::GetMaxSourcePerFile() >
456						((CPartFile*)reqfile)->GetSourceCount()) {
457						theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
458					}
459				}
460
461				// check to see if this is a new file they are asking for
462				if (m_client->GetUploadFileID() != reqfilehash) {
463						m_client->SetCommentDirty();
464				}
465
466				m_client->SetUploadFileID(reqfile);
467				m_client->ProcessExtendedInfo(&data_in, reqfile);
468
469				// send filename etc
470				CMemFile data_out(128);
471				data_out.WriteHash(reqfile->GetFileHash());
472
473				// Since it's for somebody else to see, we need to send the prettified
474				// filename, rather than the (possibly) mangled actual filename.
475				data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
476
477				CPacket* packet = new CPacket(data_out, OP_EDONKEYPROT, OP_REQFILENAMEANSWER);
478				theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
479				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client->GetFullIP() );
480				SendPacket(packet,true);
481
482				// SendPacket might kill the socket, so check
483				if (m_client)
484					m_client->SendCommentInfo(reqfile);
485
486				break;
487			}
488			throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
489			break;
490		}
491		case OP_SETREQFILEID: {	// 0.43b EXCEPT track of bad clients
492			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SETREQFILEID from ") + m_client->GetFullIP() );
493
494			theStats::AddDownOverheadFileRequest(size);
495
496			if (m_client->IsBanned()) {
497				break;
498			}
499
500			// DbT:FileRequest
501			if (size == 16) {
502				if (!m_client->GetWaitStartTime()) {
503					m_client->SetWaitStartTime();
504				}
505
506				const CMD4Hash fileID(buffer);
507				CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(fileID);
508				if ( reqfile == NULL ) {
509					reqfile = theApp->downloadqueue->GetFileByID(fileID);
510					if ( !( reqfile  != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
511						CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
512						replypacket->Copy16ToDataBuffer(fileID.GetHash());
513						theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
514						AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILERE to ") + m_client->GetFullIP() );
515						SendPacket(replypacket, true);
516						break;
517					}
518				}
519
520				// check to see if this is a new file they are asking for
521				if (m_client->GetUploadFileID() != fileID) {
522					m_client->SetCommentDirty();
523				}
524
525				m_client->SetUploadFileID(reqfile);
526				// send filestatus
527				CMemFile data(16+16);
528				data.WriteHash(reqfile->GetFileHash());
529				if (reqfile->IsPartFile()) {
530					((CPartFile*)reqfile)->WritePartStatus(&data);
531				} else {
532					data.WriteUInt16(0);
533				}
534				CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_FILESTATUS);
535				theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
536				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILESTATUS to ") + m_client->GetFullIP() );
537				SendPacket(packet, true);
538				break;
539			}
540			throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
541			break;
542			// DbT:End
543		}
544
545		case OP_FILEREQANSNOFIL: {	// 0.43b protocol, lacks ZZ's download manager on swap
546			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client->GetFullIP() );
547
548			theStats::AddDownOverheadFileRequest(size);
549			if (size == 16) {
550				// if that client does not have my file maybe has another different
551				CPartFile* reqfile = theApp->downloadqueue->GetFileByID(CMD4Hash(buffer));
552				if ( reqfile) {
553					reqfile->AddDeadSource( m_client );
554				} else {
555					break;
556				}
557
558				// we try to swap to another file ignoring no needed parts files
559				switch (m_client->GetDownloadState()) {
560					case DS_CONNECTED:
561					case DS_ONQUEUE:
562					case DS_NONEEDEDPARTS:
563					if (!m_client->SwapToAnotherFile(true, true, true, NULL)) {
564						theApp->downloadqueue->RemoveSource(m_client);
565					}
566					break;
567				}
568				break;
569			}
570			throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
571			break;
572		}
573
574		case OP_REQFILENAMEANSWER: {	// 0.43b except check for bad clients
575			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client->GetFullIP() );
576
577			theStats::AddDownOverheadFileRequest(size);
578			CMemFile data(buffer, size);
579			CMD4Hash hash = data.ReadHash();
580			const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
581			m_client->ProcessFileInfo(&data, file);
582			break;
583		}
584
585		case OP_FILESTATUS: {		// 0.43b except check for bad clients
586			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILESTATUS from ") + m_client->GetFullIP() );
587
588			theStats::AddDownOverheadFileRequest(size);
589			CMemFile data(buffer, size);
590			CMD4Hash hash = data.ReadHash();
591			const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
592			m_client->ProcessFileStatus(false, &data, file);
593			break;
594		}
595
596		case OP_STARTUPLOADREQ: {
597			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client->GetFullIP() );
598
599			theStats::AddDownOverheadFileRequest(size);
600
601			if (!m_client->CheckHandshakeFinished()) {
602				break;
603			}
604
605			m_client->CheckForAggressive();
606			if ( m_client->IsBanned() ) {
607				break;
608			}
609
610			if (size == 16) {
611				const CMD4Hash fileID(buffer);
612				CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(fileID);
613				if (reqfile) {
614					if (m_client->GetUploadFileID() != fileID) {
615						m_client->SetCommentDirty();
616					}
617					m_client->SetUploadFileID(reqfile);
618					m_client->SendCommentInfo(reqfile);
619
620					// Socket might die because of SendCommentInfo, so check
621					if (m_client)
622						theApp->uploadqueue->AddClientToQueue(m_client);
623				}
624			}
625			break;
626		}
627
628		case OP_QUEUERANK: {	// 0.43b
629			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_QUEUERANK from ") + m_client->GetFullIP() );
630
631			theStats::AddDownOverheadFileRequest(size);
632			CMemFile data(buffer, size);
633			uint32 rank = data.ReadUInt32();
634
635			m_client->SetRemoteQueueRank(rank);
636			break;
637		}
638
639		case OP_ACCEPTUPLOADREQ: {	// 0.42e (xcept khaos stats)
640			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client->GetFullIP() );
641
642			theStats::AddDownOverheadFileRequest(size);
643			if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
644				if (m_client->GetDownloadState() == DS_ONQUEUE ) {
645					m_client->SetDownloadState(DS_DOWNLOADING);
646					m_client->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
647					m_client->SendBlockRequests();
648				}
649			} else {
650				if (!m_client->GetSentCancelTransfer()) {
651					CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
652					theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
653					AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
654					m_client->SendPacket(packet,true,true);
655
656					// SendPacket can cause the socket to die, so check
657					if (m_client)
658						m_client->SetSentCancelTransfer(1);
659				}
660
661				if (m_client)
662					m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
663			}
664			break;
665		}
666
667		case OP_REQUESTPARTS: {		// 0.43b
668			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client->GetFullIP() );
669
670			theStats::AddDownOverheadFileRequest(size);
671
672			m_client->ProcessRequestPartsPacket(buffer, size, false);
673
674			break;
675		}
676
677		case OP_CANCELTRANSFER: {		// 0.43b
678			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client->GetFullIP() );
679
680			theStats::AddDownOverheadFileRequest(size);
681			theApp->uploadqueue->RemoveFromUploadQueue(m_client);
682			AddDebugLogLineN( logClient, m_client->GetUserName() + wxT(": Upload session ended due canceled transfer."));
683			break;
684		}
685
686		case OP_END_OF_DOWNLOAD: { // 0.43b except check for bad clients
687			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client->GetFullIP() );
688
689			theStats::AddDownOverheadFileRequest(size);
690			if (size>=16 && m_client->GetUploadFileID() == CMD4Hash(buffer)) {
691				theApp->uploadqueue->RemoveFromUploadQueue(m_client);
692				AddDebugLogLineN( logClient, m_client->GetUserName() + wxT(": Upload session ended due ended transfer."));
693			}
694			break;
695		}
696
697		case OP_HASHSETREQUEST: {		// 0.43b except check for bad clients
698			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client->GetFullIP() );
699
700
701			theStats::AddDownOverheadFileRequest(size);
702			if (size != 16) {
703				throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
704			}
705			m_client->SendHashsetPacket(CMD4Hash(buffer));
706			break;
707		}
708
709		case OP_HASHSETANSWER: {		// 0.43b
710			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client->GetFullIP() );
711
712			theStats::AddDownOverheadFileRequest(size);
713			m_client->ProcessHashSet(buffer, size);
714			break;
715		}
716
717		case OP_SENDINGPART: {		// 0.47a
718			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SENDINGPART from ") + m_client->GetFullIP() );
719
720			if (	 m_client->GetRequestFile() &&
721				!m_client->GetRequestFile()->IsStopped() &&
722				(m_client->GetRequestFile()->GetStatus() == PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
723
724				m_client->ProcessBlockPacket(buffer, size, false, false);
725
726				if ( 	m_client &&
727					( m_client->GetRequestFile()->IsStopped() ||
728					  m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
729					  m_client->GetRequestFile()->GetStatus() == PS_ERROR) ) {
730					if (!m_client->GetSentCancelTransfer()) {
731						CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
732						theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
733						AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
734						m_client->SendPacket(packet,true,true);
735
736						// Socket might die because of SendPacket, so check
737						if (m_client)
738							m_client->SetSentCancelTransfer(1);
739					}
740
741					if (m_client)
742						m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
743				}
744			} else {
745				if (!m_client->GetSentCancelTransfer()) {
746					CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
747					theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
748					AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
749					m_client->SendPacket(packet,true,true);
750
751					// Socket might die because of SendPacket, so check
752					m_client->SetSentCancelTransfer(1);
753				}
754				m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
755			}
756			break;
757		}
758
759		case OP_OUTOFPARTREQS: {	// 0.43b
760			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client->GetFullIP() );
761
762			theStats::AddDownOverheadFileRequest(size);
763			if (m_client->GetDownloadState() == DS_DOWNLOADING) {
764				m_client->SetDownloadState(DS_ONQUEUE);
765			}
766			break;
767		}
768
769		case OP_CHANGE_CLIENT_ID: { 	// Kad reviewed
770			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client->GetFullIP() );
771
772			theStats::AddDownOverheadOther(size);
773			CMemFile data(buffer, size);
774			uint32 nNewUserID = data.ReadUInt32();
775			uint32 nNewServerIP = data.ReadUInt32();
776
777			if (IsLowID(nNewUserID)) { // client changed server and gots a LowID
778				CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
779				if (pNewServer != NULL){
780					m_client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
781					m_client->SetServerIP(nNewServerIP);
782					m_client->SetServerPort(pNewServer->GetPort());
783				}
784			} else if (nNewUserID == m_client->GetIP()) { // client changed server and gots a HighID(IP)
785				m_client->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID));
786				CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
787				if (pNewServer != NULL){
788					m_client->SetServerIP(nNewServerIP);
789					m_client->SetServerPort(pNewServer->GetPort());
790				}
791			}
792
793			break;
794		}
795
796		case OP_CHANGE_SLOT:{	// 0.43b
797			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client->GetFullIP() );
798
799			// sometimes sent by Hybrid
800			theStats::AddDownOverheadOther(size);
801			break;
802		}
803
804		case OP_MESSAGE: {		// 0.43b
805			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MESSAGE from ") + m_client->GetFullIP() );
806
807			theStats::AddDownOverheadOther(size);
808
809			if (size < 2) {
810				throw wxString(wxT("invalid message packet"));
811			}
812			CMemFile message_file(buffer, size);
813			uint16 length = message_file.ReadUInt16();
814			if (length + 2u != size) {
815				throw wxString(wxT("invalid message packet"));
816			}
817
818			// limit message length
819			static const uint16 MAX_CLIENT_MSG_LEN = 450;
820
821			if (length > MAX_CLIENT_MSG_LEN) {
822				AddDebugLogLineN(logRemoteClient, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
823					% m_client->GetUserName() % m_client->GetFullIP() % (length - MAX_CLIENT_MSG_LEN));
824				length = MAX_CLIENT_MSG_LEN;
825			}
826
827			wxString message = message_file.ReadOnlyString((m_client->GetUnicodeSupport() != utf8strNone), length);
828			m_client->ProcessChatMessage(message);
829
830			break;
831		}
832
833		case OP_ASKSHAREDFILES:	{	// 0.43b (well, er, it does the same, but in our own way)
834			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
835
836			// client wants to know what we have in share, let's see if we allow him to know that
837			theStats::AddDownOverheadOther(size);
838			// IP banned, no answer for this request
839			if (m_client->IsBanned()) {
840				break;
841			}
842
843			if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
844				AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
845					% m_client->GetUserName()
846					% m_client->GetUserIDHybrid() );
847
848				std::vector<CKnownFile*> list;
849				theApp->sharedfiles->CopyFileList(list);
850
851				CMemFile tempfile(80);
852				tempfile.WriteUInt32(list.size());
853				for (unsigned i = 0; i < list.size(); ++i) {
854					if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
855						list[i]->CreateOfferedFilePacket(&tempfile, NULL, m_client);
856					}
857				}
858
859				// create a packet and send it
860				CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
861				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
862				theStats::AddUpOverheadOther(replypacket->GetPacketSize());
863				SendPacket(replypacket, true, true);
864			} else {
865				AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
866					% m_client->GetUserName()
867					% m_client->GetUserIDHybrid() );
868
869				CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
870				theStats::AddUpOverheadOther(replypacket->GetPacketSize());
871				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
872				SendPacket(replypacket, true, true);
873			}
874
875			break;
876		}
877
878		case OP_ASKSHAREDFILESANSWER: {	// 0.43b
879			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
880
881			theStats::AddDownOverheadOther(size);
882			wxString EmptyStr;
883			m_client->ProcessSharedFileList(buffer, size, EmptyStr);
884			break;
885		}
886
887		case OP_ASKSHAREDDIRS: { 		// 0.43b
888			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
889
890			theStats::AddDownOverheadOther(size);
891			wxASSERT( size == 0 );
892			// IP banned, no answer for this request
893			if (m_client->IsBanned()) {
894				break;
895			}
896			if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
897				AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
898					% m_client->GetUserName()
899 					% m_client->GetUserIDHybrid() );
900				// send the list of shared directories
901				m_client->SendSharedDirectories();
902			} else {
903				AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
904					% m_client->GetUserName()
905					% m_client->GetUserIDHybrid() );
906
907				CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
908				theStats::AddUpOverheadOther(replypacket->GetPacketSize());
909				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
910				SendPacket(replypacket, true, true);
911			}
912
913			break;
914		}
915
916		case OP_ASKSHAREDFILESDIR: {	// 0.43b
917			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
918
919			theStats::AddDownOverheadOther(size);
920			// IP banned, no answer for this request
921			if (m_client->IsBanned()) {
922				break;
923			}
924			CMemFile data(buffer, size);
925
926			wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
927			if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
928				AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory '%s' -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
929				wxASSERT( data.GetPosition() == data.GetLength() );
930				// send the list of shared files for the requested directory
931				m_client->SendSharedFilesOfDirectory(strReqDir);
932			} else {
933				AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory '%s' -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
934
935				CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
936				theStats::AddUpOverheadOther(replypacket->GetPacketSize());
937				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
938				SendPacket(replypacket, true, true);
939			}
940			break;
941		}
942
943		case OP_ASKSHAREDDIRSANS:{		// 0.43b
944			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
945
946			theStats::AddDownOverheadOther(size);
947			if (m_client->GetFileListRequested() == 1){
948				CMemFile data(buffer, size);
949				uint32 uDirs = data.ReadUInt32();
950				for (uint32 i = 0; i < uDirs; i++){
951					wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
952					AddLogLineC(CFormat( _("User %s (%u) shares directory '%s'") )
953						% m_client->GetUserName()
954						% m_client->GetUserIDHybrid()
955						% strDir );
956
957					CMemFile tempfile(80);
958					tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
959					CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
960					theStats::AddUpOverheadOther(replypacket->GetPacketSize());
961					AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIR to ") + m_client->GetFullIP() );
962					SendPacket(replypacket, true, true);
963				}
964				wxASSERT( data.GetPosition() == data.GetLength() );
965				m_client->SetFileListRequested(uDirs);
966			} else {
967				AddLogLineC(CFormat( _("User %s (%u) sent unrequested shared dirs.") )
968					% m_client->GetUserName()
969					% m_client->GetUserIDHybrid() );
970			}
971			break;
972		}
973
974		case OP_ASKSHAREDFILESDIRANS: {		// 0.43b
975			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
976
977			theStats::AddDownOverheadOther(size);
978			CMemFile data(buffer, size);
979			wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
980
981			if (m_client->GetFileListRequested() > 0){
982				AddLogLineC(CFormat( _("User %s (%u) sent sharedfiles-list for directory '%s'") )
983					% m_client->GetUserName()
984					% m_client->GetUserIDHybrid()
985					% strDir );
986
987				m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
988				if (m_client->GetFileListRequested() == 0) {
989					AddLogLineC(CFormat( _("User %s (%u) finished sending sharedfiles-list") )
990						% m_client->GetUserName()
991						% m_client->GetUserIDHybrid() );
992				}
993			} else {
994				AddLogLineC(CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
995					% m_client->GetUserName()
996					% m_client->GetUserIDHybrid() );
997			}
998			break;
999		}
1000
1001		case OP_ASKSHAREDDENIEDANS:
1002			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
1003
1004			theStats::AddDownOverheadOther(size);
1005			wxASSERT( size == 0 );
1006			AddLogLineC(CFormat( _("User %s (%u) denied access to shared directories/files list") )
1007				% m_client->GetUserName()
1008				% m_client->GetUserIDHybrid() );
1009
1010			m_client->SetFileListRequested(0);
1011			break;
1012
1013		default:
1014			theStats::AddDownOverheadOther(size);
1015			AddDebugLogLineN(logRemoteClient, CFormat(wxT("Edonkey packet: unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1016			return false;
1017	}
1018
1019	return true;
1020}
1021
1022
1023bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1024{
1025	#ifdef __PACKET_RECV_DUMP__
1026	//printf("Rec: OPCODE %x \n",opcode);
1027	DumpMem(buffer,size);
1028	#endif
1029
1030	// 0.42e - except the catchs on mem exception and file exception
1031	if (!m_client) {
1032		throw wxString(wxT("Unknown clients sends extended protocol packet"));
1033	}
1034	/*
1035	if (!client->CheckHandshakeFinished()) {
1036		// Here comes an extended packet without finishing the handshake.
1037		// IMHO, we should disconnect the client.
1038		throw wxString(wxT("Client send extended packet before finishing handshake"));
1039	}
1040	*/
1041	switch(opcode) {
1042		case OP_MULTIPACKET_EXT:
1043			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1044		case OP_MULTIPACKET: {
1045			if (opcode == OP_MULTIPACKET) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1046
1047			theStats::AddDownOverheadFileRequest(size);
1048
1049			if (m_client->IsBanned()) {
1050				break;
1051			}
1052
1053			if (!m_client->CheckHandshakeFinished()) {
1054				// Here comes an extended packet without finishing the handshake.
1055				// IMHO, we should disconnect the client.
1056				throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1057			}
1058
1059			CMemFile data_in(buffer, size);
1060			CMD4Hash reqfilehash = data_in.ReadHash();
1061			uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1062
1063			bool file_not_found = false;
1064			CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1065			if ( reqfile == NULL ){
1066				reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1067				if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1068					AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a non-shared file"));
1069					file_not_found = true;
1070				}
1071			}
1072
1073			if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1074				AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1075				file_not_found = true;
1076			}
1077
1078			if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1079				AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1080				file_not_found = true;
1081			}
1082
1083			if (file_not_found) {
1084				CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1085				replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1086				theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1087				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1088				SendPacket(replypacket, true);
1089				break;
1090			}
1091
1092			if (!m_client->GetWaitStartTime()) {
1093				m_client->SetWaitStartTime();
1094			}
1095			// if we are downloading this file, this could be a new source
1096			// no passive adding of files with only one part
1097			if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1098				if (thePrefs::GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount()) {
1099					theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
1100				}
1101			}
1102			// check to see if this is a new file they are asking for
1103			if (m_client->GetUploadFileID() != reqfilehash) {
1104				m_client->SetCommentDirty();
1105			}
1106			m_client->SetUploadFileID(reqfile);
1107			CMemFile data_out(128);
1108			data_out.WriteHash(reqfile->GetFileHash());
1109			while(data_in.GetLength()-data_in.GetPosition()) {
1110				if (!m_client) {
1111					throw wxString(wxT("Client suddenly disconnected"));
1112				}
1113				uint8 opcode_in = data_in.ReadUInt8();
1114				switch(opcode_in) {
1115					case OP_REQUESTFILENAME: {
1116						AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1117						m_client->ProcessExtendedInfo(&data_in, reqfile);
1118						data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1119
1120						// Since it's for somebody else to see, we need to send the prettified
1121						// filename, rather than the (possibly) mangled actual filename
1122						data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1123						break;
1124					}
1125					case OP_AICHFILEHASHREQ: {
1126						AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1127						if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1128							&& reqfile->GetAICHHashset()->HasValidMasterHash())
1129						{
1130							data_out.WriteUInt8(OP_AICHFILEHASHANS);
1131							reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1132						}
1133						break;
1134					}
1135					case OP_SETREQFILEID: {
1136						AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1137						data_out.WriteUInt8(OP_FILESTATUS);
1138						if (reqfile->IsPartFile()) {
1139							((CPartFile*)reqfile)->WritePartStatus(&data_out);
1140						} else {
1141							data_out.WriteUInt16(0);
1142						}
1143						break;
1144					}
1145					//We still send the source packet separately..
1146					//We could send it within this packet.. If agreeded, I will fix it..
1147					case OP_REQUESTSOURCES2:
1148					case OP_REQUESTSOURCES: {
1149						AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1150						uint8 byRequestedVersion = 0;
1151						uint16 byRequestedOptions = 0;
1152						if (opcode_in == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1153							byRequestedVersion = data_in.ReadUInt8();
1154							byRequestedOptions = data_in.ReadUInt16();
1155						}
1156
1157						//Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1158
1159						if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1160							uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1161							bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1162							if(
1163									//if not complete and file is rare
1164									(    reqfile->IsPartFile()
1165									&& (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1166									&& ((CPartFile*)reqfile)->GetSourceCount() <= RARE_FILE
1167									) ||
1168									//OR if file is not rare or if file is complete
1169									( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1170									)
1171							{
1172								m_client->SetLastSrcReqTime();
1173								CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1174								if(tosend) {
1175									theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1176									AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1177									SendPacket(tosend, true);
1178								}
1179							}
1180						}
1181						break;
1182					}
1183				}
1184
1185			}
1186			if( data_out.GetLength() > 16 ) {
1187				CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1188				theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1189				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1190				SendPacket(reply, true);
1191			}
1192			break;
1193		}
1194
1195		case OP_MULTIPACKETANSWER: {	// 0.43b
1196			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1197
1198			theStats::AddDownOverheadFileRequest(size);
1199
1200			if (m_client->IsBanned()) {
1201				break;
1202			}
1203
1204			if (m_client->GetKadPort() && m_client->GetKadVersion() > 1) {
1205				Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort());
1206			}
1207
1208			if (!m_client->CheckHandshakeFinished()) {
1209				// Here comes an extended packet without finishing the handshake.
1210				// IMHO, we should disconnect the client.
1211				throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1212			}
1213
1214			CMemFile data_in(buffer, size);
1215			CMD4Hash reqfilehash = data_in.ReadHash();
1216			const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1217			//Make sure we are downloading this file.
1218			if ( !reqfile ) {
1219				throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1220			}
1221			if ( !m_client->GetRequestFile() ) {
1222
1223				throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1224			}
1225			if (reqfile != m_client->GetRequestFile()) {
1226				throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1227			}
1228			while (data_in.GetLength()-data_in.GetPosition()) {
1229				// Some of the cases down there can actually send a packet and lose the client
1230				if (!m_client) {
1231					throw wxString(wxT("Client suddenly disconnected"));
1232				}
1233				uint8 opcode_in = data_in.ReadUInt8();
1234				switch(opcode_in) {
1235					case OP_REQFILENAMEANSWER: {
1236						if (!m_client) {
1237							throw wxString(wxT("Client suddenly disconnected"));
1238						} else {
1239							m_client->ProcessFileInfo(&data_in, reqfile);
1240						}
1241						break;
1242					}
1243					case OP_FILESTATUS: {
1244						if (!m_client) {
1245							throw wxString(wxT("Client suddenly disconnected"));
1246						} else {
1247							m_client->ProcessFileStatus(false, &data_in, reqfile);
1248						}
1249						break;
1250					}
1251					case OP_AICHFILEHASHANS: {
1252						if (!m_client) {
1253							throw wxString(wxT("Client suddenly disconnected"));
1254						} else {
1255							m_client->ProcessAICHFileHash(&data_in, reqfile);
1256						}
1257						break;
1258					}
1259				}
1260			}
1261
1262			break;
1263		}
1264
1265		case OP_EMULEINFO: {	// 0.43b
1266			theStats::AddDownOverheadOther(size);
1267
1268			if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1269				AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1270
1271				// If it's not a OS Info packet, is an old client
1272				// start secure identification, if
1273				//  - we have received eD2K and eMule info (old eMule)
1274				if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1275					m_client->InfoPacketsReceived();
1276				}
1277				m_client->SendMuleInfoPacket(true);
1278			} else {
1279				AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1280			}
1281			break;
1282		}
1283		case OP_EMULEINFOANSWER: {	// 0.43b
1284			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1285			theStats::AddDownOverheadOther(size);
1286
1287			m_client->ProcessMuleInfoPacket(buffer, size);
1288			// start secure identification, if
1289			//  - we have received eD2K and eMule info (old eMule)
1290
1291			if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1292				m_client->InfoPacketsReceived();
1293			}
1294
1295			break;
1296		}
1297
1298		case OP_SECIDENTSTATE:{		// 0.43b
1299			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1300
1301			if (!m_client->CheckHandshakeFinished()) {
1302				// Here comes an extended packet without finishing the handshake.
1303				// IMHO, we should disconnect the client.
1304				throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1305			}
1306			m_client->ProcessSecIdentStatePacket(buffer, size);
1307			// ProcessSecIdentStatePacket() might cause the socket to die, so check
1308			if (m_client) {
1309				int SecureIdentState = m_client->GetSecureIdentState();
1310				if (SecureIdentState == IS_SIGNATURENEEDED) {
1311					m_client->SendSignaturePacket();
1312				} else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1313					m_client->SendPublicKeyPacket();
1314					// SendPublicKeyPacket() might cause the socket to die, so check
1315					if ( m_client ) {
1316						m_client->SendSignaturePacket();
1317					}
1318				}
1319			}
1320			break;
1321		}
1322
1323		case OP_PUBLICKEY: {		// 0.43b
1324			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1325
1326			if (m_client->IsBanned() ){
1327				break;
1328			}
1329
1330			if (!m_client->CheckHandshakeFinished()) {
1331				// Here comes an extended packet without finishing the handshake.
1332				// IMHO, we should disconnect the client.
1333				throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1334			}
1335
1336			m_client->ProcessPublicKeyPacket(buffer, size);
1337			break;
1338		}
1339		case OP_SIGNATURE:{			// 0.43b
1340			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1341
1342			if (!m_client->CheckHandshakeFinished()) {
1343				// Here comes an extended packet without finishing the handshake.
1344				// IMHO, we should disconnect the client.
1345				throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1346			}
1347
1348			m_client->ProcessSignaturePacket(buffer, size);
1349			break;
1350		}
1351		case OP_SENDINGPART_I64:
1352			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1353		case OP_COMPRESSEDPART_I64:
1354			if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1355		case OP_COMPRESSEDPART: {	// 0.47a
1356			if (opcode == OP_COMPRESSEDPART) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1357
1358			if (!m_client->CheckHandshakeFinished()) {
1359				// Here comes an extended packet without finishing the handshake.
1360				// IMHO, we should disconnect the client.
1361				throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1362			}
1363
1364			if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1365
1366				m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1367
1368				if (m_client && (
1369					m_client->GetRequestFile()->IsStopped() ||
1370					m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1371					m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1372					if (!m_client->GetSentCancelTransfer()) {
1373						CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1374						theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1375						AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1376						m_client->SendPacket(packet,true,true);
1377
1378						if (m_client) {
1379							m_client->SetSentCancelTransfer(1);
1380						}
1381					}
1382
1383					if ( m_client ) {
1384						m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1385					}
1386				}
1387			} else {
1388				if (!m_client->GetSentCancelTransfer()) {
1389					CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1390					theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1391					AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1392					m_client->SendPacket(packet,true,true);
1393
1394					if ( m_client ) {
1395						m_client->SetSentCancelTransfer(1);
1396					}
1397				}
1398
1399				if ( m_client ) {
1400					m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1401				}
1402			}
1403			break;
1404		}
1405		case OP_REQUESTPARTS_I64: {
1406			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP()  );
1407
1408			theStats::AddDownOverheadFileRequest(size);
1409
1410			m_client->ProcessRequestPartsPacket(buffer, size, true);
1411
1412			break;
1413		}
1414		case OP_QUEUERANKING: {		// 0.43b
1415			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP()  );
1416
1417			theStats::AddDownOverheadOther(size);
1418
1419			if (!m_client->CheckHandshakeFinished()) {
1420				// Here comes an extended packet without finishing the handshake.
1421				// IMHO, we should disconnect the client.
1422				throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1423			}
1424
1425			if (size != 12) {
1426				throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1427			}
1428
1429			uint16 newrank = PeekUInt16(buffer);
1430			m_client->SetRemoteQueueFull(false);
1431			m_client->SetRemoteQueueRank(newrank);
1432			break;
1433		}
1434		case OP_REQUESTSOURCES2:
1435		case OP_REQUESTSOURCES:{
1436			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP()  );
1437
1438			theStats::AddDownOverheadSourceExchange(size);
1439
1440			if (!m_client->CheckHandshakeFinished()) {
1441				// Here comes an extended packet without finishing the handshake.
1442				// IMHO, we should disconnect the client.
1443				throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1444			}
1445
1446			uint8 byRequestedVersion = 0;
1447			uint16 byRequestedOptions = 0;
1448			CMemFile data_in(buffer, size);
1449			if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1450				byRequestedVersion = data_in.ReadUInt8();
1451				byRequestedOptions = data_in.ReadUInt16();
1452			}
1453
1454			if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1455				if(size != 16) {
1456					throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1457				}
1458				//first check shared file list, then download list
1459				const CMD4Hash fileID(buffer);
1460				CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1461				if(!file) {
1462					file = theApp->downloadqueue->GetFileByID(fileID);
1463				}
1464				if(file) {
1465					// There are some clients which do not follow the correct protocol procedure of sending
1466					// the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1467					// are doing this, they will not get the optimal set of sources which we could offer if
1468					// they would follow the above noted protocol sequence. They better do it the right way
1469					// or they will get just a random set of sources because we do not know their download
1470					// part status which may get cleared with the call of 'SetUploadFileID'.
1471					m_client->SetUploadFileID(file);
1472
1473					uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1474					bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1475					if(
1476					//if not complete and file is rare, allow once every 40 minutes
1477					( file->IsPartFile() &&
1478					((CPartFile*)file)->GetSourceCount() <= RARE_FILE &&
1479					(bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1480					) ||
1481					//OR if file is not rare or if file is complete, allow every 90 minutes
1482					( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1483					)
1484					{
1485						m_client->SetLastSrcReqTime();
1486						CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1487						if(tosend) {
1488							theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1489							AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1490							SendPacket(tosend, true, true);
1491						}
1492					}
1493				}
1494			}
1495			break;
1496		}
1497		case OP_ANSWERSOURCES: {
1498			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP()  );
1499
1500			theStats::AddDownOverheadSourceExchange(size);
1501
1502			if (!m_client->CheckHandshakeFinished()) {
1503				// Here comes an extended packet without finishing the handshake.
1504				// IMHO, we should disconnect the client.
1505				throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1506			}
1507
1508			CMemFile data(buffer, size);
1509			CMD4Hash hash = data.ReadHash();
1510			const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1511			if(file){
1512				if (file->IsPartFile()){
1513					//set the client's answer time
1514					m_client->SetLastSrcAnswerTime();
1515					//and set the file's last answer time
1516					((CPartFile*)file)->SetLastAnsweredTime();
1517
1518					((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1519				}
1520			}
1521			break;
1522		}
1523		case OP_ANSWERSOURCES2: {
1524			//printf("Received OP_ANSWERSOURCES2\n");
1525			theStats::AddDownOverheadSourceExchange(size);
1526
1527			if (!m_client->CheckHandshakeFinished()) {
1528				// Here comes an extended packet without finishing the handshake.
1529				// IMHO, we should disconnect the client.
1530				throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1531			}
1532
1533			CMemFile data(buffer, size);
1534			uint8 byVersion = data.ReadUInt8();
1535			CMD4Hash hash = data.ReadHash();
1536			const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1537			if (file){
1538				if (file->IsPartFile()){
1539					//set the client's answer time
1540					m_client->SetLastSrcAnswerTime();
1541					//and set the file's last answer time
1542					((CPartFile*)file)->SetLastAnsweredTime();
1543					((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1544				}
1545			}
1546			break;
1547		}
1548		case OP_FILEDESC: {		// 0.43b
1549			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP()  );
1550
1551			theStats::AddDownOverheadFileRequest(size);
1552
1553			if (!m_client->CheckHandshakeFinished()) {
1554				// Here comes an extended packet without finishing the handshake.
1555				// IMHO, we should disconnect the client.
1556				throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1557			}
1558
1559			m_client->ProcessMuleCommentPacket(buffer, size);
1560			break;
1561		}
1562
1563		// Unsupported
1564		case OP_REQUESTPREVIEW: {
1565			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW  from ") + m_client->GetFullIP()  );
1566			break;
1567		}
1568		// Unsupported
1569		case OP_PREVIEWANSWER: {
1570			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP()  );
1571			break;
1572		}
1573
1574		case OP_PUBLICIP_ANSWER: {
1575			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP()  );
1576			theStats::AddDownOverheadOther(size);
1577			m_client->ProcessPublicIPAnswer(buffer, size);
1578			break;
1579		}
1580		case OP_PUBLICIP_REQ: {
1581			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP()  );
1582			theStats::AddDownOverheadOther(size);
1583			CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1584			pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1585			theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1586			AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1587			SendPacket(pPacket);
1588			break;
1589		}
1590		case OP_AICHANSWER: {
1591			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP()  );
1592			theStats::AddDownOverheadOther(size);
1593			m_client->ProcessAICHAnswer(buffer, size);
1594			break;
1595		}
1596		case OP_AICHREQUEST: {
1597			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP()  );
1598			theStats::AddDownOverheadOther(size);
1599			m_client->ProcessAICHRequest(buffer, size);
1600			break;
1601		}
1602		case OP_AICHFILEHASHANS: {
1603			// those should not be received normally, since we should only get those in MULTIPACKET
1604			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP()  );
1605			theStats::AddDownOverheadOther(size);
1606			CMemFile data(buffer, size);
1607			m_client->ProcessAICHFileHash(&data, NULL);
1608			break;
1609		}
1610		case OP_AICHFILEHASHREQ: {
1611			// those should not be received normally, since we should only get those in MULTIPACKET
1612			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP()  );
1613			CMemFile data(buffer, size);
1614			CMD4Hash hash = data.ReadHash();
1615			CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1616			if (pPartFile == NULL){
1617				break;
1618			}
1619
1620			if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1621				&& pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1622				CMemFile data_out;
1623				data_out.WriteHash(hash);
1624				pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1625				CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1626				theStats::AddUpOverheadOther(packet->GetPacketSize());
1627					AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1628				SendPacket(packet);
1629			}
1630			break;
1631		}
1632		case OP_CALLBACK: {
1633			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1634			theStats::AddDownOverheadFileRequest(size);
1635			if(!Kademlia::CKademlia::IsRunning()) {
1636				break;
1637			}
1638			CMemFile data(buffer, size);
1639			CUInt128 check = data.ReadUInt128();
1640			check.XOR(Kademlia::CUInt128(true));
1641			if( check.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1642				break;
1643			}
1644			CUInt128 fileid = data.ReadUInt128();
1645			byte fileid2[16];
1646			fileid.ToByteArray(fileid2);
1647			const CMD4Hash fileHash(fileid2);
1648			if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1649				if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1650					break;
1651				}
1652			}
1653
1654			uint32 ip = data.ReadUInt32();
1655			uint16 tcp = data.ReadUInt16();
1656			CUpDownClient* callback;
1657			callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1658			if( callback == NULL ) {
1659				//#warning Do we actually have to check friend status here?
1660				callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1661				theApp->clientlist->AddClient(callback);
1662			}
1663			callback->TryToConnect(true);
1664			break;
1665		}
1666
1667		case OP_BUDDYPING: {
1668			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP()  );
1669			theStats::AddDownOverheadKad(size);
1670
1671			CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1672			if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1673				//This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1674				break;
1675			}
1676
1677			m_client->SetLastBuddyPingPongTime();
1678			CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1679			theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1680			AddDebugLogLineN(logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1681			SendPacket(replypacket);
1682			break;
1683		}
1684		case OP_BUDDYPONG: {
1685			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP()  );
1686			theStats::AddDownOverheadKad(size);
1687
1688			CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1689			if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1690				//This pong was not from our buddy or wrong version. Ignore
1691				break;
1692			}
1693			m_client->SetLastBuddyPingPongTime();
1694			//All this is for is to reset our socket timeout.
1695			break;
1696		}
1697		case OP_REASKCALLBACKTCP: {
1698			theStats::AddDownOverheadFileRequest(size);
1699			CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1700			if (buddy != m_client) {
1701				AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1702				//This callback was not from our buddy.. Ignore.
1703				break;
1704			}
1705			AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1706			CMemFile data_in(buffer, size);
1707			uint32 destip = data_in.ReadUInt32();
1708			uint16 destport = data_in.ReadUInt16();
1709			CMD4Hash hash = data_in.ReadHash();
1710			CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1711
1712			bool bSenderMultipleIpUnknown = false;
1713			CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1714			if (!reqfile) {
1715				AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1716				CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1717				theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1718				if (sender) {
1719					theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1720				} else {
1721					theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1722				}
1723				break;
1724			}
1725
1726			if (sender) {
1727				//Make sure we are still thinking about the same file
1728				if (hash == sender->GetUploadFileID()) {
1729					sender->AddAskedCount();
1730					sender->SetLastUpRequest();
1731					//I messed up when I first added extended info to UDP
1732					//I should have originally used the entire ProcessExtenedInfo the first time.
1733					//So now I am forced to check UDPVersion to see if we are sending all the extended info.
1734					//For now on, we should not have to change anything here if we change
1735					//anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1736					//Update extended info.
1737					if (sender->GetUDPVersion() > 3) {
1738						sender->ProcessExtendedInfo(&data_in, reqfile);
1739					} else if (sender->GetUDPVersion() > 2) {
1740						//Update our complete source counts.
1741						uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1742						uint16 nCompleteCountNew = data_in.ReadUInt16();
1743						sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1744						if (nCompleteCountLast != nCompleteCountNew) {
1745							reqfile->UpdatePartsInfo();
1746						}
1747					}
1748
1749					CMemFile data_out(128);
1750					if(sender->GetUDPVersion() > 3) {
1751						if (reqfile->IsPartFile()) {
1752							((CPartFile*)reqfile)->WritePartStatus(&data_out);
1753						} else {
1754							data_out.WriteUInt16(0);
1755						}
1756					}
1757
1758					data_out.WriteUInt16(sender->GetUploadQueueWaitingPosition());
1759					CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1760					theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1761					AddDebugLogLineN( logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP()  );
1762					theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1763				} else {
1764					AddDebugLogLineN(logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1765				}
1766			} else {
1767				if (!bSenderMultipleIpUnknown){
1768					if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1769						AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP()  );
1770						CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1771						theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1772						theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1773					}
1774				} else {
1775					AddDebugLogLineN(logRemoteClient, CFormat(wxT("OP_REASKCALLBACKTCP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u")) % Uint32toStringIP(destip) % destport);
1776				}
1777			}
1778			break;
1779		}
1780		case OP_CHATCAPTCHAREQ:
1781		{
1782			AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client->GetFullIP());
1783			theStats::AddDownOverheadOther(size);
1784			CMemFile data_in(buffer, size);
1785			m_client->ProcessCaptchaRequest(&data_in);
1786			break;
1787		}
1788		case OP_CHATCAPTCHARES:
1789		{
1790			AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client->GetFullIP());
1791			theStats::AddDownOverheadOther(size);
1792			if (size) {
1793				m_client->ProcessCaptchaReqRes(buffer[0]);
1794			}
1795			break;
1796		}
1797		case OP_FWCHECKUDPREQ: { // Support required for Kadversion >= 6
1798			AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client->GetFullIP());
1799			theStats::AddDownOverheadOther(size);
1800			CMemFile data_in(buffer, size);
1801			m_client->ProcessFirewallCheckUDPRequest(&data_in);
1802			break;
1803		}
1804		case OP_KAD_FWTCPCHECK_ACK: { // Support required for Kadversion >= 7
1805			AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client->GetFullIP());
1806			if (theApp->clientlist->IsKadFirewallCheckIP(m_client->GetIP())) {
1807				if (Kademlia::CKademlia::IsRunning()) {
1808					Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1809				}
1810			} else {
1811				AddDebugLogLineN(logListenSocket, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client->GetFullIP());
1812			}
1813			break;
1814		}
1815		default:
1816			theStats::AddDownOverheadOther(size);
1817			AddDebugLogLineN(logRemoteClient, CFormat(wxT("eMule packet : unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1818			break;
1819	}
1820
1821	return true;
1822}
1823
1824bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1825{
1826	#ifdef __PACKET_RECV_DUMP__
1827	//printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1828	DumpMem(buffer,size);
1829	#endif
1830
1831	if (!m_client) {
1832		throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1833	}
1834
1835	CMemFile data(buffer, size);
1836	try {
1837		switch(opcode) {
1838			case OP_QUEUERANK: {
1839				AddDebugLogLineN( logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1840
1841				uint8 numtags = data.ReadUInt8();
1842				wxASSERT(numtags == 1);
1843				if(numtags){}	// prevent GCC warning
1844
1845				m_client->SetRemoteQueueRank(data.GetIntTagValue());
1846
1847				theStats::AddDownOverheadFileRequest(size);
1848				break;
1849			}
1850
1851			case OP_REQUESTPARTS: {
1852				AddDebugLogLineN( logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1853
1854				m_client->ProcessRequestPartsPacketv2(data);
1855
1856				theStats::AddDownOverheadFileRequest(size);
1857				break;
1858			}
1859
1860			default:
1861				theStats::AddDownOverheadOther(size);
1862				AddDebugLogLineN(logRemoteClient, CFormat(wxT("ED2Kv2 packet : unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1863		}
1864	} catch (...) {
1865		AddDebugLogLineN(logRemoteClient, CFormat(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from %s")) % data.GetPosition() % opcode % opcode % m_client->GetFullIP());
1866		throw;
1867	}
1868
1869	return true;
1870}
1871
1872void CClientTCPSocket::OnConnect(int nErrorCode)
1873{
1874	if (nErrorCode) {
1875		OnError(nErrorCode);
1876	} else if (!m_client) {
1877		// and now? Disconnect? not?
1878		AddDebugLogLineN( logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1879	} else if (!m_client->SendHelloPacket()) {
1880		// and now? Disconnect? not?
1881		AddDebugLogLineN( logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1882	} else {
1883		ResetTimeOutTimer();
1884	}
1885}
1886
1887
1888void CClientTCPSocket::OnSend(int nErrorCode)
1889{
1890	ResetTimeOutTimer();
1891	CEMSocket::OnSend(nErrorCode);
1892}
1893
1894
1895void CClientTCPSocket::OnReceive(int nErrorCode)
1896{
1897	ResetTimeOutTimer();
1898	// We might have updated ipfilter
1899	wxASSERT(m_remoteip);
1900
1901	if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1902		if (m_client) {
1903			m_client->Safe_Delete();
1904		}
1905		Safe_Delete();
1906		AddDebugLogLineN( logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1907	} else {
1908		CEMSocket::OnReceive(nErrorCode);
1909	}
1910}
1911
1912
1913void CClientTCPSocket::OnError(int nErrorCode)
1914{
1915	//printf("* Called OnError for %p\n",this);
1916	// 0.42e + Kry changes for handling of socket lost events
1917	wxString strError;
1918
1919	if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1920		if (m_client) {
1921			if (!m_client->GetUserName().IsEmpty()) {
1922				strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1923			} else {
1924				strError = wxT("An unnamed client");
1925			}
1926			strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1927		} else {
1928			strError = wxT("A client ");
1929		}
1930		if (nErrorCode == 0) {
1931			strError += wxT("closed connection.");
1932		} else if (nErrorCode == 0xFEFF) {
1933			strError += wxT(" caused a wxSOCKET_LOST event.");
1934		}	else {
1935			strError += wxT("caused a socket blocking error.");
1936		}
1937	} else {
1938		if (theLogger.IsEnabled(logClient) && nErrorCode != 107) {
1939			// 0    -> No Error / Disconect
1940			// 107  -> Transport endpoint is not connected
1941			if (m_client) {
1942				if (!m_client->GetUserName().IsEmpty()) {
1943					strError = CFormat(wxT("OnError: Client '%s' (IP:%s) caused an error: %u. Disconnecting client!"))
1944						% m_client->GetUserName() % m_client->GetFullIP() % nErrorCode;
1945				} else {
1946					strError = CFormat(wxT("OnError: Unknown client (IP:%s) caused an error: %u. Disconnecting client!"))
1947						% m_client->GetFullIP() % nErrorCode;
1948				}
1949			} else {
1950				strError = CFormat(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"))
1951					% nErrorCode;
1952			}
1953		} else {
1954			strError = wxT("Error 107 (Transport endpoint is not connected)");
1955		}
1956	}
1957
1958	Disconnect(strError);
1959}
1960
1961
1962bool CClientTCPSocket::PacketReceived(CPacket* packet)
1963{
1964	// 0.42e
1965	bool bResult = false;
1966	uint32 uRawSize = packet->GetPacketSize();
1967
1968	AddDebugLogLineN( logRemoteClient,
1969		CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1970			% packet->GetProtocol()
1971			% packet->GetOpCode()
1972			% packet->GetPacketSize()
1973			% ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
1974	);
1975
1976	wxString exception;
1977
1978	try {
1979		bool process = true;
1980
1981		if ((packet->GetProtocol() == OP_PACKEDPROT) ||
1982			(packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
1983
1984			if (!packet->UnPackPacket()) {
1985				AddDebugLogLineN(logZLib, wxT("Failed to decompress client TCP packet."));
1986				bResult = false;
1987				process = false;
1988			} else {
1989				AddDebugLogLineN(logRemoteClient, CFormat(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"))
1990					% packet->GetProtocol() % packet->GetOpCode() % packet->GetPacketSize());
1991			}
1992		}
1993
1994		if (process) {
1995			switch (packet->GetProtocol()) {
1996				case OP_EDONKEYPROT:
1997					bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
1998					break;
1999				case OP_EMULEPROT:
2000					bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2001					break;
2002				case OP_ED2KV2HEADER:
2003					bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2004					break;
2005				case OP_ED2KV2PACKEDPROT:
2006				case OP_PACKEDPROT:
2007					// Packed inside packed?
2008					wxFAIL;
2009					break;
2010				default: {
2011					theStats::AddDownOverheadOther(uRawSize);
2012					if (m_client) {
2013						m_client->SetDownloadState(DS_ERROR);
2014					}
2015					Disconnect(wxT("Unknown protocol"));
2016					bResult = false;
2017				}
2018			}
2019		}
2020	} catch (const CEOFException& err) {
2021		exception = wxT("EOF exception: ") + err.what();
2022	} catch (const CInvalidPacket& err) {
2023		exception = wxT("InvalidPacket exception: ") + err.what();
2024	} catch (const wxString& error) {
2025		exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2026	}
2027
2028	if (!exception.IsEmpty()) {
2029		AddDebugLogLineN( logPacketErrors,
2030			CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2031				% exception
2032				% packet->GetProtocol()
2033				% packet->GetOpCode()
2034				% packet->GetPacketSize()
2035				% ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2036		);
2037
2038		if (m_client) {
2039			m_client->SetDownloadState(DS_ERROR);
2040		}
2041
2042		AddDebugLogLineN( logClient,
2043			CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2044				% ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2045				% ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2046				% exception
2047		);
2048
2049		Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2050	}
2051
2052	return bResult;
2053}
2054
2055
2056SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2057{
2058    SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2059
2060    if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2061        ResetTimeOutTimer();
2062    }
2063
2064    return returnStatus;
2065}
2066
2067
2068SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2069{
2070	SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2071
2072    if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2073        ResetTimeOutTimer();
2074    }
2075
2076    return returnStatus;
2077}
2078
2079
2080void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2081{
2082	ResetTimeOutTimer();
2083	CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2084}
2085// File_checked_for_headers
2086