Upstream tarball 20080405
[amule.git] / src / ClientTCPSocket.cpp
blobe65b4a20e41ea8b188c3479e077bc625640df772
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 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
9 // respective authors.
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "ClientTCPSocket.h" // Interface declarations
28 #include <protocol/Protocols.h>
29 #include <protocol/ed2k/Client2Client/TCP.h>
30 #include <protocol/ed2k/Client2Client/UDP.h> // Sometimes we reply with UDP packets.
31 #include <protocol/ed2k/ClientSoftware.h>
32 #include <common/EventIDs.h>
34 #include "Preferences.h" // Needed for thePrefs
35 #include "Packet.h" // Needed for CPacket
36 #include "Statistics.h" // Needed for theStats
37 #include "Logger.h" // Neeed for logRemoteClient
38 #include "updownclient.h" // Needed for CUpDownClient
39 #include <common/Format.h> // Needed for CFormat
40 #include "amule.h" // Needed for theApp
41 #include "SharedFileList.h" // Needed for CSharedFileList
42 #include "ClientList.h" // Needed for CClientList
43 #include "UploadQueue.h" // Needed for CUploadQueue
44 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket
45 #include "PartFile.h" // Needed for CPartFile
46 #include "MemFile.h" // Needed for CMemFile
47 #include "kademlia/kademlia/Kademlia.h" // Needed for CKademlia::Kademlia
48 #include "kademlia/kademlia/Prefs.h" // Needed for CKademlia::CPrefs
49 #include "DownloadQueue.h" // Needed for CDownloadQueue
50 #include "Server.h" // Needed for CServer
51 #include "ServerList.h" // Needed for CServerList
52 #include "IPFilter.h" // Needed for CIPFilter
53 #include "ListenSocket.h" // Needed for CListenSocket
54 #include "GuiEvents.h" // Needed for Notify_*
57 //#define __PACKET_RECV_DUMP__
59 //------------------------------------------------------------------------------
60 // CClientTCPSocketHandler
61 //------------------------------------------------------------------------------
63 class CClientTCPSocketHandler: public wxEvtHandler
65 public:
66 CClientTCPSocketHandler() {};
68 private:
69 void ClientTCPSocketHandler(wxSocketEvent& event);
70 DECLARE_EVENT_TABLE()
73 BEGIN_EVENT_TABLE(CClientTCPSocketHandler, wxEvtHandler)
74 EVT_SOCKET(ID_CLIENTTCPSOCKET_EVENT, CClientTCPSocketHandler::ClientTCPSocketHandler)
75 END_EVENT_TABLE()
77 void CClientTCPSocketHandler::ClientTCPSocketHandler(wxSocketEvent& event)
79 CClientTCPSocket *socket = dynamic_cast<CClientTCPSocket *>(event.GetSocket());
80 wxASSERT(socket);
81 if (!socket) {
82 return;
85 if (socket->OnDestroy() || socket->ForDeletion()) {
86 return;
89 switch(event.GetSocketEvent()) {
90 case wxSOCKET_LOST:
91 socket->OnError(0xFEFF /* SOCKET_LOST is not an error */);
92 break;
93 case wxSOCKET_INPUT:
94 socket->OnReceive(0);
95 break;
96 case wxSOCKET_OUTPUT:
97 socket->OnSend(0);
98 break;
99 case wxSOCKET_CONNECTION:
100 // connection stablished, nothing to do about it?
101 socket->OnConnect(socket->Error() ? socket->LastError() : 0);
102 break;
103 default:
104 // Nothing should arrive here...
105 wxASSERT(0);
106 break;
111 // There can be only one. :)
113 static CClientTCPSocketHandler g_clientReqSocketHandler;
116 //------------------------------------------------------------------------------
117 // CClientTCPSocket
118 //------------------------------------------------------------------------------
120 CClientTCPSocket::CClientTCPSocket(CUpDownClient* in_client, const CProxyData *ProxyData)
121 : CEMSocket(ProxyData)
123 SetClient(in_client);
124 if (in_client) {
125 m_remoteip = wxUINT32_SWAP_ALWAYS(in_client->GetUserIDHybrid());
126 } else {
127 m_remoteip = 0;
130 ResetTimeOutTimer();
131 m_ForDeletion = false;
133 SetEventHandler(g_clientReqSocketHandler, ID_CLIENTTCPSOCKET_EVENT);
134 SetNotify(
135 wxSOCKET_CONNECTION_FLAG |
136 wxSOCKET_INPUT_FLAG |
137 wxSOCKET_OUTPUT_FLAG |
138 wxSOCKET_LOST_FLAG);
139 Notify(true);
141 theApp->listensocket->AddSocket(this);
142 theApp->listensocket->AddConnection();
145 CClientTCPSocket::~CClientTCPSocket()
147 // remove event handler
148 SetNotify(0);
149 Notify(false);
151 if (m_client) {
152 m_client->SetSocket( NULL );
154 m_client = NULL;
156 if (theApp->listensocket && !theApp->listensocket->OnShutdown()) {
157 theApp->listensocket->RemoveSocket(this);
161 bool CClientTCPSocket::InitNetworkData() {
162 wxASSERT(!m_remoteip);
163 wxASSERT(!m_client);
164 amuleIPV4Address addr;
165 GetPeer(addr);
166 m_remoteip = StringIPtoUint32(addr.IPAddress());
168 MULE_CHECK(m_remoteip, false);
170 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
171 AddDebugLogLineM(false, logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Filtered IP)"));
172 return false;
173 } else {
174 AddDebugLogLineM(false, logClient, wxT("Accepted connection from ") + addr.IPAddress());
175 return true;
179 void CClientTCPSocket::ResetTimeOutTimer()
181 timeout_timer = ::GetTickCount();
185 bool CClientTCPSocket::CheckTimeOut()
187 // 0.42x
188 uint32 uTimeout = GetTimeOut();
189 if (m_client) {
191 if (m_client->GetKadState() == KS_CONNECTED_BUDDY) {
192 //We originally ignored the timeout here for buddies.
193 //This was a stupid idea on my part. There is now a ping/pong system
194 //for buddies. This ping/pong system now prevents timeouts.
195 //This release will allow lowID clients with KadVersion 0 to remain connected.
196 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
197 //JOHNTODO: Don't forget to remove backward support in a future release.
198 if ( m_client->GetKadVersion() == 0 ) {
199 return false;
202 uTimeout += MIN2MS(15);
205 if (m_client->GetChatState() != MS_NONE) {
206 uTimeout += CONNECTION_TIMEOUT;
210 if (::GetTickCount() - timeout_timer > uTimeout){
211 timeout_timer = ::GetTickCount();
212 Disconnect(wxT("Timeout"));
213 return true;
216 return false;
220 void CClientTCPSocket::SetClient(CUpDownClient* pClient)
222 m_client = pClient;
223 if (m_client) {
224 m_client->SetSocket( this );
229 void CClientTCPSocket::OnClose(int nErrorCode)
231 // 0.42x
232 wxASSERT(theApp->listensocket->IsValidSocket(this));
233 CEMSocket::OnClose(nErrorCode);
234 if (nErrorCode) {
235 Disconnect(wxString::Format(wxT("Closed: %u"), nErrorCode));
236 } else {
237 Disconnect(wxT("Close"));
242 void CClientTCPSocket::Disconnect(const wxString& strReason)
244 byConnected = ES_DISCONNECTED;
245 if (m_client) {
246 if (m_client->Disconnected(strReason, true)) {
247 // Somehow, Safe_Delete() is beeing called by Disconnected(),
248 // or any other function that sets m_client to NULL,
249 // so we must check m_client first.
250 if (m_client) {
251 m_client->SetSocket( NULL );
252 m_client->Safe_Delete();
255 m_client = NULL;
258 Safe_Delete();
262 void CClientTCPSocket::Safe_Delete()
264 if ( !ForDeletion() && !OnDestroy() ) {
265 // Paranoia is back.
266 SetNotify(0);
267 Notify(false);
268 // lfroen: first of all - stop handler
269 m_ForDeletion = true;
271 if (m_client) {
272 m_client->SetSocket( NULL );
273 m_client = NULL;
276 byConnected = ES_DISCONNECTED;
277 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
278 Destroy();
283 bool CClientTCPSocket::ProcessPacket(const byte* buffer, uint32 size, uint8 opcode)
285 #ifdef __PACKET_RECV_DUMP__
286 //printf("Rec: OPCODE %x \n",opcode);
287 DumpMem(buffer, size);
288 #endif
289 if (!m_client && opcode != OP_HELLO) {
290 throw wxString(wxT("Asks for something without saying hello"));
291 } else if (m_client && opcode != OP_HELLO && opcode != OP_HELLOANSWER) {
292 m_client->CheckHandshakeFinished(OP_EDONKEYPROT, opcode);
295 switch(opcode) {
296 case OP_HELLOANSWER: { // 0.43b
297 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HELLOANSWER from ") + m_client->GetFullIP());
298 theStats::AddDownOverheadOther(size);
299 m_client->ProcessHelloAnswer(buffer, size);
301 // start secure identification, if
302 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
303 // - we have received eMule-OP_HELLOANSWER (new eMule)
304 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
305 m_client->InfoPacketsReceived();
308 // Socket might die because of sending in InfoPacketsReceived, so check
309 if (m_client) {
310 m_client->ConnectionEstablished();
313 // Socket might die on ConnectionEstablished somehow. Check it.
314 if (m_client) {
315 Notify_UploadCtrlRefreshClient( m_client );
318 break;
320 case OP_HELLO: { // 0.43b
322 theStats::AddDownOverheadOther(size);
323 bool bNewClient = !m_client;
324 if (bNewClient) {
325 // create new client to save standart informations
326 m_client = new CUpDownClient(this);
329 // Do not move up!
330 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HELLO from ") + m_client->GetFullIP() );
332 bool bIsMuleHello = false;
334 try{
335 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
336 } catch(...) {
337 if (bNewClient && m_client) {
338 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
339 m_client->Safe_Delete();
340 m_client = NULL;
342 throw;
345 if (thePrefs::ParanoidFilter() && !IsLowID(m_client->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid()))) {
346 wxString reason = wxT("Client claims a different IP from the one we received the hello packet from: ");
347 reason += Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
348 AddDebugLogLineM(false, logClient, reason);
349 if (bNewClient) {
350 m_client->Safe_Delete();
351 m_client = NULL;
353 Disconnect(wxT("Paranoid disconecting: ") + reason);
354 return false;
357 // if IP is filtered, dont reply but disconnect...
358 if (theApp->ipfilter->IsFiltered(m_client->GetIP())) {
359 if (bNewClient) {
360 m_client->Safe_Delete();
361 m_client = NULL;
363 Disconnect(wxT("IPFilter"));
364 return false;
367 wxASSERT(m_client);
369 // now we check if we now this client already. if yes this socket will
370 // be attached to the known client, the new client will be deleted
371 // and the var. "client" will point to the known client.
372 // if not we keep our new-constructed client ;)
373 if (theApp->clientlist->AttachToAlreadyKnown(&m_client,this)) {
374 // update the old client informations
375 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
376 } else {
377 theApp->clientlist->AddClient(m_client);
378 m_client->SetCommentDirty();
380 Notify_UploadCtrlRefreshClient( m_client );
381 // send a response packet with standart informations
382 if ((m_client->GetHashType() == SO_EMULE) && !bIsMuleHello) {
383 m_client->SendMuleInfoPacket(false);
386 // Client might die from Sending in SendMuleInfoPacket, so check
387 if ( m_client ) {
388 m_client->SendHelloAnswer();
391 // Kry - If the other side supports it, send OS_INFO
392 // Client might die from Sending in SendHelloAnswer, so check
393 if (m_client && m_client->GetOSInfoSupport()) {
394 m_client->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
397 // Client might die from Sending in SendMuleInfoPacket, so check
398 if ( m_client ) {
399 m_client->ConnectionEstablished();
402 // start secure identification, if
403 // - we have received eMule-OP_HELLO (new eMule)
404 if (m_client && m_client->GetInfoPacketsReceived() == IP_BOTH) {
405 m_client->InfoPacketsReceived();
408 break;
410 case OP_REQUESTFILENAME: { // 0.43b
411 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client->GetFullIP() );
413 theStats::AddDownOverheadFileRequest(size);
414 // IP banned, no answer for this request
415 if (m_client->IsBanned()) {
416 break;
418 if (size >= 16) {
419 if (!m_client->GetWaitStartTime()) {
420 m_client->SetWaitStartTime();
422 CMemFile data_in(buffer, size);
423 CMD4Hash reqfilehash = data_in.ReadHash();
424 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
425 if ( reqfile == NULL ) {
426 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
427 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
428 break;
431 // if we are downloading this file, this could be a new source
432 // no passive adding of files with only one part
433 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
434 if (thePrefs::GetMaxSourcePerFile() >
435 ((CPartFile*)reqfile)->GetSourceCount()) {
436 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
440 // check to see if this is a new file they are asking for
441 if (m_client->GetUploadFileID() != reqfilehash) {
442 m_client->SetCommentDirty();
445 m_client->SetUploadFileID(reqfile);
446 m_client->ProcessExtendedInfo(&data_in, reqfile);
448 // send filename etc
449 CMemFile data_out(128);
450 data_out.WriteHash(reqfile->GetFileHash());
452 // Since it's for somebody else to see, we need to send the prettified
453 // filename, rather than the (possibly) mangled actual filename.
454 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
456 CPacket* packet = new CPacket(data_out, OP_EDONKEYPROT, OP_REQFILENAMEANSWER);
457 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
458 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client->GetFullIP() );
459 SendPacket(packet,true);
461 // SendPacket might kill the socket, so check
462 if (m_client)
463 m_client->SendCommentInfo(reqfile);
465 break;
467 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
468 break;
470 case OP_SETREQFILEID: { // 0.43b EXCEPT track of bad clients
471 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SETREQFILEID from ") + m_client->GetFullIP() );
473 theStats::AddDownOverheadFileRequest(size);
475 if (m_client->IsBanned()) {
476 break;
479 // DbT:FileRequest
480 if (size == 16) {
481 if (!m_client->GetWaitStartTime()) {
482 m_client->SetWaitStartTime();
485 const CMD4Hash fileID(buffer);
486 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(fileID);
487 if ( reqfile == NULL ) {
488 reqfile = theApp->downloadqueue->GetFileByID(fileID);
489 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
490 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
491 replypacket->Copy16ToDataBuffer(fileID.GetHash());
492 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
493 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILERE to ") + m_client->GetFullIP() );
494 SendPacket(replypacket, true);
495 break;
499 // check to see if this is a new file they are asking for
500 if (m_client->GetUploadFileID() != fileID) {
501 m_client->SetCommentDirty();
504 m_client->SetUploadFileID(reqfile);
505 // send filestatus
506 CMemFile data(16+16);
507 data.WriteHash(reqfile->GetFileHash());
508 if (reqfile->IsPartFile()) {
509 ((CPartFile*)reqfile)->WritePartStatus(&data);
510 } else {
511 data.WriteUInt16(0);
513 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_FILESTATUS);
514 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
515 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILESTATUS to ") + m_client->GetFullIP() );
516 SendPacket(packet, true);
517 break;
519 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
520 break;
521 // DbT:End
524 case OP_FILEREQANSNOFIL: { // 0.43b protocol, lacks ZZ's download manager on swap
525 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client->GetFullIP() );
527 theStats::AddDownOverheadFileRequest(size);
528 if (size == 16) {
529 // if that client does not have my file maybe has another different
530 CPartFile* reqfile = theApp->downloadqueue->GetFileByID(CMD4Hash(buffer));
531 if ( reqfile) {
532 reqfile->AddDeadSource( m_client );
533 } else {
534 break;
537 // we try to swap to another file ignoring no needed parts files
538 switch (m_client->GetDownloadState()) {
539 case DS_CONNECTED:
540 case DS_ONQUEUE:
541 case DS_NONEEDEDPARTS:
542 if (!m_client->SwapToAnotherFile(true, true, true, NULL)) {
543 theApp->downloadqueue->RemoveSource(m_client);
545 break;
547 break;
549 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
550 break;
553 case OP_REQFILENAMEANSWER: { // 0.43b except check for bad clients
554 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client->GetFullIP() );
556 theStats::AddDownOverheadFileRequest(size);
557 CMemFile data(buffer, size);
558 CMD4Hash hash = data.ReadHash();
559 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
560 m_client->ProcessFileInfo(&data, file);
561 break;
564 case OP_FILESTATUS: { // 0.43b except check for bad clients
565 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILESTATUS from ") + m_client->GetFullIP() );
567 theStats::AddDownOverheadFileRequest(size);
568 CMemFile data(buffer, size);
569 CMD4Hash hash = data.ReadHash();
570 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
571 m_client->ProcessFileStatus(false, &data, file);
572 break;
575 case OP_STARTUPLOADREQ: {
576 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client->GetFullIP() );
578 theStats::AddDownOverheadFileRequest(size);
580 if (!m_client->CheckHandshakeFinished(OP_EDONKEYPROT, opcode)) {
581 break;
584 m_client->CheckForAggressive();
585 if ( m_client->IsBanned() ) {
586 break;
589 if (size == 16) {
590 const CMD4Hash fileID(buffer);
591 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(fileID);
592 if (reqfile) {
593 if (m_client->GetUploadFileID() != fileID) {
594 m_client->SetCommentDirty();
596 m_client->SetUploadFileID(reqfile);
597 m_client->SendCommentInfo(reqfile);
599 // Socket might die because of SendCommentInfo, so check
600 if (m_client)
601 theApp->uploadqueue->AddClientToQueue(m_client);
604 break;
607 case OP_QUEUERANK: { // 0.43b
608 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANK from ") + m_client->GetFullIP() );
610 theStats::AddDownOverheadFileRequest(size);
611 CMemFile data(buffer, size);
612 uint32 rank = data.ReadUInt32();
614 m_client->SetRemoteQueueRank(rank);
615 break;
618 case OP_ACCEPTUPLOADREQ: { // 0.42e (xcept khaos stats)
619 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client->GetFullIP() );
621 theStats::AddDownOverheadFileRequest(size);
622 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
623 if (m_client->GetDownloadState() == DS_ONQUEUE ) {
624 m_client->SetDownloadState(DS_DOWNLOADING);
625 m_client->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
626 m_client->SendBlockRequests();
628 } else {
629 if (!m_client->GetSentCancelTransfer()) {
630 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
631 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
632 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
633 m_client->SendPacket(packet,true,true);
635 // SendPacket can cause the socket to die, so check
636 if (m_client)
637 m_client->SetSentCancelTransfer(1);
640 if (m_client)
641 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
643 break;
646 case OP_REQUESTPARTS: { // 0.43b
647 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client->GetFullIP() );
649 theStats::AddDownOverheadFileRequest(size);
651 m_client->ProcessRequestPartsPacket(buffer, size, false);
653 break;
656 case OP_CANCELTRANSFER: { // 0.43b
657 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client->GetFullIP() );
659 theStats::AddDownOverheadFileRequest(size);
660 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
661 if ( CLogger::IsEnabled( logClient ) ) {
662 AddDebugLogLineM( false, logClient, m_client->GetUserName() + wxT(": Upload session ended due canceled transfer."));
664 break;
667 case OP_END_OF_DOWNLOAD: { // 0.43b except check for bad clients
668 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client->GetFullIP() );
670 theStats::AddDownOverheadFileRequest(size);
671 if (size>=16 && m_client->GetUploadFileID() == CMD4Hash(buffer)) {
672 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
673 if ( CLogger::IsEnabled( logClient ) ) {
674 AddDebugLogLineM( false, logClient, m_client->GetUserName() + wxT(": Upload session ended due ended transfer."));
677 break;
680 case OP_HASHSETREQUEST: { // 0.43b except check for bad clients
681 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client->GetFullIP() );
684 theStats::AddDownOverheadFileRequest(size);
685 if (size != 16) {
686 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
688 m_client->SendHashsetPacket(CMD4Hash(buffer));
689 break;
692 case OP_HASHSETANSWER: { // 0.43b
693 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client->GetFullIP() );
695 theStats::AddDownOverheadFileRequest(size);
696 m_client->ProcessHashSet(buffer, size);
697 break;
700 case OP_SENDINGPART: { // 0.47a
701 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART from ") + m_client->GetFullIP() );
703 if ( m_client->GetRequestFile() &&
704 !m_client->GetRequestFile()->IsStopped() &&
705 (m_client->GetRequestFile()->GetStatus() == PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
707 m_client->ProcessBlockPacket(buffer, size, false, false);
709 if ( m_client &&
710 ( m_client->GetRequestFile()->IsStopped() ||
711 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
712 m_client->GetRequestFile()->GetStatus() == PS_ERROR) ) {
713 if (!m_client->GetSentCancelTransfer()) {
714 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
715 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
716 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
717 m_client->SendPacket(packet,true,true);
719 // Socket might die because of SendPacket, so check
720 if (m_client)
721 m_client->SetSentCancelTransfer(1);
724 if (m_client)
725 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
727 } else {
728 if (!m_client->GetSentCancelTransfer()) {
729 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
730 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
731 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
732 m_client->SendPacket(packet,true,true);
734 // Socket might die because of SendPacket, so check
735 m_client->SetSentCancelTransfer(1);
737 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
739 break;
742 case OP_OUTOFPARTREQS: { // 0.43b
743 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client->GetFullIP() );
745 theStats::AddDownOverheadFileRequest(size);
746 if (m_client->GetDownloadState() == DS_DOWNLOADING) {
747 m_client->SetDownloadState(DS_ONQUEUE);
749 break;
752 case OP_CHANGE_CLIENT_ID: { // Kad reviewed
753 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client->GetFullIP() );
755 theStats::AddDownOverheadOther(size);
756 CMemFile data(buffer, size);
757 uint32 nNewUserID = data.ReadUInt32();
758 uint32 nNewServerIP = data.ReadUInt32();
760 if (IsLowID(nNewUserID)) { // client changed server and gots a LowID
761 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
762 if (pNewServer != NULL){
763 m_client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
764 m_client->SetServerIP(nNewServerIP);
765 m_client->SetServerPort(pNewServer->GetPort());
767 } else if (nNewUserID == m_client->GetIP()) { // client changed server and gots a HighID(IP)
768 m_client->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID));
769 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
770 if (pNewServer != NULL){
771 m_client->SetServerIP(nNewServerIP);
772 m_client->SetServerPort(pNewServer->GetPort());
776 break;
779 case OP_CHANGE_SLOT:{ // 0.43b
780 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client->GetFullIP() );
782 // sometimes sent by Hybrid
783 theStats::AddDownOverheadOther(size);
784 break;
787 case OP_MESSAGE: { // 0.43b
788 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MESSAGE from ") + m_client->GetFullIP() );
790 theStats::AddDownOverheadOther(size);
792 CMemFile message_file(buffer, size);
794 wxString message = message_file.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
795 if (IsMessageFiltered(message, m_client)) {
796 AddLogLineM( true, CFormat(_("Message filtered from '%s' (IP:%s)")) % m_client->GetUserName() % m_client->GetFullIP());
797 } else {
798 AddLogLineM( true, CFormat(_("New message from '%s' (IP:%s)")) % m_client->GetUserName() % m_client->GetFullIP());
800 Notify_ChatProcessMsg(GUI_ID(m_client->GetIP(),m_client->GetUserPort()), m_client->GetUserName() + wxT("|") + message);
802 break;
805 case OP_ASKSHAREDFILES: { // 0.43b (well, er, it does the same, but in our own way)
806 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
808 // client wants to know what we have in share, let's see if we allow him to know that
809 theStats::AddDownOverheadOther(size);
810 // IP banned, no answer for this request
811 if (m_client->IsBanned()) {
812 break;
815 if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
816 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
817 % m_client->GetUserName()
818 % m_client->GetUserIDHybrid() );
820 std::vector<CKnownFile*> list;
821 theApp->sharedfiles->CopyFileList(list);
823 CMemFile tempfile(80);
824 tempfile.WriteUInt32(list.size());
825 for (unsigned i = 0; i < list.size(); ++i) {
826 if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
827 theApp->sharedfiles->CreateOfferedFilePacket(list[i], &tempfile, NULL, m_client);
831 // create a packet and send it
832 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
833 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
834 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
835 SendPacket(replypacket, true, true);
836 } else {
837 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
838 % m_client->GetUserName()
839 % m_client->GetUserIDHybrid() );
841 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
842 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
843 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
844 SendPacket(replypacket, true, true);
847 break;
850 case OP_ASKSHAREDFILESANSWER: { // 0.43b
851 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
853 theStats::AddDownOverheadOther(size);
854 wxString EmptyStr;
855 m_client->ProcessSharedFileList(buffer, size, EmptyStr);
856 break;
859 case OP_ASKSHAREDDIRS: { // 0.43b
860 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
862 theStats::AddDownOverheadOther(size);
863 wxASSERT( size == 0 );
864 // IP banned, no answer for this request
865 if (m_client->IsBanned()) {
866 break;
868 if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
869 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
870 % m_client->GetUserName()
871 % m_client->GetUserIDHybrid() );
873 // This list will contain all (unique) folders.
874 std::list<CPath> foldersToSend;
876 // The shared folders
877 const unsigned folderCount = theApp->glob_prefs->shareddir_list.size();
878 for (unsigned i = 0; i < folderCount; ++i) {
879 foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]);
882 // ... the categories folders ... (category 0 -> incoming)
883 for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) {
884 foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path);
887 // ... and the Magic thing from the eDonkey Hybrids...
888 foldersToSend.push_back(CPath(OP_INCOMPLETE_SHARED_FILES));
890 // Strip duplicates
891 foldersToSend.sort();
892 foldersToSend.unique();
894 // Send packet.
895 CMemFile tempfile(80);
896 tempfile.WriteUInt32(foldersToSend.size());
898 std::list<CPath>::iterator it = foldersToSend.begin();
899 for (; it != foldersToSend.end(); ++it) {
900 // We need to send the 'raw' filename, so we can recognize it again.
901 tempfile.WriteString(it->GetRaw(), m_client->GetUnicodeSupport());
904 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS);
905 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
906 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client->GetFullIP() );
907 SendPacket(replypacket, true, true);
908 } else {
909 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
910 % m_client->GetUserName()
911 % m_client->GetUserIDHybrid() );
913 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
914 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
915 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
916 SendPacket(replypacket, true, true);
919 break;
922 case OP_ASKSHAREDFILESDIR: { // 0.43b
923 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
925 theStats::AddDownOverheadOther(size);
926 // IP banned, no answer for this request
927 if (m_client->IsBanned()) {
928 break;
930 CMemFile data(buffer, size);
932 wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
933 if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
934 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
935 wxASSERT( data.GetPosition() == data.GetLength() );
937 CKnownFilePtrList list;
939 if (strReqDir == OP_INCOMPLETE_SHARED_FILES) {
940 // get all shared files from download queue
941 int iQueuedFiles = theApp->downloadqueue->GetFileCount();
942 for (int i = 0; i < iQueuedFiles; i++) {
943 CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i);
944 if (pFile == NULL || pFile->GetStatus(true) != PS_READY) {
945 continue;
948 list.push_back(pFile);
950 } else {
951 theApp->sharedfiles->GetSharedFilesByDirectory(strReqDir, list);
954 CMemFile tempfile(80);
955 tempfile.WriteString(strReqDir, m_client->GetUnicodeSupport());
956 tempfile.WriteUInt32(list.size());
958 while (!list.empty()) {
959 if (!list.front()->IsLargeFile() || m_client->SupportsLargeFiles()) {
960 theApp->sharedfiles->CreateOfferedFilePacket(list.front(), &tempfile, NULL, m_client);
963 list.pop_front();
966 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS);
967 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
968 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client->GetFullIP() );
969 SendPacket(replypacket, true, true);
970 } else {
971 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
973 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
974 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
975 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
976 SendPacket(replypacket, true, true);
978 break;
981 case OP_ASKSHAREDDIRSANS:{ // 0.43b
982 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
984 theStats::AddDownOverheadOther(size);
985 if (m_client->GetFileListRequested() == 1){
986 CMemFile data(buffer, size);
987 uint32 uDirs = data.ReadUInt32();
988 for (uint32 i = 0; i < uDirs; i++){
989 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
990 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
991 % m_client->GetUserName()
992 % m_client->GetUserIDHybrid()
993 % strDir );
995 CMemFile tempfile(80);
996 tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
997 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
998 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
999 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client->GetFullIP() );
1000 SendPacket(replypacket, true, true);
1002 wxASSERT( data.GetPosition() == data.GetLength() );
1003 m_client->SetFileListRequested(uDirs);
1004 } else {
1005 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1006 % m_client->GetUserName()
1007 % m_client->GetUserIDHybrid() );
1009 break;
1012 case OP_ASKSHAREDFILESDIRANS: { // 0.43b
1013 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
1015 theStats::AddDownOverheadOther(size);
1016 CMemFile data(buffer, size);
1017 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1019 if (m_client->GetFileListRequested() > 0){
1020 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1021 % m_client->GetUserName()
1022 % m_client->GetUserIDHybrid()
1023 % strDir );
1025 m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
1026 if (m_client->GetFileListRequested() == 0) {
1027 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1028 % m_client->GetUserName()
1029 % m_client->GetUserIDHybrid() );
1031 } else {
1032 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1033 % m_client->GetUserName()
1034 % m_client->GetUserIDHybrid() );
1036 break;
1039 case OP_ASKSHAREDDENIEDANS:
1040 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
1042 theStats::AddDownOverheadOther(size);
1043 wxASSERT( size == 0 );
1044 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1045 % m_client->GetUserName()
1046 % m_client->GetUserIDHybrid() );
1048 m_client->SetFileListRequested(0);
1049 break;
1051 default:
1052 theStats::AddDownOverheadOther(size);
1053 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1054 return false;
1057 return true;
1061 bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1063 #ifdef __PACKET_RECV_DUMP__
1064 //printf("Rec: OPCODE %x \n",opcode);
1065 DumpMem(buffer,size);
1066 #endif
1068 // 0.42e - except the catchs on mem exception and file exception
1069 if (!m_client) {
1070 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1073 if (!client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1074 // Here comes a extended packet without finishing the hanshake.
1075 // IMHO, we should disconnect the client.
1076 throw wxString(wxT("Client send extended packet before finishing handshake"));
1079 switch(opcode) {
1080 case OP_MULTIPACKET_EXT:
1081 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1082 case OP_MULTIPACKET: {
1083 if (opcode == OP_MULTIPACKET) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1085 theStats::AddDownOverheadFileRequest(size);
1087 if (m_client->IsBanned()) {
1088 break;
1091 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1092 // Here comes a extended packet without finishing the hanshake.
1093 // IMHO, we should disconnect the client.
1094 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1097 CMemFile data_in(buffer, size);
1098 CMD4Hash reqfilehash = data_in.ReadHash();
1099 uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1101 bool file_not_found = false;
1102 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1103 if ( reqfile == NULL ){
1104 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1105 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1106 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a non-shared file"));
1107 file_not_found = true;
1111 if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1112 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1113 file_not_found = true;
1116 if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1117 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1118 file_not_found = true;
1121 if (file_not_found) {
1122 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1123 replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1124 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1125 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1126 SendPacket(replypacket, true);
1127 break;
1130 if (!m_client->GetWaitStartTime()) {
1131 m_client->SetWaitStartTime();
1133 // if we are downloading this file, this could be a new source
1134 // no passive adding of files with only one part
1135 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1136 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount()) {
1137 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
1140 // check to see if this is a new file they are asking for
1141 if (m_client->GetUploadFileID() != reqfilehash) {
1142 m_client->SetCommentDirty();
1144 m_client->SetUploadFileID(reqfile);
1145 CMemFile data_out(128);
1146 data_out.WriteHash(reqfile->GetFileHash());
1147 while(data_in.GetLength()-data_in.GetPosition()) {
1148 if (!m_client) {
1149 throw wxString(wxT("Client suddenly disconnected"));
1151 uint8 opcode_in = data_in.ReadUInt8();
1152 switch(opcode_in) {
1153 case OP_REQUESTFILENAME: {
1154 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1155 m_client->ProcessExtendedInfo(&data_in, reqfile);
1156 data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1158 // Since it's for somebody else to see, we need to send the prettified
1159 // filename, rather than the (possibly) mangled actual filename
1160 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1161 break;
1163 case OP_AICHFILEHASHREQ: {
1164 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1165 if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1166 && reqfile->GetAICHHashset()->HasValidMasterHash())
1168 data_out.WriteUInt8(OP_AICHFILEHASHANS);
1169 reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1171 break;
1173 case OP_SETREQFILEID: {
1174 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1175 data_out.WriteUInt8(OP_FILESTATUS);
1176 if (reqfile->IsPartFile()) {
1177 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1178 } else {
1179 data_out.WriteUInt16(0);
1181 break;
1183 //We still send the source packet separately..
1184 //We could send it within this packet.. If agreeded, I will fix it..
1185 case OP_REQUESTSOURCES2:
1186 case OP_REQUESTSOURCES: {
1187 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1188 uint8 byRequestedVersion = 0;
1189 uint16 byRequestedOptions = 0;
1190 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1191 byRequestedVersion = data_in.ReadUInt8();
1192 byRequestedOptions = data_in.ReadUInt16();
1195 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1197 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1198 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1199 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1200 if(
1201 //if not complete and file is rare
1202 ( reqfile->IsPartFile()
1203 && (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1204 && ((CPartFile*)reqfile)->GetSourceCount() <= RARE_FILE
1205 ) ||
1206 //OR if file is not rare or if file is complete
1207 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1210 m_client->SetLastSrcReqTime();
1211 CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1212 if(tosend) {
1213 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1214 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1215 SendPacket(tosend, true);
1219 break;
1224 if( data_out.GetLength() > 16 ) {
1225 CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1226 theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1227 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1228 SendPacket(reply, true);
1230 break;
1233 case OP_MULTIPACKETANSWER: { // 0.43b
1234 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1236 theStats::AddDownOverheadFileRequest(size);
1238 if (m_client->IsBanned()) {
1239 break;
1242 if( m_client->GetKadPort() ) {
1243 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort());
1246 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1247 // Here comes a extended packet without finishing the hanshake.
1248 // IMHO, we should disconnect the client.
1249 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1252 CMemFile data_in(buffer, size);
1253 CMD4Hash reqfilehash = data_in.ReadHash();
1254 const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1255 //Make sure we are downloading this file.
1256 if ( !reqfile ) {
1257 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1259 if ( !m_client->GetRequestFile() ) {
1261 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1263 if (reqfile != m_client->GetRequestFile()) {
1264 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1266 while (data_in.GetLength()-data_in.GetPosition()) {
1267 // Some of the cases down there can actually send a packet and lose the client
1268 if (!m_client) {
1269 throw wxString(wxT("Client suddenly disconnected"));
1271 uint8 opcode_in = data_in.ReadUInt8();
1272 switch(opcode_in) {
1273 case OP_REQFILENAMEANSWER: {
1274 if (!m_client) {
1275 throw wxString(wxT("Client suddenly disconnected"));
1276 } else {
1277 m_client->ProcessFileInfo(&data_in, reqfile);
1279 break;
1281 case OP_FILESTATUS: {
1282 if (!m_client) {
1283 throw wxString(wxT("Client suddenly disconnected"));
1284 } else {
1285 m_client->ProcessFileStatus(false, &data_in, reqfile);
1287 break;
1289 case OP_AICHFILEHASHANS: {
1290 if (!m_client) {
1291 throw wxString(wxT("Client suddenly disconnected"));
1292 } else {
1293 m_client->ProcessAICHFileHash(&data_in, reqfile);
1295 break;
1300 break;
1303 case OP_EMULEINFO: { // 0.43b
1304 theStats::AddDownOverheadOther(size);
1306 if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1307 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1309 // If it's not a OS Info packet, is an old client
1310 // start secure identification, if
1311 // - we have received eD2K and eMule info (old eMule)
1312 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1313 m_client->InfoPacketsReceived();
1315 m_client->SendMuleInfoPacket(true);
1316 } else {
1317 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1319 break;
1321 case OP_EMULEINFOANSWER: { // 0.43b
1322 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1323 theStats::AddDownOverheadOther(size);
1325 m_client->ProcessMuleInfoPacket(buffer, size);
1326 // start secure identification, if
1327 // - we have received eD2K and eMule info (old eMule)
1329 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1330 m_client->InfoPacketsReceived();
1333 break;
1336 case OP_SECIDENTSTATE:{ // 0.43b
1337 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1339 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1340 // Here comes a extended packet without finishing the hanshake.
1341 // IMHO, we should disconnect the client.
1342 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1344 m_client->ProcessSecIdentStatePacket(buffer, size);
1345 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1346 if (m_client) {
1347 int SecureIdentState = m_client->GetSecureIdentState();
1348 if (SecureIdentState == IS_SIGNATURENEEDED) {
1349 m_client->SendSignaturePacket();
1350 } else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1351 m_client->SendPublicKeyPacket();
1352 // SendPublicKeyPacket() might cause the socket to die, so check
1353 if ( m_client ) {
1354 m_client->SendSignaturePacket();
1358 break;
1361 case OP_PUBLICKEY: { // 0.43b
1362 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1364 if (m_client->IsBanned() ){
1365 break;
1368 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1369 // Here comes a extended packet without finishing the hanshake.
1370 // IMHO, we should disconnect the client.
1371 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1374 m_client->ProcessPublicKeyPacket(buffer, size);
1375 break;
1377 case OP_SIGNATURE:{ // 0.43b
1378 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1380 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1381 // Here comes a extended packet without finishing the hanshake.
1382 // IMHO, we should disconnect the client.
1383 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1386 m_client->ProcessSignaturePacket(buffer, size);
1387 break;
1389 case OP_SENDINGPART_I64:
1390 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1391 case OP_COMPRESSEDPART_I64:
1392 if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1393 case OP_COMPRESSEDPART: { // 0.47a
1394 if (opcode == OP_COMPRESSEDPART) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1396 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1397 // Here comes a extended packet without finishing the hanshake.
1398 // IMHO, we should disconnect the client.
1399 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1402 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1404 m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1406 if (m_client && (
1407 m_client->GetRequestFile()->IsStopped() ||
1408 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1409 m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1410 if (!m_client->GetSentCancelTransfer()) {
1411 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1412 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1413 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1414 m_client->SendPacket(packet,true,true);
1416 if (m_client) {
1417 m_client->SetSentCancelTransfer(1);
1421 if ( m_client ) {
1422 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1425 } else {
1426 if (!m_client->GetSentCancelTransfer()) {
1427 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1428 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1429 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1430 m_client->SendPacket(packet,true,true);
1432 if ( m_client ) {
1433 m_client->SetSentCancelTransfer(1);
1437 if ( m_client ) {
1438 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1441 break;
1443 case OP_REQUESTPARTS_I64: {
1444 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP() );
1446 theStats::AddDownOverheadFileRequest(size);
1448 m_client->ProcessRequestPartsPacket(buffer, size, true);
1450 break;
1452 case OP_QUEUERANKING: { // 0.43b
1453 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP() );
1455 theStats::AddDownOverheadOther(size);
1457 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1458 // Here comes a extended packet without finishing the hanshake.
1459 // IMHO, we should disconnect the client.
1460 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1463 if (size != 12) {
1464 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1467 uint16 newrank = PeekUInt16(buffer);
1468 m_client->SetRemoteQueueFull(false);
1469 m_client->SetRemoteQueueRank(newrank);
1470 break;
1472 case OP_REQUESTSOURCES:{
1473 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP() );
1475 theStats::AddDownOverheadSourceExchange(size);
1477 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1478 // Here comes an extended packet without finishing the handshake.
1479 // IMHO, we should disconnect the client.
1480 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1483 uint8 byRequestedVersion = 0;
1484 uint16 byRequestedOptions = 0;
1485 CMemFile data_in(buffer, size);
1486 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1487 byRequestedVersion = data_in.ReadUInt8();
1488 byRequestedOptions = data_in.ReadUInt16();
1491 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1492 if(size != 16) {
1493 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1495 //first check shared file list, then download list
1496 const CMD4Hash fileID(buffer);
1497 CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1498 if(!file) {
1499 file = theApp->downloadqueue->GetFileByID(fileID);
1501 if(file) {
1502 // There are some clients which do not follow the correct protocol procedure of sending
1503 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1504 // are doing this, they will not get the optimal set of sources which we could offer if
1505 // they would follow the above noted protocol sequence. They better do it the right way
1506 // or they will get just a random set of sources because we do not know their download
1507 // part status which may get cleared with the call of 'SetUploadFileID'.
1508 m_client->SetUploadFileID(file);
1510 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1511 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1512 if(
1513 //if not complete and file is rare, allow once every 40 minutes
1514 ( file->IsPartFile() &&
1515 ((CPartFile*)file)->GetSourceCount() <= RARE_FILE &&
1516 (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1517 ) ||
1518 //OR if file is not rare or if file is complete, allow every 90 minutes
1519 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1522 m_client->SetLastSrcReqTime();
1523 CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1524 if(tosend) {
1525 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1526 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1527 SendPacket(tosend, true, true);
1532 break;
1534 case OP_ANSWERSOURCES: {
1535 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP() );
1537 theStats::AddDownOverheadSourceExchange(size);
1539 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1540 // Here comes a extended packet without finishing the hanshake.
1541 // IMHO, we should disconnect the client.
1542 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1545 CMemFile data(buffer, size);
1546 CMD4Hash hash = data.ReadHash();
1547 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1548 if(file){
1549 if (file->IsPartFile()){
1550 //set the client's answer time
1551 m_client->SetLastSrcAnswerTime();
1552 //and set the file's last answer time
1553 ((CPartFile*)file)->SetLastAnsweredTime();
1555 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1558 break;
1560 case OP_ANSWERSOURCES2: {
1561 //printf("Received OP_ANSWERSOURCES2\n");
1562 theStats::AddDownOverheadSourceExchange(size);
1564 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1565 // Here comes a extended packet without finishing the hanshake.
1566 // IMHO, we should disconnect the client.
1567 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1570 CMemFile data(buffer, size);
1571 uint8 byVersion = data.ReadUInt8();
1572 CMD4Hash hash = data.ReadHash();
1573 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1574 if (file){
1575 if (file->IsPartFile()){
1576 //set the client's answer time
1577 m_client->SetLastSrcAnswerTime();
1578 //and set the file's last answer time
1579 ((CPartFile*)file)->SetLastAnsweredTime();
1580 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1583 break;
1585 case OP_FILEDESC: { // 0.43b
1586 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP() );
1588 theStats::AddDownOverheadFileRequest(size);
1590 if (!m_client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1591 // Here comes a extended packet without finishing the hanshake.
1592 // IMHO, we should disconnect the client.
1593 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1596 m_client->ProcessMuleCommentPacket(buffer, size);
1597 break;
1600 // Unsupported
1601 case OP_REQUESTPREVIEW: {
1602 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client->GetFullIP() );
1603 break;
1605 // Unsupported
1606 case OP_PREVIEWANSWER: {
1607 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP() );
1608 break;
1611 case OP_PUBLICIP_ANSWER: {
1612 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP() );
1613 theStats::AddDownOverheadOther(size);
1614 m_client->ProcessPublicIPAnswer(buffer, size);
1615 break;
1617 case OP_PUBLICIP_REQ: {
1618 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP() );
1619 theStats::AddDownOverheadOther(size);
1620 CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1621 pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1622 theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1623 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1624 SendPacket(pPacket);
1625 break;
1627 case OP_AICHANSWER: {
1628 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP() );
1629 theStats::AddDownOverheadOther(size);
1630 m_client->ProcessAICHAnswer(buffer, size);
1631 break;
1633 case OP_AICHREQUEST: {
1634 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP() );
1635 theStats::AddDownOverheadOther(size);
1636 m_client->ProcessAICHRequest(buffer, size);
1637 break;
1639 case OP_AICHFILEHASHANS: {
1640 // those should not be received normally, since we should only get those in MULTIPACKET
1641 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP() );
1642 theStats::AddDownOverheadOther(size);
1643 CMemFile data(buffer, size);
1644 m_client->ProcessAICHFileHash(&data, NULL);
1645 break;
1647 case OP_AICHFILEHASHREQ: {
1648 // those should not be received normally, since we should only get those in MULTIPACKET
1649 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP() );
1650 CMemFile data(buffer, size);
1651 CMD4Hash hash = data.ReadHash();
1652 CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1653 if (pPartFile == NULL){
1654 break;
1657 if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1658 && pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1659 CMemFile data_out;
1660 data_out.WriteHash(hash);
1661 pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1662 CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1663 theStats::AddUpOverheadOther(packet->GetPacketSize());
1664 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1665 SendPacket(packet);
1667 break;
1669 case OP_CALLBACK: {
1670 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1671 theStats::AddDownOverheadFileRequest(size);
1672 if(!Kademlia::CKademlia::IsRunning()) {
1673 break;
1675 CMemFile data(buffer, size);
1676 CUInt128 check = data.ReadUInt128();
1677 check.XOR(Kademlia::CUInt128(true));
1678 if( check.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1679 break;
1681 CUInt128 fileid = data.ReadUInt128();
1682 byte fileid2[16];
1683 fileid.ToByteArray(fileid2);
1684 const CMD4Hash fileHash(fileid2);
1685 if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1686 if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1687 break;
1691 uint32 ip = data.ReadUInt32();
1692 uint16 tcp = data.ReadUInt16();
1693 CUpDownClient* callback;
1694 callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1695 if( callback == NULL ) {
1696 //#warning Do we actually have to check friend status here?
1697 callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1698 theApp->clientlist->AddClient(callback);
1700 callback->TryToConnect(true);
1701 break;
1704 case OP_BUDDYPING: {
1705 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP() );
1706 theStats::AddDownOverheadKad(size);
1708 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1709 if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1710 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1711 break;
1714 m_client->SetLastBuddyPingPongTime();
1715 CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1716 theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1717 AddDebugLogLineM(false, logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1718 SendPacket(replypacket);
1719 break;
1721 case OP_BUDDYPONG: {
1722 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP() );
1723 theStats::AddDownOverheadKad(size);
1725 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1726 if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1727 //This pong was not from our buddy or wrong version. Ignore
1728 break;
1730 m_client->SetLastBuddyPingPongTime();
1731 //All this is for is to reset our socket timeout.
1732 break;
1734 case OP_REASKCALLBACKTCP: {
1735 theStats::AddDownOverheadFileRequest(size);
1736 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1737 if (buddy != m_client) {
1738 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1739 //This callback was not from our buddy.. Ignore.
1740 break;
1742 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1743 CMemFile data_in(buffer, size);
1744 uint32 destip = data_in.ReadUInt32();
1745 uint16 destport = data_in.ReadUInt16();
1746 CMD4Hash hash = data_in.ReadHash();
1747 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1749 bool bSenderMultipleIpUnknown = false;
1750 CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1751 if (!reqfile) {
1752 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1753 CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1754 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1755 if (sender) {
1756 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1757 } else {
1758 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1760 break;
1763 if (sender) {
1764 //Make sure we are still thinking about the same file
1765 if (hash == sender->GetUploadFileID()) {
1766 sender->AddAskedCount();
1767 sender->SetLastUpRequest();
1768 //I messed up when I first added extended info to UDP
1769 //I should have originally used the entire ProcessExtenedInfo the first time.
1770 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1771 //For now on, we should not have to change anything here if we change
1772 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1773 //Update extended info.
1774 if (sender->GetUDPVersion() > 3) {
1775 sender->ProcessExtendedInfo(&data_in, reqfile);
1776 } else if (sender->GetUDPVersion() > 2) {
1777 //Update our complete source counts.
1778 uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1779 uint16 nCompleteCountNew = data_in.ReadUInt16();
1780 sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1781 if (nCompleteCountLast != nCompleteCountNew) {
1782 reqfile->UpdatePartsInfo();
1786 CMemFile data_out(128);
1787 if(sender->GetUDPVersion() > 3) {
1788 if (reqfile->IsPartFile()) {
1789 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1790 } else {
1791 data_out.WriteUInt16(0);
1795 data_out.WriteUInt16(theApp->uploadqueue->GetWaitingPosition(sender));
1796 CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1797 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1798 AddDebugLogLineM( false, logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP() );
1799 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1800 } else {
1801 AddDebugLogLineM(false, logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1803 } else {
1804 if (!bSenderMultipleIpUnknown){
1805 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1806 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP() );
1807 CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1808 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1809 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1811 } else {
1812 AddDebugLogLineM(false, logRemoteClient, CFormat(wxT("OP_REASKCALLBACKTCP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u")) % Uint32toStringIP(destip) % destport);
1815 break;
1817 default:
1818 theStats::AddDownOverheadOther(size);
1819 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode,opcode) + m_client->GetFullIP());
1820 break;
1823 return true;
1826 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1828 #ifdef __PACKET_RECV_DUMP__
1829 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1830 DumpMem(buffer,size);
1831 #endif
1833 if (!m_client) {
1834 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1837 CMemFile data(buffer, size);
1838 try {
1839 switch(opcode) {
1840 case OP_QUEUERANK: {
1841 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1843 uint8 numtags = data.ReadUInt8();
1844 wxASSERT(numtags == 1);
1846 m_client->SetRemoteQueueRank(data.GetIntTagValue());
1848 theStats::AddDownOverheadFileRequest(size);
1849 break;
1852 case OP_REQUESTPARTS: {
1853 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1855 m_client->ProcessRequestPartsPacketv2(data);
1857 theStats::AddDownOverheadFileRequest(size);
1858 break;
1861 default:
1862 theStats::AddDownOverheadOther(size);
1863 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1865 } catch (...) {
1866 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data.GetPosition(), opcode, opcode) + m_client->GetFullIP());
1867 throw;
1870 return true;
1873 void CClientTCPSocket::OnConnect(int nErrorCode)
1875 if (nErrorCode) {
1876 OnError(nErrorCode);
1877 } else if (!m_client) {
1878 // and now? Disconnect? not?
1879 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1880 } else if (!m_client->SendHelloPacket()) {
1881 // and now? Disconnect? not?
1882 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1883 } else {
1884 ResetTimeOutTimer();
1889 void CClientTCPSocket::OnSend(int nErrorCode)
1891 ResetTimeOutTimer();
1892 CEMSocket::OnSend(nErrorCode);
1896 void CClientTCPSocket::OnReceive(int nErrorCode)
1898 ResetTimeOutTimer();
1899 // We might have updated ipfilter
1900 wxASSERT(m_remoteip);
1902 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1903 if (m_client) {
1904 m_client->Safe_Delete();
1906 Safe_Delete();
1907 AddDebugLogLineM( false, logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1908 } else {
1909 CEMSocket::OnReceive(nErrorCode);
1914 void CClientTCPSocket::OnError(int nErrorCode)
1916 //printf("* Called OnError for %p\n",this);
1917 // 0.42e + Kry changes for handling of socket lost events
1918 wxString strError;
1920 if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1921 if (m_client) {
1922 if (!m_client->GetUserName().IsEmpty()) {
1923 strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1924 } else {
1925 strError = wxT("An unnamed client");
1927 strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1928 } else {
1929 strError = wxT("A client ");
1931 if (nErrorCode == 0) {
1932 strError += wxT("closed connection.");
1933 } else if (nErrorCode == 0xFEFF) {
1934 strError += wxT(" caused a wxSOCKET_LOST event.");
1935 } else {
1936 strError += wxT("caused a socket blocking error.");
1938 } else {
1939 if ( CLogger::IsEnabled( logClient ) && (nErrorCode != 107)) {
1940 // 0 -> No Error / Disconect
1941 // 107 -> Transport endpoint is not connected
1942 if (m_client) {
1943 if (!m_client->GetUserName().IsEmpty()) {
1944 strError = wxT("OnError: Client '") + m_client->GetUserName() +
1945 wxT("' (IP:") + m_client->GetFullIP() +
1946 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
1947 } else {
1948 strError = wxT("OnError: Unknown client (IP:") +
1949 m_client->GetFullIP() +
1950 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
1952 } else {
1953 strError = wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
1954 nErrorCode);
1956 } else {
1957 strError = wxT("Error 107 (Transport endpoint is not connected)");
1961 Disconnect(strError);
1965 bool CClientTCPSocket::PacketReceived(CPacket* packet)
1967 // 0.42e
1968 bool bResult = false;
1969 uint32 uRawSize = packet->GetPacketSize();
1971 AddDebugLogLineM( false, logRemoteClient,
1972 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1973 % packet->GetProtocol()
1974 % packet->GetOpCode()
1975 % packet->GetPacketSize()
1976 % ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
1979 wxString exception;
1981 try {
1982 bool process = true;
1984 if ((packet->GetProtocol() == OP_PACKEDPROT) ||
1985 (packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
1987 if (!packet->UnPackPacket()) {
1988 AddDebugLogLineM( false, logZLib, wxT("Failed to decompress client TCP packet."));
1989 bResult = false;
1990 process = false;
1991 } else {
1992 AddDebugLogLineM(false, logRemoteClient,
1993 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
1994 packet->GetProtocol(),
1995 packet->GetOpCode(),
1996 packet->GetPacketSize())
2001 if (process) {
2002 switch (packet->GetProtocol()) {
2003 case OP_EDONKEYPROT:
2004 bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
2005 break;
2006 case OP_EMULEPROT:
2007 bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2008 break;
2009 case OP_ED2KV2HEADER:
2010 bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2011 break;
2012 case OP_ED2KV2PACKEDPROT:
2013 case OP_PACKEDPROT:
2014 // Packed inside packed?
2015 wxASSERT(0);
2016 break;
2017 default: {
2018 theStats::AddDownOverheadOther(uRawSize);
2019 if (m_client) {
2020 m_client->SetDownloadState(DS_ERROR);
2022 Disconnect(wxT("Unknown protocol"));
2023 bResult = false;
2027 } catch (const CEOFException& err) {
2028 exception = wxT("EOF exception: ") + err.what();
2029 } catch (const CInvalidPacket& err) {
2030 exception = wxT("InvalidPacket exception: ") + err.what();
2031 } catch (const wxString& error) {
2032 exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2035 if (!exception.IsEmpty()) {
2036 AddDebugLogLineM( false, logPacketErrors,
2037 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2038 % exception
2039 % packet->GetProtocol()
2040 % packet->GetOpCode()
2041 % packet->GetPacketSize()
2042 % ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2045 if (m_client) {
2046 m_client->SetDownloadState(DS_ERROR);
2049 AddDebugLogLineM( false, logClient,
2050 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2051 % ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2052 % ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2053 % exception
2056 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2059 return bResult;
2063 bool CClientTCPSocket::IsMessageFiltered(const wxString& Message, CUpDownClient* client) {
2065 bool filtered = false;
2066 // If we're chatting to the guy, we don't want to filter!
2067 if (client->GetChatState() != MS_CHATTING) {
2068 if (thePrefs::MsgOnlyFriends() && !client->IsFriend()) {
2069 filtered = true;
2070 } else if (thePrefs::MsgOnlySecure() && client->GetUserName().IsEmpty() ) {
2071 filtered = true;
2072 } else if (thePrefs::MustFilterMessages()) {
2073 filtered = thePrefs::IsMessageFiltered(Message);
2076 return filtered;
2079 SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2081 SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2083 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2084 ResetTimeOutTimer();
2087 return returnStatus;
2091 SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2093 SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2095 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2096 ResetTimeOutTimer();
2099 return returnStatus;
2103 void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2105 ResetTimeOutTimer();
2106 CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2108 // File_checked_for_headers