2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )//
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "ClientTCPSocket.h" // Interface declarations
27 #include <protocol/Protocols.h>
28 #include <protocol/ed2k/Client2Client/TCP.h>
29 #include <protocol/ed2k/Client2Client/UDP.h> // Sometimes we reply with UDP packets.
30 #include <protocol/ed2k/ClientSoftware.h>
31 #include <protocol/kad2/Client2Client/TCP.h>
32 #include <common/EventIDs.h>
34 #include "Preferences.h" // Needed for thePrefs
35 #include "Packet.h" // Needed for CPacket
36 #include "Statistics.h" // Needed for theStats
37 #include "Logger.h" // Neeed for logRemoteClient
38 #include "updownclient.h" // Needed for CUpDownClient
39 #include <common/Format.h> // Needed for CFormat
40 #include "amule.h" // Needed for theApp
41 #include "SharedFileList.h" // Needed for CSharedFileList
42 #include "ClientList.h" // Needed for CClientList
43 #include "UploadQueue.h" // Needed for CUploadQueue
44 #include "ClientUDPSocket.h" // Needed for CClientUDPSocket
45 #include "PartFile.h" // Needed for CPartFile
46 #include "MemFile.h" // Needed for CMemFile
47 #include "kademlia/kademlia/Kademlia.h" // Needed for CKademlia::Kademlia
48 #include "kademlia/kademlia/Prefs.h" // Needed for CKademlia::CPrefs
49 #include "DownloadQueue.h" // Needed for CDownloadQueue
50 #include "Server.h" // Needed for CServer
51 #include "ServerList.h" // Needed for CServerList
52 #include "IPFilter.h" // Needed for CIPFilter
53 #include "ListenSocket.h" // Needed for CListenSocket
54 #include "GuiEvents.h" // Needed for Notify_*
57 //#define __PACKET_RECV_DUMP__
61 //------------------------------------------------------------------------------
62 // CClientTCPSocketHandler
63 //------------------------------------------------------------------------------
65 class CClientTCPSocketHandler
: public wxEvtHandler
68 CClientTCPSocketHandler() {};
71 void ClientTCPSocketHandler(wxSocketEvent
& event
);
75 BEGIN_EVENT_TABLE(CClientTCPSocketHandler
, wxEvtHandler
)
76 EVT_SOCKET(ID_CLIENTTCPSOCKET_EVENT
, CClientTCPSocketHandler::ClientTCPSocketHandler
)
79 void CClientTCPSocketHandler::ClientTCPSocketHandler(wxSocketEvent
& event
)
81 wxSocketBase
* baseSocket
= event
.GetSocket();
82 // wxASSERT(baseSocket); // Rather want a log message right now. Enough other wx problems. >:(
83 if (!baseSocket
) { // WTF?
84 AddDebugLogLineN(logClient
, wxT("received bad wxSocketEvent"));
88 CClientTCPSocket
*socket
= dynamic_cast<CClientTCPSocket
*>(baseSocket
);
94 if (socket
->IsDestroying()) {
98 switch(event
.GetSocketEvent()) {
100 socket
->OnError(0xFEFF /* SOCKET_LOST is not an error */);
103 socket
->OnReceive(0);
105 case wxSOCKET_OUTPUT
:
108 case wxSOCKET_CONNECTION
:
109 // connection stablished, nothing to do about it?
110 socket
->OnConnect(socket
->LastError());
113 // Nothing should arrive here...
120 // There can be only one. :)
122 static CClientTCPSocketHandler g_clientReqSocketHandler
;
124 #endif /* !ASIO_SOCKETS */
127 //------------------------------------------------------------------------------
129 //------------------------------------------------------------------------------
131 CClientTCPSocket::CClientTCPSocket(CUpDownClient
* in_client
, const CProxyData
*ProxyData
)
132 : CEMSocket(ProxyData
)
134 SetClient(in_client
);
136 m_remoteip
= wxUINT32_SWAP_ALWAYS(in_client
->GetUserIDHybrid());
144 SetEventHandler(g_clientReqSocketHandler
, ID_CLIENTTCPSOCKET_EVENT
);
146 wxSOCKET_CONNECTION_FLAG
|
147 wxSOCKET_INPUT_FLAG
|
148 wxSOCKET_OUTPUT_FLAG
|
153 theApp
->listensocket
->AddSocket(this);
154 theApp
->listensocket
->AddConnection();
157 CClientTCPSocket::~CClientTCPSocket()
160 // remove event handler
166 m_client
->SetSocket( NULL
);
170 if (theApp
->listensocket
&& !theApp
->listensocket
->OnShutdown()) {
171 theApp
->listensocket
->RemoveSocket(this);
175 bool CClientTCPSocket::InitNetworkData()
177 wxASSERT(!m_remoteip
);
179 m_remoteip
= GetPeerInt();
181 MULE_CHECK(m_remoteip
, false);
183 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
184 AddDebugLogLineN(logClient
, wxT("Denied connection from ") + GetPeer() + wxT("(Filtered IP)"));
186 } else if (theApp
->clientlist
->IsBannedClient(m_remoteip
)) {
187 AddDebugLogLineN(logClient
, wxT("Denied connection from ") + GetPeer() + wxT("(Banned IP)"));
190 AddDebugLogLineN(logClient
, wxT("Accepted connection from ") + GetPeer());
195 void CClientTCPSocket::ResetTimeOutTimer()
197 timeout_timer
= ::GetTickCount();
201 bool CClientTCPSocket::CheckTimeOut()
204 uint32 uTimeout
= GetTimeOut();
207 if (m_client
->GetKadState() == KS_CONNECTED_BUDDY
) {
208 //We originally ignored the timeout here for buddies.
209 //This was a stupid idea on my part. There is now a ping/pong system
210 //for buddies. This ping/pong system now prevents timeouts.
211 //This release will allow lowID clients with KadVersion 0 to remain connected.
212 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
213 //JOHNTODO: Don't forget to remove backward support in a future release.
214 if ( m_client
->GetKadVersion() == 0 ) {
218 uTimeout
+= MIN2MS(15);
221 if (m_client
->GetChatState() != MS_NONE
) {
222 uTimeout
+= CONNECTION_TIMEOUT
;
226 if (::GetTickCount() - timeout_timer
> uTimeout
){
227 timeout_timer
= ::GetTickCount();
228 Disconnect(wxT("Timeout"));
236 void CClientTCPSocket::SetClient(CUpDownClient
* pClient
)
240 m_client
->SetSocket( this );
245 void CClientTCPSocket::OnClose(int nErrorCode
)
248 wxASSERT(theApp
->listensocket
->IsValidSocket(this));
249 CEMSocket::OnClose(nErrorCode
);
251 Disconnect(CFormat(wxT("Closed: %u")) % nErrorCode
);
253 Disconnect(wxT("Close"));
258 void CClientTCPSocket::Disconnect(const wxString
& strReason
)
260 byConnected
= ES_DISCONNECTED
;
262 if (m_client
->Disconnected(strReason
, true)) {
263 // Somehow, Safe_Delete() is beeing called by Disconnected(),
264 // or any other function that sets m_client to NULL,
265 // so we must check m_client first.
267 m_client
->SetSocket( NULL
);
268 m_client
->Safe_Delete();
278 void CClientTCPSocket::Safe_Delete()
280 // More paranoia - make sure client is unlinked in any case
282 m_client
->SetSocket( NULL
);
286 // Destroy may be called several times
287 byConnected
= ES_DISCONNECTED
;
292 void CClientTCPSocket::Safe_Delete_Client()
295 m_client
->Safe_Delete();
301 bool CClientTCPSocket::ProcessPacket(const uint8_t* buffer
, uint32 size
, uint8 opcode
)
303 #ifdef __PACKET_RECV_DUMP__
304 //printf("Rec: OPCODE %x \n",opcode);
305 DumpMem(buffer
, size
);
307 if (!m_client
&& opcode
!= OP_HELLO
) {
308 throw wxString(wxT("Asks for something without saying hello"));
309 } else if (m_client
&& opcode
!= OP_HELLO
&& opcode
!= OP_HELLOANSWER
) {
310 m_client
->CheckHandshakeFinished();
314 case OP_HELLOANSWER
: { // 0.43b
315 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_HELLOANSWER from ") + m_client
->GetFullIP());
316 theStats::AddDownOverheadOther(size
);
317 m_client
->ProcessHelloAnswer(buffer
, size
);
319 // start secure identification, if
320 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
321 // - we have received eMule-OP_HELLOANSWER (new eMule)
322 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
323 m_client
->InfoPacketsReceived();
326 // Socket might die because of sending in InfoPacketsReceived, so check
328 m_client
->ConnectionEstablished();
331 // Socket might die on ConnectionEstablished somehow. Check it.
333 Notify_SharedCtrlRefreshClient( m_client
->ECID() , AVAILABLE_SOURCE
);
338 case OP_HELLO
: { // 0.43b
340 theStats::AddDownOverheadOther(size
);
341 bool bNewClient
= !m_client
;
343 // create new client to save standart informations
344 m_client
= new CUpDownClient(this);
348 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_HELLO from ") + m_client
->GetFullIP() );
350 bool bIsMuleHello
= false;
353 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
355 if (bNewClient
&& m_client
) {
356 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
357 m_client
->Safe_Delete();
363 if (thePrefs::ParanoidFilter() && !IsLowID(m_client
->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid()))) {
364 wxString reason
= wxT("Client claims a different IP from the one we received the hello packet from: ");
365 reason
+= Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
366 AddDebugLogLineN(logClient
, reason
);
368 m_client
->Safe_Delete();
371 Disconnect(wxT("Paranoid disconecting: ") + reason
);
375 // if IP is filtered, dont reply but disconnect...
376 if (theApp
->ipfilter
->IsFiltered(m_client
->GetIP())) {
378 m_client
->Safe_Delete();
381 Disconnect(wxT("IPFilter"));
387 // now we check if we know this client already. if yes this socket will
388 // be attached to the known client, the new client will be deleted
389 // and the var. "client" will point to the known client.
390 // if not we keep our new-constructed client ;)
391 if (theApp
->clientlist
->AttachToAlreadyKnown(&m_client
,this)) {
392 // update the old client informations
393 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
395 theApp
->clientlist
->AddClient(m_client
);
396 m_client
->SetCommentDirty();
398 Notify_SharedCtrlRefreshClient( m_client
->ECID(), AVAILABLE_SOURCE
);
399 // send a response packet with standart informations
400 if ((m_client
->GetHashType() == SO_EMULE
) && !bIsMuleHello
) {
401 m_client
->SendMuleInfoPacket(false);
404 // Client might die from Sending in SendMuleInfoPacket, so check
406 m_client
->SendHelloAnswer();
409 // Kry - If the other side supports it, send OS_INFO
410 // Client might die from Sending in SendHelloAnswer, so check
411 if (m_client
&& m_client
->GetOSInfoSupport()) {
412 m_client
->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
415 // Client might die from Sending in SendMuleInfoPacket, so check
417 m_client
->ConnectionEstablished();
420 // start secure identification, if
421 // - we have received eMule-OP_HELLO (new eMule)
422 if (m_client
&& m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
423 m_client
->InfoPacketsReceived();
428 case OP_REQUESTFILENAME
: { // 0.43b
429 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client
->GetFullIP() );
431 theStats::AddDownOverheadFileRequest(size
);
432 // IP banned, no answer for this request
433 if (m_client
->IsBanned()) {
437 if (!m_client
->GetWaitStartTime()) {
438 m_client
->SetWaitStartTime();
440 CMemFile
data_in(buffer
, size
);
441 CMD4Hash reqfilehash
= data_in
.ReadHash();
442 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
443 if ( reqfile
== NULL
) {
444 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
445 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
449 // if we are downloading this file, this could be a new source
450 // no passive adding of files with only one part
451 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
452 if (thePrefs::GetMaxSourcePerFile() > static_cast<CPartFile
*>(reqfile
)->GetSourceCount()) {
453 theApp
->downloadqueue
->CheckAndAddKnownSource(static_cast<CPartFile
*>(reqfile
), m_client
);
457 // check to see if this is a new file they are asking for
458 if (m_client
->GetUploadFileID() != reqfilehash
) {
459 m_client
->SetCommentDirty();
462 m_client
->SetUploadFileID(reqfile
);
463 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
466 CMemFile
data_out(128);
467 data_out
.WriteHash(reqfile
->GetFileHash());
469 // Since it's for somebody else to see, we need to send the prettified
470 // filename, rather than the (possibly) mangled actual filename.
471 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
473 CPacket
* packet
= new CPacket(data_out
, OP_EDONKEYPROT
, OP_REQFILENAMEANSWER
);
474 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
475 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client
->GetFullIP() );
476 SendPacket(packet
,true);
478 // SendPacket might kill the socket, so check
480 m_client
->SendCommentInfo(reqfile
);
484 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
487 case OP_SETREQFILEID
: { // 0.43b EXCEPT track of bad clients
488 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SETREQFILEID from ") + m_client
->GetFullIP() );
490 theStats::AddDownOverheadFileRequest(size
);
492 if (m_client
->IsBanned()) {
498 if (!m_client
->GetWaitStartTime()) {
499 m_client
->SetWaitStartTime();
502 const CMD4Hash
fileID(buffer
);
503 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
504 if ( reqfile
== NULL
) {
505 reqfile
= theApp
->downloadqueue
->GetFileByID(fileID
);
506 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
507 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
508 replypacket
->Copy16ToDataBuffer(fileID
.GetHash());
509 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
510 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILERE to ") + m_client
->GetFullIP() );
511 SendPacket(replypacket
, true);
516 // check to see if this is a new file they are asking for
517 if (m_client
->GetUploadFileID() != fileID
) {
518 m_client
->SetCommentDirty();
521 m_client
->SetUploadFileID(reqfile
);
523 CMemFile
data(16+16);
524 data
.WriteHash(reqfile
->GetFileHash());
525 if (reqfile
->IsPartFile()) {
526 static_cast<CPartFile
*>(reqfile
)->WritePartStatus(&data
);
530 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_FILESTATUS
);
531 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
532 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILESTATUS to ") + m_client
->GetFullIP() );
533 SendPacket(packet
, true);
536 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
541 case OP_FILEREQANSNOFIL
: { // 0.43b protocol, lacks ZZ's download manager on swap
542 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client
->GetFullIP() );
544 theStats::AddDownOverheadFileRequest(size
);
546 // if that client does not have my file maybe has another different
547 CPartFile
* reqfile
= theApp
->downloadqueue
->GetFileByID(CMD4Hash(buffer
));
549 reqfile
->AddDeadSource( m_client
);
554 // we try to swap to another file ignoring no needed parts files
555 switch (m_client
->GetDownloadState()) {
558 case DS_NONEEDEDPARTS
:
559 if (!m_client
->SwapToAnotherFile(true, true, true, NULL
)) {
560 theApp
->downloadqueue
->RemoveSource(m_client
);
566 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
570 case OP_REQFILENAMEANSWER
: { // 0.43b except check for bad clients
571 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client
->GetFullIP() );
573 theStats::AddDownOverheadFileRequest(size
);
574 CMemFile
data(buffer
, size
);
575 CMD4Hash hash
= data
.ReadHash();
576 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
577 m_client
->ProcessFileInfo(&data
, file
);
581 case OP_FILESTATUS
: { // 0.43b except check for bad clients
582 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_FILESTATUS from ") + m_client
->GetFullIP() );
584 theStats::AddDownOverheadFileRequest(size
);
585 CMemFile
data(buffer
, size
);
586 CMD4Hash hash
= data
.ReadHash();
587 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
588 m_client
->ProcessFileStatus(false, &data
, file
);
592 case OP_STARTUPLOADREQ
: {
593 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client
->GetFullIP() );
595 theStats::AddDownOverheadFileRequest(size
);
597 if (!m_client
->CheckHandshakeFinished()) {
601 m_client
->CheckForAggressive();
602 if ( m_client
->IsBanned() ) {
607 const CMD4Hash
fileID(buffer
);
608 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
610 if (m_client
->GetUploadFileID() != fileID
) {
611 m_client
->SetCommentDirty();
613 m_client
->SetUploadFileID(reqfile
);
614 m_client
->SendCommentInfo(reqfile
);
616 // Socket might die because of SendCommentInfo, so check
618 theApp
->uploadqueue
->AddClientToQueue(m_client
);
624 case OP_QUEUERANK
: { // 0.43b
625 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_QUEUERANK from ") + m_client
->GetFullIP() );
627 theStats::AddDownOverheadFileRequest(size
);
628 CMemFile
data(buffer
, size
);
629 uint32 rank
= data
.ReadUInt32();
631 m_client
->SetRemoteQueueRank(rank
);
635 case OP_ACCEPTUPLOADREQ
: { // 0.42e (xcept khaos stats)
636 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client
->GetFullIP() );
638 theStats::AddDownOverheadFileRequest(size
);
639 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
640 if (m_client
->GetDownloadState() == DS_ONQUEUE
) {
641 m_client
->SetDownloadState(DS_DOWNLOADING
);
642 m_client
->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
643 m_client
->SendBlockRequests();
646 if (!m_client
->GetSentCancelTransfer()) {
647 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
648 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
649 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
650 m_client
->SendPacket(packet
,true,true);
652 // SendPacket can cause the socket to die, so check
654 m_client
->SetSentCancelTransfer(1);
658 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
663 case OP_REQUESTPARTS
: { // 0.43b
664 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
666 theStats::AddDownOverheadFileRequest(size
);
668 m_client
->ProcessRequestPartsPacket(buffer
, size
, false);
673 case OP_CANCELTRANSFER
: { // 0.43b
674 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client
->GetFullIP() );
676 theStats::AddDownOverheadFileRequest(size
);
677 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
678 AddDebugLogLineN( logClient
, m_client
->GetUserName() + wxT(": Upload session ended due canceled transfer."));
682 case OP_END_OF_DOWNLOAD
: { // 0.43b except check for bad clients
683 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client
->GetFullIP() );
685 theStats::AddDownOverheadFileRequest(size
);
686 if (size
>=16 && m_client
->GetUploadFileID() == CMD4Hash(buffer
)) {
687 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
688 AddDebugLogLineN( logClient
, m_client
->GetUserName() + wxT(": Upload session ended due ended transfer."));
693 case OP_HASHSETREQUEST
: { // 0.43b except check for bad clients
694 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client
->GetFullIP() );
697 theStats::AddDownOverheadFileRequest(size
);
699 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
701 m_client
->SendHashsetPacket(CMD4Hash(buffer
));
705 case OP_HASHSETANSWER
: { // 0.43b
706 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client
->GetFullIP() );
708 theStats::AddDownOverheadFileRequest(size
);
709 m_client
->ProcessHashSet(buffer
, size
);
713 case OP_SENDINGPART
: { // 0.47a
714 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SENDINGPART from ") + m_client
->GetFullIP() );
716 if ( m_client
->GetRequestFile() &&
717 !m_client
->GetRequestFile()->IsStopped() &&
718 (m_client
->GetRequestFile()->GetStatus() == PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
720 m_client
->ProcessBlockPacket(buffer
, size
, false, false);
723 ( m_client
->GetRequestFile()->IsStopped() ||
724 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
725 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
) ) {
726 if (!m_client
->GetSentCancelTransfer()) {
727 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
728 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
729 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
730 m_client
->SendPacket(packet
,true,true);
732 // Socket might die because of SendPacket, so check
734 m_client
->SetSentCancelTransfer(1);
738 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
741 if (!m_client
->GetSentCancelTransfer()) {
742 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
743 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
744 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
745 m_client
->SendPacket(packet
,true,true);
747 // Socket might die because of SendPacket, so check
748 m_client
->SetSentCancelTransfer(1);
750 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
755 case OP_OUTOFPARTREQS
: { // 0.43b
756 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client
->GetFullIP() );
758 theStats::AddDownOverheadFileRequest(size
);
759 if (m_client
->GetDownloadState() == DS_DOWNLOADING
) {
760 m_client
->SetDownloadState(DS_ONQUEUE
);
765 case OP_CHANGE_CLIENT_ID
: { // Kad reviewed
766 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client
->GetFullIP() );
768 theStats::AddDownOverheadOther(size
);
769 CMemFile
data(buffer
, size
);
770 uint32 nNewUserID
= data
.ReadUInt32();
771 uint32 nNewServerIP
= data
.ReadUInt32();
773 if (IsLowID(nNewUserID
)) { // client changed server and gots a LowID
774 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
775 if (pNewServer
!= NULL
){
776 m_client
->SetUserIDHybrid(nNewUserID
); // update UserID only if we know the server
777 m_client
->SetServerIP(nNewServerIP
);
778 m_client
->SetServerPort(pNewServer
->GetPort());
780 } else if (nNewUserID
== m_client
->GetIP()) { // client changed server and gots a HighID(IP)
781 m_client
->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID
));
782 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
783 if (pNewServer
!= NULL
){
784 m_client
->SetServerIP(nNewServerIP
);
785 m_client
->SetServerPort(pNewServer
->GetPort());
792 case OP_CHANGE_SLOT
:{ // 0.43b
793 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client
->GetFullIP() );
795 // sometimes sent by Hybrid
796 theStats::AddDownOverheadOther(size
);
800 case OP_MESSAGE
: { // 0.43b
801 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MESSAGE from ") + m_client
->GetFullIP() );
803 theStats::AddDownOverheadOther(size
);
806 throw wxString(wxT("invalid message packet"));
808 CMemFile
message_file(buffer
, size
);
809 uint16 length
= message_file
.ReadUInt16();
810 if (length
+ 2u != size
) {
811 throw wxString(wxT("invalid message packet"));
814 // limit message length
815 static const uint16 MAX_CLIENT_MSG_LEN
= 450;
817 if (length
> MAX_CLIENT_MSG_LEN
) {
818 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
819 % m_client
->GetUserName() % m_client
->GetFullIP() % (length
- MAX_CLIENT_MSG_LEN
));
820 length
= MAX_CLIENT_MSG_LEN
;
823 wxString message
= message_file
.ReadOnlyString((m_client
->GetUnicodeSupport() != utf8strNone
), length
);
824 m_client
->ProcessChatMessage(message
);
829 case OP_ASKSHAREDFILES
: { // 0.43b (well, er, it does the same, but in our own way)
830 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client
->GetFullIP() );
832 // client wants to know what we have in share, let's see if we allow him to know that
833 theStats::AddDownOverheadOther(size
);
834 // IP banned, no answer for this request
835 if (m_client
->IsBanned()) {
839 if (thePrefs::CanSeeShares() == vsfaEverybody
|| (thePrefs::CanSeeShares() == vsfaFriends
&& m_client
->IsFriend())) {
840 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
841 % m_client
->GetUserName()
842 % m_client
->GetUserIDHybrid() );
844 std::vector
<CKnownFile
*> list
;
845 theApp
->sharedfiles
->CopyFileList(list
);
847 CMemFile
tempfile(80);
848 tempfile
.WriteUInt32(list
.size());
849 for (unsigned i
= 0; i
< list
.size(); ++i
) {
850 if (!list
[i
]->IsLargeFile() || m_client
->SupportsLargeFiles()) {
851 list
[i
]->CreateOfferedFilePacket(&tempfile
, NULL
, m_client
);
855 // create a packet and send it
856 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESANSWER
);
857 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client
->GetFullIP() );
858 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
859 SendPacket(replypacket
, true, true);
861 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
862 % m_client
->GetUserName()
863 % m_client
->GetUserIDHybrid() );
865 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
866 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
867 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
868 SendPacket(replypacket
, true, true);
874 case OP_ASKSHAREDFILESANSWER
: { // 0.43b
875 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client
->GetFullIP() );
877 theStats::AddDownOverheadOther(size
);
879 m_client
->ProcessSharedFileList(buffer
, size
, EmptyStr
);
883 case OP_ASKSHAREDDIRS
: { // 0.43b
884 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client
->GetFullIP() );
886 theStats::AddDownOverheadOther(size
);
887 wxASSERT( size
== 0 );
888 // IP banned, no answer for this request
889 if (m_client
->IsBanned()) {
892 if ((thePrefs::CanSeeShares()==vsfaEverybody
) || ((thePrefs::CanSeeShares()==vsfaFriends
) && m_client
->IsFriend())) {
893 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
894 % m_client
->GetUserName()
895 % m_client
->GetUserIDHybrid() );
896 // send the list of shared directories
897 m_client
->SendSharedDirectories();
899 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
900 % m_client
->GetUserName()
901 % m_client
->GetUserIDHybrid() );
903 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
904 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
905 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
906 SendPacket(replypacket
, true, true);
912 case OP_ASKSHAREDFILESDIR
: { // 0.43b
913 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client
->GetFullIP() );
915 theStats::AddDownOverheadOther(size
);
916 // IP banned, no answer for this request
917 if (m_client
->IsBanned()) {
920 CMemFile
data(buffer
, size
);
922 wxString strReqDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
923 if (thePrefs::CanSeeShares()==vsfaEverybody
|| (thePrefs::CanSeeShares()==vsfaFriends
&& m_client
->IsFriend())) {
924 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory '%s' -> accepted")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
925 wxASSERT( data
.GetPosition() == data
.GetLength() );
926 // send the list of shared files for the requested directory
927 m_client
->SendSharedFilesOfDirectory(strReqDir
);
929 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory '%s' -> denied")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
931 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
932 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
933 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
934 SendPacket(replypacket
, true, true);
939 case OP_ASKSHAREDDIRSANS
:{ // 0.43b
940 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client
->GetFullIP() );
942 theStats::AddDownOverheadOther(size
);
943 if (m_client
->GetFileListRequested() == 1){
944 CMemFile
data(buffer
, size
);
945 uint32 uDirs
= data
.ReadUInt32();
946 for (uint32 i
= 0; i
< uDirs
; i
++){
947 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
948 AddLogLineC(CFormat( _("User %s (%u) shares directory '%s'") )
949 % m_client
->GetUserName()
950 % m_client
->GetUserIDHybrid()
953 CMemFile
tempfile(80);
954 tempfile
.WriteString(strDir
, m_client
->GetUnicodeSupport());
955 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIR
);
956 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
957 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESDIR to ") + m_client
->GetFullIP() );
958 SendPacket(replypacket
, true, true);
960 wxASSERT( data
.GetPosition() == data
.GetLength() );
961 m_client
->SetFileListRequested(uDirs
);
963 AddLogLineC(CFormat( _("User %s (%u) sent unrequested shared dirs.") )
964 % m_client
->GetUserName()
965 % m_client
->GetUserIDHybrid() );
970 case OP_ASKSHAREDFILESDIRANS
: { // 0.43b
971 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client
->GetFullIP() );
973 theStats::AddDownOverheadOther(size
);
974 CMemFile
data(buffer
, size
);
975 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
977 if (m_client
->GetFileListRequested() > 0){
978 AddLogLineC(CFormat( _("User %s (%u) sent sharedfiles-list for directory '%s'") )
979 % m_client
->GetUserName()
980 % m_client
->GetUserIDHybrid()
983 m_client
->ProcessSharedFileList(buffer
+ data
.GetPosition(), size
- data
.GetPosition(), strDir
);
984 if (m_client
->GetFileListRequested() == 0) {
985 AddLogLineC(CFormat( _("User %s (%u) finished sending sharedfiles-list") )
986 % m_client
->GetUserName()
987 % m_client
->GetUserIDHybrid() );
990 AddLogLineC(CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
991 % m_client
->GetUserName()
992 % m_client
->GetUserIDHybrid() );
997 case OP_ASKSHAREDDENIEDANS
:
998 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client
->GetFullIP() );
1000 theStats::AddDownOverheadOther(size
);
1001 wxASSERT( size
== 0 );
1002 AddLogLineC(CFormat( _("User %s (%u) denied access to shared directories/files list") )
1003 % m_client
->GetUserName()
1004 % m_client
->GetUserIDHybrid() );
1006 m_client
->SetFileListRequested(0);
1010 theStats::AddDownOverheadOther(size
);
1011 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Edonkey packet: unknown opcode: %i %x from %s")) % opcode
% opcode
% m_client
->GetFullIP());
1019 bool CClientTCPSocket::ProcessExtPacket(const uint8_t* buffer
, uint32 size
, uint8 opcode
)
1021 #ifdef __PACKET_RECV_DUMP__
1022 //printf("Rec: OPCODE %x \n",opcode);
1023 DumpMem(buffer
,size
);
1026 // 0.42e - except the catchs on mem exception and file exception
1028 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1031 if (!client->CheckHandshakeFinished()) {
1032 // Here comes an extended packet without finishing the handshake.
1033 // IMHO, we should disconnect the client.
1034 throw wxString(wxT("Client send extended packet before finishing handshake"));
1038 case OP_MULTIPACKET_EXT
:
1039 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client
->GetFullIP());
1041 case OP_MULTIPACKET
: {
1042 if (opcode
== OP_MULTIPACKET
) AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET from ") + m_client
->GetFullIP() );
1044 theStats::AddDownOverheadFileRequest(size
);
1046 if (m_client
->IsBanned()) {
1050 if (!m_client
->CheckHandshakeFinished()) {
1051 // Here comes an extended packet without finishing the handshake.
1052 // IMHO, we should disconnect the client.
1053 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1056 CMemFile
data_in(buffer
, size
);
1057 CMD4Hash reqfilehash
= data_in
.ReadHash();
1058 uint64 nSize
= (opcode
== OP_MULTIPACKET_EXT
) ? data_in
.ReadUInt64() : 0;
1060 bool file_not_found
= false;
1061 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
1062 if ( reqfile
== NULL
){
1063 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1064 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
1065 AddDebugLogLineN(logRemoteClient
, wxT("Remote client asked for a non-shared file"));
1066 file_not_found
= true;
1070 if (!file_not_found
&& reqfile
->IsLargeFile() && !m_client
->SupportsLargeFiles()) {
1071 AddDebugLogLineN(logRemoteClient
, wxT("Remote client asked for a large file but doesn't support them"));
1072 file_not_found
= true;
1075 if (!file_not_found
&& nSize
&& (reqfile
->GetFileSize() != nSize
)) {
1076 AddDebugLogLineN(logRemoteClient
, wxT("Remote client asked for a file but specified wrong size"));
1077 file_not_found
= true;
1080 if (file_not_found
) {
1081 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
1082 replypacket
->Copy16ToDataBuffer(reqfilehash
.GetHash());
1083 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
1084 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client
->GetFullIP() );
1085 SendPacket(replypacket
, true);
1089 if (!m_client
->GetWaitStartTime()) {
1090 m_client
->SetWaitStartTime();
1092 // if we are downloading this file, this could be a new source
1093 // no passive adding of files with only one part
1094 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
1095 if (thePrefs::GetMaxSourcePerFile() > static_cast<CPartFile
*>(reqfile
)->GetSourceCount()) {
1096 theApp
->downloadqueue
->CheckAndAddKnownSource(static_cast<CPartFile
*>(reqfile
), m_client
);
1099 // check to see if this is a new file they are asking for
1100 if (m_client
->GetUploadFileID() != reqfilehash
) {
1101 m_client
->SetCommentDirty();
1103 m_client
->SetUploadFileID(reqfile
);
1104 CMemFile
data_out(128);
1105 data_out
.WriteHash(reqfile
->GetFileHash());
1106 while(data_in
.GetLength()-data_in
.GetPosition()) {
1108 throw wxString(wxT("Client suddenly disconnected"));
1110 uint8 opcode_in
= data_in
.ReadUInt8();
1112 case OP_REQUESTFILENAME
: {
1113 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1114 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
1115 data_out
.WriteUInt8(OP_REQFILENAMEANSWER
);
1117 // Since it's for somebody else to see, we need to send the prettified
1118 // filename, rather than the (possibly) mangled actual filename
1119 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
1122 case OP_AICHFILEHASHREQ
: {
1123 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1124 if (m_client
->IsSupportingAICH() && reqfile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1125 && reqfile
->GetAICHHashset()->HasValidMasterHash())
1127 data_out
.WriteUInt8(OP_AICHFILEHASHANS
);
1128 reqfile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1132 case OP_SETREQFILEID
: {
1133 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1134 data_out
.WriteUInt8(OP_FILESTATUS
);
1135 if (reqfile
->IsPartFile()) {
1136 static_cast<CPartFile
*>(reqfile
)->WritePartStatus(&data_out
);
1138 data_out
.WriteUInt16(0);
1142 //We still send the source packet separately..
1143 //We could send it within this packet.. If agreeded, I will fix it..
1144 case OP_REQUESTSOURCES2
:
1145 case OP_REQUESTSOURCES
: {
1146 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1147 uint8 byRequestedVersion
= 0;
1148 uint16 byRequestedOptions
= 0;
1149 if (opcode_in
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1150 byRequestedVersion
= data_in
.ReadUInt8();
1151 byRequestedOptions
= data_in
.ReadUInt16();
1154 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1156 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() > 1) {
1157 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1158 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1160 //if not complete and file is rare
1161 ( reqfile
->IsPartFile()
1162 && (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1163 && static_cast<CPartFile
*>(reqfile
)->GetSourceCount() <= RARE_FILE
1165 //OR if file is not rare or if file is complete
1166 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1169 m_client
->SetLastSrcReqTime();
1170 CPacket
* tosend
= reqfile
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1172 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1173 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1174 SendPacket(tosend
, true);
1183 if( data_out
.GetLength() > 16 ) {
1184 CPacket
* reply
= new CPacket(data_out
, OP_EMULEPROT
, OP_MULTIPACKETANSWER
);
1185 theStats::AddUpOverheadFileRequest(reply
->GetPacketSize());
1186 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client
->GetFullIP() );
1187 SendPacket(reply
, true);
1192 case OP_MULTIPACKETANSWER
: { // 0.43b
1193 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client
->GetFullIP() );
1195 theStats::AddDownOverheadFileRequest(size
);
1197 if (m_client
->IsBanned()) {
1201 if (m_client
->GetKadPort() && m_client
->GetKadVersion() > 1) {
1202 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client
->GetIP()), m_client
->GetKadPort());
1205 if (!m_client
->CheckHandshakeFinished()) {
1206 // Here comes an extended packet without finishing the handshake.
1207 // IMHO, we should disconnect the client.
1208 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1211 CMemFile
data_in(buffer
, size
);
1212 CMD4Hash reqfilehash
= data_in
.ReadHash();
1213 const CPartFile
*reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1214 //Make sure we are downloading this file.
1216 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1218 if ( !m_client
->GetRequestFile() ) {
1220 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1222 if (reqfile
!= m_client
->GetRequestFile()) {
1223 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1225 while (data_in
.GetLength()-data_in
.GetPosition()) {
1226 // Some of the cases down there can actually send a packet and lose the client
1228 throw wxString(wxT("Client suddenly disconnected"));
1230 uint8 opcode_in
= data_in
.ReadUInt8();
1232 case OP_REQFILENAMEANSWER
: {
1234 throw wxString(wxT("Client suddenly disconnected"));
1236 m_client
->ProcessFileInfo(&data_in
, reqfile
);
1240 case OP_FILESTATUS
: {
1242 throw wxString(wxT("Client suddenly disconnected"));
1244 m_client
->ProcessFileStatus(false, &data_in
, reqfile
);
1248 case OP_AICHFILEHASHANS
: {
1250 throw wxString(wxT("Client suddenly disconnected"));
1252 m_client
->ProcessAICHFileHash(&data_in
, reqfile
);
1262 case OP_EMULEINFO
: { // 0.43b
1263 theStats::AddDownOverheadOther(size
);
1265 if (!m_client
->ProcessMuleInfoPacket(buffer
, size
)) {
1266 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_EMULEINFO from ") + m_client
->GetFullIP() );
1268 // If it's not a OS Info packet, is an old client
1269 // start secure identification, if
1270 // - we have received eD2K and eMule info (old eMule)
1271 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1272 m_client
->InfoPacketsReceived();
1274 m_client
->SendMuleInfoPacket(true);
1276 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1280 case OP_EMULEINFOANSWER
: { // 0.43b
1281 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client
->GetFullIP() );
1282 theStats::AddDownOverheadOther(size
);
1284 m_client
->ProcessMuleInfoPacket(buffer
, size
);
1285 // start secure identification, if
1286 // - we have received eD2K and eMule info (old eMule)
1288 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1289 m_client
->InfoPacketsReceived();
1295 case OP_SECIDENTSTATE
:{ // 0.43b
1296 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client
->GetFullIP() );
1298 if (!m_client
->CheckHandshakeFinished()) {
1299 // Here comes an extended packet without finishing the handshake.
1300 // IMHO, we should disconnect the client.
1301 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1303 m_client
->ProcessSecIdentStatePacket(buffer
, size
);
1304 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1306 int SecureIdentState
= m_client
->GetSecureIdentState();
1307 if (SecureIdentState
== IS_SIGNATURENEEDED
) {
1308 m_client
->SendSignaturePacket();
1309 } else if (SecureIdentState
== IS_KEYANDSIGNEEDED
) {
1310 m_client
->SendPublicKeyPacket();
1311 // SendPublicKeyPacket() might cause the socket to die, so check
1313 m_client
->SendSignaturePacket();
1320 case OP_PUBLICKEY
: { // 0.43b
1321 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PUBLICKEY from ") + m_client
->GetFullIP() );
1323 if (m_client
->IsBanned() ){
1327 if (!m_client
->CheckHandshakeFinished()) {
1328 // Here comes an extended packet without finishing the handshake.
1329 // IMHO, we should disconnect the client.
1330 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1333 m_client
->ProcessPublicKeyPacket(buffer
, size
);
1336 case OP_SIGNATURE
:{ // 0.43b
1337 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SIGNATURE from ") + m_client
->GetFullIP() );
1339 if (!m_client
->CheckHandshakeFinished()) {
1340 // Here comes an extended packet without finishing the handshake.
1341 // IMHO, we should disconnect the client.
1342 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1345 m_client
->ProcessSignaturePacket(buffer
, size
);
1348 case OP_SENDINGPART_I64
:
1349 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client
->GetFullIP() );
1351 case OP_COMPRESSEDPART_I64
:
1352 if (opcode
== OP_COMPRESSEDPART_I64
) AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client
->GetFullIP() );
1354 case OP_COMPRESSEDPART
: { // 0.47a
1355 if (opcode
== OP_COMPRESSEDPART
) AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART 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_COMPRESSEDPART before finishing handshake"));
1363 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
1365 m_client
->ProcessBlockPacket(buffer
, size
, (opcode
!= OP_SENDINGPART_I64
), (opcode
== OP_COMPRESSEDPART_I64
) || (opcode
== OP_SENDINGPART_I64
));
1368 m_client
->GetRequestFile()->IsStopped() ||
1369 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
1370 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
)) {
1371 if (!m_client
->GetSentCancelTransfer()) {
1372 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1373 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1374 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1375 m_client
->SendPacket(packet
,true,true);
1378 m_client
->SetSentCancelTransfer(1);
1383 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
1387 if (!m_client
->GetSentCancelTransfer()) {
1388 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1389 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1390 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1391 m_client
->SendPacket(packet
,true,true);
1394 m_client
->SetSentCancelTransfer(1);
1399 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
1404 case OP_REQUESTPARTS_I64
: {
1405 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client
->GetFullIP() );
1407 theStats::AddDownOverheadFileRequest(size
);
1409 m_client
->ProcessRequestPartsPacket(buffer
, size
, true);
1413 case OP_QUEUERANKING
: { // 0.43b
1414 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_QUEUERANKING from ") + m_client
->GetFullIP() );
1416 theStats::AddDownOverheadOther(size
);
1418 if (!m_client
->CheckHandshakeFinished()) {
1419 // Here comes an extended packet without finishing the handshake.
1420 // IMHO, we should disconnect the client.
1421 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1425 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1428 uint16 newrank
= PeekUInt16(buffer
);
1429 m_client
->SetRemoteQueueFull(false);
1430 m_client
->SetRemoteQueueRank(newrank
);
1433 case OP_REQUESTSOURCES2
:
1434 case OP_REQUESTSOURCES
:{
1435 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client
->GetFullIP() );
1437 theStats::AddDownOverheadSourceExchange(size
);
1439 if (!m_client
->CheckHandshakeFinished()) {
1440 // Here comes an extended packet without finishing the handshake.
1441 // IMHO, we should disconnect the client.
1442 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1445 uint8 byRequestedVersion
= 0;
1446 uint16 byRequestedOptions
= 0;
1447 CMemFile
data_in(buffer
, size
);
1448 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1449 byRequestedVersion
= data_in
.ReadUInt8();
1450 byRequestedOptions
= data_in
.ReadUInt16();
1453 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() >= 1) {
1455 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1457 //first check shared file list, then download list
1458 const CMD4Hash
fileID(buffer
);
1459 CKnownFile
* file
= theApp
->sharedfiles
->GetFileByID(fileID
);
1461 file
= theApp
->downloadqueue
->GetFileByID(fileID
);
1464 // There are some clients which do not follow the correct protocol procedure of sending
1465 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1466 // are doing this, they will not get the optimal set of sources which we could offer if
1467 // they would follow the above noted protocol sequence. They better do it the right way
1468 // or they will get just a random set of sources because we do not know their download
1469 // part status which may get cleared with the call of 'SetUploadFileID'.
1470 m_client
->SetUploadFileID(file
);
1472 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1473 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1475 //if not complete and file is rare, allow once every 40 minutes
1476 ( file
->IsPartFile() &&
1477 static_cast<CPartFile
*>(file
)->GetSourceCount() <= RARE_FILE
&&
1478 (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1480 //OR if file is not rare or if file is complete, allow every 90 minutes
1481 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1484 m_client
->SetLastSrcReqTime();
1485 CPacket
* tosend
= file
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1487 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1488 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1489 SendPacket(tosend
, true, true);
1496 case OP_ANSWERSOURCES
: {
1497 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client
->GetFullIP() );
1499 theStats::AddDownOverheadSourceExchange(size
);
1501 if (!m_client
->CheckHandshakeFinished()) {
1502 // Here comes an extended packet without finishing the handshake.
1503 // IMHO, we should disconnect the client.
1504 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1507 CMemFile
data(buffer
, size
);
1508 CMD4Hash hash
= data
.ReadHash();
1509 CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1511 if (file
->IsPartFile()){
1512 //set the client's answer time
1513 m_client
->SetLastSrcAnswerTime();
1514 //and set the file's last answer time
1515 static_cast<CPartFile
*>(file
)->SetLastAnsweredTime();
1516 static_cast<CPartFile
*>(file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, m_client
->GetSourceExchange1Version(), false, m_client
);
1521 case OP_ANSWERSOURCES2
: {
1522 //printf("Received OP_ANSWERSOURCES2\n");
1523 theStats::AddDownOverheadSourceExchange(size
);
1525 if (!m_client
->CheckHandshakeFinished()) {
1526 // Here comes an extended packet without finishing the handshake.
1527 // IMHO, we should disconnect the client.
1528 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1531 CMemFile
data(buffer
, size
);
1532 uint8 byVersion
= data
.ReadUInt8();
1533 CMD4Hash hash
= data
.ReadHash();
1534 CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1536 if (file
->IsPartFile()){
1537 //set the client's answer time
1538 m_client
->SetLastSrcAnswerTime();
1539 //and set the file's last answer time
1540 static_cast<CPartFile
*>(file
)->SetLastAnsweredTime();
1541 static_cast<CPartFile
*>(file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, byVersion
, true, m_client
);
1546 case OP_FILEDESC
: { // 0.43b
1547 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_FILEDESC from ") + m_client
->GetFullIP() );
1549 theStats::AddDownOverheadFileRequest(size
);
1551 if (!m_client
->CheckHandshakeFinished()) {
1552 // Here comes an extended packet without finishing the handshake.
1553 // IMHO, we should disconnect the client.
1554 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1557 m_client
->ProcessMuleCommentPacket(buffer
, size
);
1562 case OP_REQUESTPREVIEW
: {
1563 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client
->GetFullIP() );
1567 case OP_PREVIEWANSWER
: {
1568 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client
->GetFullIP() );
1572 case OP_PUBLICIP_ANSWER
: {
1573 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client
->GetFullIP() );
1574 theStats::AddDownOverheadOther(size
);
1575 m_client
->ProcessPublicIPAnswer(buffer
, size
);
1578 case OP_PUBLICIP_REQ
: {
1579 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client
->GetFullIP() );
1580 theStats::AddDownOverheadOther(size
);
1581 CPacket
* pPacket
= new CPacket(OP_PUBLICIP_ANSWER
, 4, OP_EMULEPROT
);
1582 pPacket
->CopyUInt32ToDataBuffer(m_client
->GetIP());
1583 theStats::AddUpOverheadOther(pPacket
->GetPacketSize());
1584 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client
->GetFullIP());
1585 SendPacket(pPacket
);
1588 case OP_AICHANSWER
: {
1589 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHANSWER from ") + m_client
->GetFullIP() );
1590 theStats::AddDownOverheadOther(size
);
1591 m_client
->ProcessAICHAnswer(buffer
, size
);
1594 case OP_AICHREQUEST
: {
1595 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHREQUEST from ") + m_client
->GetFullIP() );
1596 theStats::AddDownOverheadOther(size
);
1597 m_client
->ProcessAICHRequest(buffer
, size
);
1600 case OP_AICHFILEHASHANS
: {
1601 // those should not be received normally, since we should only get those in MULTIPACKET
1602 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client
->GetFullIP() );
1603 theStats::AddDownOverheadOther(size
);
1604 CMemFile
data(buffer
, size
);
1605 m_client
->ProcessAICHFileHash(&data
, NULL
);
1608 case OP_AICHFILEHASHREQ
: {
1609 // those should not be received normally, since we should only get those in MULTIPACKET
1610 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client
->GetFullIP() );
1611 CMemFile
data(buffer
, size
);
1612 CMD4Hash hash
= data
.ReadHash();
1613 CKnownFile
* pPartFile
= theApp
->sharedfiles
->GetFileByID(hash
);
1614 if (pPartFile
== NULL
){
1618 if (m_client
->IsSupportingAICH() && pPartFile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1619 && pPartFile
->GetAICHHashset()->HasValidMasterHash()) {
1621 data_out
.WriteHash(hash
);
1622 pPartFile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1623 CPacket
* packet
= new CPacket(data_out
, OP_EMULEPROT
, OP_AICHFILEHASHANS
);
1624 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1625 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client
->GetFullIP());
1631 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CALLBACK from ") + m_client
->GetFullIP() );
1632 theStats::AddDownOverheadFileRequest(size
);
1633 if(!Kademlia::CKademlia::IsRunning()) {
1636 CMemFile
data(buffer
, size
);
1637 CUInt128 check
= data
.ReadUInt128();
1638 check
^= Kademlia::CUInt128(true);
1639 if (check
!= Kademlia::CKademlia::GetPrefs()->GetKadID()) {
1642 CUInt128 fileid
= data
.ReadUInt128();
1643 uint8_t fileid2
[16];
1644 fileid
.ToByteArray(fileid2
);
1645 const CMD4Hash
fileHash(fileid2
);
1646 if (theApp
->sharedfiles
->GetFileByID(fileHash
) == NULL
) {
1647 if (theApp
->downloadqueue
->GetFileByID(fileHash
) == NULL
) {
1652 uint32 ip
= data
.ReadUInt32();
1653 uint16 tcp
= data
.ReadUInt16();
1654 CUpDownClient
* callback
;
1655 callback
= theApp
->clientlist
->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip
), tcp
);
1656 if( callback
== NULL
) {
1657 //#warning Do we actually have to check friend status here?
1658 callback
= new CUpDownClient(tcp
,ip
,0,0,NULL
,false, false);
1659 theApp
->clientlist
->AddClient(callback
);
1661 callback
->TryToConnect(true);
1665 case OP_BUDDYPING
: {
1666 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_BUDDYPING from ") + m_client
->GetFullIP() );
1667 theStats::AddDownOverheadKad(size
);
1669 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1670 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 || !m_client
->AllowIncomeingBuddyPingPong() ) {
1671 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1675 m_client
->SetLastBuddyPingPongTime();
1676 CPacket
* replypacket
= new CPacket(OP_BUDDYPONG
, 0, OP_EMULEPROT
);
1677 theStats::AddUpOverheadKad(replypacket
->GetPacketSize());
1678 AddDebugLogLineN(logLocalClient
,wxT("Local Client: OP_BUDDYPONG to ") + m_client
->GetFullIP());
1679 SendPacket(replypacket
);
1682 case OP_BUDDYPONG
: {
1683 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_BUDDYPONG from ") + m_client
->GetFullIP() );
1684 theStats::AddDownOverheadKad(size
);
1686 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1687 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 ) {
1688 //This pong was not from our buddy or wrong version. Ignore
1691 m_client
->SetLastBuddyPingPongTime();
1692 //All this is for is to reset our socket timeout.
1695 case OP_REASKCALLBACKTCP
: {
1696 theStats::AddDownOverheadFileRequest(size
);
1697 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1698 if (buddy
!= m_client
) {
1699 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() + wxT(" which is not our buddy!") );
1700 //This callback was not from our buddy.. Ignore.
1703 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() );
1704 CMemFile
data_in(buffer
, size
);
1705 uint32 destip
= data_in
.ReadUInt32();
1706 uint16 destport
= data_in
.ReadUInt16();
1707 CMD4Hash hash
= data_in
.ReadHash();
1708 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(hash
);
1710 bool bSenderMultipleIpUnknown
= false;
1711 CUpDownClient
* sender
= theApp
->uploadqueue
->GetWaitingClientByIP_UDP(destip
, destport
, true, &bSenderMultipleIpUnknown
);
1713 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILENOTFOUND to ") + m_client
->GetFullIP() );
1714 CPacket
* response
= new CPacket(OP_FILENOTFOUND
,0,OP_EMULEPROT
);
1715 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1717 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1719 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1725 //Make sure we are still thinking about the same file
1726 if (hash
== sender
->GetUploadFileID()) {
1727 sender
->AddAskedCount();
1728 sender
->SetLastUpRequest();
1729 //I messed up when I first added extended info to UDP
1730 //I should have originally used the entire ProcessExtenedInfo the first time.
1731 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1732 //For now on, we should not have to change anything here if we change
1733 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1734 //Update extended info.
1735 if (sender
->GetUDPVersion() > 3) {
1736 sender
->ProcessExtendedInfo(&data_in
, reqfile
);
1737 } else if (sender
->GetUDPVersion() > 2) {
1738 //Update our complete source counts.
1739 uint16 nCompleteCountLast
= sender
->GetUpCompleteSourcesCount();
1740 uint16 nCompleteCountNew
= data_in
.ReadUInt16();
1741 sender
->SetUpCompleteSourcesCount(nCompleteCountNew
);
1742 if (nCompleteCountLast
!= nCompleteCountNew
) {
1743 reqfile
->UpdatePartsInfo();
1747 CMemFile
data_out(128);
1748 if(sender
->GetUDPVersion() > 3) {
1749 if (reqfile
->IsPartFile()) {
1750 static_cast<CPartFile
*>(reqfile
)->WritePartStatus(&data_out
);
1752 data_out
.WriteUInt16(0);
1756 data_out
.WriteUInt16(sender
->GetUploadQueueWaitingPosition());
1757 CPacket
* response
= new CPacket(data_out
, OP_EMULEPROT
, OP_REASKACK
);
1758 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1759 AddDebugLogLineN( logLocalClient
, wxT("Local Client UDP: OP_REASKACK to ") + m_client
->GetFullIP() );
1760 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1762 AddDebugLogLineN(logListenSocket
, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1765 if (!bSenderMultipleIpUnknown
){
1766 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1767 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_QUEUEFULL to ") + m_client
->GetFullIP() );
1768 CPacket
* response
= new CPacket(OP_QUEUEFULL
,0,OP_EMULEPROT
);
1769 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1770 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1773 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("OP_REASKCALLBACKTCP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u")) % Uint32toStringIP(destip
) % destport
);
1778 case OP_CHATCAPTCHAREQ
:
1780 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client
->GetFullIP());
1781 theStats::AddDownOverheadOther(size
);
1782 CMemFile
data_in(buffer
, size
);
1783 m_client
->ProcessCaptchaRequest(&data_in
);
1786 case OP_CHATCAPTCHARES
:
1788 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client
->GetFullIP());
1789 theStats::AddDownOverheadOther(size
);
1791 m_client
->ProcessCaptchaReqRes(buffer
[0]);
1795 case OP_FWCHECKUDPREQ
: { // Support required for Kadversion >= 6
1796 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client
->GetFullIP());
1797 theStats::AddDownOverheadOther(size
);
1798 CMemFile
data_in(buffer
, size
);
1799 m_client
->ProcessFirewallCheckUDPRequest(&data_in
);
1802 case OP_KAD_FWTCPCHECK_ACK
: { // Support required for Kadversion >= 7
1803 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client
->GetFullIP());
1804 if (theApp
->clientlist
->IsKadFirewallCheckIP(m_client
->GetIP())) {
1805 if (Kademlia::CKademlia::IsRunning()) {
1806 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1809 AddDebugLogLineN(logListenSocket
, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client
->GetFullIP());
1814 theStats::AddDownOverheadOther(size
);
1815 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("eMule packet : unknown opcode: %i %x from %s")) % opcode
% opcode
% m_client
->GetFullIP());
1822 bool CClientTCPSocket::ProcessED2Kv2Packet(const uint8_t* buffer
, uint32 size
, uint8 opcode
)
1824 #ifdef __PACKET_RECV_DUMP__
1825 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1826 DumpMem(buffer
,size
);
1830 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1833 CMemFile
data(buffer
, size
);
1836 case OP_QUEUERANK
: {
1837 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client
->GetFullIP() );
1839 uint8 numtags
= data
.ReadUInt8();
1840 wxASSERT(numtags
== 1);
1841 if(numtags
){} // prevent GCC warning
1843 m_client
->SetRemoteQueueRank(data
.GetIntTagValue());
1845 theStats::AddDownOverheadFileRequest(size
);
1849 case OP_REQUESTPARTS
: {
1850 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
1852 m_client
->ProcessRequestPartsPacketv2(data
);
1854 theStats::AddDownOverheadFileRequest(size
);
1859 theStats::AddDownOverheadOther(size
);
1860 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("ED2Kv2 packet : unknown opcode: %i %x from %s")) % opcode
% opcode
% m_client
->GetFullIP());
1863 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from %s")) % data
.GetPosition() % opcode
% opcode
% m_client
->GetFullIP());
1870 void CClientTCPSocket::OnConnect(int nErrorCode
)
1873 OnError(nErrorCode
);
1874 } else if (!m_client
) {
1875 // and now? Disconnect? not?
1876 AddDebugLogLineN( logClient
, wxT("Couldn't send hello packet (Client deleted!)") );
1877 } else if (!m_client
->SendHelloPacket()) {
1878 // and now? Disconnect? not?
1879 AddDebugLogLineN( logClient
, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1881 ResetTimeOutTimer();
1886 void CClientTCPSocket::OnSend(int nErrorCode
)
1888 ResetTimeOutTimer();
1889 CEMSocket::OnSend(nErrorCode
);
1893 void CClientTCPSocket::OnReceive(int nErrorCode
)
1895 ResetTimeOutTimer();
1896 // We might have updated ipfilter
1897 wxASSERT(m_remoteip
);
1899 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
1901 m_client
->Safe_Delete();
1904 AddDebugLogLineN( logIPFilter
, wxT("A connected client was dropped by IPFilter on new packet received"));
1906 CEMSocket::OnReceive(nErrorCode
);
1911 void CClientTCPSocket::OnError(int nErrorCode
)
1913 //printf("* Called OnError for %p\n",this);
1914 // 0.42e + Kry changes for handling of socket lost events
1917 if ((nErrorCode
== 0) || (nErrorCode
== 7) || (nErrorCode
== 0xFEFF)) {
1919 if (!m_client
->GetUserName().IsEmpty()) {
1920 strError
= wxT("Client '") + m_client
->GetUserName() + wxT("'");
1922 strError
= wxT("An unnamed client");
1924 strError
+= wxT(" (IP:") + m_client
->GetFullIP() + wxT(") ");
1926 strError
= wxT("A client ");
1928 if (nErrorCode
== 0) {
1929 strError
+= wxT("closed connection.");
1930 } else if (nErrorCode
== 0xFEFF) {
1931 strError
+= wxT(" caused a wxSOCKET_LOST event.");
1933 strError
+= wxT("caused a socket blocking error.");
1936 if (theLogger
.IsEnabled(logClient
) && nErrorCode
!= 107) {
1937 // 0 -> No Error / Disconect
1938 // 107 -> Transport endpoint is not connected
1940 if (!m_client
->GetUserName().IsEmpty()) {
1941 strError
= CFormat(wxT("OnError: Client '%s' (IP:%s) caused an error: %u. Disconnecting client!"))
1942 % m_client
->GetUserName() % m_client
->GetFullIP() % nErrorCode
;
1944 strError
= CFormat(wxT("OnError: Unknown client (IP:%s) caused an error: %u. Disconnecting client!"))
1945 % m_client
->GetFullIP() % nErrorCode
;
1948 strError
= CFormat(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"))
1952 strError
= wxT("Error 107 (Transport endpoint is not connected)");
1956 Disconnect(strError
);
1960 bool CClientTCPSocket::PacketReceived(CPacket
* packet
)
1963 bool bResult
= false;
1964 uint32 uRawSize
= packet
->GetPacketSize();
1966 AddDebugLogLineN( logRemoteClient
,
1967 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1968 % packet
->GetProtocol()
1969 % packet
->GetOpCode()
1970 % packet
->GetPacketSize()
1971 % ( m_client
? m_client
->GetFullIP() : wxT("Unknown Client") )
1977 bool process
= true;
1979 if ((packet
->GetProtocol() == OP_PACKEDPROT
) ||
1980 (packet
->GetProtocol() == OP_ED2KV2PACKEDPROT
)) {
1982 if (!packet
->UnPackPacket()) {
1983 AddDebugLogLineN(logZLib
, wxT("Failed to decompress client TCP packet."));
1987 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"))
1988 % packet
->GetProtocol() % packet
->GetOpCode() % packet
->GetPacketSize());
1993 switch (packet
->GetProtocol()) {
1994 case OP_EDONKEYPROT
:
1995 bResult
= ProcessPacket(packet
->GetDataBuffer(),uRawSize
,packet
->GetOpCode());
1998 bResult
= ProcessExtPacket(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2000 case OP_ED2KV2HEADER
:
2001 bResult
= ProcessED2Kv2Packet(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2003 case OP_ED2KV2PACKEDPROT
:
2005 // Packed inside packed?
2009 theStats::AddDownOverheadOther(uRawSize
);
2011 m_client
->SetDownloadState(DS_ERROR
);
2013 Disconnect(wxT("Unknown protocol"));
2018 } catch (const CEOFException
& err
) {
2019 exception
= wxT("EOF exception: ") + err
.what();
2020 } catch (const CInvalidPacket
& err
) {
2021 exception
= wxT("InvalidPacket exception: ") + err
.what();
2022 } catch (const wxString
& error
) {
2023 exception
= wxT("error: ") + (error
.IsEmpty() ? wxString(wxT("Unknown error")) : error
);
2026 if (!exception
.IsEmpty()) {
2027 AddDebugLogLineN( logPacketErrors
,
2028 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2030 % packet
->GetProtocol()
2031 % packet
->GetOpCode()
2032 % packet
->GetPacketSize()
2033 % ( m_client
? m_client
->GetClientFullInfo() : wxT("Unknown") )
2037 m_client
->SetDownloadState(DS_ERROR
);
2040 AddDebugLogLineN( logClient
,
2041 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2042 % ( m_client
? m_client
->GetUserName() : wxString(wxT("Unknown")) )
2043 % ( m_client
? m_client
->GetFullIP() : wxString(wxT("Unknown")) )
2047 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2054 SocketSentBytes
CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2056 SocketSentBytes returnStatus
= CEMSocket::SendControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2058 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2059 ResetTimeOutTimer();
2062 return returnStatus
;
2066 SocketSentBytes
CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2068 SocketSentBytes returnStatus
= CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2070 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2071 ResetTimeOutTimer();
2074 return returnStatus
;
2078 void CClientTCPSocket::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
, uint32 actualPayloadSize
)
2080 ResetTimeOutTimer();
2081 CEMSocket::SendPacket(packet
,delpacket
,controlpacket
, actualPayloadSize
);
2083 // File_checked_for_headers