Improve speed of category tab title updates
[amule.git] / src / ClientTCPSocket.cpp
blob8fcf2a71d4fee2619058f6b4be1084d6ca240652
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 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->OnDestroy() || socket->ForDeletion()) {
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->Error() ? socket->LastError() : 0);
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();
138 m_ForDeletion = false;
140 SetEventHandler(g_clientReqSocketHandler, ID_CLIENTTCPSOCKET_EVENT);
141 SetNotify(
142 wxSOCKET_CONNECTION_FLAG |
143 wxSOCKET_INPUT_FLAG |
144 wxSOCKET_OUTPUT_FLAG |
145 wxSOCKET_LOST_FLAG);
146 Notify(true);
148 theApp->listensocket->AddSocket(this);
149 theApp->listensocket->AddConnection();
152 CClientTCPSocket::~CClientTCPSocket()
154 // remove event handler
155 SetNotify(0);
156 Notify(false);
158 if (m_client) {
159 m_client->SetSocket( NULL );
161 m_client = NULL;
163 if (theApp->listensocket && !theApp->listensocket->OnShutdown()) {
164 theApp->listensocket->RemoveSocket(this);
168 bool CClientTCPSocket::InitNetworkData()
170 wxASSERT(!m_remoteip);
171 wxASSERT(!m_client);
172 amuleIPV4Address addr;
173 GetPeer(addr);
174 m_remoteip = StringIPtoUint32(addr.IPAddress());
176 MULE_CHECK(m_remoteip, false);
178 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
179 AddDebugLogLineN(logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Filtered IP)"));
180 return false;
181 } else if (theApp->clientlist->IsBannedClient(m_remoteip)) {
182 AddDebugLogLineN(logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Banned IP)"));
183 return false;
184 } else {
185 AddDebugLogLineN(logClient, wxT("Accepted connection from ") + addr.IPAddress());
186 return true;
190 void CClientTCPSocket::ResetTimeOutTimer()
192 timeout_timer = ::GetTickCount();
196 bool CClientTCPSocket::CheckTimeOut()
198 // 0.42x
199 uint32 uTimeout = GetTimeOut();
200 if (m_client) {
202 if (m_client->GetKadState() == KS_CONNECTED_BUDDY) {
203 //We originally ignored the timeout here for buddies.
204 //This was a stupid idea on my part. There is now a ping/pong system
205 //for buddies. This ping/pong system now prevents timeouts.
206 //This release will allow lowID clients with KadVersion 0 to remain connected.
207 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
208 //JOHNTODO: Don't forget to remove backward support in a future release.
209 if ( m_client->GetKadVersion() == 0 ) {
210 return false;
213 uTimeout += MIN2MS(15);
216 if (m_client->GetChatState() != MS_NONE) {
217 uTimeout += CONNECTION_TIMEOUT;
221 if (::GetTickCount() - timeout_timer > uTimeout){
222 timeout_timer = ::GetTickCount();
223 Disconnect(wxT("Timeout"));
224 return true;
227 return false;
231 void CClientTCPSocket::SetClient(CUpDownClient* pClient)
233 m_client = pClient;
234 if (m_client) {
235 m_client->SetSocket( this );
240 void CClientTCPSocket::OnClose(int nErrorCode)
242 // 0.42x
243 wxASSERT(theApp->listensocket->IsValidSocket(this));
244 CEMSocket::OnClose(nErrorCode);
245 if (nErrorCode) {
246 Disconnect(CFormat(wxT("Closed: %u")) % nErrorCode);
247 } else {
248 Disconnect(wxT("Close"));
253 void CClientTCPSocket::Disconnect(const wxString& strReason)
255 byConnected = ES_DISCONNECTED;
256 if (m_client) {
257 if (m_client->Disconnected(strReason, true)) {
258 // Somehow, Safe_Delete() is beeing called by Disconnected(),
259 // or any other function that sets m_client to NULL,
260 // so we must check m_client first.
261 if (m_client) {
262 m_client->SetSocket( NULL );
263 m_client->Safe_Delete();
266 m_client = NULL;
269 Safe_Delete();
273 void CClientTCPSocket::Safe_Delete()
275 // More paranoia - make sure client is unlinked in any case
276 if (m_client) {
277 m_client->SetSocket( NULL );
278 m_client = NULL;
281 if ( !ForDeletion() && !OnDestroy() ) {
282 // Paranoia is back.
283 SetNotify(0);
284 Notify(false);
285 // lfroen: first of all - stop handler
286 m_ForDeletion = true;
288 byConnected = ES_DISCONNECTED;
289 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
290 Destroy();
295 void CClientTCPSocket::Safe_Delete_Client()
297 if (m_client) {
298 m_client->Safe_Delete();
299 m_client = NULL;
304 bool CClientTCPSocket::ProcessPacket(const byte* buffer, uint32 size, uint8 opcode)
306 #ifdef __PACKET_RECV_DUMP__
307 //printf("Rec: OPCODE %x \n",opcode);
308 DumpMem(buffer, size);
309 #endif
310 if (!m_client && opcode != OP_HELLO) {
311 throw wxString(wxT("Asks for something without saying hello"));
312 } else if (m_client && opcode != OP_HELLO && opcode != OP_HELLOANSWER) {
313 m_client->CheckHandshakeFinished();
316 switch(opcode) {
317 case OP_HELLOANSWER: { // 0.43b
318 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_HELLOANSWER from ") + m_client->GetFullIP());
319 theStats::AddDownOverheadOther(size);
320 m_client->ProcessHelloAnswer(buffer, size);
322 // start secure identification, if
323 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
324 // - we have received eMule-OP_HELLOANSWER (new eMule)
325 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
326 m_client->InfoPacketsReceived();
329 // Socket might die because of sending in InfoPacketsReceived, so check
330 if (m_client) {
331 m_client->ConnectionEstablished();
334 // Socket might die on ConnectionEstablished somehow. Check it.
335 if (m_client) {
336 Notify_SharedCtrlRefreshClient( m_client->ECID() , AVAILABLE_SOURCE);
339 break;
341 case OP_HELLO: { // 0.43b
343 theStats::AddDownOverheadOther(size);
344 bool bNewClient = !m_client;
345 if (bNewClient) {
346 // create new client to save standart informations
347 m_client = new CUpDownClient(this);
350 // Do not move up!
351 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_HELLO from ") + m_client->GetFullIP() );
353 bool bIsMuleHello = false;
355 try{
356 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
357 } catch(...) {
358 if (bNewClient && m_client) {
359 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
360 m_client->Safe_Delete();
361 m_client = NULL;
363 throw;
366 if (thePrefs::ParanoidFilter() && !IsLowID(m_client->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid()))) {
367 wxString reason = wxT("Client claims a different IP from the one we received the hello packet from: ");
368 reason += Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
369 AddDebugLogLineN(logClient, reason);
370 if (bNewClient) {
371 m_client->Safe_Delete();
372 m_client = NULL;
374 Disconnect(wxT("Paranoid disconecting: ") + reason);
375 return false;
378 // if IP is filtered, dont reply but disconnect...
379 if (theApp->ipfilter->IsFiltered(m_client->GetIP())) {
380 if (bNewClient) {
381 m_client->Safe_Delete();
382 m_client = NULL;
384 Disconnect(wxT("IPFilter"));
385 return false;
388 wxASSERT(m_client);
390 // now we check if we know this client already. if yes this socket will
391 // be attached to the known client, the new client will be deleted
392 // and the var. "client" will point to the known client.
393 // if not we keep our new-constructed client ;)
394 if (theApp->clientlist->AttachToAlreadyKnown(&m_client,this)) {
395 // update the old client informations
396 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
397 } else {
398 theApp->clientlist->AddClient(m_client);
399 m_client->SetCommentDirty();
401 Notify_SharedCtrlRefreshClient( m_client->ECID(), AVAILABLE_SOURCE );
402 // send a response packet with standart informations
403 if ((m_client->GetHashType() == SO_EMULE) && !bIsMuleHello) {
404 m_client->SendMuleInfoPacket(false);
407 // Client might die from Sending in SendMuleInfoPacket, so check
408 if ( m_client ) {
409 m_client->SendHelloAnswer();
412 // Kry - If the other side supports it, send OS_INFO
413 // Client might die from Sending in SendHelloAnswer, so check
414 if (m_client && m_client->GetOSInfoSupport()) {
415 m_client->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
418 // Client might die from Sending in SendMuleInfoPacket, so check
419 if ( m_client ) {
420 m_client->ConnectionEstablished();
423 // start secure identification, if
424 // - we have received eMule-OP_HELLO (new eMule)
425 if (m_client && m_client->GetInfoPacketsReceived() == IP_BOTH) {
426 m_client->InfoPacketsReceived();
429 break;
431 case OP_REQUESTFILENAME: { // 0.43b
432 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client->GetFullIP() );
434 theStats::AddDownOverheadFileRequest(size);
435 // IP banned, no answer for this request
436 if (m_client->IsBanned()) {
437 break;
439 if (size >= 16) {
440 if (!m_client->GetWaitStartTime()) {
441 m_client->SetWaitStartTime();
443 CMemFile data_in(buffer, size);
444 CMD4Hash reqfilehash = data_in.ReadHash();
445 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
446 if ( reqfile == NULL ) {
447 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
448 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
449 break;
452 // if we are downloading this file, this could be a new source
453 // no passive adding of files with only one part
454 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
455 if (thePrefs::GetMaxSourcePerFile() >
456 ((CPartFile*)reqfile)->GetSourceCount()) {
457 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
461 // check to see if this is a new file they are asking for
462 if (m_client->GetUploadFileID() != reqfilehash) {
463 m_client->SetCommentDirty();
466 m_client->SetUploadFileID(reqfile);
467 m_client->ProcessExtendedInfo(&data_in, reqfile);
469 // send filename etc
470 CMemFile data_out(128);
471 data_out.WriteHash(reqfile->GetFileHash());
473 // Since it's for somebody else to see, we need to send the prettified
474 // filename, rather than the (possibly) mangled actual filename.
475 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
477 CPacket* packet = new CPacket(data_out, OP_EDONKEYPROT, OP_REQFILENAMEANSWER);
478 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
479 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client->GetFullIP() );
480 SendPacket(packet,true);
482 // SendPacket might kill the socket, so check
483 if (m_client)
484 m_client->SendCommentInfo(reqfile);
486 break;
488 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
489 break;
491 case OP_SETREQFILEID: { // 0.43b EXCEPT track of bad clients
492 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SETREQFILEID from ") + m_client->GetFullIP() );
494 theStats::AddDownOverheadFileRequest(size);
496 if (m_client->IsBanned()) {
497 break;
500 // DbT:FileRequest
501 if (size == 16) {
502 if (!m_client->GetWaitStartTime()) {
503 m_client->SetWaitStartTime();
506 const CMD4Hash fileID(buffer);
507 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(fileID);
508 if ( reqfile == NULL ) {
509 reqfile = theApp->downloadqueue->GetFileByID(fileID);
510 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
511 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
512 replypacket->Copy16ToDataBuffer(fileID.GetHash());
513 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
514 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILERE to ") + m_client->GetFullIP() );
515 SendPacket(replypacket, true);
516 break;
520 // check to see if this is a new file they are asking for
521 if (m_client->GetUploadFileID() != fileID) {
522 m_client->SetCommentDirty();
525 m_client->SetUploadFileID(reqfile);
526 // send filestatus
527 CMemFile data(16+16);
528 data.WriteHash(reqfile->GetFileHash());
529 if (reqfile->IsPartFile()) {
530 ((CPartFile*)reqfile)->WritePartStatus(&data);
531 } else {
532 data.WriteUInt16(0);
534 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_FILESTATUS);
535 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
536 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILESTATUS to ") + m_client->GetFullIP() );
537 SendPacket(packet, true);
538 break;
540 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
541 break;
542 // DbT:End
545 case OP_FILEREQANSNOFIL: { // 0.43b protocol, lacks ZZ's download manager on swap
546 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client->GetFullIP() );
548 theStats::AddDownOverheadFileRequest(size);
549 if (size == 16) {
550 // if that client does not have my file maybe has another different
551 CPartFile* reqfile = theApp->downloadqueue->GetFileByID(CMD4Hash(buffer));
552 if ( reqfile) {
553 reqfile->AddDeadSource( m_client );
554 } else {
555 break;
558 // we try to swap to another file ignoring no needed parts files
559 switch (m_client->GetDownloadState()) {
560 case DS_CONNECTED:
561 case DS_ONQUEUE:
562 case DS_NONEEDEDPARTS:
563 if (!m_client->SwapToAnotherFile(true, true, true, NULL)) {
564 theApp->downloadqueue->RemoveSource(m_client);
566 break;
568 break;
570 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
571 break;
574 case OP_REQFILENAMEANSWER: { // 0.43b except check for bad clients
575 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client->GetFullIP() );
577 theStats::AddDownOverheadFileRequest(size);
578 CMemFile data(buffer, size);
579 CMD4Hash hash = data.ReadHash();
580 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
581 m_client->ProcessFileInfo(&data, file);
582 break;
585 case OP_FILESTATUS: { // 0.43b except check for bad clients
586 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILESTATUS from ") + m_client->GetFullIP() );
588 theStats::AddDownOverheadFileRequest(size);
589 CMemFile data(buffer, size);
590 CMD4Hash hash = data.ReadHash();
591 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
592 m_client->ProcessFileStatus(false, &data, file);
593 break;
596 case OP_STARTUPLOADREQ: {
597 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client->GetFullIP() );
599 theStats::AddDownOverheadFileRequest(size);
601 if (!m_client->CheckHandshakeFinished()) {
602 break;
605 m_client->CheckForAggressive();
606 if ( m_client->IsBanned() ) {
607 break;
610 if (size == 16) {
611 const CMD4Hash fileID(buffer);
612 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(fileID);
613 if (reqfile) {
614 if (m_client->GetUploadFileID() != fileID) {
615 m_client->SetCommentDirty();
617 m_client->SetUploadFileID(reqfile);
618 m_client->SendCommentInfo(reqfile);
620 // Socket might die because of SendCommentInfo, so check
621 if (m_client)
622 theApp->uploadqueue->AddClientToQueue(m_client);
625 break;
628 case OP_QUEUERANK: { // 0.43b
629 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_QUEUERANK from ") + m_client->GetFullIP() );
631 theStats::AddDownOverheadFileRequest(size);
632 CMemFile data(buffer, size);
633 uint32 rank = data.ReadUInt32();
635 m_client->SetRemoteQueueRank(rank);
636 break;
639 case OP_ACCEPTUPLOADREQ: { // 0.42e (xcept khaos stats)
640 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client->GetFullIP() );
642 theStats::AddDownOverheadFileRequest(size);
643 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
644 if (m_client->GetDownloadState() == DS_ONQUEUE ) {
645 m_client->SetDownloadState(DS_DOWNLOADING);
646 m_client->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
647 m_client->SendBlockRequests();
649 } else {
650 if (!m_client->GetSentCancelTransfer()) {
651 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
652 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
653 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
654 m_client->SendPacket(packet,true,true);
656 // SendPacket can cause the socket to die, so check
657 if (m_client)
658 m_client->SetSentCancelTransfer(1);
661 if (m_client)
662 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
664 break;
667 case OP_REQUESTPARTS: { // 0.43b
668 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client->GetFullIP() );
670 theStats::AddDownOverheadFileRequest(size);
672 m_client->ProcessRequestPartsPacket(buffer, size, false);
674 break;
677 case OP_CANCELTRANSFER: { // 0.43b
678 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client->GetFullIP() );
680 theStats::AddDownOverheadFileRequest(size);
681 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
682 AddDebugLogLineN( logClient, m_client->GetUserName() + wxT(": Upload session ended due canceled transfer."));
683 break;
686 case OP_END_OF_DOWNLOAD: { // 0.43b except check for bad clients
687 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client->GetFullIP() );
689 theStats::AddDownOverheadFileRequest(size);
690 if (size>=16 && m_client->GetUploadFileID() == CMD4Hash(buffer)) {
691 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
692 AddDebugLogLineN( logClient, m_client->GetUserName() + wxT(": Upload session ended due ended transfer."));
694 break;
697 case OP_HASHSETREQUEST: { // 0.43b except check for bad clients
698 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client->GetFullIP() );
701 theStats::AddDownOverheadFileRequest(size);
702 if (size != 16) {
703 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
705 m_client->SendHashsetPacket(CMD4Hash(buffer));
706 break;
709 case OP_HASHSETANSWER: { // 0.43b
710 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client->GetFullIP() );
712 theStats::AddDownOverheadFileRequest(size);
713 m_client->ProcessHashSet(buffer, size);
714 break;
717 case OP_SENDINGPART: { // 0.47a
718 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SENDINGPART from ") + m_client->GetFullIP() );
720 if ( m_client->GetRequestFile() &&
721 !m_client->GetRequestFile()->IsStopped() &&
722 (m_client->GetRequestFile()->GetStatus() == PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
724 m_client->ProcessBlockPacket(buffer, size, false, false);
726 if ( m_client &&
727 ( m_client->GetRequestFile()->IsStopped() ||
728 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
729 m_client->GetRequestFile()->GetStatus() == PS_ERROR) ) {
730 if (!m_client->GetSentCancelTransfer()) {
731 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
732 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
733 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
734 m_client->SendPacket(packet,true,true);
736 // Socket might die because of SendPacket, so check
737 if (m_client)
738 m_client->SetSentCancelTransfer(1);
741 if (m_client)
742 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
744 } else {
745 if (!m_client->GetSentCancelTransfer()) {
746 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
747 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
748 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
749 m_client->SendPacket(packet,true,true);
751 // Socket might die because of SendPacket, so check
752 m_client->SetSentCancelTransfer(1);
754 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
756 break;
759 case OP_OUTOFPARTREQS: { // 0.43b
760 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client->GetFullIP() );
762 theStats::AddDownOverheadFileRequest(size);
763 if (m_client->GetDownloadState() == DS_DOWNLOADING) {
764 m_client->SetDownloadState(DS_ONQUEUE);
766 break;
769 case OP_CHANGE_CLIENT_ID: { // Kad reviewed
770 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client->GetFullIP() );
772 theStats::AddDownOverheadOther(size);
773 CMemFile data(buffer, size);
774 uint32 nNewUserID = data.ReadUInt32();
775 uint32 nNewServerIP = data.ReadUInt32();
777 if (IsLowID(nNewUserID)) { // client changed server and gots a LowID
778 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
779 if (pNewServer != NULL){
780 m_client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
781 m_client->SetServerIP(nNewServerIP);
782 m_client->SetServerPort(pNewServer->GetPort());
784 } else if (nNewUserID == m_client->GetIP()) { // client changed server and gots a HighID(IP)
785 m_client->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID));
786 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
787 if (pNewServer != NULL){
788 m_client->SetServerIP(nNewServerIP);
789 m_client->SetServerPort(pNewServer->GetPort());
793 break;
796 case OP_CHANGE_SLOT:{ // 0.43b
797 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client->GetFullIP() );
799 // sometimes sent by Hybrid
800 theStats::AddDownOverheadOther(size);
801 break;
804 case OP_MESSAGE: { // 0.43b
805 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MESSAGE from ") + m_client->GetFullIP() );
807 theStats::AddDownOverheadOther(size);
809 if (size < 2) {
810 throw wxString(wxT("invalid message packet"));
812 CMemFile message_file(buffer, size);
813 uint16 length = message_file.ReadUInt16();
814 if (length + 2u != size) {
815 throw wxString(wxT("invalid message packet"));
818 // limit message length
819 static const uint16 MAX_CLIENT_MSG_LEN = 450;
821 if (length > MAX_CLIENT_MSG_LEN) {
822 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
823 % m_client->GetUserName() % m_client->GetFullIP() % (length - MAX_CLIENT_MSG_LEN));
824 length = MAX_CLIENT_MSG_LEN;
827 wxString message = message_file.ReadOnlyString((m_client->GetUnicodeSupport() != utf8strNone), length);
828 m_client->ProcessChatMessage(message);
830 break;
833 case OP_ASKSHAREDFILES: { // 0.43b (well, er, it does the same, but in our own way)
834 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
836 // client wants to know what we have in share, let's see if we allow him to know that
837 theStats::AddDownOverheadOther(size);
838 // IP banned, no answer for this request
839 if (m_client->IsBanned()) {
840 break;
843 if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
844 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
845 % m_client->GetUserName()
846 % m_client->GetUserIDHybrid() );
848 std::vector<CKnownFile*> list;
849 theApp->sharedfiles->CopyFileList(list);
851 CMemFile tempfile(80);
852 tempfile.WriteUInt32(list.size());
853 for (unsigned i = 0; i < list.size(); ++i) {
854 if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
855 list[i]->CreateOfferedFilePacket(&tempfile, NULL, m_client);
859 // create a packet and send it
860 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
861 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
862 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
863 SendPacket(replypacket, true, true);
864 } else {
865 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
866 % m_client->GetUserName()
867 % m_client->GetUserIDHybrid() );
869 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
870 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
871 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
872 SendPacket(replypacket, true, true);
875 break;
878 case OP_ASKSHAREDFILESANSWER: { // 0.43b
879 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
881 theStats::AddDownOverheadOther(size);
882 wxString EmptyStr;
883 m_client->ProcessSharedFileList(buffer, size, EmptyStr);
884 break;
887 case OP_ASKSHAREDDIRS: { // 0.43b
888 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
890 theStats::AddDownOverheadOther(size);
891 wxASSERT( size == 0 );
892 // IP banned, no answer for this request
893 if (m_client->IsBanned()) {
894 break;
896 if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
897 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
898 % m_client->GetUserName()
899 % m_client->GetUserIDHybrid() );
901 // This list will contain all (unique) folders.
902 std::list<CPath> foldersToSend;
904 // The shared folders
905 const unsigned folderCount = theApp->glob_prefs->shareddir_list.size();
906 for (unsigned i = 0; i < folderCount; ++i) {
907 foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]);
910 // ... the categories folders ... (category 0 -> incoming)
911 for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) {
912 foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path);
915 // ... and the Magic thing from the eDonkey Hybrids...
916 foldersToSend.push_back(CPath(OP_INCOMPLETE_SHARED_FILES));
918 // Strip duplicates
919 foldersToSend.sort();
920 foldersToSend.unique();
922 // Send packet.
923 CMemFile tempfile(80);
924 tempfile.WriteUInt32(foldersToSend.size());
926 std::list<CPath>::iterator it = foldersToSend.begin();
927 for (; it != foldersToSend.end(); ++it) {
928 // We need to send the 'raw' filename, so we can recognize it again.
929 tempfile.WriteString(it->GetRaw(), m_client->GetUnicodeSupport());
932 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS);
933 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
934 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client->GetFullIP() );
935 SendPacket(replypacket, true, true);
936 } else {
937 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
938 % m_client->GetUserName()
939 % m_client->GetUserIDHybrid() );
941 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
942 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
943 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
944 SendPacket(replypacket, true, true);
947 break;
950 case OP_ASKSHAREDFILESDIR: { // 0.43b
951 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
953 theStats::AddDownOverheadOther(size);
954 // IP banned, no answer for this request
955 if (m_client->IsBanned()) {
956 break;
958 CMemFile data(buffer, size);
960 wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
961 if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
962 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
963 wxASSERT( data.GetPosition() == data.GetLength() );
965 CKnownFilePtrList list;
967 if (strReqDir == OP_INCOMPLETE_SHARED_FILES) {
968 // get all shared files from download queue
969 int iQueuedFiles = theApp->downloadqueue->GetFileCount();
970 for (int i = 0; i < iQueuedFiles; i++) {
971 CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i);
972 if (pFile == NULL || pFile->GetStatus(true) != PS_READY) {
973 continue;
976 list.push_back(pFile);
978 } else {
979 theApp->sharedfiles->GetSharedFilesByDirectory(strReqDir, list);
982 CMemFile tempfile(80);
983 tempfile.WriteString(strReqDir, m_client->GetUnicodeSupport());
984 tempfile.WriteUInt32(list.size());
986 while (!list.empty()) {
987 if (!list.front()->IsLargeFile() || m_client->SupportsLargeFiles()) {
988 list.front()->CreateOfferedFilePacket(&tempfile, NULL, m_client);
991 list.pop_front();
994 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS);
995 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
996 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client->GetFullIP() );
997 SendPacket(replypacket, true, true);
998 } else {
999 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
1001 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
1002 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
1003 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
1004 SendPacket(replypacket, true, true);
1006 break;
1009 case OP_ASKSHAREDDIRSANS:{ // 0.43b
1010 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
1012 theStats::AddDownOverheadOther(size);
1013 if (m_client->GetFileListRequested() == 1){
1014 CMemFile data(buffer, size);
1015 uint32 uDirs = data.ReadUInt32();
1016 for (uint32 i = 0; i < uDirs; i++){
1017 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1018 AddLogLineC(CFormat( _("User %s (%u) shares directory %s") )
1019 % m_client->GetUserName()
1020 % m_client->GetUserIDHybrid()
1021 % strDir );
1023 CMemFile tempfile(80);
1024 tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
1025 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
1026 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
1027 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client->GetFullIP() );
1028 SendPacket(replypacket, true, true);
1030 wxASSERT( data.GetPosition() == data.GetLength() );
1031 m_client->SetFileListRequested(uDirs);
1032 } else {
1033 AddLogLineC(CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1034 % m_client->GetUserName()
1035 % m_client->GetUserIDHybrid() );
1037 break;
1040 case OP_ASKSHAREDFILESDIRANS: { // 0.43b
1041 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
1043 theStats::AddDownOverheadOther(size);
1044 CMemFile data(buffer, size);
1045 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1047 if (m_client->GetFileListRequested() > 0){
1048 AddLogLineC(CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1049 % m_client->GetUserName()
1050 % m_client->GetUserIDHybrid()
1051 % strDir );
1053 m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
1054 if (m_client->GetFileListRequested() == 0) {
1055 AddLogLineC(CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1056 % m_client->GetUserName()
1057 % m_client->GetUserIDHybrid() );
1059 } else {
1060 AddLogLineC(CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1061 % m_client->GetUserName()
1062 % m_client->GetUserIDHybrid() );
1064 break;
1067 case OP_ASKSHAREDDENIEDANS:
1068 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
1070 theStats::AddDownOverheadOther(size);
1071 wxASSERT( size == 0 );
1072 AddLogLineC(CFormat( _("User %s (%u) denied access to shared directories/files list") )
1073 % m_client->GetUserName()
1074 % m_client->GetUserIDHybrid() );
1076 m_client->SetFileListRequested(0);
1077 break;
1079 default:
1080 theStats::AddDownOverheadOther(size);
1081 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Edonkey packet: unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1082 return false;
1085 return true;
1089 bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1091 #ifdef __PACKET_RECV_DUMP__
1092 //printf("Rec: OPCODE %x \n",opcode);
1093 DumpMem(buffer,size);
1094 #endif
1096 // 0.42e - except the catchs on mem exception and file exception
1097 if (!m_client) {
1098 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1101 if (!client->CheckHandshakeFinished()) {
1102 // Here comes an extended packet without finishing the handshake.
1103 // IMHO, we should disconnect the client.
1104 throw wxString(wxT("Client send extended packet before finishing handshake"));
1107 switch(opcode) {
1108 case OP_MULTIPACKET_EXT:
1109 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1110 case OP_MULTIPACKET: {
1111 if (opcode == OP_MULTIPACKET) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1113 theStats::AddDownOverheadFileRequest(size);
1115 if (m_client->IsBanned()) {
1116 break;
1119 if (!m_client->CheckHandshakeFinished()) {
1120 // Here comes an extended packet without finishing the handshake.
1121 // IMHO, we should disconnect the client.
1122 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1125 CMemFile data_in(buffer, size);
1126 CMD4Hash reqfilehash = data_in.ReadHash();
1127 uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1129 bool file_not_found = false;
1130 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1131 if ( reqfile == NULL ){
1132 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1133 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1134 AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a non-shared file"));
1135 file_not_found = true;
1139 if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1140 AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1141 file_not_found = true;
1144 if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1145 AddDebugLogLineN(logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1146 file_not_found = true;
1149 if (file_not_found) {
1150 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1151 replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1152 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1153 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1154 SendPacket(replypacket, true);
1155 break;
1158 if (!m_client->GetWaitStartTime()) {
1159 m_client->SetWaitStartTime();
1161 // if we are downloading this file, this could be a new source
1162 // no passive adding of files with only one part
1163 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1164 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount()) {
1165 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
1168 // check to see if this is a new file they are asking for
1169 if (m_client->GetUploadFileID() != reqfilehash) {
1170 m_client->SetCommentDirty();
1172 m_client->SetUploadFileID(reqfile);
1173 CMemFile data_out(128);
1174 data_out.WriteHash(reqfile->GetFileHash());
1175 while(data_in.GetLength()-data_in.GetPosition()) {
1176 if (!m_client) {
1177 throw wxString(wxT("Client suddenly disconnected"));
1179 uint8 opcode_in = data_in.ReadUInt8();
1180 switch(opcode_in) {
1181 case OP_REQUESTFILENAME: {
1182 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1183 m_client->ProcessExtendedInfo(&data_in, reqfile);
1184 data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1186 // Since it's for somebody else to see, we need to send the prettified
1187 // filename, rather than the (possibly) mangled actual filename
1188 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1189 break;
1191 case OP_AICHFILEHASHREQ: {
1192 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1193 if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1194 && reqfile->GetAICHHashset()->HasValidMasterHash())
1196 data_out.WriteUInt8(OP_AICHFILEHASHANS);
1197 reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1199 break;
1201 case OP_SETREQFILEID: {
1202 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1203 data_out.WriteUInt8(OP_FILESTATUS);
1204 if (reqfile->IsPartFile()) {
1205 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1206 } else {
1207 data_out.WriteUInt16(0);
1209 break;
1211 //We still send the source packet separately..
1212 //We could send it within this packet.. If agreeded, I will fix it..
1213 case OP_REQUESTSOURCES2:
1214 case OP_REQUESTSOURCES: {
1215 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1216 uint8 byRequestedVersion = 0;
1217 uint16 byRequestedOptions = 0;
1218 if (opcode_in == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1219 byRequestedVersion = data_in.ReadUInt8();
1220 byRequestedOptions = data_in.ReadUInt16();
1223 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1225 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1226 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1227 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1228 if(
1229 //if not complete and file is rare
1230 ( reqfile->IsPartFile()
1231 && (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1232 && ((CPartFile*)reqfile)->GetSourceCount() <= RARE_FILE
1233 ) ||
1234 //OR if file is not rare or if file is complete
1235 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1238 m_client->SetLastSrcReqTime();
1239 CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1240 if(tosend) {
1241 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1242 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1243 SendPacket(tosend, true);
1247 break;
1252 if( data_out.GetLength() > 16 ) {
1253 CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1254 theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1255 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1256 SendPacket(reply, true);
1258 break;
1261 case OP_MULTIPACKETANSWER: { // 0.43b
1262 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1264 theStats::AddDownOverheadFileRequest(size);
1266 if (m_client->IsBanned()) {
1267 break;
1270 if (m_client->GetKadPort() && m_client->GetKadVersion() > 1) {
1271 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort());
1274 if (!m_client->CheckHandshakeFinished()) {
1275 // Here comes an extended packet without finishing the handshake.
1276 // IMHO, we should disconnect the client.
1277 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1280 CMemFile data_in(buffer, size);
1281 CMD4Hash reqfilehash = data_in.ReadHash();
1282 const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1283 //Make sure we are downloading this file.
1284 if ( !reqfile ) {
1285 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1287 if ( !m_client->GetRequestFile() ) {
1289 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1291 if (reqfile != m_client->GetRequestFile()) {
1292 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1294 while (data_in.GetLength()-data_in.GetPosition()) {
1295 // Some of the cases down there can actually send a packet and lose the client
1296 if (!m_client) {
1297 throw wxString(wxT("Client suddenly disconnected"));
1299 uint8 opcode_in = data_in.ReadUInt8();
1300 switch(opcode_in) {
1301 case OP_REQFILENAMEANSWER: {
1302 if (!m_client) {
1303 throw wxString(wxT("Client suddenly disconnected"));
1304 } else {
1305 m_client->ProcessFileInfo(&data_in, reqfile);
1307 break;
1309 case OP_FILESTATUS: {
1310 if (!m_client) {
1311 throw wxString(wxT("Client suddenly disconnected"));
1312 } else {
1313 m_client->ProcessFileStatus(false, &data_in, reqfile);
1315 break;
1317 case OP_AICHFILEHASHANS: {
1318 if (!m_client) {
1319 throw wxString(wxT("Client suddenly disconnected"));
1320 } else {
1321 m_client->ProcessAICHFileHash(&data_in, reqfile);
1323 break;
1328 break;
1331 case OP_EMULEINFO: { // 0.43b
1332 theStats::AddDownOverheadOther(size);
1334 if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1335 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1337 // If it's not a OS Info packet, is an old client
1338 // start secure identification, if
1339 // - we have received eD2K and eMule info (old eMule)
1340 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1341 m_client->InfoPacketsReceived();
1343 m_client->SendMuleInfoPacket(true);
1344 } else {
1345 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1347 break;
1349 case OP_EMULEINFOANSWER: { // 0.43b
1350 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1351 theStats::AddDownOverheadOther(size);
1353 m_client->ProcessMuleInfoPacket(buffer, size);
1354 // start secure identification, if
1355 // - we have received eD2K and eMule info (old eMule)
1357 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1358 m_client->InfoPacketsReceived();
1361 break;
1364 case OP_SECIDENTSTATE:{ // 0.43b
1365 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1367 if (!m_client->CheckHandshakeFinished()) {
1368 // Here comes an extended packet without finishing the handshake.
1369 // IMHO, we should disconnect the client.
1370 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1372 m_client->ProcessSecIdentStatePacket(buffer, size);
1373 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1374 if (m_client) {
1375 int SecureIdentState = m_client->GetSecureIdentState();
1376 if (SecureIdentState == IS_SIGNATURENEEDED) {
1377 m_client->SendSignaturePacket();
1378 } else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1379 m_client->SendPublicKeyPacket();
1380 // SendPublicKeyPacket() might cause the socket to die, so check
1381 if ( m_client ) {
1382 m_client->SendSignaturePacket();
1386 break;
1389 case OP_PUBLICKEY: { // 0.43b
1390 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1392 if (m_client->IsBanned() ){
1393 break;
1396 if (!m_client->CheckHandshakeFinished()) {
1397 // Here comes an extended packet without finishing the handshake.
1398 // IMHO, we should disconnect the client.
1399 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1402 m_client->ProcessPublicKeyPacket(buffer, size);
1403 break;
1405 case OP_SIGNATURE:{ // 0.43b
1406 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1408 if (!m_client->CheckHandshakeFinished()) {
1409 // Here comes an extended packet without finishing the handshake.
1410 // IMHO, we should disconnect the client.
1411 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1414 m_client->ProcessSignaturePacket(buffer, size);
1415 break;
1417 case OP_SENDINGPART_I64:
1418 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1419 case OP_COMPRESSEDPART_I64:
1420 if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1421 case OP_COMPRESSEDPART: { // 0.47a
1422 if (opcode == OP_COMPRESSEDPART) AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1424 if (!m_client->CheckHandshakeFinished()) {
1425 // Here comes an extended packet without finishing the handshake.
1426 // IMHO, we should disconnect the client.
1427 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1430 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1432 m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1434 if (m_client && (
1435 m_client->GetRequestFile()->IsStopped() ||
1436 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1437 m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1438 if (!m_client->GetSentCancelTransfer()) {
1439 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1440 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1441 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1442 m_client->SendPacket(packet,true,true);
1444 if (m_client) {
1445 m_client->SetSentCancelTransfer(1);
1449 if ( m_client ) {
1450 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1453 } else {
1454 if (!m_client->GetSentCancelTransfer()) {
1455 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1456 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1457 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1458 m_client->SendPacket(packet,true,true);
1460 if ( m_client ) {
1461 m_client->SetSentCancelTransfer(1);
1465 if ( m_client ) {
1466 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1469 break;
1471 case OP_REQUESTPARTS_I64: {
1472 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP() );
1474 theStats::AddDownOverheadFileRequest(size);
1476 m_client->ProcessRequestPartsPacket(buffer, size, true);
1478 break;
1480 case OP_QUEUERANKING: { // 0.43b
1481 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP() );
1483 theStats::AddDownOverheadOther(size);
1485 if (!m_client->CheckHandshakeFinished()) {
1486 // Here comes an extended packet without finishing the handshake.
1487 // IMHO, we should disconnect the client.
1488 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1491 if (size != 12) {
1492 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1495 uint16 newrank = PeekUInt16(buffer);
1496 m_client->SetRemoteQueueFull(false);
1497 m_client->SetRemoteQueueRank(newrank);
1498 break;
1500 case OP_REQUESTSOURCES2:
1501 case OP_REQUESTSOURCES:{
1502 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP() );
1504 theStats::AddDownOverheadSourceExchange(size);
1506 if (!m_client->CheckHandshakeFinished()) {
1507 // Here comes an extended packet without finishing the handshake.
1508 // IMHO, we should disconnect the client.
1509 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1512 uint8 byRequestedVersion = 0;
1513 uint16 byRequestedOptions = 0;
1514 CMemFile data_in(buffer, size);
1515 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1516 byRequestedVersion = data_in.ReadUInt8();
1517 byRequestedOptions = data_in.ReadUInt16();
1520 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1521 if(size != 16) {
1522 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1524 //first check shared file list, then download list
1525 const CMD4Hash fileID(buffer);
1526 CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1527 if(!file) {
1528 file = theApp->downloadqueue->GetFileByID(fileID);
1530 if(file) {
1531 // There are some clients which do not follow the correct protocol procedure of sending
1532 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1533 // are doing this, they will not get the optimal set of sources which we could offer if
1534 // they would follow the above noted protocol sequence. They better do it the right way
1535 // or they will get just a random set of sources because we do not know their download
1536 // part status which may get cleared with the call of 'SetUploadFileID'.
1537 m_client->SetUploadFileID(file);
1539 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1540 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1541 if(
1542 //if not complete and file is rare, allow once every 40 minutes
1543 ( file->IsPartFile() &&
1544 ((CPartFile*)file)->GetSourceCount() <= RARE_FILE &&
1545 (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1546 ) ||
1547 //OR if file is not rare or if file is complete, allow every 90 minutes
1548 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1551 m_client->SetLastSrcReqTime();
1552 CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1553 if(tosend) {
1554 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1555 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1556 SendPacket(tosend, true, true);
1561 break;
1563 case OP_ANSWERSOURCES: {
1564 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP() );
1566 theStats::AddDownOverheadSourceExchange(size);
1568 if (!m_client->CheckHandshakeFinished()) {
1569 // Here comes an extended packet without finishing the handshake.
1570 // IMHO, we should disconnect the client.
1571 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1574 CMemFile data(buffer, size);
1575 CMD4Hash hash = data.ReadHash();
1576 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1577 if(file){
1578 if (file->IsPartFile()){
1579 //set the client's answer time
1580 m_client->SetLastSrcAnswerTime();
1581 //and set the file's last answer time
1582 ((CPartFile*)file)->SetLastAnsweredTime();
1584 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1587 break;
1589 case OP_ANSWERSOURCES2: {
1590 //printf("Received OP_ANSWERSOURCES2\n");
1591 theStats::AddDownOverheadSourceExchange(size);
1593 if (!m_client->CheckHandshakeFinished()) {
1594 // Here comes an extended packet without finishing the handshake.
1595 // IMHO, we should disconnect the client.
1596 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1599 CMemFile data(buffer, size);
1600 uint8 byVersion = data.ReadUInt8();
1601 CMD4Hash hash = data.ReadHash();
1602 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1603 if (file){
1604 if (file->IsPartFile()){
1605 //set the client's answer time
1606 m_client->SetLastSrcAnswerTime();
1607 //and set the file's last answer time
1608 ((CPartFile*)file)->SetLastAnsweredTime();
1609 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1612 break;
1614 case OP_FILEDESC: { // 0.43b
1615 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP() );
1617 theStats::AddDownOverheadFileRequest(size);
1619 if (!m_client->CheckHandshakeFinished()) {
1620 // Here comes an extended packet without finishing the handshake.
1621 // IMHO, we should disconnect the client.
1622 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1625 m_client->ProcessMuleCommentPacket(buffer, size);
1626 break;
1629 // Unsupported
1630 case OP_REQUESTPREVIEW: {
1631 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client->GetFullIP() );
1632 break;
1634 // Unsupported
1635 case OP_PREVIEWANSWER: {
1636 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP() );
1637 break;
1640 case OP_PUBLICIP_ANSWER: {
1641 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP() );
1642 theStats::AddDownOverheadOther(size);
1643 m_client->ProcessPublicIPAnswer(buffer, size);
1644 break;
1646 case OP_PUBLICIP_REQ: {
1647 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP() );
1648 theStats::AddDownOverheadOther(size);
1649 CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1650 pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1651 theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1652 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1653 SendPacket(pPacket);
1654 break;
1656 case OP_AICHANSWER: {
1657 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP() );
1658 theStats::AddDownOverheadOther(size);
1659 m_client->ProcessAICHAnswer(buffer, size);
1660 break;
1662 case OP_AICHREQUEST: {
1663 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP() );
1664 theStats::AddDownOverheadOther(size);
1665 m_client->ProcessAICHRequest(buffer, size);
1666 break;
1668 case OP_AICHFILEHASHANS: {
1669 // those should not be received normally, since we should only get those in MULTIPACKET
1670 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP() );
1671 theStats::AddDownOverheadOther(size);
1672 CMemFile data(buffer, size);
1673 m_client->ProcessAICHFileHash(&data, NULL);
1674 break;
1676 case OP_AICHFILEHASHREQ: {
1677 // those should not be received normally, since we should only get those in MULTIPACKET
1678 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP() );
1679 CMemFile data(buffer, size);
1680 CMD4Hash hash = data.ReadHash();
1681 CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1682 if (pPartFile == NULL){
1683 break;
1686 if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1687 && pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1688 CMemFile data_out;
1689 data_out.WriteHash(hash);
1690 pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1691 CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1692 theStats::AddUpOverheadOther(packet->GetPacketSize());
1693 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1694 SendPacket(packet);
1696 break;
1698 case OP_CALLBACK: {
1699 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1700 theStats::AddDownOverheadFileRequest(size);
1701 if(!Kademlia::CKademlia::IsRunning()) {
1702 break;
1704 CMemFile data(buffer, size);
1705 CUInt128 check = data.ReadUInt128();
1706 check.XOR(Kademlia::CUInt128(true));
1707 if( check.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1708 break;
1710 CUInt128 fileid = data.ReadUInt128();
1711 byte fileid2[16];
1712 fileid.ToByteArray(fileid2);
1713 const CMD4Hash fileHash(fileid2);
1714 if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1715 if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1716 break;
1720 uint32 ip = data.ReadUInt32();
1721 uint16 tcp = data.ReadUInt16();
1722 CUpDownClient* callback;
1723 callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1724 if( callback == NULL ) {
1725 //#warning Do we actually have to check friend status here?
1726 callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1727 theApp->clientlist->AddClient(callback);
1729 callback->TryToConnect(true);
1730 break;
1733 case OP_BUDDYPING: {
1734 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP() );
1735 theStats::AddDownOverheadKad(size);
1737 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1738 if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1739 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1740 break;
1743 m_client->SetLastBuddyPingPongTime();
1744 CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1745 theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1746 AddDebugLogLineN(logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1747 SendPacket(replypacket);
1748 break;
1750 case OP_BUDDYPONG: {
1751 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP() );
1752 theStats::AddDownOverheadKad(size);
1754 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1755 if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1756 //This pong was not from our buddy or wrong version. Ignore
1757 break;
1759 m_client->SetLastBuddyPingPongTime();
1760 //All this is for is to reset our socket timeout.
1761 break;
1763 case OP_REASKCALLBACKTCP: {
1764 theStats::AddDownOverheadFileRequest(size);
1765 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1766 if (buddy != m_client) {
1767 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1768 //This callback was not from our buddy.. Ignore.
1769 break;
1771 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1772 CMemFile data_in(buffer, size);
1773 uint32 destip = data_in.ReadUInt32();
1774 uint16 destport = data_in.ReadUInt16();
1775 CMD4Hash hash = data_in.ReadHash();
1776 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1778 bool bSenderMultipleIpUnknown = false;
1779 CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1780 if (!reqfile) {
1781 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1782 CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1783 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1784 if (sender) {
1785 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1786 } else {
1787 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1789 break;
1792 if (sender) {
1793 //Make sure we are still thinking about the same file
1794 if (hash == sender->GetUploadFileID()) {
1795 sender->AddAskedCount();
1796 sender->SetLastUpRequest();
1797 //I messed up when I first added extended info to UDP
1798 //I should have originally used the entire ProcessExtenedInfo the first time.
1799 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1800 //For now on, we should not have to change anything here if we change
1801 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1802 //Update extended info.
1803 if (sender->GetUDPVersion() > 3) {
1804 sender->ProcessExtendedInfo(&data_in, reqfile);
1805 } else if (sender->GetUDPVersion() > 2) {
1806 //Update our complete source counts.
1807 uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1808 uint16 nCompleteCountNew = data_in.ReadUInt16();
1809 sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1810 if (nCompleteCountLast != nCompleteCountNew) {
1811 reqfile->UpdatePartsInfo();
1815 CMemFile data_out(128);
1816 if(sender->GetUDPVersion() > 3) {
1817 if (reqfile->IsPartFile()) {
1818 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1819 } else {
1820 data_out.WriteUInt16(0);
1824 data_out.WriteUInt16(sender->GetUploadQueueWaitingPosition());
1825 CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1826 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1827 AddDebugLogLineN( logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP() );
1828 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1829 } else {
1830 AddDebugLogLineN(logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1832 } else {
1833 if (!bSenderMultipleIpUnknown){
1834 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1835 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP() );
1836 CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1837 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1838 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1840 } else {
1841 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);
1844 break;
1846 case OP_CHATCAPTCHAREQ:
1848 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client->GetFullIP());
1849 theStats::AddDownOverheadOther(size);
1850 CMemFile data_in(buffer, size);
1851 m_client->ProcessCaptchaRequest(&data_in);
1852 break;
1854 case OP_CHATCAPTCHARES:
1856 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client->GetFullIP());
1857 theStats::AddDownOverheadOther(size);
1858 if (size) {
1859 m_client->ProcessCaptchaReqRes(buffer[0]);
1861 break;
1863 case OP_FWCHECKUDPREQ: { // Support required for Kadversion >= 6
1864 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client->GetFullIP());
1865 theStats::AddDownOverheadOther(size);
1866 CMemFile data_in(buffer, size);
1867 m_client->ProcessFirewallCheckUDPRequest(&data_in);
1868 break;
1870 case OP_KAD_FWTCPCHECK_ACK: { // Support required for Kadversion >= 7
1871 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client->GetFullIP());
1872 if (theApp->clientlist->IsKadFirewallCheckIP(m_client->GetIP())) {
1873 if (Kademlia::CKademlia::IsRunning()) {
1874 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1876 } else {
1877 AddDebugLogLineN(logListenSocket, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client->GetFullIP());
1879 break;
1881 default:
1882 theStats::AddDownOverheadOther(size);
1883 AddDebugLogLineN(logRemoteClient, CFormat(wxT("eMule packet : unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1884 break;
1887 return true;
1890 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1892 #ifdef __PACKET_RECV_DUMP__
1893 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1894 DumpMem(buffer,size);
1895 #endif
1897 if (!m_client) {
1898 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1901 CMemFile data(buffer, size);
1902 try {
1903 switch(opcode) {
1904 case OP_QUEUERANK: {
1905 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1907 uint8 numtags = data.ReadUInt8();
1908 wxASSERT(numtags == 1);
1909 if(numtags){} // prevent GCC warning
1911 m_client->SetRemoteQueueRank(data.GetIntTagValue());
1913 theStats::AddDownOverheadFileRequest(size);
1914 break;
1917 case OP_REQUESTPARTS: {
1918 AddDebugLogLineN( logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1920 m_client->ProcessRequestPartsPacketv2(data);
1922 theStats::AddDownOverheadFileRequest(size);
1923 break;
1926 default:
1927 theStats::AddDownOverheadOther(size);
1928 AddDebugLogLineN(logRemoteClient, CFormat(wxT("ED2Kv2 packet : unknown opcode: %i %x from %s")) % opcode % opcode % m_client->GetFullIP());
1930 } catch (...) {
1931 AddDebugLogLineN(logRemoteClient, CFormat(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from %s")) % data.GetPosition() % opcode % opcode % m_client->GetFullIP());
1932 throw;
1935 return true;
1938 void CClientTCPSocket::OnConnect(int nErrorCode)
1940 if (nErrorCode) {
1941 OnError(nErrorCode);
1942 } else if (!m_client) {
1943 // and now? Disconnect? not?
1944 AddDebugLogLineN( logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1945 } else if (!m_client->SendHelloPacket()) {
1946 // and now? Disconnect? not?
1947 AddDebugLogLineN( logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1948 } else {
1949 ResetTimeOutTimer();
1954 void CClientTCPSocket::OnSend(int nErrorCode)
1956 ResetTimeOutTimer();
1957 CEMSocket::OnSend(nErrorCode);
1961 void CClientTCPSocket::OnReceive(int nErrorCode)
1963 ResetTimeOutTimer();
1964 // We might have updated ipfilter
1965 wxASSERT(m_remoteip);
1967 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1968 if (m_client) {
1969 m_client->Safe_Delete();
1971 Safe_Delete();
1972 AddDebugLogLineN( logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1973 } else {
1974 CEMSocket::OnReceive(nErrorCode);
1979 void CClientTCPSocket::OnError(int nErrorCode)
1981 //printf("* Called OnError for %p\n",this);
1982 // 0.42e + Kry changes for handling of socket lost events
1983 wxString strError;
1985 if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1986 if (m_client) {
1987 if (!m_client->GetUserName().IsEmpty()) {
1988 strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1989 } else {
1990 strError = wxT("An unnamed client");
1992 strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1993 } else {
1994 strError = wxT("A client ");
1996 if (nErrorCode == 0) {
1997 strError += wxT("closed connection.");
1998 } else if (nErrorCode == 0xFEFF) {
1999 strError += wxT(" caused a wxSOCKET_LOST event.");
2000 } else {
2001 strError += wxT("caused a socket blocking error.");
2003 } else {
2004 if (theLogger.IsEnabled(logClient) && nErrorCode != 107) {
2005 // 0 -> No Error / Disconect
2006 // 107 -> Transport endpoint is not connected
2007 if (m_client) {
2008 if (!m_client->GetUserName().IsEmpty()) {
2009 strError = CFormat(wxT("OnError: Client '%s' (IP:%s) caused an error: %u. Disconnecting client!"))
2010 % m_client->GetUserName() % m_client->GetFullIP() % nErrorCode;
2011 } else {
2012 strError = CFormat(wxT("OnError: Unknown client (IP:%s) caused an error: %u. Disconnecting client!"))
2013 % m_client->GetFullIP() % nErrorCode;
2015 } else {
2016 strError = CFormat(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"))
2017 % nErrorCode;
2019 } else {
2020 strError = wxT("Error 107 (Transport endpoint is not connected)");
2024 Disconnect(strError);
2028 bool CClientTCPSocket::PacketReceived(CPacket* packet)
2030 // 0.42e
2031 bool bResult = false;
2032 uint32 uRawSize = packet->GetPacketSize();
2034 AddDebugLogLineN( logRemoteClient,
2035 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
2036 % packet->GetProtocol()
2037 % packet->GetOpCode()
2038 % packet->GetPacketSize()
2039 % ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
2042 wxString exception;
2044 try {
2045 bool process = true;
2047 if ((packet->GetProtocol() == OP_PACKEDPROT) ||
2048 (packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
2050 if (!packet->UnPackPacket()) {
2051 AddDebugLogLineN(logZLib, wxT("Failed to decompress client TCP packet."));
2052 bResult = false;
2053 process = false;
2054 } else {
2055 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"))
2056 % packet->GetProtocol() % packet->GetOpCode() % packet->GetPacketSize());
2060 if (process) {
2061 switch (packet->GetProtocol()) {
2062 case OP_EDONKEYPROT:
2063 bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
2064 break;
2065 case OP_EMULEPROT:
2066 bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2067 break;
2068 case OP_ED2KV2HEADER:
2069 bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2070 break;
2071 case OP_ED2KV2PACKEDPROT:
2072 case OP_PACKEDPROT:
2073 // Packed inside packed?
2074 wxFAIL;
2075 break;
2076 default: {
2077 theStats::AddDownOverheadOther(uRawSize);
2078 if (m_client) {
2079 m_client->SetDownloadState(DS_ERROR);
2081 Disconnect(wxT("Unknown protocol"));
2082 bResult = false;
2086 } catch (const CEOFException& err) {
2087 exception = wxT("EOF exception: ") + err.what();
2088 } catch (const CInvalidPacket& err) {
2089 exception = wxT("InvalidPacket exception: ") + err.what();
2090 } catch (const wxString& error) {
2091 exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2094 if (!exception.IsEmpty()) {
2095 AddDebugLogLineN( logPacketErrors,
2096 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2097 % exception
2098 % packet->GetProtocol()
2099 % packet->GetOpCode()
2100 % packet->GetPacketSize()
2101 % ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2104 if (m_client) {
2105 m_client->SetDownloadState(DS_ERROR);
2108 AddDebugLogLineN( logClient,
2109 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2110 % ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2111 % ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2112 % exception
2115 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2118 return bResult;
2122 SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2124 SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2126 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2127 ResetTimeOutTimer();
2130 return returnStatus;
2134 SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2136 SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2138 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2139 ResetTimeOutTimer();
2142 return returnStatus;
2146 void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2148 ResetTimeOutTimer();
2149 CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2151 // File_checked_for_headers