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-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )//
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
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__
59 //------------------------------------------------------------------------------
60 // CClientTCPSocketHandler
61 //------------------------------------------------------------------------------
63 class CClientTCPSocketHandler
: public wxEvtHandler
66 CClientTCPSocketHandler() {};
69 void ClientTCPSocketHandler(wxSocketEvent
& event
);
73 BEGIN_EVENT_TABLE(CClientTCPSocketHandler
, wxEvtHandler
)
74 EVT_SOCKET(ID_CLIENTTCPSOCKET_EVENT
, CClientTCPSocketHandler::ClientTCPSocketHandler
)
77 void CClientTCPSocketHandler::ClientTCPSocketHandler(wxSocketEvent
& event
)
79 CClientTCPSocket
*socket
= dynamic_cast<CClientTCPSocket
*>(event
.GetSocket());
85 if (socket
->OnDestroy() || socket
->ForDeletion()) {
89 switch(event
.GetSocketEvent()) {
91 socket
->OnError(0xFEFF /* SOCKET_LOST is not an error */);
99 case wxSOCKET_CONNECTION
:
100 // connection stablished, nothing to do about it?
101 socket
->OnConnect(socket
->Error() ? socket
->LastError() : 0);
104 // Nothing should arrive here...
111 // There can be only one. :)
113 static CClientTCPSocketHandler g_clientReqSocketHandler
;
116 //------------------------------------------------------------------------------
118 //------------------------------------------------------------------------------
120 CClientTCPSocket::CClientTCPSocket(CUpDownClient
* in_client
, const CProxyData
*ProxyData
)
121 : CEMSocket(ProxyData
)
123 SetClient(in_client
);
125 m_remoteip
= wxUINT32_SWAP_ALWAYS(in_client
->GetUserIDHybrid());
131 m_ForDeletion
= false;
133 SetEventHandler(g_clientReqSocketHandler
, ID_CLIENTTCPSOCKET_EVENT
);
135 wxSOCKET_CONNECTION_FLAG
|
136 wxSOCKET_INPUT_FLAG
|
137 wxSOCKET_OUTPUT_FLAG
|
141 theApp
->listensocket
->AddSocket(this);
142 theApp
->listensocket
->AddConnection();
145 CClientTCPSocket::~CClientTCPSocket()
147 // remove event handler
152 m_client
->SetSocket( NULL
);
156 if (theApp
->listensocket
&& !theApp
->listensocket
->OnShutdown()) {
157 theApp
->listensocket
->RemoveSocket(this);
161 bool CClientTCPSocket::InitNetworkData()
163 wxASSERT(!m_remoteip
);
165 amuleIPV4Address addr
;
167 m_remoteip
= StringIPtoUint32(addr
.IPAddress());
169 MULE_CHECK(m_remoteip
, false);
171 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
172 AddDebugLogLineM(false, logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Filtered IP)"));
174 } else if (theApp
->clientlist
->IsBannedClient(m_remoteip
)) {
175 AddDebugLogLineM(false, logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Banned IP)"));
178 AddDebugLogLineM(false, logClient
, wxT("Accepted connection from ") + addr
.IPAddress());
183 void CClientTCPSocket::ResetTimeOutTimer()
185 timeout_timer
= ::GetTickCount();
189 bool CClientTCPSocket::CheckTimeOut()
192 uint32 uTimeout
= GetTimeOut();
195 if (m_client
->GetKadState() == KS_CONNECTED_BUDDY
) {
196 //We originally ignored the timeout here for buddies.
197 //This was a stupid idea on my part. There is now a ping/pong system
198 //for buddies. This ping/pong system now prevents timeouts.
199 //This release will allow lowID clients with KadVersion 0 to remain connected.
200 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
201 //JOHNTODO: Don't forget to remove backward support in a future release.
202 if ( m_client
->GetKadVersion() == 0 ) {
206 uTimeout
+= MIN2MS(15);
209 if (m_client
->GetChatState() != MS_NONE
) {
210 uTimeout
+= CONNECTION_TIMEOUT
;
214 if (::GetTickCount() - timeout_timer
> uTimeout
){
215 timeout_timer
= ::GetTickCount();
216 Disconnect(wxT("Timeout"));
224 void CClientTCPSocket::SetClient(CUpDownClient
* pClient
)
228 m_client
->SetSocket( this );
233 void CClientTCPSocket::OnClose(int nErrorCode
)
236 wxASSERT(theApp
->listensocket
->IsValidSocket(this));
237 CEMSocket::OnClose(nErrorCode
);
239 Disconnect(wxString::Format(wxT("Closed: %u"), nErrorCode
));
241 Disconnect(wxT("Close"));
246 void CClientTCPSocket::Disconnect(const wxString
& strReason
)
248 byConnected
= ES_DISCONNECTED
;
250 if (m_client
->Disconnected(strReason
, true)) {
251 // Somehow, Safe_Delete() is beeing called by Disconnected(),
252 // or any other function that sets m_client to NULL,
253 // so we must check m_client first.
255 m_client
->SetSocket( NULL
);
256 m_client
->Safe_Delete();
266 void CClientTCPSocket::Safe_Delete()
268 if ( !ForDeletion() && !OnDestroy() ) {
272 // lfroen: first of all - stop handler
273 m_ForDeletion
= true;
276 m_client
->SetSocket( NULL
);
280 byConnected
= ES_DISCONNECTED
;
281 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
287 bool CClientTCPSocket::ProcessPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
289 #ifdef __PACKET_RECV_DUMP__
290 //printf("Rec: OPCODE %x \n",opcode);
291 DumpMem(buffer
, size
);
293 if (!m_client
&& opcode
!= OP_HELLO
) {
294 throw wxString(wxT("Asks for something without saying hello"));
295 } else if (m_client
&& opcode
!= OP_HELLO
&& opcode
!= OP_HELLOANSWER
) {
296 m_client
->CheckHandshakeFinished(OP_EDONKEYPROT
, opcode
);
300 case OP_HELLOANSWER
: { // 0.43b
301 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HELLOANSWER from ") + m_client
->GetFullIP());
302 theStats::AddDownOverheadOther(size
);
303 m_client
->ProcessHelloAnswer(buffer
, size
);
305 // start secure identification, if
306 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
307 // - we have received eMule-OP_HELLOANSWER (new eMule)
308 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
309 m_client
->InfoPacketsReceived();
312 // Socket might die because of sending in InfoPacketsReceived, so check
314 m_client
->ConnectionEstablished();
317 // Socket might die on ConnectionEstablished somehow. Check it.
319 Notify_UploadCtrlRefreshClient( m_client
);
324 case OP_HELLO
: { // 0.43b
326 theStats::AddDownOverheadOther(size
);
327 bool bNewClient
= !m_client
;
329 // create new client to save standart informations
330 m_client
= new CUpDownClient(this);
334 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HELLO from ") + m_client
->GetFullIP() );
336 bool bIsMuleHello
= false;
339 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
341 if (bNewClient
&& m_client
) {
342 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
343 m_client
->Safe_Delete();
349 if (thePrefs::ParanoidFilter() && !IsLowID(m_client
->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid()))) {
350 wxString reason
= wxT("Client claims a different IP from the one we received the hello packet from: ");
351 reason
+= Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
352 AddDebugLogLineM(false, logClient
, reason
);
354 m_client
->Safe_Delete();
357 Disconnect(wxT("Paranoid disconecting: ") + reason
);
361 // if IP is filtered, dont reply but disconnect...
362 if (theApp
->ipfilter
->IsFiltered(m_client
->GetIP())) {
364 m_client
->Safe_Delete();
367 Disconnect(wxT("IPFilter"));
373 // now we check if we now this client already. if yes this socket will
374 // be attached to the known client, the new client will be deleted
375 // and the var. "client" will point to the known client.
376 // if not we keep our new-constructed client ;)
377 if (theApp
->clientlist
->AttachToAlreadyKnown(&m_client
,this)) {
378 // update the old client informations
379 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
381 theApp
->clientlist
->AddClient(m_client
);
382 m_client
->SetCommentDirty();
384 Notify_UploadCtrlRefreshClient( m_client
);
385 // send a response packet with standart informations
386 if ((m_client
->GetHashType() == SO_EMULE
) && !bIsMuleHello
) {
387 m_client
->SendMuleInfoPacket(false);
390 // Client might die from Sending in SendMuleInfoPacket, so check
392 m_client
->SendHelloAnswer();
395 // Kry - If the other side supports it, send OS_INFO
396 // Client might die from Sending in SendHelloAnswer, so check
397 if (m_client
&& m_client
->GetOSInfoSupport()) {
398 m_client
->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
401 // Client might die from Sending in SendMuleInfoPacket, so check
403 m_client
->ConnectionEstablished();
406 // start secure identification, if
407 // - we have received eMule-OP_HELLO (new eMule)
408 if (m_client
&& m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
409 m_client
->InfoPacketsReceived();
414 case OP_REQUESTFILENAME
: { // 0.43b
415 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client
->GetFullIP() );
417 theStats::AddDownOverheadFileRequest(size
);
418 // IP banned, no answer for this request
419 if (m_client
->IsBanned()) {
423 if (!m_client
->GetWaitStartTime()) {
424 m_client
->SetWaitStartTime();
426 CMemFile
data_in(buffer
, size
);
427 CMD4Hash reqfilehash
= data_in
.ReadHash();
428 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
429 if ( reqfile
== NULL
) {
430 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
431 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
435 // if we are downloading this file, this could be a new source
436 // no passive adding of files with only one part
437 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
438 if (thePrefs::GetMaxSourcePerFile() >
439 ((CPartFile
*)reqfile
)->GetSourceCount()) {
440 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
444 // check to see if this is a new file they are asking for
445 if (m_client
->GetUploadFileID() != reqfilehash
) {
446 m_client
->SetCommentDirty();
449 m_client
->SetUploadFileID(reqfile
);
450 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
453 CMemFile
data_out(128);
454 data_out
.WriteHash(reqfile
->GetFileHash());
456 // Since it's for somebody else to see, we need to send the prettified
457 // filename, rather than the (possibly) mangled actual filename.
458 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
460 CPacket
* packet
= new CPacket(data_out
, OP_EDONKEYPROT
, OP_REQFILENAMEANSWER
);
461 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
462 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client
->GetFullIP() );
463 SendPacket(packet
,true);
465 // SendPacket might kill the socket, so check
467 m_client
->SendCommentInfo(reqfile
);
471 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
474 case OP_SETREQFILEID
: { // 0.43b EXCEPT track of bad clients
475 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SETREQFILEID from ") + m_client
->GetFullIP() );
477 theStats::AddDownOverheadFileRequest(size
);
479 if (m_client
->IsBanned()) {
485 if (!m_client
->GetWaitStartTime()) {
486 m_client
->SetWaitStartTime();
489 const CMD4Hash
fileID(buffer
);
490 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
491 if ( reqfile
== NULL
) {
492 reqfile
= theApp
->downloadqueue
->GetFileByID(fileID
);
493 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
494 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
495 replypacket
->Copy16ToDataBuffer(fileID
.GetHash());
496 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
497 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILERE to ") + m_client
->GetFullIP() );
498 SendPacket(replypacket
, true);
503 // check to see if this is a new file they are asking for
504 if (m_client
->GetUploadFileID() != fileID
) {
505 m_client
->SetCommentDirty();
508 m_client
->SetUploadFileID(reqfile
);
510 CMemFile
data(16+16);
511 data
.WriteHash(reqfile
->GetFileHash());
512 if (reqfile
->IsPartFile()) {
513 ((CPartFile
*)reqfile
)->WritePartStatus(&data
);
517 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_FILESTATUS
);
518 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
519 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILESTATUS to ") + m_client
->GetFullIP() );
520 SendPacket(packet
, true);
523 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
528 case OP_FILEREQANSNOFIL
: { // 0.43b protocol, lacks ZZ's download manager on swap
529 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client
->GetFullIP() );
531 theStats::AddDownOverheadFileRequest(size
);
533 // if that client does not have my file maybe has another different
534 CPartFile
* reqfile
= theApp
->downloadqueue
->GetFileByID(CMD4Hash(buffer
));
536 reqfile
->AddDeadSource( m_client
);
541 // we try to swap to another file ignoring no needed parts files
542 switch (m_client
->GetDownloadState()) {
545 case DS_NONEEDEDPARTS
:
546 if (!m_client
->SwapToAnotherFile(true, true, true, NULL
)) {
547 theApp
->downloadqueue
->RemoveSource(m_client
);
553 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
557 case OP_REQFILENAMEANSWER
: { // 0.43b except check for bad clients
558 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client
->GetFullIP() );
560 theStats::AddDownOverheadFileRequest(size
);
561 CMemFile
data(buffer
, size
);
562 CMD4Hash hash
= data
.ReadHash();
563 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
564 m_client
->ProcessFileInfo(&data
, file
);
568 case OP_FILESTATUS
: { // 0.43b except check for bad clients
569 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILESTATUS from ") + m_client
->GetFullIP() );
571 theStats::AddDownOverheadFileRequest(size
);
572 CMemFile
data(buffer
, size
);
573 CMD4Hash hash
= data
.ReadHash();
574 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
575 m_client
->ProcessFileStatus(false, &data
, file
);
579 case OP_STARTUPLOADREQ
: {
580 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client
->GetFullIP() );
582 theStats::AddDownOverheadFileRequest(size
);
584 if (!m_client
->CheckHandshakeFinished(OP_EDONKEYPROT
, opcode
)) {
588 m_client
->CheckForAggressive();
589 if ( m_client
->IsBanned() ) {
594 const CMD4Hash
fileID(buffer
);
595 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
597 if (m_client
->GetUploadFileID() != fileID
) {
598 m_client
->SetCommentDirty();
600 m_client
->SetUploadFileID(reqfile
);
601 m_client
->SendCommentInfo(reqfile
);
603 // Socket might die because of SendCommentInfo, so check
605 theApp
->uploadqueue
->AddClientToQueue(m_client
);
611 case OP_QUEUERANK
: { // 0.43b
612 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_QUEUERANK from ") + m_client
->GetFullIP() );
614 theStats::AddDownOverheadFileRequest(size
);
615 CMemFile
data(buffer
, size
);
616 uint32 rank
= data
.ReadUInt32();
618 m_client
->SetRemoteQueueRank(rank
);
622 case OP_ACCEPTUPLOADREQ
: { // 0.42e (xcept khaos stats)
623 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client
->GetFullIP() );
625 theStats::AddDownOverheadFileRequest(size
);
626 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
627 if (m_client
->GetDownloadState() == DS_ONQUEUE
) {
628 m_client
->SetDownloadState(DS_DOWNLOADING
);
629 m_client
->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
630 m_client
->SendBlockRequests();
633 if (!m_client
->GetSentCancelTransfer()) {
634 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
635 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
636 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
637 m_client
->SendPacket(packet
,true,true);
639 // SendPacket can cause the socket to die, so check
641 m_client
->SetSentCancelTransfer(1);
645 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
650 case OP_REQUESTPARTS
: { // 0.43b
651 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
653 theStats::AddDownOverheadFileRequest(size
);
655 m_client
->ProcessRequestPartsPacket(buffer
, size
, false);
660 case OP_CANCELTRANSFER
: { // 0.43b
661 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client
->GetFullIP() );
663 theStats::AddDownOverheadFileRequest(size
);
664 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
665 AddDebugLogLineM( false, logClient
, m_client
->GetUserName() + wxT(": Upload session ended due canceled transfer."));
669 case OP_END_OF_DOWNLOAD
: { // 0.43b except check for bad clients
670 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client
->GetFullIP() );
672 theStats::AddDownOverheadFileRequest(size
);
673 if (size
>=16 && m_client
->GetUploadFileID() == CMD4Hash(buffer
)) {
674 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
675 AddDebugLogLineM( false, logClient
, m_client
->GetUserName() + wxT(": Upload session ended due ended transfer."));
680 case OP_HASHSETREQUEST
: { // 0.43b except check for bad clients
681 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client
->GetFullIP() );
684 theStats::AddDownOverheadFileRequest(size
);
686 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
688 m_client
->SendHashsetPacket(CMD4Hash(buffer
));
692 case OP_HASHSETANSWER
: { // 0.43b
693 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client
->GetFullIP() );
695 theStats::AddDownOverheadFileRequest(size
);
696 m_client
->ProcessHashSet(buffer
, size
);
700 case OP_SENDINGPART
: { // 0.47a
701 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SENDINGPART from ") + m_client
->GetFullIP() );
703 if ( m_client
->GetRequestFile() &&
704 !m_client
->GetRequestFile()->IsStopped() &&
705 (m_client
->GetRequestFile()->GetStatus() == PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
707 m_client
->ProcessBlockPacket(buffer
, size
, false, false);
710 ( m_client
->GetRequestFile()->IsStopped() ||
711 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
712 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
) ) {
713 if (!m_client
->GetSentCancelTransfer()) {
714 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
715 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
716 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
717 m_client
->SendPacket(packet
,true,true);
719 // Socket might die because of SendPacket, so check
721 m_client
->SetSentCancelTransfer(1);
725 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
728 if (!m_client
->GetSentCancelTransfer()) {
729 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
730 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
731 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
732 m_client
->SendPacket(packet
,true,true);
734 // Socket might die because of SendPacket, so check
735 m_client
->SetSentCancelTransfer(1);
737 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
742 case OP_OUTOFPARTREQS
: { // 0.43b
743 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client
->GetFullIP() );
745 theStats::AddDownOverheadFileRequest(size
);
746 if (m_client
->GetDownloadState() == DS_DOWNLOADING
) {
747 m_client
->SetDownloadState(DS_ONQUEUE
);
752 case OP_CHANGE_CLIENT_ID
: { // Kad reviewed
753 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client
->GetFullIP() );
755 theStats::AddDownOverheadOther(size
);
756 CMemFile
data(buffer
, size
);
757 uint32 nNewUserID
= data
.ReadUInt32();
758 uint32 nNewServerIP
= data
.ReadUInt32();
760 if (IsLowID(nNewUserID
)) { // client changed server and gots a LowID
761 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
762 if (pNewServer
!= NULL
){
763 m_client
->SetUserIDHybrid(nNewUserID
); // update UserID only if we know the server
764 m_client
->SetServerIP(nNewServerIP
);
765 m_client
->SetServerPort(pNewServer
->GetPort());
767 } else if (nNewUserID
== m_client
->GetIP()) { // client changed server and gots a HighID(IP)
768 m_client
->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID
));
769 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
770 if (pNewServer
!= NULL
){
771 m_client
->SetServerIP(nNewServerIP
);
772 m_client
->SetServerPort(pNewServer
->GetPort());
779 case OP_CHANGE_SLOT
:{ // 0.43b
780 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client
->GetFullIP() );
782 // sometimes sent by Hybrid
783 theStats::AddDownOverheadOther(size
);
787 case OP_MESSAGE
: { // 0.43b
788 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MESSAGE from ") + m_client
->GetFullIP() );
790 theStats::AddDownOverheadOther(size
);
793 throw wxString(wxT("invalid message packet"));
795 CMemFile
message_file(buffer
, size
);
796 uint16 length
= message_file
.ReadUInt16();
797 if (length
+ 2u != size
) {
798 throw wxString(wxT("invalid message packet"));
801 // limit message length
802 static const uint16 MAX_CLIENT_MSG_LEN
= 450;
804 if (length
> MAX_CLIENT_MSG_LEN
) {
805 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
806 % m_client
->GetUserName() % m_client
->GetFullIP() % (length
- MAX_CLIENT_MSG_LEN
));
807 length
= MAX_CLIENT_MSG_LEN
;
810 wxString message
= message_file
.ReadOnlyString((m_client
->GetUnicodeSupport() != utf8strNone
), length
);
811 m_client
->ProcessChatMessage(message
);
816 case OP_ASKSHAREDFILES
: { // 0.43b (well, er, it does the same, but in our own way)
817 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client
->GetFullIP() );
819 // client wants to know what we have in share, let's see if we allow him to know that
820 theStats::AddDownOverheadOther(size
);
821 // IP banned, no answer for this request
822 if (m_client
->IsBanned()) {
826 if (thePrefs::CanSeeShares() == vsfaEverybody
|| (thePrefs::CanSeeShares() == vsfaFriends
&& m_client
->IsFriend())) {
827 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
828 % m_client
->GetUserName()
829 % m_client
->GetUserIDHybrid() );
831 std::vector
<CKnownFile
*> list
;
832 theApp
->sharedfiles
->CopyFileList(list
);
834 CMemFile
tempfile(80);
835 tempfile
.WriteUInt32(list
.size());
836 for (unsigned i
= 0; i
< list
.size(); ++i
) {
837 if (!list
[i
]->IsLargeFile() || m_client
->SupportsLargeFiles()) {
838 theApp
->sharedfiles
->CreateOfferedFilePacket(list
[i
], &tempfile
, NULL
, m_client
);
842 // create a packet and send it
843 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESANSWER
);
844 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client
->GetFullIP() );
845 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
846 SendPacket(replypacket
, true, true);
848 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
849 % m_client
->GetUserName()
850 % m_client
->GetUserIDHybrid() );
852 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
853 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
854 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
855 SendPacket(replypacket
, true, true);
861 case OP_ASKSHAREDFILESANSWER
: { // 0.43b
862 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client
->GetFullIP() );
864 theStats::AddDownOverheadOther(size
);
866 m_client
->ProcessSharedFileList(buffer
, size
, EmptyStr
);
870 case OP_ASKSHAREDDIRS
: { // 0.43b
871 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client
->GetFullIP() );
873 theStats::AddDownOverheadOther(size
);
874 wxASSERT( size
== 0 );
875 // IP banned, no answer for this request
876 if (m_client
->IsBanned()) {
879 if ((thePrefs::CanSeeShares()==vsfaEverybody
) || ((thePrefs::CanSeeShares()==vsfaFriends
) && m_client
->IsFriend())) {
880 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
881 % m_client
->GetUserName()
882 % m_client
->GetUserIDHybrid() );
884 // This list will contain all (unique) folders.
885 std::list
<CPath
> foldersToSend
;
887 // The shared folders
888 const unsigned folderCount
= theApp
->glob_prefs
->shareddir_list
.size();
889 for (unsigned i
= 0; i
< folderCount
; ++i
) {
890 foldersToSend
.push_back(theApp
->glob_prefs
->shareddir_list
[i
]);
893 // ... the categories folders ... (category 0 -> incoming)
894 for (unsigned i
= 0; i
< theApp
->glob_prefs
->GetCatCount(); ++i
) {
895 foldersToSend
.push_back(theApp
->glob_prefs
->GetCategory(i
)->path
);
898 // ... and the Magic thing from the eDonkey Hybrids...
899 foldersToSend
.push_back(CPath(OP_INCOMPLETE_SHARED_FILES
));
902 foldersToSend
.sort();
903 foldersToSend
.unique();
906 CMemFile
tempfile(80);
907 tempfile
.WriteUInt32(foldersToSend
.size());
909 std::list
<CPath
>::iterator it
= foldersToSend
.begin();
910 for (; it
!= foldersToSend
.end(); ++it
) {
911 // We need to send the 'raw' filename, so we can recognize it again.
912 tempfile
.WriteString(it
->GetRaw(), m_client
->GetUnicodeSupport());
915 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDDIRSANS
);
916 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
917 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client
->GetFullIP() );
918 SendPacket(replypacket
, true, true);
920 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
921 % m_client
->GetUserName()
922 % m_client
->GetUserIDHybrid() );
924 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
925 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
926 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
927 SendPacket(replypacket
, true, true);
933 case OP_ASKSHAREDFILESDIR
: { // 0.43b
934 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client
->GetFullIP() );
936 theStats::AddDownOverheadOther(size
);
937 // IP banned, no answer for this request
938 if (m_client
->IsBanned()) {
941 CMemFile
data(buffer
, size
);
943 wxString strReqDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
944 if (thePrefs::CanSeeShares()==vsfaEverybody
|| (thePrefs::CanSeeShares()==vsfaFriends
&& m_client
->IsFriend())) {
945 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
946 wxASSERT( data
.GetPosition() == data
.GetLength() );
948 CKnownFilePtrList list
;
950 if (strReqDir
== OP_INCOMPLETE_SHARED_FILES
) {
951 // get all shared files from download queue
952 int iQueuedFiles
= theApp
->downloadqueue
->GetFileCount();
953 for (int i
= 0; i
< iQueuedFiles
; i
++) {
954 CPartFile
* pFile
= theApp
->downloadqueue
->GetFileByIndex(i
);
955 if (pFile
== NULL
|| pFile
->GetStatus(true) != PS_READY
) {
959 list
.push_back(pFile
);
962 theApp
->sharedfiles
->GetSharedFilesByDirectory(strReqDir
, list
);
965 CMemFile
tempfile(80);
966 tempfile
.WriteString(strReqDir
, m_client
->GetUnicodeSupport());
967 tempfile
.WriteUInt32(list
.size());
969 while (!list
.empty()) {
970 if (!list
.front()->IsLargeFile() || m_client
->SupportsLargeFiles()) {
971 theApp
->sharedfiles
->CreateOfferedFilePacket(list
.front(), &tempfile
, NULL
, m_client
);
977 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIRANS
);
978 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
979 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client
->GetFullIP() );
980 SendPacket(replypacket
, true, true);
982 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
984 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
985 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
986 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
987 SendPacket(replypacket
, true, true);
992 case OP_ASKSHAREDDIRSANS
:{ // 0.43b
993 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client
->GetFullIP() );
995 theStats::AddDownOverheadOther(size
);
996 if (m_client
->GetFileListRequested() == 1){
997 CMemFile
data(buffer
, size
);
998 uint32 uDirs
= data
.ReadUInt32();
999 for (uint32 i
= 0; i
< uDirs
; i
++){
1000 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
1001 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
1002 % m_client
->GetUserName()
1003 % m_client
->GetUserIDHybrid()
1006 CMemFile
tempfile(80);
1007 tempfile
.WriteString(strDir
, m_client
->GetUnicodeSupport());
1008 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIR
);
1009 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
1010 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client
->GetFullIP() );
1011 SendPacket(replypacket
, true, true);
1013 wxASSERT( data
.GetPosition() == data
.GetLength() );
1014 m_client
->SetFileListRequested(uDirs
);
1016 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1017 % m_client
->GetUserName()
1018 % m_client
->GetUserIDHybrid() );
1023 case OP_ASKSHAREDFILESDIRANS
: { // 0.43b
1024 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client
->GetFullIP() );
1026 theStats::AddDownOverheadOther(size
);
1027 CMemFile
data(buffer
, size
);
1028 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
1030 if (m_client
->GetFileListRequested() > 0){
1031 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1032 % m_client
->GetUserName()
1033 % m_client
->GetUserIDHybrid()
1036 m_client
->ProcessSharedFileList(buffer
+ data
.GetPosition(), size
- data
.GetPosition(), strDir
);
1037 if (m_client
->GetFileListRequested() == 0) {
1038 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1039 % m_client
->GetUserName()
1040 % m_client
->GetUserIDHybrid() );
1043 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1044 % m_client
->GetUserName()
1045 % m_client
->GetUserIDHybrid() );
1050 case OP_ASKSHAREDDENIEDANS
:
1051 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client
->GetFullIP() );
1053 theStats::AddDownOverheadOther(size
);
1054 wxASSERT( size
== 0 );
1055 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1056 % m_client
->GetUserName()
1057 % m_client
->GetUserIDHybrid() );
1059 m_client
->SetFileListRequested(0);
1063 theStats::AddDownOverheadOther(size
);
1064 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode
, opcode
) + m_client
->GetFullIP());
1072 bool CClientTCPSocket::ProcessExtPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
1074 #ifdef __PACKET_RECV_DUMP__
1075 //printf("Rec: OPCODE %x \n",opcode);
1076 DumpMem(buffer
,size
);
1079 // 0.42e - except the catchs on mem exception and file exception
1081 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1084 if (!client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1085 // Here comes a extended packet without finishing the hanshake.
1086 // IMHO, we should disconnect the client.
1087 throw wxString(wxT("Client send extended packet before finishing handshake"));
1091 case OP_MULTIPACKET_EXT
:
1092 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client
->GetFullIP());
1093 case OP_MULTIPACKET
: {
1094 if (opcode
== OP_MULTIPACKET
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET from ") + m_client
->GetFullIP() );
1096 theStats::AddDownOverheadFileRequest(size
);
1098 if (m_client
->IsBanned()) {
1102 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1103 // Here comes a extended packet without finishing the hanshake.
1104 // IMHO, we should disconnect the client.
1105 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1108 CMemFile
data_in(buffer
, size
);
1109 CMD4Hash reqfilehash
= data_in
.ReadHash();
1110 uint64 nSize
= (opcode
== OP_MULTIPACKET_EXT
) ? data_in
.ReadUInt64() : 0;
1112 bool file_not_found
= false;
1113 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
1114 if ( reqfile
== NULL
){
1115 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1116 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
1117 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a non-shared file"));
1118 file_not_found
= true;
1122 if (!file_not_found
&& reqfile
->IsLargeFile() && !m_client
->SupportsLargeFiles()) {
1123 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a large file but doesn't support them"));
1124 file_not_found
= true;
1127 if (!file_not_found
&& nSize
&& (reqfile
->GetFileSize() != nSize
)) {
1128 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a file but specified wrong size"));
1129 file_not_found
= true;
1132 if (file_not_found
) {
1133 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
1134 replypacket
->Copy16ToDataBuffer(reqfilehash
.GetHash());
1135 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
1136 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client
->GetFullIP() );
1137 SendPacket(replypacket
, true);
1141 if (!m_client
->GetWaitStartTime()) {
1142 m_client
->SetWaitStartTime();
1144 // if we are downloading this file, this could be a new source
1145 // no passive adding of files with only one part
1146 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
1147 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile
*)reqfile
)->GetSourceCount()) {
1148 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
1151 // check to see if this is a new file they are asking for
1152 if (m_client
->GetUploadFileID() != reqfilehash
) {
1153 m_client
->SetCommentDirty();
1155 m_client
->SetUploadFileID(reqfile
);
1156 CMemFile
data_out(128);
1157 data_out
.WriteHash(reqfile
->GetFileHash());
1158 while(data_in
.GetLength()-data_in
.GetPosition()) {
1160 throw wxString(wxT("Client suddenly disconnected"));
1162 uint8 opcode_in
= data_in
.ReadUInt8();
1164 case OP_REQUESTFILENAME
: {
1165 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1166 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
1167 data_out
.WriteUInt8(OP_REQFILENAMEANSWER
);
1169 // Since it's for somebody else to see, we need to send the prettified
1170 // filename, rather than the (possibly) mangled actual filename
1171 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
1174 case OP_AICHFILEHASHREQ
: {
1175 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1176 if (m_client
->IsSupportingAICH() && reqfile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1177 && reqfile
->GetAICHHashset()->HasValidMasterHash())
1179 data_out
.WriteUInt8(OP_AICHFILEHASHANS
);
1180 reqfile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1184 case OP_SETREQFILEID
: {
1185 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1186 data_out
.WriteUInt8(OP_FILESTATUS
);
1187 if (reqfile
->IsPartFile()) {
1188 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1190 data_out
.WriteUInt16(0);
1194 //We still send the source packet separately..
1195 //We could send it within this packet.. If agreeded, I will fix it..
1196 case OP_REQUESTSOURCES2
:
1197 case OP_REQUESTSOURCES
: {
1198 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1199 uint8 byRequestedVersion
= 0;
1200 uint16 byRequestedOptions
= 0;
1201 if (opcode_in
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1202 byRequestedVersion
= data_in
.ReadUInt8();
1203 byRequestedOptions
= data_in
.ReadUInt16();
1206 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1208 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() > 1) {
1209 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1210 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1212 //if not complete and file is rare
1213 ( reqfile
->IsPartFile()
1214 && (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1215 && ((CPartFile
*)reqfile
)->GetSourceCount() <= RARE_FILE
1217 //OR if file is not rare or if file is complete
1218 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1221 m_client
->SetLastSrcReqTime();
1222 CPacket
* tosend
= reqfile
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1224 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1225 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1226 SendPacket(tosend
, true);
1235 if( data_out
.GetLength() > 16 ) {
1236 CPacket
* reply
= new CPacket(data_out
, OP_EMULEPROT
, OP_MULTIPACKETANSWER
);
1237 theStats::AddUpOverheadFileRequest(reply
->GetPacketSize());
1238 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client
->GetFullIP() );
1239 SendPacket(reply
, true);
1244 case OP_MULTIPACKETANSWER
: { // 0.43b
1245 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client
->GetFullIP() );
1247 theStats::AddDownOverheadFileRequest(size
);
1249 if (m_client
->IsBanned()) {
1253 if( m_client
->GetKadPort() ) {
1254 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client
->GetIP()), m_client
->GetKadPort(), m_client
->GetKadVersion() > 1);
1257 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1258 // Here comes a extended packet without finishing the hanshake.
1259 // IMHO, we should disconnect the client.
1260 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1263 CMemFile
data_in(buffer
, size
);
1264 CMD4Hash reqfilehash
= data_in
.ReadHash();
1265 const CPartFile
*reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1266 //Make sure we are downloading this file.
1268 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1270 if ( !m_client
->GetRequestFile() ) {
1272 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1274 if (reqfile
!= m_client
->GetRequestFile()) {
1275 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1277 while (data_in
.GetLength()-data_in
.GetPosition()) {
1278 // Some of the cases down there can actually send a packet and lose the client
1280 throw wxString(wxT("Client suddenly disconnected"));
1282 uint8 opcode_in
= data_in
.ReadUInt8();
1284 case OP_REQFILENAMEANSWER
: {
1286 throw wxString(wxT("Client suddenly disconnected"));
1288 m_client
->ProcessFileInfo(&data_in
, reqfile
);
1292 case OP_FILESTATUS
: {
1294 throw wxString(wxT("Client suddenly disconnected"));
1296 m_client
->ProcessFileStatus(false, &data_in
, reqfile
);
1300 case OP_AICHFILEHASHANS
: {
1302 throw wxString(wxT("Client suddenly disconnected"));
1304 m_client
->ProcessAICHFileHash(&data_in
, reqfile
);
1314 case OP_EMULEINFO
: { // 0.43b
1315 theStats::AddDownOverheadOther(size
);
1317 if (!m_client
->ProcessMuleInfoPacket(buffer
, size
)) {
1318 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFO from ") + m_client
->GetFullIP() );
1320 // If it's not a OS Info packet, is an old client
1321 // start secure identification, if
1322 // - we have received eD2K and eMule info (old eMule)
1323 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1324 m_client
->InfoPacketsReceived();
1326 m_client
->SendMuleInfoPacket(true);
1328 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1332 case OP_EMULEINFOANSWER
: { // 0.43b
1333 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client
->GetFullIP() );
1334 theStats::AddDownOverheadOther(size
);
1336 m_client
->ProcessMuleInfoPacket(buffer
, size
);
1337 // start secure identification, if
1338 // - we have received eD2K and eMule info (old eMule)
1340 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1341 m_client
->InfoPacketsReceived();
1347 case OP_SECIDENTSTATE
:{ // 0.43b
1348 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client
->GetFullIP() );
1350 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1351 // Here comes a extended packet without finishing the hanshake.
1352 // IMHO, we should disconnect the client.
1353 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1355 m_client
->ProcessSecIdentStatePacket(buffer
, size
);
1356 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1358 int SecureIdentState
= m_client
->GetSecureIdentState();
1359 if (SecureIdentState
== IS_SIGNATURENEEDED
) {
1360 m_client
->SendSignaturePacket();
1361 } else if (SecureIdentState
== IS_KEYANDSIGNEEDED
) {
1362 m_client
->SendPublicKeyPacket();
1363 // SendPublicKeyPacket() might cause the socket to die, so check
1365 m_client
->SendSignaturePacket();
1372 case OP_PUBLICKEY
: { // 0.43b
1373 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICKEY from ") + m_client
->GetFullIP() );
1375 if (m_client
->IsBanned() ){
1379 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1380 // Here comes a extended packet without finishing the hanshake.
1381 // IMHO, we should disconnect the client.
1382 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1385 m_client
->ProcessPublicKeyPacket(buffer
, size
);
1388 case OP_SIGNATURE
:{ // 0.43b
1389 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SIGNATURE from ") + m_client
->GetFullIP() );
1391 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1392 // Here comes a extended packet without finishing the hanshake.
1393 // IMHO, we should disconnect the client.
1394 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1397 m_client
->ProcessSignaturePacket(buffer
, size
);
1400 case OP_SENDINGPART_I64
:
1401 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client
->GetFullIP() );
1402 case OP_COMPRESSEDPART_I64
:
1403 if (opcode
== OP_COMPRESSEDPART_I64
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client
->GetFullIP() );
1404 case OP_COMPRESSEDPART
: { // 0.47a
1405 if (opcode
== OP_COMPRESSEDPART
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client
->GetFullIP() );
1407 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1408 // Here comes a extended packet without finishing the hanshake.
1409 // IMHO, we should disconnect the client.
1410 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1413 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
1415 m_client
->ProcessBlockPacket(buffer
, size
, (opcode
!= OP_SENDINGPART_I64
), (opcode
== OP_COMPRESSEDPART_I64
) || (opcode
== OP_SENDINGPART_I64
));
1418 m_client
->GetRequestFile()->IsStopped() ||
1419 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
1420 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
)) {
1421 if (!m_client
->GetSentCancelTransfer()) {
1422 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1423 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1424 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1425 m_client
->SendPacket(packet
,true,true);
1428 m_client
->SetSentCancelTransfer(1);
1433 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
1437 if (!m_client
->GetSentCancelTransfer()) {
1438 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1439 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1440 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1441 m_client
->SendPacket(packet
,true,true);
1444 m_client
->SetSentCancelTransfer(1);
1449 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
1454 case OP_REQUESTPARTS_I64
: {
1455 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client
->GetFullIP() );
1457 theStats::AddDownOverheadFileRequest(size
);
1459 m_client
->ProcessRequestPartsPacket(buffer
, size
, true);
1463 case OP_QUEUERANKING
: { // 0.43b
1464 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_QUEUERANKING from ") + m_client
->GetFullIP() );
1466 theStats::AddDownOverheadOther(size
);
1468 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1469 // Here comes a extended packet without finishing the hanshake.
1470 // IMHO, we should disconnect the client.
1471 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1475 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1478 uint16 newrank
= PeekUInt16(buffer
);
1479 m_client
->SetRemoteQueueFull(false);
1480 m_client
->SetRemoteQueueRank(newrank
);
1483 case OP_REQUESTSOURCES2
:
1484 case OP_REQUESTSOURCES
:{
1485 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client
->GetFullIP() );
1487 theStats::AddDownOverheadSourceExchange(size
);
1489 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1490 // Here comes an extended packet without finishing the handshake.
1491 // IMHO, we should disconnect the client.
1492 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1495 uint8 byRequestedVersion
= 0;
1496 uint16 byRequestedOptions
= 0;
1497 CMemFile
data_in(buffer
, size
);
1498 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1499 byRequestedVersion
= data_in
.ReadUInt8();
1500 byRequestedOptions
= data_in
.ReadUInt16();
1503 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() >= 1) {
1505 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1507 //first check shared file list, then download list
1508 const CMD4Hash
fileID(buffer
);
1509 CKnownFile
* file
= theApp
->sharedfiles
->GetFileByID(fileID
);
1511 file
= theApp
->downloadqueue
->GetFileByID(fileID
);
1514 // There are some clients which do not follow the correct protocol procedure of sending
1515 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1516 // are doing this, they will not get the optimal set of sources which we could offer if
1517 // they would follow the above noted protocol sequence. They better do it the right way
1518 // or they will get just a random set of sources because we do not know their download
1519 // part status which may get cleared with the call of 'SetUploadFileID'.
1520 m_client
->SetUploadFileID(file
);
1522 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1523 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1525 //if not complete and file is rare, allow once every 40 minutes
1526 ( file
->IsPartFile() &&
1527 ((CPartFile
*)file
)->GetSourceCount() <= RARE_FILE
&&
1528 (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1530 //OR if file is not rare or if file is complete, allow every 90 minutes
1531 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1534 m_client
->SetLastSrcReqTime();
1535 CPacket
* tosend
= file
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1537 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1538 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1539 SendPacket(tosend
, true, true);
1546 case OP_ANSWERSOURCES
: {
1547 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client
->GetFullIP() );
1549 theStats::AddDownOverheadSourceExchange(size
);
1551 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1552 // Here comes a extended packet without finishing the hanshake.
1553 // IMHO, we should disconnect the client.
1554 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1557 CMemFile
data(buffer
, size
);
1558 CMD4Hash hash
= data
.ReadHash();
1559 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1561 if (file
->IsPartFile()){
1562 //set the client's answer time
1563 m_client
->SetLastSrcAnswerTime();
1564 //and set the file's last answer time
1565 ((CPartFile
*)file
)->SetLastAnsweredTime();
1567 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, m_client
->GetSourceExchange1Version(), false, m_client
);
1572 case OP_ANSWERSOURCES2
: {
1573 //printf("Received OP_ANSWERSOURCES2\n");
1574 theStats::AddDownOverheadSourceExchange(size
);
1576 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1577 // Here comes a extended packet without finishing the hanshake.
1578 // IMHO, we should disconnect the client.
1579 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1582 CMemFile
data(buffer
, size
);
1583 uint8 byVersion
= data
.ReadUInt8();
1584 CMD4Hash hash
= data
.ReadHash();
1585 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1587 if (file
->IsPartFile()){
1588 //set the client's answer time
1589 m_client
->SetLastSrcAnswerTime();
1590 //and set the file's last answer time
1591 ((CPartFile
*)file
)->SetLastAnsweredTime();
1592 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, byVersion
, true, m_client
);
1597 case OP_FILEDESC
: { // 0.43b
1598 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILEDESC from ") + m_client
->GetFullIP() );
1600 theStats::AddDownOverheadFileRequest(size
);
1602 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1603 // Here comes a extended packet without finishing the hanshake.
1604 // IMHO, we should disconnect the client.
1605 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1608 m_client
->ProcessMuleCommentPacket(buffer
, size
);
1613 case OP_REQUESTPREVIEW
: {
1614 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client
->GetFullIP() );
1618 case OP_PREVIEWANSWER
: {
1619 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client
->GetFullIP() );
1623 case OP_PUBLICIP_ANSWER
: {
1624 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client
->GetFullIP() );
1625 theStats::AddDownOverheadOther(size
);
1626 m_client
->ProcessPublicIPAnswer(buffer
, size
);
1629 case OP_PUBLICIP_REQ
: {
1630 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client
->GetFullIP() );
1631 theStats::AddDownOverheadOther(size
);
1632 CPacket
* pPacket
= new CPacket(OP_PUBLICIP_ANSWER
, 4, OP_EMULEPROT
);
1633 pPacket
->CopyUInt32ToDataBuffer(m_client
->GetIP());
1634 theStats::AddUpOverheadOther(pPacket
->GetPacketSize());
1635 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client
->GetFullIP());
1636 SendPacket(pPacket
);
1639 case OP_AICHANSWER
: {
1640 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHANSWER from ") + m_client
->GetFullIP() );
1641 theStats::AddDownOverheadOther(size
);
1642 m_client
->ProcessAICHAnswer(buffer
, size
);
1645 case OP_AICHREQUEST
: {
1646 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHREQUEST from ") + m_client
->GetFullIP() );
1647 theStats::AddDownOverheadOther(size
);
1648 m_client
->ProcessAICHRequest(buffer
, size
);
1651 case OP_AICHFILEHASHANS
: {
1652 // those should not be received normally, since we should only get those in MULTIPACKET
1653 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client
->GetFullIP() );
1654 theStats::AddDownOverheadOther(size
);
1655 CMemFile
data(buffer
, size
);
1656 m_client
->ProcessAICHFileHash(&data
, NULL
);
1659 case OP_AICHFILEHASHREQ
: {
1660 // those should not be received normally, since we should only get those in MULTIPACKET
1661 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client
->GetFullIP() );
1662 CMemFile
data(buffer
, size
);
1663 CMD4Hash hash
= data
.ReadHash();
1664 CKnownFile
* pPartFile
= theApp
->sharedfiles
->GetFileByID(hash
);
1665 if (pPartFile
== NULL
){
1669 if (m_client
->IsSupportingAICH() && pPartFile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1670 && pPartFile
->GetAICHHashset()->HasValidMasterHash()) {
1672 data_out
.WriteHash(hash
);
1673 pPartFile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1674 CPacket
* packet
= new CPacket(data_out
, OP_EMULEPROT
, OP_AICHFILEHASHANS
);
1675 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1676 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client
->GetFullIP());
1682 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CALLBACK from ") + m_client
->GetFullIP() );
1683 theStats::AddDownOverheadFileRequest(size
);
1684 if(!Kademlia::CKademlia::IsRunning()) {
1687 CMemFile
data(buffer
, size
);
1688 CUInt128 check
= data
.ReadUInt128();
1689 check
.XOR(Kademlia::CUInt128(true));
1690 if( check
.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1693 CUInt128 fileid
= data
.ReadUInt128();
1695 fileid
.ToByteArray(fileid2
);
1696 const CMD4Hash
fileHash(fileid2
);
1697 if (theApp
->sharedfiles
->GetFileByID(fileHash
) == NULL
) {
1698 if (theApp
->downloadqueue
->GetFileByID(fileHash
) == NULL
) {
1703 uint32 ip
= data
.ReadUInt32();
1704 uint16 tcp
= data
.ReadUInt16();
1705 CUpDownClient
* callback
;
1706 callback
= theApp
->clientlist
->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip
), tcp
);
1707 if( callback
== NULL
) {
1708 //#warning Do we actually have to check friend status here?
1709 callback
= new CUpDownClient(tcp
,ip
,0,0,NULL
,false, false);
1710 theApp
->clientlist
->AddClient(callback
);
1712 callback
->TryToConnect(true);
1716 case OP_BUDDYPING
: {
1717 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_BUDDYPING from ") + m_client
->GetFullIP() );
1718 theStats::AddDownOverheadKad(size
);
1720 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1721 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 || !m_client
->AllowIncomeingBuddyPingPong() ) {
1722 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1726 m_client
->SetLastBuddyPingPongTime();
1727 CPacket
* replypacket
= new CPacket(OP_BUDDYPONG
, 0, OP_EMULEPROT
);
1728 theStats::AddUpOverheadKad(replypacket
->GetPacketSize());
1729 AddDebugLogLineM(false, logLocalClient
,wxT("Local Client: OP_BUDDYPONG to ") + m_client
->GetFullIP());
1730 SendPacket(replypacket
);
1733 case OP_BUDDYPONG
: {
1734 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_BUDDYPONG from ") + m_client
->GetFullIP() );
1735 theStats::AddDownOverheadKad(size
);
1737 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1738 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 ) {
1739 //This pong was not from our buddy or wrong version. Ignore
1742 m_client
->SetLastBuddyPingPongTime();
1743 //All this is for is to reset our socket timeout.
1746 case OP_REASKCALLBACKTCP
: {
1747 theStats::AddDownOverheadFileRequest(size
);
1748 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1749 if (buddy
!= m_client
) {
1750 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() + wxT(" which is not our buddy!") );
1751 //This callback was not from our buddy.. Ignore.
1754 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() );
1755 CMemFile
data_in(buffer
, size
);
1756 uint32 destip
= data_in
.ReadUInt32();
1757 uint16 destport
= data_in
.ReadUInt16();
1758 CMD4Hash hash
= data_in
.ReadHash();
1759 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(hash
);
1761 bool bSenderMultipleIpUnknown
= false;
1762 CUpDownClient
* sender
= theApp
->uploadqueue
->GetWaitingClientByIP_UDP(destip
, destport
, true, &bSenderMultipleIpUnknown
);
1764 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILENOTFOUND to ") + m_client
->GetFullIP() );
1765 CPacket
* response
= new CPacket(OP_FILENOTFOUND
,0,OP_EMULEPROT
);
1766 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1768 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1770 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1776 //Make sure we are still thinking about the same file
1777 if (hash
== sender
->GetUploadFileID()) {
1778 sender
->AddAskedCount();
1779 sender
->SetLastUpRequest();
1780 //I messed up when I first added extended info to UDP
1781 //I should have originally used the entire ProcessExtenedInfo the first time.
1782 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1783 //For now on, we should not have to change anything here if we change
1784 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1785 //Update extended info.
1786 if (sender
->GetUDPVersion() > 3) {
1787 sender
->ProcessExtendedInfo(&data_in
, reqfile
);
1788 } else if (sender
->GetUDPVersion() > 2) {
1789 //Update our complete source counts.
1790 uint16 nCompleteCountLast
= sender
->GetUpCompleteSourcesCount();
1791 uint16 nCompleteCountNew
= data_in
.ReadUInt16();
1792 sender
->SetUpCompleteSourcesCount(nCompleteCountNew
);
1793 if (nCompleteCountLast
!= nCompleteCountNew
) {
1794 reqfile
->UpdatePartsInfo();
1798 CMemFile
data_out(128);
1799 if(sender
->GetUDPVersion() > 3) {
1800 if (reqfile
->IsPartFile()) {
1801 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1803 data_out
.WriteUInt16(0);
1807 data_out
.WriteUInt16(theApp
->uploadqueue
->GetWaitingPosition(sender
));
1808 CPacket
* response
= new CPacket(data_out
, OP_EMULEPROT
, OP_REASKACK
);
1809 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1810 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client UDP: OP_REASKACK to ") + m_client
->GetFullIP() );
1811 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1813 AddDebugLogLineM(false, logListenSocket
, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1816 if (!bSenderMultipleIpUnknown
){
1817 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1818 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_QUEUEFULL to ") + m_client
->GetFullIP() );
1819 CPacket
* response
= new CPacket(OP_QUEUEFULL
,0,OP_EMULEPROT
);
1820 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1821 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1824 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
);
1829 case OP_CHATCAPTCHAREQ
:
1831 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client
->GetFullIP());
1832 theStats::AddDownOverheadOther(size
);
1833 CMemFile
data_in(buffer
, size
);
1834 m_client
->ProcessCaptchaRequest(&data_in
);
1837 case OP_CHATCAPTCHARES
:
1839 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client
->GetFullIP());
1840 theStats::AddDownOverheadOther(size
);
1842 m_client
->ProcessCaptchaReqRes(buffer
[0]);
1846 case OP_FWCHECKUDPREQ
: { // Support required for Kadversion >= 6
1847 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client
->GetFullIP());
1848 theStats::AddDownOverheadOther(size
);
1849 CMemFile
data_in(buffer
, size
);
1850 m_client
->ProcessFirewallCheckUDPRequest(&data_in
);
1853 case OP_KAD_FWTCPCHECK_ACK
: { // Support required for Kadversion >= 7
1854 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client
->GetFullIP());
1855 if (theApp
->clientlist
->IsKadFirewallCheckIP(m_client
->GetIP())) {
1856 if (Kademlia::CKademlia::IsRunning()) {
1857 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1860 AddDebugLogLineM(false, logListenSocket
, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client
->GetFullIP());
1865 theStats::AddDownOverheadOther(size
);
1866 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode
,opcode
) + m_client
->GetFullIP());
1873 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte
* buffer
, uint32 size
, uint8 opcode
)
1875 #ifdef __PACKET_RECV_DUMP__
1876 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1877 DumpMem(buffer
,size
);
1881 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1884 CMemFile
data(buffer
, size
);
1887 case OP_QUEUERANK
: {
1888 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client
->GetFullIP() );
1890 uint8 numtags
= data
.ReadUInt8();
1891 wxASSERT(numtags
== 1);
1893 m_client
->SetRemoteQueueRank(data
.GetIntTagValue());
1895 theStats::AddDownOverheadFileRequest(size
);
1899 case OP_REQUESTPARTS
: {
1900 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
1902 m_client
->ProcessRequestPartsPacketv2(data
);
1904 theStats::AddDownOverheadFileRequest(size
);
1909 theStats::AddDownOverheadOther(size
);
1910 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode
, opcode
) + m_client
->GetFullIP());
1913 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data
.GetPosition(), opcode
, opcode
) + m_client
->GetFullIP());
1920 void CClientTCPSocket::OnConnect(int nErrorCode
)
1923 OnError(nErrorCode
);
1924 } else if (!m_client
) {
1925 // and now? Disconnect? not?
1926 AddDebugLogLineM( false, logClient
, wxT("Couldn't send hello packet (Client deleted!)") );
1927 } else if (!m_client
->SendHelloPacket()) {
1928 // and now? Disconnect? not?
1929 AddDebugLogLineM( false, logClient
, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1931 ResetTimeOutTimer();
1936 void CClientTCPSocket::OnSend(int nErrorCode
)
1938 ResetTimeOutTimer();
1939 CEMSocket::OnSend(nErrorCode
);
1943 void CClientTCPSocket::OnReceive(int nErrorCode
)
1945 ResetTimeOutTimer();
1946 // We might have updated ipfilter
1947 wxASSERT(m_remoteip
);
1949 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
1951 m_client
->Safe_Delete();
1954 AddDebugLogLineM( false, logIPFilter
, wxT("A connected client was dropped by IPFilter on new packet received"));
1956 CEMSocket::OnReceive(nErrorCode
);
1961 void CClientTCPSocket::OnError(int nErrorCode
)
1963 //printf("* Called OnError for %p\n",this);
1964 // 0.42e + Kry changes for handling of socket lost events
1967 if ((nErrorCode
== 0) || (nErrorCode
== 7) || (nErrorCode
== 0xFEFF)) {
1969 if (!m_client
->GetUserName().IsEmpty()) {
1970 strError
= wxT("Client '") + m_client
->GetUserName() + wxT("'");
1972 strError
= wxT("An unnamed client");
1974 strError
+= wxT(" (IP:") + m_client
->GetFullIP() + wxT(") ");
1976 strError
= wxT("A client ");
1978 if (nErrorCode
== 0) {
1979 strError
+= wxT("closed connection.");
1980 } else if (nErrorCode
== 0xFEFF) {
1981 strError
+= wxT(" caused a wxSOCKET_LOST event.");
1983 strError
+= wxT("caused a socket blocking error.");
1986 if (theLogger
.IsEnabled(logClient
) && nErrorCode
!= 107) {
1987 // 0 -> No Error / Disconect
1988 // 107 -> Transport endpoint is not connected
1990 if (!m_client
->GetUserName().IsEmpty()) {
1991 strError
= wxT("OnError: Client '") + m_client
->GetUserName() +
1992 wxT("' (IP:") + m_client
->GetFullIP() +
1993 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode
);
1995 strError
= wxT("OnError: Unknown client (IP:") +
1996 m_client
->GetFullIP() +
1997 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode
);
2000 strError
= wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
2004 strError
= wxT("Error 107 (Transport endpoint is not connected)");
2008 Disconnect(strError
);
2012 bool CClientTCPSocket::PacketReceived(CPacket
* packet
)
2015 bool bResult
= false;
2016 uint32 uRawSize
= packet
->GetPacketSize();
2018 AddDebugLogLineM( false, logRemoteClient
,
2019 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
2020 % packet
->GetProtocol()
2021 % packet
->GetOpCode()
2022 % packet
->GetPacketSize()
2023 % ( m_client
? m_client
->GetFullIP() : wxT("Unknown Client") )
2029 bool process
= true;
2031 if ((packet
->GetProtocol() == OP_PACKEDPROT
) ||
2032 (packet
->GetProtocol() == OP_ED2KV2PACKEDPROT
)) {
2034 if (!packet
->UnPackPacket()) {
2035 AddDebugLogLineM( false, logZLib
, wxT("Failed to decompress client TCP packet."));
2039 AddDebugLogLineM(false, logRemoteClient
,
2040 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
2041 packet
->GetProtocol(),
2042 packet
->GetOpCode(),
2043 packet
->GetPacketSize())
2049 switch (packet
->GetProtocol()) {
2050 case OP_EDONKEYPROT
:
2051 bResult
= ProcessPacket(packet
->GetDataBuffer(),uRawSize
,packet
->GetOpCode());
2054 bResult
= ProcessExtPacket(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2056 case OP_ED2KV2HEADER
:
2057 bResult
= ProcessED2Kv2Packet(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2059 case OP_ED2KV2PACKEDPROT
:
2061 // Packed inside packed?
2065 theStats::AddDownOverheadOther(uRawSize
);
2067 m_client
->SetDownloadState(DS_ERROR
);
2069 Disconnect(wxT("Unknown protocol"));
2074 } catch (const CEOFException
& err
) {
2075 exception
= wxT("EOF exception: ") + err
.what();
2076 } catch (const CInvalidPacket
& err
) {
2077 exception
= wxT("InvalidPacket exception: ") + err
.what();
2078 } catch (const wxString
& error
) {
2079 exception
= wxT("error: ") + (error
.IsEmpty() ? wxString(wxT("Unknown error")) : error
);
2082 if (!exception
.IsEmpty()) {
2083 AddDebugLogLineM( false, logPacketErrors
,
2084 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2086 % packet
->GetProtocol()
2087 % packet
->GetOpCode()
2088 % packet
->GetPacketSize()
2089 % ( m_client
? m_client
->GetClientFullInfo() : wxT("Unknown") )
2093 m_client
->SetDownloadState(DS_ERROR
);
2096 AddDebugLogLineM( false, logClient
,
2097 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2098 % ( m_client
? m_client
->GetUserName() : wxString(wxT("Unknown")) )
2099 % ( m_client
? m_client
->GetFullIP() : wxString(wxT("Unknown")) )
2103 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2110 SocketSentBytes
CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2112 SocketSentBytes returnStatus
= CEMSocket::SendControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2114 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2115 ResetTimeOutTimer();
2118 return returnStatus
;
2122 SocketSentBytes
CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2124 SocketSentBytes returnStatus
= CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2126 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2127 ResetTimeOutTimer();
2130 return returnStatus
;
2134 void CClientTCPSocket::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
, uint32 actualPayloadSize
)
2136 ResetTimeOutTimer();
2137 CEMSocket::SendPacket(packet
,delpacket
,controlpacket
, actualPayloadSize
);
2139 // File_checked_for_headers