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