Upstream tarball 9407
[amule.git] / src / ClientTCPSocket.cpp
blobbf1dc58e9b84c28d3be3ebd6c374794fbb4a5a27
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 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.
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
25 #include "ClientTCPSocket.h" // Interface declarations
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>
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_*
57 //#define __PACKET_RECV_DUMP__
59 //------------------------------------------------------------------------------
60 // CClientTCPSocketHandler
61 //------------------------------------------------------------------------------
63 class CClientTCPSocketHandler: public wxEvtHandler
65 public:
66 CClientTCPSocketHandler() {};
68 private:
69 void ClientTCPSocketHandler(wxSocketEvent& event);
70 DECLARE_EVENT_TABLE()
73 BEGIN_EVENT_TABLE(CClientTCPSocketHandler, wxEvtHandler)
74 EVT_SOCKET(ID_CLIENTTCPSOCKET_EVENT, CClientTCPSocketHandler::ClientTCPSocketHandler)
75 END_EVENT_TABLE()
77 void CClientTCPSocketHandler::ClientTCPSocketHandler(wxSocketEvent& event)
79 CClientTCPSocket *socket = dynamic_cast<CClientTCPSocket *>(event.GetSocket());
80 wxASSERT(socket);
81 if (!socket) {
82 return;
85 if (socket->OnDestroy() || socket->ForDeletion()) {
86 return;
89 switch(event.GetSocketEvent()) {
90 case wxSOCKET_LOST:
91 socket->OnError(0xFEFF /* SOCKET_LOST is not an error */);
92 break;
93 case wxSOCKET_INPUT:
94 socket->OnReceive(0);
95 break;
96 case wxSOCKET_OUTPUT:
97 socket->OnSend(0);
98 break;
99 case wxSOCKET_CONNECTION:
100 // connection stablished, nothing to do about it?
101 socket->OnConnect(socket->Error() ? socket->LastError() : 0);
102 break;
103 default:
104 // Nothing should arrive here...
105 wxASSERT(0);
106 break;
111 // There can be only one. :)
113 static CClientTCPSocketHandler g_clientReqSocketHandler;
116 //------------------------------------------------------------------------------
117 // CClientTCPSocket
118 //------------------------------------------------------------------------------
120 CClientTCPSocket::CClientTCPSocket(CUpDownClient* in_client, const CProxyData *ProxyData)
121 : CEMSocket(ProxyData)
123 SetClient(in_client);
124 if (in_client) {
125 m_remoteip = wxUINT32_SWAP_ALWAYS(in_client->GetUserIDHybrid());
126 } else {
127 m_remoteip = 0;
130 ResetTimeOutTimer();
131 m_ForDeletion = false;
133 SetEventHandler(g_clientReqSocketHandler, ID_CLIENTTCPSOCKET_EVENT);
134 SetNotify(
135 wxSOCKET_CONNECTION_FLAG |
136 wxSOCKET_INPUT_FLAG |
137 wxSOCKET_OUTPUT_FLAG |
138 wxSOCKET_LOST_FLAG);
139 Notify(true);
141 theApp->listensocket->AddSocket(this);
142 theApp->listensocket->AddConnection();
145 CClientTCPSocket::~CClientTCPSocket()
147 // remove event handler
148 SetNotify(0);
149 Notify(false);
151 if (m_client) {
152 m_client->SetSocket( NULL );
154 m_client = NULL;
156 if (theApp->listensocket && !theApp->listensocket->OnShutdown()) {
157 theApp->listensocket->RemoveSocket(this);
161 bool CClientTCPSocket::InitNetworkData()
163 wxASSERT(!m_remoteip);
164 wxASSERT(!m_client);
165 amuleIPV4Address addr;
166 GetPeer(addr);
167 m_remoteip = StringIPtoUint32(addr.IPAddress());
169 MULE_CHECK(m_remoteip, false);
171 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
172 AddDebugLogLineM(false, logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Filtered IP)"));
173 return false;
174 } else if (theApp->clientlist->IsBannedClient(m_remoteip)) {
175 AddDebugLogLineM(false, logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Banned IP)"));
176 return false;
177 } else {
178 AddDebugLogLineM(false, logClient, wxT("Accepted connection from ") + addr.IPAddress());
179 return true;
183 void CClientTCPSocket::ResetTimeOutTimer()
185 timeout_timer = ::GetTickCount();
189 bool CClientTCPSocket::CheckTimeOut()
191 // 0.42x
192 uint32 uTimeout = GetTimeOut();
193 if (m_client) {
195 if (m_client->GetKadState() == KS_CONNECTED_BUDDY) {
196 //We originally ignored the timeout here for buddies.
197 //This was a stupid idea on my part. There is now a ping/pong system
198 //for buddies. This ping/pong system now prevents timeouts.
199 //This release will allow lowID clients with KadVersion 0 to remain connected.
200 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
201 //JOHNTODO: Don't forget to remove backward support in a future release.
202 if ( m_client->GetKadVersion() == 0 ) {
203 return false;
206 uTimeout += MIN2MS(15);
209 if (m_client->GetChatState() != MS_NONE) {
210 uTimeout += CONNECTION_TIMEOUT;
214 if (::GetTickCount() - timeout_timer > uTimeout){
215 timeout_timer = ::GetTickCount();
216 Disconnect(wxT("Timeout"));
217 return true;
220 return false;
224 void CClientTCPSocket::SetClient(CUpDownClient* pClient)
226 m_client = pClient;
227 if (m_client) {
228 m_client->SetSocket( this );
233 void CClientTCPSocket::OnClose(int nErrorCode)
235 // 0.42x
236 wxASSERT(theApp->listensocket->IsValidSocket(this));
237 CEMSocket::OnClose(nErrorCode);
238 if (nErrorCode) {
239 Disconnect(wxString::Format(wxT("Closed: %u"), nErrorCode));
240 } else {
241 Disconnect(wxT("Close"));
246 void CClientTCPSocket::Disconnect(const wxString& strReason)
248 byConnected = ES_DISCONNECTED;
249 if (m_client) {
250 if (m_client->Disconnected(strReason, true)) {
251 // Somehow, Safe_Delete() is beeing called by Disconnected(),
252 // or any other function that sets m_client to NULL,
253 // so we must check m_client first.
254 if (m_client) {
255 m_client->SetSocket( NULL );
256 m_client->Safe_Delete();
259 m_client = NULL;
262 Safe_Delete();
266 void CClientTCPSocket::Safe_Delete()
268 if ( !ForDeletion() && !OnDestroy() ) {
269 // Paranoia is back.
270 SetNotify(0);
271 Notify(false);
272 // lfroen: first of all - stop handler
273 m_ForDeletion = true;
275 if (m_client) {
276 m_client->SetSocket( NULL );
277 m_client = NULL;
280 byConnected = ES_DISCONNECTED;
281 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
282 Destroy();
287 bool CClientTCPSocket::ProcessPacket(const byte* buffer, uint32 size, uint8 opcode)
289 #ifdef __PACKET_RECV_DUMP__
290 //printf("Rec: OPCODE %x \n",opcode);
291 DumpMem(buffer, size);
292 #endif
293 if (!m_client && opcode != OP_HELLO) {
294 throw wxString(wxT("Asks for something without saying hello"));
295 } else if (m_client && opcode != OP_HELLO && opcode != OP_HELLOANSWER) {
296 m_client->CheckHandshakeFinished(OP_EDONKEYPROT, opcode);
299 switch(opcode) {
300 case OP_HELLOANSWER: { // 0.43b
301 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HELLOANSWER from ") + m_client->GetFullIP());
302 theStats::AddDownOverheadOther(size);
303 m_client->ProcessHelloAnswer(buffer, size);
305 // start secure identification, if
306 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
307 // - we have received eMule-OP_HELLOANSWER (new eMule)
308 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
309 m_client->InfoPacketsReceived();
312 // Socket might die because of sending in InfoPacketsReceived, so check
313 if (m_client) {
314 m_client->ConnectionEstablished();
317 // Socket might die on ConnectionEstablished somehow. Check it.
318 if (m_client) {
319 Notify_UploadCtrlRefreshClient( m_client );
322 break;
324 case OP_HELLO: { // 0.43b
326 theStats::AddDownOverheadOther(size);
327 bool bNewClient = !m_client;
328 if (bNewClient) {
329 // create new client to save standart informations
330 m_client = new CUpDownClient(this);
333 // Do not move up!
334 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HELLO from ") + m_client->GetFullIP() );
336 bool bIsMuleHello = false;
338 try{
339 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
340 } catch(...) {
341 if (bNewClient && m_client) {
342 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
343 m_client->Safe_Delete();
344 m_client = NULL;
346 throw;
349 if (thePrefs::ParanoidFilter() && !IsLowID(m_client->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid()))) {
350 wxString reason = wxT("Client claims a different IP from the one we received the hello packet from: ");
351 reason += Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
352 AddDebugLogLineM(false, logClient, reason);
353 if (bNewClient) {
354 m_client->Safe_Delete();
355 m_client = NULL;
357 Disconnect(wxT("Paranoid disconecting: ") + reason);
358 return false;
361 // if IP is filtered, dont reply but disconnect...
362 if (theApp->ipfilter->IsFiltered(m_client->GetIP())) {
363 if (bNewClient) {
364 m_client->Safe_Delete();
365 m_client = NULL;
367 Disconnect(wxT("IPFilter"));
368 return false;
371 wxASSERT(m_client);
373 // now we check if we now this client already. if yes this socket will
374 // be attached to the known client, the new client will be deleted
375 // and the var. "client" will point to the known client.
376 // if not we keep our new-constructed client ;)
377 if (theApp->clientlist->AttachToAlreadyKnown(&m_client,this)) {
378 // update the old client informations
379 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
380 } else {
381 theApp->clientlist->AddClient(m_client);
382 m_client->SetCommentDirty();
384 Notify_UploadCtrlRefreshClient( m_client );
385 // send a response packet with standart informations
386 if ((m_client->GetHashType() == SO_EMULE) && !bIsMuleHello) {
387 m_client->SendMuleInfoPacket(false);
390 // Client might die from Sending in SendMuleInfoPacket, so check
391 if ( m_client ) {
392 m_client->SendHelloAnswer();
395 // Kry - If the other side supports it, send OS_INFO
396 // Client might die from Sending in SendHelloAnswer, so check
397 if (m_client && m_client->GetOSInfoSupport()) {
398 m_client->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
401 // Client might die from Sending in SendMuleInfoPacket, so check
402 if ( m_client ) {
403 m_client->ConnectionEstablished();
406 // start secure identification, if
407 // - we have received eMule-OP_HELLO (new eMule)
408 if (m_client && m_client->GetInfoPacketsReceived() == IP_BOTH) {
409 m_client->InfoPacketsReceived();
412 break;
414 case OP_REQUESTFILENAME: { // 0.43b
415 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client->GetFullIP() );
417 theStats::AddDownOverheadFileRequest(size);
418 // IP banned, no answer for this request
419 if (m_client->IsBanned()) {
420 break;
422 if (size >= 16) {
423 if (!m_client->GetWaitStartTime()) {
424 m_client->SetWaitStartTime();
426 CMemFile data_in(buffer, size);
427 CMD4Hash reqfilehash = data_in.ReadHash();
428 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
429 if ( reqfile == NULL ) {
430 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
431 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
432 break;
435 // if we are downloading this file, this could be a new source
436 // no passive adding of files with only one part
437 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
438 if (thePrefs::GetMaxSourcePerFile() >
439 ((CPartFile*)reqfile)->GetSourceCount()) {
440 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
444 // check to see if this is a new file they are asking for
445 if (m_client->GetUploadFileID() != reqfilehash) {
446 m_client->SetCommentDirty();
449 m_client->SetUploadFileID(reqfile);
450 m_client->ProcessExtendedInfo(&data_in, reqfile);
452 // send filename etc
453 CMemFile data_out(128);
454 data_out.WriteHash(reqfile->GetFileHash());
456 // Since it's for somebody else to see, we need to send the prettified
457 // filename, rather than the (possibly) mangled actual filename.
458 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
460 CPacket* packet = new CPacket(data_out, OP_EDONKEYPROT, OP_REQFILENAMEANSWER);
461 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
462 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client->GetFullIP() );
463 SendPacket(packet,true);
465 // SendPacket might kill the socket, so check
466 if (m_client)
467 m_client->SendCommentInfo(reqfile);
469 break;
471 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
472 break;
474 case OP_SETREQFILEID: { // 0.43b EXCEPT track of bad clients
475 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SETREQFILEID from ") + m_client->GetFullIP() );
477 theStats::AddDownOverheadFileRequest(size);
479 if (m_client->IsBanned()) {
480 break;
483 // DbT:FileRequest
484 if (size == 16) {
485 if (!m_client->GetWaitStartTime()) {
486 m_client->SetWaitStartTime();
489 const CMD4Hash fileID(buffer);
490 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(fileID);
491 if ( reqfile == NULL ) {
492 reqfile = theApp->downloadqueue->GetFileByID(fileID);
493 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
494 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
495 replypacket->Copy16ToDataBuffer(fileID.GetHash());
496 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
497 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILERE to ") + m_client->GetFullIP() );
498 SendPacket(replypacket, true);
499 break;
503 // check to see if this is a new file they are asking for
504 if (m_client->GetUploadFileID() != fileID) {
505 m_client->SetCommentDirty();
508 m_client->SetUploadFileID(reqfile);
509 // send filestatus
510 CMemFile data(16+16);
511 data.WriteHash(reqfile->GetFileHash());
512 if (reqfile->IsPartFile()) {
513 ((CPartFile*)reqfile)->WritePartStatus(&data);
514 } else {
515 data.WriteUInt16(0);
517 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_FILESTATUS);
518 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
519 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILESTATUS to ") + m_client->GetFullIP() );
520 SendPacket(packet, true);
521 break;
523 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
524 break;
525 // DbT:End
528 case OP_FILEREQANSNOFIL: { // 0.43b protocol, lacks ZZ's download manager on swap
529 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client->GetFullIP() );
531 theStats::AddDownOverheadFileRequest(size);
532 if (size == 16) {
533 // if that client does not have my file maybe has another different
534 CPartFile* reqfile = theApp->downloadqueue->GetFileByID(CMD4Hash(buffer));
535 if ( reqfile) {
536 reqfile->AddDeadSource( m_client );
537 } else {
538 break;
541 // we try to swap to another file ignoring no needed parts files
542 switch (m_client->GetDownloadState()) {
543 case DS_CONNECTED:
544 case DS_ONQUEUE:
545 case DS_NONEEDEDPARTS:
546 if (!m_client->SwapToAnotherFile(true, true, true, NULL)) {
547 theApp->downloadqueue->RemoveSource(m_client);
549 break;
551 break;
553 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
554 break;
557 case OP_REQFILENAMEANSWER: { // 0.43b except check for bad clients
558 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client->GetFullIP() );
560 theStats::AddDownOverheadFileRequest(size);
561 CMemFile data(buffer, size);
562 CMD4Hash hash = data.ReadHash();
563 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
564 m_client->ProcessFileInfo(&data, file);
565 break;
568 case OP_FILESTATUS: { // 0.43b except check for bad clients
569 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILESTATUS from ") + m_client->GetFullIP() );
571 theStats::AddDownOverheadFileRequest(size);
572 CMemFile data(buffer, size);
573 CMD4Hash hash = data.ReadHash();
574 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
575 m_client->ProcessFileStatus(false, &data, file);
576 break;
579 case OP_STARTUPLOADREQ: {
580 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client->GetFullIP() );
582 theStats::AddDownOverheadFileRequest(size);
584 if (!m_client->CheckHandshakeFinished(OP_EDONKEYPROT, opcode)) {
585 break;
588 m_client->CheckForAggressive();
589 if ( m_client->IsBanned() ) {
590 break;
593 if (size == 16) {
594 const CMD4Hash fileID(buffer);
595 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(fileID);
596 if (reqfile) {
597 if (m_client->GetUploadFileID() != fileID) {
598 m_client->SetCommentDirty();
600 m_client->SetUploadFileID(reqfile);
601 m_client->SendCommentInfo(reqfile);
603 // Socket might die because of SendCommentInfo, so check
604 if (m_client)
605 theApp->uploadqueue->AddClientToQueue(m_client);
608 break;
611 case OP_QUEUERANK: { // 0.43b
612 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANK from ") + m_client->GetFullIP() );
614 theStats::AddDownOverheadFileRequest(size);
615 CMemFile data(buffer, size);
616 uint32 rank = data.ReadUInt32();
618 m_client->SetRemoteQueueRank(rank);
619 break;
622 case OP_ACCEPTUPLOADREQ: { // 0.42e (xcept khaos stats)
623 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client->GetFullIP() );
625 theStats::AddDownOverheadFileRequest(size);
626 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
627 if (m_client->GetDownloadState() == DS_ONQUEUE ) {
628 m_client->SetDownloadState(DS_DOWNLOADING);
629 m_client->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
630 m_client->SendBlockRequests();
632 } else {
633 if (!m_client->GetSentCancelTransfer()) {
634 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
635 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
636 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
637 m_client->SendPacket(packet,true,true);
639 // SendPacket can cause the socket to die, so check
640 if (m_client)
641 m_client->SetSentCancelTransfer(1);
644 if (m_client)
645 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
647 break;
650 case OP_REQUESTPARTS: { // 0.43b
651 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client->GetFullIP() );
653 theStats::AddDownOverheadFileRequest(size);
655 m_client->ProcessRequestPartsPacket(buffer, size, false);
657 break;
660 case OP_CANCELTRANSFER: { // 0.43b
661 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client->GetFullIP() );
663 theStats::AddDownOverheadFileRequest(size);
664 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
665 AddDebugLogLineM( false, logClient, m_client->GetUserName() + wxT(": Upload session ended due canceled transfer."));
666 break;
669 case OP_END_OF_DOWNLOAD: { // 0.43b except check for bad clients
670 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client->GetFullIP() );
672 theStats::AddDownOverheadFileRequest(size);
673 if (size>=16 && m_client->GetUploadFileID() == CMD4Hash(buffer)) {
674 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
675 AddDebugLogLineM( false, logClient, m_client->GetUserName() + wxT(": Upload session ended due ended transfer."));
677 break;
680 case OP_HASHSETREQUEST: { // 0.43b except check for bad clients
681 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client->GetFullIP() );
684 theStats::AddDownOverheadFileRequest(size);
685 if (size != 16) {
686 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
688 m_client->SendHashsetPacket(CMD4Hash(buffer));
689 break;
692 case OP_HASHSETANSWER: { // 0.43b
693 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client->GetFullIP() );
695 theStats::AddDownOverheadFileRequest(size);
696 m_client->ProcessHashSet(buffer, size);
697 break;
700 case OP_SENDINGPART: { // 0.47a
701 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART from ") + m_client->GetFullIP() );
703 if ( m_client->GetRequestFile() &&
704 !m_client->GetRequestFile()->IsStopped() &&
705 (m_client->GetRequestFile()->GetStatus() == PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
707 m_client->ProcessBlockPacket(buffer, size, false, false);
709 if ( m_client &&
710 ( m_client->GetRequestFile()->IsStopped() ||
711 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
712 m_client->GetRequestFile()->GetStatus() == PS_ERROR) ) {
713 if (!m_client->GetSentCancelTransfer()) {
714 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
715 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
716 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
717 m_client->SendPacket(packet,true,true);
719 // Socket might die because of SendPacket, so check
720 if (m_client)
721 m_client->SetSentCancelTransfer(1);
724 if (m_client)
725 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
727 } else {
728 if (!m_client->GetSentCancelTransfer()) {
729 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
730 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
731 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
732 m_client->SendPacket(packet,true,true);
734 // Socket might die because of SendPacket, so check
735 m_client->SetSentCancelTransfer(1);
737 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
739 break;
742 case OP_OUTOFPARTREQS: { // 0.43b
743 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client->GetFullIP() );
745 theStats::AddDownOverheadFileRequest(size);
746 if (m_client->GetDownloadState() == DS_DOWNLOADING) {
747 m_client->SetDownloadState(DS_ONQUEUE);
749 break;
752 case OP_CHANGE_CLIENT_ID: { // Kad reviewed
753 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client->GetFullIP() );
755 theStats::AddDownOverheadOther(size);
756 CMemFile data(buffer, size);
757 uint32 nNewUserID = data.ReadUInt32();
758 uint32 nNewServerIP = data.ReadUInt32();
760 if (IsLowID(nNewUserID)) { // client changed server and gots a LowID
761 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
762 if (pNewServer != NULL){
763 m_client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
764 m_client->SetServerIP(nNewServerIP);
765 m_client->SetServerPort(pNewServer->GetPort());
767 } else if (nNewUserID == m_client->GetIP()) { // client changed server and gots a HighID(IP)
768 m_client->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID));
769 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
770 if (pNewServer != NULL){
771 m_client->SetServerIP(nNewServerIP);
772 m_client->SetServerPort(pNewServer->GetPort());
776 break;
779 case OP_CHANGE_SLOT:{ // 0.43b
780 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client->GetFullIP() );
782 // sometimes sent by Hybrid
783 theStats::AddDownOverheadOther(size);
784 break;
787 case OP_MESSAGE: { // 0.43b
788 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MESSAGE from ") + m_client->GetFullIP() );
790 theStats::AddDownOverheadOther(size);
792 CMemFile message_file(buffer, size);
794 wxString message = message_file.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
795 if (IsMessageFiltered(message, m_client)) {
796 AddLogLineM( true, CFormat(_("Message filtered from '%s' (IP:%s)")) % m_client->GetUserName() % m_client->GetFullIP());
797 } else {
798 wxString logMsg = CFormat(_("New message from '%s' (IP:%s)")) % m_client->GetUserName() % m_client->GetFullIP();
799 if(thePrefs::ShowMessagesInLog()) {
800 logMsg += wxT(": ") + message;
802 AddLogLineM( true, logMsg);
804 Notify_ChatProcessMsg(GUI_ID(m_client->GetIP(),m_client->GetUserPort()), m_client->GetUserName() + wxT("|") + message);
806 break;
809 case OP_ASKSHAREDFILES: { // 0.43b (well, er, it does the same, but in our own way)
810 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
812 // client wants to know what we have in share, let's see if we allow him to know that
813 theStats::AddDownOverheadOther(size);
814 // IP banned, no answer for this request
815 if (m_client->IsBanned()) {
816 break;
819 if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
820 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
821 % m_client->GetUserName()
822 % m_client->GetUserIDHybrid() );
824 std::vector<CKnownFile*> list;
825 theApp->sharedfiles->CopyFileList(list);
827 CMemFile tempfile(80);
828 tempfile.WriteUInt32(list.size());
829 for (unsigned i = 0; i < list.size(); ++i) {
830 if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
831 theApp->sharedfiles->CreateOfferedFilePacket(list[i], &tempfile, NULL, m_client);
835 // create a packet and send it
836 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
837 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
838 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
839 SendPacket(replypacket, true, true);
840 } else {
841 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
842 % m_client->GetUserName()
843 % m_client->GetUserIDHybrid() );
845 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
846 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
847 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
848 SendPacket(replypacket, true, true);
851 break;
854 case OP_ASKSHAREDFILESANSWER: { // 0.43b
855 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
857 theStats::AddDownOverheadOther(size);
858 wxString EmptyStr;
859 m_client->ProcessSharedFileList(buffer, size, EmptyStr);
860 break;
863 case OP_ASKSHAREDDIRS: { // 0.43b
864 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
866 theStats::AddDownOverheadOther(size);
867 wxASSERT( size == 0 );
868 // IP banned, no answer for this request
869 if (m_client->IsBanned()) {
870 break;
872 if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
873 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
874 % m_client->GetUserName()
875 % m_client->GetUserIDHybrid() );
877 // This list will contain all (unique) folders.
878 std::list<CPath> foldersToSend;
880 // The shared folders
881 const unsigned folderCount = theApp->glob_prefs->shareddir_list.size();
882 for (unsigned i = 0; i < folderCount; ++i) {
883 foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]);
886 // ... the categories folders ... (category 0 -> incoming)
887 for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) {
888 foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path);
891 // ... and the Magic thing from the eDonkey Hybrids...
892 foldersToSend.push_back(CPath(OP_INCOMPLETE_SHARED_FILES));
894 // Strip duplicates
895 foldersToSend.sort();
896 foldersToSend.unique();
898 // Send packet.
899 CMemFile tempfile(80);
900 tempfile.WriteUInt32(foldersToSend.size());
902 std::list<CPath>::iterator it = foldersToSend.begin();
903 for (; it != foldersToSend.end(); ++it) {
904 // We need to send the 'raw' filename, so we can recognize it again.
905 tempfile.WriteString(it->GetRaw(), m_client->GetUnicodeSupport());
908 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS);
909 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
910 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client->GetFullIP() );
911 SendPacket(replypacket, true, true);
912 } else {
913 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
914 % m_client->GetUserName()
915 % m_client->GetUserIDHybrid() );
917 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
918 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
919 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
920 SendPacket(replypacket, true, true);
923 break;
926 case OP_ASKSHAREDFILESDIR: { // 0.43b
927 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
929 theStats::AddDownOverheadOther(size);
930 // IP banned, no answer for this request
931 if (m_client->IsBanned()) {
932 break;
934 CMemFile data(buffer, size);
936 wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
937 if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
938 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
939 wxASSERT( data.GetPosition() == data.GetLength() );
941 CKnownFilePtrList list;
943 if (strReqDir == OP_INCOMPLETE_SHARED_FILES) {
944 // get all shared files from download queue
945 int iQueuedFiles = theApp->downloadqueue->GetFileCount();
946 for (int i = 0; i < iQueuedFiles; i++) {
947 CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i);
948 if (pFile == NULL || pFile->GetStatus(true) != PS_READY) {
949 continue;
952 list.push_back(pFile);
954 } else {
955 theApp->sharedfiles->GetSharedFilesByDirectory(strReqDir, list);
958 CMemFile tempfile(80);
959 tempfile.WriteString(strReqDir, m_client->GetUnicodeSupport());
960 tempfile.WriteUInt32(list.size());
962 while (!list.empty()) {
963 if (!list.front()->IsLargeFile() || m_client->SupportsLargeFiles()) {
964 theApp->sharedfiles->CreateOfferedFilePacket(list.front(), &tempfile, NULL, m_client);
967 list.pop_front();
970 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS);
971 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
972 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client->GetFullIP() );
973 SendPacket(replypacket, true, true);
974 } else {
975 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
977 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
978 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
979 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
980 SendPacket(replypacket, true, true);
982 break;
985 case OP_ASKSHAREDDIRSANS:{ // 0.43b
986 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
988 theStats::AddDownOverheadOther(size);
989 if (m_client->GetFileListRequested() == 1){
990 CMemFile data(buffer, size);
991 uint32 uDirs = data.ReadUInt32();
992 for (uint32 i = 0; i < uDirs; i++){
993 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
994 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
995 % m_client->GetUserName()
996 % m_client->GetUserIDHybrid()
997 % strDir );
999 CMemFile tempfile(80);
1000 tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
1001 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
1002 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
1003 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client->GetFullIP() );
1004 SendPacket(replypacket, true, true);
1006 wxASSERT( data.GetPosition() == data.GetLength() );
1007 m_client->SetFileListRequested(uDirs);
1008 } else {
1009 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1010 % m_client->GetUserName()
1011 % m_client->GetUserIDHybrid() );
1013 break;
1016 case OP_ASKSHAREDFILESDIRANS: { // 0.43b
1017 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
1019 theStats::AddDownOverheadOther(size);
1020 CMemFile data(buffer, size);
1021 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1023 if (m_client->GetFileListRequested() > 0){
1024 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1025 % m_client->GetUserName()
1026 % m_client->GetUserIDHybrid()
1027 % strDir );
1029 m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
1030 if (m_client->GetFileListRequested() == 0) {
1031 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1032 % m_client->GetUserName()
1033 % m_client->GetUserIDHybrid() );
1035 } else {
1036 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1037 % m_client->GetUserName()
1038 % m_client->GetUserIDHybrid() );
1040 break;
1043 case OP_ASKSHAREDDENIEDANS:
1044 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
1046 theStats::AddDownOverheadOther(size);
1047 wxASSERT( size == 0 );
1048 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1049 % m_client->GetUserName()
1050 % m_client->GetUserIDHybrid() );
1052 m_client->SetFileListRequested(0);
1053 break;
1055 default:
1056 theStats::AddDownOverheadOther(size);
1057 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1058 return false;
1061 return true;
1065 bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1067 #ifdef __PACKET_RECV_DUMP__
1068 //printf("Rec: OPCODE %x \n",opcode);
1069 DumpMem(buffer,size);
1070 #endif
1072 // 0.42e - except the catchs on mem exception and file exception
1073 if (!m_client) {
1074 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1077 if (!client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1078 // Here comes a extended packet without finishing the hanshake.
1079 // IMHO, we should disconnect the client.
1080 throw wxString(wxT("Client send extended packet before finishing handshake"));
1083 switch(opcode) {
1084 case OP_MULTIPACKET_EXT:
1085 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1086 case OP_MULTIPACKET: {
1087 if (opcode == OP_MULTIPACKET) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1089 theStats::AddDownOverheadFileRequest(size);
1091 if (m_client->IsBanned()) {
1092 break;
1095 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1096 // Here comes a extended packet without finishing the hanshake.
1097 // IMHO, we should disconnect the client.
1098 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1101 CMemFile data_in(buffer, size);
1102 CMD4Hash reqfilehash = data_in.ReadHash();
1103 uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1105 bool file_not_found = false;
1106 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1107 if ( reqfile == NULL ){
1108 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1109 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1110 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a non-shared file"));
1111 file_not_found = true;
1115 if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1116 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1117 file_not_found = true;
1120 if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1121 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1122 file_not_found = true;
1125 if (file_not_found) {
1126 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1127 replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1128 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1129 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1130 SendPacket(replypacket, true);
1131 break;
1134 if (!m_client->GetWaitStartTime()) {
1135 m_client->SetWaitStartTime();
1137 // if we are downloading this file, this could be a new source
1138 // no passive adding of files with only one part
1139 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1140 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount()) {
1141 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
1144 // check to see if this is a new file they are asking for
1145 if (m_client->GetUploadFileID() != reqfilehash) {
1146 m_client->SetCommentDirty();
1148 m_client->SetUploadFileID(reqfile);
1149 CMemFile data_out(128);
1150 data_out.WriteHash(reqfile->GetFileHash());
1151 while(data_in.GetLength()-data_in.GetPosition()) {
1152 if (!m_client) {
1153 throw wxString(wxT("Client suddenly disconnected"));
1155 uint8 opcode_in = data_in.ReadUInt8();
1156 switch(opcode_in) {
1157 case OP_REQUESTFILENAME: {
1158 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1159 m_client->ProcessExtendedInfo(&data_in, reqfile);
1160 data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1162 // Since it's for somebody else to see, we need to send the prettified
1163 // filename, rather than the (possibly) mangled actual filename
1164 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1165 break;
1167 case OP_AICHFILEHASHREQ: {
1168 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1169 if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1170 && reqfile->GetAICHHashset()->HasValidMasterHash())
1172 data_out.WriteUInt8(OP_AICHFILEHASHANS);
1173 reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1175 break;
1177 case OP_SETREQFILEID: {
1178 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1179 data_out.WriteUInt8(OP_FILESTATUS);
1180 if (reqfile->IsPartFile()) {
1181 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1182 } else {
1183 data_out.WriteUInt16(0);
1185 break;
1187 //We still send the source packet separately..
1188 //We could send it within this packet.. If agreeded, I will fix it..
1189 case OP_REQUESTSOURCES2:
1190 case OP_REQUESTSOURCES: {
1191 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1192 uint8 byRequestedVersion = 0;
1193 uint16 byRequestedOptions = 0;
1194 if (opcode_in == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1195 byRequestedVersion = data_in.ReadUInt8();
1196 byRequestedOptions = data_in.ReadUInt16();
1199 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1201 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1202 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1203 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1204 if(
1205 //if not complete and file is rare
1206 ( reqfile->IsPartFile()
1207 && (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1208 && ((CPartFile*)reqfile)->GetSourceCount() <= RARE_FILE
1209 ) ||
1210 //OR if file is not rare or if file is complete
1211 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1214 m_client->SetLastSrcReqTime();
1215 CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1216 if(tosend) {
1217 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1218 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1219 SendPacket(tosend, true);
1223 break;
1228 if( data_out.GetLength() > 16 ) {
1229 CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1230 theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1231 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1232 SendPacket(reply, true);
1234 break;
1237 case OP_MULTIPACKETANSWER: { // 0.43b
1238 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1240 theStats::AddDownOverheadFileRequest(size);
1242 if (m_client->IsBanned()) {
1243 break;
1246 if( m_client->GetKadPort() ) {
1247 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort(), m_client->GetKadVersion() > 1);
1250 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1251 // Here comes a extended packet without finishing the hanshake.
1252 // IMHO, we should disconnect the client.
1253 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1256 CMemFile data_in(buffer, size);
1257 CMD4Hash reqfilehash = data_in.ReadHash();
1258 const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1259 //Make sure we are downloading this file.
1260 if ( !reqfile ) {
1261 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1263 if ( !m_client->GetRequestFile() ) {
1265 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1267 if (reqfile != m_client->GetRequestFile()) {
1268 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1270 while (data_in.GetLength()-data_in.GetPosition()) {
1271 // Some of the cases down there can actually send a packet and lose the client
1272 if (!m_client) {
1273 throw wxString(wxT("Client suddenly disconnected"));
1275 uint8 opcode_in = data_in.ReadUInt8();
1276 switch(opcode_in) {
1277 case OP_REQFILENAMEANSWER: {
1278 if (!m_client) {
1279 throw wxString(wxT("Client suddenly disconnected"));
1280 } else {
1281 m_client->ProcessFileInfo(&data_in, reqfile);
1283 break;
1285 case OP_FILESTATUS: {
1286 if (!m_client) {
1287 throw wxString(wxT("Client suddenly disconnected"));
1288 } else {
1289 m_client->ProcessFileStatus(false, &data_in, reqfile);
1291 break;
1293 case OP_AICHFILEHASHANS: {
1294 if (!m_client) {
1295 throw wxString(wxT("Client suddenly disconnected"));
1296 } else {
1297 m_client->ProcessAICHFileHash(&data_in, reqfile);
1299 break;
1304 break;
1307 case OP_EMULEINFO: { // 0.43b
1308 theStats::AddDownOverheadOther(size);
1310 if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1311 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1313 // If it's not a OS Info packet, is an old client
1314 // start secure identification, if
1315 // - we have received eD2K and eMule info (old eMule)
1316 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1317 m_client->InfoPacketsReceived();
1319 m_client->SendMuleInfoPacket(true);
1320 } else {
1321 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1323 break;
1325 case OP_EMULEINFOANSWER: { // 0.43b
1326 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1327 theStats::AddDownOverheadOther(size);
1329 m_client->ProcessMuleInfoPacket(buffer, size);
1330 // start secure identification, if
1331 // - we have received eD2K and eMule info (old eMule)
1333 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1334 m_client->InfoPacketsReceived();
1337 break;
1340 case OP_SECIDENTSTATE:{ // 0.43b
1341 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1343 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1344 // Here comes a extended packet without finishing the hanshake.
1345 // IMHO, we should disconnect the client.
1346 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1348 m_client->ProcessSecIdentStatePacket(buffer, size);
1349 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1350 if (m_client) {
1351 int SecureIdentState = m_client->GetSecureIdentState();
1352 if (SecureIdentState == IS_SIGNATURENEEDED) {
1353 m_client->SendSignaturePacket();
1354 } else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1355 m_client->SendPublicKeyPacket();
1356 // SendPublicKeyPacket() might cause the socket to die, so check
1357 if ( m_client ) {
1358 m_client->SendSignaturePacket();
1362 break;
1365 case OP_PUBLICKEY: { // 0.43b
1366 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1368 if (m_client->IsBanned() ){
1369 break;
1372 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1373 // Here comes a extended packet without finishing the hanshake.
1374 // IMHO, we should disconnect the client.
1375 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1378 m_client->ProcessPublicKeyPacket(buffer, size);
1379 break;
1381 case OP_SIGNATURE:{ // 0.43b
1382 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1384 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1385 // Here comes a extended packet without finishing the hanshake.
1386 // IMHO, we should disconnect the client.
1387 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1390 m_client->ProcessSignaturePacket(buffer, size);
1391 break;
1393 case OP_SENDINGPART_I64:
1394 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1395 case OP_COMPRESSEDPART_I64:
1396 if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1397 case OP_COMPRESSEDPART: { // 0.47a
1398 if (opcode == OP_COMPRESSEDPART) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1400 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1401 // Here comes a extended packet without finishing the hanshake.
1402 // IMHO, we should disconnect the client.
1403 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1406 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1408 m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1410 if (m_client && (
1411 m_client->GetRequestFile()->IsStopped() ||
1412 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1413 m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1414 if (!m_client->GetSentCancelTransfer()) {
1415 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1416 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1417 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1418 m_client->SendPacket(packet,true,true);
1420 if (m_client) {
1421 m_client->SetSentCancelTransfer(1);
1425 if ( m_client ) {
1426 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1429 } else {
1430 if (!m_client->GetSentCancelTransfer()) {
1431 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1432 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1433 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1434 m_client->SendPacket(packet,true,true);
1436 if ( m_client ) {
1437 m_client->SetSentCancelTransfer(1);
1441 if ( m_client ) {
1442 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1445 break;
1447 case OP_REQUESTPARTS_I64: {
1448 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP() );
1450 theStats::AddDownOverheadFileRequest(size);
1452 m_client->ProcessRequestPartsPacket(buffer, size, true);
1454 break;
1456 case OP_QUEUERANKING: { // 0.43b
1457 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP() );
1459 theStats::AddDownOverheadOther(size);
1461 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1462 // Here comes a extended packet without finishing the hanshake.
1463 // IMHO, we should disconnect the client.
1464 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1467 if (size != 12) {
1468 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1471 uint16 newrank = PeekUInt16(buffer);
1472 m_client->SetRemoteQueueFull(false);
1473 m_client->SetRemoteQueueRank(newrank);
1474 break;
1476 case OP_REQUESTSOURCES2:
1477 case OP_REQUESTSOURCES:{
1478 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP() );
1480 theStats::AddDownOverheadSourceExchange(size);
1482 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1483 // Here comes an extended packet without finishing the handshake.
1484 // IMHO, we should disconnect the client.
1485 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1488 uint8 byRequestedVersion = 0;
1489 uint16 byRequestedOptions = 0;
1490 CMemFile data_in(buffer, size);
1491 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1492 byRequestedVersion = data_in.ReadUInt8();
1493 byRequestedOptions = data_in.ReadUInt16();
1496 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1497 if(size != 16) {
1498 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1500 //first check shared file list, then download list
1501 const CMD4Hash fileID(buffer);
1502 CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1503 if(!file) {
1504 file = theApp->downloadqueue->GetFileByID(fileID);
1506 if(file) {
1507 // There are some clients which do not follow the correct protocol procedure of sending
1508 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1509 // are doing this, they will not get the optimal set of sources which we could offer if
1510 // they would follow the above noted protocol sequence. They better do it the right way
1511 // or they will get just a random set of sources because we do not know their download
1512 // part status which may get cleared with the call of 'SetUploadFileID'.
1513 m_client->SetUploadFileID(file);
1515 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1516 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1517 if(
1518 //if not complete and file is rare, allow once every 40 minutes
1519 ( file->IsPartFile() &&
1520 ((CPartFile*)file)->GetSourceCount() <= RARE_FILE &&
1521 (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1522 ) ||
1523 //OR if file is not rare or if file is complete, allow every 90 minutes
1524 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1527 m_client->SetLastSrcReqTime();
1528 CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1529 if(tosend) {
1530 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1531 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1532 SendPacket(tosend, true, true);
1537 break;
1539 case OP_ANSWERSOURCES: {
1540 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP() );
1542 theStats::AddDownOverheadSourceExchange(size);
1544 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1545 // Here comes a extended packet without finishing the hanshake.
1546 // IMHO, we should disconnect the client.
1547 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1550 CMemFile data(buffer, size);
1551 CMD4Hash hash = data.ReadHash();
1552 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1553 if(file){
1554 if (file->IsPartFile()){
1555 //set the client's answer time
1556 m_client->SetLastSrcAnswerTime();
1557 //and set the file's last answer time
1558 ((CPartFile*)file)->SetLastAnsweredTime();
1560 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1563 break;
1565 case OP_ANSWERSOURCES2: {
1566 //printf("Received OP_ANSWERSOURCES2\n");
1567 theStats::AddDownOverheadSourceExchange(size);
1569 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1570 // Here comes a extended packet without finishing the hanshake.
1571 // IMHO, we should disconnect the client.
1572 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1575 CMemFile data(buffer, size);
1576 uint8 byVersion = data.ReadUInt8();
1577 CMD4Hash hash = data.ReadHash();
1578 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1579 if (file){
1580 if (file->IsPartFile()){
1581 //set the client's answer time
1582 m_client->SetLastSrcAnswerTime();
1583 //and set the file's last answer time
1584 ((CPartFile*)file)->SetLastAnsweredTime();
1585 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1588 break;
1590 case OP_FILEDESC: { // 0.43b
1591 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP() );
1593 theStats::AddDownOverheadFileRequest(size);
1595 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1596 // Here comes a extended packet without finishing the hanshake.
1597 // IMHO, we should disconnect the client.
1598 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1601 m_client->ProcessMuleCommentPacket(buffer, size);
1602 break;
1605 // Unsupported
1606 case OP_REQUESTPREVIEW: {
1607 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client->GetFullIP() );
1608 break;
1610 // Unsupported
1611 case OP_PREVIEWANSWER: {
1612 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP() );
1613 break;
1616 case OP_PUBLICIP_ANSWER: {
1617 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP() );
1618 theStats::AddDownOverheadOther(size);
1619 m_client->ProcessPublicIPAnswer(buffer, size);
1620 break;
1622 case OP_PUBLICIP_REQ: {
1623 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP() );
1624 theStats::AddDownOverheadOther(size);
1625 CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1626 pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1627 theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1628 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1629 SendPacket(pPacket);
1630 break;
1632 case OP_AICHANSWER: {
1633 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP() );
1634 theStats::AddDownOverheadOther(size);
1635 m_client->ProcessAICHAnswer(buffer, size);
1636 break;
1638 case OP_AICHREQUEST: {
1639 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP() );
1640 theStats::AddDownOverheadOther(size);
1641 m_client->ProcessAICHRequest(buffer, size);
1642 break;
1644 case OP_AICHFILEHASHANS: {
1645 // those should not be received normally, since we should only get those in MULTIPACKET
1646 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP() );
1647 theStats::AddDownOverheadOther(size);
1648 CMemFile data(buffer, size);
1649 m_client->ProcessAICHFileHash(&data, NULL);
1650 break;
1652 case OP_AICHFILEHASHREQ: {
1653 // those should not be received normally, since we should only get those in MULTIPACKET
1654 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP() );
1655 CMemFile data(buffer, size);
1656 CMD4Hash hash = data.ReadHash();
1657 CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1658 if (pPartFile == NULL){
1659 break;
1662 if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1663 && pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1664 CMemFile data_out;
1665 data_out.WriteHash(hash);
1666 pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1667 CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1668 theStats::AddUpOverheadOther(packet->GetPacketSize());
1669 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1670 SendPacket(packet);
1672 break;
1674 case OP_CALLBACK: {
1675 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1676 theStats::AddDownOverheadFileRequest(size);
1677 if(!Kademlia::CKademlia::IsRunning()) {
1678 break;
1680 CMemFile data(buffer, size);
1681 CUInt128 check = data.ReadUInt128();
1682 check.XOR(Kademlia::CUInt128(true));
1683 if( check.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1684 break;
1686 CUInt128 fileid = data.ReadUInt128();
1687 byte fileid2[16];
1688 fileid.ToByteArray(fileid2);
1689 const CMD4Hash fileHash(fileid2);
1690 if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1691 if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1692 break;
1696 uint32 ip = data.ReadUInt32();
1697 uint16 tcp = data.ReadUInt16();
1698 CUpDownClient* callback;
1699 callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1700 if( callback == NULL ) {
1701 //#warning Do we actually have to check friend status here?
1702 callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1703 theApp->clientlist->AddClient(callback);
1705 callback->TryToConnect(true);
1706 break;
1709 case OP_BUDDYPING: {
1710 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP() );
1711 theStats::AddDownOverheadKad(size);
1713 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1714 if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1715 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1716 break;
1719 m_client->SetLastBuddyPingPongTime();
1720 CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1721 theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1722 AddDebugLogLineM(false, logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1723 SendPacket(replypacket);
1724 break;
1726 case OP_BUDDYPONG: {
1727 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP() );
1728 theStats::AddDownOverheadKad(size);
1730 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1731 if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1732 //This pong was not from our buddy or wrong version. Ignore
1733 break;
1735 m_client->SetLastBuddyPingPongTime();
1736 //All this is for is to reset our socket timeout.
1737 break;
1739 case OP_REASKCALLBACKTCP: {
1740 theStats::AddDownOverheadFileRequest(size);
1741 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1742 if (buddy != m_client) {
1743 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1744 //This callback was not from our buddy.. Ignore.
1745 break;
1747 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1748 CMemFile data_in(buffer, size);
1749 uint32 destip = data_in.ReadUInt32();
1750 uint16 destport = data_in.ReadUInt16();
1751 CMD4Hash hash = data_in.ReadHash();
1752 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1754 bool bSenderMultipleIpUnknown = false;
1755 CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1756 if (!reqfile) {
1757 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1758 CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1759 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1760 if (sender) {
1761 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1762 } else {
1763 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1765 break;
1768 if (sender) {
1769 //Make sure we are still thinking about the same file
1770 if (hash == sender->GetUploadFileID()) {
1771 sender->AddAskedCount();
1772 sender->SetLastUpRequest();
1773 //I messed up when I first added extended info to UDP
1774 //I should have originally used the entire ProcessExtenedInfo the first time.
1775 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1776 //For now on, we should not have to change anything here if we change
1777 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1778 //Update extended info.
1779 if (sender->GetUDPVersion() > 3) {
1780 sender->ProcessExtendedInfo(&data_in, reqfile);
1781 } else if (sender->GetUDPVersion() > 2) {
1782 //Update our complete source counts.
1783 uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1784 uint16 nCompleteCountNew = data_in.ReadUInt16();
1785 sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1786 if (nCompleteCountLast != nCompleteCountNew) {
1787 reqfile->UpdatePartsInfo();
1791 CMemFile data_out(128);
1792 if(sender->GetUDPVersion() > 3) {
1793 if (reqfile->IsPartFile()) {
1794 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1795 } else {
1796 data_out.WriteUInt16(0);
1800 data_out.WriteUInt16(theApp->uploadqueue->GetWaitingPosition(sender));
1801 CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1802 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1803 AddDebugLogLineM( false, logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP() );
1804 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1805 } else {
1806 AddDebugLogLineM(false, logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1808 } else {
1809 if (!bSenderMultipleIpUnknown){
1810 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1811 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP() );
1812 CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1813 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1814 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1816 } else {
1817 AddDebugLogLineM(false, 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);
1820 break;
1822 case OP_FWCHECKUDPREQ: { // Support required for Kadversion >= 6
1823 AddDebugLogLineM(false, logRemoteClient, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client->GetFullIP());
1824 theStats::AddDownOverheadOther(size);
1825 CMemFile data_in(buffer, size);
1826 m_client->ProcessFirewallCheckUDPRequest(&data_in);
1827 break;
1829 case OP_KAD_FWTCPCHECK_ACK: { // Support required for Kadversion >= 7
1830 AddDebugLogLineM(false, logRemoteClient, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client->GetFullIP());
1831 if (theApp->clientlist->IsKadFirewallCheckIP(m_client->GetIP())) {
1832 if (Kademlia::CKademlia::IsRunning()) {
1833 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1835 } else {
1836 AddDebugLogLineM(false, logListenSocket, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client->GetFullIP());
1838 break;
1840 default:
1841 theStats::AddDownOverheadOther(size);
1842 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode,opcode) + m_client->GetFullIP());
1843 break;
1846 return true;
1849 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1851 #ifdef __PACKET_RECV_DUMP__
1852 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1853 DumpMem(buffer,size);
1854 #endif
1856 if (!m_client) {
1857 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1860 CMemFile data(buffer, size);
1861 try {
1862 switch(opcode) {
1863 case OP_QUEUERANK: {
1864 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1866 uint8 numtags = data.ReadUInt8();
1867 wxASSERT(numtags == 1);
1869 m_client->SetRemoteQueueRank(data.GetIntTagValue());
1871 theStats::AddDownOverheadFileRequest(size);
1872 break;
1875 case OP_REQUESTPARTS: {
1876 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1878 m_client->ProcessRequestPartsPacketv2(data);
1880 theStats::AddDownOverheadFileRequest(size);
1881 break;
1884 default:
1885 theStats::AddDownOverheadOther(size);
1886 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1888 } catch (...) {
1889 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data.GetPosition(), opcode, opcode) + m_client->GetFullIP());
1890 throw;
1893 return true;
1896 void CClientTCPSocket::OnConnect(int nErrorCode)
1898 if (nErrorCode) {
1899 OnError(nErrorCode);
1900 } else if (!m_client) {
1901 // and now? Disconnect? not?
1902 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1903 } else if (!m_client->SendHelloPacket()) {
1904 // and now? Disconnect? not?
1905 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1906 } else {
1907 ResetTimeOutTimer();
1912 void CClientTCPSocket::OnSend(int nErrorCode)
1914 ResetTimeOutTimer();
1915 CEMSocket::OnSend(nErrorCode);
1919 void CClientTCPSocket::OnReceive(int nErrorCode)
1921 ResetTimeOutTimer();
1922 // We might have updated ipfilter
1923 wxASSERT(m_remoteip);
1925 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1926 if (m_client) {
1927 m_client->Safe_Delete();
1929 Safe_Delete();
1930 AddDebugLogLineM( false, logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1931 } else {
1932 CEMSocket::OnReceive(nErrorCode);
1937 void CClientTCPSocket::OnError(int nErrorCode)
1939 //printf("* Called OnError for %p\n",this);
1940 // 0.42e + Kry changes for handling of socket lost events
1941 wxString strError;
1943 if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1944 if (m_client) {
1945 if (!m_client->GetUserName().IsEmpty()) {
1946 strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1947 } else {
1948 strError = wxT("An unnamed client");
1950 strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1951 } else {
1952 strError = wxT("A client ");
1954 if (nErrorCode == 0) {
1955 strError += wxT("closed connection.");
1956 } else if (nErrorCode == 0xFEFF) {
1957 strError += wxT(" caused a wxSOCKET_LOST event.");
1958 } else {
1959 strError += wxT("caused a socket blocking error.");
1961 } else {
1962 if (theLogger.IsEnabled(logClient) && nErrorCode != 107) {
1963 // 0 -> No Error / Disconect
1964 // 107 -> Transport endpoint is not connected
1965 if (m_client) {
1966 if (!m_client->GetUserName().IsEmpty()) {
1967 strError = wxT("OnError: Client '") + m_client->GetUserName() +
1968 wxT("' (IP:") + m_client->GetFullIP() +
1969 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
1970 } else {
1971 strError = wxT("OnError: Unknown client (IP:") +
1972 m_client->GetFullIP() +
1973 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
1975 } else {
1976 strError = wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
1977 nErrorCode);
1979 } else {
1980 strError = wxT("Error 107 (Transport endpoint is not connected)");
1984 Disconnect(strError);
1988 bool CClientTCPSocket::PacketReceived(CPacket* packet)
1990 // 0.42e
1991 bool bResult = false;
1992 uint32 uRawSize = packet->GetPacketSize();
1994 AddDebugLogLineM( false, logRemoteClient,
1995 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1996 % packet->GetProtocol()
1997 % packet->GetOpCode()
1998 % packet->GetPacketSize()
1999 % ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
2002 wxString exception;
2004 try {
2005 bool process = true;
2007 if ((packet->GetProtocol() == OP_PACKEDPROT) ||
2008 (packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
2010 if (!packet->UnPackPacket()) {
2011 AddDebugLogLineM( false, logZLib, wxT("Failed to decompress client TCP packet."));
2012 bResult = false;
2013 process = false;
2014 } else {
2015 AddDebugLogLineM(false, logRemoteClient,
2016 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
2017 packet->GetProtocol(),
2018 packet->GetOpCode(),
2019 packet->GetPacketSize())
2024 if (process) {
2025 switch (packet->GetProtocol()) {
2026 case OP_EDONKEYPROT:
2027 bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
2028 break;
2029 case OP_EMULEPROT:
2030 bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2031 break;
2032 case OP_ED2KV2HEADER:
2033 bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2034 break;
2035 case OP_ED2KV2PACKEDPROT:
2036 case OP_PACKEDPROT:
2037 // Packed inside packed?
2038 wxASSERT(0);
2039 break;
2040 default: {
2041 theStats::AddDownOverheadOther(uRawSize);
2042 if (m_client) {
2043 m_client->SetDownloadState(DS_ERROR);
2045 Disconnect(wxT("Unknown protocol"));
2046 bResult = false;
2050 } catch (const CEOFException& err) {
2051 exception = wxT("EOF exception: ") + err.what();
2052 } catch (const CInvalidPacket& err) {
2053 exception = wxT("InvalidPacket exception: ") + err.what();
2054 } catch (const wxString& error) {
2055 exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2058 if (!exception.IsEmpty()) {
2059 AddDebugLogLineM( false, logPacketErrors,
2060 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2061 % exception
2062 % packet->GetProtocol()
2063 % packet->GetOpCode()
2064 % packet->GetPacketSize()
2065 % ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2068 if (m_client) {
2069 m_client->SetDownloadState(DS_ERROR);
2072 AddDebugLogLineM( false, logClient,
2073 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2074 % ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2075 % ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2076 % exception
2079 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2082 return bResult;
2086 bool CClientTCPSocket::IsMessageFiltered(const wxString& Message, CUpDownClient* client) {
2088 bool filtered = false;
2089 // If we're chatting to the guy, we don't want to filter!
2090 if (client->GetChatState() != MS_CHATTING) {
2091 if (thePrefs::MsgOnlyFriends() && !client->IsFriend()) {
2092 filtered = true;
2093 } else if (thePrefs::MsgOnlySecure() && client->GetUserName().IsEmpty() ) {
2094 filtered = true;
2095 } else if (thePrefs::MustFilterMessages()) {
2096 filtered = thePrefs::IsMessageFiltered(Message);
2099 return filtered;
2102 SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2104 SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2106 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2107 ResetTimeOutTimer();
2110 return returnStatus;
2114 SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2116 SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2118 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2119 ResetTimeOutTimer();
2122 return returnStatus;
2126 void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2128 ResetTimeOutTimer();
2129 CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2131 // File_checked_for_headers