Upstream tarball 10143
[amule.git] / src / ClientTCPSocket.cpp
blob33831e2ca1fd64e08cadf0cd944f0079087fcb18
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 AddDebugLogLineM(false, 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 AddDebugLogLineM(false, logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Filtered IP)"));
180 return false;
181 } else if (theApp->clientlist->IsBannedClient(m_remoteip)) {
182 AddDebugLogLineM(false, logClient, wxT("Denied connection from ") + addr.IPAddress() + wxT("(Banned IP)"));
183 return false;
184 } else {
185 AddDebugLogLineM(false, 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(wxString::Format(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 if ( !ForDeletion() && !OnDestroy() ) {
276 // Paranoia is back.
277 SetNotify(0);
278 Notify(false);
279 // lfroen: first of all - stop handler
280 m_ForDeletion = true;
282 if (m_client) {
283 m_client->SetSocket( NULL );
284 m_client = NULL;
287 byConnected = ES_DISCONNECTED;
288 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
289 Destroy();
294 bool CClientTCPSocket::ProcessPacket(const byte* buffer, uint32 size, uint8 opcode)
296 #ifdef __PACKET_RECV_DUMP__
297 //printf("Rec: OPCODE %x \n",opcode);
298 DumpMem(buffer, size);
299 #endif
300 if (!m_client && opcode != OP_HELLO) {
301 throw wxString(wxT("Asks for something without saying hello"));
302 } else if (m_client && opcode != OP_HELLO && opcode != OP_HELLOANSWER) {
303 m_client->CheckHandshakeFinished();
306 switch(opcode) {
307 case OP_HELLOANSWER: { // 0.43b
308 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HELLOANSWER from ") + m_client->GetFullIP());
309 theStats::AddDownOverheadOther(size);
310 m_client->ProcessHelloAnswer(buffer, size);
312 // start secure identification, if
313 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
314 // - we have received eMule-OP_HELLOANSWER (new eMule)
315 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
316 m_client->InfoPacketsReceived();
319 // Socket might die because of sending in InfoPacketsReceived, so check
320 if (m_client) {
321 m_client->ConnectionEstablished();
324 // Socket might die on ConnectionEstablished somehow. Check it.
325 if (m_client) {
326 Notify_SharedCtrlRefreshClient( m_client , AVAILABLE_SOURCE);
329 break;
331 case OP_HELLO: { // 0.43b
333 theStats::AddDownOverheadOther(size);
334 bool bNewClient = !m_client;
335 if (bNewClient) {
336 // create new client to save standart informations
337 m_client = new CUpDownClient(this);
340 // Do not move up!
341 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HELLO from ") + m_client->GetFullIP() );
343 bool bIsMuleHello = false;
345 try{
346 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
347 } catch(...) {
348 if (bNewClient && m_client) {
349 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
350 m_client->Safe_Delete();
351 m_client = NULL;
353 throw;
356 if (thePrefs::ParanoidFilter() && !IsLowID(m_client->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid()))) {
357 wxString reason = wxT("Client claims a different IP from the one we received the hello packet from: ");
358 reason += Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
359 AddDebugLogLineM(false, logClient, reason);
360 if (bNewClient) {
361 m_client->Safe_Delete();
362 m_client = NULL;
364 Disconnect(wxT("Paranoid disconecting: ") + reason);
365 return false;
368 // if IP is filtered, dont reply but disconnect...
369 if (theApp->ipfilter->IsFiltered(m_client->GetIP())) {
370 if (bNewClient) {
371 m_client->Safe_Delete();
372 m_client = NULL;
374 Disconnect(wxT("IPFilter"));
375 return false;
378 wxASSERT(m_client);
380 // now we check if we now this client already. if yes this socket will
381 // be attached to the known client, the new client will be deleted
382 // and the var. "client" will point to the known client.
383 // if not we keep our new-constructed client ;)
384 if (theApp->clientlist->AttachToAlreadyKnown(&m_client,this)) {
385 // update the old client informations
386 bIsMuleHello = m_client->ProcessHelloPacket(buffer, size);
387 } else {
388 theApp->clientlist->AddClient(m_client);
389 m_client->SetCommentDirty();
391 Notify_SharedCtrlRefreshClient( m_client, AVAILABLE_SOURCE );
392 // send a response packet with standart informations
393 if ((m_client->GetHashType() == SO_EMULE) && !bIsMuleHello) {
394 m_client->SendMuleInfoPacket(false);
397 // Client might die from Sending in SendMuleInfoPacket, so check
398 if ( m_client ) {
399 m_client->SendHelloAnswer();
402 // Kry - If the other side supports it, send OS_INFO
403 // Client might die from Sending in SendHelloAnswer, so check
404 if (m_client && m_client->GetOSInfoSupport()) {
405 m_client->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
408 // Client might die from Sending in SendMuleInfoPacket, so check
409 if ( m_client ) {
410 m_client->ConnectionEstablished();
413 // start secure identification, if
414 // - we have received eMule-OP_HELLO (new eMule)
415 if (m_client && m_client->GetInfoPacketsReceived() == IP_BOTH) {
416 m_client->InfoPacketsReceived();
419 break;
421 case OP_REQUESTFILENAME: { // 0.43b
422 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client->GetFullIP() );
424 theStats::AddDownOverheadFileRequest(size);
425 // IP banned, no answer for this request
426 if (m_client->IsBanned()) {
427 break;
429 if (size >= 16) {
430 if (!m_client->GetWaitStartTime()) {
431 m_client->SetWaitStartTime();
433 CMemFile data_in(buffer, size);
434 CMD4Hash reqfilehash = data_in.ReadHash();
435 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
436 if ( reqfile == NULL ) {
437 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
438 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
439 break;
442 // if we are downloading this file, this could be a new source
443 // no passive adding of files with only one part
444 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
445 if (thePrefs::GetMaxSourcePerFile() >
446 ((CPartFile*)reqfile)->GetSourceCount()) {
447 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
451 // check to see if this is a new file they are asking for
452 if (m_client->GetUploadFileID() != reqfilehash) {
453 m_client->SetCommentDirty();
456 m_client->SetUploadFileID(reqfile);
457 m_client->ProcessExtendedInfo(&data_in, reqfile);
459 // send filename etc
460 CMemFile data_out(128);
461 data_out.WriteHash(reqfile->GetFileHash());
463 // Since it's for somebody else to see, we need to send the prettified
464 // filename, rather than the (possibly) mangled actual filename.
465 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
467 CPacket* packet = new CPacket(data_out, OP_EDONKEYPROT, OP_REQFILENAMEANSWER);
468 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
469 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client->GetFullIP() );
470 SendPacket(packet,true);
472 // SendPacket might kill the socket, so check
473 if (m_client)
474 m_client->SendCommentInfo(reqfile);
476 break;
478 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
479 break;
481 case OP_SETREQFILEID: { // 0.43b EXCEPT track of bad clients
482 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SETREQFILEID from ") + m_client->GetFullIP() );
484 theStats::AddDownOverheadFileRequest(size);
486 if (m_client->IsBanned()) {
487 break;
490 // DbT:FileRequest
491 if (size == 16) {
492 if (!m_client->GetWaitStartTime()) {
493 m_client->SetWaitStartTime();
496 const CMD4Hash fileID(buffer);
497 CKnownFile *reqfile = theApp->sharedfiles->GetFileByID(fileID);
498 if ( reqfile == NULL ) {
499 reqfile = theApp->downloadqueue->GetFileByID(fileID);
500 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
501 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
502 replypacket->Copy16ToDataBuffer(fileID.GetHash());
503 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
504 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILERE to ") + m_client->GetFullIP() );
505 SendPacket(replypacket, true);
506 break;
510 // check to see if this is a new file they are asking for
511 if (m_client->GetUploadFileID() != fileID) {
512 m_client->SetCommentDirty();
515 m_client->SetUploadFileID(reqfile);
516 // send filestatus
517 CMemFile data(16+16);
518 data.WriteHash(reqfile->GetFileHash());
519 if (reqfile->IsPartFile()) {
520 ((CPartFile*)reqfile)->WritePartStatus(&data);
521 } else {
522 data.WriteUInt16(0);
524 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_FILESTATUS);
525 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
526 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILESTATUS to ") + m_client->GetFullIP() );
527 SendPacket(packet, true);
528 break;
530 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
531 break;
532 // DbT:End
535 case OP_FILEREQANSNOFIL: { // 0.43b protocol, lacks ZZ's download manager on swap
536 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client->GetFullIP() );
538 theStats::AddDownOverheadFileRequest(size);
539 if (size == 16) {
540 // if that client does not have my file maybe has another different
541 CPartFile* reqfile = theApp->downloadqueue->GetFileByID(CMD4Hash(buffer));
542 if ( reqfile) {
543 reqfile->AddDeadSource( m_client );
544 } else {
545 break;
548 // we try to swap to another file ignoring no needed parts files
549 switch (m_client->GetDownloadState()) {
550 case DS_CONNECTED:
551 case DS_ONQUEUE:
552 case DS_NONEEDEDPARTS:
553 if (!m_client->SwapToAnotherFile(true, true, true, NULL)) {
554 theApp->downloadqueue->RemoveSource(m_client);
556 break;
558 break;
560 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
561 break;
564 case OP_REQFILENAMEANSWER: { // 0.43b except check for bad clients
565 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQFILENAMEANSWER 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->ProcessFileInfo(&data, file);
572 break;
575 case OP_FILESTATUS: { // 0.43b except check for bad clients
576 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILESTATUS from ") + m_client->GetFullIP() );
578 theStats::AddDownOverheadFileRequest(size);
579 CMemFile data(buffer, size);
580 CMD4Hash hash = data.ReadHash();
581 const CPartFile* file = theApp->downloadqueue->GetFileByID(hash);
582 m_client->ProcessFileStatus(false, &data, file);
583 break;
586 case OP_STARTUPLOADREQ: {
587 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client->GetFullIP() );
589 theStats::AddDownOverheadFileRequest(size);
591 if (!m_client->CheckHandshakeFinished()) {
592 break;
595 m_client->CheckForAggressive();
596 if ( m_client->IsBanned() ) {
597 break;
600 if (size == 16) {
601 const CMD4Hash fileID(buffer);
602 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(fileID);
603 if (reqfile) {
604 if (m_client->GetUploadFileID() != fileID) {
605 m_client->SetCommentDirty();
607 m_client->SetUploadFileID(reqfile);
608 m_client->SendCommentInfo(reqfile);
610 // Socket might die because of SendCommentInfo, so check
611 if (m_client)
612 theApp->uploadqueue->AddClientToQueue(m_client);
615 break;
618 case OP_QUEUERANK: { // 0.43b
619 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANK from ") + m_client->GetFullIP() );
621 theStats::AddDownOverheadFileRequest(size);
622 CMemFile data(buffer, size);
623 uint32 rank = data.ReadUInt32();
625 m_client->SetRemoteQueueRank(rank);
626 break;
629 case OP_ACCEPTUPLOADREQ: { // 0.42e (xcept khaos stats)
630 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client->GetFullIP() );
632 theStats::AddDownOverheadFileRequest(size);
633 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
634 if (m_client->GetDownloadState() == DS_ONQUEUE ) {
635 m_client->SetDownloadState(DS_DOWNLOADING);
636 m_client->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
637 m_client->SendBlockRequests();
639 } else {
640 if (!m_client->GetSentCancelTransfer()) {
641 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
642 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
643 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
644 m_client->SendPacket(packet,true,true);
646 // SendPacket can cause the socket to die, so check
647 if (m_client)
648 m_client->SetSentCancelTransfer(1);
651 if (m_client)
652 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
654 break;
657 case OP_REQUESTPARTS: { // 0.43b
658 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client->GetFullIP() );
660 theStats::AddDownOverheadFileRequest(size);
662 m_client->ProcessRequestPartsPacket(buffer, size, false);
664 break;
667 case OP_CANCELTRANSFER: { // 0.43b
668 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client->GetFullIP() );
670 theStats::AddDownOverheadFileRequest(size);
671 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
672 AddDebugLogLineM( false, logClient, m_client->GetUserName() + wxT(": Upload session ended due canceled transfer."));
673 break;
676 case OP_END_OF_DOWNLOAD: { // 0.43b except check for bad clients
677 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client->GetFullIP() );
679 theStats::AddDownOverheadFileRequest(size);
680 if (size>=16 && m_client->GetUploadFileID() == CMD4Hash(buffer)) {
681 theApp->uploadqueue->RemoveFromUploadQueue(m_client);
682 AddDebugLogLineM( false, logClient, m_client->GetUserName() + wxT(": Upload session ended due ended transfer."));
684 break;
687 case OP_HASHSETREQUEST: { // 0.43b except check for bad clients
688 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client->GetFullIP() );
691 theStats::AddDownOverheadFileRequest(size);
692 if (size != 16) {
693 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
695 m_client->SendHashsetPacket(CMD4Hash(buffer));
696 break;
699 case OP_HASHSETANSWER: { // 0.43b
700 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client->GetFullIP() );
702 theStats::AddDownOverheadFileRequest(size);
703 m_client->ProcessHashSet(buffer, size);
704 break;
707 case OP_SENDINGPART: { // 0.47a
708 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART from ") + m_client->GetFullIP() );
710 if ( m_client->GetRequestFile() &&
711 !m_client->GetRequestFile()->IsStopped() &&
712 (m_client->GetRequestFile()->GetStatus() == PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
714 m_client->ProcessBlockPacket(buffer, size, false, false);
716 if ( m_client &&
717 ( m_client->GetRequestFile()->IsStopped() ||
718 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
719 m_client->GetRequestFile()->GetStatus() == PS_ERROR) ) {
720 if (!m_client->GetSentCancelTransfer()) {
721 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
722 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
723 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
724 m_client->SendPacket(packet,true,true);
726 // Socket might die because of SendPacket, so check
727 if (m_client)
728 m_client->SetSentCancelTransfer(1);
731 if (m_client)
732 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
734 } else {
735 if (!m_client->GetSentCancelTransfer()) {
736 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
737 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
738 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
739 m_client->SendPacket(packet,true,true);
741 // Socket might die because of SendPacket, so check
742 m_client->SetSentCancelTransfer(1);
744 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
746 break;
749 case OP_OUTOFPARTREQS: { // 0.43b
750 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client->GetFullIP() );
752 theStats::AddDownOverheadFileRequest(size);
753 if (m_client->GetDownloadState() == DS_DOWNLOADING) {
754 m_client->SetDownloadState(DS_ONQUEUE);
756 break;
759 case OP_CHANGE_CLIENT_ID: { // Kad reviewed
760 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client->GetFullIP() );
762 theStats::AddDownOverheadOther(size);
763 CMemFile data(buffer, size);
764 uint32 nNewUserID = data.ReadUInt32();
765 uint32 nNewServerIP = data.ReadUInt32();
767 if (IsLowID(nNewUserID)) { // client changed server and gots a LowID
768 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
769 if (pNewServer != NULL){
770 m_client->SetUserIDHybrid(nNewUserID); // update UserID only if we know the server
771 m_client->SetServerIP(nNewServerIP);
772 m_client->SetServerPort(pNewServer->GetPort());
774 } else if (nNewUserID == m_client->GetIP()) { // client changed server and gots a HighID(IP)
775 m_client->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID));
776 CServer* pNewServer = theApp->serverlist->GetServerByIP(nNewServerIP);
777 if (pNewServer != NULL){
778 m_client->SetServerIP(nNewServerIP);
779 m_client->SetServerPort(pNewServer->GetPort());
783 break;
786 case OP_CHANGE_SLOT:{ // 0.43b
787 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client->GetFullIP() );
789 // sometimes sent by Hybrid
790 theStats::AddDownOverheadOther(size);
791 break;
794 case OP_MESSAGE: { // 0.43b
795 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MESSAGE from ") + m_client->GetFullIP() );
797 theStats::AddDownOverheadOther(size);
799 if (size < 2) {
800 throw wxString(wxT("invalid message packet"));
802 CMemFile message_file(buffer, size);
803 uint16 length = message_file.ReadUInt16();
804 if (length + 2u != size) {
805 throw wxString(wxT("invalid message packet"));
808 // limit message length
809 static const uint16 MAX_CLIENT_MSG_LEN = 450;
811 if (length > MAX_CLIENT_MSG_LEN) {
812 AddDebugLogLineN(logRemoteClient, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
813 % m_client->GetUserName() % m_client->GetFullIP() % (length - MAX_CLIENT_MSG_LEN));
814 length = MAX_CLIENT_MSG_LEN;
817 wxString message = message_file.ReadOnlyString((m_client->GetUnicodeSupport() != utf8strNone), length);
818 m_client->ProcessChatMessage(message);
820 break;
823 case OP_ASKSHAREDFILES: { // 0.43b (well, er, it does the same, but in our own way)
824 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client->GetFullIP() );
826 // client wants to know what we have in share, let's see if we allow him to know that
827 theStats::AddDownOverheadOther(size);
828 // IP banned, no answer for this request
829 if (m_client->IsBanned()) {
830 break;
833 if (thePrefs::CanSeeShares() == vsfaEverybody || (thePrefs::CanSeeShares() == vsfaFriends && m_client->IsFriend())) {
834 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
835 % m_client->GetUserName()
836 % m_client->GetUserIDHybrid() );
838 std::vector<CKnownFile*> list;
839 theApp->sharedfiles->CopyFileList(list);
841 CMemFile tempfile(80);
842 tempfile.WriteUInt32(list.size());
843 for (unsigned i = 0; i < list.size(); ++i) {
844 if (!list[i]->IsLargeFile() || m_client->SupportsLargeFiles()) {
845 theApp->sharedfiles->CreateOfferedFilePacket(list[i], &tempfile, NULL, m_client);
849 // create a packet and send it
850 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESANSWER);
851 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client->GetFullIP() );
852 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
853 SendPacket(replypacket, true, true);
854 } else {
855 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
856 % m_client->GetUserName()
857 % m_client->GetUserIDHybrid() );
859 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
860 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
861 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
862 SendPacket(replypacket, true, true);
865 break;
868 case OP_ASKSHAREDFILESANSWER: { // 0.43b
869 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client->GetFullIP() );
871 theStats::AddDownOverheadOther(size);
872 wxString EmptyStr;
873 m_client->ProcessSharedFileList(buffer, size, EmptyStr);
874 break;
877 case OP_ASKSHAREDDIRS: { // 0.43b
878 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client->GetFullIP() );
880 theStats::AddDownOverheadOther(size);
881 wxASSERT( size == 0 );
882 // IP banned, no answer for this request
883 if (m_client->IsBanned()) {
884 break;
886 if ((thePrefs::CanSeeShares()==vsfaEverybody) || ((thePrefs::CanSeeShares()==vsfaFriends) && m_client->IsFriend())) {
887 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
888 % m_client->GetUserName()
889 % m_client->GetUserIDHybrid() );
891 // This list will contain all (unique) folders.
892 std::list<CPath> foldersToSend;
894 // The shared folders
895 const unsigned folderCount = theApp->glob_prefs->shareddir_list.size();
896 for (unsigned i = 0; i < folderCount; ++i) {
897 foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]);
900 // ... the categories folders ... (category 0 -> incoming)
901 for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) {
902 foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path);
905 // ... and the Magic thing from the eDonkey Hybrids...
906 foldersToSend.push_back(CPath(OP_INCOMPLETE_SHARED_FILES));
908 // Strip duplicates
909 foldersToSend.sort();
910 foldersToSend.unique();
912 // Send packet.
913 CMemFile tempfile(80);
914 tempfile.WriteUInt32(foldersToSend.size());
916 std::list<CPath>::iterator it = foldersToSend.begin();
917 for (; it != foldersToSend.end(); ++it) {
918 // We need to send the 'raw' filename, so we can recognize it again.
919 tempfile.WriteString(it->GetRaw(), m_client->GetUnicodeSupport());
922 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS);
923 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
924 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client->GetFullIP() );
925 SendPacket(replypacket, true, true);
926 } else {
927 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
928 % m_client->GetUserName()
929 % m_client->GetUserIDHybrid() );
931 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
932 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
933 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
934 SendPacket(replypacket, true, true);
937 break;
940 case OP_ASKSHAREDFILESDIR: { // 0.43b
941 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client->GetFullIP() );
943 theStats::AddDownOverheadOther(size);
944 // IP banned, no answer for this request
945 if (m_client->IsBanned()) {
946 break;
948 CMemFile data(buffer, size);
950 wxString strReqDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
951 if (thePrefs::CanSeeShares()==vsfaEverybody || (thePrefs::CanSeeShares()==vsfaFriends && m_client->IsFriend())) {
952 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
953 wxASSERT( data.GetPosition() == data.GetLength() );
955 CKnownFilePtrList list;
957 if (strReqDir == OP_INCOMPLETE_SHARED_FILES) {
958 // get all shared files from download queue
959 int iQueuedFiles = theApp->downloadqueue->GetFileCount();
960 for (int i = 0; i < iQueuedFiles; i++) {
961 CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i);
962 if (pFile == NULL || pFile->GetStatus(true) != PS_READY) {
963 continue;
966 list.push_back(pFile);
968 } else {
969 theApp->sharedfiles->GetSharedFilesByDirectory(strReqDir, list);
972 CMemFile tempfile(80);
973 tempfile.WriteString(strReqDir, m_client->GetUnicodeSupport());
974 tempfile.WriteUInt32(list.size());
976 while (!list.empty()) {
977 if (!list.front()->IsLargeFile() || m_client->SupportsLargeFiles()) {
978 theApp->sharedfiles->CreateOfferedFilePacket(list.front(), &tempfile, NULL, m_client);
981 list.pop_front();
984 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS);
985 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
986 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client->GetFullIP() );
987 SendPacket(replypacket, true, true);
988 } else {
989 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client->GetUserName() % m_client->GetUserIDHybrid() % strReqDir);
991 CPacket* replypacket = new CPacket(OP_ASKSHAREDDENIEDANS, 0, OP_EDONKEYPROT);
992 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
993 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client->GetFullIP() );
994 SendPacket(replypacket, true, true);
996 break;
999 case OP_ASKSHAREDDIRSANS:{ // 0.43b
1000 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client->GetFullIP() );
1002 theStats::AddDownOverheadOther(size);
1003 if (m_client->GetFileListRequested() == 1){
1004 CMemFile data(buffer, size);
1005 uint32 uDirs = data.ReadUInt32();
1006 for (uint32 i = 0; i < uDirs; i++){
1007 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1008 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
1009 % m_client->GetUserName()
1010 % m_client->GetUserIDHybrid()
1011 % strDir );
1013 CMemFile tempfile(80);
1014 tempfile.WriteString(strDir, m_client->GetUnicodeSupport());
1015 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIR);
1016 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
1017 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client->GetFullIP() );
1018 SendPacket(replypacket, true, true);
1020 wxASSERT( data.GetPosition() == data.GetLength() );
1021 m_client->SetFileListRequested(uDirs);
1022 } else {
1023 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1024 % m_client->GetUserName()
1025 % m_client->GetUserIDHybrid() );
1027 break;
1030 case OP_ASKSHAREDFILESDIRANS: { // 0.43b
1031 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client->GetFullIP() );
1033 theStats::AddDownOverheadOther(size);
1034 CMemFile data(buffer, size);
1035 wxString strDir = data.ReadString((m_client->GetUnicodeSupport() != utf8strNone));
1037 if (m_client->GetFileListRequested() > 0){
1038 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1039 % m_client->GetUserName()
1040 % m_client->GetUserIDHybrid()
1041 % strDir );
1043 m_client->ProcessSharedFileList(buffer + data.GetPosition(), size - data.GetPosition(), strDir);
1044 if (m_client->GetFileListRequested() == 0) {
1045 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1046 % m_client->GetUserName()
1047 % m_client->GetUserIDHybrid() );
1049 } else {
1050 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1051 % m_client->GetUserName()
1052 % m_client->GetUserIDHybrid() );
1054 break;
1057 case OP_ASKSHAREDDENIEDANS:
1058 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client->GetFullIP() );
1060 theStats::AddDownOverheadOther(size);
1061 wxASSERT( size == 0 );
1062 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1063 % m_client->GetUserName()
1064 % m_client->GetUserIDHybrid() );
1066 m_client->SetFileListRequested(0);
1067 break;
1069 default:
1070 theStats::AddDownOverheadOther(size);
1071 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1072 return false;
1075 return true;
1079 bool CClientTCPSocket::ProcessExtPacket(const byte* buffer, uint32 size, uint8 opcode)
1081 #ifdef __PACKET_RECV_DUMP__
1082 //printf("Rec: OPCODE %x \n",opcode);
1083 DumpMem(buffer,size);
1084 #endif
1086 // 0.42e - except the catchs on mem exception and file exception
1087 if (!m_client) {
1088 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1091 if (!client->CheckHandshakeFinished()) {
1092 // Here comes an extended packet without finishing the handshake.
1093 // IMHO, we should disconnect the client.
1094 throw wxString(wxT("Client send extended packet before finishing handshake"));
1097 switch(opcode) {
1098 case OP_MULTIPACKET_EXT:
1099 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client->GetFullIP());
1100 case OP_MULTIPACKET: {
1101 if (opcode == OP_MULTIPACKET) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET from ") + m_client->GetFullIP() );
1103 theStats::AddDownOverheadFileRequest(size);
1105 if (m_client->IsBanned()) {
1106 break;
1109 if (!m_client->CheckHandshakeFinished()) {
1110 // Here comes an extended packet without finishing the handshake.
1111 // IMHO, we should disconnect the client.
1112 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1115 CMemFile data_in(buffer, size);
1116 CMD4Hash reqfilehash = data_in.ReadHash();
1117 uint64 nSize = (opcode == OP_MULTIPACKET_EXT) ? data_in.ReadUInt64() : 0;
1119 bool file_not_found = false;
1120 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(reqfilehash);
1121 if ( reqfile == NULL ){
1122 reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1123 if ( !( reqfile != NULL && reqfile->GetFileSize() > PARTSIZE ) ) {
1124 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a non-shared file"));
1125 file_not_found = true;
1129 if (!file_not_found && reqfile->IsLargeFile() && !m_client->SupportsLargeFiles()) {
1130 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a large file but doesn't support them"));
1131 file_not_found = true;
1134 if (!file_not_found && nSize && (reqfile->GetFileSize() != nSize)) {
1135 AddDebugLogLineM(false, logRemoteClient, wxT("Remote client asked for a file but specified wrong size"));
1136 file_not_found = true;
1139 if (file_not_found) {
1140 CPacket* replypacket = new CPacket(OP_FILEREQANSNOFIL, 16, OP_EDONKEYPROT);
1141 replypacket->Copy16ToDataBuffer(reqfilehash.GetHash());
1142 theStats::AddUpOverheadFileRequest(replypacket->GetPacketSize());
1143 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client->GetFullIP() );
1144 SendPacket(replypacket, true);
1145 break;
1148 if (!m_client->GetWaitStartTime()) {
1149 m_client->SetWaitStartTime();
1151 // if we are downloading this file, this could be a new source
1152 // no passive adding of files with only one part
1153 if (reqfile->IsPartFile() && reqfile->GetFileSize() > PARTSIZE) {
1154 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile*)reqfile)->GetSourceCount()) {
1155 theApp->downloadqueue->CheckAndAddKnownSource((CPartFile*)reqfile, m_client);
1158 // check to see if this is a new file they are asking for
1159 if (m_client->GetUploadFileID() != reqfilehash) {
1160 m_client->SetCommentDirty();
1162 m_client->SetUploadFileID(reqfile);
1163 CMemFile data_out(128);
1164 data_out.WriteHash(reqfile->GetFileHash());
1165 while(data_in.GetLength()-data_in.GetPosition()) {
1166 if (!m_client) {
1167 throw wxString(wxT("Client suddenly disconnected"));
1169 uint8 opcode_in = data_in.ReadUInt8();
1170 switch(opcode_in) {
1171 case OP_REQUESTFILENAME: {
1172 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1173 m_client->ProcessExtendedInfo(&data_in, reqfile);
1174 data_out.WriteUInt8(OP_REQFILENAMEANSWER);
1176 // Since it's for somebody else to see, we need to send the prettified
1177 // filename, rather than the (possibly) mangled actual filename
1178 data_out.WriteString(reqfile->GetFileName().GetPrintable(), m_client->GetUnicodeSupport());
1179 break;
1181 case OP_AICHFILEHASHREQ: {
1182 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1183 if (m_client->IsSupportingAICH() && reqfile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1184 && reqfile->GetAICHHashset()->HasValidMasterHash())
1186 data_out.WriteUInt8(OP_AICHFILEHASHANS);
1187 reqfile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1189 break;
1191 case OP_SETREQFILEID: {
1192 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1193 data_out.WriteUInt8(OP_FILESTATUS);
1194 if (reqfile->IsPartFile()) {
1195 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1196 } else {
1197 data_out.WriteUInt16(0);
1199 break;
1201 //We still send the source packet separately..
1202 //We could send it within this packet.. If agreeded, I will fix it..
1203 case OP_REQUESTSOURCES2:
1204 case OP_REQUESTSOURCES: {
1205 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1206 uint8 byRequestedVersion = 0;
1207 uint16 byRequestedOptions = 0;
1208 if (opcode_in == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1209 byRequestedVersion = data_in.ReadUInt8();
1210 byRequestedOptions = data_in.ReadUInt16();
1213 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1215 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() > 1) {
1216 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1217 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1218 if(
1219 //if not complete and file is rare
1220 ( reqfile->IsPartFile()
1221 && (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1222 && ((CPartFile*)reqfile)->GetSourceCount() <= RARE_FILE
1223 ) ||
1224 //OR if file is not rare or if file is complete
1225 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1228 m_client->SetLastSrcReqTime();
1229 CPacket* tosend = reqfile->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1230 if(tosend) {
1231 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1232 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1233 SendPacket(tosend, true);
1237 break;
1242 if( data_out.GetLength() > 16 ) {
1243 CPacket* reply = new CPacket(data_out, OP_EMULEPROT, OP_MULTIPACKETANSWER);
1244 theStats::AddUpOverheadFileRequest(reply->GetPacketSize());
1245 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client->GetFullIP() );
1246 SendPacket(reply, true);
1248 break;
1251 case OP_MULTIPACKETANSWER: { // 0.43b
1252 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client->GetFullIP() );
1254 theStats::AddDownOverheadFileRequest(size);
1256 if (m_client->IsBanned()) {
1257 break;
1260 if( m_client->GetKadPort() ) {
1261 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client->GetIP()), m_client->GetKadPort(), m_client->GetKadVersion() > 1);
1264 if (!m_client->CheckHandshakeFinished()) {
1265 // Here comes an extended packet without finishing the handshake.
1266 // IMHO, we should disconnect the client.
1267 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1270 CMemFile data_in(buffer, size);
1271 CMD4Hash reqfilehash = data_in.ReadHash();
1272 const CPartFile *reqfile = theApp->downloadqueue->GetFileByID(reqfilehash);
1273 //Make sure we are downloading this file.
1274 if ( !reqfile ) {
1275 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1277 if ( !m_client->GetRequestFile() ) {
1279 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1281 if (reqfile != m_client->GetRequestFile()) {
1282 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1284 while (data_in.GetLength()-data_in.GetPosition()) {
1285 // Some of the cases down there can actually send a packet and lose the client
1286 if (!m_client) {
1287 throw wxString(wxT("Client suddenly disconnected"));
1289 uint8 opcode_in = data_in.ReadUInt8();
1290 switch(opcode_in) {
1291 case OP_REQFILENAMEANSWER: {
1292 if (!m_client) {
1293 throw wxString(wxT("Client suddenly disconnected"));
1294 } else {
1295 m_client->ProcessFileInfo(&data_in, reqfile);
1297 break;
1299 case OP_FILESTATUS: {
1300 if (!m_client) {
1301 throw wxString(wxT("Client suddenly disconnected"));
1302 } else {
1303 m_client->ProcessFileStatus(false, &data_in, reqfile);
1305 break;
1307 case OP_AICHFILEHASHANS: {
1308 if (!m_client) {
1309 throw wxString(wxT("Client suddenly disconnected"));
1310 } else {
1311 m_client->ProcessAICHFileHash(&data_in, reqfile);
1313 break;
1318 break;
1321 case OP_EMULEINFO: { // 0.43b
1322 theStats::AddDownOverheadOther(size);
1324 if (!m_client->ProcessMuleInfoPacket(buffer, size)) {
1325 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO from ") + m_client->GetFullIP() );
1327 // If it's not a OS Info packet, is an old client
1328 // start secure identification, if
1329 // - we have received eD2K and eMule info (old eMule)
1330 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1331 m_client->InfoPacketsReceived();
1333 m_client->SendMuleInfoPacket(true);
1334 } else {
1335 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1337 break;
1339 case OP_EMULEINFOANSWER: { // 0.43b
1340 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client->GetFullIP() );
1341 theStats::AddDownOverheadOther(size);
1343 m_client->ProcessMuleInfoPacket(buffer, size);
1344 // start secure identification, if
1345 // - we have received eD2K and eMule info (old eMule)
1347 if (m_client->GetInfoPacketsReceived() == IP_BOTH) {
1348 m_client->InfoPacketsReceived();
1351 break;
1354 case OP_SECIDENTSTATE:{ // 0.43b
1355 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client->GetFullIP() );
1357 if (!m_client->CheckHandshakeFinished()) {
1358 // Here comes an extended packet without finishing the handshake.
1359 // IMHO, we should disconnect the client.
1360 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1362 m_client->ProcessSecIdentStatePacket(buffer, size);
1363 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1364 if (m_client) {
1365 int SecureIdentState = m_client->GetSecureIdentState();
1366 if (SecureIdentState == IS_SIGNATURENEEDED) {
1367 m_client->SendSignaturePacket();
1368 } else if (SecureIdentState == IS_KEYANDSIGNEEDED) {
1369 m_client->SendPublicKeyPacket();
1370 // SendPublicKeyPacket() might cause the socket to die, so check
1371 if ( m_client ) {
1372 m_client->SendSignaturePacket();
1376 break;
1379 case OP_PUBLICKEY: { // 0.43b
1380 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICKEY from ") + m_client->GetFullIP() );
1382 if (m_client->IsBanned() ){
1383 break;
1386 if (!m_client->CheckHandshakeFinished()) {
1387 // Here comes an extended packet without finishing the handshake.
1388 // IMHO, we should disconnect the client.
1389 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1392 m_client->ProcessPublicKeyPacket(buffer, size);
1393 break;
1395 case OP_SIGNATURE:{ // 0.43b
1396 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SIGNATURE from ") + m_client->GetFullIP() );
1398 if (!m_client->CheckHandshakeFinished()) {
1399 // Here comes an extended packet without finishing the handshake.
1400 // IMHO, we should disconnect the client.
1401 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1404 m_client->ProcessSignaturePacket(buffer, size);
1405 break;
1407 case OP_SENDINGPART_I64:
1408 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client->GetFullIP() );
1409 case OP_COMPRESSEDPART_I64:
1410 if (opcode == OP_COMPRESSEDPART_I64) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client->GetFullIP() );
1411 case OP_COMPRESSEDPART: { // 0.47a
1412 if (opcode == OP_COMPRESSEDPART) AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client->GetFullIP() );
1414 if (!m_client->CheckHandshakeFinished()) {
1415 // Here comes an extended packet without finishing the handshake.
1416 // IMHO, we should disconnect the client.
1417 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1420 if (m_client->GetRequestFile() && !m_client->GetRequestFile()->IsStopped() && (m_client->GetRequestFile()->GetStatus()==PS_READY || m_client->GetRequestFile()->GetStatus()==PS_EMPTY)) {
1422 m_client->ProcessBlockPacket(buffer, size, (opcode != OP_SENDINGPART_I64), (opcode == OP_COMPRESSEDPART_I64) || (opcode == OP_SENDINGPART_I64));
1424 if (m_client && (
1425 m_client->GetRequestFile()->IsStopped() ||
1426 m_client->GetRequestFile()->GetStatus() == PS_PAUSED ||
1427 m_client->GetRequestFile()->GetStatus() == PS_ERROR)) {
1428 if (!m_client->GetSentCancelTransfer()) {
1429 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1430 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1431 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1432 m_client->SendPacket(packet,true,true);
1434 if (m_client) {
1435 m_client->SetSentCancelTransfer(1);
1439 if ( m_client ) {
1440 m_client->SetDownloadState(m_client->GetRequestFile()->IsStopped() ? DS_NONE : DS_ONQUEUE);
1443 } else {
1444 if (!m_client->GetSentCancelTransfer()) {
1445 CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT);
1446 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1447 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client->GetFullIP() );
1448 m_client->SendPacket(packet,true,true);
1450 if ( m_client ) {
1451 m_client->SetSentCancelTransfer(1);
1455 if ( m_client ) {
1456 m_client->SetDownloadState((m_client->GetRequestFile()==NULL || m_client->GetRequestFile()->IsStopped()) ? DS_NONE : DS_ONQUEUE);
1459 break;
1461 case OP_REQUESTPARTS_I64: {
1462 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client->GetFullIP() );
1464 theStats::AddDownOverheadFileRequest(size);
1466 m_client->ProcessRequestPartsPacket(buffer, size, true);
1468 break;
1470 case OP_QUEUERANKING: { // 0.43b
1471 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_QUEUERANKING from ") + m_client->GetFullIP() );
1473 theStats::AddDownOverheadOther(size);
1475 if (!m_client->CheckHandshakeFinished()) {
1476 // Here comes an extended packet without finishing the handshake.
1477 // IMHO, we should disconnect the client.
1478 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1481 if (size != 12) {
1482 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1485 uint16 newrank = PeekUInt16(buffer);
1486 m_client->SetRemoteQueueFull(false);
1487 m_client->SetRemoteQueueRank(newrank);
1488 break;
1490 case OP_REQUESTSOURCES2:
1491 case OP_REQUESTSOURCES:{
1492 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client->GetFullIP() );
1494 theStats::AddDownOverheadSourceExchange(size);
1496 if (!m_client->CheckHandshakeFinished()) {
1497 // Here comes an extended packet without finishing the handshake.
1498 // IMHO, we should disconnect the client.
1499 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1502 uint8 byRequestedVersion = 0;
1503 uint16 byRequestedOptions = 0;
1504 CMemFile data_in(buffer, size);
1505 if (opcode == OP_REQUESTSOURCES2){ // SX2 requests contains additional data
1506 byRequestedVersion = data_in.ReadUInt8();
1507 byRequestedOptions = data_in.ReadUInt16();
1510 if (byRequestedVersion > 0 || m_client->GetSourceExchange1Version() >= 1) {
1511 if(size != 16) {
1512 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1514 //first check shared file list, then download list
1515 const CMD4Hash fileID(buffer);
1516 CKnownFile* file = theApp->sharedfiles->GetFileByID(fileID);
1517 if(!file) {
1518 file = theApp->downloadqueue->GetFileByID(fileID);
1520 if(file) {
1521 // There are some clients which do not follow the correct protocol procedure of sending
1522 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1523 // are doing this, they will not get the optimal set of sources which we could offer if
1524 // they would follow the above noted protocol sequence. They better do it the right way
1525 // or they will get just a random set of sources because we do not know their download
1526 // part status which may get cleared with the call of 'SetUploadFileID'.
1527 m_client->SetUploadFileID(file);
1529 uint32 dwTimePassed = ::GetTickCount() - m_client->GetLastSrcReqTime() + CONNECTION_LATENCY;
1530 bool bNeverAskedBefore = m_client->GetLastSrcReqTime() == 0;
1531 if(
1532 //if not complete and file is rare, allow once every 40 minutes
1533 ( file->IsPartFile() &&
1534 ((CPartFile*)file)->GetSourceCount() <= RARE_FILE &&
1535 (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS)
1536 ) ||
1537 //OR if file is not rare or if file is complete, allow every 90 minutes
1538 ( (bNeverAskedBefore || dwTimePassed > SOURCECLIENTREASKS * MINCOMMONPENALTY) )
1541 m_client->SetLastSrcReqTime();
1542 CPacket* tosend = file->CreateSrcInfoPacket(m_client, byRequestedVersion, byRequestedOptions);
1543 if(tosend) {
1544 theStats::AddUpOverheadSourceExchange(tosend->GetPacketSize());
1545 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client->GetFullIP() );
1546 SendPacket(tosend, true, true);
1551 break;
1553 case OP_ANSWERSOURCES: {
1554 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client->GetFullIP() );
1556 theStats::AddDownOverheadSourceExchange(size);
1558 if (!m_client->CheckHandshakeFinished()) {
1559 // Here comes an extended packet without finishing the handshake.
1560 // IMHO, we should disconnect the client.
1561 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1564 CMemFile data(buffer, size);
1565 CMD4Hash hash = data.ReadHash();
1566 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1567 if(file){
1568 if (file->IsPartFile()){
1569 //set the client's answer time
1570 m_client->SetLastSrcAnswerTime();
1571 //and set the file's last answer time
1572 ((CPartFile*)file)->SetLastAnsweredTime();
1574 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, m_client->GetSourceExchange1Version(), false, m_client);
1577 break;
1579 case OP_ANSWERSOURCES2: {
1580 //printf("Received OP_ANSWERSOURCES2\n");
1581 theStats::AddDownOverheadSourceExchange(size);
1583 if (!m_client->CheckHandshakeFinished()) {
1584 // Here comes an extended packet without finishing the handshake.
1585 // IMHO, we should disconnect the client.
1586 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1589 CMemFile data(buffer, size);
1590 uint8 byVersion = data.ReadUInt8();
1591 CMD4Hash hash = data.ReadHash();
1592 const CKnownFile* file = theApp->downloadqueue->GetFileByID(hash);
1593 if (file){
1594 if (file->IsPartFile()){
1595 //set the client's answer time
1596 m_client->SetLastSrcAnswerTime();
1597 //and set the file's last answer time
1598 ((CPartFile*)file)->SetLastAnsweredTime();
1599 ((CPartFile*)file)->AddClientSources(&data, SF_SOURCE_EXCHANGE, byVersion, true, m_client);
1602 break;
1604 case OP_FILEDESC: { // 0.43b
1605 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_FILEDESC from ") + m_client->GetFullIP() );
1607 theStats::AddDownOverheadFileRequest(size);
1609 if (!m_client->CheckHandshakeFinished()) {
1610 // Here comes an extended packet without finishing the handshake.
1611 // IMHO, we should disconnect the client.
1612 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1615 m_client->ProcessMuleCommentPacket(buffer, size);
1616 break;
1619 // Unsupported
1620 case OP_REQUESTPREVIEW: {
1621 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client->GetFullIP() );
1622 break;
1624 // Unsupported
1625 case OP_PREVIEWANSWER: {
1626 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client->GetFullIP() );
1627 break;
1630 case OP_PUBLICIP_ANSWER: {
1631 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client->GetFullIP() );
1632 theStats::AddDownOverheadOther(size);
1633 m_client->ProcessPublicIPAnswer(buffer, size);
1634 break;
1636 case OP_PUBLICIP_REQ: {
1637 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client->GetFullIP() );
1638 theStats::AddDownOverheadOther(size);
1639 CPacket* pPacket = new CPacket(OP_PUBLICIP_ANSWER, 4, OP_EMULEPROT);
1640 pPacket->CopyUInt32ToDataBuffer(m_client->GetIP());
1641 theStats::AddUpOverheadOther(pPacket->GetPacketSize());
1642 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client->GetFullIP());
1643 SendPacket(pPacket);
1644 break;
1646 case OP_AICHANSWER: {
1647 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHANSWER from ") + m_client->GetFullIP() );
1648 theStats::AddDownOverheadOther(size);
1649 m_client->ProcessAICHAnswer(buffer, size);
1650 break;
1652 case OP_AICHREQUEST: {
1653 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHREQUEST from ") + m_client->GetFullIP() );
1654 theStats::AddDownOverheadOther(size);
1655 m_client->ProcessAICHRequest(buffer, size);
1656 break;
1658 case OP_AICHFILEHASHANS: {
1659 // those should not be received normally, since we should only get those in MULTIPACKET
1660 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client->GetFullIP() );
1661 theStats::AddDownOverheadOther(size);
1662 CMemFile data(buffer, size);
1663 m_client->ProcessAICHFileHash(&data, NULL);
1664 break;
1666 case OP_AICHFILEHASHREQ: {
1667 // those should not be received normally, since we should only get those in MULTIPACKET
1668 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client->GetFullIP() );
1669 CMemFile data(buffer, size);
1670 CMD4Hash hash = data.ReadHash();
1671 CKnownFile* pPartFile = theApp->sharedfiles->GetFileByID(hash);
1672 if (pPartFile == NULL){
1673 break;
1676 if (m_client->IsSupportingAICH() && pPartFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1677 && pPartFile->GetAICHHashset()->HasValidMasterHash()) {
1678 CMemFile data_out;
1679 data_out.WriteHash(hash);
1680 pPartFile->GetAICHHashset()->GetMasterHash().Write(&data_out);
1681 CPacket* packet = new CPacket(data_out, OP_EMULEPROT, OP_AICHFILEHASHANS);
1682 theStats::AddUpOverheadOther(packet->GetPacketSize());
1683 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client->GetFullIP());
1684 SendPacket(packet);
1686 break;
1688 case OP_CALLBACK: {
1689 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_CALLBACK from ") + m_client->GetFullIP() );
1690 theStats::AddDownOverheadFileRequest(size);
1691 if(!Kademlia::CKademlia::IsRunning()) {
1692 break;
1694 CMemFile data(buffer, size);
1695 CUInt128 check = data.ReadUInt128();
1696 check.XOR(Kademlia::CUInt128(true));
1697 if( check.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1698 break;
1700 CUInt128 fileid = data.ReadUInt128();
1701 byte fileid2[16];
1702 fileid.ToByteArray(fileid2);
1703 const CMD4Hash fileHash(fileid2);
1704 if (theApp->sharedfiles->GetFileByID(fileHash) == NULL) {
1705 if (theApp->downloadqueue->GetFileByID(fileHash) == NULL) {
1706 break;
1710 uint32 ip = data.ReadUInt32();
1711 uint16 tcp = data.ReadUInt16();
1712 CUpDownClient* callback;
1713 callback = theApp->clientlist->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip), tcp);
1714 if( callback == NULL ) {
1715 //#warning Do we actually have to check friend status here?
1716 callback = new CUpDownClient(tcp,ip,0,0,NULL,false, false);
1717 theApp->clientlist->AddClient(callback);
1719 callback->TryToConnect(true);
1720 break;
1723 case OP_BUDDYPING: {
1724 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPING from ") + m_client->GetFullIP() );
1725 theStats::AddDownOverheadKad(size);
1727 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1728 if( buddy != m_client || m_client->GetKadVersion() == 0 || !m_client->AllowIncomeingBuddyPingPong() ) {
1729 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1730 break;
1733 m_client->SetLastBuddyPingPongTime();
1734 CPacket* replypacket = new CPacket(OP_BUDDYPONG, 0, OP_EMULEPROT);
1735 theStats::AddUpOverheadKad(replypacket->GetPacketSize());
1736 AddDebugLogLineM(false, logLocalClient,wxT("Local Client: OP_BUDDYPONG to ") + m_client->GetFullIP());
1737 SendPacket(replypacket);
1738 break;
1740 case OP_BUDDYPONG: {
1741 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_BUDDYPONG from ") + m_client->GetFullIP() );
1742 theStats::AddDownOverheadKad(size);
1744 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1745 if( buddy != m_client || m_client->GetKadVersion() == 0 ) {
1746 //This pong was not from our buddy or wrong version. Ignore
1747 break;
1749 m_client->SetLastBuddyPingPongTime();
1750 //All this is for is to reset our socket timeout.
1751 break;
1753 case OP_REASKCALLBACKTCP: {
1754 theStats::AddDownOverheadFileRequest(size);
1755 CUpDownClient* buddy = theApp->clientlist->GetBuddy();
1756 if (buddy != m_client) {
1757 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() + wxT(" which is not our buddy!") );
1758 //This callback was not from our buddy.. Ignore.
1759 break;
1761 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client->GetFullIP() );
1762 CMemFile data_in(buffer, size);
1763 uint32 destip = data_in.ReadUInt32();
1764 uint16 destport = data_in.ReadUInt16();
1765 CMD4Hash hash = data_in.ReadHash();
1766 CKnownFile* reqfile = theApp->sharedfiles->GetFileByID(hash);
1768 bool bSenderMultipleIpUnknown = false;
1769 CUpDownClient* sender = theApp->uploadqueue->GetWaitingClientByIP_UDP(destip, destport, true, &bSenderMultipleIpUnknown);
1770 if (!reqfile) {
1771 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_FILENOTFOUND to ") + m_client->GetFullIP() );
1772 CPacket* response = new CPacket(OP_FILENOTFOUND,0,OP_EMULEPROT);
1773 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1774 if (sender) {
1775 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1776 } else {
1777 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1779 break;
1782 if (sender) {
1783 //Make sure we are still thinking about the same file
1784 if (hash == sender->GetUploadFileID()) {
1785 sender->AddAskedCount();
1786 sender->SetLastUpRequest();
1787 //I messed up when I first added extended info to UDP
1788 //I should have originally used the entire ProcessExtenedInfo the first time.
1789 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1790 //For now on, we should not have to change anything here if we change
1791 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1792 //Update extended info.
1793 if (sender->GetUDPVersion() > 3) {
1794 sender->ProcessExtendedInfo(&data_in, reqfile);
1795 } else if (sender->GetUDPVersion() > 2) {
1796 //Update our complete source counts.
1797 uint16 nCompleteCountLast= sender->GetUpCompleteSourcesCount();
1798 uint16 nCompleteCountNew = data_in.ReadUInt16();
1799 sender->SetUpCompleteSourcesCount(nCompleteCountNew);
1800 if (nCompleteCountLast != nCompleteCountNew) {
1801 reqfile->UpdatePartsInfo();
1805 CMemFile data_out(128);
1806 if(sender->GetUDPVersion() > 3) {
1807 if (reqfile->IsPartFile()) {
1808 ((CPartFile*)reqfile)->WritePartStatus(&data_out);
1809 } else {
1810 data_out.WriteUInt16(0);
1814 data_out.WriteUInt16(theApp->uploadqueue->GetWaitingPosition(sender));
1815 CPacket* response = new CPacket(data_out, OP_EMULEPROT, OP_REASKACK);
1816 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1817 AddDebugLogLineM( false, logLocalClient, wxT("Local Client UDP: OP_REASKACK to ") + m_client->GetFullIP() );
1818 theApp->clientudp->SendPacket(response, destip, destport, sender->ShouldReceiveCryptUDPPackets(), sender->GetUserHash().GetHash(), false, 0);
1819 } else {
1820 AddDebugLogLineM(false, logListenSocket, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1822 } else {
1823 if (!bSenderMultipleIpUnknown){
1824 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1825 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_QUEUEFULL to ") + m_client->GetFullIP() );
1826 CPacket* response = new CPacket(OP_QUEUEFULL,0,OP_EMULEPROT);
1827 theStats::AddUpOverheadFileRequest(response->GetPacketSize());
1828 theApp->clientudp->SendPacket(response, destip, destport, false, NULL, false, 0);
1830 } else {
1831 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);
1834 break;
1836 case OP_CHATCAPTCHAREQ:
1838 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client->GetFullIP());
1839 theStats::AddDownOverheadOther(size);
1840 CMemFile data_in(buffer, size);
1841 m_client->ProcessCaptchaRequest(&data_in);
1842 break;
1844 case OP_CHATCAPTCHARES:
1846 AddDebugLogLineN(logRemoteClient, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client->GetFullIP());
1847 theStats::AddDownOverheadOther(size);
1848 if (size) {
1849 m_client->ProcessCaptchaReqRes(buffer[0]);
1851 break;
1853 case OP_FWCHECKUDPREQ: { // Support required for Kadversion >= 6
1854 AddDebugLogLineM(false, logRemoteClient, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client->GetFullIP());
1855 theStats::AddDownOverheadOther(size);
1856 CMemFile data_in(buffer, size);
1857 m_client->ProcessFirewallCheckUDPRequest(&data_in);
1858 break;
1860 case OP_KAD_FWTCPCHECK_ACK: { // Support required for Kadversion >= 7
1861 AddDebugLogLineM(false, logRemoteClient, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client->GetFullIP());
1862 if (theApp->clientlist->IsKadFirewallCheckIP(m_client->GetIP())) {
1863 if (Kademlia::CKademlia::IsRunning()) {
1864 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1866 } else {
1867 AddDebugLogLineM(false, logListenSocket, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client->GetFullIP());
1869 break;
1871 default:
1872 theStats::AddDownOverheadOther(size);
1873 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode,opcode) + m_client->GetFullIP());
1874 break;
1877 return true;
1880 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte* buffer, uint32 size, uint8 opcode)
1882 #ifdef __PACKET_RECV_DUMP__
1883 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1884 DumpMem(buffer,size);
1885 #endif
1887 if (!m_client) {
1888 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1891 CMemFile data(buffer, size);
1892 try {
1893 switch(opcode) {
1894 case OP_QUEUERANK: {
1895 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client->GetFullIP() );
1897 uint8 numtags = data.ReadUInt8();
1898 wxASSERT(numtags == 1);
1899 if(numtags){} // prevent GCC warning
1901 m_client->SetRemoteQueueRank(data.GetIntTagValue());
1903 theStats::AddDownOverheadFileRequest(size);
1904 break;
1907 case OP_REQUESTPARTS: {
1908 AddDebugLogLineM( false, logRemoteClient, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client->GetFullIP() );
1910 m_client->ProcessRequestPartsPacketv2(data);
1912 theStats::AddDownOverheadFileRequest(size);
1913 break;
1916 default:
1917 theStats::AddDownOverheadOther(size);
1918 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode, opcode) + m_client->GetFullIP());
1920 } catch (...) {
1921 AddDebugLogLineM( false, logRemoteClient, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data.GetPosition(), opcode, opcode) + m_client->GetFullIP());
1922 throw;
1925 return true;
1928 void CClientTCPSocket::OnConnect(int nErrorCode)
1930 if (nErrorCode) {
1931 OnError(nErrorCode);
1932 } else if (!m_client) {
1933 // and now? Disconnect? not?
1934 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted!)") );
1935 } else if (!m_client->SendHelloPacket()) {
1936 // and now? Disconnect? not?
1937 AddDebugLogLineM( false, logClient, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1938 } else {
1939 ResetTimeOutTimer();
1944 void CClientTCPSocket::OnSend(int nErrorCode)
1946 ResetTimeOutTimer();
1947 CEMSocket::OnSend(nErrorCode);
1951 void CClientTCPSocket::OnReceive(int nErrorCode)
1953 ResetTimeOutTimer();
1954 // We might have updated ipfilter
1955 wxASSERT(m_remoteip);
1957 if (theApp->ipfilter->IsFiltered(m_remoteip)) {
1958 if (m_client) {
1959 m_client->Safe_Delete();
1961 Safe_Delete();
1962 AddDebugLogLineM( false, logIPFilter, wxT("A connected client was dropped by IPFilter on new packet received"));
1963 } else {
1964 CEMSocket::OnReceive(nErrorCode);
1969 void CClientTCPSocket::OnError(int nErrorCode)
1971 //printf("* Called OnError for %p\n",this);
1972 // 0.42e + Kry changes for handling of socket lost events
1973 wxString strError;
1975 if ((nErrorCode == 0) || (nErrorCode == 7) || (nErrorCode == 0xFEFF)) {
1976 if (m_client) {
1977 if (!m_client->GetUserName().IsEmpty()) {
1978 strError = wxT("Client '") + m_client->GetUserName() + wxT("'");
1979 } else {
1980 strError = wxT("An unnamed client");
1982 strError += wxT(" (IP:") + m_client->GetFullIP() + wxT(") ");
1983 } else {
1984 strError = wxT("A client ");
1986 if (nErrorCode == 0) {
1987 strError += wxT("closed connection.");
1988 } else if (nErrorCode == 0xFEFF) {
1989 strError += wxT(" caused a wxSOCKET_LOST event.");
1990 } else {
1991 strError += wxT("caused a socket blocking error.");
1993 } else {
1994 if (theLogger.IsEnabled(logClient) && nErrorCode != 107) {
1995 // 0 -> No Error / Disconect
1996 // 107 -> Transport endpoint is not connected
1997 if (m_client) {
1998 if (!m_client->GetUserName().IsEmpty()) {
1999 strError = wxT("OnError: Client '") + m_client->GetUserName() +
2000 wxT("' (IP:") + m_client->GetFullIP() +
2001 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
2002 } else {
2003 strError = wxT("OnError: Unknown client (IP:") +
2004 m_client->GetFullIP() +
2005 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode);
2007 } else {
2008 strError = wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
2009 nErrorCode);
2011 } else {
2012 strError = wxT("Error 107 (Transport endpoint is not connected)");
2016 Disconnect(strError);
2020 bool CClientTCPSocket::PacketReceived(CPacket* packet)
2022 // 0.42e
2023 bool bResult = false;
2024 uint32 uRawSize = packet->GetPacketSize();
2026 AddDebugLogLineM( false, logRemoteClient,
2027 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
2028 % packet->GetProtocol()
2029 % packet->GetOpCode()
2030 % packet->GetPacketSize()
2031 % ( m_client ? m_client->GetFullIP() : wxT("Unknown Client") )
2034 wxString exception;
2036 try {
2037 bool process = true;
2039 if ((packet->GetProtocol() == OP_PACKEDPROT) ||
2040 (packet->GetProtocol() == OP_ED2KV2PACKEDPROT)) {
2042 if (!packet->UnPackPacket()) {
2043 AddDebugLogLineM( false, logZLib, wxT("Failed to decompress client TCP packet."));
2044 bResult = false;
2045 process = false;
2046 } else {
2047 AddDebugLogLineM(false, logRemoteClient,
2048 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
2049 packet->GetProtocol(),
2050 packet->GetOpCode(),
2051 packet->GetPacketSize())
2056 if (process) {
2057 switch (packet->GetProtocol()) {
2058 case OP_EDONKEYPROT:
2059 bResult = ProcessPacket(packet->GetDataBuffer(),uRawSize,packet->GetOpCode());
2060 break;
2061 case OP_EMULEPROT:
2062 bResult = ProcessExtPacket(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2063 break;
2064 case OP_ED2KV2HEADER:
2065 bResult = ProcessED2Kv2Packet(packet->GetDataBuffer(), packet->GetPacketSize(), packet->GetOpCode());
2066 break;
2067 case OP_ED2KV2PACKEDPROT:
2068 case OP_PACKEDPROT:
2069 // Packed inside packed?
2070 wxFAIL;
2071 break;
2072 default: {
2073 theStats::AddDownOverheadOther(uRawSize);
2074 if (m_client) {
2075 m_client->SetDownloadState(DS_ERROR);
2077 Disconnect(wxT("Unknown protocol"));
2078 bResult = false;
2082 } catch (const CEOFException& err) {
2083 exception = wxT("EOF exception: ") + err.what();
2084 } catch (const CInvalidPacket& err) {
2085 exception = wxT("InvalidPacket exception: ") + err.what();
2086 } catch (const wxString& error) {
2087 exception = wxT("error: ") + (error.IsEmpty() ? wxString(wxT("Unknown error")) : error);
2090 if (!exception.IsEmpty()) {
2091 AddDebugLogLineM( false, logPacketErrors,
2092 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2093 % exception
2094 % packet->GetProtocol()
2095 % packet->GetOpCode()
2096 % packet->GetPacketSize()
2097 % ( m_client ? m_client->GetClientFullInfo() : wxT("Unknown") )
2100 if (m_client) {
2101 m_client->SetDownloadState(DS_ERROR);
2104 AddDebugLogLineM( false, logClient,
2105 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2106 % ( m_client ? m_client->GetUserName() : wxString(wxT("Unknown")) )
2107 % ( m_client ? m_client->GetFullIP() : wxString(wxT("Unknown")) )
2108 % exception
2111 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2114 return bResult;
2118 SocketSentBytes CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2120 SocketSentBytes returnStatus = CEMSocket::SendControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2122 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2123 ResetTimeOutTimer();
2126 return returnStatus;
2130 SocketSentBytes CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend, uint32 overchargeMaxBytesToSend)
2132 SocketSentBytes returnStatus = CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend, overchargeMaxBytesToSend);
2134 if(returnStatus.success && (returnStatus.sentBytesControlPackets > 0 || returnStatus.sentBytesStandardPackets > 0)) {
2135 ResetTimeOutTimer();
2138 return returnStatus;
2142 void CClientTCPSocket::SendPacket(CPacket* packet, bool delpacket, bool controlpacket, uint32 actualPayloadSize)
2144 ResetTimeOutTimer();
2145 CEMSocket::SendPacket(packet,delpacket,controlpacket, actualPayloadSize);
2147 // File_checked_for_headers