2 // This file is part of the aMule Project.
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 )
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
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.
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 <protocol/kad2/Client2Client/TCP.h>
33 #include <common/EventIDs.h>
35 #include "Preferences.h" // Needed for thePrefs
36 #include "Packet.h" // Needed for CPacket
37 #include "Statistics.h" // Needed for theStats
38 #include "Logger.h" // Neeed for logRemoteClient
39 #include "updownclient.h" // Needed for CUpDownClient
40 #include <common/Format.h> // Needed for CFormat
41 #include "amule.h" // Needed for theApp
42 #include "SharedFileList.h" // Needed for CSharedFileList
43 #include "ClientList.h" // Needed for CClientList
44 #include "UploadQueue.h" // Needed for CUploadQueue
45 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket
46 #include "PartFile.h" // Needed for CPartFile
47 #include "MemFile.h" // Needed for CMemFile
48 #include "kademlia/kademlia/Kademlia.h" // Needed for CKademlia::Kademlia
49 #include "kademlia/kademlia/Prefs.h" // Needed for CKademlia::CPrefs
50 #include "DownloadQueue.h" // Needed for CDownloadQueue
51 #include "Server.h" // Needed for CServer
52 #include "ServerList.h" // Needed for CServerList
53 #include "IPFilter.h" // Needed for CIPFilter
54 #include "ListenSocket.h" // Needed for CListenSocket
55 #include "GuiEvents.h" // Needed for Notify_*
58 //#define __PACKET_RECV_DUMP__
60 //------------------------------------------------------------------------------
61 // CClientTCPSocketHandler
62 //------------------------------------------------------------------------------
64 class CClientTCPSocketHandler
: public wxEvtHandler
67 CClientTCPSocketHandler() {};
70 void ClientTCPSocketHandler(wxSocketEvent
& event
);
74 BEGIN_EVENT_TABLE(CClientTCPSocketHandler
, wxEvtHandler
)
75 EVT_SOCKET(ID_CLIENTTCPSOCKET_EVENT
, CClientTCPSocketHandler::ClientTCPSocketHandler
)
78 void CClientTCPSocketHandler::ClientTCPSocketHandler(wxSocketEvent
& event
)
80 CClientTCPSocket
*socket
= dynamic_cast<CClientTCPSocket
*>(event
.GetSocket());
86 if (socket
->OnDestroy() || socket
->ForDeletion()) {
90 switch(event
.GetSocketEvent()) {
92 socket
->OnError(0xFEFF /* SOCKET_LOST is not an error */);
100 case wxSOCKET_CONNECTION
:
101 // connection stablished, nothing to do about it?
102 socket
->OnConnect(socket
->Error() ? socket
->LastError() : 0);
105 // Nothing should arrive here...
112 // There can be only one. :)
114 static CClientTCPSocketHandler g_clientReqSocketHandler
;
117 //------------------------------------------------------------------------------
119 //------------------------------------------------------------------------------
121 CClientTCPSocket::CClientTCPSocket(CUpDownClient
* in_client
, const CProxyData
*ProxyData
)
122 : CEMSocket(ProxyData
)
124 SetClient(in_client
);
126 m_remoteip
= wxUINT32_SWAP_ALWAYS(in_client
->GetUserIDHybrid());
132 m_ForDeletion
= false;
134 SetEventHandler(g_clientReqSocketHandler
, ID_CLIENTTCPSOCKET_EVENT
);
136 wxSOCKET_CONNECTION_FLAG
|
137 wxSOCKET_INPUT_FLAG
|
138 wxSOCKET_OUTPUT_FLAG
|
142 theApp
->listensocket
->AddSocket(this);
143 theApp
->listensocket
->AddConnection();
146 CClientTCPSocket::~CClientTCPSocket()
148 // remove event handler
153 m_client
->SetSocket( NULL
);
157 if (theApp
->listensocket
&& !theApp
->listensocket
->OnShutdown()) {
158 theApp
->listensocket
->RemoveSocket(this);
162 bool CClientTCPSocket::InitNetworkData()
164 wxASSERT(!m_remoteip
);
166 amuleIPV4Address addr
;
168 m_remoteip
= StringIPtoUint32(addr
.IPAddress());
170 MULE_CHECK(m_remoteip
, false);
172 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
173 AddDebugLogLineM(false, logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Filtered IP)"));
175 } else if (theApp
->clientlist
->IsBannedClient(m_remoteip
)) {
176 AddDebugLogLineM(false, logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Banned IP)"));
179 AddDebugLogLineM(false, logClient
, wxT("Accepted connection from ") + addr
.IPAddress());
184 void CClientTCPSocket::ResetTimeOutTimer()
186 timeout_timer
= ::GetTickCount();
190 bool CClientTCPSocket::CheckTimeOut()
193 uint32 uTimeout
= GetTimeOut();
196 if (m_client
->GetKadState() == KS_CONNECTED_BUDDY
) {
197 //We originally ignored the timeout here for buddies.
198 //This was a stupid idea on my part. There is now a ping/pong system
199 //for buddies. This ping/pong system now prevents timeouts.
200 //This release will allow lowID clients with KadVersion 0 to remain connected.
201 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
202 //JOHNTODO: Don't forget to remove backward support in a future release.
203 if ( m_client
->GetKadVersion() == 0 ) {
207 uTimeout
+= MIN2MS(15);
210 if (m_client
->GetChatState() != MS_NONE
) {
211 uTimeout
+= CONNECTION_TIMEOUT
;
215 if (::GetTickCount() - timeout_timer
> uTimeout
){
216 timeout_timer
= ::GetTickCount();
217 Disconnect(wxT("Timeout"));
225 void CClientTCPSocket::SetClient(CUpDownClient
* pClient
)
229 m_client
->SetSocket( this );
234 void CClientTCPSocket::OnClose(int nErrorCode
)
237 wxASSERT(theApp
->listensocket
->IsValidSocket(this));
238 CEMSocket::OnClose(nErrorCode
);
240 Disconnect(wxString::Format(wxT("Closed: %u"), nErrorCode
));
242 Disconnect(wxT("Close"));
247 void CClientTCPSocket::Disconnect(const wxString
& strReason
)
249 byConnected
= ES_DISCONNECTED
;
251 if (m_client
->Disconnected(strReason
, true)) {
252 // Somehow, Safe_Delete() is beeing called by Disconnected(),
253 // or any other function that sets m_client to NULL,
254 // so we must check m_client first.
256 m_client
->SetSocket( NULL
);
257 m_client
->Safe_Delete();
267 void CClientTCPSocket::Safe_Delete()
269 if ( !ForDeletion() && !OnDestroy() ) {
273 // lfroen: first of all - stop handler
274 m_ForDeletion
= true;
277 m_client
->SetSocket( NULL
);
281 byConnected
= ES_DISCONNECTED
;
282 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
288 bool CClientTCPSocket::ProcessPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
290 #ifdef __PACKET_RECV_DUMP__
291 //printf("Rec: OPCODE %x \n",opcode);
292 DumpMem(buffer
, size
);
294 if (!m_client
&& opcode
!= OP_HELLO
) {
295 throw wxString(wxT("Asks for something without saying hello"));
296 } else if (m_client
&& opcode
!= OP_HELLO
&& opcode
!= OP_HELLOANSWER
) {
297 m_client
->CheckHandshakeFinished(OP_EDONKEYPROT
, opcode
);
301 case OP_HELLOANSWER
: { // 0.43b
302 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HELLOANSWER from ") + m_client
->GetFullIP());
303 theStats::AddDownOverheadOther(size
);
304 m_client
->ProcessHelloAnswer(buffer
, size
);
306 // start secure identification, if
307 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
308 // - we have received eMule-OP_HELLOANSWER (new eMule)
309 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
310 m_client
->InfoPacketsReceived();
313 // Socket might die because of sending in InfoPacketsReceived, so check
315 m_client
->ConnectionEstablished();
318 // Socket might die on ConnectionEstablished somehow. Check it.
320 Notify_UploadCtrlRefreshClient( m_client
);
325 case OP_HELLO
: { // 0.43b
327 theStats::AddDownOverheadOther(size
);
328 bool bNewClient
= !m_client
;
330 // create new client to save standart informations
331 m_client
= new CUpDownClient(this);
335 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HELLO from ") + m_client
->GetFullIP() );
337 bool bIsMuleHello
= false;
340 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
342 if (bNewClient
&& m_client
) {
343 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
344 m_client
->Safe_Delete();
350 if (thePrefs::ParanoidFilter() && !IsLowID(m_client
->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid()))) {
351 wxString reason
= wxT("Client claims a different IP from the one we received the hello packet from: ");
352 reason
+= Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
353 AddDebugLogLineM(false, logClient
, reason
);
355 m_client
->Safe_Delete();
358 Disconnect(wxT("Paranoid disconecting: ") + reason
);
362 // if IP is filtered, dont reply but disconnect...
363 if (theApp
->ipfilter
->IsFiltered(m_client
->GetIP())) {
365 m_client
->Safe_Delete();
368 Disconnect(wxT("IPFilter"));
374 // now we check if we now this client already. if yes this socket will
375 // be attached to the known client, the new client will be deleted
376 // and the var. "client" will point to the known client.
377 // if not we keep our new-constructed client ;)
378 if (theApp
->clientlist
->AttachToAlreadyKnown(&m_client
,this)) {
379 // update the old client informations
380 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
382 theApp
->clientlist
->AddClient(m_client
);
383 m_client
->SetCommentDirty();
385 Notify_UploadCtrlRefreshClient( m_client
);
386 // send a response packet with standart informations
387 if ((m_client
->GetHashType() == SO_EMULE
) && !bIsMuleHello
) {
388 m_client
->SendMuleInfoPacket(false);
391 // Client might die from Sending in SendMuleInfoPacket, so check
393 m_client
->SendHelloAnswer();
396 // Kry - If the other side supports it, send OS_INFO
397 // Client might die from Sending in SendHelloAnswer, so check
398 if (m_client
&& m_client
->GetOSInfoSupport()) {
399 m_client
->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
402 // Client might die from Sending in SendMuleInfoPacket, so check
404 m_client
->ConnectionEstablished();
407 // start secure identification, if
408 // - we have received eMule-OP_HELLO (new eMule)
409 if (m_client
&& m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
410 m_client
->InfoPacketsReceived();
415 case OP_REQUESTFILENAME
: { // 0.43b
416 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client
->GetFullIP() );
418 theStats::AddDownOverheadFileRequest(size
);
419 // IP banned, no answer for this request
420 if (m_client
->IsBanned()) {
424 if (!m_client
->GetWaitStartTime()) {
425 m_client
->SetWaitStartTime();
427 CMemFile
data_in(buffer
, size
);
428 CMD4Hash reqfilehash
= data_in
.ReadHash();
429 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
430 if ( reqfile
== NULL
) {
431 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
432 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
436 // if we are downloading this file, this could be a new source
437 // no passive adding of files with only one part
438 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
439 if (thePrefs::GetMaxSourcePerFile() >
440 ((CPartFile
*)reqfile
)->GetSourceCount()) {
441 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
445 // check to see if this is a new file they are asking for
446 if (m_client
->GetUploadFileID() != reqfilehash
) {
447 m_client
->SetCommentDirty();
450 m_client
->SetUploadFileID(reqfile
);
451 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
454 CMemFile
data_out(128);
455 data_out
.WriteHash(reqfile
->GetFileHash());
457 // Since it's for somebody else to see, we need to send the prettified
458 // filename, rather than the (possibly) mangled actual filename.
459 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
461 CPacket
* packet
= new CPacket(data_out
, OP_EDONKEYPROT
, OP_REQFILENAMEANSWER
);
462 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
463 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client
->GetFullIP() );
464 SendPacket(packet
,true);
466 // SendPacket might kill the socket, so check
468 m_client
->SendCommentInfo(reqfile
);
472 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
475 case OP_SETREQFILEID
: { // 0.43b EXCEPT track of bad clients
476 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SETREQFILEID from ") + m_client
->GetFullIP() );
478 theStats::AddDownOverheadFileRequest(size
);
480 if (m_client
->IsBanned()) {
486 if (!m_client
->GetWaitStartTime()) {
487 m_client
->SetWaitStartTime();
490 const CMD4Hash
fileID(buffer
);
491 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
492 if ( reqfile
== NULL
) {
493 reqfile
= theApp
->downloadqueue
->GetFileByID(fileID
);
494 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
495 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
496 replypacket
->Copy16ToDataBuffer(fileID
.GetHash());
497 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
498 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILERE to ") + m_client
->GetFullIP() );
499 SendPacket(replypacket
, true);
504 // check to see if this is a new file they are asking for
505 if (m_client
->GetUploadFileID() != fileID
) {
506 m_client
->SetCommentDirty();
509 m_client
->SetUploadFileID(reqfile
);
511 CMemFile
data(16+16);
512 data
.WriteHash(reqfile
->GetFileHash());
513 if (reqfile
->IsPartFile()) {
514 ((CPartFile
*)reqfile
)->WritePartStatus(&data
);
518 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_FILESTATUS
);
519 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
520 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILESTATUS to ") + m_client
->GetFullIP() );
521 SendPacket(packet
, true);
524 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
529 case OP_FILEREQANSNOFIL
: { // 0.43b protocol, lacks ZZ's download manager on swap
530 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client
->GetFullIP() );
532 theStats::AddDownOverheadFileRequest(size
);
534 // if that client does not have my file maybe has another different
535 CPartFile
* reqfile
= theApp
->downloadqueue
->GetFileByID(CMD4Hash(buffer
));
537 reqfile
->AddDeadSource( m_client
);
542 // we try to swap to another file ignoring no needed parts files
543 switch (m_client
->GetDownloadState()) {
546 case DS_NONEEDEDPARTS
:
547 if (!m_client
->SwapToAnotherFile(true, true, true, NULL
)) {
548 theApp
->downloadqueue
->RemoveSource(m_client
);
554 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
558 case OP_REQFILENAMEANSWER
: { // 0.43b except check for bad clients
559 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client
->GetFullIP() );
561 theStats::AddDownOverheadFileRequest(size
);
562 CMemFile
data(buffer
, size
);
563 CMD4Hash hash
= data
.ReadHash();
564 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
565 m_client
->ProcessFileInfo(&data
, file
);
569 case OP_FILESTATUS
: { // 0.43b except check for bad clients
570 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILESTATUS from ") + m_client
->GetFullIP() );
572 theStats::AddDownOverheadFileRequest(size
);
573 CMemFile
data(buffer
, size
);
574 CMD4Hash hash
= data
.ReadHash();
575 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
576 m_client
->ProcessFileStatus(false, &data
, file
);
580 case OP_STARTUPLOADREQ
: {
581 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client
->GetFullIP() );
583 theStats::AddDownOverheadFileRequest(size
);
585 if (!m_client
->CheckHandshakeFinished(OP_EDONKEYPROT
, opcode
)) {
589 m_client
->CheckForAggressive();
590 if ( m_client
->IsBanned() ) {
595 const CMD4Hash
fileID(buffer
);
596 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
598 if (m_client
->GetUploadFileID() != fileID
) {
599 m_client
->SetCommentDirty();
601 m_client
->SetUploadFileID(reqfile
);
602 m_client
->SendCommentInfo(reqfile
);
604 // Socket might die because of SendCommentInfo, so check
606 theApp
->uploadqueue
->AddClientToQueue(m_client
);
612 case OP_QUEUERANK
: { // 0.43b
613 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_QUEUERANK from ") + m_client
->GetFullIP() );
615 theStats::AddDownOverheadFileRequest(size
);
616 CMemFile
data(buffer
, size
);
617 uint32 rank
= data
.ReadUInt32();
619 m_client
->SetRemoteQueueRank(rank
);
623 case OP_ACCEPTUPLOADREQ
: { // 0.42e (xcept khaos stats)
624 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client
->GetFullIP() );
626 theStats::AddDownOverheadFileRequest(size
);
627 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
628 if (m_client
->GetDownloadState() == DS_ONQUEUE
) {
629 m_client
->SetDownloadState(DS_DOWNLOADING
);
630 m_client
->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
631 m_client
->SendBlockRequests();
634 if (!m_client
->GetSentCancelTransfer()) {
635 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
636 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
637 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
638 m_client
->SendPacket(packet
,true,true);
640 // SendPacket can cause the socket to die, so check
642 m_client
->SetSentCancelTransfer(1);
646 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
651 case OP_REQUESTPARTS
: { // 0.43b
652 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
654 theStats::AddDownOverheadFileRequest(size
);
656 m_client
->ProcessRequestPartsPacket(buffer
, size
, false);
661 case OP_CANCELTRANSFER
: { // 0.43b
662 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client
->GetFullIP() );
664 theStats::AddDownOverheadFileRequest(size
);
665 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
666 if ( CLogger::IsEnabled( logClient
) ) {
667 AddDebugLogLineM( false, logClient
, m_client
->GetUserName() + wxT(": Upload session ended due canceled transfer."));
672 case OP_END_OF_DOWNLOAD
: { // 0.43b except check for bad clients
673 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client
->GetFullIP() );
675 theStats::AddDownOverheadFileRequest(size
);
676 if (size
>=16 && m_client
->GetUploadFileID() == CMD4Hash(buffer
)) {
677 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
678 if ( CLogger::IsEnabled( logClient
) ) {
679 AddDebugLogLineM( false, logClient
, m_client
->GetUserName() + wxT(": Upload session ended due ended transfer."));
685 case OP_HASHSETREQUEST
: { // 0.43b except check for bad clients
686 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client
->GetFullIP() );
689 theStats::AddDownOverheadFileRequest(size
);
691 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
693 m_client
->SendHashsetPacket(CMD4Hash(buffer
));
697 case OP_HASHSETANSWER
: { // 0.43b
698 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client
->GetFullIP() );
700 theStats::AddDownOverheadFileRequest(size
);
701 m_client
->ProcessHashSet(buffer
, size
);
705 case OP_SENDINGPART
: { // 0.47a
706 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SENDINGPART from ") + m_client
->GetFullIP() );
708 if ( m_client
->GetRequestFile() &&
709 !m_client
->GetRequestFile()->IsStopped() &&
710 (m_client
->GetRequestFile()->GetStatus() == PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
712 m_client
->ProcessBlockPacket(buffer
, size
, false, false);
715 ( m_client
->GetRequestFile()->IsStopped() ||
716 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
717 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
) ) {
718 if (!m_client
->GetSentCancelTransfer()) {
719 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
720 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
721 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
722 m_client
->SendPacket(packet
,true,true);
724 // Socket might die because of SendPacket, so check
726 m_client
->SetSentCancelTransfer(1);
730 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
733 if (!m_client
->GetSentCancelTransfer()) {
734 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
735 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
736 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
737 m_client
->SendPacket(packet
,true,true);
739 // Socket might die because of SendPacket, so check
740 m_client
->SetSentCancelTransfer(1);
742 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
747 case OP_OUTOFPARTREQS
: { // 0.43b
748 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client
->GetFullIP() );
750 theStats::AddDownOverheadFileRequest(size
);
751 if (m_client
->GetDownloadState() == DS_DOWNLOADING
) {
752 m_client
->SetDownloadState(DS_ONQUEUE
);
757 case OP_CHANGE_CLIENT_ID
: { // Kad reviewed
758 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client
->GetFullIP() );
760 theStats::AddDownOverheadOther(size
);
761 CMemFile
data(buffer
, size
);
762 uint32 nNewUserID
= data
.ReadUInt32();
763 uint32 nNewServerIP
= data
.ReadUInt32();
765 if (IsLowID(nNewUserID
)) { // client changed server and gots a LowID
766 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
767 if (pNewServer
!= NULL
){
768 m_client
->SetUserIDHybrid(nNewUserID
); // update UserID only if we know the server
769 m_client
->SetServerIP(nNewServerIP
);
770 m_client
->SetServerPort(pNewServer
->GetPort());
772 } else if (nNewUserID
== m_client
->GetIP()) { // client changed server and gots a HighID(IP)
773 m_client
->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID
));
774 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
775 if (pNewServer
!= NULL
){
776 m_client
->SetServerIP(nNewServerIP
);
777 m_client
->SetServerPort(pNewServer
->GetPort());
784 case OP_CHANGE_SLOT
:{ // 0.43b
785 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client
->GetFullIP() );
787 // sometimes sent by Hybrid
788 theStats::AddDownOverheadOther(size
);
792 case OP_MESSAGE
: { // 0.43b
793 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MESSAGE from ") + m_client
->GetFullIP() );
795 theStats::AddDownOverheadOther(size
);
797 CMemFile
message_file(buffer
, size
);
799 wxString message
= message_file
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
800 if (IsMessageFiltered(message
, m_client
)) {
801 AddLogLineM( true, CFormat(_("Message filtered from '%s' (IP:%s)")) % m_client
->GetUserName() % m_client
->GetFullIP());
803 AddLogLineM( true, CFormat(_("New message from '%s' (IP:%s)")) % m_client
->GetUserName() % m_client
->GetFullIP());
805 Notify_ChatProcessMsg(GUI_ID(m_client
->GetIP(),m_client
->GetUserPort()), m_client
->GetUserName() + wxT("|") + message
);
810 case OP_ASKSHAREDFILES
: { // 0.43b (well, er, it does the same, but in our own way)
811 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client
->GetFullIP() );
813 // client wants to know what we have in share, let's see if we allow him to know that
814 theStats::AddDownOverheadOther(size
);
815 // IP banned, no answer for this request
816 if (m_client
->IsBanned()) {
820 if (thePrefs::CanSeeShares() == vsfaEverybody
|| (thePrefs::CanSeeShares() == vsfaFriends
&& m_client
->IsFriend())) {
821 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
822 % m_client
->GetUserName()
823 % m_client
->GetUserIDHybrid() );
825 std::vector
<CKnownFile
*> list
;
826 theApp
->sharedfiles
->CopyFileList(list
);
828 CMemFile
tempfile(80);
829 tempfile
.WriteUInt32(list
.size());
830 for (unsigned i
= 0; i
< list
.size(); ++i
) {
831 if (!list
[i
]->IsLargeFile() || m_client
->SupportsLargeFiles()) {
832 theApp
->sharedfiles
->CreateOfferedFilePacket(list
[i
], &tempfile
, NULL
, m_client
);
836 // create a packet and send it
837 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESANSWER
);
838 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client
->GetFullIP() );
839 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
840 SendPacket(replypacket
, true, true);
842 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
843 % m_client
->GetUserName()
844 % m_client
->GetUserIDHybrid() );
846 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
847 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
848 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
849 SendPacket(replypacket
, true, true);
855 case OP_ASKSHAREDFILESANSWER
: { // 0.43b
856 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client
->GetFullIP() );
858 theStats::AddDownOverheadOther(size
);
860 m_client
->ProcessSharedFileList(buffer
, size
, EmptyStr
);
864 case OP_ASKSHAREDDIRS
: { // 0.43b
865 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client
->GetFullIP() );
867 theStats::AddDownOverheadOther(size
);
868 wxASSERT( size
== 0 );
869 // IP banned, no answer for this request
870 if (m_client
->IsBanned()) {
873 if ((thePrefs::CanSeeShares()==vsfaEverybody
) || ((thePrefs::CanSeeShares()==vsfaFriends
) && m_client
->IsFriend())) {
874 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
875 % m_client
->GetUserName()
876 % m_client
->GetUserIDHybrid() );
878 // This list will contain all (unique) folders.
879 std::list
<CPath
> foldersToSend
;
881 // The shared folders
882 const unsigned folderCount
= theApp
->glob_prefs
->shareddir_list
.size();
883 for (unsigned i
= 0; i
< folderCount
; ++i
) {
884 foldersToSend
.push_back(theApp
->glob_prefs
->shareddir_list
[i
]);
887 // ... the categories folders ... (category 0 -> incoming)
888 for (unsigned i
= 0; i
< theApp
->glob_prefs
->GetCatCount(); ++i
) {
889 foldersToSend
.push_back(theApp
->glob_prefs
->GetCategory(i
)->path
);
892 // ... and the Magic thing from the eDonkey Hybrids...
893 foldersToSend
.push_back(CPath(OP_INCOMPLETE_SHARED_FILES
));
896 foldersToSend
.sort();
897 foldersToSend
.unique();
900 CMemFile
tempfile(80);
901 tempfile
.WriteUInt32(foldersToSend
.size());
903 std::list
<CPath
>::iterator it
= foldersToSend
.begin();
904 for (; it
!= foldersToSend
.end(); ++it
) {
905 // We need to send the 'raw' filename, so we can recognize it again.
906 tempfile
.WriteString(it
->GetRaw(), m_client
->GetUnicodeSupport());
909 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDDIRSANS
);
910 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
911 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client
->GetFullIP() );
912 SendPacket(replypacket
, true, true);
914 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
915 % m_client
->GetUserName()
916 % m_client
->GetUserIDHybrid() );
918 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
919 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
920 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
921 SendPacket(replypacket
, true, true);
927 case OP_ASKSHAREDFILESDIR
: { // 0.43b
928 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client
->GetFullIP() );
930 theStats::AddDownOverheadOther(size
);
931 // IP banned, no answer for this request
932 if (m_client
->IsBanned()) {
935 CMemFile
data(buffer
, size
);
937 wxString strReqDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
938 if (thePrefs::CanSeeShares()==vsfaEverybody
|| (thePrefs::CanSeeShares()==vsfaFriends
&& m_client
->IsFriend())) {
939 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
940 wxASSERT( data
.GetPosition() == data
.GetLength() );
942 CKnownFilePtrList list
;
944 if (strReqDir
== OP_INCOMPLETE_SHARED_FILES
) {
945 // get all shared files from download queue
946 int iQueuedFiles
= theApp
->downloadqueue
->GetFileCount();
947 for (int i
= 0; i
< iQueuedFiles
; i
++) {
948 CPartFile
* pFile
= theApp
->downloadqueue
->GetFileByIndex(i
);
949 if (pFile
== NULL
|| pFile
->GetStatus(true) != PS_READY
) {
953 list
.push_back(pFile
);
956 theApp
->sharedfiles
->GetSharedFilesByDirectory(strReqDir
, list
);
959 CMemFile
tempfile(80);
960 tempfile
.WriteString(strReqDir
, m_client
->GetUnicodeSupport());
961 tempfile
.WriteUInt32(list
.size());
963 while (!list
.empty()) {
964 if (!list
.front()->IsLargeFile() || m_client
->SupportsLargeFiles()) {
965 theApp
->sharedfiles
->CreateOfferedFilePacket(list
.front(), &tempfile
, NULL
, m_client
);
971 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIRANS
);
972 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
973 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client
->GetFullIP() );
974 SendPacket(replypacket
, true, true);
976 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
978 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
979 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
980 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
981 SendPacket(replypacket
, true, true);
986 case OP_ASKSHAREDDIRSANS
:{ // 0.43b
987 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client
->GetFullIP() );
989 theStats::AddDownOverheadOther(size
);
990 if (m_client
->GetFileListRequested() == 1){
991 CMemFile
data(buffer
, size
);
992 uint32 uDirs
= data
.ReadUInt32();
993 for (uint32 i
= 0; i
< uDirs
; i
++){
994 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
995 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
996 % m_client
->GetUserName()
997 % m_client
->GetUserIDHybrid()
1000 CMemFile
tempfile(80);
1001 tempfile
.WriteString(strDir
, m_client
->GetUnicodeSupport());
1002 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIR
);
1003 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
1004 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client
->GetFullIP() );
1005 SendPacket(replypacket
, true, true);
1007 wxASSERT( data
.GetPosition() == data
.GetLength() );
1008 m_client
->SetFileListRequested(uDirs
);
1010 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1011 % m_client
->GetUserName()
1012 % m_client
->GetUserIDHybrid() );
1017 case OP_ASKSHAREDFILESDIRANS
: { // 0.43b
1018 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client
->GetFullIP() );
1020 theStats::AddDownOverheadOther(size
);
1021 CMemFile
data(buffer
, size
);
1022 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
1024 if (m_client
->GetFileListRequested() > 0){
1025 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1026 % m_client
->GetUserName()
1027 % m_client
->GetUserIDHybrid()
1030 m_client
->ProcessSharedFileList(buffer
+ data
.GetPosition(), size
- data
.GetPosition(), strDir
);
1031 if (m_client
->GetFileListRequested() == 0) {
1032 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1033 % m_client
->GetUserName()
1034 % m_client
->GetUserIDHybrid() );
1037 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1038 % m_client
->GetUserName()
1039 % m_client
->GetUserIDHybrid() );
1044 case OP_ASKSHAREDDENIEDANS
:
1045 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client
->GetFullIP() );
1047 theStats::AddDownOverheadOther(size
);
1048 wxASSERT( size
== 0 );
1049 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1050 % m_client
->GetUserName()
1051 % m_client
->GetUserIDHybrid() );
1053 m_client
->SetFileListRequested(0);
1057 theStats::AddDownOverheadOther(size
);
1058 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode
, opcode
) + m_client
->GetFullIP());
1066 bool CClientTCPSocket::ProcessExtPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
1068 #ifdef __PACKET_RECV_DUMP__
1069 //printf("Rec: OPCODE %x \n",opcode);
1070 DumpMem(buffer
,size
);
1073 // 0.42e - except the catchs on mem exception and file exception
1075 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1078 if (!client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1079 // Here comes a extended packet without finishing the hanshake.
1080 // IMHO, we should disconnect the client.
1081 throw wxString(wxT("Client send extended packet before finishing handshake"));
1085 case OP_MULTIPACKET_EXT
:
1086 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client
->GetFullIP());
1087 case OP_MULTIPACKET
: {
1088 if (opcode
== OP_MULTIPACKET
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET from ") + m_client
->GetFullIP() );
1090 theStats::AddDownOverheadFileRequest(size
);
1092 if (m_client
->IsBanned()) {
1096 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1097 // Here comes a extended packet without finishing the hanshake.
1098 // IMHO, we should disconnect the client.
1099 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1102 CMemFile
data_in(buffer
, size
);
1103 CMD4Hash reqfilehash
= data_in
.ReadHash();
1104 uint64 nSize
= (opcode
== OP_MULTIPACKET_EXT
) ? data_in
.ReadUInt64() : 0;
1106 bool file_not_found
= false;
1107 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
1108 if ( reqfile
== NULL
){
1109 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1110 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
1111 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a non-shared file"));
1112 file_not_found
= true;
1116 if (!file_not_found
&& reqfile
->IsLargeFile() && !m_client
->SupportsLargeFiles()) {
1117 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a large file but doesn't support them"));
1118 file_not_found
= true;
1121 if (!file_not_found
&& nSize
&& (reqfile
->GetFileSize() != nSize
)) {
1122 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a file but specified wrong size"));
1123 file_not_found
= true;
1126 if (file_not_found
) {
1127 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
1128 replypacket
->Copy16ToDataBuffer(reqfilehash
.GetHash());
1129 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
1130 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client
->GetFullIP() );
1131 SendPacket(replypacket
, true);
1135 if (!m_client
->GetWaitStartTime()) {
1136 m_client
->SetWaitStartTime();
1138 // if we are downloading this file, this could be a new source
1139 // no passive adding of files with only one part
1140 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
1141 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile
*)reqfile
)->GetSourceCount()) {
1142 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
1145 // check to see if this is a new file they are asking for
1146 if (m_client
->GetUploadFileID() != reqfilehash
) {
1147 m_client
->SetCommentDirty();
1149 m_client
->SetUploadFileID(reqfile
);
1150 CMemFile
data_out(128);
1151 data_out
.WriteHash(reqfile
->GetFileHash());
1152 while(data_in
.GetLength()-data_in
.GetPosition()) {
1154 throw wxString(wxT("Client suddenly disconnected"));
1156 uint8 opcode_in
= data_in
.ReadUInt8();
1158 case OP_REQUESTFILENAME
: {
1159 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1160 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
1161 data_out
.WriteUInt8(OP_REQFILENAMEANSWER
);
1163 // Since it's for somebody else to see, we need to send the prettified
1164 // filename, rather than the (possibly) mangled actual filename
1165 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
1168 case OP_AICHFILEHASHREQ
: {
1169 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1170 if (m_client
->IsSupportingAICH() && reqfile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1171 && reqfile
->GetAICHHashset()->HasValidMasterHash())
1173 data_out
.WriteUInt8(OP_AICHFILEHASHANS
);
1174 reqfile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1178 case OP_SETREQFILEID
: {
1179 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1180 data_out
.WriteUInt8(OP_FILESTATUS
);
1181 if (reqfile
->IsPartFile()) {
1182 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1184 data_out
.WriteUInt16(0);
1188 //We still send the source packet separately..
1189 //We could send it within this packet.. If agreeded, I will fix it..
1190 case OP_REQUESTSOURCES2
:
1191 case OP_REQUESTSOURCES
: {
1192 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1193 uint8 byRequestedVersion
= 0;
1194 uint16 byRequestedOptions
= 0;
1195 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1196 byRequestedVersion
= data_in
.ReadUInt8();
1197 byRequestedOptions
= data_in
.ReadUInt16();
1200 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1202 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() > 1) {
1203 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1204 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1206 //if not complete and file is rare
1207 ( reqfile
->IsPartFile()
1208 && (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1209 && ((CPartFile
*)reqfile
)->GetSourceCount() <= RARE_FILE
1211 //OR if file is not rare or if file is complete
1212 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1215 m_client
->SetLastSrcReqTime();
1216 CPacket
* tosend
= reqfile
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1218 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1219 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1220 SendPacket(tosend
, true);
1229 if( data_out
.GetLength() > 16 ) {
1230 CPacket
* reply
= new CPacket(data_out
, OP_EMULEPROT
, OP_MULTIPACKETANSWER
);
1231 theStats::AddUpOverheadFileRequest(reply
->GetPacketSize());
1232 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client
->GetFullIP() );
1233 SendPacket(reply
, true);
1238 case OP_MULTIPACKETANSWER
: { // 0.43b
1239 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client
->GetFullIP() );
1241 theStats::AddDownOverheadFileRequest(size
);
1243 if (m_client
->IsBanned()) {
1247 if( m_client
->GetKadPort() ) {
1248 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client
->GetIP()), m_client
->GetKadPort(), m_client
->GetKadVersion() > 1);
1251 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1252 // Here comes a extended packet without finishing the hanshake.
1253 // IMHO, we should disconnect the client.
1254 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1257 CMemFile
data_in(buffer
, size
);
1258 CMD4Hash reqfilehash
= data_in
.ReadHash();
1259 const CPartFile
*reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1260 //Make sure we are downloading this file.
1262 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1264 if ( !m_client
->GetRequestFile() ) {
1266 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1268 if (reqfile
!= m_client
->GetRequestFile()) {
1269 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1271 while (data_in
.GetLength()-data_in
.GetPosition()) {
1272 // Some of the cases down there can actually send a packet and lose the client
1274 throw wxString(wxT("Client suddenly disconnected"));
1276 uint8 opcode_in
= data_in
.ReadUInt8();
1278 case OP_REQFILENAMEANSWER
: {
1280 throw wxString(wxT("Client suddenly disconnected"));
1282 m_client
->ProcessFileInfo(&data_in
, reqfile
);
1286 case OP_FILESTATUS
: {
1288 throw wxString(wxT("Client suddenly disconnected"));
1290 m_client
->ProcessFileStatus(false, &data_in
, reqfile
);
1294 case OP_AICHFILEHASHANS
: {
1296 throw wxString(wxT("Client suddenly disconnected"));
1298 m_client
->ProcessAICHFileHash(&data_in
, reqfile
);
1308 case OP_EMULEINFO
: { // 0.43b
1309 theStats::AddDownOverheadOther(size
);
1311 if (!m_client
->ProcessMuleInfoPacket(buffer
, size
)) {
1312 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFO from ") + m_client
->GetFullIP() );
1314 // If it's not a OS Info packet, is an old client
1315 // start secure identification, if
1316 // - we have received eD2K and eMule info (old eMule)
1317 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1318 m_client
->InfoPacketsReceived();
1320 m_client
->SendMuleInfoPacket(true);
1322 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1326 case OP_EMULEINFOANSWER
: { // 0.43b
1327 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client
->GetFullIP() );
1328 theStats::AddDownOverheadOther(size
);
1330 m_client
->ProcessMuleInfoPacket(buffer
, size
);
1331 // start secure identification, if
1332 // - we have received eD2K and eMule info (old eMule)
1334 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1335 m_client
->InfoPacketsReceived();
1341 case OP_SECIDENTSTATE
:{ // 0.43b
1342 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client
->GetFullIP() );
1344 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1345 // Here comes a extended packet without finishing the hanshake.
1346 // IMHO, we should disconnect the client.
1347 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1349 m_client
->ProcessSecIdentStatePacket(buffer
, size
);
1350 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1352 int SecureIdentState
= m_client
->GetSecureIdentState();
1353 if (SecureIdentState
== IS_SIGNATURENEEDED
) {
1354 m_client
->SendSignaturePacket();
1355 } else if (SecureIdentState
== IS_KEYANDSIGNEEDED
) {
1356 m_client
->SendPublicKeyPacket();
1357 // SendPublicKeyPacket() might cause the socket to die, so check
1359 m_client
->SendSignaturePacket();
1366 case OP_PUBLICKEY
: { // 0.43b
1367 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICKEY from ") + m_client
->GetFullIP() );
1369 if (m_client
->IsBanned() ){
1373 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1374 // Here comes a extended packet without finishing the hanshake.
1375 // IMHO, we should disconnect the client.
1376 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1379 m_client
->ProcessPublicKeyPacket(buffer
, size
);
1382 case OP_SIGNATURE
:{ // 0.43b
1383 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SIGNATURE from ") + m_client
->GetFullIP() );
1385 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1386 // Here comes a extended packet without finishing the hanshake.
1387 // IMHO, we should disconnect the client.
1388 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1391 m_client
->ProcessSignaturePacket(buffer
, size
);
1394 case OP_SENDINGPART_I64
:
1395 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client
->GetFullIP() );
1396 case OP_COMPRESSEDPART_I64
:
1397 if (opcode
== OP_COMPRESSEDPART_I64
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client
->GetFullIP() );
1398 case OP_COMPRESSEDPART
: { // 0.47a
1399 if (opcode
== OP_COMPRESSEDPART
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client
->GetFullIP() );
1401 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1402 // Here comes a extended packet without finishing the hanshake.
1403 // IMHO, we should disconnect the client.
1404 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1407 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
1409 m_client
->ProcessBlockPacket(buffer
, size
, (opcode
!= OP_SENDINGPART_I64
), (opcode
== OP_COMPRESSEDPART_I64
) || (opcode
== OP_SENDINGPART_I64
));
1412 m_client
->GetRequestFile()->IsStopped() ||
1413 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
1414 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
)) {
1415 if (!m_client
->GetSentCancelTransfer()) {
1416 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1417 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1418 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1419 m_client
->SendPacket(packet
,true,true);
1422 m_client
->SetSentCancelTransfer(1);
1427 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
1431 if (!m_client
->GetSentCancelTransfer()) {
1432 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1433 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1434 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1435 m_client
->SendPacket(packet
,true,true);
1438 m_client
->SetSentCancelTransfer(1);
1443 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
1448 case OP_REQUESTPARTS_I64
: {
1449 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client
->GetFullIP() );
1451 theStats::AddDownOverheadFileRequest(size
);
1453 m_client
->ProcessRequestPartsPacket(buffer
, size
, true);
1457 case OP_QUEUERANKING
: { // 0.43b
1458 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_QUEUERANKING from ") + m_client
->GetFullIP() );
1460 theStats::AddDownOverheadOther(size
);
1462 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1463 // Here comes a extended packet without finishing the hanshake.
1464 // IMHO, we should disconnect the client.
1465 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1469 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1472 uint16 newrank
= PeekUInt16(buffer
);
1473 m_client
->SetRemoteQueueFull(false);
1474 m_client
->SetRemoteQueueRank(newrank
);
1477 case OP_REQUESTSOURCES
:{
1478 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client
->GetFullIP() );
1480 theStats::AddDownOverheadSourceExchange(size
);
1482 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1483 // Here comes an extended packet without finishing the handshake.
1484 // IMHO, we should disconnect the client.
1485 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1488 uint8 byRequestedVersion
= 0;
1489 uint16 byRequestedOptions
= 0;
1490 CMemFile
data_in(buffer
, size
);
1491 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1492 byRequestedVersion
= data_in
.ReadUInt8();
1493 byRequestedOptions
= data_in
.ReadUInt16();
1496 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() >= 1) {
1498 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1500 //first check shared file list, then download list
1501 const CMD4Hash
fileID(buffer
);
1502 CKnownFile
* file
= theApp
->sharedfiles
->GetFileByID(fileID
);
1504 file
= theApp
->downloadqueue
->GetFileByID(fileID
);
1507 // There are some clients which do not follow the correct protocol procedure of sending
1508 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1509 // are doing this, they will not get the optimal set of sources which we could offer if
1510 // they would follow the above noted protocol sequence. They better do it the right way
1511 // or they will get just a random set of sources because we do not know their download
1512 // part status which may get cleared with the call of 'SetUploadFileID'.
1513 m_client
->SetUploadFileID(file
);
1515 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1516 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1518 //if not complete and file is rare, allow once every 40 minutes
1519 ( file
->IsPartFile() &&
1520 ((CPartFile
*)file
)->GetSourceCount() <= RARE_FILE
&&
1521 (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1523 //OR if file is not rare or if file is complete, allow every 90 minutes
1524 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1527 m_client
->SetLastSrcReqTime();
1528 CPacket
* tosend
= file
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1530 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1531 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1532 SendPacket(tosend
, true, true);
1539 case OP_ANSWERSOURCES
: {
1540 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client
->GetFullIP() );
1542 theStats::AddDownOverheadSourceExchange(size
);
1544 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1545 // Here comes a extended packet without finishing the hanshake.
1546 // IMHO, we should disconnect the client.
1547 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1550 CMemFile
data(buffer
, size
);
1551 CMD4Hash hash
= data
.ReadHash();
1552 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1554 if (file
->IsPartFile()){
1555 //set the client's answer time
1556 m_client
->SetLastSrcAnswerTime();
1557 //and set the file's last answer time
1558 ((CPartFile
*)file
)->SetLastAnsweredTime();
1560 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, m_client
->GetSourceExchange1Version(), false, m_client
);
1565 case OP_ANSWERSOURCES2
: {
1566 //printf("Received OP_ANSWERSOURCES2\n");
1567 theStats::AddDownOverheadSourceExchange(size
);
1569 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1570 // Here comes a extended packet without finishing the hanshake.
1571 // IMHO, we should disconnect the client.
1572 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1575 CMemFile
data(buffer
, size
);
1576 uint8 byVersion
= data
.ReadUInt8();
1577 CMD4Hash hash
= data
.ReadHash();
1578 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1580 if (file
->IsPartFile()){
1581 //set the client's answer time
1582 m_client
->SetLastSrcAnswerTime();
1583 //and set the file's last answer time
1584 ((CPartFile
*)file
)->SetLastAnsweredTime();
1585 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, byVersion
, true, m_client
);
1590 case OP_FILEDESC
: { // 0.43b
1591 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILEDESC from ") + m_client
->GetFullIP() );
1593 theStats::AddDownOverheadFileRequest(size
);
1595 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1596 // Here comes a extended packet without finishing the hanshake.
1597 // IMHO, we should disconnect the client.
1598 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1601 m_client
->ProcessMuleCommentPacket(buffer
, size
);
1606 case OP_REQUESTPREVIEW
: {
1607 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client
->GetFullIP() );
1611 case OP_PREVIEWANSWER
: {
1612 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client
->GetFullIP() );
1616 case OP_PUBLICIP_ANSWER
: {
1617 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client
->GetFullIP() );
1618 theStats::AddDownOverheadOther(size
);
1619 m_client
->ProcessPublicIPAnswer(buffer
, size
);
1622 case OP_PUBLICIP_REQ
: {
1623 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client
->GetFullIP() );
1624 theStats::AddDownOverheadOther(size
);
1625 CPacket
* pPacket
= new CPacket(OP_PUBLICIP_ANSWER
, 4, OP_EMULEPROT
);
1626 pPacket
->CopyUInt32ToDataBuffer(m_client
->GetIP());
1627 theStats::AddUpOverheadOther(pPacket
->GetPacketSize());
1628 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client
->GetFullIP());
1629 SendPacket(pPacket
);
1632 case OP_AICHANSWER
: {
1633 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHANSWER from ") + m_client
->GetFullIP() );
1634 theStats::AddDownOverheadOther(size
);
1635 m_client
->ProcessAICHAnswer(buffer
, size
);
1638 case OP_AICHREQUEST
: {
1639 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHREQUEST from ") + m_client
->GetFullIP() );
1640 theStats::AddDownOverheadOther(size
);
1641 m_client
->ProcessAICHRequest(buffer
, size
);
1644 case OP_AICHFILEHASHANS
: {
1645 // those should not be received normally, since we should only get those in MULTIPACKET
1646 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client
->GetFullIP() );
1647 theStats::AddDownOverheadOther(size
);
1648 CMemFile
data(buffer
, size
);
1649 m_client
->ProcessAICHFileHash(&data
, NULL
);
1652 case OP_AICHFILEHASHREQ
: {
1653 // those should not be received normally, since we should only get those in MULTIPACKET
1654 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client
->GetFullIP() );
1655 CMemFile
data(buffer
, size
);
1656 CMD4Hash hash
= data
.ReadHash();
1657 CKnownFile
* pPartFile
= theApp
->sharedfiles
->GetFileByID(hash
);
1658 if (pPartFile
== NULL
){
1662 if (m_client
->IsSupportingAICH() && pPartFile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1663 && pPartFile
->GetAICHHashset()->HasValidMasterHash()) {
1665 data_out
.WriteHash(hash
);
1666 pPartFile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1667 CPacket
* packet
= new CPacket(data_out
, OP_EMULEPROT
, OP_AICHFILEHASHANS
);
1668 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1669 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client
->GetFullIP());
1675 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CALLBACK from ") + m_client
->GetFullIP() );
1676 theStats::AddDownOverheadFileRequest(size
);
1677 if(!Kademlia::CKademlia::IsRunning()) {
1680 CMemFile
data(buffer
, size
);
1681 CUInt128 check
= data
.ReadUInt128();
1682 check
.XOR(Kademlia::CUInt128(true));
1683 if( check
.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1686 CUInt128 fileid
= data
.ReadUInt128();
1688 fileid
.ToByteArray(fileid2
);
1689 const CMD4Hash
fileHash(fileid2
);
1690 if (theApp
->sharedfiles
->GetFileByID(fileHash
) == NULL
) {
1691 if (theApp
->downloadqueue
->GetFileByID(fileHash
) == NULL
) {
1696 uint32 ip
= data
.ReadUInt32();
1697 uint16 tcp
= data
.ReadUInt16();
1698 CUpDownClient
* callback
;
1699 callback
= theApp
->clientlist
->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip
), tcp
);
1700 if( callback
== NULL
) {
1701 //#warning Do we actually have to check friend status here?
1702 callback
= new CUpDownClient(tcp
,ip
,0,0,NULL
,false, false);
1703 theApp
->clientlist
->AddClient(callback
);
1705 callback
->TryToConnect(true);
1709 case OP_BUDDYPING
: {
1710 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_BUDDYPING from ") + m_client
->GetFullIP() );
1711 theStats::AddDownOverheadKad(size
);
1713 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1714 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 || !m_client
->AllowIncomeingBuddyPingPong() ) {
1715 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1719 m_client
->SetLastBuddyPingPongTime();
1720 CPacket
* replypacket
= new CPacket(OP_BUDDYPONG
, 0, OP_EMULEPROT
);
1721 theStats::AddUpOverheadKad(replypacket
->GetPacketSize());
1722 AddDebugLogLineM(false, logLocalClient
,wxT("Local Client: OP_BUDDYPONG to ") + m_client
->GetFullIP());
1723 SendPacket(replypacket
);
1726 case OP_BUDDYPONG
: {
1727 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_BUDDYPONG from ") + m_client
->GetFullIP() );
1728 theStats::AddDownOverheadKad(size
);
1730 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1731 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 ) {
1732 //This pong was not from our buddy or wrong version. Ignore
1735 m_client
->SetLastBuddyPingPongTime();
1736 //All this is for is to reset our socket timeout.
1739 case OP_REASKCALLBACKTCP
: {
1740 theStats::AddDownOverheadFileRequest(size
);
1741 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1742 if (buddy
!= m_client
) {
1743 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() + wxT(" which is not our buddy!") );
1744 //This callback was not from our buddy.. Ignore.
1747 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() );
1748 CMemFile
data_in(buffer
, size
);
1749 uint32 destip
= data_in
.ReadUInt32();
1750 uint16 destport
= data_in
.ReadUInt16();
1751 CMD4Hash hash
= data_in
.ReadHash();
1752 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(hash
);
1754 bool bSenderMultipleIpUnknown
= false;
1755 CUpDownClient
* sender
= theApp
->uploadqueue
->GetWaitingClientByIP_UDP(destip
, destport
, true, &bSenderMultipleIpUnknown
);
1757 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILENOTFOUND to ") + m_client
->GetFullIP() );
1758 CPacket
* response
= new CPacket(OP_FILENOTFOUND
,0,OP_EMULEPROT
);
1759 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1761 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1763 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1769 //Make sure we are still thinking about the same file
1770 if (hash
== sender
->GetUploadFileID()) {
1771 sender
->AddAskedCount();
1772 sender
->SetLastUpRequest();
1773 //I messed up when I first added extended info to UDP
1774 //I should have originally used the entire ProcessExtenedInfo the first time.
1775 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1776 //For now on, we should not have to change anything here if we change
1777 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1778 //Update extended info.
1779 if (sender
->GetUDPVersion() > 3) {
1780 sender
->ProcessExtendedInfo(&data_in
, reqfile
);
1781 } else if (sender
->GetUDPVersion() > 2) {
1782 //Update our complete source counts.
1783 uint16 nCompleteCountLast
= sender
->GetUpCompleteSourcesCount();
1784 uint16 nCompleteCountNew
= data_in
.ReadUInt16();
1785 sender
->SetUpCompleteSourcesCount(nCompleteCountNew
);
1786 if (nCompleteCountLast
!= nCompleteCountNew
) {
1787 reqfile
->UpdatePartsInfo();
1791 CMemFile
data_out(128);
1792 if(sender
->GetUDPVersion() > 3) {
1793 if (reqfile
->IsPartFile()) {
1794 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1796 data_out
.WriteUInt16(0);
1800 data_out
.WriteUInt16(theApp
->uploadqueue
->GetWaitingPosition(sender
));
1801 CPacket
* response
= new CPacket(data_out
, OP_EMULEPROT
, OP_REASKACK
);
1802 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1803 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client UDP: OP_REASKACK to ") + m_client
->GetFullIP() );
1804 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1806 AddDebugLogLineM(false, logListenSocket
, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1809 if (!bSenderMultipleIpUnknown
){
1810 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1811 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_QUEUEFULL to ") + m_client
->GetFullIP() );
1812 CPacket
* response
= new CPacket(OP_QUEUEFULL
,0,OP_EMULEPROT
);
1813 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1814 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1817 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
);
1822 case OP_FWCHECKUDPREQ
: { // Support required for Kadversion >= 6
1823 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client
->GetFullIP());
1824 theStats::AddDownOverheadOther(size
);
1825 CMemFile
data_in(buffer
, size
);
1826 m_client
->ProcessFirewallCheckUDPRequest(&data_in
);
1829 case OP_KAD_FWTCPCHECK_ACK
: { // Support required for Kadversion >= 7
1830 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client
->GetFullIP());
1831 if (theApp
->clientlist
->IsKadFirewallCheckIP(m_client
->GetIP())) {
1832 if (Kademlia::CKademlia::IsRunning()) {
1833 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1836 AddDebugLogLineM(false, logListenSocket
, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client
->GetFullIP());
1841 theStats::AddDownOverheadOther(size
);
1842 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode
,opcode
) + m_client
->GetFullIP());
1849 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte
* buffer
, uint32 size
, uint8 opcode
)
1851 #ifdef __PACKET_RECV_DUMP__
1852 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1853 DumpMem(buffer
,size
);
1857 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1860 CMemFile
data(buffer
, size
);
1863 case OP_QUEUERANK
: {
1864 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client
->GetFullIP() );
1866 uint8 numtags
= data
.ReadUInt8();
1867 wxASSERT(numtags
== 1);
1869 m_client
->SetRemoteQueueRank(data
.GetIntTagValue());
1871 theStats::AddDownOverheadFileRequest(size
);
1875 case OP_REQUESTPARTS
: {
1876 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
1878 m_client
->ProcessRequestPartsPacketv2(data
);
1880 theStats::AddDownOverheadFileRequest(size
);
1885 theStats::AddDownOverheadOther(size
);
1886 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode
, opcode
) + m_client
->GetFullIP());
1889 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data
.GetPosition(), opcode
, opcode
) + m_client
->GetFullIP());
1896 void CClientTCPSocket::OnConnect(int nErrorCode
)
1899 OnError(nErrorCode
);
1900 } else if (!m_client
) {
1901 // and now? Disconnect? not?
1902 AddDebugLogLineM( false, logClient
, wxT("Couldn't send hello packet (Client deleted!)") );
1903 } else if (!m_client
->SendHelloPacket()) {
1904 // and now? Disconnect? not?
1905 AddDebugLogLineM( false, logClient
, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1907 ResetTimeOutTimer();
1912 void CClientTCPSocket::OnSend(int nErrorCode
)
1914 ResetTimeOutTimer();
1915 CEMSocket::OnSend(nErrorCode
);
1919 void CClientTCPSocket::OnReceive(int nErrorCode
)
1921 ResetTimeOutTimer();
1922 // We might have updated ipfilter
1923 wxASSERT(m_remoteip
);
1925 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
1927 m_client
->Safe_Delete();
1930 AddDebugLogLineM( false, logIPFilter
, wxT("A connected client was dropped by IPFilter on new packet received"));
1932 CEMSocket::OnReceive(nErrorCode
);
1937 void CClientTCPSocket::OnError(int nErrorCode
)
1939 //printf("* Called OnError for %p\n",this);
1940 // 0.42e + Kry changes for handling of socket lost events
1943 if ((nErrorCode
== 0) || (nErrorCode
== 7) || (nErrorCode
== 0xFEFF)) {
1945 if (!m_client
->GetUserName().IsEmpty()) {
1946 strError
= wxT("Client '") + m_client
->GetUserName() + wxT("'");
1948 strError
= wxT("An unnamed client");
1950 strError
+= wxT(" (IP:") + m_client
->GetFullIP() + wxT(") ");
1952 strError
= wxT("A client ");
1954 if (nErrorCode
== 0) {
1955 strError
+= wxT("closed connection.");
1956 } else if (nErrorCode
== 0xFEFF) {
1957 strError
+= wxT(" caused a wxSOCKET_LOST event.");
1959 strError
+= wxT("caused a socket blocking error.");
1962 if ( CLogger::IsEnabled( logClient
) && (nErrorCode
!= 107)) {
1963 // 0 -> No Error / Disconect
1964 // 107 -> Transport endpoint is not connected
1966 if (!m_client
->GetUserName().IsEmpty()) {
1967 strError
= wxT("OnError: Client '") + m_client
->GetUserName() +
1968 wxT("' (IP:") + m_client
->GetFullIP() +
1969 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode
);
1971 strError
= wxT("OnError: Unknown client (IP:") +
1972 m_client
->GetFullIP() +
1973 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode
);
1976 strError
= wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
1980 strError
= wxT("Error 107 (Transport endpoint is not connected)");
1984 Disconnect(strError
);
1988 bool CClientTCPSocket::PacketReceived(CPacket
* packet
)
1991 bool bResult
= false;
1992 uint32 uRawSize
= packet
->GetPacketSize();
1994 AddDebugLogLineM( false, logRemoteClient
,
1995 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1996 % packet
->GetProtocol()
1997 % packet
->GetOpCode()
1998 % packet
->GetPacketSize()
1999 % ( m_client
? m_client
->GetFullIP() : wxT("Unknown Client") )
2005 bool process
= true;
2007 if ((packet
->GetProtocol() == OP_PACKEDPROT
) ||
2008 (packet
->GetProtocol() == OP_ED2KV2PACKEDPROT
)) {
2010 if (!packet
->UnPackPacket()) {
2011 AddDebugLogLineM( false, logZLib
, wxT("Failed to decompress client TCP packet."));
2015 AddDebugLogLineM(false, logRemoteClient
,
2016 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
2017 packet
->GetProtocol(),
2018 packet
->GetOpCode(),
2019 packet
->GetPacketSize())
2025 switch (packet
->GetProtocol()) {
2026 case OP_EDONKEYPROT
:
2027 bResult
= ProcessPacket(packet
->GetDataBuffer(),uRawSize
,packet
->GetOpCode());
2030 bResult
= ProcessExtPacket(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2032 case OP_ED2KV2HEADER
:
2033 bResult
= ProcessED2Kv2Packet(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2035 case OP_ED2KV2PACKEDPROT
:
2037 // Packed inside packed?
2041 theStats::AddDownOverheadOther(uRawSize
);
2043 m_client
->SetDownloadState(DS_ERROR
);
2045 Disconnect(wxT("Unknown protocol"));
2050 } catch (const CEOFException
& err
) {
2051 exception
= wxT("EOF exception: ") + err
.what();
2052 } catch (const CInvalidPacket
& err
) {
2053 exception
= wxT("InvalidPacket exception: ") + err
.what();
2054 } catch (const wxString
& error
) {
2055 exception
= wxT("error: ") + (error
.IsEmpty() ? wxString(wxT("Unknown error")) : error
);
2058 if (!exception
.IsEmpty()) {
2059 AddDebugLogLineM( false, logPacketErrors
,
2060 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2062 % packet
->GetProtocol()
2063 % packet
->GetOpCode()
2064 % packet
->GetPacketSize()
2065 % ( m_client
? m_client
->GetClientFullInfo() : wxT("Unknown") )
2069 m_client
->SetDownloadState(DS_ERROR
);
2072 AddDebugLogLineM( false, logClient
,
2073 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2074 % ( m_client
? m_client
->GetUserName() : wxString(wxT("Unknown")) )
2075 % ( m_client
? m_client
->GetFullIP() : wxString(wxT("Unknown")) )
2079 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2086 bool CClientTCPSocket::IsMessageFiltered(const wxString
& Message
, CUpDownClient
* client
) {
2088 bool filtered
= false;
2089 // If we're chatting to the guy, we don't want to filter!
2090 if (client
->GetChatState() != MS_CHATTING
) {
2091 if (thePrefs::MsgOnlyFriends() && !client
->IsFriend()) {
2093 } else if (thePrefs::MsgOnlySecure() && client
->GetUserName().IsEmpty() ) {
2095 } else if (thePrefs::MustFilterMessages()) {
2096 filtered
= thePrefs::IsMessageFiltered(Message
);
2102 SocketSentBytes
CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2104 SocketSentBytes returnStatus
= CEMSocket::SendControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2106 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2107 ResetTimeOutTimer();
2110 return returnStatus
;
2114 SocketSentBytes
CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2116 SocketSentBytes returnStatus
= CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2118 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2119 ResetTimeOutTimer();
2122 return returnStatus
;
2126 void CClientTCPSocket::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
, uint32 actualPayloadSize
)
2128 ResetTimeOutTimer();
2129 CEMSocket::SendPacket(packet
,delpacket
,controlpacket
, actualPayloadSize
);
2131 // File_checked_for_headers