Upstream tarball 9450
[amule.git] / src / ClientTCPSocket.cpp
blob977141e33f919c456296325b934bc6d77616eab5
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 wxFAIL;
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 if (size < 2) {
793 throw wxString(wxT("invalid message packet"));
795 CMemFile message_file(buffer, size);
796 uint16 length = message_file.ReadUInt16();
797 if (length + 2u != size) {
798 throw wxString(wxT("invalid message packet"));
801 // limit message length
802 static const uint16 MAX_CLIENT_MSG_LEN = 450;
804 if (length > MAX_CLIENT_MSG_LEN) {
805 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
806 % m_client->GetUserName() % m_client->GetFullIP() % (length - MAX_CLIENT_MSG_LEN));
807 length = MAX_CLIENT_MSG_LEN;
810 wxString message = message_file.ReadOnlyString((m_client->GetUnicodeSupport() != utf8strNone), length);
811 m_client->ProcessChatMessage(message);
813 break;
816 case OP_ASKSHAREDFILES: { // 0.43b (well, er, it does the same, but in our own way)
817 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
819 // client wants to know what we have in share, let's see if we allow him to know that
820 theStats::AddDownOverheadOther(size);
821 // IP banned, no answer for this request
822 if (m_client->IsBanned()) {
823 break;
826 if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
827 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
828 % m_client->GetUserName()
829 % m_client->GetUserIDHybrid() );
831 std::vector<CKnownFile*> list;
832 theApp->sharedfiles->CopyFileList(list);
834 CMemFile tempfile(80);
835 tempfile.WriteUInt32(list.size());
836 for (unsigned i = 0; i < list.size(); ++i) {
837 if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
838 theApp->sharedfiles->CreateOfferedFilePacket(list[i], &tempfile, NULL, m_client);
842 // create a packet and send it
843 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
844 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
845 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
846 SendPacket(replypacket, true, true);
847 } else {
848 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
849 % m_client->GetUserName()
850 % m_client->GetUserIDHybrid() );
852 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
853 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
854 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
855 SendPacket(replypacket, true, true);
858 break;
861 case OP_ASKSHAREDFILESANSWER: { // 0.43b
862 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
864 theStats::AddDownOverheadOther(size);
865 wxString EmptyStr;
866 m_client->ProcessSharedFileList(buffer, size, EmptyStr);
867 break;
870 case OP_ASKSHAREDDIRS: { // 0.43b
871 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
873 theStats::AddDownOverheadOther(size);
874 wxASSERT( size == 0 );
875 // IP banned, no answer for this request
876 if (m_client->IsBanned()) {
877 break;
879 if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
880 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
881 % m_client->GetUserName()
882 % m_client->GetUserIDHybrid() );
884 // This list will contain all (unique) folders.
885 std::list<CPath> foldersToSend;
887 // The shared folders
888 const unsigned folderCount = theApp->glob_prefs->shareddir_list.size();
889 for (unsigned i = 0; i < folderCount; ++i) {
890 foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]);
893 // ... the categories folders ... (category 0 -> incoming)
894 for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) {
895 foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path);
898 // ... and the Magic thing from the eDonkey Hybrids...
899 foldersToSend.push_back(CPath(OP_INCOMPLETE_SHARED_FILES));
901 // Strip duplicates
902 foldersToSend.sort();
903 foldersToSend.unique();
905 // Send packet.
906 CMemFile tempfile(80);
907 tempfile.WriteUInt32(foldersToSend.size());
909 std::list<CPath>::iterator it = foldersToSend.begin();
910 for (; it != foldersToSend.end(); ++it) {
911 // We need to send the 'raw' filename, so we can recognize it again.
912 tempfile.WriteString(it->GetRaw(), m_client->GetUnicodeSupport());
915 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS);
916 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
917 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client->GetFullIP() );
918 SendPacket(replypacket, true, true);
919 } else {
920 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
921 % m_client->GetUserName()
922 % m_client->GetUserIDHybrid() );
924 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
925 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
926 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
927 SendPacket(replypacket, true, true);
930 break;
933 case OP_ASKSHAREDFILESDIR: { // 0.43b
934 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
936 theStats::AddDownOverheadOther(size);
937 // IP banned, no answer for this request
938 if (m_client->IsBanned()) {
939 break;
941 CMemFile data(buffer, size);
943 wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
944 if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
945 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
946 wxASSERT( data.GetPosition() == data.GetLength() );
948 CKnownFilePtrList list;
950 if (strReqDir == OP_INCOMPLETE_SHARED_FILES) {
951 // get all shared files from download queue
952 int iQueuedFiles = theApp->downloadqueue->GetFileCount();
953 for (int i = 0; i < iQueuedFiles; i++) {
954 CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i);
955 if (pFile == NULL || pFile->GetStatus(true) != PS_READY) {
956 continue;
959 list.push_back(pFile);
961 } else {
962 theApp->sharedfiles->GetSharedFilesByDirectory(strReqDir, list);
965 CMemFile tempfile(80);
966 tempfile.WriteString(strReqDir, m_client->GetUnicodeSupport());
967 tempfile.WriteUInt32(list.size());
969 while (!list.empty()) {
970 if (!list.front()->IsLargeFile() || m_client->SupportsLargeFiles()) {
971 theApp->sharedfiles->CreateOfferedFilePacket(list.front(), &tempfile, NULL, m_client);
974 list.pop_front();
977 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS);
978 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
979 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client->GetFullIP() );
980 SendPacket(replypacket, true, true);
981 } else {
982 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
984 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
985 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
986 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
987 SendPacket(replypacket, true, true);
989 break;
992 case OP_ASKSHAREDDIRSANS:{ // 0.43b
993 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
995 theStats::AddDownOverheadOther(size);
996 if (m_client->GetFileListRequested() == 1){
997 CMemFile data(buffer, size);
998 uint32 uDirs = data.ReadUInt32();
999 for (uint32 i = 0; i < uDirs; i++){
1000 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1001 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
1002 % m_client->GetUserName()
1003 % m_client->GetUserIDHybrid()
1004 % strDir );
1006 CMemFile tempfile(80);
1007 tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
1008 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
1009 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
1010 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client->GetFullIP() );
1011 SendPacket(replypacket, true, true);
1013 wxASSERT( data.GetPosition() == data.GetLength() );
1014 m_client->SetFileListRequested(uDirs);
1015 } else {
1016 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1017 % m_client->GetUserName()
1018 % m_client->GetUserIDHybrid() );
1020 break;
1023 case OP_ASKSHAREDFILESDIRANS: { // 0.43b
1024 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
1026 theStats::AddDownOverheadOther(size);
1027 CMemFile data(buffer, size);
1028 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1030 if (m_client->GetFileListRequested() > 0){
1031 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1032 % m_client->GetUserName()
1033 % m_client->GetUserIDHybrid()
1034 % strDir );
1036 m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
1037 if (m_client->GetFileListRequested() == 0) {
1038 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1039 % m_client->GetUserName()
1040 % m_client->GetUserIDHybrid() );
1042 } else {
1043 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1044 % m_client->GetUserName()
1045 % m_client->GetUserIDHybrid() );
1047 break;
1050 case OP_ASKSHAREDDENIEDANS:
1051 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
1053 theStats::AddDownOverheadOther(size);
1054 wxASSERT( size == 0 );
1055 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1056 % m_client->GetUserName()
1057 % m_client->GetUserIDHybrid() );
1059 m_client->SetFileListRequested(0);
1060 break;
1062 default:
1063 theStats::AddDownOverheadOther(size);
1064 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1065 return false;
1068 return true;
1072 bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1074 #ifdef __PACKET_RECV_DUMP__
1075 //printf("Rec: OPCODE %x \n",opcode);
1076 DumpMem(buffer,size);
1077 #endif
1079 // 0.42e - except the catchs on mem exception and file exception
1080 if (!m_client) {
1081 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1084 if (!client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1085 // Here comes a extended packet without finishing the hanshake.
1086 // IMHO, we should disconnect the client.
1087 throw wxString(wxT("Client send extended packet before finishing handshake"));
1090 switch(opcode) {
1091 case OP_MULTIPACKET_EXT:
1092 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1093 case OP_MULTIPACKET: {
1094 if (opcode == OP_MULTIPACKET) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1096 theStats::AddDownOverheadFileRequest(size);
1098 if (m_client->IsBanned()) {
1099 break;
1102 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1103 // Here comes a extended packet without finishing the hanshake.
1104 // IMHO, we should disconnect the client.
1105 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1108 CMemFile data_in(buffer, size);
1109 CMD4Hash reqfilehash = data_in.ReadHash();
1110 uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1112 bool file_not_found = false;
1113 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1114 if ( reqfile == NULL ){
1115 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1116 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1117 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a non-shared file"));
1118 file_not_found = true;
1122 if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1123 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1124 file_not_found = true;
1127 if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1128 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1129 file_not_found = true;
1132 if (file_not_found) {
1133 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1134 replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1135 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1136 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1137 SendPacket(replypacket, true);
1138 break;
1141 if (!m_client->GetWaitStartTime()) {
1142 m_client->SetWaitStartTime();
1144 // if we are downloading this file, this could be a new source
1145 // no passive adding of files with only one part
1146 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1147 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount()) {
1148 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
1151 // check to see if this is a new file they are asking for
1152 if (m_client->GetUploadFileID() != reqfilehash) {
1153 m_client->SetCommentDirty();
1155 m_client->SetUploadFileID(reqfile);
1156 CMemFile data_out(128);
1157 data_out.WriteHash(reqfile->GetFileHash());
1158 while(data_in.GetLength()-data_in.GetPosition()) {
1159 if (!m_client) {
1160 throw wxString(wxT("Client suddenly disconnected"));
1162 uint8 opcode_in = data_in.ReadUInt8();
1163 switch(opcode_in) {
1164 case OP_REQUESTFILENAME: {
1165 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1166 m_client->ProcessExtendedInfo(&data_in, reqfile);
1167 data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1169 // Since it's for somebody else to see, we need to send the prettified
1170 // filename, rather than the (possibly) mangled actual filename
1171 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1172 break;
1174 case OP_AICHFILEHASHREQ: {
1175 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1176 if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1177 && reqfile->GetAICHHashset()->HasValidMasterHash())
1179 data_out.WriteUInt8(OP_AICHFILEHASHANS);
1180 reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1182 break;
1184 case OP_SETREQFILEID: {
1185 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1186 data_out.WriteUInt8(OP_FILESTATUS);
1187 if (reqfile->IsPartFile()) {
1188 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1189 } else {
1190 data_out.WriteUInt16(0);
1192 break;
1194 //We still send the source packet separately..
1195 //We could send it within this packet.. If agreeded, I will fix it..
1196 case OP_REQUESTSOURCES2:
1197 case OP_REQUESTSOURCES: {
1198 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1199 uint8 byRequestedVersion = 0;
1200 uint16 byRequestedOptions = 0;
1201 if (opcode_in == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1202 byRequestedVersion = data_in.ReadUInt8();
1203 byRequestedOptions = data_in.ReadUInt16();
1206 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1208 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1209 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1210 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1211 if(
1212 //if not complete and file is rare
1213 ( reqfile->IsPartFile()
1214 && (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1215 && ((CPartFile*)reqfile)->GetSourceCount() <= RARE_FILE
1216 ) ||
1217 //OR if file is not rare or if file is complete
1218 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1221 m_client->SetLastSrcReqTime();
1222 CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1223 if(tosend) {
1224 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1225 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1226 SendPacket(tosend, true);
1230 break;
1235 if( data_out.GetLength() > 16 ) {
1236 CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1237 theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1238 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1239 SendPacket(reply, true);
1241 break;
1244 case OP_MULTIPACKETANSWER: { // 0.43b
1245 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1247 theStats::AddDownOverheadFileRequest(size);
1249 if (m_client->IsBanned()) {
1250 break;
1253 if( m_client->GetKadPort() ) {
1254 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort(), m_client->GetKadVersion() > 1);
1257 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1258 // Here comes a extended packet without finishing the hanshake.
1259 // IMHO, we should disconnect the client.
1260 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1263 CMemFile data_in(buffer, size);
1264 CMD4Hash reqfilehash = data_in.ReadHash();
1265 const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1266 //Make sure we are downloading this file.
1267 if ( !reqfile ) {
1268 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1270 if ( !m_client->GetRequestFile() ) {
1272 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1274 if (reqfile != m_client->GetRequestFile()) {
1275 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1277 while (data_in.GetLength()-data_in.GetPosition()) {
1278 // Some of the cases down there can actually send a packet and lose the client
1279 if (!m_client) {
1280 throw wxString(wxT("Client suddenly disconnected"));
1282 uint8 opcode_in = data_in.ReadUInt8();
1283 switch(opcode_in) {
1284 case OP_REQFILENAMEANSWER: {
1285 if (!m_client) {
1286 throw wxString(wxT("Client suddenly disconnected"));
1287 } else {
1288 m_client->ProcessFileInfo(&data_in, reqfile);
1290 break;
1292 case OP_FILESTATUS: {
1293 if (!m_client) {
1294 throw wxString(wxT("Client suddenly disconnected"));
1295 } else {
1296 m_client->ProcessFileStatus(false, &data_in, reqfile);
1298 break;
1300 case OP_AICHFILEHASHANS: {
1301 if (!m_client) {
1302 throw wxString(wxT("Client suddenly disconnected"));
1303 } else {
1304 m_client->ProcessAICHFileHash(&data_in, reqfile);
1306 break;
1311 break;
1314 case OP_EMULEINFO: { // 0.43b
1315 theStats::AddDownOverheadOther(size);
1317 if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1318 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1320 // If it's not a OS Info packet, is an old client
1321 // start secure identification, if
1322 // - we have received eD2K and eMule info (old eMule)
1323 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1324 m_client->InfoPacketsReceived();
1326 m_client->SendMuleInfoPacket(true);
1327 } else {
1328 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1330 break;
1332 case OP_EMULEINFOANSWER: { // 0.43b
1333 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1334 theStats::AddDownOverheadOther(size);
1336 m_client->ProcessMuleInfoPacket(buffer, size);
1337 // start secure identification, if
1338 // - we have received eD2K and eMule info (old eMule)
1340 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1341 m_client->InfoPacketsReceived();
1344 break;
1347 case OP_SECIDENTSTATE:{ // 0.43b
1348 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1350 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1351 // Here comes a extended packet without finishing the hanshake.
1352 // IMHO, we should disconnect the client.
1353 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1355 m_client->ProcessSecIdentStatePacket(buffer, size);
1356 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1357 if (m_client) {
1358 int SecureIdentState = m_client->GetSecureIdentState();
1359 if (SecureIdentState == IS_SIGNATURENEEDED) {
1360 m_client->SendSignaturePacket();
1361 } else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1362 m_client->SendPublicKeyPacket();
1363 // SendPublicKeyPacket() might cause the socket to die, so check
1364 if ( m_client ) {
1365 m_client->SendSignaturePacket();
1369 break;
1372 case OP_PUBLICKEY: { // 0.43b
1373 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1375 if (m_client->IsBanned() ){
1376 break;
1379 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1380 // Here comes a extended packet without finishing the hanshake.
1381 // IMHO, we should disconnect the client.
1382 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1385 m_client->ProcessPublicKeyPacket(buffer, size);
1386 break;
1388 case OP_SIGNATURE:{ // 0.43b
1389 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1391 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1392 // Here comes a extended packet without finishing the hanshake.
1393 // IMHO, we should disconnect the client.
1394 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1397 m_client->ProcessSignaturePacket(buffer, size);
1398 break;
1400 case OP_SENDINGPART_I64:
1401 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1402 case OP_COMPRESSEDPART_I64:
1403 if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1404 case OP_COMPRESSEDPART: { // 0.47a
1405 if (opcode == OP_COMPRESSEDPART) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1407 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1408 // Here comes a extended packet without finishing the hanshake.
1409 // IMHO, we should disconnect the client.
1410 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1413 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1415 m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1417 if (m_client && (
1418 m_client->GetRequestFile()->IsStopped() ||
1419 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1420 m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1421 if (!m_client->GetSentCancelTransfer()) {
1422 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1423 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1424 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1425 m_client->SendPacket(packet,true,true);
1427 if (m_client) {
1428 m_client->SetSentCancelTransfer(1);
1432 if ( m_client ) {
1433 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1436 } else {
1437 if (!m_client->GetSentCancelTransfer()) {
1438 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1439 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1440 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1441 m_client->SendPacket(packet,true,true);
1443 if ( m_client ) {
1444 m_client->SetSentCancelTransfer(1);
1448 if ( m_client ) {
1449 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1452 break;
1454 case OP_REQUESTPARTS_I64: {
1455 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP() );
1457 theStats::AddDownOverheadFileRequest(size);
1459 m_client->ProcessRequestPartsPacket(buffer, size, true);
1461 break;
1463 case OP_QUEUERANKING: { // 0.43b
1464 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP() );
1466 theStats::AddDownOverheadOther(size);
1468 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1469 // Here comes a extended packet without finishing the hanshake.
1470 // IMHO, we should disconnect the client.
1471 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1474 if (size != 12) {
1475 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1478 uint16 newrank = PeekUInt16(buffer);
1479 m_client->SetRemoteQueueFull(false);
1480 m_client->SetRemoteQueueRank(newrank);
1481 break;
1483 case OP_REQUESTSOURCES2:
1484 case OP_REQUESTSOURCES:{
1485 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP() );
1487 theStats::AddDownOverheadSourceExchange(size);
1489 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1490 // Here comes an extended packet without finishing the handshake.
1491 // IMHO, we should disconnect the client.
1492 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1495 uint8 byRequestedVersion = 0;
1496 uint16 byRequestedOptions = 0;
1497 CMemFile data_in(buffer, size);
1498 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1499 byRequestedVersion = data_in.ReadUInt8();
1500 byRequestedOptions = data_in.ReadUInt16();
1503 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1504 if(size != 16) {
1505 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1507 //first check shared file list, then download list
1508 const CMD4Hash fileID(buffer);
1509 CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1510 if(!file) {
1511 file = theApp->downloadqueue->GetFileByID(fileID);
1513 if(file) {
1514 // There are some clients which do not follow the correct protocol procedure of sending
1515 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1516 // are doing this, they will not get the optimal set of sources which we could offer if
1517 // they would follow the above noted protocol sequence. They better do it the right way
1518 // or they will get just a random set of sources because we do not know their download
1519 // part status which may get cleared with the call of 'SetUploadFileID'.
1520 m_client->SetUploadFileID(file);
1522 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1523 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1524 if(
1525 //if not complete and file is rare, allow once every 40 minutes
1526 ( file->IsPartFile() &&
1527 ((CPartFile*)file)->GetSourceCount() <= RARE_FILE &&
1528 (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1529 ) ||
1530 //OR if file is not rare or if file is complete, allow every 90 minutes
1531 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1534 m_client->SetLastSrcReqTime();
1535 CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1536 if(tosend) {
1537 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1538 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1539 SendPacket(tosend, true, true);
1544 break;
1546 case OP_ANSWERSOURCES: {
1547 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP() );
1549 theStats::AddDownOverheadSourceExchange(size);
1551 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1552 // Here comes a extended packet without finishing the hanshake.
1553 // IMHO, we should disconnect the client.
1554 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1557 CMemFile data(buffer, size);
1558 CMD4Hash hash = data.ReadHash();
1559 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1560 if(file){
1561 if (file->IsPartFile()){
1562 //set the client's answer time
1563 m_client->SetLastSrcAnswerTime();
1564 //and set the file's last answer time
1565 ((CPartFile*)file)->SetLastAnsweredTime();
1567 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1570 break;
1572 case OP_ANSWERSOURCES2: {
1573 //printf("Received OP_ANSWERSOURCES2\n");
1574 theStats::AddDownOverheadSourceExchange(size);
1576 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1577 // Here comes a extended packet without finishing the hanshake.
1578 // IMHO, we should disconnect the client.
1579 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1582 CMemFile data(buffer, size);
1583 uint8 byVersion = data.ReadUInt8();
1584 CMD4Hash hash = data.ReadHash();
1585 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1586 if (file){
1587 if (file->IsPartFile()){
1588 //set the client's answer time
1589 m_client->SetLastSrcAnswerTime();
1590 //and set the file's last answer time
1591 ((CPartFile*)file)->SetLastAnsweredTime();
1592 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1595 break;
1597 case OP_FILEDESC: { // 0.43b
1598 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP() );
1600 theStats::AddDownOverheadFileRequest(size);
1602 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1603 // Here comes a extended packet without finishing the hanshake.
1604 // IMHO, we should disconnect the client.
1605 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1608 m_client->ProcessMuleCommentPacket(buffer, size);
1609 break;
1612 // Unsupported
1613 case OP_REQUESTPREVIEW: {
1614 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client->GetFullIP() );
1615 break;
1617 // Unsupported
1618 case OP_PREVIEWANSWER: {
1619 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP() );
1620 break;
1623 case OP_PUBLICIP_ANSWER: {
1624 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP() );
1625 theStats::AddDownOverheadOther(size);
1626 m_client->ProcessPublicIPAnswer(buffer, size);
1627 break;
1629 case OP_PUBLICIP_REQ: {
1630 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP() );
1631 theStats::AddDownOverheadOther(size);
1632 CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1633 pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1634 theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1635 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1636 SendPacket(pPacket);
1637 break;
1639 case OP_AICHANSWER: {
1640 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP() );
1641 theStats::AddDownOverheadOther(size);
1642 m_client->ProcessAICHAnswer(buffer, size);
1643 break;
1645 case OP_AICHREQUEST: {
1646 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP() );
1647 theStats::AddDownOverheadOther(size);
1648 m_client->ProcessAICHRequest(buffer, size);
1649 break;
1651 case OP_AICHFILEHASHANS: {
1652 // those should not be received normally, since we should only get those in MULTIPACKET
1653 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP() );
1654 theStats::AddDownOverheadOther(size);
1655 CMemFile data(buffer, size);
1656 m_client->ProcessAICHFileHash(&data, NULL);
1657 break;
1659 case OP_AICHFILEHASHREQ: {
1660 // those should not be received normally, since we should only get those in MULTIPACKET
1661 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP() );
1662 CMemFile data(buffer, size);
1663 CMD4Hash hash = data.ReadHash();
1664 CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1665 if (pPartFile == NULL){
1666 break;
1669 if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1670 && pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1671 CMemFile data_out;
1672 data_out.WriteHash(hash);
1673 pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1674 CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1675 theStats::AddUpOverheadOther(packet->GetPacketSize());
1676 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1677 SendPacket(packet);
1679 break;
1681 case OP_CALLBACK: {
1682 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1683 theStats::AddDownOverheadFileRequest(size);
1684 if(!Kademlia::CKademlia::IsRunning()) {
1685 break;
1687 CMemFile data(buffer, size);
1688 CUInt128 check = data.ReadUInt128();
1689 check.XOR(Kademlia::CUInt128(true));
1690 if( check.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1691 break;
1693 CUInt128 fileid = data.ReadUInt128();
1694 byte fileid2[16];
1695 fileid.ToByteArray(fileid2);
1696 const CMD4Hash fileHash(fileid2);
1697 if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1698 if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1699 break;
1703 uint32 ip = data.ReadUInt32();
1704 uint16 tcp = data.ReadUInt16();
1705 CUpDownClient* callback;
1706 callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1707 if( callback == NULL ) {
1708 //#warning Do we actually have to check friend status here?
1709 callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1710 theApp->clientlist->AddClient(callback);
1712 callback->TryToConnect(true);
1713 break;
1716 case OP_BUDDYPING: {
1717 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP() );
1718 theStats::AddDownOverheadKad(size);
1720 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1721 if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1722 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1723 break;
1726 m_client->SetLastBuddyPingPongTime();
1727 CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1728 theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1729 AddDebugLogLineM(false, logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1730 SendPacket(replypacket);
1731 break;
1733 case OP_BUDDYPONG: {
1734 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP() );
1735 theStats::AddDownOverheadKad(size);
1737 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1738 if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1739 //This pong was not from our buddy or wrong version. Ignore
1740 break;
1742 m_client->SetLastBuddyPingPongTime();
1743 //All this is for is to reset our socket timeout.
1744 break;
1746 case OP_REASKCALLBACKTCP: {
1747 theStats::AddDownOverheadFileRequest(size);
1748 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1749 if (buddy != m_client) {
1750 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1751 //This callback was not from our buddy.. Ignore.
1752 break;
1754 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1755 CMemFile data_in(buffer, size);
1756 uint32 destip = data_in.ReadUInt32();
1757 uint16 destport = data_in.ReadUInt16();
1758 CMD4Hash hash = data_in.ReadHash();
1759 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1761 bool bSenderMultipleIpUnknown = false;
1762 CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1763 if (!reqfile) {
1764 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1765 CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1766 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1767 if (sender) {
1768 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1769 } else {
1770 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1772 break;
1775 if (sender) {
1776 //Make sure we are still thinking about the same file
1777 if (hash == sender->GetUploadFileID()) {
1778 sender->AddAskedCount();
1779 sender->SetLastUpRequest();
1780 //I messed up when I first added extended info to UDP
1781 //I should have originally used the entire ProcessExtenedInfo the first time.
1782 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1783 //For now on, we should not have to change anything here if we change
1784 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1785 //Update extended info.
1786 if (sender->GetUDPVersion() > 3) {
1787 sender->ProcessExtendedInfo(&data_in, reqfile);
1788 } else if (sender->GetUDPVersion() > 2) {
1789 //Update our complete source counts.
1790 uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1791 uint16 nCompleteCountNew = data_in.ReadUInt16();
1792 sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1793 if (nCompleteCountLast != nCompleteCountNew) {
1794 reqfile->UpdatePartsInfo();
1798 CMemFile data_out(128);
1799 if(sender->GetUDPVersion() > 3) {
1800 if (reqfile->IsPartFile()) {
1801 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1802 } else {
1803 data_out.WriteUInt16(0);
1807 data_out.WriteUInt16(theApp->uploadqueue->GetWaitingPosition(sender));
1808 CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1809 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1810 AddDebugLogLineM( false, logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP() );
1811 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1812 } else {
1813 AddDebugLogLineM(false, logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1815 } else {
1816 if (!bSenderMultipleIpUnknown){
1817 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1818 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP() );
1819 CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1820 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1821 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1823 } else {
1824 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);
1827 break;
1829 case OP_CHATCAPTCHAREQ:
1831 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client->GetFullIP());
1832 theStats::AddDownOverheadOther(size);
1833 CMemFile data_in(buffer, size);
1834 m_client->ProcessCaptchaRequest(&data_in);
1835 break;
1837 case OP_CHATCAPTCHARES:
1839 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client->GetFullIP());
1840 theStats::AddDownOverheadOther(size);
1841 if (size) {
1842 m_client->ProcessCaptchaReqRes(buffer[0]);
1844 break;
1846 case OP_FWCHECKUDPREQ: { // Support required for Kadversion >= 6
1847 AddDebugLogLineM(false, logRemoteClient, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client->GetFullIP());
1848 theStats::AddDownOverheadOther(size);
1849 CMemFile data_in(buffer, size);
1850 m_client->ProcessFirewallCheckUDPRequest(&data_in);
1851 break;
1853 case OP_KAD_FWTCPCHECK_ACK: { // Support required for Kadversion >= 7
1854 AddDebugLogLineM(false, logRemoteClient, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client->GetFullIP());
1855 if (theApp->clientlist->IsKadFirewallCheckIP(m_client->GetIP())) {
1856 if (Kademlia::CKademlia::IsRunning()) {
1857 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1859 } else {
1860 AddDebugLogLineM(false, logListenSocket, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client->GetFullIP());
1862 break;
1864 default:
1865 theStats::AddDownOverheadOther(size);
1866 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode,opcode) + m_client->GetFullIP());
1867 break;
1870 return true;
1873 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1875 #ifdef __PACKET_RECV_DUMP__
1876 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1877 DumpMem(buffer,size);
1878 #endif
1880 if (!m_client) {
1881 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1884 CMemFile data(buffer, size);
1885 try {
1886 switch(opcode) {
1887 case OP_QUEUERANK: {
1888 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1890 uint8 numtags = data.ReadUInt8();
1891 wxASSERT(numtags == 1);
1893 m_client->SetRemoteQueueRank(data.GetIntTagValue());
1895 theStats::AddDownOverheadFileRequest(size);
1896 break;
1899 case OP_REQUESTPARTS: {
1900 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1902 m_client->ProcessRequestPartsPacketv2(data);
1904 theStats::AddDownOverheadFileRequest(size);
1905 break;
1908 default:
1909 theStats::AddDownOverheadOther(size);
1910 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1912 } catch (...) {
1913 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data.GetPosition(), opcode, opcode) + m_client->GetFullIP());
1914 throw;
1917 return true;
1920 void CClientTCPSocket::OnConnect(int nErrorCode)
1922 if (nErrorCode) {
1923 OnError(nErrorCode);
1924 } else if (!m_client) {
1925 // and now? Disconnect? not?
1926 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1927 } else if (!m_client->SendHelloPacket()) {
1928 // and now? Disconnect? not?
1929 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1930 } else {
1931 ResetTimeOutTimer();
1936 void CClientTCPSocket::OnSend(int nErrorCode)
1938 ResetTimeOutTimer();
1939 CEMSocket::OnSend(nErrorCode);
1943 void CClientTCPSocket::OnReceive(int nErrorCode)
1945 ResetTimeOutTimer();
1946 // We might have updated ipfilter
1947 wxASSERT(m_remoteip);
1949 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1950 if (m_client) {
1951 m_client->Safe_Delete();
1953 Safe_Delete();
1954 AddDebugLogLineM( false, logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1955 } else {
1956 CEMSocket::OnReceive(nErrorCode);
1961 void CClientTCPSocket::OnError(int nErrorCode)
1963 //printf("* Called OnError for %p\n",this);
1964 // 0.42e + Kry changes for handling of socket lost events
1965 wxString strError;
1967 if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1968 if (m_client) {
1969 if (!m_client->GetUserName().IsEmpty()) {
1970 strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1971 } else {
1972 strError = wxT("An unnamed client");
1974 strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1975 } else {
1976 strError = wxT("A client ");
1978 if (nErrorCode == 0) {
1979 strError += wxT("closed connection.");
1980 } else if (nErrorCode == 0xFEFF) {
1981 strError += wxT(" caused a wxSOCKET_LOST event.");
1982 } else {
1983 strError += wxT("caused a socket blocking error.");
1985 } else {
1986 if (theLogger.IsEnabled(logClient) && nErrorCode != 107) {
1987 // 0 -> No Error / Disconect
1988 // 107 -> Transport endpoint is not connected
1989 if (m_client) {
1990 if (!m_client->GetUserName().IsEmpty()) {
1991 strError = wxT("OnError: Client '") + m_client->GetUserName() +
1992 wxT("' (IP:") + m_client->GetFullIP() +
1993 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
1994 } else {
1995 strError = wxT("OnError: Unknown client (IP:") +
1996 m_client->GetFullIP() +
1997 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
1999 } else {
2000 strError = wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
2001 nErrorCode);
2003 } else {
2004 strError = wxT("Error 107 (Transport endpoint is not connected)");
2008 Disconnect(strError);
2012 bool CClientTCPSocket::PacketReceived(CPacket* packet)
2014 // 0.42e
2015 bool bResult = false;
2016 uint32 uRawSize = packet->GetPacketSize();
2018 AddDebugLogLineM( false, logRemoteClient,
2019 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
2020 % packet->GetProtocol()
2021 % packet->GetOpCode()
2022 % packet->GetPacketSize()
2023 % ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
2026 wxString exception;
2028 try {
2029 bool process = true;
2031 if ((packet->GetProtocol() == OP_PACKEDPROT) ||
2032 (packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
2034 if (!packet->UnPackPacket()) {
2035 AddDebugLogLineM( false, logZLib, wxT("Failed to decompress client TCP packet."));
2036 bResult = false;
2037 process = false;
2038 } else {
2039 AddDebugLogLineM(false, logRemoteClient,
2040 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
2041 packet->GetProtocol(),
2042 packet->GetOpCode(),
2043 packet->GetPacketSize())
2048 if (process) {
2049 switch (packet->GetProtocol()) {
2050 case OP_EDONKEYPROT:
2051 bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
2052 break;
2053 case OP_EMULEPROT:
2054 bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2055 break;
2056 case OP_ED2KV2HEADER:
2057 bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2058 break;
2059 case OP_ED2KV2PACKEDPROT:
2060 case OP_PACKEDPROT:
2061 // Packed inside packed?
2062 wxFAIL;
2063 break;
2064 default: {
2065 theStats::AddDownOverheadOther(uRawSize);
2066 if (m_client) {
2067 m_client->SetDownloadState(DS_ERROR);
2069 Disconnect(wxT("Unknown protocol"));
2070 bResult = false;
2074 } catch (const CEOFException& err) {
2075 exception = wxT("EOF exception: ") + err.what();
2076 } catch (const CInvalidPacket& err) {
2077 exception = wxT("InvalidPacket exception: ") + err.what();
2078 } catch (const wxString& error) {
2079 exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2082 if (!exception.IsEmpty()) {
2083 AddDebugLogLineM( false, logPacketErrors,
2084 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2085 % exception
2086 % packet->GetProtocol()
2087 % packet->GetOpCode()
2088 % packet->GetPacketSize()
2089 % ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2092 if (m_client) {
2093 m_client->SetDownloadState(DS_ERROR);
2096 AddDebugLogLineM( false, logClient,
2097 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2098 % ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2099 % ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2100 % exception
2103 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2106 return bResult;
2110 SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2112 SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2114 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2115 ResetTimeOutTimer();
2118 return returnStatus;
2122 SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2124 SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2126 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2127 ResetTimeOutTimer();
2130 return returnStatus;
2134 void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2136 ResetTimeOutTimer();
2137 CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2139 // File_checked_for_headers