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 wxSocketBase
* baseSocket
= event
.GetSocket();
80 // wxASSERT(baseSocket); // Rather want a log message right now. Enough other wx problems. >:(
81 if (!baseSocket
) { // WTF?
82 AddDebugLogLineN(logClient
, wxT("received bad wxSocketEvent"));
86 CClientTCPSocket
*socket
= dynamic_cast<CClientTCPSocket
*>(baseSocket
);
92 if (socket
->OnDestroy() || socket
->ForDeletion()) {
96 switch(event
.GetSocketEvent()) {
98 socket
->OnError(0xFEFF /* SOCKET_LOST is not an error */);
101 socket
->OnReceive(0);
103 case wxSOCKET_OUTPUT
:
106 case wxSOCKET_CONNECTION
:
107 // connection stablished, nothing to do about it?
108 socket
->OnConnect(socket
->Error() ? socket
->LastError() : 0);
111 // Nothing should arrive here...
118 // There can be only one. :)
120 static CClientTCPSocketHandler g_clientReqSocketHandler
;
123 //------------------------------------------------------------------------------
125 //------------------------------------------------------------------------------
127 CClientTCPSocket::CClientTCPSocket(CUpDownClient
* in_client
, const CProxyData
*ProxyData
)
128 : CEMSocket(ProxyData
)
130 SetClient(in_client
);
132 m_remoteip
= wxUINT32_SWAP_ALWAYS(in_client
->GetUserIDHybrid());
138 m_ForDeletion
= false;
140 SetEventHandler(g_clientReqSocketHandler
, ID_CLIENTTCPSOCKET_EVENT
);
142 wxSOCKET_CONNECTION_FLAG
|
143 wxSOCKET_INPUT_FLAG
|
144 wxSOCKET_OUTPUT_FLAG
|
148 theApp
->listensocket
->AddSocket(this);
149 theApp
->listensocket
->AddConnection();
152 CClientTCPSocket::~CClientTCPSocket()
154 // remove event handler
159 m_client
->SetSocket( NULL
);
163 if (theApp
->listensocket
&& !theApp
->listensocket
->OnShutdown()) {
164 theApp
->listensocket
->RemoveSocket(this);
168 bool CClientTCPSocket::InitNetworkData()
170 wxASSERT(!m_remoteip
);
172 amuleIPV4Address addr
;
174 m_remoteip
= StringIPtoUint32(addr
.IPAddress());
176 MULE_CHECK(m_remoteip
, false);
178 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
179 AddDebugLogLineN(logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Filtered IP)"));
181 } else if (theApp
->clientlist
->IsBannedClient(m_remoteip
)) {
182 AddDebugLogLineN(logClient
, wxT("Denied connection from ") + addr
.IPAddress() + wxT("(Banned IP)"));
185 AddDebugLogLineN(logClient
, wxT("Accepted connection from ") + addr
.IPAddress());
190 void CClientTCPSocket::ResetTimeOutTimer()
192 timeout_timer
= ::GetTickCount();
196 bool CClientTCPSocket::CheckTimeOut()
199 uint32 uTimeout
= GetTimeOut();
202 if (m_client
->GetKadState() == KS_CONNECTED_BUDDY
) {
203 //We originally ignored the timeout here for buddies.
204 //This was a stupid idea on my part. There is now a ping/pong system
205 //for buddies. This ping/pong system now prevents timeouts.
206 //This release will allow lowID clients with KadVersion 0 to remain connected.
207 //But a soon future version needs to allow these older clients to time out to prevent dead connections from continuing.
208 //JOHNTODO: Don't forget to remove backward support in a future release.
209 if ( m_client
->GetKadVersion() == 0 ) {
213 uTimeout
+= MIN2MS(15);
216 if (m_client
->GetChatState() != MS_NONE
) {
217 uTimeout
+= CONNECTION_TIMEOUT
;
221 if (::GetTickCount() - timeout_timer
> uTimeout
){
222 timeout_timer
= ::GetTickCount();
223 Disconnect(wxT("Timeout"));
231 void CClientTCPSocket::SetClient(CUpDownClient
* pClient
)
235 m_client
->SetSocket( this );
240 void CClientTCPSocket::OnClose(int nErrorCode
)
243 wxASSERT(theApp
->listensocket
->IsValidSocket(this));
244 CEMSocket::OnClose(nErrorCode
);
246 Disconnect(CFormat(wxT("Closed: %u")) % nErrorCode
);
248 Disconnect(wxT("Close"));
253 void CClientTCPSocket::Disconnect(const wxString
& strReason
)
255 byConnected
= ES_DISCONNECTED
;
257 if (m_client
->Disconnected(strReason
, true)) {
258 // Somehow, Safe_Delete() is beeing called by Disconnected(),
259 // or any other function that sets m_client to NULL,
260 // so we must check m_client first.
262 m_client
->SetSocket( NULL
);
263 m_client
->Safe_Delete();
273 void CClientTCPSocket::Safe_Delete()
275 if ( !ForDeletion() && !OnDestroy() ) {
279 // lfroen: first of all - stop handler
280 m_ForDeletion
= true;
283 m_client
->SetSocket( NULL
);
287 byConnected
= ES_DISCONNECTED
;
288 Close(); // Destroy is suposed to call Close(), but.. it doesn't hurt.
294 bool CClientTCPSocket::ProcessPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
296 #ifdef __PACKET_RECV_DUMP__
297 //printf("Rec: OPCODE %x \n",opcode);
298 DumpMem(buffer
, size
);
300 if (!m_client
&& opcode
!= OP_HELLO
) {
301 throw wxString(wxT("Asks for something without saying hello"));
302 } else if (m_client
&& opcode
!= OP_HELLO
&& opcode
!= OP_HELLOANSWER
) {
303 m_client
->CheckHandshakeFinished();
307 case OP_HELLOANSWER
: { // 0.43b
308 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_HELLOANSWER from ") + m_client
->GetFullIP());
309 theStats::AddDownOverheadOther(size
);
310 m_client
->ProcessHelloAnswer(buffer
, size
);
312 // start secure identification, if
313 // - we have received OP_EMULEINFO and OP_HELLOANSWER (old eMule)
314 // - we have received eMule-OP_HELLOANSWER (new eMule)
315 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
316 m_client
->InfoPacketsReceived();
319 // Socket might die because of sending in InfoPacketsReceived, so check
321 m_client
->ConnectionEstablished();
324 // Socket might die on ConnectionEstablished somehow. Check it.
326 Notify_SharedCtrlRefreshClient( m_client
, AVAILABLE_SOURCE
);
331 case OP_HELLO
: { // 0.43b
333 theStats::AddDownOverheadOther(size
);
334 bool bNewClient
= !m_client
;
336 // create new client to save standart informations
337 m_client
= new CUpDownClient(this);
341 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_HELLO from ") + m_client
->GetFullIP() );
343 bool bIsMuleHello
= false;
346 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
348 if (bNewClient
&& m_client
) {
349 // Don't let CUpDownClient::Disconnected be processed for a client which is not in the list of clients.
350 m_client
->Safe_Delete();
356 if (thePrefs::ParanoidFilter() && !IsLowID(m_client
->GetUserIDHybrid()) && (GetRemoteIP() != wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid()))) {
357 wxString reason
= wxT("Client claims a different IP from the one we received the hello packet from: ");
358 reason
+= Uint32toStringIP(wxUINT32_SWAP_ALWAYS(m_client
->GetUserIDHybrid())) + wxT(" / ") + Uint32toStringIP(GetRemoteIP());
359 AddDebugLogLineN(logClient
, reason
);
361 m_client
->Safe_Delete();
364 Disconnect(wxT("Paranoid disconecting: ") + reason
);
368 // if IP is filtered, dont reply but disconnect...
369 if (theApp
->ipfilter
->IsFiltered(m_client
->GetIP())) {
371 m_client
->Safe_Delete();
374 Disconnect(wxT("IPFilter"));
380 // now we check if we now this client already. if yes this socket will
381 // be attached to the known client, the new client will be deleted
382 // and the var. "client" will point to the known client.
383 // if not we keep our new-constructed client ;)
384 if (theApp
->clientlist
->AttachToAlreadyKnown(&m_client
,this)) {
385 // update the old client informations
386 bIsMuleHello
= m_client
->ProcessHelloPacket(buffer
, size
);
388 theApp
->clientlist
->AddClient(m_client
);
389 m_client
->SetCommentDirty();
391 Notify_SharedCtrlRefreshClient( m_client
, AVAILABLE_SOURCE
);
392 // send a response packet with standart informations
393 if ((m_client
->GetHashType() == SO_EMULE
) && !bIsMuleHello
) {
394 m_client
->SendMuleInfoPacket(false);
397 // Client might die from Sending in SendMuleInfoPacket, so check
399 m_client
->SendHelloAnswer();
402 // Kry - If the other side supports it, send OS_INFO
403 // Client might die from Sending in SendHelloAnswer, so check
404 if (m_client
&& m_client
->GetOSInfoSupport()) {
405 m_client
->SendMuleInfoPacket(false,true); // Send the OS Info tag on the recycled Mule Info
408 // Client might die from Sending in SendMuleInfoPacket, so check
410 m_client
->ConnectionEstablished();
413 // start secure identification, if
414 // - we have received eMule-OP_HELLO (new eMule)
415 if (m_client
&& m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
416 m_client
->InfoPacketsReceived();
421 case OP_REQUESTFILENAME
: { // 0.43b
422 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTFILENAME from ") + m_client
->GetFullIP() );
424 theStats::AddDownOverheadFileRequest(size
);
425 // IP banned, no answer for this request
426 if (m_client
->IsBanned()) {
430 if (!m_client
->GetWaitStartTime()) {
431 m_client
->SetWaitStartTime();
433 CMemFile
data_in(buffer
, size
);
434 CMD4Hash reqfilehash
= data_in
.ReadHash();
435 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
436 if ( reqfile
== NULL
) {
437 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
438 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
442 // if we are downloading this file, this could be a new source
443 // no passive adding of files with only one part
444 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
445 if (thePrefs::GetMaxSourcePerFile() >
446 ((CPartFile
*)reqfile
)->GetSourceCount()) {
447 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
451 // check to see if this is a new file they are asking for
452 if (m_client
->GetUploadFileID() != reqfilehash
) {
453 m_client
->SetCommentDirty();
456 m_client
->SetUploadFileID(reqfile
);
457 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
460 CMemFile
data_out(128);
461 data_out
.WriteHash(reqfile
->GetFileHash());
463 // Since it's for somebody else to see, we need to send the prettified
464 // filename, rather than the (possibly) mangled actual filename.
465 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
467 CPacket
* packet
= new CPacket(data_out
, OP_EDONKEYPROT
, OP_REQFILENAMEANSWER
);
468 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
469 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_REQFILENAMEANSWER to ") + m_client
->GetFullIP() );
470 SendPacket(packet
,true);
472 // SendPacket might kill the socket, so check
474 m_client
->SendCommentInfo(reqfile
);
478 throw wxString(wxT("Invalid OP_REQUESTFILENAME packet size"));
481 case OP_SETREQFILEID
: { // 0.43b EXCEPT track of bad clients
482 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SETREQFILEID from ") + m_client
->GetFullIP() );
484 theStats::AddDownOverheadFileRequest(size
);
486 if (m_client
->IsBanned()) {
492 if (!m_client
->GetWaitStartTime()) {
493 m_client
->SetWaitStartTime();
496 const CMD4Hash
fileID(buffer
);
497 CKnownFile
*reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
498 if ( reqfile
== NULL
) {
499 reqfile
= theApp
->downloadqueue
->GetFileByID(fileID
);
500 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
501 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
502 replypacket
->Copy16ToDataBuffer(fileID
.GetHash());
503 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
504 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILERE to ") + m_client
->GetFullIP() );
505 SendPacket(replypacket
, true);
510 // check to see if this is a new file they are asking for
511 if (m_client
->GetUploadFileID() != fileID
) {
512 m_client
->SetCommentDirty();
515 m_client
->SetUploadFileID(reqfile
);
517 CMemFile
data(16+16);
518 data
.WriteHash(reqfile
->GetFileHash());
519 if (reqfile
->IsPartFile()) {
520 ((CPartFile
*)reqfile
)->WritePartStatus(&data
);
524 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_FILESTATUS
);
525 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
526 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILESTATUS to ") + m_client
->GetFullIP() );
527 SendPacket(packet
, true);
530 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
535 case OP_FILEREQANSNOFIL
: { // 0.43b protocol, lacks ZZ's download manager on swap
536 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_FILEREQANSNOFIL from ") + m_client
->GetFullIP() );
538 theStats::AddDownOverheadFileRequest(size
);
540 // if that client does not have my file maybe has another different
541 CPartFile
* reqfile
= theApp
->downloadqueue
->GetFileByID(CMD4Hash(buffer
));
543 reqfile
->AddDeadSource( m_client
);
548 // we try to swap to another file ignoring no needed parts files
549 switch (m_client
->GetDownloadState()) {
552 case DS_NONEEDEDPARTS
:
553 if (!m_client
->SwapToAnotherFile(true, true, true, NULL
)) {
554 theApp
->downloadqueue
->RemoveSource(m_client
);
560 throw wxString(wxT("Invalid OP_FILEREQUEST packet size"));
564 case OP_REQFILENAMEANSWER
: { // 0.43b except check for bad clients
565 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQFILENAMEANSWER from ") + m_client
->GetFullIP() );
567 theStats::AddDownOverheadFileRequest(size
);
568 CMemFile
data(buffer
, size
);
569 CMD4Hash hash
= data
.ReadHash();
570 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
571 m_client
->ProcessFileInfo(&data
, file
);
575 case OP_FILESTATUS
: { // 0.43b except check for bad clients
576 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_FILESTATUS from ") + m_client
->GetFullIP() );
578 theStats::AddDownOverheadFileRequest(size
);
579 CMemFile
data(buffer
, size
);
580 CMD4Hash hash
= data
.ReadHash();
581 const CPartFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
582 m_client
->ProcessFileStatus(false, &data
, file
);
586 case OP_STARTUPLOADREQ
: {
587 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_STARTUPLOADREQ from ") + m_client
->GetFullIP() );
589 theStats::AddDownOverheadFileRequest(size
);
591 if (!m_client
->CheckHandshakeFinished()) {
595 m_client
->CheckForAggressive();
596 if ( m_client
->IsBanned() ) {
601 const CMD4Hash
fileID(buffer
);
602 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(fileID
);
604 if (m_client
->GetUploadFileID() != fileID
) {
605 m_client
->SetCommentDirty();
607 m_client
->SetUploadFileID(reqfile
);
608 m_client
->SendCommentInfo(reqfile
);
610 // Socket might die because of SendCommentInfo, so check
612 theApp
->uploadqueue
->AddClientToQueue(m_client
);
618 case OP_QUEUERANK
: { // 0.43b
619 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_QUEUERANK from ") + m_client
->GetFullIP() );
621 theStats::AddDownOverheadFileRequest(size
);
622 CMemFile
data(buffer
, size
);
623 uint32 rank
= data
.ReadUInt32();
625 m_client
->SetRemoteQueueRank(rank
);
629 case OP_ACCEPTUPLOADREQ
: { // 0.42e (xcept khaos stats)
630 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ACCEPTUPLOADREQ from ") + m_client
->GetFullIP() );
632 theStats::AddDownOverheadFileRequest(size
);
633 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
634 if (m_client
->GetDownloadState() == DS_ONQUEUE
) {
635 m_client
->SetDownloadState(DS_DOWNLOADING
);
636 m_client
->SetLastPartAsked(0xffff); // Reset current downloaded Chunk // Maella -Enhanced Chunk Selection- (based on jicxicmic)
637 m_client
->SendBlockRequests();
640 if (!m_client
->GetSentCancelTransfer()) {
641 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
642 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
643 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
644 m_client
->SendPacket(packet
,true,true);
646 // SendPacket can cause the socket to die, so check
648 m_client
->SetSentCancelTransfer(1);
652 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
657 case OP_REQUESTPARTS
: { // 0.43b
658 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
660 theStats::AddDownOverheadFileRequest(size
);
662 m_client
->ProcessRequestPartsPacket(buffer
, size
, false);
667 case OP_CANCELTRANSFER
: { // 0.43b
668 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CANCELTRANSFER from ") + m_client
->GetFullIP() );
670 theStats::AddDownOverheadFileRequest(size
);
671 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
672 AddDebugLogLineN( logClient
, m_client
->GetUserName() + wxT(": Upload session ended due canceled transfer."));
676 case OP_END_OF_DOWNLOAD
: { // 0.43b except check for bad clients
677 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_END_OF_DOWNLOAD from ") + m_client
->GetFullIP() );
679 theStats::AddDownOverheadFileRequest(size
);
680 if (size
>=16 && m_client
->GetUploadFileID() == CMD4Hash(buffer
)) {
681 theApp
->uploadqueue
->RemoveFromUploadQueue(m_client
);
682 AddDebugLogLineN( logClient
, m_client
->GetUserName() + wxT(": Upload session ended due ended transfer."));
687 case OP_HASHSETREQUEST
: { // 0.43b except check for bad clients
688 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_HASHSETREQUEST from ") + m_client
->GetFullIP() );
691 theStats::AddDownOverheadFileRequest(size
);
693 throw wxString(wxT("Invalid OP_HASHSETREQUEST packet size"));
695 m_client
->SendHashsetPacket(CMD4Hash(buffer
));
699 case OP_HASHSETANSWER
: { // 0.43b
700 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_HASHSETANSWER from ") + m_client
->GetFullIP() );
702 theStats::AddDownOverheadFileRequest(size
);
703 m_client
->ProcessHashSet(buffer
, size
);
707 case OP_SENDINGPART
: { // 0.47a
708 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SENDINGPART from ") + m_client
->GetFullIP() );
710 if ( m_client
->GetRequestFile() &&
711 !m_client
->GetRequestFile()->IsStopped() &&
712 (m_client
->GetRequestFile()->GetStatus() == PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
714 m_client
->ProcessBlockPacket(buffer
, size
, false, false);
717 ( m_client
->GetRequestFile()->IsStopped() ||
718 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
719 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
) ) {
720 if (!m_client
->GetSentCancelTransfer()) {
721 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
722 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
723 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
724 m_client
->SendPacket(packet
,true,true);
726 // Socket might die because of SendPacket, so check
728 m_client
->SetSentCancelTransfer(1);
732 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
735 if (!m_client
->GetSentCancelTransfer()) {
736 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
737 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
738 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
739 m_client
->SendPacket(packet
,true,true);
741 // Socket might die because of SendPacket, so check
742 m_client
->SetSentCancelTransfer(1);
744 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
749 case OP_OUTOFPARTREQS
: { // 0.43b
750 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_OUTOFPARTREQS from ") + m_client
->GetFullIP() );
752 theStats::AddDownOverheadFileRequest(size
);
753 if (m_client
->GetDownloadState() == DS_DOWNLOADING
) {
754 m_client
->SetDownloadState(DS_ONQUEUE
);
759 case OP_CHANGE_CLIENT_ID
: { // Kad reviewed
760 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CHANGE_CLIENT_ID from ") + m_client
->GetFullIP() );
762 theStats::AddDownOverheadOther(size
);
763 CMemFile
data(buffer
, size
);
764 uint32 nNewUserID
= data
.ReadUInt32();
765 uint32 nNewServerIP
= data
.ReadUInt32();
767 if (IsLowID(nNewUserID
)) { // client changed server and gots a LowID
768 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
769 if (pNewServer
!= NULL
){
770 m_client
->SetUserIDHybrid(nNewUserID
); // update UserID only if we know the server
771 m_client
->SetServerIP(nNewServerIP
);
772 m_client
->SetServerPort(pNewServer
->GetPort());
774 } else if (nNewUserID
== m_client
->GetIP()) { // client changed server and gots a HighID(IP)
775 m_client
->SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(nNewUserID
));
776 CServer
* pNewServer
= theApp
->serverlist
->GetServerByIP(nNewServerIP
);
777 if (pNewServer
!= NULL
){
778 m_client
->SetServerIP(nNewServerIP
);
779 m_client
->SetServerPort(pNewServer
->GetPort());
786 case OP_CHANGE_SLOT
:{ // 0.43b
787 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CHANGE_SLOT from ") + m_client
->GetFullIP() );
789 // sometimes sent by Hybrid
790 theStats::AddDownOverheadOther(size
);
794 case OP_MESSAGE
: { // 0.43b
795 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MESSAGE from ") + m_client
->GetFullIP() );
797 theStats::AddDownOverheadOther(size
);
800 throw wxString(wxT("invalid message packet"));
802 CMemFile
message_file(buffer
, size
);
803 uint16 length
= message_file
.ReadUInt16();
804 if (length
+ 2u != size
) {
805 throw wxString(wxT("invalid message packet"));
808 // limit message length
809 static const uint16 MAX_CLIENT_MSG_LEN
= 450;
811 if (length
> MAX_CLIENT_MSG_LEN
) {
812 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Message from '%s' (IP:%s) exceeds limit by %u chars, truncated."))
813 % m_client
->GetUserName() % m_client
->GetFullIP() % (length
- MAX_CLIENT_MSG_LEN
));
814 length
= MAX_CLIENT_MSG_LEN
;
817 wxString message
= message_file
.ReadOnlyString((m_client
->GetUnicodeSupport() != utf8strNone
), length
);
818 m_client
->ProcessChatMessage(message
);
823 case OP_ASKSHAREDFILES
: { // 0.43b (well, er, it does the same, but in our own way)
824 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILES from ") + m_client
->GetFullIP() );
826 // client wants to know what we have in share, let's see if we allow him to know that
827 theStats::AddDownOverheadOther(size
);
828 // IP banned, no answer for this request
829 if (m_client
->IsBanned()) {
833 if (thePrefs::CanSeeShares() == vsfaEverybody
|| (thePrefs::CanSeeShares() == vsfaFriends
&& m_client
->IsFriend())) {
834 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Accepted"))
835 % m_client
->GetUserName()
836 % m_client
->GetUserIDHybrid() );
838 std::vector
<CKnownFile
*> list
;
839 theApp
->sharedfiles
->CopyFileList(list
);
841 CMemFile
tempfile(80);
842 tempfile
.WriteUInt32(list
.size());
843 for (unsigned i
= 0; i
< list
.size(); ++i
) {
844 if (!list
[i
]->IsLargeFile() || m_client
->SupportsLargeFiles()) {
845 theApp
->sharedfiles
->CreateOfferedFilePacket(list
[i
], &tempfile
, NULL
, m_client
);
849 // create a packet and send it
850 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESANSWER
);
851 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESANSWER to ") + m_client
->GetFullIP() );
852 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
853 SendPacket(replypacket
, true, true);
855 AddLogLineC(CFormat( _("User %s (%u) requested your sharedfiles-list -> Denied"))
856 % m_client
->GetUserName()
857 % m_client
->GetUserIDHybrid() );
859 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
860 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
861 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
862 SendPacket(replypacket
, true, true);
868 case OP_ASKSHAREDFILESANSWER
: { // 0.43b
869 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESANSWER from ") + m_client
->GetFullIP() );
871 theStats::AddDownOverheadOther(size
);
873 m_client
->ProcessSharedFileList(buffer
, size
, EmptyStr
);
877 case OP_ASKSHAREDDIRS
: { // 0.43b
878 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRS from ") + m_client
->GetFullIP() );
880 theStats::AddDownOverheadOther(size
);
881 wxASSERT( size
== 0 );
882 // IP banned, no answer for this request
883 if (m_client
->IsBanned()) {
886 if ((thePrefs::CanSeeShares()==vsfaEverybody
) || ((thePrefs::CanSeeShares()==vsfaFriends
) && m_client
->IsFriend())) {
887 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Accepted") )
888 % m_client
->GetUserName()
889 % m_client
->GetUserIDHybrid() );
891 // This list will contain all (unique) folders.
892 std::list
<CPath
> foldersToSend
;
894 // The shared folders
895 const unsigned folderCount
= theApp
->glob_prefs
->shareddir_list
.size();
896 for (unsigned i
= 0; i
< folderCount
; ++i
) {
897 foldersToSend
.push_back(theApp
->glob_prefs
->shareddir_list
[i
]);
900 // ... the categories folders ... (category 0 -> incoming)
901 for (unsigned i
= 0; i
< theApp
->glob_prefs
->GetCatCount(); ++i
) {
902 foldersToSend
.push_back(theApp
->glob_prefs
->GetCategory(i
)->path
);
905 // ... and the Magic thing from the eDonkey Hybrids...
906 foldersToSend
.push_back(CPath(OP_INCOMPLETE_SHARED_FILES
));
909 foldersToSend
.sort();
910 foldersToSend
.unique();
913 CMemFile
tempfile(80);
914 tempfile
.WriteUInt32(foldersToSend
.size());
916 std::list
<CPath
>::iterator it
= foldersToSend
.begin();
917 for (; it
!= foldersToSend
.end(); ++it
) {
918 // We need to send the 'raw' filename, so we can recognize it again.
919 tempfile
.WriteString(it
->GetRaw(), m_client
->GetUnicodeSupport());
922 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDDIRSANS
);
923 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
924 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + m_client
->GetFullIP() );
925 SendPacket(replypacket
, true, true);
927 AddLogLineC(CFormat( _("User %s (%u) requested your shareddirectories-list -> Denied") )
928 % m_client
->GetUserName()
929 % m_client
->GetUserIDHybrid() );
931 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
932 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
933 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
934 SendPacket(replypacket
, true, true);
940 case OP_ASKSHAREDFILESDIR
: { // 0.43b
941 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIR from ") + m_client
->GetFullIP() );
943 theStats::AddDownOverheadOther(size
);
944 // IP banned, no answer for this request
945 if (m_client
->IsBanned()) {
948 CMemFile
data(buffer
, size
);
950 wxString strReqDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
951 if (thePrefs::CanSeeShares()==vsfaEverybody
|| (thePrefs::CanSeeShares()==vsfaFriends
&& m_client
->IsFriend())) {
952 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> accepted")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
953 wxASSERT( data
.GetPosition() == data
.GetLength() );
955 CKnownFilePtrList list
;
957 if (strReqDir
== OP_INCOMPLETE_SHARED_FILES
) {
958 // get all shared files from download queue
959 int iQueuedFiles
= theApp
->downloadqueue
->GetFileCount();
960 for (int i
= 0; i
< iQueuedFiles
; i
++) {
961 CPartFile
* pFile
= theApp
->downloadqueue
->GetFileByIndex(i
);
962 if (pFile
== NULL
|| pFile
->GetStatus(true) != PS_READY
) {
966 list
.push_back(pFile
);
969 theApp
->sharedfiles
->GetSharedFilesByDirectory(strReqDir
, list
);
972 CMemFile
tempfile(80);
973 tempfile
.WriteString(strReqDir
, m_client
->GetUnicodeSupport());
974 tempfile
.WriteUInt32(list
.size());
976 while (!list
.empty()) {
977 if (!list
.front()->IsLargeFile() || m_client
->SupportsLargeFiles()) {
978 theApp
->sharedfiles
->CreateOfferedFilePacket(list
.front(), &tempfile
, NULL
, m_client
);
984 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIRANS
);
985 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
986 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + m_client
->GetFullIP() );
987 SendPacket(replypacket
, true, true);
989 AddLogLineC(CFormat(_("User %s (%u) requested your sharedfiles-list for directory %s -> denied")) % m_client
->GetUserName() % m_client
->GetUserIDHybrid() % strReqDir
);
991 CPacket
* replypacket
= new CPacket(OP_ASKSHAREDDENIEDANS
, 0, OP_EDONKEYPROT
);
992 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
993 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDENIEDANS to ") + m_client
->GetFullIP() );
994 SendPacket(replypacket
, true, true);
999 case OP_ASKSHAREDDIRSANS
:{ // 0.43b
1000 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDIRSANS from ") + m_client
->GetFullIP() );
1002 theStats::AddDownOverheadOther(size
);
1003 if (m_client
->GetFileListRequested() == 1){
1004 CMemFile
data(buffer
, size
);
1005 uint32 uDirs
= data
.ReadUInt32();
1006 for (uint32 i
= 0; i
< uDirs
; i
++){
1007 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
1008 AddLogLineC(CFormat( _("User %s (%u) shares directory %s") )
1009 % m_client
->GetUserName()
1010 % m_client
->GetUserIDHybrid()
1013 CMemFile
tempfile(80);
1014 tempfile
.WriteString(strDir
, m_client
->GetUnicodeSupport());
1015 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIR
);
1016 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
1017 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESD to ") + m_client
->GetFullIP() );
1018 SendPacket(replypacket
, true, true);
1020 wxASSERT( data
.GetPosition() == data
.GetLength() );
1021 m_client
->SetFileListRequested(uDirs
);
1023 AddLogLineC(CFormat( _("User %s (%u) sent unrequested shared dirs.") )
1024 % m_client
->GetUserName()
1025 % m_client
->GetUserIDHybrid() );
1030 case OP_ASKSHAREDFILESDIRANS
: { // 0.43b
1031 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDFILESDIRANS from ") + m_client
->GetFullIP() );
1033 theStats::AddDownOverheadOther(size
);
1034 CMemFile
data(buffer
, size
);
1035 wxString strDir
= data
.ReadString((m_client
->GetUnicodeSupport() != utf8strNone
));
1037 if (m_client
->GetFileListRequested() > 0){
1038 AddLogLineC(CFormat( _("User %s (%u) sent sharedfiles-list for directory %s") )
1039 % m_client
->GetUserName()
1040 % m_client
->GetUserIDHybrid()
1043 m_client
->ProcessSharedFileList(buffer
+ data
.GetPosition(), size
- data
.GetPosition(), strDir
);
1044 if (m_client
->GetFileListRequested() == 0) {
1045 AddLogLineC(CFormat( _("User %s (%u) finished sending sharedfiles-list") )
1046 % m_client
->GetUserName()
1047 % m_client
->GetUserIDHybrid() );
1050 AddLogLineC(CFormat( _("User %s (%u) sent unwanted sharedfiles-list") )
1051 % m_client
->GetUserName()
1052 % m_client
->GetUserIDHybrid() );
1057 case OP_ASKSHAREDDENIEDANS
:
1058 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ASKSHAREDDENIEDANS from ") + m_client
->GetFullIP() );
1060 theStats::AddDownOverheadOther(size
);
1061 wxASSERT( size
== 0 );
1062 AddLogLineC(CFormat( _("User %s (%u) denied access to shared directories/files list") )
1063 % m_client
->GetUserName()
1064 % m_client
->GetUserIDHybrid() );
1066 m_client
->SetFileListRequested(0);
1070 theStats::AddDownOverheadOther(size
);
1071 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Edonkey packet: unknown opcode: %i %x from %s")) % opcode
% opcode
% m_client
->GetFullIP());
1079 bool CClientTCPSocket::ProcessExtPacket(const byte
* buffer
, uint32 size
, uint8 opcode
)
1081 #ifdef __PACKET_RECV_DUMP__
1082 //printf("Rec: OPCODE %x \n",opcode);
1083 DumpMem(buffer
,size
);
1086 // 0.42e - except the catchs on mem exception and file exception
1088 throw wxString(wxT("Unknown clients sends extended protocol packet"));
1091 if (!client->CheckHandshakeFinished()) {
1092 // Here comes an extended packet without finishing the handshake.
1093 // IMHO, we should disconnect the client.
1094 throw wxString(wxT("Client send extended packet before finishing handshake"));
1098 case OP_MULTIPACKET_EXT
:
1099 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET_EXT from ") + m_client
->GetFullIP());
1100 case OP_MULTIPACKET
: {
1101 if (opcode
== OP_MULTIPACKET
) AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET from ") + m_client
->GetFullIP() );
1103 theStats::AddDownOverheadFileRequest(size
);
1105 if (m_client
->IsBanned()) {
1109 if (!m_client
->CheckHandshakeFinished()) {
1110 // Here comes an extended packet without finishing the handshake.
1111 // IMHO, we should disconnect the client.
1112 throw wxString(wxT("Client send OP_MULTIPACKET before finishing handshake"));
1115 CMemFile
data_in(buffer
, size
);
1116 CMD4Hash reqfilehash
= data_in
.ReadHash();
1117 uint64 nSize
= (opcode
== OP_MULTIPACKET_EXT
) ? data_in
.ReadUInt64() : 0;
1119 bool file_not_found
= false;
1120 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(reqfilehash
);
1121 if ( reqfile
== NULL
){
1122 reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1123 if ( !( reqfile
!= NULL
&& reqfile
->GetFileSize() > PARTSIZE
) ) {
1124 AddDebugLogLineN(logRemoteClient
, wxT("Remote client asked for a non-shared file"));
1125 file_not_found
= true;
1129 if (!file_not_found
&& reqfile
->IsLargeFile() && !m_client
->SupportsLargeFiles()) {
1130 AddDebugLogLineN(logRemoteClient
, wxT("Remote client asked for a large file but doesn't support them"));
1131 file_not_found
= true;
1134 if (!file_not_found
&& nSize
&& (reqfile
->GetFileSize() != nSize
)) {
1135 AddDebugLogLineN(logRemoteClient
, wxT("Remote client asked for a file but specified wrong size"));
1136 file_not_found
= true;
1139 if (file_not_found
) {
1140 CPacket
* replypacket
= new CPacket(OP_FILEREQANSNOFIL
, 16, OP_EDONKEYPROT
);
1141 replypacket
->Copy16ToDataBuffer(reqfilehash
.GetHash());
1142 theStats::AddUpOverheadFileRequest(replypacket
->GetPacketSize());
1143 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILEREQANSNOFIL to ") + m_client
->GetFullIP() );
1144 SendPacket(replypacket
, true);
1148 if (!m_client
->GetWaitStartTime()) {
1149 m_client
->SetWaitStartTime();
1151 // if we are downloading this file, this could be a new source
1152 // no passive adding of files with only one part
1153 if (reqfile
->IsPartFile() && reqfile
->GetFileSize() > PARTSIZE
) {
1154 if (thePrefs::GetMaxSourcePerFile() > ((CPartFile
*)reqfile
)->GetSourceCount()) {
1155 theApp
->downloadqueue
->CheckAndAddKnownSource((CPartFile
*)reqfile
, m_client
);
1158 // check to see if this is a new file they are asking for
1159 if (m_client
->GetUploadFileID() != reqfilehash
) {
1160 m_client
->SetCommentDirty();
1162 m_client
->SetUploadFileID(reqfile
);
1163 CMemFile
data_out(128);
1164 data_out
.WriteHash(reqfile
->GetFileHash());
1165 while(data_in
.GetLength()-data_in
.GetPosition()) {
1167 throw wxString(wxT("Client suddenly disconnected"));
1169 uint8 opcode_in
= data_in
.ReadUInt8();
1171 case OP_REQUESTFILENAME
: {
1172 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTFILENAME") );
1173 m_client
->ProcessExtendedInfo(&data_in
, reqfile
);
1174 data_out
.WriteUInt8(OP_REQFILENAMEANSWER
);
1176 // Since it's for somebody else to see, we need to send the prettified
1177 // filename, rather than the (possibly) mangled actual filename
1178 data_out
.WriteString(reqfile
->GetFileName().GetPrintable(), m_client
->GetUnicodeSupport());
1181 case OP_AICHFILEHASHREQ
: {
1182 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_AICHFILEHASHANS") );
1183 if (m_client
->IsSupportingAICH() && reqfile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1184 && reqfile
->GetAICHHashset()->HasValidMasterHash())
1186 data_out
.WriteUInt8(OP_AICHFILEHASHANS
);
1187 reqfile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1191 case OP_SETREQFILEID
: {
1192 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_SETREQFILEID") );
1193 data_out
.WriteUInt8(OP_FILESTATUS
);
1194 if (reqfile
->IsPartFile()) {
1195 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1197 data_out
.WriteUInt16(0);
1201 //We still send the source packet separately..
1202 //We could send it within this packet.. If agreeded, I will fix it..
1203 case OP_REQUESTSOURCES2
:
1204 case OP_REQUESTSOURCES
: {
1205 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKET has OP_REQUESTSOURCES(2)") );
1206 uint8 byRequestedVersion
= 0;
1207 uint16 byRequestedOptions
= 0;
1208 if (opcode_in
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1209 byRequestedVersion
= data_in
.ReadUInt8();
1210 byRequestedOptions
= data_in
.ReadUInt16();
1213 //Although this shouldn't happen, it's a just in case to any Mods that mess with version numbers.
1215 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() > 1) {
1216 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1217 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1219 //if not complete and file is rare
1220 ( reqfile
->IsPartFile()
1221 && (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1222 && ((CPartFile
*)reqfile
)->GetSourceCount() <= RARE_FILE
1224 //OR if file is not rare or if file is complete
1225 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1228 m_client
->SetLastSrcReqTime();
1229 CPacket
* tosend
= reqfile
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1231 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1232 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1233 SendPacket(tosend
, true);
1242 if( data_out
.GetLength() > 16 ) {
1243 CPacket
* reply
= new CPacket(data_out
, OP_EMULEPROT
, OP_MULTIPACKETANSWER
);
1244 theStats::AddUpOverheadFileRequest(reply
->GetPacketSize());
1245 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_MULTIPACKETANSWER to ") + m_client
->GetFullIP() );
1246 SendPacket(reply
, true);
1251 case OP_MULTIPACKETANSWER
: { // 0.43b
1252 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_MULTIPACKETANSWER from ") + m_client
->GetFullIP() );
1254 theStats::AddDownOverheadFileRequest(size
);
1256 if (m_client
->IsBanned()) {
1260 if (m_client
->GetKadPort() && m_client
->GetKadVersion() > 1) {
1261 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(m_client
->GetIP()), m_client
->GetKadPort());
1264 if (!m_client
->CheckHandshakeFinished()) {
1265 // Here comes an extended packet without finishing the handshake.
1266 // IMHO, we should disconnect the client.
1267 throw wxString(wxT("Client send OP_MULTIPACKETANSWER before finishing handshake"));
1270 CMemFile
data_in(buffer
, size
);
1271 CMD4Hash reqfilehash
= data_in
.ReadHash();
1272 const CPartFile
*reqfile
= theApp
->downloadqueue
->GetFileByID(reqfilehash
);
1273 //Make sure we are downloading this file.
1275 throw wxString(wxT(" Wrong File ID: (OP_MULTIPACKETANSWER; reqfile==NULL)"));
1277 if ( !m_client
->GetRequestFile() ) {
1279 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; client->reqfile==NULL)"));
1281 if (reqfile
!= m_client
->GetRequestFile()) {
1282 throw wxString(wxT(" Wrong File ID: OP_MULTIPACKETANSWER; reqfile!=client->reqfile)"));
1284 while (data_in
.GetLength()-data_in
.GetPosition()) {
1285 // Some of the cases down there can actually send a packet and lose the client
1287 throw wxString(wxT("Client suddenly disconnected"));
1289 uint8 opcode_in
= data_in
.ReadUInt8();
1291 case OP_REQFILENAMEANSWER
: {
1293 throw wxString(wxT("Client suddenly disconnected"));
1295 m_client
->ProcessFileInfo(&data_in
, reqfile
);
1299 case OP_FILESTATUS
: {
1301 throw wxString(wxT("Client suddenly disconnected"));
1303 m_client
->ProcessFileStatus(false, &data_in
, reqfile
);
1307 case OP_AICHFILEHASHANS
: {
1309 throw wxString(wxT("Client suddenly disconnected"));
1311 m_client
->ProcessAICHFileHash(&data_in
, reqfile
);
1321 case OP_EMULEINFO
: { // 0.43b
1322 theStats::AddDownOverheadOther(size
);
1324 if (!m_client
->ProcessMuleInfoPacket(buffer
, size
)) {
1325 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_EMULEINFO from ") + m_client
->GetFullIP() );
1327 // If it's not a OS Info packet, is an old client
1328 // start secure identification, if
1329 // - we have received eD2K and eMule info (old eMule)
1330 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1331 m_client
->InfoPacketsReceived();
1333 m_client
->SendMuleInfoPacket(true);
1335 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_EMULEINFO is an OS_INFO") );
1339 case OP_EMULEINFOANSWER
: { // 0.43b
1340 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_EMULEINFOANSWER from ") + m_client
->GetFullIP() );
1341 theStats::AddDownOverheadOther(size
);
1343 m_client
->ProcessMuleInfoPacket(buffer
, size
);
1344 // start secure identification, if
1345 // - we have received eD2K and eMule info (old eMule)
1347 if (m_client
->GetInfoPacketsReceived() == IP_BOTH
) {
1348 m_client
->InfoPacketsReceived();
1354 case OP_SECIDENTSTATE
:{ // 0.43b
1355 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SECIDENTSTATE from ") + m_client
->GetFullIP() );
1357 if (!m_client
->CheckHandshakeFinished()) {
1358 // Here comes an extended packet without finishing the handshake.
1359 // IMHO, we should disconnect the client.
1360 throw wxString(wxT("Client send OP_SECIDENTSTATE before finishing handshake"));
1362 m_client
->ProcessSecIdentStatePacket(buffer
, size
);
1363 // ProcessSecIdentStatePacket() might cause the socket to die, so check
1365 int SecureIdentState
= m_client
->GetSecureIdentState();
1366 if (SecureIdentState
== IS_SIGNATURENEEDED
) {
1367 m_client
->SendSignaturePacket();
1368 } else if (SecureIdentState
== IS_KEYANDSIGNEEDED
) {
1369 m_client
->SendPublicKeyPacket();
1370 // SendPublicKeyPacket() might cause the socket to die, so check
1372 m_client
->SendSignaturePacket();
1379 case OP_PUBLICKEY
: { // 0.43b
1380 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PUBLICKEY from ") + m_client
->GetFullIP() );
1382 if (m_client
->IsBanned() ){
1386 if (!m_client
->CheckHandshakeFinished()) {
1387 // Here comes an extended packet without finishing the handshake.
1388 // IMHO, we should disconnect the client.
1389 throw wxString(wxT("Client send OP_PUBLICKEY before finishing handshake"));
1392 m_client
->ProcessPublicKeyPacket(buffer
, size
);
1395 case OP_SIGNATURE
:{ // 0.43b
1396 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SIGNATURE from ") + m_client
->GetFullIP() );
1398 if (!m_client
->CheckHandshakeFinished()) {
1399 // Here comes an extended packet without finishing the handshake.
1400 // IMHO, we should disconnect the client.
1401 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1404 m_client
->ProcessSignaturePacket(buffer
, size
);
1407 case OP_SENDINGPART_I64
:
1408 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_SENDINGPART_I64 from ") + m_client
->GetFullIP() );
1409 case OP_COMPRESSEDPART_I64
:
1410 if (opcode
== OP_COMPRESSEDPART_I64
) AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART_I64 from ") + m_client
->GetFullIP() );
1411 case OP_COMPRESSEDPART
: { // 0.47a
1412 if (opcode
== OP_COMPRESSEDPART
) AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_COMPRESSEDPART from ") + m_client
->GetFullIP() );
1414 if (!m_client
->CheckHandshakeFinished()) {
1415 // Here comes an extended packet without finishing the handshake.
1416 // IMHO, we should disconnect the client.
1417 throw wxString(wxT("Client send OP_COMPRESSEDPART before finishing handshake"));
1420 if (m_client
->GetRequestFile() && !m_client
->GetRequestFile()->IsStopped() && (m_client
->GetRequestFile()->GetStatus()==PS_READY
|| m_client
->GetRequestFile()->GetStatus()==PS_EMPTY
)) {
1422 m_client
->ProcessBlockPacket(buffer
, size
, (opcode
!= OP_SENDINGPART_I64
), (opcode
== OP_COMPRESSEDPART_I64
) || (opcode
== OP_SENDINGPART_I64
));
1425 m_client
->GetRequestFile()->IsStopped() ||
1426 m_client
->GetRequestFile()->GetStatus() == PS_PAUSED
||
1427 m_client
->GetRequestFile()->GetStatus() == PS_ERROR
)) {
1428 if (!m_client
->GetSentCancelTransfer()) {
1429 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1430 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1431 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1432 m_client
->SendPacket(packet
,true,true);
1435 m_client
->SetSentCancelTransfer(1);
1440 m_client
->SetDownloadState(m_client
->GetRequestFile()->IsStopped() ? DS_NONE
: DS_ONQUEUE
);
1444 if (!m_client
->GetSentCancelTransfer()) {
1445 CPacket
* packet
= new CPacket(OP_CANCELTRANSFER
, 0, OP_EDONKEYPROT
);
1446 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1447 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_CANCELTRANSFER to ") + m_client
->GetFullIP() );
1448 m_client
->SendPacket(packet
,true,true);
1451 m_client
->SetSentCancelTransfer(1);
1456 m_client
->SetDownloadState((m_client
->GetRequestFile()==NULL
|| m_client
->GetRequestFile()->IsStopped()) ? DS_NONE
: DS_ONQUEUE
);
1461 case OP_REQUESTPARTS_I64
: {
1462 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTPARTS_I64 from ") + m_client
->GetFullIP() );
1464 theStats::AddDownOverheadFileRequest(size
);
1466 m_client
->ProcessRequestPartsPacket(buffer
, size
, true);
1470 case OP_QUEUERANKING
: { // 0.43b
1471 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_QUEUERANKING from ") + m_client
->GetFullIP() );
1473 theStats::AddDownOverheadOther(size
);
1475 if (!m_client
->CheckHandshakeFinished()) {
1476 // Here comes an extended packet without finishing the handshake.
1477 // IMHO, we should disconnect the client.
1478 throw wxString(wxT("Client send OP_QUEUERANKING before finishing handshake"));
1482 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1485 uint16 newrank
= PeekUInt16(buffer
);
1486 m_client
->SetRemoteQueueFull(false);
1487 m_client
->SetRemoteQueueRank(newrank
);
1490 case OP_REQUESTSOURCES2
:
1491 case OP_REQUESTSOURCES
:{
1492 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTSOURCES from ") + m_client
->GetFullIP() );
1494 theStats::AddDownOverheadSourceExchange(size
);
1496 if (!m_client
->CheckHandshakeFinished()) {
1497 // Here comes an extended packet without finishing the handshake.
1498 // IMHO, we should disconnect the client.
1499 throw wxString(wxT("Client send OP_REQUESTSOURCES before finishing handshake"));
1502 uint8 byRequestedVersion
= 0;
1503 uint16 byRequestedOptions
= 0;
1504 CMemFile
data_in(buffer
, size
);
1505 if (opcode
== OP_REQUESTSOURCES2
){ // SX2 requests contains additional data
1506 byRequestedVersion
= data_in
.ReadUInt8();
1507 byRequestedOptions
= data_in
.ReadUInt16();
1510 if (byRequestedVersion
> 0 || m_client
->GetSourceExchange1Version() >= 1) {
1512 throw wxString(wxT("Invalid size (OP_QUEUERANKING)"));
1514 //first check shared file list, then download list
1515 const CMD4Hash
fileID(buffer
);
1516 CKnownFile
* file
= theApp
->sharedfiles
->GetFileByID(fileID
);
1518 file
= theApp
->downloadqueue
->GetFileByID(fileID
);
1521 // There are some clients which do not follow the correct protocol procedure of sending
1522 // the sequence OP_REQUESTFILENAME, OP_SETREQFILEID, OP_REQUESTSOURCES. If those clients
1523 // are doing this, they will not get the optimal set of sources which we could offer if
1524 // they would follow the above noted protocol sequence. They better do it the right way
1525 // or they will get just a random set of sources because we do not know their download
1526 // part status which may get cleared with the call of 'SetUploadFileID'.
1527 m_client
->SetUploadFileID(file
);
1529 uint32 dwTimePassed
= ::GetTickCount() - m_client
->GetLastSrcReqTime() + CONNECTION_LATENCY
;
1530 bool bNeverAskedBefore
= m_client
->GetLastSrcReqTime() == 0;
1532 //if not complete and file is rare, allow once every 40 minutes
1533 ( file
->IsPartFile() &&
1534 ((CPartFile
*)file
)->GetSourceCount() <= RARE_FILE
&&
1535 (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
)
1537 //OR if file is not rare or if file is complete, allow every 90 minutes
1538 ( (bNeverAskedBefore
|| dwTimePassed
> SOURCECLIENTREASKS
* MINCOMMONPENALTY
) )
1541 m_client
->SetLastSrcReqTime();
1542 CPacket
* tosend
= file
->CreateSrcInfoPacket(m_client
, byRequestedVersion
, byRequestedOptions
);
1544 theStats::AddUpOverheadSourceExchange(tosend
->GetPacketSize());
1545 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ANSWERSOURCES to ") + m_client
->GetFullIP() );
1546 SendPacket(tosend
, true, true);
1553 case OP_ANSWERSOURCES
: {
1554 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_ANSWERSOURCES from ") + m_client
->GetFullIP() );
1556 theStats::AddDownOverheadSourceExchange(size
);
1558 if (!m_client
->CheckHandshakeFinished()) {
1559 // Here comes an extended packet without finishing the handshake.
1560 // IMHO, we should disconnect the client.
1561 throw wxString(wxT("Client send OP_ANSWERSOURCES before finishing handshake"));
1564 CMemFile
data(buffer
, size
);
1565 CMD4Hash hash
= data
.ReadHash();
1566 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1568 if (file
->IsPartFile()){
1569 //set the client's answer time
1570 m_client
->SetLastSrcAnswerTime();
1571 //and set the file's last answer time
1572 ((CPartFile
*)file
)->SetLastAnsweredTime();
1574 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, m_client
->GetSourceExchange1Version(), false, m_client
);
1579 case OP_ANSWERSOURCES2
: {
1580 //printf("Received OP_ANSWERSOURCES2\n");
1581 theStats::AddDownOverheadSourceExchange(size
);
1583 if (!m_client
->CheckHandshakeFinished()) {
1584 // Here comes an extended packet without finishing the handshake.
1585 // IMHO, we should disconnect the client.
1586 throw wxString(wxT("Client send OP_ANSWERSOURCES2 before finishing handshake"));
1589 CMemFile
data(buffer
, size
);
1590 uint8 byVersion
= data
.ReadUInt8();
1591 CMD4Hash hash
= data
.ReadHash();
1592 const CKnownFile
* file
= theApp
->downloadqueue
->GetFileByID(hash
);
1594 if (file
->IsPartFile()){
1595 //set the client's answer time
1596 m_client
->SetLastSrcAnswerTime();
1597 //and set the file's last answer time
1598 ((CPartFile
*)file
)->SetLastAnsweredTime();
1599 ((CPartFile
*)file
)->AddClientSources(&data
, SF_SOURCE_EXCHANGE
, byVersion
, true, m_client
);
1604 case OP_FILEDESC
: { // 0.43b
1605 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_FILEDESC from ") + m_client
->GetFullIP() );
1607 theStats::AddDownOverheadFileRequest(size
);
1609 if (!m_client
->CheckHandshakeFinished()) {
1610 // Here comes an extended packet without finishing the handshake.
1611 // IMHO, we should disconnect the client.
1612 throw wxString(wxT("Client send OP_FILEDESC before finishing handshake"));
1615 m_client
->ProcessMuleCommentPacket(buffer
, size
);
1620 case OP_REQUESTPREVIEW
: {
1621 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REQUESTPREVIEW from ") + m_client
->GetFullIP() );
1625 case OP_PREVIEWANSWER
: {
1626 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PREVIEWANSWER from ") + m_client
->GetFullIP() );
1630 case OP_PUBLICIP_ANSWER
: {
1631 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_ANSWER from ") + m_client
->GetFullIP() );
1632 theStats::AddDownOverheadOther(size
);
1633 m_client
->ProcessPublicIPAnswer(buffer
, size
);
1636 case OP_PUBLICIP_REQ
: {
1637 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_PUBLICIP_REQ from ") + m_client
->GetFullIP() );
1638 theStats::AddDownOverheadOther(size
);
1639 CPacket
* pPacket
= new CPacket(OP_PUBLICIP_ANSWER
, 4, OP_EMULEPROT
);
1640 pPacket
->CopyUInt32ToDataBuffer(m_client
->GetIP());
1641 theStats::AddUpOverheadOther(pPacket
->GetPacketSize());
1642 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_PUBLICIP_ANSWER to") + m_client
->GetFullIP());
1643 SendPacket(pPacket
);
1646 case OP_AICHANSWER
: {
1647 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHANSWER from ") + m_client
->GetFullIP() );
1648 theStats::AddDownOverheadOther(size
);
1649 m_client
->ProcessAICHAnswer(buffer
, size
);
1652 case OP_AICHREQUEST
: {
1653 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHREQUEST from ") + m_client
->GetFullIP() );
1654 theStats::AddDownOverheadOther(size
);
1655 m_client
->ProcessAICHRequest(buffer
, size
);
1658 case OP_AICHFILEHASHANS
: {
1659 // those should not be received normally, since we should only get those in MULTIPACKET
1660 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHANS from ") + m_client
->GetFullIP() );
1661 theStats::AddDownOverheadOther(size
);
1662 CMemFile
data(buffer
, size
);
1663 m_client
->ProcessAICHFileHash(&data
, NULL
);
1666 case OP_AICHFILEHASHREQ
: {
1667 // those should not be received normally, since we should only get those in MULTIPACKET
1668 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_AICHFILEHASHREQ from ") + m_client
->GetFullIP() );
1669 CMemFile
data(buffer
, size
);
1670 CMD4Hash hash
= data
.ReadHash();
1671 CKnownFile
* pPartFile
= theApp
->sharedfiles
->GetFileByID(hash
);
1672 if (pPartFile
== NULL
){
1676 if (m_client
->IsSupportingAICH() && pPartFile
->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE
1677 && pPartFile
->GetAICHHashset()->HasValidMasterHash()) {
1679 data_out
.WriteHash(hash
);
1680 pPartFile
->GetAICHHashset()->GetMasterHash().Write(&data_out
);
1681 CPacket
* packet
= new CPacket(data_out
, OP_EMULEPROT
, OP_AICHFILEHASHANS
);
1682 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1683 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_AICHFILEHASHANS to") + m_client
->GetFullIP());
1689 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_CALLBACK from ") + m_client
->GetFullIP() );
1690 theStats::AddDownOverheadFileRequest(size
);
1691 if(!Kademlia::CKademlia::IsRunning()) {
1694 CMemFile
data(buffer
, size
);
1695 CUInt128 check
= data
.ReadUInt128();
1696 check
.XOR(Kademlia::CUInt128(true));
1697 if( check
.CompareTo(Kademlia::CKademlia::GetPrefs()->GetKadID())) {
1700 CUInt128 fileid
= data
.ReadUInt128();
1702 fileid
.ToByteArray(fileid2
);
1703 const CMD4Hash
fileHash(fileid2
);
1704 if (theApp
->sharedfiles
->GetFileByID(fileHash
) == NULL
) {
1705 if (theApp
->downloadqueue
->GetFileByID(fileHash
) == NULL
) {
1710 uint32 ip
= data
.ReadUInt32();
1711 uint16 tcp
= data
.ReadUInt16();
1712 CUpDownClient
* callback
;
1713 callback
= theApp
->clientlist
->FindClientByIP(wxUINT32_SWAP_ALWAYS(ip
), tcp
);
1714 if( callback
== NULL
) {
1715 //#warning Do we actually have to check friend status here?
1716 callback
= new CUpDownClient(tcp
,ip
,0,0,NULL
,false, false);
1717 theApp
->clientlist
->AddClient(callback
);
1719 callback
->TryToConnect(true);
1723 case OP_BUDDYPING
: {
1724 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_BUDDYPING from ") + m_client
->GetFullIP() );
1725 theStats::AddDownOverheadKad(size
);
1727 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1728 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 || !m_client
->AllowIncomeingBuddyPingPong() ) {
1729 //This ping was not from our buddy or wrong version or packet sent to fast. Ignore
1733 m_client
->SetLastBuddyPingPongTime();
1734 CPacket
* replypacket
= new CPacket(OP_BUDDYPONG
, 0, OP_EMULEPROT
);
1735 theStats::AddUpOverheadKad(replypacket
->GetPacketSize());
1736 AddDebugLogLineN(logLocalClient
,wxT("Local Client: OP_BUDDYPONG to ") + m_client
->GetFullIP());
1737 SendPacket(replypacket
);
1740 case OP_BUDDYPONG
: {
1741 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_BUDDYPONG from ") + m_client
->GetFullIP() );
1742 theStats::AddDownOverheadKad(size
);
1744 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1745 if( buddy
!= m_client
|| m_client
->GetKadVersion() == 0 ) {
1746 //This pong was not from our buddy or wrong version. Ignore
1749 m_client
->SetLastBuddyPingPongTime();
1750 //All this is for is to reset our socket timeout.
1753 case OP_REASKCALLBACKTCP
: {
1754 theStats::AddDownOverheadFileRequest(size
);
1755 CUpDownClient
* buddy
= theApp
->clientlist
->GetBuddy();
1756 if (buddy
!= m_client
) {
1757 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() + wxT(" which is not our buddy!") );
1758 //This callback was not from our buddy.. Ignore.
1761 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: OP_REASKCALLBACKTCP from ") + m_client
->GetFullIP() );
1762 CMemFile
data_in(buffer
, size
);
1763 uint32 destip
= data_in
.ReadUInt32();
1764 uint16 destport
= data_in
.ReadUInt16();
1765 CMD4Hash hash
= data_in
.ReadHash();
1766 CKnownFile
* reqfile
= theApp
->sharedfiles
->GetFileByID(hash
);
1768 bool bSenderMultipleIpUnknown
= false;
1769 CUpDownClient
* sender
= theApp
->uploadqueue
->GetWaitingClientByIP_UDP(destip
, destport
, true, &bSenderMultipleIpUnknown
);
1771 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_FILENOTFOUND to ") + m_client
->GetFullIP() );
1772 CPacket
* response
= new CPacket(OP_FILENOTFOUND
,0,OP_EMULEPROT
);
1773 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1775 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1777 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1783 //Make sure we are still thinking about the same file
1784 if (hash
== sender
->GetUploadFileID()) {
1785 sender
->AddAskedCount();
1786 sender
->SetLastUpRequest();
1787 //I messed up when I first added extended info to UDP
1788 //I should have originally used the entire ProcessExtenedInfo the first time.
1789 //So now I am forced to check UDPVersion to see if we are sending all the extended info.
1790 //For now on, we should not have to change anything here if we change
1791 //anything to the extended info data as this will be taken care of in ProcessExtendedInfo()
1792 //Update extended info.
1793 if (sender
->GetUDPVersion() > 3) {
1794 sender
->ProcessExtendedInfo(&data_in
, reqfile
);
1795 } else if (sender
->GetUDPVersion() > 2) {
1796 //Update our complete source counts.
1797 uint16 nCompleteCountLast
= sender
->GetUpCompleteSourcesCount();
1798 uint16 nCompleteCountNew
= data_in
.ReadUInt16();
1799 sender
->SetUpCompleteSourcesCount(nCompleteCountNew
);
1800 if (nCompleteCountLast
!= nCompleteCountNew
) {
1801 reqfile
->UpdatePartsInfo();
1805 CMemFile
data_out(128);
1806 if(sender
->GetUDPVersion() > 3) {
1807 if (reqfile
->IsPartFile()) {
1808 ((CPartFile
*)reqfile
)->WritePartStatus(&data_out
);
1810 data_out
.WriteUInt16(0);
1814 data_out
.WriteUInt16(sender
->GetUploadQueueWaitingPosition());
1815 CPacket
* response
= new CPacket(data_out
, OP_EMULEPROT
, OP_REASKACK
);
1816 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1817 AddDebugLogLineN( logLocalClient
, wxT("Local Client UDP: OP_REASKACK to ") + m_client
->GetFullIP() );
1818 theApp
->clientudp
->SendPacket(response
, destip
, destport
, sender
->ShouldReceiveCryptUDPPackets(), sender
->GetUserHash().GetHash(), false, 0);
1820 AddDebugLogLineN(logListenSocket
, wxT("Client UDP socket; OP_REASKCALLBACKTCP; reqfile does not match"));
1823 if (!bSenderMultipleIpUnknown
){
1824 if ((theStats::GetWaitingUserCount() + 50) > thePrefs::GetQueueSize()) {
1825 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_QUEUEFULL to ") + m_client
->GetFullIP() );
1826 CPacket
* response
= new CPacket(OP_QUEUEFULL
,0,OP_EMULEPROT
);
1827 theStats::AddUpOverheadFileRequest(response
->GetPacketSize());
1828 theApp
->clientudp
->SendPacket(response
, destip
, destport
, false, NULL
, false, 0);
1831 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("OP_REASKCALLBACKTCP Packet received - multiple clients with the same IP but different UDP port found. Possible UDP Portmapping problem, enforcing TCP connection. IP: %s, Port: %u")) % Uint32toStringIP(destip
) % destport
);
1836 case OP_CHATCAPTCHAREQ
:
1838 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_CHATCAPTCHAREQ from ") + m_client
->GetFullIP());
1839 theStats::AddDownOverheadOther(size
);
1840 CMemFile
data_in(buffer
, size
);
1841 m_client
->ProcessCaptchaRequest(&data_in
);
1844 case OP_CHATCAPTCHARES
:
1846 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_CHATCAPTCHARES from ") + m_client
->GetFullIP());
1847 theStats::AddDownOverheadOther(size
);
1849 m_client
->ProcessCaptchaReqRes(buffer
[0]);
1853 case OP_FWCHECKUDPREQ
: { // Support required for Kadversion >= 6
1854 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_FWCHECKUDPREQ from ") + m_client
->GetFullIP());
1855 theStats::AddDownOverheadOther(size
);
1856 CMemFile
data_in(buffer
, size
);
1857 m_client
->ProcessFirewallCheckUDPRequest(&data_in
);
1860 case OP_KAD_FWTCPCHECK_ACK
: { // Support required for Kadversion >= 7
1861 AddDebugLogLineN(logRemoteClient
, wxT("Remote Client: OP_KAD_FWTCPCHECK_ACK from ") + m_client
->GetFullIP());
1862 if (theApp
->clientlist
->IsKadFirewallCheckIP(m_client
->GetIP())) {
1863 if (Kademlia::CKademlia::IsRunning()) {
1864 Kademlia::CKademlia::GetPrefs()->IncFirewalled();
1867 AddDebugLogLineN(logListenSocket
, wxT("Received unrequested OP_KAD_FWTCPCHECK_ACK packet from ") + m_client
->GetFullIP());
1872 theStats::AddDownOverheadOther(size
);
1873 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("eMule packet : unknown opcode: %i %x from %s")) % opcode
% opcode
% m_client
->GetFullIP());
1880 bool CClientTCPSocket::ProcessED2Kv2Packet(const byte
* buffer
, uint32 size
, uint8 opcode
)
1882 #ifdef __PACKET_RECV_DUMP__
1883 //printf("Rec: OPCODE %x ED2Kv2\n",opcode);
1884 DumpMem(buffer
,size
);
1888 throw wxString(wxT("Unknown clients sends extended ED2Kv2 protocol packet"));
1891 CMemFile
data(buffer
, size
);
1894 case OP_QUEUERANK
: {
1895 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_QUEUERANK from ") + m_client
->GetFullIP() );
1897 uint8 numtags
= data
.ReadUInt8();
1898 wxASSERT(numtags
== 1);
1899 if(numtags
){} // prevent GCC warning
1901 m_client
->SetRemoteQueueRank(data
.GetIntTagValue());
1903 theStats::AddDownOverheadFileRequest(size
);
1907 case OP_REQUESTPARTS
: {
1908 AddDebugLogLineN( logRemoteClient
, wxT("Remote Client: ED2Kv2 OP_REQUESTPARTS from ") + m_client
->GetFullIP() );
1910 m_client
->ProcessRequestPartsPacketv2(data
);
1912 theStats::AddDownOverheadFileRequest(size
);
1917 theStats::AddDownOverheadOther(size
);
1918 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("ED2Kv2 packet : unknown opcode: %i %x from %s")) % opcode
% opcode
% m_client
->GetFullIP());
1921 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("ED2Kv2 packet is corrupt at pos %i! opcode: %i %x from %s")) % data
.GetPosition() % opcode
% opcode
% m_client
->GetFullIP());
1928 void CClientTCPSocket::OnConnect(int nErrorCode
)
1931 OnError(nErrorCode
);
1932 } else if (!m_client
) {
1933 // and now? Disconnect? not?
1934 AddDebugLogLineN( logClient
, wxT("Couldn't send hello packet (Client deleted!)") );
1935 } else if (!m_client
->SendHelloPacket()) {
1936 // and now? Disconnect? not?
1937 AddDebugLogLineN( logClient
, wxT("Couldn't send hello packet (Client deleted by SendHelloPacket!)") );
1939 ResetTimeOutTimer();
1944 void CClientTCPSocket::OnSend(int nErrorCode
)
1946 ResetTimeOutTimer();
1947 CEMSocket::OnSend(nErrorCode
);
1951 void CClientTCPSocket::OnReceive(int nErrorCode
)
1953 ResetTimeOutTimer();
1954 // We might have updated ipfilter
1955 wxASSERT(m_remoteip
);
1957 if (theApp
->ipfilter
->IsFiltered(m_remoteip
)) {
1959 m_client
->Safe_Delete();
1962 AddDebugLogLineN( logIPFilter
, wxT("A connected client was dropped by IPFilter on new packet received"));
1964 CEMSocket::OnReceive(nErrorCode
);
1969 void CClientTCPSocket::OnError(int nErrorCode
)
1971 //printf("* Called OnError for %p\n",this);
1972 // 0.42e + Kry changes for handling of socket lost events
1975 if ((nErrorCode
== 0) || (nErrorCode
== 7) || (nErrorCode
== 0xFEFF)) {
1977 if (!m_client
->GetUserName().IsEmpty()) {
1978 strError
= wxT("Client '") + m_client
->GetUserName() + wxT("'");
1980 strError
= wxT("An unnamed client");
1982 strError
+= wxT(" (IP:") + m_client
->GetFullIP() + wxT(") ");
1984 strError
= wxT("A client ");
1986 if (nErrorCode
== 0) {
1987 strError
+= wxT("closed connection.");
1988 } else if (nErrorCode
== 0xFEFF) {
1989 strError
+= wxT(" caused a wxSOCKET_LOST event.");
1991 strError
+= wxT("caused a socket blocking error.");
1994 if (theLogger
.IsEnabled(logClient
) && nErrorCode
!= 107) {
1995 // 0 -> No Error / Disconect
1996 // 107 -> Transport endpoint is not connected
1998 if (!m_client
->GetUserName().IsEmpty()) {
1999 strError
= CFormat(wxT("OnError: Client '%s' (IP:%s) caused an error: %u. Disconnecting client!"))
2000 % m_client
->GetUserName() % m_client
->GetFullIP() % nErrorCode
;
2002 strError
= CFormat(wxT("OnError: Unknown client (IP:%s) caused an error: %u. Disconnecting client!"))
2003 % m_client
->GetFullIP() % nErrorCode
;
2006 strError
= CFormat(wxT("OnError: A client caused an error or did something bad (error %u). Disconnecting client !"))
2010 strError
= wxT("Error 107 (Transport endpoint is not connected)");
2014 Disconnect(strError
);
2018 bool CClientTCPSocket::PacketReceived(CPacket
* packet
)
2021 bool bResult
= false;
2022 uint32 uRawSize
= packet
->GetPacketSize();
2024 AddDebugLogLineN( logRemoteClient
,
2025 CFormat(wxT("Packet with protocol %x, opcode %x, size %u received from %s"))
2026 % packet
->GetProtocol()
2027 % packet
->GetOpCode()
2028 % packet
->GetPacketSize()
2029 % ( m_client
? m_client
->GetFullIP() : wxT("Unknown Client") )
2035 bool process
= true;
2037 if ((packet
->GetProtocol() == OP_PACKEDPROT
) ||
2038 (packet
->GetProtocol() == OP_ED2KV2PACKEDPROT
)) {
2040 if (!packet
->UnPackPacket()) {
2041 AddDebugLogLineN(logZLib
, wxT("Failed to decompress client TCP packet."));
2045 AddDebugLogLineN(logRemoteClient
, CFormat(wxT("Packet unpacked, new protocol %x, opcode %x, size %u"))
2046 % packet
->GetProtocol() % packet
->GetOpCode() % packet
->GetPacketSize());
2051 switch (packet
->GetProtocol()) {
2052 case OP_EDONKEYPROT
:
2053 bResult
= ProcessPacket(packet
->GetDataBuffer(),uRawSize
,packet
->GetOpCode());
2056 bResult
= ProcessExtPacket(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2058 case OP_ED2KV2HEADER
:
2059 bResult
= ProcessED2Kv2Packet(packet
->GetDataBuffer(), packet
->GetPacketSize(), packet
->GetOpCode());
2061 case OP_ED2KV2PACKEDPROT
:
2063 // Packed inside packed?
2067 theStats::AddDownOverheadOther(uRawSize
);
2069 m_client
->SetDownloadState(DS_ERROR
);
2071 Disconnect(wxT("Unknown protocol"));
2076 } catch (const CEOFException
& err
) {
2077 exception
= wxT("EOF exception: ") + err
.what();
2078 } catch (const CInvalidPacket
& err
) {
2079 exception
= wxT("InvalidPacket exception: ") + err
.what();
2080 } catch (const wxString
& error
) {
2081 exception
= wxT("error: ") + (error
.IsEmpty() ? wxString(wxT("Unknown error")) : error
);
2084 if (!exception
.IsEmpty()) {
2085 AddDebugLogLineN( logPacketErrors
,
2086 CFormat(wxT("Caught %s\nOn packet with protocol %x, opcode %x, size %u\tClientData: %s\n"))
2088 % packet
->GetProtocol()
2089 % packet
->GetOpCode()
2090 % packet
->GetPacketSize()
2091 % ( m_client
? m_client
->GetClientFullInfo() : wxT("Unknown") )
2095 m_client
->SetDownloadState(DS_ERROR
);
2098 AddDebugLogLineN( logClient
,
2099 CFormat( wxT("Client '%s' (IP: %s) caused an error (%s). Disconnecting client!" ) )
2100 % ( m_client
? m_client
->GetUserName() : wxString(wxT("Unknown")) )
2101 % ( m_client
? m_client
->GetFullIP() : wxString(wxT("Unknown")) )
2105 Disconnect(wxT("Caught exception on CClientTCPSocket::ProcessPacket\n"));
2112 SocketSentBytes
CClientTCPSocket::SendControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2114 SocketSentBytes returnStatus
= CEMSocket::SendControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2116 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2117 ResetTimeOutTimer();
2120 return returnStatus
;
2124 SocketSentBytes
CClientTCPSocket::SendFileAndControlData(uint32 maxNumberOfBytesToSend
, uint32 overchargeMaxBytesToSend
)
2126 SocketSentBytes returnStatus
= CEMSocket::SendFileAndControlData(maxNumberOfBytesToSend
, overchargeMaxBytesToSend
);
2128 if(returnStatus
.success
&& (returnStatus
.sentBytesControlPackets
> 0 || returnStatus
.sentBytesStandardPackets
> 0)) {
2129 ResetTimeOutTimer();
2132 return returnStatus
;
2136 void CClientTCPSocket::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
, uint32 actualPayloadSize
)
2138 ResetTimeOutTimer();
2139 CEMSocket::SendPacket(packet
,delpacket
,controlpacket
, actualPayloadSize
);
2141 // File_checked_for_headers