Reduced variable scope
[amule.git] / src / ClientTCPSocket.cpp
blobc485ae81c9dcdf6b03b44ba23ab38d145d43e7a5
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )//
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
8 // respective authors.
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
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.
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 wxSocketBase* baseSocket = event.GetSocket();
80 // wxASSERT(baseSocket); // Rather want a log message right now. Enough other wx problems. >:(
81 if (!baseSocket) { // WTF?
82 AddDebugLogLineN(logClient, wxT("received bad wxSocketEvent"));
83 return;
86 CClientTCPSocket *socket = dynamic_cast<CClientTCPSocket *>(baseSocket);
87 wxASSERT(socket);
88 if (!socket) {
89 return;
92 if (socket->IsDestroying()) {
93 return;
96 switch(event.GetSocketEvent()) {
97 case wxSOCKET_LOST:
98 socket->OnError(0xFEFF /* SOCKET_LOST is not an error */);
99 break;
100 case wxSOCKET_INPUT:
101 socket->OnReceive(0);
102 break;
103 case wxSOCKET_OUTPUT:
104 socket->OnSend(0);
105 break;
106 case wxSOCKET_CONNECTION:
107 // connection stablished, nothing to do about it?
108 socket->OnConnect(socket->LastError());
109 break;
110 default:
111 // Nothing should arrive here...
112 wxFAIL;
113 break;
118 // There can be only one. :)
120 static CClientTCPSocketHandler g_clientReqSocketHandler;
123 //------------------------------------------------------------------------------
124 // CClientTCPSocket
125 //------------------------------------------------------------------------------
127 CClientTCPSocket::CClientTCPSocket(CUpDownClient* in_client, const CProxyData *ProxyData)
128 : CEMSocket(ProxyData)
130 SetClient(in_client);
131 if (in_client) {
132 m_remoteip = wxUINT32_SWAP_ALWAYS(in_client->GetUserIDHybrid());
133 } else {
134 m_remoteip = 0;
137 ResetTimeOutTimer();
139 SetEventHandler(g_clientReqSocketHandler, ID_CLIENTTCPSOCKET_EVENT);
140 SetNotify(
141 wxSOCKET_CONNECTION_FLAG |
142 wxSOCKET_INPUT_FLAG |
143 wxSOCKET_OUTPUT_FLAG |
144 wxSOCKET_LOST_FLAG);
145 Notify(true);
147 theApp->listensocket->AddSocket(this);
148 theApp->listensocket->AddConnection();
151 CClientTCPSocket::~CClientTCPSocket()
153 // remove event handler
154 SetNotify(0);
155 Notify(false);
157 if (m_client) {
158 m_client->SetSocket( NULL );
160 m_client = NULL;
162 if (theApp->listensocket && !theApp->listensocket->OnShutdown()) {
163 theApp->listensocket->RemoveSocket(this);
167 bool CClientTCPSocket::InitNetworkData()
169 wxASSERT(!m_remoteip);
170 wxASSERT(!m_client);
171 m_remoteip = GetPeerInt();
173 MULE_CHECK(m_remoteip, false);
175 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
176 AddDebugLogLineN(logClient, wxT("Denied connection from ") + GetPeer() + wxT("(Filtered IP)"));
177 return false;
178 } else if (theApp->clientlist->IsBannedClient(m_remoteip)) {
179 AddDebugLogLineN(logClient, wxT("Denied connection from ") + GetPeer() + wxT("(Banned IP)"));
180 return false;
181 } else {
182 AddDebugLogLineN(logClient, wxT("Accepted connection from ") + GetPeer());
183 return true;
187 void CClientTCPSocket::ResetTimeOutTimer()
189 timeout_timer = ::GetTickCount();
193 bool CClientTCPSocket::CheckTimeOut()
195 // 0.42x
196 uint32 uTimeout = GetTimeOut();
197 if (m_client) {
199 if (m_client->GetKadState() == KS_CONNECTED_BUDDY) {
200 //We originally ignored the timeout here for buddies.
201 //This was a stupid idea on my part. There is now a ping/pong system
202 //for buddies. This ping/pong system now prevents timeouts.
203 //This release will allow lowID clients with KadVersion 0 to remain connected.
204 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
205 //JOHNTODO: Don't forget to remove backward support in a future release.
206 if ( m_client->GetKadVersion() == 0 ) {
207 return false;
210 uTimeout += MIN2MS(15);
213 if (m_client->GetChatState() != MS_NONE) {
214 uTimeout += CONNECTION_TIMEOUT;
218 if (::GetTickCount() - timeout_timer > uTimeout){
219 timeout_timer = ::GetTickCount();
220 Disconnect(wxT("Timeout"));
221 return true;
224 return false;
228 void CClientTCPSocket::SetClient(CUpDownClient* pClient)
230 m_client = pClient;
231 if (m_client) {
232 m_client->SetSocket( this );
237 void CClientTCPSocket::OnClose(int nErrorCode)
239 // 0.42x
240 wxASSERT(theApp->listensocket->IsValidSocket(this));
241 CEMSocket::OnClose(nErrorCode);
242 if (nErrorCode) {
243 Disconnect(CFormat(wxT("Closed: %u")) % nErrorCode);
244 } else {
245 Disconnect(wxT("Close"));
250 void CClientTCPSocket::Disconnect(const wxString& strReason)
252 byConnected = ES_DISCONNECTED;
253 if (m_client) {
254 if (m_client->Disconnected(strReason, true)) {
255 // Somehow, Safe_Delete() is beeing called by Disconnected(),
256 // or any other function that sets m_client to NULL,
257 // so we must check m_client first.
258 if (m_client) {
259 m_client->SetSocket( NULL );
260 m_client->Safe_Delete();
263 m_client = NULL;
266 Safe_Delete();
270 void CClientTCPSocket::Safe_Delete()
272 // More paranoia - make sure client is unlinked in any case
273 if (m_client) {
274 m_client->SetSocket( NULL );
275 m_client = NULL;
278 // Destroy may be called several times
279 byConnected = ES_DISCONNECTED;
280 Destroy();
284 void CClientTCPSocket::Safe_Delete_Client()
286 if (m_client) {
287 m_client->Safe_Delete();
288 m_client = NULL;
293 bool CClientTCPSocket::ProcessPacket(const byte* buffer, uint32 size, uint8 opcode)
295 #ifdef __PACKET_RECV_DUMP__
296 //printf("Rec: OPCODE %x \n",opcode);
297 DumpMem(buffer, size);
298 #endif
299 if (!m_client && opcode != OP_HELLO) {
300 throw wxString(wxT("Asks for something without saying hello"));
301 } else if (m_client && opcode != OP_HELLO && opcode != OP_HELLOANSWER) {
302 m_client->CheckHandshakeFinished();
305 switch(opcode) {
306 case OP_HELLOANSWER: { // 0.43b
307 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_HELLOANSWER from ") + m_client->GetFullIP());
308 theStats::AddDownOverheadOther(size);
309 m_client->ProcessHelloAnswer(buffer, size);
311 // start secure identification, if
312 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
313 // - we have received eMule-OP_HELLOANSWER (new eMule)
314 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
315 m_client->InfoPacketsReceived();
318 // Socket might die because of sending in InfoPacketsReceived, so check
319 if (m_client) {
320 m_client->ConnectionEstablished();
323 // Socket might die on ConnectionEstablished somehow. Check it.
324 if (m_client) {
325 Notify_SharedCtrlRefreshClient( m_client->ECID() , AVAILABLE_SOURCE);
328 break;
330 case OP_HELLO: { // 0.43b
332 theStats::AddDownOverheadOther(size);
333 bool bNewClient = !m_client;
334 if (bNewClient) {
335 // create new client to save standart informations
336 m_client = new CUpDownClient(this);
339 // Do not move up!
340 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_HELLO from ") + m_client->GetFullIP() );
342 bool bIsMuleHello = false;
344 try{
345 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
346 } catch(...) {
347 if (bNewClient && m_client) {
348 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
349 m_client->Safe_Delete();
350 m_client = NULL;
352 throw;
355 if (thePrefs::ParanoidFilter() && !IsLowID(m_client->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid()))) {
356 wxString reason = wxT("Client claims a different IP from the one we received the hello packet from: ");
357 reason += Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
358 AddDebugLogLineN(logClient, reason);
359 if (bNewClient) {
360 m_client->Safe_Delete();
361 m_client = NULL;
363 Disconnect(wxT("Paranoid disconecting: ") + reason);
364 return false;
367 // if IP is filtered, dont reply but disconnect...
368 if (theApp->ipfilter->IsFiltered(m_client->GetIP())) {
369 if (bNewClient) {
370 m_client->Safe_Delete();
371 m_client = NULL;
373 Disconnect(wxT("IPFilter"));
374 return false;
377 wxASSERT(m_client);
379 // now we check if we know this client already. if yes this socket will
380 // be attached to the known client, the new client will be deleted
381 // and the var. "client" will point to the known client.
382 // if not we keep our new-constructed client ;)
383 if (theApp->clientlist->AttachToAlreadyKnown(&m_client,this)) {
384 // update the old client informations
385 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
386 } else {
387 theApp->clientlist->AddClient(m_client);
388 m_client->SetCommentDirty();
390 Notify_SharedCtrlRefreshClient( m_client->ECID(), AVAILABLE_SOURCE );
391 // send a response packet with standart informations
392 if ((m_client->GetHashType() == SO_EMULE) && !bIsMuleHello) {
393 m_client->SendMuleInfoPacket(false);
396 // Client might die from Sending in SendMuleInfoPacket, so check
397 if ( m_client ) {
398 m_client->SendHelloAnswer();
401 // Kry - If the other side supports it, send OS_INFO
402 // Client might die from Sending in SendHelloAnswer, so check
403 if (m_client && m_client->GetOSInfoSupport()) {
404 m_client->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
407 // Client might die from Sending in SendMuleInfoPacket, so check
408 if ( m_client ) {
409 m_client->ConnectionEstablished();
412 // start secure identification, if
413 // - we have received eMule-OP_HELLO (new eMule)
414 if (m_client && m_client->GetInfoPacketsReceived() == IP_BOTH) {
415 m_client->InfoPacketsReceived();
418 break;
420 case OP_REQUESTFILENAME: { // 0.43b
421 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client->GetFullIP() );
423 theStats::AddDownOverheadFileRequest(size);
424 // IP banned, no answer for this request
425 if (m_client->IsBanned()) {
426 break;
428 if (size >= 16) {
429 if (!m_client->GetWaitStartTime()) {
430 m_client->SetWaitStartTime();
432 CMemFile data_in(buffer, size);
433 CMD4Hash reqfilehash = data_in.ReadHash();
434 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
435 if ( reqfile == NULL ) {
436 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
437 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
438 break;
441 // if we are downloading this file, this could be a new source
442 // no passive adding of files with only one part
443 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
444 if (thePrefs::GetMaxSourcePerFile() > static_cast<CPartFile*>(reqfile)->GetSourceCount()) {
445 theApp->downloadqueue->CheckAndAddKnownSource(static_cast<CPartFile*>(reqfile), m_client);
449 // check to see if this is a new file they are asking for
450 if (m_client->GetUploadFileID() != reqfilehash) {
451 m_client->SetCommentDirty();
454 m_client->SetUploadFileID(reqfile);
455 m_client->ProcessExtendedInfo(&data_in, reqfile);
457 // send filename etc
458 CMemFile data_out(128);
459 data_out.WriteHash(reqfile->GetFileHash());
461 // Since it's for somebody else to see, we need to send the prettified
462 // filename, rather than the (possibly) mangled actual filename.
463 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
465 CPacket* packet = new CPacket(data_out, OP_EDONKEYPROT, OP_REQFILENAMEANSWER);
466 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
467 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client->GetFullIP() );
468 SendPacket(packet,true);
470 // SendPacket might kill the socket, so check
471 if (m_client)
472 m_client->SendCommentInfo(reqfile);
474 break;
476 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
477 break;
479 case OP_SETREQFILEID: { // 0.43b EXCEPT track of bad clients
480 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SETREQFILEID from ") + m_client->GetFullIP() );
482 theStats::AddDownOverheadFileRequest(size);
484 if (m_client->IsBanned()) {
485 break;
488 // DbT:FileRequest
489 if (size == 16) {
490 if (!m_client->GetWaitStartTime()) {
491 m_client->SetWaitStartTime();
494 const CMD4Hash fileID(buffer);
495 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(fileID);
496 if ( reqfile == NULL ) {
497 reqfile = theApp->downloadqueue->GetFileByID(fileID);
498 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
499 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
500 replypacket->Copy16ToDataBuffer(fileID.GetHash());
501 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
502 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILERE to ") + m_client->GetFullIP() );
503 SendPacket(replypacket, true);
504 break;
508 // check to see if this is a new file they are asking for
509 if (m_client->GetUploadFileID() != fileID) {
510 m_client->SetCommentDirty();
513 m_client->SetUploadFileID(reqfile);
514 // send filestatus
515 CMemFile data(16+16);
516 data.WriteHash(reqfile->GetFileHash());
517 if (reqfile->IsPartFile()) {
518 static_cast<CPartFile*>(reqfile)->WritePartStatus(&data);
519 } else {
520 data.WriteUInt16(0);
522 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_FILESTATUS);
523 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
524 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILESTATUS to ") + m_client->GetFullIP() );
525 SendPacket(packet, true);
526 break;
528 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
529 break;
530 // DbT:End
533 case OP_FILEREQANSNOFIL: { // 0.43b protocol, lacks ZZ's download manager on swap
534 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client->GetFullIP() );
536 theStats::AddDownOverheadFileRequest(size);
537 if (size == 16) {
538 // if that client does not have my file maybe has another different
539 CPartFile* reqfile = theApp->downloadqueue->GetFileByID(CMD4Hash(buffer));
540 if ( reqfile) {
541 reqfile->AddDeadSource( m_client );
542 } else {
543 break;
546 // we try to swap to another file ignoring no needed parts files
547 switch (m_client->GetDownloadState()) {
548 case DS_CONNECTED:
549 case DS_ONQUEUE:
550 case DS_NONEEDEDPARTS:
551 if (!m_client->SwapToAnotherFile(true, true, true, NULL)) {
552 theApp->downloadqueue->RemoveSource(m_client);
554 break;
556 break;
558 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
559 break;
562 case OP_REQFILENAMEANSWER: { // 0.43b except check for bad clients
563 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client->GetFullIP() );
565 theStats::AddDownOverheadFileRequest(size);
566 CMemFile data(buffer, size);
567 CMD4Hash hash = data.ReadHash();
568 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
569 m_client->ProcessFileInfo(&data, file);
570 break;
573 case OP_FILESTATUS: { // 0.43b except check for bad clients
574 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILESTATUS from ") + m_client->GetFullIP() );
576 theStats::AddDownOverheadFileRequest(size);
577 CMemFile data(buffer, size);
578 CMD4Hash hash = data.ReadHash();
579 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
580 m_client->ProcessFileStatus(false, &data, file);
581 break;
584 case OP_STARTUPLOADREQ: {
585 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client->GetFullIP() );
587 theStats::AddDownOverheadFileRequest(size);
589 if (!m_client->CheckHandshakeFinished()) {
590 break;
593 m_client->CheckForAggressive();
594 if ( m_client->IsBanned() ) {
595 break;
598 if (size == 16) {
599 const CMD4Hash fileID(buffer);
600 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(fileID);
601 if (reqfile) {
602 if (m_client->GetUploadFileID() != fileID) {
603 m_client->SetCommentDirty();
605 m_client->SetUploadFileID(reqfile);
606 m_client->SendCommentInfo(reqfile);
608 // Socket might die because of SendCommentInfo, so check
609 if (m_client)
610 theApp->uploadqueue->AddClientToQueue(m_client);
613 break;
616 case OP_QUEUERANK: { // 0.43b
617 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_QUEUERANK from ") + m_client->GetFullIP() );
619 theStats::AddDownOverheadFileRequest(size);
620 CMemFile data(buffer, size);
621 uint32 rank = data.ReadUInt32();
623 m_client->SetRemoteQueueRank(rank);
624 break;
627 case OP_ACCEPTUPLOADREQ: { // 0.42e (xcept khaos stats)
628 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client->GetFullIP() );
630 theStats::AddDownOverheadFileRequest(size);
631 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
632 if (m_client->GetDownloadState() == DS_ONQUEUE ) {
633 m_client->SetDownloadState(DS_DOWNLOADING);
634 m_client->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
635 m_client->SendBlockRequests();
637 } else {
638 if (!m_client->GetSentCancelTransfer()) {
639 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
640 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
641 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
642 m_client->SendPacket(packet,true,true);
644 // SendPacket can cause the socket to die, so check
645 if (m_client)
646 m_client->SetSentCancelTransfer(1);
649 if (m_client)
650 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
652 break;
655 case OP_REQUESTPARTS: { // 0.43b
656 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client->GetFullIP() );
658 theStats::AddDownOverheadFileRequest(size);
660 m_client->ProcessRequestPartsPacket(buffer, size, false);
662 break;
665 case OP_CANCELTRANSFER: { // 0.43b
666 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client->GetFullIP() );
668 theStats::AddDownOverheadFileRequest(size);
669 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
670 AddDebugLogLineN( logClient, m_client->GetUserName() + wxT(": Upload session ended due canceled transfer."));
671 break;
674 case OP_END_OF_DOWNLOAD: { // 0.43b except check for bad clients
675 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client->GetFullIP() );
677 theStats::AddDownOverheadFileRequest(size);
678 if (size>=16 && m_client->GetUploadFileID() == CMD4Hash(buffer)) {
679 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
680 AddDebugLogLineN( logClient, m_client->GetUserName() + wxT(": Upload session ended due ended transfer."));
682 break;
685 case OP_HASHSETREQUEST: { // 0.43b except check for bad clients
686 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client->GetFullIP() );
689 theStats::AddDownOverheadFileRequest(size);
690 if (size != 16) {
691 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
693 m_client->SendHashsetPacket(CMD4Hash(buffer));
694 break;
697 case OP_HASHSETANSWER: { // 0.43b
698 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client->GetFullIP() );
700 theStats::AddDownOverheadFileRequest(size);
701 m_client->ProcessHashSet(buffer, size);
702 break;
705 case OP_SENDINGPART: { // 0.47a
706 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SENDINGPART from ") + m_client->GetFullIP() );
708 if ( m_client->GetRequestFile() &&
709 !m_client->GetRequestFile()->IsStopped() &&
710 (m_client->GetRequestFile()->GetStatus() == PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
712 m_client->ProcessBlockPacket(buffer, size, false, false);
714 if ( m_client &&
715 ( m_client->GetRequestFile()->IsStopped() ||
716 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
717 m_client->GetRequestFile()->GetStatus() == PS_ERROR) ) {
718 if (!m_client->GetSentCancelTransfer()) {
719 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
720 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
721 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
722 m_client->SendPacket(packet,true,true);
724 // Socket might die because of SendPacket, so check
725 if (m_client)
726 m_client->SetSentCancelTransfer(1);
729 if (m_client)
730 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
732 } else {
733 if (!m_client->GetSentCancelTransfer()) {
734 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
735 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
736 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
737 m_client->SendPacket(packet,true,true);
739 // Socket might die because of SendPacket, so check
740 m_client->SetSentCancelTransfer(1);
742 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
744 break;
747 case OP_OUTOFPARTREQS: { // 0.43b
748 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client->GetFullIP() );
750 theStats::AddDownOverheadFileRequest(size);
751 if (m_client->GetDownloadState() == DS_DOWNLOADING) {
752 m_client->SetDownloadState(DS_ONQUEUE);
754 break;
757 case OP_CHANGE_CLIENT_ID: { // Kad reviewed
758 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client->GetFullIP() );
760 theStats::AddDownOverheadOther(size);
761 CMemFile data(buffer, size);
762 uint32 nNewUserID = data.ReadUInt32();
763 uint32 nNewServerIP = data.ReadUInt32();
765 if (IsLowID(nNewUserID)) { // client changed server and gots a LowID
766 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
767 if (pNewServer != NULL){
768 m_client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
769 m_client->SetServerIP(nNewServerIP);
770 m_client->SetServerPort(pNewServer->GetPort());
772 } else if (nNewUserID == m_client->GetIP()) { // client changed server and gots a HighID(IP)
773 m_client->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID));
774 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
775 if (pNewServer != NULL){
776 m_client->SetServerIP(nNewServerIP);
777 m_client->SetServerPort(pNewServer->GetPort());
781 break;
784 case OP_CHANGE_SLOT:{ // 0.43b
785 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client->GetFullIP() );
787 // sometimes sent by Hybrid
788 theStats::AddDownOverheadOther(size);
789 break;
792 case OP_MESSAGE: { // 0.43b
793 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MESSAGE from ") + m_client->GetFullIP() );
795 theStats::AddDownOverheadOther(size);
797 if (size < 2) {
798 throw wxString(wxT("invalid message packet"));
800 CMemFile message_file(buffer, size);
801 uint16 length = message_file.ReadUInt16();
802 if (length + 2u != size) {
803 throw wxString(wxT("invalid message packet"));
806 // limit message length
807 static const uint16 MAX_CLIENT_MSG_LEN = 450;
809 if (length > MAX_CLIENT_MSG_LEN) {
810 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
811 % m_client->GetUserName() % m_client->GetFullIP() % (length - MAX_CLIENT_MSG_LEN));
812 length = MAX_CLIENT_MSG_LEN;
815 wxString message = message_file.ReadOnlyString((m_client->GetUnicodeSupport() != utf8strNone), length);
816 m_client->ProcessChatMessage(message);
818 break;
821 case OP_ASKSHAREDFILES: { // 0.43b (well, er, it does the same, but in our own way)
822 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
824 // client wants to know what we have in share, let's see if we allow him to know that
825 theStats::AddDownOverheadOther(size);
826 // IP banned, no answer for this request
827 if (m_client->IsBanned()) {
828 break;
831 if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
832 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
833 % m_client->GetUserName()
834 % m_client->GetUserIDHybrid() );
836 std::vector<CKnownFile*> list;
837 theApp->sharedfiles->CopyFileList(list);
839 CMemFile tempfile(80);
840 tempfile.WriteUInt32(list.size());
841 for (unsigned i = 0; i < list.size(); ++i) {
842 if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
843 list[i]->CreateOfferedFilePacket(&tempfile, NULL, m_client);
847 // create a packet and send it
848 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
849 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
850 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
851 SendPacket(replypacket, true, true);
852 } else {
853 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
854 % m_client->GetUserName()
855 % m_client->GetUserIDHybrid() );
857 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
858 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
859 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
860 SendPacket(replypacket, true, true);
863 break;
866 case OP_ASKSHAREDFILESANSWER: { // 0.43b
867 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
869 theStats::AddDownOverheadOther(size);
870 wxString EmptyStr;
871 m_client->ProcessSharedFileList(buffer, size, EmptyStr);
872 break;
875 case OP_ASKSHAREDDIRS: { // 0.43b
876 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
878 theStats::AddDownOverheadOther(size);
879 wxASSERT( size == 0 );
880 // IP banned, no answer for this request
881 if (m_client->IsBanned()) {
882 break;
884 if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
885 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
886 % m_client->GetUserName()
887 % m_client->GetUserIDHybrid() );
888 // send the list of shared directories
889 m_client->SendSharedDirectories();
890 } else {
891 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
892 % m_client->GetUserName()
893 % m_client->GetUserIDHybrid() );
895 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
896 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
897 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
898 SendPacket(replypacket, true, true);
901 break;
904 case OP_ASKSHAREDFILESDIR: { // 0.43b
905 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
907 theStats::AddDownOverheadOther(size);
908 // IP banned, no answer for this request
909 if (m_client->IsBanned()) {
910 break;
912 CMemFile data(buffer, size);
914 wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
915 if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
916 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory '%s' -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
917 wxASSERT( data.GetPosition() == data.GetLength() );
918 // send the list of shared files for the requested directory
919 m_client->SendSharedFilesOfDirectory(strReqDir);
920 } else {
921 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory '%s' -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
923 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
924 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
925 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
926 SendPacket(replypacket, true, true);
928 break;
931 case OP_ASKSHAREDDIRSANS:{ // 0.43b
932 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
934 theStats::AddDownOverheadOther(size);
935 if (m_client->GetFileListRequested() == 1){
936 CMemFile data(buffer, size);
937 uint32 uDirs = data.ReadUInt32();
938 for (uint32 i = 0; i < uDirs; i++){
939 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
940 AddLogLineC(CFormat( _("User %s (%u) shares directory '%s'") )
941 % m_client->GetUserName()
942 % m_client->GetUserIDHybrid()
943 % strDir );
945 CMemFile tempfile(80);
946 tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
947 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
948 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
949 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIR to ") + m_client->GetFullIP() );
950 SendPacket(replypacket, true, true);
952 wxASSERT( data.GetPosition() == data.GetLength() );
953 m_client->SetFileListRequested(uDirs);
954 } else {
955 AddLogLineC(CFormat( _("User %s (%u) sent unrequested shared dirs.") )
956 % m_client->GetUserName()
957 % m_client->GetUserIDHybrid() );
959 break;
962 case OP_ASKSHAREDFILESDIRANS: { // 0.43b
963 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
965 theStats::AddDownOverheadOther(size);
966 CMemFile data(buffer, size);
967 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
969 if (m_client->GetFileListRequested() > 0){
970 AddLogLineC(CFormat( _("User %s (%u) sent sharedfiles-list for directory '%s'") )
971 % m_client->GetUserName()
972 % m_client->GetUserIDHybrid()
973 % strDir );
975 m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
976 if (m_client->GetFileListRequested() == 0) {
977 AddLogLineC(CFormat( _("User %s (%u) finished sending sharedfiles-list") )
978 % m_client->GetUserName()
979 % m_client->GetUserIDHybrid() );
981 } else {
982 AddLogLineC(CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
983 % m_client->GetUserName()
984 % m_client->GetUserIDHybrid() );
986 break;
989 case OP_ASKSHAREDDENIEDANS:
990 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
992 theStats::AddDownOverheadOther(size);
993 wxASSERT( size == 0 );
994 AddLogLineC(CFormat( _("User %s (%u) denied access to shared directories/files list") )
995 % m_client->GetUserName()
996 % m_client->GetUserIDHybrid() );
998 m_client->SetFileListRequested(0);
999 break;
1001 default:
1002 theStats::AddDownOverheadOther(size);
1003 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Edonkey packet: unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1004 return false;
1007 return true;
1011 bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1013 #ifdef __PACKET_RECV_DUMP__
1014 //printf("Rec: OPCODE %x \n",opcode);
1015 DumpMem(buffer,size);
1016 #endif
1018 // 0.42e - except the catchs on mem exception and file exception
1019 if (!m_client) {
1020 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1023 if (!client->CheckHandshakeFinished()) {
1024 // Here comes an extended packet without finishing the handshake.
1025 // IMHO, we should disconnect the client.
1026 throw wxString(wxT("Client send extended packet before finishing handshake"));
1029 switch(opcode) {
1030 case OP_MULTIPACKET_EXT:
1031 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1032 case OP_MULTIPACKET: {
1033 if (opcode == OP_MULTIPACKET) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1035 theStats::AddDownOverheadFileRequest(size);
1037 if (m_client->IsBanned()) {
1038 break;
1041 if (!m_client->CheckHandshakeFinished()) {
1042 // Here comes an extended packet without finishing the handshake.
1043 // IMHO, we should disconnect the client.
1044 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1047 CMemFile data_in(buffer, size);
1048 CMD4Hash reqfilehash = data_in.ReadHash();
1049 uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1051 bool file_not_found = false;
1052 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1053 if ( reqfile == NULL ){
1054 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1055 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1056 AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a non-shared file"));
1057 file_not_found = true;
1061 if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1062 AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1063 file_not_found = true;
1066 if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1067 AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1068 file_not_found = true;
1071 if (file_not_found) {
1072 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1073 replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1074 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1075 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1076 SendPacket(replypacket, true);
1077 break;
1080 if (!m_client->GetWaitStartTime()) {
1081 m_client->SetWaitStartTime();
1083 // if we are downloading this file, this could be a new source
1084 // no passive adding of files with only one part
1085 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1086 if (thePrefs::GetMaxSourcePerFile() > static_cast<CPartFile*>(reqfile)->GetSourceCount()) {
1087 theApp->downloadqueue->CheckAndAddKnownSource(static_cast<CPartFile*>(reqfile), m_client);
1090 // check to see if this is a new file they are asking for
1091 if (m_client->GetUploadFileID() != reqfilehash) {
1092 m_client->SetCommentDirty();
1094 m_client->SetUploadFileID(reqfile);
1095 CMemFile data_out(128);
1096 data_out.WriteHash(reqfile->GetFileHash());
1097 while(data_in.GetLength()-data_in.GetPosition()) {
1098 if (!m_client) {
1099 throw wxString(wxT("Client suddenly disconnected"));
1101 uint8 opcode_in = data_in.ReadUInt8();
1102 switch(opcode_in) {
1103 case OP_REQUESTFILENAME: {
1104 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1105 m_client->ProcessExtendedInfo(&data_in, reqfile);
1106 data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1108 // Since it's for somebody else to see, we need to send the prettified
1109 // filename, rather than the (possibly) mangled actual filename
1110 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1111 break;
1113 case OP_AICHFILEHASHREQ: {
1114 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1115 if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1116 && reqfile->GetAICHHashset()->HasValidMasterHash())
1118 data_out.WriteUInt8(OP_AICHFILEHASHANS);
1119 reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1121 break;
1123 case OP_SETREQFILEID: {
1124 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1125 data_out.WriteUInt8(OP_FILESTATUS);
1126 if (reqfile->IsPartFile()) {
1127 static_cast<CPartFile*>(reqfile)->WritePartStatus(&data_out);
1128 } else {
1129 data_out.WriteUInt16(0);
1131 break;
1133 //We still send the source packet separately..
1134 //We could send it within this packet.. If agreeded, I will fix it..
1135 case OP_REQUESTSOURCES2:
1136 case OP_REQUESTSOURCES: {
1137 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1138 uint8 byRequestedVersion = 0;
1139 uint16 byRequestedOptions = 0;
1140 if (opcode_in == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1141 byRequestedVersion = data_in.ReadUInt8();
1142 byRequestedOptions = data_in.ReadUInt16();
1145 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1147 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1148 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1149 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1151 //if not complete and file is rare
1152 ( reqfile->IsPartFile()
1153 && (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1154 && static_cast<CPartFile*>(reqfile)->GetSourceCount() <= RARE_FILE
1155 ) ||
1156 //OR if file is not rare or if file is complete
1157 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1160 m_client->SetLastSrcReqTime();
1161 CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1162 if(tosend) {
1163 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1164 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1165 SendPacket(tosend, true);
1169 break;
1174 if( data_out.GetLength() > 16 ) {
1175 CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1176 theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1177 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1178 SendPacket(reply, true);
1180 break;
1183 case OP_MULTIPACKETANSWER: { // 0.43b
1184 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1186 theStats::AddDownOverheadFileRequest(size);
1188 if (m_client->IsBanned()) {
1189 break;
1192 if (m_client->GetKadPort() && m_client->GetKadVersion() > 1) {
1193 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort());
1196 if (!m_client->CheckHandshakeFinished()) {
1197 // Here comes an extended packet without finishing the handshake.
1198 // IMHO, we should disconnect the client.
1199 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1202 CMemFile data_in(buffer, size);
1203 CMD4Hash reqfilehash = data_in.ReadHash();
1204 const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1205 //Make sure we are downloading this file.
1206 if ( !reqfile ) {
1207 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1209 if ( !m_client->GetRequestFile() ) {
1211 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1213 if (reqfile != m_client->GetRequestFile()) {
1214 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1216 while (data_in.GetLength()-data_in.GetPosition()) {
1217 // Some of the cases down there can actually send a packet and lose the client
1218 if (!m_client) {
1219 throw wxString(wxT("Client suddenly disconnected"));
1221 uint8 opcode_in = data_in.ReadUInt8();
1222 switch(opcode_in) {
1223 case OP_REQFILENAMEANSWER: {
1224 if (!m_client) {
1225 throw wxString(wxT("Client suddenly disconnected"));
1226 } else {
1227 m_client->ProcessFileInfo(&data_in, reqfile);
1229 break;
1231 case OP_FILESTATUS: {
1232 if (!m_client) {
1233 throw wxString(wxT("Client suddenly disconnected"));
1234 } else {
1235 m_client->ProcessFileStatus(false, &data_in, reqfile);
1237 break;
1239 case OP_AICHFILEHASHANS: {
1240 if (!m_client) {
1241 throw wxString(wxT("Client suddenly disconnected"));
1242 } else {
1243 m_client->ProcessAICHFileHash(&data_in, reqfile);
1245 break;
1250 break;
1253 case OP_EMULEINFO: { // 0.43b
1254 theStats::AddDownOverheadOther(size);
1256 if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1257 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1259 // If it's not a OS Info packet, is an old client
1260 // start secure identification, if
1261 // - we have received eD2K and eMule info (old eMule)
1262 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1263 m_client->InfoPacketsReceived();
1265 m_client->SendMuleInfoPacket(true);
1266 } else {
1267 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1269 break;
1271 case OP_EMULEINFOANSWER: { // 0.43b
1272 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1273 theStats::AddDownOverheadOther(size);
1275 m_client->ProcessMuleInfoPacket(buffer, size);
1276 // start secure identification, if
1277 // - we have received eD2K and eMule info (old eMule)
1279 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1280 m_client->InfoPacketsReceived();
1283 break;
1286 case OP_SECIDENTSTATE:{ // 0.43b
1287 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1289 if (!m_client->CheckHandshakeFinished()) {
1290 // Here comes an extended packet without finishing the handshake.
1291 // IMHO, we should disconnect the client.
1292 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1294 m_client->ProcessSecIdentStatePacket(buffer, size);
1295 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1296 if (m_client) {
1297 int SecureIdentState = m_client->GetSecureIdentState();
1298 if (SecureIdentState == IS_SIGNATURENEEDED) {
1299 m_client->SendSignaturePacket();
1300 } else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1301 m_client->SendPublicKeyPacket();
1302 // SendPublicKeyPacket() might cause the socket to die, so check
1303 if ( m_client ) {
1304 m_client->SendSignaturePacket();
1308 break;
1311 case OP_PUBLICKEY: { // 0.43b
1312 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1314 if (m_client->IsBanned() ){
1315 break;
1318 if (!m_client->CheckHandshakeFinished()) {
1319 // Here comes an extended packet without finishing the handshake.
1320 // IMHO, we should disconnect the client.
1321 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1324 m_client->ProcessPublicKeyPacket(buffer, size);
1325 break;
1327 case OP_SIGNATURE:{ // 0.43b
1328 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1330 if (!m_client->CheckHandshakeFinished()) {
1331 // Here comes an extended packet without finishing the handshake.
1332 // IMHO, we should disconnect the client.
1333 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1336 m_client->ProcessSignaturePacket(buffer, size);
1337 break;
1339 case OP_SENDINGPART_I64:
1340 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1341 case OP_COMPRESSEDPART_I64:
1342 if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1343 case OP_COMPRESSEDPART: { // 0.47a
1344 if (opcode == OP_COMPRESSEDPART) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1346 if (!m_client->CheckHandshakeFinished()) {
1347 // Here comes an extended packet without finishing the handshake.
1348 // IMHO, we should disconnect the client.
1349 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1352 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1354 m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1356 if (m_client && (
1357 m_client->GetRequestFile()->IsStopped() ||
1358 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1359 m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1360 if (!m_client->GetSentCancelTransfer()) {
1361 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1362 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1363 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1364 m_client->SendPacket(packet,true,true);
1366 if (m_client) {
1367 m_client->SetSentCancelTransfer(1);
1371 if ( m_client ) {
1372 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1375 } else {
1376 if (!m_client->GetSentCancelTransfer()) {
1377 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1378 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1379 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1380 m_client->SendPacket(packet,true,true);
1382 if ( m_client ) {
1383 m_client->SetSentCancelTransfer(1);
1387 if ( m_client ) {
1388 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1391 break;
1393 case OP_REQUESTPARTS_I64: {
1394 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP() );
1396 theStats::AddDownOverheadFileRequest(size);
1398 m_client->ProcessRequestPartsPacket(buffer, size, true);
1400 break;
1402 case OP_QUEUERANKING: { // 0.43b
1403 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP() );
1405 theStats::AddDownOverheadOther(size);
1407 if (!m_client->CheckHandshakeFinished()) {
1408 // Here comes an extended packet without finishing the handshake.
1409 // IMHO, we should disconnect the client.
1410 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1413 if (size != 12) {
1414 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1417 uint16 newrank = PeekUInt16(buffer);
1418 m_client->SetRemoteQueueFull(false);
1419 m_client->SetRemoteQueueRank(newrank);
1420 break;
1422 case OP_REQUESTSOURCES2:
1423 case OP_REQUESTSOURCES:{
1424 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP() );
1426 theStats::AddDownOverheadSourceExchange(size);
1428 if (!m_client->CheckHandshakeFinished()) {
1429 // Here comes an extended packet without finishing the handshake.
1430 // IMHO, we should disconnect the client.
1431 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1434 uint8 byRequestedVersion = 0;
1435 uint16 byRequestedOptions = 0;
1436 CMemFile data_in(buffer, size);
1437 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1438 byRequestedVersion = data_in.ReadUInt8();
1439 byRequestedOptions = data_in.ReadUInt16();
1442 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1443 if(size != 16) {
1444 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1446 //first check shared file list, then download list
1447 const CMD4Hash fileID(buffer);
1448 CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1449 if(!file) {
1450 file = theApp->downloadqueue->GetFileByID(fileID);
1452 if(file) {
1453 // There are some clients which do not follow the correct protocol procedure of sending
1454 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1455 // are doing this, they will not get the optimal set of sources which we could offer if
1456 // they would follow the above noted protocol sequence. They better do it the right way
1457 // or they will get just a random set of sources because we do not know their download
1458 // part status which may get cleared with the call of 'SetUploadFileID'.
1459 m_client->SetUploadFileID(file);
1461 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1462 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1464 //if not complete and file is rare, allow once every 40 minutes
1465 ( file->IsPartFile() &&
1466 static_cast<CPartFile*>(file)->GetSourceCount() <= RARE_FILE &&
1467 (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1468 ) ||
1469 //OR if file is not rare or if file is complete, allow every 90 minutes
1470 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1473 m_client->SetLastSrcReqTime();
1474 CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1475 if(tosend) {
1476 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1477 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1478 SendPacket(tosend, true, true);
1483 break;
1485 case OP_ANSWERSOURCES: {
1486 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP() );
1488 theStats::AddDownOverheadSourceExchange(size);
1490 if (!m_client->CheckHandshakeFinished()) {
1491 // Here comes an extended packet without finishing the handshake.
1492 // IMHO, we should disconnect the client.
1493 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1496 CMemFile data(buffer, size);
1497 CMD4Hash hash = data.ReadHash();
1498 CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1499 if(file){
1500 if (file->IsPartFile()){
1501 //set the client's answer time
1502 m_client->SetLastSrcAnswerTime();
1503 //and set the file's last answer time
1504 static_cast<CPartFile*>(file)->SetLastAnsweredTime();
1505 static_cast<CPartFile*>(file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1508 break;
1510 case OP_ANSWERSOURCES2: {
1511 //printf("Received OP_ANSWERSOURCES2\n");
1512 theStats::AddDownOverheadSourceExchange(size);
1514 if (!m_client->CheckHandshakeFinished()) {
1515 // Here comes an extended packet without finishing the handshake.
1516 // IMHO, we should disconnect the client.
1517 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1520 CMemFile data(buffer, size);
1521 uint8 byVersion = data.ReadUInt8();
1522 CMD4Hash hash = data.ReadHash();
1523 CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1524 if (file){
1525 if (file->IsPartFile()){
1526 //set the client's answer time
1527 m_client->SetLastSrcAnswerTime();
1528 //and set the file's last answer time
1529 static_cast<CPartFile*>(file)->SetLastAnsweredTime();
1530 static_cast<CPartFile*>(file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1533 break;
1535 case OP_FILEDESC: { // 0.43b
1536 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP() );
1538 theStats::AddDownOverheadFileRequest(size);
1540 if (!m_client->CheckHandshakeFinished()) {
1541 // Here comes an extended packet without finishing the handshake.
1542 // IMHO, we should disconnect the client.
1543 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1546 m_client->ProcessMuleCommentPacket(buffer, size);
1547 break;
1550 // Unsupported
1551 case OP_REQUESTPREVIEW: {
1552 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client->GetFullIP() );
1553 break;
1555 // Unsupported
1556 case OP_PREVIEWANSWER: {
1557 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP() );
1558 break;
1561 case OP_PUBLICIP_ANSWER: {
1562 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP() );
1563 theStats::AddDownOverheadOther(size);
1564 m_client->ProcessPublicIPAnswer(buffer, size);
1565 break;
1567 case OP_PUBLICIP_REQ: {
1568 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP() );
1569 theStats::AddDownOverheadOther(size);
1570 CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1571 pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1572 theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1573 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1574 SendPacket(pPacket);
1575 break;
1577 case OP_AICHANSWER: {
1578 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP() );
1579 theStats::AddDownOverheadOther(size);
1580 m_client->ProcessAICHAnswer(buffer, size);
1581 break;
1583 case OP_AICHREQUEST: {
1584 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP() );
1585 theStats::AddDownOverheadOther(size);
1586 m_client->ProcessAICHRequest(buffer, size);
1587 break;
1589 case OP_AICHFILEHASHANS: {
1590 // those should not be received normally, since we should only get those in MULTIPACKET
1591 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP() );
1592 theStats::AddDownOverheadOther(size);
1593 CMemFile data(buffer, size);
1594 m_client->ProcessAICHFileHash(&data, NULL);
1595 break;
1597 case OP_AICHFILEHASHREQ: {
1598 // those should not be received normally, since we should only get those in MULTIPACKET
1599 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP() );
1600 CMemFile data(buffer, size);
1601 CMD4Hash hash = data.ReadHash();
1602 CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1603 if (pPartFile == NULL){
1604 break;
1607 if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1608 && pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1609 CMemFile data_out;
1610 data_out.WriteHash(hash);
1611 pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1612 CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1613 theStats::AddUpOverheadOther(packet->GetPacketSize());
1614 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1615 SendPacket(packet);
1617 break;
1619 case OP_CALLBACK: {
1620 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1621 theStats::AddDownOverheadFileRequest(size);
1622 if(!Kademlia::CKademlia::IsRunning()) {
1623 break;
1625 CMemFile data(buffer, size);
1626 CUInt128 check = data.ReadUInt128();
1627 check ^= Kademlia::CUInt128(true);
1628 if (check != Kademlia::CKademlia::GetPrefs()->GetKadID()) {
1629 break;
1631 CUInt128 fileid = data.ReadUInt128();
1632 byte fileid2[16];
1633 fileid.ToByteArray(fileid2);
1634 const CMD4Hash fileHash(fileid2);
1635 if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1636 if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1637 break;
1641 uint32 ip = data.ReadUInt32();
1642 uint16 tcp = data.ReadUInt16();
1643 CUpDownClient* callback;
1644 callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1645 if( callback == NULL ) {
1646 //#warning Do we actually have to check friend status here?
1647 callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1648 theApp->clientlist->AddClient(callback);
1650 callback->TryToConnect(true);
1651 break;
1654 case OP_BUDDYPING: {
1655 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP() );
1656 theStats::AddDownOverheadKad(size);
1658 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1659 if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1660 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1661 break;
1664 m_client->SetLastBuddyPingPongTime();
1665 CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1666 theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1667 AddDebugLogLineN(logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1668 SendPacket(replypacket);
1669 break;
1671 case OP_BUDDYPONG: {
1672 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP() );
1673 theStats::AddDownOverheadKad(size);
1675 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1676 if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1677 //This pong was not from our buddy or wrong version. Ignore
1678 break;
1680 m_client->SetLastBuddyPingPongTime();
1681 //All this is for is to reset our socket timeout.
1682 break;
1684 case OP_REASKCALLBACKTCP: {
1685 theStats::AddDownOverheadFileRequest(size);
1686 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1687 if (buddy != m_client) {
1688 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1689 //This callback was not from our buddy.. Ignore.
1690 break;
1692 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1693 CMemFile data_in(buffer, size);
1694 uint32 destip = data_in.ReadUInt32();
1695 uint16 destport = data_in.ReadUInt16();
1696 CMD4Hash hash = data_in.ReadHash();
1697 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1699 bool bSenderMultipleIpUnknown = false;
1700 CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1701 if (!reqfile) {
1702 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1703 CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1704 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1705 if (sender) {
1706 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1707 } else {
1708 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1710 break;
1713 if (sender) {
1714 //Make sure we are still thinking about the same file
1715 if (hash == sender->GetUploadFileID()) {
1716 sender->AddAskedCount();
1717 sender->SetLastUpRequest();
1718 //I messed up when I first added extended info to UDP
1719 //I should have originally used the entire ProcessExtenedInfo the first time.
1720 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1721 //For now on, we should not have to change anything here if we change
1722 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1723 //Update extended info.
1724 if (sender->GetUDPVersion() > 3) {
1725 sender->ProcessExtendedInfo(&data_in, reqfile);
1726 } else if (sender->GetUDPVersion() > 2) {
1727 //Update our complete source counts.
1728 uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1729 uint16 nCompleteCountNew = data_in.ReadUInt16();
1730 sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1731 if (nCompleteCountLast != nCompleteCountNew) {
1732 reqfile->UpdatePartsInfo();
1736 CMemFile data_out(128);
1737 if(sender->GetUDPVersion() > 3) {
1738 if (reqfile->IsPartFile()) {
1739 static_cast<CPartFile*>(reqfile)->WritePartStatus(&data_out);
1740 } else {
1741 data_out.WriteUInt16(0);
1745 data_out.WriteUInt16(sender->GetUploadQueueWaitingPosition());
1746 CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1747 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1748 AddDebugLogLineN( logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP() );
1749 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1750 } else {
1751 AddDebugLogLineN(logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1753 } else {
1754 if (!bSenderMultipleIpUnknown){
1755 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1756 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP() );
1757 CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1758 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1759 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1761 } else {
1762 AddDebugLogLineN(logRemoteClient, CFormat(wxT("OP_REASKCALLBACKTCP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u")) % Uint32toStringIP(destip) % destport);
1765 break;
1767 case OP_CHATCAPTCHAREQ:
1769 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client->GetFullIP());
1770 theStats::AddDownOverheadOther(size);
1771 CMemFile data_in(buffer, size);
1772 m_client->ProcessCaptchaRequest(&data_in);
1773 break;
1775 case OP_CHATCAPTCHARES:
1777 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client->GetFullIP());
1778 theStats::AddDownOverheadOther(size);
1779 if (size) {
1780 m_client->ProcessCaptchaReqRes(buffer[0]);
1782 break;
1784 case OP_FWCHECKUDPREQ: { // Support required for Kadversion >= 6
1785 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client->GetFullIP());
1786 theStats::AddDownOverheadOther(size);
1787 CMemFile data_in(buffer, size);
1788 m_client->ProcessFirewallCheckUDPRequest(&data_in);
1789 break;
1791 case OP_KAD_FWTCPCHECK_ACK: { // Support required for Kadversion >= 7
1792 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client->GetFullIP());
1793 if (theApp->clientlist->IsKadFirewallCheckIP(m_client->GetIP())) {
1794 if (Kademlia::CKademlia::IsRunning()) {
1795 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1797 } else {
1798 AddDebugLogLineN(logListenSocket, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client->GetFullIP());
1800 break;
1802 default:
1803 theStats::AddDownOverheadOther(size);
1804 AddDebugLogLineN(logRemoteClient, CFormat(wxT("eMule packet : unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1805 break;
1808 return true;
1811 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1813 #ifdef __PACKET_RECV_DUMP__
1814 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1815 DumpMem(buffer,size);
1816 #endif
1818 if (!m_client) {
1819 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1822 CMemFile data(buffer, size);
1823 try {
1824 switch(opcode) {
1825 case OP_QUEUERANK: {
1826 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1828 uint8 numtags = data.ReadUInt8();
1829 wxASSERT(numtags == 1);
1830 if(numtags){} // prevent GCC warning
1832 m_client->SetRemoteQueueRank(data.GetIntTagValue());
1834 theStats::AddDownOverheadFileRequest(size);
1835 break;
1838 case OP_REQUESTPARTS: {
1839 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1841 m_client->ProcessRequestPartsPacketv2(data);
1843 theStats::AddDownOverheadFileRequest(size);
1844 break;
1847 default:
1848 theStats::AddDownOverheadOther(size);
1849 AddDebugLogLineN(logRemoteClient, CFormat(wxT("ED2Kv2 packet : unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1851 } catch (...) {
1852 AddDebugLogLineN(logRemoteClient, CFormat(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from %s")) % data.GetPosition() % opcode % opcode % m_client->GetFullIP());
1853 throw;
1856 return true;
1859 void CClientTCPSocket::OnConnect(int nErrorCode)
1861 if (nErrorCode) {
1862 OnError(nErrorCode);
1863 } else if (!m_client) {
1864 // and now? Disconnect? not?
1865 AddDebugLogLineN( logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1866 } else if (!m_client->SendHelloPacket()) {
1867 // and now? Disconnect? not?
1868 AddDebugLogLineN( logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1869 } else {
1870 ResetTimeOutTimer();
1875 void CClientTCPSocket::OnSend(int nErrorCode)
1877 ResetTimeOutTimer();
1878 CEMSocket::OnSend(nErrorCode);
1882 void CClientTCPSocket::OnReceive(int nErrorCode)
1884 ResetTimeOutTimer();
1885 // We might have updated ipfilter
1886 wxASSERT(m_remoteip);
1888 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1889 if (m_client) {
1890 m_client->Safe_Delete();
1892 Safe_Delete();
1893 AddDebugLogLineN( logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1894 } else {
1895 CEMSocket::OnReceive(nErrorCode);
1900 void CClientTCPSocket::OnError(int nErrorCode)
1902 //printf("* Called OnError for %p\n",this);
1903 // 0.42e + Kry changes for handling of socket lost events
1904 wxString strError;
1906 if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1907 if (m_client) {
1908 if (!m_client->GetUserName().IsEmpty()) {
1909 strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1910 } else {
1911 strError = wxT("An unnamed client");
1913 strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1914 } else {
1915 strError = wxT("A client ");
1917 if (nErrorCode == 0) {
1918 strError += wxT("closed connection.");
1919 } else if (nErrorCode == 0xFEFF) {
1920 strError += wxT(" caused a wxSOCKET_LOST event.");
1921 } else {
1922 strError += wxT("caused a socket blocking error.");
1924 } else {
1925 if (theLogger.IsEnabled(logClient) && nErrorCode != 107) {
1926 // 0 -> No Error / Disconect
1927 // 107 -> Transport endpoint is not connected
1928 if (m_client) {
1929 if (!m_client->GetUserName().IsEmpty()) {
1930 strError = CFormat(wxT("OnError: Client '%s' (IP:%s) caused an error: %u. Disconnecting client!"))
1931 % m_client->GetUserName() % m_client->GetFullIP() % nErrorCode;
1932 } else {
1933 strError = CFormat(wxT("OnError: Unknown client (IP:%s) caused an error: %u. Disconnecting client!"))
1934 % m_client->GetFullIP() % nErrorCode;
1936 } else {
1937 strError = CFormat(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"))
1938 % nErrorCode;
1940 } else {
1941 strError = wxT("Error 107 (Transport endpoint is not connected)");
1945 Disconnect(strError);
1949 bool CClientTCPSocket::PacketReceived(CPacket* packet)
1951 // 0.42e
1952 bool bResult = false;
1953 uint32 uRawSize = packet->GetPacketSize();
1955 AddDebugLogLineN( logRemoteClient,
1956 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1957 % packet->GetProtocol()
1958 % packet->GetOpCode()
1959 % packet->GetPacketSize()
1960 % ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
1963 wxString exception;
1965 try {
1966 bool process = true;
1968 if ((packet->GetProtocol() == OP_PACKEDPROT) ||
1969 (packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
1971 if (!packet->UnPackPacket()) {
1972 AddDebugLogLineN(logZLib, wxT("Failed to decompress client TCP packet."));
1973 bResult = false;
1974 process = false;
1975 } else {
1976 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"))
1977 % packet->GetProtocol() % packet->GetOpCode() % packet->GetPacketSize());
1981 if (process) {
1982 switch (packet->GetProtocol()) {
1983 case OP_EDONKEYPROT:
1984 bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
1985 break;
1986 case OP_EMULEPROT:
1987 bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
1988 break;
1989 case OP_ED2KV2HEADER:
1990 bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
1991 break;
1992 case OP_ED2KV2PACKEDPROT:
1993 case OP_PACKEDPROT:
1994 // Packed inside packed?
1995 wxFAIL;
1996 break;
1997 default: {
1998 theStats::AddDownOverheadOther(uRawSize);
1999 if (m_client) {
2000 m_client->SetDownloadState(DS_ERROR);
2002 Disconnect(wxT("Unknown protocol"));
2003 bResult = false;
2007 } catch (const CEOFException& err) {
2008 exception = wxT("EOF exception: ") + err.what();
2009 } catch (const CInvalidPacket& err) {
2010 exception = wxT("InvalidPacket exception: ") + err.what();
2011 } catch (const wxString& error) {
2012 exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2015 if (!exception.IsEmpty()) {
2016 AddDebugLogLineN( logPacketErrors,
2017 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2018 % exception
2019 % packet->GetProtocol()
2020 % packet->GetOpCode()
2021 % packet->GetPacketSize()
2022 % ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2025 if (m_client) {
2026 m_client->SetDownloadState(DS_ERROR);
2029 AddDebugLogLineN( logClient,
2030 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2031 % ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2032 % ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2033 % exception
2036 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2039 return bResult;
2043 SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2045 SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2047 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2048 ResetTimeOutTimer();
2051 return returnStatus;
2055 SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2057 SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2059 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2060 ResetTimeOutTimer();
2063 return returnStatus;
2067 void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2069 ResetTimeOutTimer();
2070 CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2072 // File_checked_for_headers