2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "ClientTCPSocket.h" // Interface declarations
28 #include <protocol/Protocols.h>
29 #include <protocol/ed2k/Client2Client/TCP.h>
30 #include <protocol/ed2k/Client2Client/UDP.h> // Sometimes we reply with UDP packets.
31 #include <protocol/ed2k/ClientSoftware.h>
32 #include <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() {
162 wxASSERT(!m_remoteip
);
164 amuleIPV4Address addr
;
166 m_remoteip
= StringIPtoUint32(addr
.IPAddress());
168 MULE_CHECK(m_remoteip
, false);
170 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
171 AddDebugLogLineM(false, logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Filtered IP)"));
174 AddDebugLogLineM(false, logClient
, wxT("Accepted connection from ") + addr
.IPAddress());
179 void CClientTCPSocket::ResetTimeOutTimer()
181 timeout_timer
= ::GetTickCount();
185 bool CClientTCPSocket::CheckTimeOut()
188 uint32 uTimeout
= GetTimeOut();
191 if (m_client
->GetKadState() == KS_CONNECTED_BUDDY
) {
192 //We originally ignored the timeout here for buddies.
193 //This was a stupid idea on my part. There is now a ping/pong system
194 //for buddies. This ping/pong system now prevents timeouts.
195 //This release will allow lowID clients with KadVersion 0 to remain connected.
196 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
197 //JOHNTODO: Don't forget to remove backward support in a future release.
198 if ( m_client
->GetKadVersion() == 0 ) {
202 uTimeout
+= MIN2MS(15);
205 if (m_client
->GetChatState() != MS_NONE
) {
206 uTimeout
+= CONNECTION_TIMEOUT
;
210 if (::GetTickCount() - timeout_timer
> uTimeout
){
211 timeout_timer
= ::GetTickCount();
212 Disconnect(wxT("Timeout"));
220 void CClientTCPSocket::SetClient(CUpDownClient
* pClient
)
224 m_client
->SetSocket( this );
229 void CClientTCPSocket::OnClose(int nErrorCode
)
232 wxASSERT(theApp
->listensocket
->IsValidSocket(this));
233 CEMSocket::OnClose(nErrorCode
);
235 Disconnect(wxString::Format(wxT("Closed: %u"), nErrorCode
));
237 Disconnect(wxT("Close"));
242 void CClientTCPSocket::Disconnect(const wxString
& strReason
)
244 byConnected
= ES_DISCONNECTED
;
246 if (m_client
->Disconnected(strReason
, true)) {
247 // Somehow, Safe_Delete() is beeing called by Disconnected(),
248 // or any other function that sets m_client to NULL,
249 // so we must check m_client first.
251 m_client
->SetSocket( NULL
);
252 m_client
->Safe_Delete();
262 void CClientTCPSocket::Safe_Delete()
264 if ( !ForDeletion() && !OnDestroy() ) {
268 // lfroen: first of all - stop handler
269 m_ForDeletion
= true;
272 m_client
->SetSocket( NULL
);
276 byConnected
= ES_DISCONNECTED
;
277 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
283 bool CClientTCPSocket::ProcessPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
285 #ifdef __PACKET_RECV_DUMP__
286 //printf("Rec: OPCODE %x \n",opcode);
287 DumpMem(buffer
, size
);
289 if (!m_client
&& opcode
!= OP_HELLO
) {
290 throw wxString(wxT("Asks for something without saying hello"));
291 } else if (m_client
&& opcode
!= OP_HELLO
&& opcode
!= OP_HELLOANSWER
) {
292 m_client
->CheckHandshakeFinished(OP_EDONKEYPROT
, opcode
);
296 case OP_HELLOANSWER
: { // 0.43b
297 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HELLOANSWER from ") + m_client
->GetFullIP());
298 theStats::AddDownOverheadOther(size
);
299 m_client
->ProcessHelloAnswer(buffer
, size
);
301 // start secure identification, if
302 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
303 // - we have received eMule-OP_HELLOANSWER (new eMule)
304 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
305 m_client
->InfoPacketsReceived();
308 // Socket might die because of sending in InfoPacketsReceived, so check
310 m_client
->ConnectionEstablished();
313 // Socket might die on ConnectionEstablished somehow. Check it.
315 Notify_UploadCtrlRefreshClient( m_client
);
320 case OP_HELLO
: { // 0.43b
322 theStats::AddDownOverheadOther(size
);
323 bool bNewClient
= !m_client
;
325 // create new client to save standart informations
326 m_client
= new CUpDownClient(this);
330 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_HELLO from ") + m_client
->GetFullIP() );
332 bool bIsMuleHello
= false;
335 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
337 if (bNewClient
&& m_client
) {
338 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
339 m_client
->Safe_Delete();
345 if (thePrefs::ParanoidFilter() && !IsLowID(m_client
->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid()))) {
346 wxString reason
= wxT("Client claims a different IP from the one we received the hello packet from: ");
347 reason
+= Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
348 AddDebugLogLineM(false, logClient
, reason
);
350 m_client
->Safe_Delete();
353 Disconnect(wxT("Paranoid disconecting: ") + reason
);
357 // if IP is filtered, dont reply but disconnect...
358 if (theApp
->ipfilter
->IsFiltered(m_client
->GetIP())) {
360 m_client
->Safe_Delete();
363 Disconnect(wxT("IPFilter"));
369 // now we check if we now this client already. if yes this socket will
370 // be attached to the known client, the new client will be deleted
371 // and the var. "client" will point to the known client.
372 // if not we keep our new-constructed client ;)
373 if (theApp
->clientlist
->AttachToAlreadyKnown(&m_client
,this)) {
374 // update the old client informations
375 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
377 theApp
->clientlist
->AddClient(m_client
);
378 m_client
->SetCommentDirty();
380 Notify_UploadCtrlRefreshClient( m_client
);
381 // send a response packet with standart informations
382 if ((m_client
->GetHashType() == SO_EMULE
) && !bIsMuleHello
) {
383 m_client
->SendMuleInfoPacket(false);
386 // Client might die from Sending in SendMuleInfoPacket, so check
388 m_client
->SendHelloAnswer();
391 // Kry - If the other side supports it, send OS_INFO
392 // Client might die from Sending in SendHelloAnswer, so check
393 if (m_client
&& m_client
->GetOSInfoSupport()) {
394 m_client
->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
397 // Client might die from Sending in SendMuleInfoPacket, so check
399 m_client
->ConnectionEstablished();
402 // start secure identification, if
403 // - we have received eMule-OP_HELLO (new eMule)
404 if (m_client
&& m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
405 m_client
->InfoPacketsReceived();
410 case OP_REQUESTFILENAME
: { // 0.43b
411 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client
->GetFullIP() );
413 theStats::AddDownOverheadFileRequest(size
);
414 // IP banned, no answer for this request
415 if (m_client
->IsBanned()) {
419 if (!m_client
->GetWaitStartTime()) {
420 m_client
->SetWaitStartTime();
422 CMemFile
data_in(buffer
, size
);
423 CMD4Hash reqfilehash
= data_in
.ReadHash();
424 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
425 if ( reqfile
== NULL
) {
426 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
427 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
431 // if we are downloading this file, this could be a new source
432 // no passive adding of files with only one part
433 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
434 if (thePrefs::GetMaxSourcePerFile() >
435 ((CPartFile
*)reqfile
)->GetSourceCount()) {
436 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
440 // check to see if this is a new file they are asking for
441 if (m_client
->GetUploadFileID() != reqfilehash
) {
442 m_client
->SetCommentDirty();
445 m_client
->SetUploadFileID(reqfile
);
446 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
449 CMemFile
data_out(128);
450 data_out
.WriteHash(reqfile
->GetFileHash());
452 // Since it's for somebody else to see, we need to send the prettified
453 // filename, rather than the (possibly) mangled actual filename.
454 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
456 CPacket
* packet
= new CPacket(data_out
, OP_EDONKEYPROT
, OP_REQFILENAMEANSWER
);
457 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
458 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client
->GetFullIP() );
459 SendPacket(packet
,true);
461 // SendPacket might kill the socket, so check
463 m_client
->SendCommentInfo(reqfile
);
467 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
470 case OP_SETREQFILEID
: { // 0.43b EXCEPT track of bad clients
471 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SETREQFILEID from ") + m_client
->GetFullIP() );
473 theStats::AddDownOverheadFileRequest(size
);
475 if (m_client
->IsBanned()) {
481 if (!m_client
->GetWaitStartTime()) {
482 m_client
->SetWaitStartTime();
485 const CMD4Hash
fileID(buffer
);
486 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
487 if ( reqfile
== NULL
) {
488 reqfile
= theApp
->downloadqueue
->GetFileByID(fileID
);
489 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
490 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
491 replypacket
->Copy16ToDataBuffer(fileID
.GetHash());
492 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
493 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILERE to ") + m_client
->GetFullIP() );
494 SendPacket(replypacket
, true);
499 // check to see if this is a new file they are asking for
500 if (m_client
->GetUploadFileID() != fileID
) {
501 m_client
->SetCommentDirty();
504 m_client
->SetUploadFileID(reqfile
);
506 CMemFile
data(16+16);
507 data
.WriteHash(reqfile
->GetFileHash());
508 if (reqfile
->IsPartFile()) {
509 ((CPartFile
*)reqfile
)->WritePartStatus(&data
);
513 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_FILESTATUS
);
514 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
515 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILESTATUS to ") + m_client
->GetFullIP() );
516 SendPacket(packet
, true);
519 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
524 case OP_FILEREQANSNOFIL
: { // 0.43b protocol, lacks ZZ's download manager on swap
525 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client
->GetFullIP() );
527 theStats::AddDownOverheadFileRequest(size
);
529 // if that client does not have my file maybe has another different
530 CPartFile
* reqfile
= theApp
->downloadqueue
->GetFileByID(CMD4Hash(buffer
));
532 reqfile
->AddDeadSource( m_client
);
537 // we try to swap to another file ignoring no needed parts files
538 switch (m_client
->GetDownloadState()) {
541 case DS_NONEEDEDPARTS
:
542 if (!m_client
->SwapToAnotherFile(true, true, true, NULL
)) {
543 theApp
->downloadqueue
->RemoveSource(m_client
);
549 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
553 case OP_REQFILENAMEANSWER
: { // 0.43b except check for bad clients
554 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client
->GetFullIP() );
556 theStats::AddDownOverheadFileRequest(size
);
557 CMemFile
data(buffer
, size
);
558 CMD4Hash hash
= data
.ReadHash();
559 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
560 m_client
->ProcessFileInfo(&data
, file
);
564 case OP_FILESTATUS
: { // 0.43b except check for bad clients
565 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILESTATUS from ") + m_client
->GetFullIP() );
567 theStats::AddDownOverheadFileRequest(size
);
568 CMemFile
data(buffer
, size
);
569 CMD4Hash hash
= data
.ReadHash();
570 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
571 m_client
->ProcessFileStatus(false, &data
, file
);
575 case OP_STARTUPLOADREQ
: {
576 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client
->GetFullIP() );
578 theStats::AddDownOverheadFileRequest(size
);
580 if (!m_client
->CheckHandshakeFinished(OP_EDONKEYPROT
, opcode
)) {
584 m_client
->CheckForAggressive();
585 if ( m_client
->IsBanned() ) {
590 const CMD4Hash
fileID(buffer
);
591 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
593 if (m_client
->GetUploadFileID() != fileID
) {
594 m_client
->SetCommentDirty();
596 m_client
->SetUploadFileID(reqfile
);
597 m_client
->SendCommentInfo(reqfile
);
599 // Socket might die because of SendCommentInfo, so check
601 theApp
->uploadqueue
->AddClientToQueue(m_client
);
607 case OP_QUEUERANK
: { // 0.43b
608 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_QUEUERANK from ") + m_client
->GetFullIP() );
610 theStats::AddDownOverheadFileRequest(size
);
611 CMemFile
data(buffer
, size
);
612 uint32 rank
= data
.ReadUInt32();
614 m_client
->SetRemoteQueueRank(rank
);
618 case OP_ACCEPTUPLOADREQ
: { // 0.42e (xcept khaos stats)
619 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client
->GetFullIP() );
621 theStats::AddDownOverheadFileRequest(size
);
622 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
623 if (m_client
->GetDownloadState() == DS_ONQUEUE
) {
624 m_client
->SetDownloadState(DS_DOWNLOADING
);
625 m_client
->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
626 m_client
->SendBlockRequests();
629 if (!m_client
->GetSentCancelTransfer()) {
630 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
631 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
632 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
633 m_client
->SendPacket(packet
,true,true);
635 // SendPacket can cause the socket to die, so check
637 m_client
->SetSentCancelTransfer(1);
641 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
646 case OP_REQUESTPARTS
: { // 0.43b
647 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
649 theStats::AddDownOverheadFileRequest(size
);
651 m_client
->ProcessRequestPartsPacket(buffer
, size
, false);
656 case OP_CANCELTRANSFER
: { // 0.43b
657 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client
->GetFullIP() );
659 theStats::AddDownOverheadFileRequest(size
);
660 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
661 if ( CLogger::IsEnabled( logClient
) ) {
662 AddDebugLogLineM( false, logClient
, m_client
->GetUserName() + wxT(": Upload session ended due canceled transfer."));
667 case OP_END_OF_DOWNLOAD
: { // 0.43b except check for bad clients
668 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client
->GetFullIP() );
670 theStats::AddDownOverheadFileRequest(size
);
671 if (size
>=16 && m_client
->GetUploadFileID() == CMD4Hash(buffer
)) {
672 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
673 if ( CLogger::IsEnabled( logClient
) ) {
674 AddDebugLogLineM( false, logClient
, m_client
->GetUserName() + wxT(": Upload session ended due ended transfer."));
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
);
792 CMemFile
message_file(buffer
, size
);
794 wxString message
= message_file
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
795 if (IsMessageFiltered(message
, m_client
)) {
796 AddLogLineM( true, CFormat(_("Message filtered from '%s' (IP:%s)")) % m_client
->GetUserName() % m_client
->GetFullIP());
798 AddLogLineM( true, CFormat(_("New message from '%s' (IP:%s)")) % m_client
->GetUserName() % m_client
->GetFullIP());
800 Notify_ChatProcessMsg(GUI_ID(m_client
->GetIP(),m_client
->GetUserPort()), m_client
->GetUserName() + wxT("|") + message
);
805 case OP_ASKSHAREDFILES
: { // 0.43b (well, er, it does the same, but in our own way)
806 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client
->GetFullIP() );
808 // client wants to know what we have in share, let's see if we allow him to know that
809 theStats::AddDownOverheadOther(size
);
810 // IP banned, no answer for this request
811 if (m_client
->IsBanned()) {
815 if (thePrefs::CanSeeShares() == vsfaEverybody
|| (thePrefs::CanSeeShares() == vsfaFriends
&& m_client
->IsFriend())) {
816 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
817 % m_client
->GetUserName()
818 % m_client
->GetUserIDHybrid() );
820 std::vector
<CKnownFile
*> list
;
821 theApp
->sharedfiles
->CopyFileList(list
);
823 CMemFile
tempfile(80);
824 tempfile
.WriteUInt32(list
.size());
825 for (unsigned i
= 0; i
< list
.size(); ++i
) {
826 if (!list
[i
]->IsLargeFile() || m_client
->SupportsLargeFiles()) {
827 theApp
->sharedfiles
->CreateOfferedFilePacket(list
[i
], &tempfile
, NULL
, m_client
);
831 // create a packet and send it
832 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESANSWER
);
833 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client
->GetFullIP() );
834 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
835 SendPacket(replypacket
, true, true);
837 AddLogLineM( true, CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
838 % m_client
->GetUserName()
839 % m_client
->GetUserIDHybrid() );
841 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
842 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
843 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
844 SendPacket(replypacket
, true, true);
850 case OP_ASKSHAREDFILESANSWER
: { // 0.43b
851 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client
->GetFullIP() );
853 theStats::AddDownOverheadOther(size
);
855 m_client
->ProcessSharedFileList(buffer
, size
, EmptyStr
);
859 case OP_ASKSHAREDDIRS
: { // 0.43b
860 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client
->GetFullIP() );
862 theStats::AddDownOverheadOther(size
);
863 wxASSERT( size
== 0 );
864 // IP banned, no answer for this request
865 if (m_client
->IsBanned()) {
868 if ((thePrefs::CanSeeShares()==vsfaEverybody
) || ((thePrefs::CanSeeShares()==vsfaFriends
) && m_client
->IsFriend())) {
869 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
870 % m_client
->GetUserName()
871 % m_client
->GetUserIDHybrid() );
873 // This list will contain all (unique) folders.
874 std::list
<CPath
> foldersToSend
;
876 // The shared folders
877 const unsigned folderCount
= theApp
->glob_prefs
->shareddir_list
.size();
878 for (unsigned i
= 0; i
< folderCount
; ++i
) {
879 foldersToSend
.push_back(theApp
->glob_prefs
->shareddir_list
[i
]);
882 // ... the categories folders ... (category 0 -> incoming)
883 for (unsigned i
= 0; i
< theApp
->glob_prefs
->GetCatCount(); ++i
) {
884 foldersToSend
.push_back(theApp
->glob_prefs
->GetCategory(i
)->path
);
887 // ... and the Magic thing from the eDonkey Hybrids...
888 foldersToSend
.push_back(CPath(OP_INCOMPLETE_SHARED_FILES
));
891 foldersToSend
.sort();
892 foldersToSend
.unique();
895 CMemFile
tempfile(80);
896 tempfile
.WriteUInt32(foldersToSend
.size());
898 std::list
<CPath
>::iterator it
= foldersToSend
.begin();
899 for (; it
!= foldersToSend
.end(); ++it
) {
900 // We need to send the 'raw' filename, so we can recognize it again.
901 tempfile
.WriteString(it
->GetRaw(), m_client
->GetUnicodeSupport());
904 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDDIRSANS
);
905 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
906 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client
->GetFullIP() );
907 SendPacket(replypacket
, true, true);
909 AddLogLineM( true, CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
910 % m_client
->GetUserName()
911 % m_client
->GetUserIDHybrid() );
913 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
914 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
915 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
916 SendPacket(replypacket
, true, true);
922 case OP_ASKSHAREDFILESDIR
: { // 0.43b
923 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client
->GetFullIP() );
925 theStats::AddDownOverheadOther(size
);
926 // IP banned, no answer for this request
927 if (m_client
->IsBanned()) {
930 CMemFile
data(buffer
, size
);
932 wxString strReqDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
933 if (thePrefs::CanSeeShares()==vsfaEverybody
|| (thePrefs::CanSeeShares()==vsfaFriends
&& m_client
->IsFriend())) {
934 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
935 wxASSERT( data
.GetPosition() == data
.GetLength() );
937 CKnownFilePtrList list
;
939 if (strReqDir
== OP_INCOMPLETE_SHARED_FILES
) {
940 // get all shared files from download queue
941 int iQueuedFiles
= theApp
->downloadqueue
->GetFileCount();
942 for (int i
= 0; i
< iQueuedFiles
; i
++) {
943 CPartFile
* pFile
= theApp
->downloadqueue
->GetFileByIndex(i
);
944 if (pFile
== NULL
|| pFile
->GetStatus(true) != PS_READY
) {
948 list
.push_back(pFile
);
951 theApp
->sharedfiles
->GetSharedFilesByDirectory(strReqDir
, list
);
954 CMemFile
tempfile(80);
955 tempfile
.WriteString(strReqDir
, m_client
->GetUnicodeSupport());
956 tempfile
.WriteUInt32(list
.size());
958 while (!list
.empty()) {
959 if (!list
.front()->IsLargeFile() || m_client
->SupportsLargeFiles()) {
960 theApp
->sharedfiles
->CreateOfferedFilePacket(list
.front(), &tempfile
, NULL
, m_client
);
966 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIRANS
);
967 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
968 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client
->GetFullIP() );
969 SendPacket(replypacket
, true, true);
971 AddLogLineM( true, CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
973 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
974 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
975 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
976 SendPacket(replypacket
, true, true);
981 case OP_ASKSHAREDDIRSANS
:{ // 0.43b
982 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client
->GetFullIP() );
984 theStats::AddDownOverheadOther(size
);
985 if (m_client
->GetFileListRequested() == 1){
986 CMemFile
data(buffer
, size
);
987 uint32 uDirs
= data
.ReadUInt32();
988 for (uint32 i
= 0; i
< uDirs
; i
++){
989 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
990 AddLogLineM( true, CFormat( _("User %s (%u) shares directory %s") )
991 % m_client
->GetUserName()
992 % m_client
->GetUserIDHybrid()
995 CMemFile
tempfile(80);
996 tempfile
.WriteString(strDir
, m_client
->GetUnicodeSupport());
997 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIR
);
998 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
999 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client
->GetFullIP() );
1000 SendPacket(replypacket
, true, true);
1002 wxASSERT( data
.GetPosition() == data
.GetLength() );
1003 m_client
->SetFileListRequested(uDirs
);
1005 AddLogLineM( true, CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1006 % m_client
->GetUserName()
1007 % m_client
->GetUserIDHybrid() );
1012 case OP_ASKSHAREDFILESDIRANS
: { // 0.43b
1013 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client
->GetFullIP() );
1015 theStats::AddDownOverheadOther(size
);
1016 CMemFile
data(buffer
, size
);
1017 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
1019 if (m_client
->GetFileListRequested() > 0){
1020 AddLogLineM( true, CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1021 % m_client
->GetUserName()
1022 % m_client
->GetUserIDHybrid()
1025 m_client
->ProcessSharedFileList(buffer
+ data
.GetPosition(), size
- data
.GetPosition(), strDir
);
1026 if (m_client
->GetFileListRequested() == 0) {
1027 AddLogLineM( true, CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1028 % m_client
->GetUserName()
1029 % m_client
->GetUserIDHybrid() );
1032 AddLogLineM( true, CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1033 % m_client
->GetUserName()
1034 % m_client
->GetUserIDHybrid() );
1039 case OP_ASKSHAREDDENIEDANS
:
1040 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client
->GetFullIP() );
1042 theStats::AddDownOverheadOther(size
);
1043 wxASSERT( size
== 0 );
1044 AddLogLineM( true, CFormat( _("User %s (%u) denied access to shared directories/files list") )
1045 % m_client
->GetUserName()
1046 % m_client
->GetUserIDHybrid() );
1048 m_client
->SetFileListRequested(0);
1052 theStats::AddDownOverheadOther(size
);
1053 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("Edonkey packet: unknown opcode: %i %x from "), opcode
, opcode
) + m_client
->GetFullIP());
1061 bool CClientTCPSocket::ProcessExtPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
1063 #ifdef __PACKET_RECV_DUMP__
1064 //printf("Rec: OPCODE %x \n",opcode);
1065 DumpMem(buffer
,size
);
1068 // 0.42e - except the catchs on mem exception and file exception
1070 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1073 if (!client->CheckHandshakeFinished(OP_EMULEPROT, opcode)) {
1074 // Here comes a extended packet without finishing the hanshake.
1075 // IMHO, we should disconnect the client.
1076 throw wxString(wxT("Client send extended packet before finishing handshake"));
1080 case OP_MULTIPACKET_EXT
:
1081 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client
->GetFullIP());
1082 case OP_MULTIPACKET
: {
1083 if (opcode
== OP_MULTIPACKET
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET from ") + m_client
->GetFullIP() );
1085 theStats::AddDownOverheadFileRequest(size
);
1087 if (m_client
->IsBanned()) {
1091 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1092 // Here comes a extended packet without finishing the hanshake.
1093 // IMHO, we should disconnect the client.
1094 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1097 CMemFile
data_in(buffer
, size
);
1098 CMD4Hash reqfilehash
= data_in
.ReadHash();
1099 uint64 nSize
= (opcode
== OP_MULTIPACKET_EXT
) ? data_in
.ReadUInt64() : 0;
1101 bool file_not_found
= false;
1102 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
1103 if ( reqfile
== NULL
){
1104 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1105 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
1106 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a non-shared file"));
1107 file_not_found
= true;
1111 if (!file_not_found
&& reqfile
->IsLargeFile() && !m_client
->SupportsLargeFiles()) {
1112 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a large file but doesn't support them"));
1113 file_not_found
= true;
1116 if (!file_not_found
&& nSize
&& (reqfile
->GetFileSize() != nSize
)) {
1117 AddDebugLogLineM(false, logRemoteClient
, wxT("Remote client asked for a file but specified wrong size"));
1118 file_not_found
= true;
1121 if (file_not_found
) {
1122 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
1123 replypacket
->Copy16ToDataBuffer(reqfilehash
.GetHash());
1124 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
1125 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client
->GetFullIP() );
1126 SendPacket(replypacket
, true);
1130 if (!m_client
->GetWaitStartTime()) {
1131 m_client
->SetWaitStartTime();
1133 // if we are downloading this file, this could be a new source
1134 // no passive adding of files with only one part
1135 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
1136 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile
*)reqfile
)->GetSourceCount()) {
1137 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
1140 // check to see if this is a new file they are asking for
1141 if (m_client
->GetUploadFileID() != reqfilehash
) {
1142 m_client
->SetCommentDirty();
1144 m_client
->SetUploadFileID(reqfile
);
1145 CMemFile
data_out(128);
1146 data_out
.WriteHash(reqfile
->GetFileHash());
1147 while(data_in
.GetLength()-data_in
.GetPosition()) {
1149 throw wxString(wxT("Client suddenly disconnected"));
1151 uint8 opcode_in
= data_in
.ReadUInt8();
1153 case OP_REQUESTFILENAME
: {
1154 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1155 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
1156 data_out
.WriteUInt8(OP_REQFILENAMEANSWER
);
1158 // Since it's for somebody else to see, we need to send the prettified
1159 // filename, rather than the (possibly) mangled actual filename
1160 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
1163 case OP_AICHFILEHASHREQ
: {
1164 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1165 if (m_client
->IsSupportingAICH() && reqfile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1166 && reqfile
->GetAICHHashset()->HasValidMasterHash())
1168 data_out
.WriteUInt8(OP_AICHFILEHASHANS
);
1169 reqfile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1173 case OP_SETREQFILEID
: {
1174 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1175 data_out
.WriteUInt8(OP_FILESTATUS
);
1176 if (reqfile
->IsPartFile()) {
1177 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1179 data_out
.WriteUInt16(0);
1183 //We still send the source packet separately..
1184 //We could send it within this packet.. If agreeded, I will fix it..
1185 case OP_REQUESTSOURCES2
:
1186 case OP_REQUESTSOURCES
: {
1187 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1188 uint8 byRequestedVersion
= 0;
1189 uint16 byRequestedOptions
= 0;
1190 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1191 byRequestedVersion
= data_in
.ReadUInt8();
1192 byRequestedOptions
= data_in
.ReadUInt16();
1195 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1197 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() > 1) {
1198 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1199 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1201 //if not complete and file is rare
1202 ( reqfile
->IsPartFile()
1203 && (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1204 && ((CPartFile
*)reqfile
)->GetSourceCount() <= RARE_FILE
1206 //OR if file is not rare or if file is complete
1207 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1210 m_client
->SetLastSrcReqTime();
1211 CPacket
* tosend
= reqfile
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1213 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1214 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1215 SendPacket(tosend
, true);
1224 if( data_out
.GetLength() > 16 ) {
1225 CPacket
* reply
= new CPacket(data_out
, OP_EMULEPROT
, OP_MULTIPACKETANSWER
);
1226 theStats::AddUpOverheadFileRequest(reply
->GetPacketSize());
1227 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client
->GetFullIP() );
1228 SendPacket(reply
, true);
1233 case OP_MULTIPACKETANSWER
: { // 0.43b
1234 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client
->GetFullIP() );
1236 theStats::AddDownOverheadFileRequest(size
);
1238 if (m_client
->IsBanned()) {
1242 if( m_client
->GetKadPort() ) {
1243 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client
->GetIP()), m_client
->GetKadPort());
1246 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1247 // Here comes a extended packet without finishing the hanshake.
1248 // IMHO, we should disconnect the client.
1249 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1252 CMemFile
data_in(buffer
, size
);
1253 CMD4Hash reqfilehash
= data_in
.ReadHash();
1254 const CPartFile
*reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1255 //Make sure we are downloading this file.
1257 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1259 if ( !m_client
->GetRequestFile() ) {
1261 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1263 if (reqfile
!= m_client
->GetRequestFile()) {
1264 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1266 while (data_in
.GetLength()-data_in
.GetPosition()) {
1267 // Some of the cases down there can actually send a packet and lose the client
1269 throw wxString(wxT("Client suddenly disconnected"));
1271 uint8 opcode_in
= data_in
.ReadUInt8();
1273 case OP_REQFILENAMEANSWER
: {
1275 throw wxString(wxT("Client suddenly disconnected"));
1277 m_client
->ProcessFileInfo(&data_in
, reqfile
);
1281 case OP_FILESTATUS
: {
1283 throw wxString(wxT("Client suddenly disconnected"));
1285 m_client
->ProcessFileStatus(false, &data_in
, reqfile
);
1289 case OP_AICHFILEHASHANS
: {
1291 throw wxString(wxT("Client suddenly disconnected"));
1293 m_client
->ProcessAICHFileHash(&data_in
, reqfile
);
1303 case OP_EMULEINFO
: { // 0.43b
1304 theStats::AddDownOverheadOther(size
);
1306 if (!m_client
->ProcessMuleInfoPacket(buffer
, size
)) {
1307 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFO from ") + m_client
->GetFullIP() );
1309 // If it's not a OS Info packet, is an old client
1310 // start secure identification, if
1311 // - we have received eD2K and eMule info (old eMule)
1312 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1313 m_client
->InfoPacketsReceived();
1315 m_client
->SendMuleInfoPacket(true);
1317 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1321 case OP_EMULEINFOANSWER
: { // 0.43b
1322 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client
->GetFullIP() );
1323 theStats::AddDownOverheadOther(size
);
1325 m_client
->ProcessMuleInfoPacket(buffer
, size
);
1326 // start secure identification, if
1327 // - we have received eD2K and eMule info (old eMule)
1329 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1330 m_client
->InfoPacketsReceived();
1336 case OP_SECIDENTSTATE
:{ // 0.43b
1337 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client
->GetFullIP() );
1339 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1340 // Here comes a extended packet without finishing the hanshake.
1341 // IMHO, we should disconnect the client.
1342 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1344 m_client
->ProcessSecIdentStatePacket(buffer
, size
);
1345 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1347 int SecureIdentState
= m_client
->GetSecureIdentState();
1348 if (SecureIdentState
== IS_SIGNATURENEEDED
) {
1349 m_client
->SendSignaturePacket();
1350 } else if (SecureIdentState
== IS_KEYANDSIGNEEDED
) {
1351 m_client
->SendPublicKeyPacket();
1352 // SendPublicKeyPacket() might cause the socket to die, so check
1354 m_client
->SendSignaturePacket();
1361 case OP_PUBLICKEY
: { // 0.43b
1362 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICKEY from ") + m_client
->GetFullIP() );
1364 if (m_client
->IsBanned() ){
1368 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1369 // Here comes a extended packet without finishing the hanshake.
1370 // IMHO, we should disconnect the client.
1371 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1374 m_client
->ProcessPublicKeyPacket(buffer
, size
);
1377 case OP_SIGNATURE
:{ // 0.43b
1378 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SIGNATURE from ") + m_client
->GetFullIP() );
1380 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1381 // Here comes a extended packet without finishing the hanshake.
1382 // IMHO, we should disconnect the client.
1383 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1386 m_client
->ProcessSignaturePacket(buffer
, size
);
1389 case OP_SENDINGPART_I64
:
1390 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client
->GetFullIP() );
1391 case OP_COMPRESSEDPART_I64
:
1392 if (opcode
== OP_COMPRESSEDPART_I64
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client
->GetFullIP() );
1393 case OP_COMPRESSEDPART
: { // 0.47a
1394 if (opcode
== OP_COMPRESSEDPART
) AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client
->GetFullIP() );
1396 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1397 // Here comes a extended packet without finishing the hanshake.
1398 // IMHO, we should disconnect the client.
1399 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1402 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
1404 m_client
->ProcessBlockPacket(buffer
, size
, (opcode
!= OP_SENDINGPART_I64
), (opcode
== OP_COMPRESSEDPART_I64
) || (opcode
== OP_SENDINGPART_I64
));
1407 m_client
->GetRequestFile()->IsStopped() ||
1408 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
1409 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
)) {
1410 if (!m_client
->GetSentCancelTransfer()) {
1411 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1412 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1413 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1414 m_client
->SendPacket(packet
,true,true);
1417 m_client
->SetSentCancelTransfer(1);
1422 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
1426 if (!m_client
->GetSentCancelTransfer()) {
1427 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1428 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1429 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1430 m_client
->SendPacket(packet
,true,true);
1433 m_client
->SetSentCancelTransfer(1);
1438 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
1443 case OP_REQUESTPARTS_I64
: {
1444 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client
->GetFullIP() );
1446 theStats::AddDownOverheadFileRequest(size
);
1448 m_client
->ProcessRequestPartsPacket(buffer
, size
, true);
1452 case OP_QUEUERANKING
: { // 0.43b
1453 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_QUEUERANKING from ") + m_client
->GetFullIP() );
1455 theStats::AddDownOverheadOther(size
);
1457 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1458 // Here comes a extended packet without finishing the hanshake.
1459 // IMHO, we should disconnect the client.
1460 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1464 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1467 uint16 newrank
= PeekUInt16(buffer
);
1468 m_client
->SetRemoteQueueFull(false);
1469 m_client
->SetRemoteQueueRank(newrank
);
1472 case OP_REQUESTSOURCES
:{
1473 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client
->GetFullIP() );
1475 theStats::AddDownOverheadSourceExchange(size
);
1477 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1478 // Here comes an extended packet without finishing the handshake.
1479 // IMHO, we should disconnect the client.
1480 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1483 uint8 byRequestedVersion
= 0;
1484 uint16 byRequestedOptions
= 0;
1485 CMemFile
data_in(buffer
, size
);
1486 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1487 byRequestedVersion
= data_in
.ReadUInt8();
1488 byRequestedOptions
= data_in
.ReadUInt16();
1491 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() >= 1) {
1493 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1495 //first check shared file list, then download list
1496 const CMD4Hash
fileID(buffer
);
1497 CKnownFile
* file
= theApp
->sharedfiles
->GetFileByID(fileID
);
1499 file
= theApp
->downloadqueue
->GetFileByID(fileID
);
1502 // There are some clients which do not follow the correct protocol procedure of sending
1503 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1504 // are doing this, they will not get the optimal set of sources which we could offer if
1505 // they would follow the above noted protocol sequence. They better do it the right way
1506 // or they will get just a random set of sources because we do not know their download
1507 // part status which may get cleared with the call of 'SetUploadFileID'.
1508 m_client
->SetUploadFileID(file
);
1510 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1511 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1513 //if not complete and file is rare, allow once every 40 minutes
1514 ( file
->IsPartFile() &&
1515 ((CPartFile
*)file
)->GetSourceCount() <= RARE_FILE
&&
1516 (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1518 //OR if file is not rare or if file is complete, allow every 90 minutes
1519 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1522 m_client
->SetLastSrcReqTime();
1523 CPacket
* tosend
= file
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1525 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1526 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1527 SendPacket(tosend
, true, true);
1534 case OP_ANSWERSOURCES
: {
1535 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client
->GetFullIP() );
1537 theStats::AddDownOverheadSourceExchange(size
);
1539 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1540 // Here comes a extended packet without finishing the hanshake.
1541 // IMHO, we should disconnect the client.
1542 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1545 CMemFile
data(buffer
, size
);
1546 CMD4Hash hash
= data
.ReadHash();
1547 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1549 if (file
->IsPartFile()){
1550 //set the client's answer time
1551 m_client
->SetLastSrcAnswerTime();
1552 //and set the file's last answer time
1553 ((CPartFile
*)file
)->SetLastAnsweredTime();
1555 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, m_client
->GetSourceExchange1Version(), false, m_client
);
1560 case OP_ANSWERSOURCES2
: {
1561 //printf("Received OP_ANSWERSOURCES2\n");
1562 theStats::AddDownOverheadSourceExchange(size
);
1564 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1565 // Here comes a extended packet without finishing the hanshake.
1566 // IMHO, we should disconnect the client.
1567 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1570 CMemFile
data(buffer
, size
);
1571 uint8 byVersion
= data
.ReadUInt8();
1572 CMD4Hash hash
= data
.ReadHash();
1573 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1575 if (file
->IsPartFile()){
1576 //set the client's answer time
1577 m_client
->SetLastSrcAnswerTime();
1578 //and set the file's last answer time
1579 ((CPartFile
*)file
)->SetLastAnsweredTime();
1580 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, byVersion
, true, m_client
);
1585 case OP_FILEDESC
: { // 0.43b
1586 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_FILEDESC from ") + m_client
->GetFullIP() );
1588 theStats::AddDownOverheadFileRequest(size
);
1590 if (!m_client
->CheckHandshakeFinished(OP_EMULEPROT
, opcode
)) {
1591 // Here comes a extended packet without finishing the hanshake.
1592 // IMHO, we should disconnect the client.
1593 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1596 m_client
->ProcessMuleCommentPacket(buffer
, size
);
1601 case OP_REQUESTPREVIEW
: {
1602 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client
->GetFullIP() );
1606 case OP_PREVIEWANSWER
: {
1607 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client
->GetFullIP() );
1611 case OP_PUBLICIP_ANSWER
: {
1612 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client
->GetFullIP() );
1613 theStats::AddDownOverheadOther(size
);
1614 m_client
->ProcessPublicIPAnswer(buffer
, size
);
1617 case OP_PUBLICIP_REQ
: {
1618 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client
->GetFullIP() );
1619 theStats::AddDownOverheadOther(size
);
1620 CPacket
* pPacket
= new CPacket(OP_PUBLICIP_ANSWER
, 4, OP_EMULEPROT
);
1621 pPacket
->CopyUInt32ToDataBuffer(m_client
->GetIP());
1622 theStats::AddUpOverheadOther(pPacket
->GetPacketSize());
1623 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client
->GetFullIP());
1624 SendPacket(pPacket
);
1627 case OP_AICHANSWER
: {
1628 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHANSWER from ") + m_client
->GetFullIP() );
1629 theStats::AddDownOverheadOther(size
);
1630 m_client
->ProcessAICHAnswer(buffer
, size
);
1633 case OP_AICHREQUEST
: {
1634 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHREQUEST from ") + m_client
->GetFullIP() );
1635 theStats::AddDownOverheadOther(size
);
1636 m_client
->ProcessAICHRequest(buffer
, size
);
1639 case OP_AICHFILEHASHANS
: {
1640 // those should not be received normally, since we should only get those in MULTIPACKET
1641 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client
->GetFullIP() );
1642 theStats::AddDownOverheadOther(size
);
1643 CMemFile
data(buffer
, size
);
1644 m_client
->ProcessAICHFileHash(&data
, NULL
);
1647 case OP_AICHFILEHASHREQ
: {
1648 // those should not be received normally, since we should only get those in MULTIPACKET
1649 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client
->GetFullIP() );
1650 CMemFile
data(buffer
, size
);
1651 CMD4Hash hash
= data
.ReadHash();
1652 CKnownFile
* pPartFile
= theApp
->sharedfiles
->GetFileByID(hash
);
1653 if (pPartFile
== NULL
){
1657 if (m_client
->IsSupportingAICH() && pPartFile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1658 && pPartFile
->GetAICHHashset()->HasValidMasterHash()) {
1660 data_out
.WriteHash(hash
);
1661 pPartFile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1662 CPacket
* packet
= new CPacket(data_out
, OP_EMULEPROT
, OP_AICHFILEHASHANS
);
1663 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1664 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client
->GetFullIP());
1670 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_CALLBACK from ") + m_client
->GetFullIP() );
1671 theStats::AddDownOverheadFileRequest(size
);
1672 if(!Kademlia::CKademlia::IsRunning()) {
1675 CMemFile
data(buffer
, size
);
1676 CUInt128 check
= data
.ReadUInt128();
1677 check
.XOR(Kademlia::CUInt128(true));
1678 if( check
.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1681 CUInt128 fileid
= data
.ReadUInt128();
1683 fileid
.ToByteArray(fileid2
);
1684 const CMD4Hash
fileHash(fileid2
);
1685 if (theApp
->sharedfiles
->GetFileByID(fileHash
) == NULL
) {
1686 if (theApp
->downloadqueue
->GetFileByID(fileHash
) == NULL
) {
1691 uint32 ip
= data
.ReadUInt32();
1692 uint16 tcp
= data
.ReadUInt16();
1693 CUpDownClient
* callback
;
1694 callback
= theApp
->clientlist
->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip
), tcp
);
1695 if( callback
== NULL
) {
1696 //#warning Do we actually have to check friend status here?
1697 callback
= new CUpDownClient(tcp
,ip
,0,0,NULL
,false, false);
1698 theApp
->clientlist
->AddClient(callback
);
1700 callback
->TryToConnect(true);
1704 case OP_BUDDYPING
: {
1705 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_BUDDYPING from ") + m_client
->GetFullIP() );
1706 theStats::AddDownOverheadKad(size
);
1708 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1709 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 || !m_client
->AllowIncomeingBuddyPingPong() ) {
1710 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1714 m_client
->SetLastBuddyPingPongTime();
1715 CPacket
* replypacket
= new CPacket(OP_BUDDYPONG
, 0, OP_EMULEPROT
);
1716 theStats::AddUpOverheadKad(replypacket
->GetPacketSize());
1717 AddDebugLogLineM(false, logLocalClient
,wxT("Local Client: OP_BUDDYPONG to ") + m_client
->GetFullIP());
1718 SendPacket(replypacket
);
1721 case OP_BUDDYPONG
: {
1722 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_BUDDYPONG from ") + m_client
->GetFullIP() );
1723 theStats::AddDownOverheadKad(size
);
1725 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1726 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 ) {
1727 //This pong was not from our buddy or wrong version. Ignore
1730 m_client
->SetLastBuddyPingPongTime();
1731 //All this is for is to reset our socket timeout.
1734 case OP_REASKCALLBACKTCP
: {
1735 theStats::AddDownOverheadFileRequest(size
);
1736 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1737 if (buddy
!= m_client
) {
1738 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() + wxT(" which is not our buddy!") );
1739 //This callback was not from our buddy.. Ignore.
1742 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() );
1743 CMemFile
data_in(buffer
, size
);
1744 uint32 destip
= data_in
.ReadUInt32();
1745 uint16 destport
= data_in
.ReadUInt16();
1746 CMD4Hash hash
= data_in
.ReadHash();
1747 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(hash
);
1749 bool bSenderMultipleIpUnknown
= false;
1750 CUpDownClient
* sender
= theApp
->uploadqueue
->GetWaitingClientByIP_UDP(destip
, destport
, true, &bSenderMultipleIpUnknown
);
1752 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_FILENOTFOUND to ") + m_client
->GetFullIP() );
1753 CPacket
* response
= new CPacket(OP_FILENOTFOUND
,0,OP_EMULEPROT
);
1754 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1756 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1758 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1764 //Make sure we are still thinking about the same file
1765 if (hash
== sender
->GetUploadFileID()) {
1766 sender
->AddAskedCount();
1767 sender
->SetLastUpRequest();
1768 //I messed up when I first added extended info to UDP
1769 //I should have originally used the entire ProcessExtenedInfo the first time.
1770 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1771 //For now on, we should not have to change anything here if we change
1772 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1773 //Update extended info.
1774 if (sender
->GetUDPVersion() > 3) {
1775 sender
->ProcessExtendedInfo(&data_in
, reqfile
);
1776 } else if (sender
->GetUDPVersion() > 2) {
1777 //Update our complete source counts.
1778 uint16 nCompleteCountLast
= sender
->GetUpCompleteSourcesCount();
1779 uint16 nCompleteCountNew
= data_in
.ReadUInt16();
1780 sender
->SetUpCompleteSourcesCount(nCompleteCountNew
);
1781 if (nCompleteCountLast
!= nCompleteCountNew
) {
1782 reqfile
->UpdatePartsInfo();
1786 CMemFile
data_out(128);
1787 if(sender
->GetUDPVersion() > 3) {
1788 if (reqfile
->IsPartFile()) {
1789 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1791 data_out
.WriteUInt16(0);
1795 data_out
.WriteUInt16(theApp
->uploadqueue
->GetWaitingPosition(sender
));
1796 CPacket
* response
= new CPacket(data_out
, OP_EMULEPROT
, OP_REASKACK
);
1797 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1798 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client UDP: OP_REASKACK to ") + m_client
->GetFullIP() );
1799 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1801 AddDebugLogLineM(false, logListenSocket
, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1804 if (!bSenderMultipleIpUnknown
){
1805 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1806 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_QUEUEFULL to ") + m_client
->GetFullIP() );
1807 CPacket
* response
= new CPacket(OP_QUEUEFULL
,0,OP_EMULEPROT
);
1808 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1809 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1812 AddDebugLogLineM(false, logRemoteClient
, CFormat(wxT("OP_REASKCALLBACKTCP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u")) % Uint32toStringIP(destip
) % destport
);
1818 theStats::AddDownOverheadOther(size
);
1819 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("eMule packet : unknown opcode: %i %x from "),opcode
,opcode
) + m_client
->GetFullIP());
1826 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte
* buffer
, uint32 size
, uint8 opcode
)
1828 #ifdef __PACKET_RECV_DUMP__
1829 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1830 DumpMem(buffer
,size
);
1834 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1837 CMemFile
data(buffer
, size
);
1840 case OP_QUEUERANK
: {
1841 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client
->GetFullIP() );
1843 uint8 numtags
= data
.ReadUInt8();
1844 wxASSERT(numtags
== 1);
1846 m_client
->SetRemoteQueueRank(data
.GetIntTagValue());
1848 theStats::AddDownOverheadFileRequest(size
);
1852 case OP_REQUESTPARTS
: {
1853 AddDebugLogLineM( false, logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
1855 m_client
->ProcessRequestPartsPacketv2(data
);
1857 theStats::AddDownOverheadFileRequest(size
);
1862 theStats::AddDownOverheadOther(size
);
1863 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("ED2Kv2 packet : unknown opcode: %i %x from "), opcode
, opcode
) + m_client
->GetFullIP());
1866 AddDebugLogLineM( false, logRemoteClient
, wxString::Format(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from "),data
.GetPosition(), opcode
, opcode
) + m_client
->GetFullIP());
1873 void CClientTCPSocket::OnConnect(int nErrorCode
)
1876 OnError(nErrorCode
);
1877 } else if (!m_client
) {
1878 // and now? Disconnect? not?
1879 AddDebugLogLineM( false, logClient
, wxT("Couldn't send hello packet (Client deleted!)") );
1880 } else if (!m_client
->SendHelloPacket()) {
1881 // and now? Disconnect? not?
1882 AddDebugLogLineM( false, logClient
, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1884 ResetTimeOutTimer();
1889 void CClientTCPSocket::OnSend(int nErrorCode
)
1891 ResetTimeOutTimer();
1892 CEMSocket::OnSend(nErrorCode
);
1896 void CClientTCPSocket::OnReceive(int nErrorCode
)
1898 ResetTimeOutTimer();
1899 // We might have updated ipfilter
1900 wxASSERT(m_remoteip
);
1902 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
1904 m_client
->Safe_Delete();
1907 AddDebugLogLineM( false, logIPFilter
, wxT("A connected client was dropped by IPFilter on new packet received"));
1909 CEMSocket::OnReceive(nErrorCode
);
1914 void CClientTCPSocket::OnError(int nErrorCode
)
1916 //printf("* Called OnError for %p\n",this);
1917 // 0.42e + Kry changes for handling of socket lost events
1920 if ((nErrorCode
== 0) || (nErrorCode
== 7) || (nErrorCode
== 0xFEFF)) {
1922 if (!m_client
->GetUserName().IsEmpty()) {
1923 strError
= wxT("Client '") + m_client
->GetUserName() + wxT("'");
1925 strError
= wxT("An unnamed client");
1927 strError
+= wxT(" (IP:") + m_client
->GetFullIP() + wxT(") ");
1929 strError
= wxT("A client ");
1931 if (nErrorCode
== 0) {
1932 strError
+= wxT("closed connection.");
1933 } else if (nErrorCode
== 0xFEFF) {
1934 strError
+= wxT(" caused a wxSOCKET_LOST event.");
1936 strError
+= wxT("caused a socket blocking error.");
1939 if ( CLogger::IsEnabled( logClient
) && (nErrorCode
!= 107)) {
1940 // 0 -> No Error / Disconect
1941 // 107 -> Transport endpoint is not connected
1943 if (!m_client
->GetUserName().IsEmpty()) {
1944 strError
= wxT("OnError: Client '") + m_client
->GetUserName() +
1945 wxT("' (IP:") + m_client
->GetFullIP() +
1946 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode
);
1948 strError
= wxT("OnError: Unknown client (IP:") +
1949 m_client
->GetFullIP() +
1950 wxString::Format(wxT(") caused an error: %u. Disconnecting client!"), nErrorCode
);
1953 strError
= wxString::Format(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"),
1957 strError
= wxT("Error 107 (Transport endpoint is not connected)");
1961 Disconnect(strError
);
1965 bool CClientTCPSocket::PacketReceived(CPacket
* packet
)
1968 bool bResult
= false;
1969 uint32 uRawSize
= packet
->GetPacketSize();
1971 AddDebugLogLineM( false, logRemoteClient
,
1972 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
1973 % packet
->GetProtocol()
1974 % packet
->GetOpCode()
1975 % packet
->GetPacketSize()
1976 % ( m_client
? m_client
->GetFullIP() : wxT("Unknown Client") )
1982 bool process
= true;
1984 if ((packet
->GetProtocol() == OP_PACKEDPROT
) ||
1985 (packet
->GetProtocol() == OP_ED2KV2PACKEDPROT
)) {
1987 if (!packet
->UnPackPacket()) {
1988 AddDebugLogLineM( false, logZLib
, wxT("Failed to decompress client TCP packet."));
1992 AddDebugLogLineM(false, logRemoteClient
,
1993 wxString::Format(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"),
1994 packet
->GetProtocol(),
1995 packet
->GetOpCode(),
1996 packet
->GetPacketSize())
2002 switch (packet
->GetProtocol()) {
2003 case OP_EDONKEYPROT
:
2004 bResult
= ProcessPacket(packet
->GetDataBuffer(),uRawSize
,packet
->GetOpCode());
2007 bResult
= ProcessExtPacket(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2009 case OP_ED2KV2HEADER
:
2010 bResult
= ProcessED2Kv2Packet(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2012 case OP_ED2KV2PACKEDPROT
:
2014 // Packed inside packed?
2018 theStats::AddDownOverheadOther(uRawSize
);
2020 m_client
->SetDownloadState(DS_ERROR
);
2022 Disconnect(wxT("Unknown protocol"));
2027 } catch (const CEOFException
& err
) {
2028 exception
= wxT("EOF exception: ") + err
.what();
2029 } catch (const CInvalidPacket
& err
) {
2030 exception
= wxT("InvalidPacket exception: ") + err
.what();
2031 } catch (const wxString
& error
) {
2032 exception
= wxT("error: ") + (error
.IsEmpty() ? wxString(wxT("Unknown error")) : error
);
2035 if (!exception
.IsEmpty()) {
2036 AddDebugLogLineM( false, logPacketErrors
,
2037 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2039 % packet
->GetProtocol()
2040 % packet
->GetOpCode()
2041 % packet
->GetPacketSize()
2042 % ( m_client
? m_client
->GetClientFullInfo() : wxT("Unknown") )
2046 m_client
->SetDownloadState(DS_ERROR
);
2049 AddDebugLogLineM( false, logClient
,
2050 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2051 % ( m_client
? m_client
->GetUserName() : wxString(wxT("Unknown")) )
2052 % ( m_client
? m_client
->GetFullIP() : wxString(wxT("Unknown")) )
2056 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2063 bool CClientTCPSocket::IsMessageFiltered(const wxString
& Message
, CUpDownClient
* client
) {
2065 bool filtered
= false;
2066 // If we're chatting to the guy, we don't want to filter!
2067 if (client
->GetChatState() != MS_CHATTING
) {
2068 if (thePrefs::MsgOnlyFriends() && !client
->IsFriend()) {
2070 } else if (thePrefs::MsgOnlySecure() && client
->GetUserName().IsEmpty() ) {
2072 } else if (thePrefs::MustFilterMessages()) {
2073 filtered
= thePrefs::IsMessageFiltered(Message
);
2079 SocketSentBytes
CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2081 SocketSentBytes returnStatus
= CEMSocket::SendControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2083 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2084 ResetTimeOutTimer();
2087 return returnStatus
;
2091 SocketSentBytes
CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2093 SocketSentBytes returnStatus
= CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2095 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2096 ResetTimeOutTimer();
2099 return returnStatus
;
2103 void CClientTCPSocket::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
, uint32 actualPayloadSize
)
2105 ResetTimeOutTimer();
2106 CEMSocket::SendPacket(packet
,delpacket
,controlpacket
, actualPayloadSize
);
2108 // File_checked_for_headers