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
28 #include "updownclient.h" // Needed for CUpDownClient
30 #include <protocol/Protocols.h>
31 #include <protocol/ed2k/Client2Client/TCP.h>
32 #include <protocol/ed2k/ClientSoftware.h>
33 #include <protocol/kad/Client2Client/UDP.h>
34 #include <protocol/kad2/Constants.h>
35 #include <protocol/kad2/Client2Client/TCP.h>
36 #include <protocol/kad2/Client2Client/UDP.h>
38 #include <common/ClientVersion.h>
40 #include <tags/ClientTags.h>
42 #include <zlib.h> // Needed for inflateEnd
44 #include <common/Format.h> // Needed for CFormat
46 #include "SearchList.h" // Needed for CSearchList
47 #include "DownloadQueue.h" // Needed for CDownloadQueue
48 #include "UploadQueue.h" // Needed for CUploadQueue
49 #include "IPFilter.h" // Needed for CIPFilter
50 #include "ServerConnect.h" // Needed for CServerConnect
51 #include "ClientCredits.h" // Needed for CClientCredits
52 #include "ClientCreditsList.h" // Needed for CClientCreditsList
53 #include "Server.h" // Needed for CServer
54 #include "Preferences.h" // Needed for CPreferences
55 #include "MemFile.h" // Needed for CMemFile
56 #include "Packet.h" // Needed for CPacket
57 #include "Friend.h" // Needed for CFriend
58 #include "ClientList.h" // Needed for CClientList
59 #include "amule.h" // Needed for theApp
60 #include "PartFile.h" // Needed for CPartFile
61 #include "ClientTCPSocket.h" // Needed for CClientTCPSocket
62 #include "ListenSocket.h" // Needed for CListenSocket
63 #include "FriendList.h" // Needed for CFriendList
64 #include "Statistics.h" // Needed for theStats
65 #include "ClientUDPSocket.h"
67 #include "DataToText.h" // Needed for GetSoftName()
68 #include "GuiEvents.h" // Needed for Notify_
69 #include "ServerList.h" // For CServerList
71 #include "kademlia/kademlia/Kademlia.h"
72 #include "kademlia/kademlia/Prefs.h"
73 #include "kademlia/kademlia/Search.h"
74 #include "kademlia/kademlia/UDPFirewallTester.h"
75 #include "kademlia/routing/RoutingZone.h"
78 //#define __PACKET_DEBUG__
81 // some client testing variables
82 static wxString crash_name
= wxT("[Invalid User Name]");
83 static wxString empty_name
= wxT("[Empty User Name]");
85 // members of CUpDownClient
86 // which are used by down and uploading functions
89 CUpDownClient::CUpDownClient(CClientTCPSocket
* sender
)
100 CUpDownClient::CUpDownClient(uint16 in_port
, uint32 in_userid
, uint32 in_serverip
, uint16 in_serverport
, CPartFile
* in_reqfile
, bool ed2kID
, bool checkfriend
)
104 m_nUserPort
= in_port
;
106 if(ed2kID
&& !IsLowID(in_userid
)) {
107 SetUserIDHybrid( wxUINT32_SWAP_ALWAYS(in_userid
) );
109 SetUserIDHybrid( in_userid
);
112 //If highID and ED2K source, incoming ID and IP are equal..
113 //If highID and Kad source, incoming IP needs swap for the IP
117 m_nConnectIP
= in_userid
;
119 m_nConnectIP
= wxUINT32_SWAP_ALWAYS(in_userid
);
121 // Will be on right endianess now
122 m_FullUserIP
= Uint32toStringIP(m_nConnectIP
);
125 m_dwServerIP
= in_serverip
;
126 m_nServerPort
= in_serverport
;
127 SetRequestFile( in_reqfile
);
131 if ((m_Friend
= theApp
->friendlist
->FindFriend(CMD4Hash(), m_dwUserIP
, m_nUserPort
)) != NULL
){
132 m_Friend
->LinkClient(this);
134 // avoid that an unwanted client instance keeps a friend slot
135 m_bFriendSlot
= false;
141 void CUpDownClient::Init()
143 m_bAddNextConnect
= false;
145 m_byChatstate
= MS_NONE
;
146 m_nKadState
= KS_NONE
;
148 m_reqfile
= NULL
; // No file required yet
149 m_nTransferredUp
= 0;
154 fDownAvgFilter
= 1.0;
155 bytesReceivedCycle
= 0;
157 m_iFileListRequested
= 0;
158 m_dwLastUpRequest
= 0;
159 m_bEmuleProtocol
= false;
160 m_bCompleteSource
= false;
161 m_bFriendSlot
= false;
162 m_bCommentDirty
= false;
163 m_bReaskPending
= false;
164 m_bUDPPending
= false;
167 m_dwLastAskedTime
= 0;
168 m_nDownloadState
= DS_NONE
;
170 m_nTransferredDown
= 0;
171 m_nUploadState
= US_NONE
;
172 m_dwLastBlockReceived
= 0;
173 m_bUnicodeSupport
= false;
175 m_fSentOutOfPartReqs
= 0;
176 m_nCurQueueSessionPayloadUp
= 0;
177 m_addedPayloadQueueSession
= 0;
179 m_nSumForAvgUpDataRate
= 0;
181 m_nRemoteQueueRank
= 0;
182 m_nOldRemoteQueueRank
= 0;
183 m_dwLastSourceRequest
= 0;
184 m_dwLastSourceAnswer
= 0;
185 m_dwLastAskedForSources
= 0;
187 m_SecureIdentState
= IS_UNAVAILABLE
;
188 m_dwLastSignatureIP
= 0;
190 m_byInfopacketsReceived
= IP_NONE
;
197 m_clientSoft
=SO_UNKNOWN
;
199 m_bRemoteQueueFull
= false;
200 m_HasValidHash
= false;
203 m_fHashsetRequesting
= 0;
204 m_fSharedDirectories
= 0;
205 m_lastPartAsked
= 0xffff;
206 m_nUpCompleteSourcesCount
= 0;
207 m_lastRefreshedDLDisplay
= 0;
208 m_bHelloAnswerPending
= false;
209 m_fSentCancelTransfer
= 0;
210 m_Aggressiveness
= 0;
211 m_LastFileRequest
= 0;
213 m_clientState
= CS_NEW
;
215 ClearHelloProperties();
217 m_pReqFileAICHHash
= NULL
;
219 m_fAICHRequested
= 0;
220 m_fSupportsLargeFiles
= 0;
221 m_fExtMultiPacket
= 0;
227 m_fNeedOurPublicIP
= false;
228 m_bHashsetRequested
= false;
230 m_nLastBlockOffset
= 0;
232 m_uploadingfile
= NULL
;
234 m_OSInfo_sent
= false;
242 m_nSourceFrom
= SF_NONE
;
245 amuleIPV4Address address
;
246 m_socket
->GetPeer(address
);
247 m_FullUserIP
= address
.IPAddress();
248 SetIP(StringIPtoUint32(m_FullUserIP
));
254 m_lastClientSoft
= (uint32
)(-1);
255 m_lastClientVersion
= 0;
257 /* Creation time (for buddies timeout) */
258 m_nCreationTime
= ::GetTickCount();
260 m_MaxBlockRequests
= STANDARD_BLOCKS_REQUEST
; // Safe starting amount
262 m_last_block_start
= 0;
265 SetLastBuddyPingPongTime();
266 m_fRequestsCryptLayer
= 0;
267 m_fSupportsCryptLayer
= 0;
268 m_fRequiresCryptLayer
= 0;
269 m_fSupportsSourceEx2
= 0;
270 m_fDirectUDPCallback
= 0;
271 m_dwDirectCallbackTimeout
= 0;
273 m_hasbeenobfuscatinglately
= false;
277 CUpDownClient::~CUpDownClient()
280 if (!connection_reason
.IsEmpty()) {
281 printf("Client to check for %s was deleted without connection.\n",(const char*)unicode2char(connection_reason
));
285 if (m_lastClientSoft
== SO_UNKNOWN
) {
286 theStats::RemoveUnknownClient();
287 } else if (m_lastClientSoft
!= (uint32
)(-1)) {
288 theStats::RemoveKnownClient(m_lastClientSoft
, m_lastClientVersion
, m_lastOSInfo
);
291 // Indicate that we are not anymore on stats
292 m_lastClientSoft
= (uint32
)(-1);
295 if (IsAICHReqPending()){
296 m_fAICHRequested
= FALSE
;
297 CAICHHashSet::ClientAICHRequestFailed(this);
300 //theApp->clientlist->RemoveClient(this, wxT("Destructing client object"));
303 m_Friend
->UnLinkClient();
304 Notify_ChatRefreshFriend(m_Friend
->GetIP(), m_Friend
->GetPort(), wxEmptyString
);
308 // The socket should have been removed in Safe_Delete, but it
309 // doesn't hurt to have an extra check.
311 m_socket
->Safe_Delete();
317 ClearUploadBlockRequests();
318 ClearDownloadBlockRequests();
320 DeleteContents(m_WaitingPackets_list
);
322 if (m_iRating
>0 || !m_strComment
.IsEmpty()) {
324 m_strComment
.Clear();
326 m_reqfile
->UpdateFileRatingCommentAvail();
330 // Ensure that source-counts gets updated in case
331 // of a source not on the download-queue
332 SetRequestFile( NULL
);
334 SetUploadFileID(NULL
);
336 if (m_pReqFileAICHHash
!= NULL
) {
337 delete m_pReqFileAICHHash
;
338 m_pReqFileAICHHash
= NULL
;
342 void CUpDownClient::ClearHelloProperties()
347 m_byEmuleVersion
= 0;
348 m_bySourceExchange1Ver
= 0;
349 m_byAcceptCommentVer
= 0;
350 m_byExtendedRequestsVer
= 0;
351 m_byCompatibleClient
= 0;
353 m_bySupportSecIdent
= 0;
354 m_bSupportsPreview
= 0;
355 m_nClientVersion
= 0;
356 m_fSharedDirectories
= 0;
358 m_fOsInfoSupport
= 0;
359 m_fValueBasedTypeTags
= 0;
362 m_fRequestsCryptLayer
= 0;
363 m_fSupportsCryptLayer
= 0;
364 m_fRequiresCryptLayer
= 0;
365 m_fSupportsSourceEx2
= 0;
366 m_fDirectUDPCallback
= 0;
369 bool CUpDownClient::ProcessHelloPacket(const byte
* pachPacket
, uint32 nSize
)
371 const CMemFile
data(pachPacket
,nSize
);
372 uint8 hashsize
= data
.ReadUInt8();
373 if ( 16 != hashsize
) {
375 * Hint: We can not accept other sizes here because:
376 * - the magic number is spread all over the source
377 * - the answer packet lacks the size field
379 throw wxString(wxT("Invalid Hello packet: Other userhash sizes than 16 are not implemented"));
381 // eMule 0.42: reset all client properties; a client may not send a particular emule tag any longer
382 ClearHelloProperties();
384 return ProcessHelloTypePacket(data
);
387 void CUpDownClient::Safe_Delete()
389 // Because we are delaying the deletion, we might end up trying to delete
390 // it twice, however, this is normal and shouldn't trigger any failures
391 if ( m_clientState
== CS_DYING
) {
395 m_clientState
= CS_DYING
;
397 // Close the socket to avoid any more connections and related events
399 m_socket
->Safe_Delete();
404 // Schedule the client for deletion if we still have the clientlist
405 if ( theApp
->clientlist
) {
406 theApp
->clientlist
->AddToDeleteQueue( this );
413 bool CUpDownClient::ProcessHelloAnswer(const byte
* pachPacket
, uint32 nSize
)
415 const CMemFile
data(pachPacket
,nSize
);
416 bool bIsMule
= ProcessHelloTypePacket(data
);
417 m_bHelloAnswerPending
= false;
421 bool CUpDownClient::ProcessHelloTypePacket(const CMemFile
& data
)
426 m_fNoViewSharedFiles
= 0;
427 m_bUnicodeSupport
= false;
428 uint32 dwEmuleTags
= 0;
430 CMD4Hash hash
= data
.ReadHash();
432 SetUserIDHybrid( data
.ReadUInt32() );
433 uint16 nUserPort
= data
.ReadUInt16(); // hmm clientport is sent twice - why?
434 uint32 tagcount
= data
.ReadUInt32();
435 for (uint32 i
= 0;i
< tagcount
; i
++){
436 CTag
temptag(data
, true);
437 switch(temptag
.GetNameID()){
439 m_Username
= temptag
.GetStr();
443 m_nClientVersion
= temptag
.GetInt();
447 if (temptag
.IsStr()) {
448 m_strModVersion
= temptag
.GetStr();
449 } else if (temptag
.IsInt()) {
450 m_strModVersion
= wxString::Format(wxT("ModID=%u"), temptag
.GetInt());
452 m_strModVersion
= wxT("ModID=<Unknown>");
458 nUserPort
= temptag
.GetInt();
461 case CT_EMULE_UDPPORTS
:
464 SetKadPort((temptag
.GetInt() >> 16) & 0xFFFF);
465 m_nUDPPort
= temptag
.GetInt() & 0xFFFF;
467 #ifdef __PACKET_DEBUG__
468 printf("Hello type packet processing with eMule ports UDP=%i KAD=%i\n",m_nUDPPort
,m_nKadPort
);
472 case CT_EMULE_BUDDYIP
:
474 m_nBuddyIP
= temptag
.GetInt();
475 #ifdef __PACKET_DEBUG__
476 printf("Hello type packet processing with eMule BuddyIP=%u (%s)\n",m_nBuddyIP
, (const char*)unicode2char(Uint32toStringIP(m_nBuddyIP
)));
480 case CT_EMULE_BUDDYUDP
:
481 // 16 --Reserved for future use--
483 m_nBuddyPort
= (uint16
)temptag
.GetInt();
484 #ifdef __PACKET_DEBUG__
485 printf("Hello type packet processing with eMule BuddyPort=%u\n",m_nBuddyPort
);
489 case CT_EMULE_MISCOPTIONS1
: {
490 // 3 AICH Version (0 = not supported)
493 // 4 Data compression version
498 // 1 PeerCache supported
499 // 1 No 'View Shared Files' supported
502 uint32 flags
= temptag
.GetInt();
503 m_fSupportsAICH
= (flags
>> (4*7+1)) & 0x07;
504 m_bUnicodeSupport
= (flags
>> 4*7) & 0x01;
505 m_byUDPVer
= (flags
>> 4*6) & 0x0f;
506 m_byDataCompVer
= (flags
>> 4*5) & 0x0f;
507 m_bySupportSecIdent
= (flags
>> 4*4) & 0x0f;
508 m_bySourceExchange1Ver
= (flags
>> 4*3) & 0x0f;
509 m_byExtendedRequestsVer
= (flags
>> 4*2) & 0x0f;
510 m_byAcceptCommentVer
= (flags
>> 4*1) & 0x0f;
511 m_fNoViewSharedFiles
= (flags
>> 1*2) & 0x01;
512 m_bMultiPacket
= (flags
>> 1*1) & 0x01;
513 m_fSupportsPreview
= (flags
>> 1*0) & 0x01;
515 #ifdef __PACKET_DEBUG__
516 printf("Hello type packet processing with eMule Misc Options:\n");
517 printf("m_byUDPVer = %i\n",m_byUDPVer
);
518 printf("m_byDataCompVer = %i\n",m_byDataCompVer
);
519 printf("m_bySupportSecIdent = %i\n",m_bySupportSecIdent
);
520 printf("m_bySourceExchangeVer = %i\n",m_bySourceExchange1Ver
);
521 printf("m_byExtendedRequestsVer = %i\n",m_byExtendedRequestsVer
);
522 printf("m_byAcceptCommentVer = %i\n",m_byAcceptCommentVer
);
523 printf("m_fNoViewSharedFiles = %i\n",m_fNoViewSharedFiles
);
524 printf("m_bMultiPacket = %i\n",m_bMultiPacket
);
525 printf("m_fSupportsPreview = %i\n",m_fSharedDirectories
);
526 printf("That's all.\n");
532 case CT_EMULE_MISCOPTIONS2
:
534 // 1 Direct UDP Callback supported and available
535 // 1 Supports ChatCaptchas
536 // 1 Supports SourceExachnge2 Packets, ignores SX1 Packet Version
537 // 1 Requires CryptLayer
538 // 1 Requests CryptLayer
539 // 1 Supports CryptLayer
540 // 1 Reserved (ModBit)
541 // 1 Ext Multipacket (Hash+Size instead of Hash)
542 // 1 Large Files (includes support for 64bit tags)
543 // 4 Kad Version - will go up to version 15 only (may need to add another field at some point in the future)
544 m_fDirectUDPCallback
= (temptag
.GetInt() >> 12) & 0x01;
546 m_fSupportsSourceEx2
= (temptag
.GetInt() >> 10) & 0x01;
547 m_fRequiresCryptLayer
= (temptag
.GetInt() >> 9) & 0x01;
548 m_fRequestsCryptLayer
= (temptag
.GetInt() >> 8) & 0x01;
549 m_fSupportsCryptLayer
= (temptag
.GetInt() >> 7) & 0x01;
551 m_fExtMultiPacket
= (temptag
.GetInt() >> 5) & 0x01;
552 m_fSupportsLargeFiles
= (temptag
.GetInt() >> 4) & 0x01;
553 m_byKadVersion
= (temptag
.GetInt() >> 0) & 0x0f;
556 m_fRequestsCryptLayer
&= m_fSupportsCryptLayer
;
557 m_fRequiresCryptLayer
&= m_fRequestsCryptLayer
;
559 #ifdef __PACKET_DEBUG__
560 printf("Hello type packet processing with eMule Misc Options 2:\n");
561 printf(" m_fDirectUDPCallback = %i\n", m_fDirectUDPCallback
);
562 printf(" m_fSupportsSourceEx2 = %i\n", m_fSupportsSourceEx2
);
563 printf(" m_fRequiresCryptLayer = %i\n", m_fRequiresCryptLayer
);
564 printf(" m_fRequestsCryptLayer = %i\n", m_fRequestsCryptLayer
);
565 printf(" m_fSupportsCryptLayer = %i\n", m_fSupportsCryptLayer
);
566 printf(" m_fExtMultiPacket = %i\n", m_fExtMultiPacket
);
567 printf(" m_fSupportsLargeFiles = %i\n", m_fSupportsLargeFiles
);
568 printf(" KadVersion = %u\n", m_byKadVersion
);
569 printf("That's all.\n");
573 // Special tag for Compat. Clients Misc options.
574 case CT_EMULECOMPAT_OPTIONS
:
575 // 1 Operative System Info
576 // 1 Value-based-type int tags (experimental!)
577 m_fValueBasedTypeTags
= (temptag
.GetInt() >> 1*1) & 0x01;
578 m_fOsInfoSupport
= (temptag
.GetInt() >> 1*0) & 0x01;
581 case CT_EMULE_VERSION
:
582 // 8 Compatible Client ID
583 // 7 Mjr Version (Doesn't really matter..)
584 // 7 Min Version (Only need 0-99)
585 // 3 Upd Version (Only need 0-5)
586 // 7 Bld Version (Only need 0-99)
587 m_byCompatibleClient
= (temptag
.GetInt() >> 24);
588 m_nClientVersion
= temptag
.GetInt() & 0x00ffffff;
589 m_byEmuleVersion
= 0x99;
590 m_fSharedDirectories
= 1;
596 m_nUserPort
= nUserPort
;
597 m_dwServerIP
= data
.ReadUInt32();
598 m_nServerPort
= data
.ReadUInt16();
599 // Hybrid now has an extra uint32.. What is it for?
600 // Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
601 if ( data
.GetLength() - data
.GetPosition() == sizeof(uint32
) ) {
602 uint32 test
= data
.ReadUInt32();
603 /*if (test == 'KDLM') below kdlm is converted to ascii values.
604 This fixes a warning with gcc 3.4.
607 if (test
== 0x4b444c4d) { //if it's == "KDLM"
611 m_fSharedDirectories
= 1;
616 amuleIPV4Address address
;
617 m_socket
->GetPeer(address
);
618 m_FullUserIP
= address
.IPAddress();
619 SetIP(StringIPtoUint32(m_FullUserIP
));
621 throw wxString(wxT("Huh, socket failure. Avoided crash this time."));
624 if (thePrefs::AddServersFromClient()) {
625 CServer
* addsrv
= new CServer(m_nServerPort
, Uint32toStringIP(m_dwServerIP
));
626 addsrv
->SetListName(addsrv
->GetAddress());
627 if (!theApp
->AddServer(addsrv
)) {
632 //(a)If this is a highID user, store the ID in the Hybrid format.
633 //(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
634 //(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
635 //because they will send a ID that is the same as their IP..
636 if(!HasLowID() || m_nUserIDHybrid
== 0 || m_nUserIDHybrid
== m_dwUserIP
) {
637 SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(m_dwUserIP
));
640 // get client credits
641 CClientCredits
* pFoundCredits
= theApp
->clientcredits
->GetCredit(m_UserHash
);
642 if (credits
== NULL
){
643 credits
= pFoundCredits
;
644 if (!theApp
->clientlist
->ComparePriorUserhash(m_dwUserIP
, m_nUserPort
, pFoundCredits
)){
645 AddDebugLogLineM( false, logClient
, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed (Found in TrackedClientsList)") ) % GetUserName() % GetFullIP() );
648 } else if (credits
!= pFoundCredits
){
649 // userhash change ok, however two hours "waittime" before it can be used
650 credits
= pFoundCredits
;
651 AddDebugLogLineM( false, logClient
, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed") ) % GetUserName() % GetFullIP() );
655 if ((m_Friend
= theApp
->friendlist
->FindFriend(m_UserHash
, m_dwUserIP
, m_nUserPort
)) != NULL
){
656 m_Friend
->LinkClient(this);
658 // avoid that an unwanted client instance keeps a friend slot
659 SetFriendSlot(false);
665 m_byInfopacketsReceived
|= IP_EDONKEYPROTPACK
;
667 // check if at least CT_EMULEVERSION was received, all other tags are optional
668 bool bIsMule
= (dwEmuleTags
& 0x04) == 0x04;
670 m_bEmuleProtocol
= true;
671 m_byInfopacketsReceived
|= IP_EMULEPROTPACK
;
675 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(GetIP()), GetKadPort(), GetKadVersion() > 1);
682 bool CUpDownClient::SendHelloPacket() {
684 if (m_socket
== NULL
){
689 // if IP is filtered, dont greet him but disconnect...
690 amuleIPV4Address address
;
691 m_socket
->GetPeer(address
);
692 if ( theApp
->ipfilter
->IsFiltered(StringIPtoUint32(address
.IPAddress()))) {
693 if (Disconnected(wxT("IPFilter"))) {
701 data
.WriteUInt8(16); // size of userhash
702 SendHelloTypePacket(&data
);
704 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_HELLO
);
705 theStats::AddUpOverheadOther(packet
->GetPacketSize());
706 SendPacket(packet
,true);
707 m_bHelloAnswerPending
= true;
708 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_HELLO to ") + GetFullIP() );
712 void CUpDownClient::SendMuleInfoPacket(bool bAnswer
, bool OSInfo
) {
714 if (m_socket
== NULL
){
719 CPacket
* packet
= NULL
;
722 data
.WriteUInt8(CURRENT_VERSION_SHORT
);
726 // Special MuleInfo packet for clients supporting it.
727 // This means aMule >= 2.0.0 and Hydranode
729 // Violently mark it as special Mule Info packet
730 // Sending this makes non-supporting-osinfo clients to refuse to read this
731 // packet. Anyway, this packet should NEVER get to non-supporting clients.
733 data
.WriteUInt8(/*EMULE_PROTOCOL*/ 0xFF);
735 data
.WriteUInt32(1); // One Tag (OS_INFO)
737 CTagString
tag1(ET_OS_INFO
,theApp
->GetOSType());
738 tag1
.WriteTagToFile(&data
);
740 m_OSInfo_sent
= true; // So we don't send it again
744 // Normal MuleInfo packet
746 // Kry - There's no point on upgrading to VBT tags here
747 // as no client supporting it uses mule info packet.
749 data
.WriteUInt8(EMULE_PROTOCOL
);
754 CTagInt32
tag1(ET_COMPRESSION
,1);
755 tag1
.WriteTagToFile(&data
);
756 CTagInt32
tag2(ET_UDPVER
,4);
757 tag2
.WriteTagToFile(&data
);
758 CTagInt32
tag3(ET_UDPPORT
, thePrefs::GetEffectiveUDPPort());
759 tag3
.WriteTagToFile(&data
);
760 CTagInt32
tag4(ET_SOURCEEXCHANGE
,3);
761 tag4
.WriteTagToFile(&data
);
762 CTagInt32
tag5(ET_COMMENTS
,1);
763 tag5
.WriteTagToFile(&data
);
764 CTagInt32
tag6(ET_EXTENDEDREQUEST
,2);
765 tag6
.WriteTagToFile(&data
);
767 uint32 dwTagValue
= (theApp
->CryptoAvailable() ? 3 : 0);
768 // Kry - Needs the preview code from eMule
770 // set 'Preview supported' only if 'View Shared Files' allowed
771 if (thePrefs::CanSeeShares() != vsfaNobody) {
775 CTagInt32
tag7(ET_FEATURES
, dwTagValue
);
776 tag7
.WriteTagToFile(&data
);
778 CTagInt32
tag8(ET_COMPATIBLECLIENT
,SO_AMULE
);
779 tag8
.WriteTagToFile(&data
);
781 // Support for tag ET_MOD_VERSION
782 wxString
mod_name(MOD_VERSION_LONG
);
783 CTagString
tag9(ET_MOD_VERSION
, mod_name
);
784 tag9
.WriteTagToFile(&data
);
789 packet
= new CPacket(data
, OP_EMULEPROT
, (bAnswer
? OP_EMULEINFOANSWER
: OP_EMULEINFO
));
792 theStats::AddUpOverheadOther(packet
->GetPacketSize());
793 SendPacket(packet
,true,true);
797 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_EMULEINFO to ") + GetFullIP() );
799 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_EMULEINFO/OS_INFO to ") + GetFullIP() );
802 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_EMULEINFOANSWER to ") + GetFullIP() );
807 bool CUpDownClient::ProcessMuleInfoPacket(const byte
* pachPacket
, uint32 nSize
)
809 uint8 protocol_version
;
811 const CMemFile
data(pachPacket
,nSize
);
813 // The version number part of this packet will soon be useless since
814 // it is only able to go to v.99. Why the version is a uint8 and why
815 // it was not done as a tag like the eDonkey hello packet is not known.
816 // Therefore, sooner or later, we are going to have to switch over to
817 // using the eDonkey hello packet to set the version. No sense making
818 // a third value sent for versions.
819 uint8 mule_version
= data
.ReadUInt8();
820 protocol_version
= data
.ReadUInt8();
821 uint32 tagcount
= data
.ReadUInt32();
822 if (protocol_version
== 0xFF) {
823 // OS Info supporting clients sending a recycled Mule info packet
824 for (uint32 i
= 0;i
< tagcount
; i
++){
825 CTag
temptag(data
, true);
826 switch(temptag
.GetNameID()){
828 // Special tag, only supporting clients (aMule/Hydranode)
829 // It was recycled from a mod's tag, so if the other side
830 // is not supporting OS Info, we're seriously fucked up :)
831 m_sClientOSInfo
= temptag
.GetStr();
833 // If we didn't send our OSInfo to this client, just send it
834 if (!m_OSInfo_sent
) {
835 SendMuleInfoPacket(false,true);
842 // Your ad... er... I mean TAG, here
849 // Old eMule sending tags
850 m_byCompatibleClient
= 0;
851 m_byEmuleVersion
= mule_version
;
853 if( m_byEmuleVersion
== 0x2B ) {
854 m_byEmuleVersion
= 0x22;
857 if (!(m_bEmuleProtocol
= (protocol_version
== EMULE_PROTOCOL
))) {
861 for (uint32 i
= 0;i
< tagcount
; i
++){
862 CTag
temptag(data
, false);
863 switch(temptag
.GetNameID()){
865 // Bits 31- 8: 0 - reserved
866 // Bits 7- 0: data compression version
867 m_byDataCompVer
= temptag
.GetInt();
871 // Bits 31-16: 0 - reserved
872 // Bits 15- 0: UDP port
873 m_nUDPPort
= temptag
.GetInt();
877 // Bits 31- 8: 0 - reserved
878 // Bits 7- 0: UDP protocol version
879 m_byUDPVer
= temptag
.GetInt();
882 case ET_SOURCEEXCHANGE
:
883 // Bits 31- 8: 0 - reserved
884 // Bits 7- 0: source exchange protocol version
885 m_bySourceExchange1Ver
= temptag
.GetInt();
889 // Bits 31- 8: 0 - reserved
890 // Bits 7- 0: comments version
891 m_byAcceptCommentVer
= temptag
.GetInt();
894 case ET_EXTENDEDREQUEST
:
895 // Bits 31- 8: 0 - reserved
896 // Bits 7- 0: extended requests version
897 m_byExtendedRequestsVer
= temptag
.GetInt();
900 case ET_COMPATIBLECLIENT
:
901 // Bits 31- 8: 0 - reserved
902 // Bits 7- 0: compatible client ID
903 m_byCompatibleClient
= temptag
.GetInt();
907 // Bits 31- 8: 0 - reserved
909 // Bit 6- 0: secure identification
910 m_bySupportSecIdent
= temptag
.GetInt() & 3;
911 m_bSupportsPreview
= (temptag
.GetInt() & 128) > 0;
916 if (temptag
.IsStr()) {
917 m_strModVersion
= temptag
.GetStr();
918 } else if (temptag
.IsInt()) {
919 m_strModVersion
= wxString::Format(wxT("ModID=%u"), temptag
.GetInt());
921 m_strModVersion
= wxT("ModID=<Unknown>");
927 AddDebugLogLineM( false, logPacketErrors
,
928 CFormat( wxT("Unknown Mule tag (%s) from client: %s") )
929 % temptag
.GetFullInfo()
930 % GetClientFullInfo()
937 if( m_byDataCompVer
== 0 ){
938 m_bySourceExchange1Ver
= 0;
939 m_byExtendedRequestsVer
= 0;
940 m_byAcceptCommentVer
= 0;
944 //implicitly supported options by older clients
945 //in the future do not use version to guess about new features
946 if(m_byEmuleVersion
< 0x25 && m_byEmuleVersion
> 0x22) {
950 if(m_byEmuleVersion
< 0x25 && m_byEmuleVersion
> 0x21) {
951 m_bySourceExchange1Ver
= 1;
954 if(m_byEmuleVersion
== 0x24) {
955 m_byAcceptCommentVer
= 1;
958 // Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
959 // the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
960 // directory which has a trailing backslash.
961 if(m_byEmuleVersion
>= 0x28 && !m_bIsML
) {// MLdonkey currently does not support shared directories
962 m_fSharedDirectories
= 1;
967 m_byInfopacketsReceived
|= IP_EMULEPROTPACK
;
970 return (protocol_version
== 0xFF); // This was a OS_Info?
974 void CUpDownClient::SendHelloAnswer()
976 if (m_socket
== NULL
){
982 SendHelloTypePacket(&data
);
983 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_HELLOANSWER
);
984 theStats::AddUpOverheadOther(packet
->GetPacketSize());
985 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_HELLOANSWER to ") + GetFullIP() );
986 SendPacket(packet
,true);
990 void CUpDownClient::SendHelloTypePacket(CMemFile
* data
)
992 data
->WriteHash(thePrefs::GetUserHash());
993 data
->WriteUInt32(theApp
->GetID());
994 data
->WriteUInt16(thePrefs::GetPort());
998 if( theApp
->clientlist
->GetBuddy() && theApp
->IsFirewalled() ) {
1001 tagcount
++; // eMule misc flags 2 (kad version)
1004 // Kry - This is the tagcount!!! Be sure to update it!!
1005 // Last update: CT_EMULECOMPAT_OPTIONS included
1006 data
->WriteUInt32(tagcount
+ 1);
1008 data
->WriteUInt32(tagcount
); // NO MOD_VERSION
1012 CTagString
tagname(CT_NAME
,thePrefs::GetUserNick());
1013 tagname
.WriteTagToFile(data
, utf8strRaw
);
1015 CTagVarInt
tagversion(CT_VERSION
, EDONKEYVERSION
, GetVBTTags() ? 0 : 32);
1016 tagversion
.WriteTagToFile(data
);
1019 uint32 kadUDPPort
= 0;
1021 if(Kademlia::CKademlia::IsConnected()) {
1022 if (Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0 && Kademlia::CKademlia::GetPrefs()->GetUseExternKadPort() && Kademlia::CUDPFirewallTester::IsVerified()) {
1023 kadUDPPort
= Kademlia::CKademlia::GetPrefs()->GetExternalKadPort();
1025 kadUDPPort
= Kademlia::CKademlia::GetPrefs()->GetInternKadPort();
1029 CTagVarInt
tagUdpPorts(CT_EMULE_UDPPORTS
, (kadUDPPort
<< 16) | ((uint32
)thePrefs::GetEffectiveUDPPort()), GetVBTTags() ? 0 : 32);
1030 tagUdpPorts
.WriteTagToFile(data
);
1032 if( theApp
->clientlist
->GetBuddy() && theApp
->IsFirewalled() ) {
1033 CTagVarInt
tagBuddyIP(CT_EMULE_BUDDYIP
, theApp
->clientlist
->GetBuddy()->GetIP(), GetVBTTags() ? 0 : 32);
1034 tagBuddyIP
.WriteTagToFile(data
);
1036 CTagVarInt
tagBuddyPort(CT_EMULE_BUDDYUDP
,
1038 ((uint32
)theApp
->clientlist
->GetBuddy()->GetUDPPort() )
1039 , GetVBTTags() ? 0 : 32);
1040 tagBuddyPort
.WriteTagToFile(data
);
1044 CTagVarInt
tagMuleVersion(CT_EMULE_VERSION
,
1046 make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
)
1048 , GetVBTTags() ? 0 : 32);
1049 tagMuleVersion
.WriteTagToFile(data
);
1052 // eMule Misc. Options #1
1053 const uint32 uUdpVer
= 4;
1054 const uint32 uDataCompVer
= 1;
1055 const uint32 uSupportSecIdent
= theApp
->CryptoAvailable() ? 3 : 0;
1056 const uint32 uSourceExchangeVer
= 3;
1057 const uint32 uExtendedRequestsVer
= 2;
1058 const uint32 uAcceptCommentVer
= 1;
1059 const uint32 uNoViewSharedFiles
= (thePrefs::CanSeeShares() == vsfaNobody
) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag
1060 const uint32 uMultiPacket
= 1;
1061 const uint32 uSupportPreview
= 0; // No network preview at all.
1062 const uint32 uPeerCache
= 0; // No peercache for aMule, baby
1063 const uint32 uUnicodeSupport
= 1;
1064 const uint32 nAICHVer
= 1; // AICH is ENABLED right now.
1066 CTagVarInt
tagMisOptions(CT_EMULE_MISCOPTIONS1
,
1067 (nAICHVer
<< ((4*7)+1)) |
1068 (uUnicodeSupport
<< 4*7) |
1070 (uDataCompVer
<< 4*5) |
1071 (uSupportSecIdent
<< 4*4) |
1072 (uSourceExchangeVer
<< 4*3) |
1073 (uExtendedRequestsVer
<< 4*2) |
1074 (uAcceptCommentVer
<< 4*1) |
1075 (uPeerCache
<< 1*3) |
1076 (uNoViewSharedFiles
<< 1*2) |
1077 (uMultiPacket
<< 1*1) |
1078 (uSupportPreview
<< 1*0)
1079 , GetVBTTags() ? 0 : 32);
1080 tagMisOptions
.WriteTagToFile(data
);
1082 // eMule Misc. Options #2
1083 const uint32 uKadVersion
= KADEMLIA_VERSION
;
1084 const uint32 uSupportLargeFiles
= 1;
1085 const uint32 uExtMultiPacket
= 1;
1086 const uint32 uReserved
= 0; // mod bit
1087 const uint32 uSupportsCryptLayer
= thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1088 const uint32 uRequestsCryptLayer
= thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1089 const uint32 uRequiresCryptLayer
= thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1090 const uint32 uSupportsSourceEx2
= 1;
1091 // direct callback is only possible if connected to kad, tcp firewalled and verified UDP open (for example on a full cone NAT)
1092 const uint32 uDirectUDPCallback
= (Kademlia::CKademlia::IsRunning() && Kademlia::CKademlia::IsFirewalled()
1093 && !Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) && Kademlia::CUDPFirewallTester::IsVerified()) ? 1 : 0;
1095 CTagVarInt
tagMisOptions2(CT_EMULE_MISCOPTIONS2
,
1097 (uDirectUDPCallback
<< 12) |
1098 // (uSupportsCaptcha << 11) | // No captcha support in aMule
1099 (uSupportsSourceEx2
<< 10) |
1100 (uRequiresCryptLayer
<< 9) |
1101 (uRequestsCryptLayer
<< 8) |
1102 (uSupportsCryptLayer
<< 7) |
1104 (uExtMultiPacket
<< 5) |
1105 (uSupportLargeFiles
<< 4) |
1107 , GetVBTTags() ? 0 : 32 );
1108 tagMisOptions2
.WriteTagToFile(data
);
1110 const uint32 nOSInfoSupport
= 1; // We support OS_INFO
1111 const uint32 nValueBasedTypeTags
= 0; // Experimental, disabled
1113 CTagVarInt
tagMisCompatOptions(CT_EMULECOMPAT_OPTIONS
,
1114 (nValueBasedTypeTags
<< 1*1) |
1115 (nOSInfoSupport
<< 1*0)
1116 , GetVBTTags() ? 0 : 32);
1118 tagMisCompatOptions
.WriteTagToFile(data
);
1121 wxString
mod_name(MOD_VERSION_LONG
);
1122 CTagString
tagModName(ET_MOD_VERSION
, mod_name
);
1123 tagModName
.WriteTagToFile(data
);
1128 if (theApp
->IsConnectedED2K()) {
1129 dwIP
= theApp
->serverconnect
->GetCurrentServer()->GetIP();
1130 nPort
= theApp
->serverconnect
->GetCurrentServer()->GetPort();
1132 data
->WriteUInt32(dwIP
);
1133 data
->WriteUInt16(nPort
);
1137 void CUpDownClient::ProcessMuleCommentPacket(const byte
* pachPacket
, uint32 nSize
)
1140 throw CInvalidPacket(wxT("Comment packet for unknown file"));
1143 if (!m_reqfile
->IsPartFile()) {
1144 throw CInvalidPacket(wxT("Comment packet for completed file"));
1147 const CMemFile
data(pachPacket
, nSize
);
1149 uint8 rating
= data
.ReadUInt8();
1151 AddDebugLogLineM( false, logClient
, wxString(wxT("Invalid Rating for file '")) << m_clientFilename
<< wxT("' received: ") << rating
);
1155 AddDebugLogLineM( false, logClient
, wxString(wxT("Rating for file '")) << m_clientFilename
<< wxT("' received: ") << m_iRating
);
1158 // The comment is unicoded, with a uin32 len and safe read
1159 // (won't break if string size is < than advertised len)
1160 // Truncated to MAXFILECOMMENTLEN size
1161 m_strComment
= data
.ReadString((GetUnicodeSupport() != utf8strNone
), 4 /* bytes (it's a uint32)*/, true).Left(MAXFILECOMMENTLEN
);
1163 AddDebugLogLineM( false, logClient
, wxString(wxT("Description for file '")) << m_clientFilename
<< wxT("' received: ") << m_strComment
);
1165 // Update file rating
1166 m_reqfile
->UpdateFileRatingCommentAvail();
1170 void CUpDownClient::ClearDownloadBlockRequests()
1173 std::list
<Requested_Block_Struct
*>::iterator it
= m_DownloadBlocks_list
.begin();
1174 for (; it
!= m_DownloadBlocks_list
.end(); ++it
) {
1175 Requested_Block_Struct
* cur_block
= *it
;
1178 m_reqfile
->RemoveBlockFromList(cur_block
->StartOffset
, cur_block
->EndOffset
);
1184 m_DownloadBlocks_list
.clear();
1188 std::list
<Pending_Block_Struct
*>::iterator it
= m_PendingBlocks_list
.begin();
1189 for (; it
!= m_PendingBlocks_list
.end(); ++it
) {
1190 Pending_Block_Struct
* pending
= *it
;
1193 m_reqfile
->RemoveBlockFromList(pending
->block
->StartOffset
, pending
->block
->EndOffset
);
1196 delete pending
->block
;
1197 // Not always allocated
1198 if (pending
->zStream
){
1199 inflateEnd(pending
->zStream
);
1200 delete pending
->zStream
;
1206 m_PendingBlocks_list
.clear();
1211 bool CUpDownClient::Disconnected(const wxString
& strReason
, bool bFromSocket
)
1213 //wxASSERT(theApp->clientlist->IsValidClient(this));
1215 // was this a direct callback?
1216 if (m_dwDirectCallbackTimeout
!= 0) {
1217 theApp
->clientlist
->RemoveDirectCallback(this);
1218 m_dwDirectCallbackTimeout
= 0;
1219 theApp
->clientlist
->AddDeadSource(this);
1220 AddDebugLogLineM(false, logClient
, wxT("Direct callback failed to client ") + GetUserHash().Encode() + wxT(" on ip ") + GetFullIP());
1223 if (GetKadState() == KS_QUEUED_FWCHECK_UDP
|| GetKadState() == KS_CONNECTING_FWCHECK_UDP
) {
1224 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test was cancelled
1225 } else if (GetKadState() == KS_FWCHECK_UDP
) {
1226 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, false, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test has failed
1227 // } else if (GetKadState() == KS_CONNECTED_BUDDY) {
1228 // AddDebugLogLineM(false, logClient, wxT("Buddy client disconnected - ") + strReason);
1231 //If this is a KAD client object, just delete it!
1232 SetKadState(KS_NONE
);
1234 if (GetUploadState() == US_UPLOADING
) {
1235 theApp
->uploadqueue
->RemoveFromUploadQueue(this);
1238 if (GetDownloadState() == DS_DOWNLOADING
) {
1239 SetDownloadState(DS_ONQUEUE
);
1241 // ensure that all possible block requests are removed from the partfile
1242 ClearDownloadBlockRequests();
1244 if ( GetDownloadState() == DS_CONNECTED
){
1245 theApp
->clientlist
->AddDeadSource(this);
1246 theApp
->downloadqueue
->RemoveSource(this);
1250 // we had still an AICH request pending, handle it
1251 if (IsAICHReqPending()){
1252 m_fAICHRequested
= FALSE
;
1253 CAICHHashSet::ClientAICHRequestFailed(this);
1256 // The remote client does not have to answer with OP_HASHSETANSWER *immediatly*
1257 // after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client
1258 // is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
1259 if (((GetDownloadState() == DS_REQHASHSET
) || m_fHashsetRequesting
) && (m_reqfile
)) {
1260 m_reqfile
->SetHashSetNeeded(true);
1263 //check if this client is needed in any way, if not delete it
1264 bool bDelete
= true;
1265 switch(m_nUploadState
){
1266 case US_ONUPLOADQUEUE
:
1270 switch(m_nDownloadState
){
1272 case DS_TOOMANYCONNS
:
1273 case DS_NONEEDEDPARTS
:
1278 switch(m_nUploadState
){
1280 case US_WAITCALLBACK
:
1282 theApp
->clientlist
->AddDeadSource(this);
1285 switch(m_nDownloadState
){
1287 case DS_WAITCALLBACK
:
1289 theApp
->clientlist
->AddDeadSource(this);
1294 if (GetChatState() != MS_NONE
){
1296 m_pendingMessage
.Clear();
1297 Notify_ChatConnResult(false,GUI_ID(GetIP(),GetUserPort()),wxEmptyString
);
1300 if (!bFromSocket
&& m_socket
){
1301 wxASSERT (theApp
->listensocket
->IsValidSocket(m_socket
));
1302 m_socket
->Safe_Delete();
1307 if (m_iFileListRequested
){
1308 AddLogLineM( false, CFormat(_("Failed to retrieve shared files from user '%s'")) % GetUserName() );
1309 m_iFileListRequested
= 0;
1312 Notify_ClientCtrlRefreshClient( this );
1316 // Remove the friend linkage
1317 Notify_ChatRefreshFriend(m_Friend
->GetIP(), m_Friend
->GetPort(), wxEmptyString
);
1319 AddDebugLogLineM( false, logClient
, wxString() <<
1320 wxT("--- Deleted client \"") << GetClientFullInfo() <<
1321 wxT("\"; Reason was ") << strReason
);
1323 AddDebugLogLineM( false, logClient
, wxString() <<
1324 wxT("--- Disconnected client \"") << GetClientFullInfo() <<
1325 wxT("\"; Reason was ") << strReason
);
1326 m_fHashsetRequesting
= 0;
1327 SetSentCancelTransfer(0);
1328 m_bHelloAnswerPending
= false;
1329 m_fSentOutOfPartReqs
= 0;
1335 //Returned bool is not if the TryToConnect is successful or not..
1336 //false means the client was deleted!
1337 //true means the client was not deleted!
1338 bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon
)
1341 if (theApp
->listensocket
->TooManySockets() && !bIgnoreMaxCon
) {
1342 if (!(m_socket
&& m_socket
->IsConnected())) {
1343 if(Disconnected(wxT("Too many connections"))) {
1351 // Do not try to connect to source which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it)
1352 if ( (RequiresCryptLayer() && !thePrefs::IsClientCryptLayerSupported()) || (thePrefs::IsClientCryptLayerRequired() && !SupportsCryptLayer()) ){
1353 if(Disconnected(wxT("CryptLayer-Settings (Obfuscation) incompatible"))){
1362 uint32 uClientIP
= GetIP();
1363 if (uClientIP
== 0 && !HasLowID()) {
1364 uClientIP
= wxUINT32_SWAP_ALWAYS(m_nUserIDHybrid
);
1368 // Although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
1369 // we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
1370 if (theApp
->ipfilter
->IsFiltered(uClientIP
)) {
1371 AddDebugLogLineM(false, logIPFilter
, CFormat(wxT("Filtered ip %u (%s) on TryToConnect\n")) % uClientIP
% Uint32toStringIP(uClientIP
));
1372 if (Disconnected(wxT("IPFilter"))) {
1380 // for safety: check again whether that IP is banned
1381 if (theApp
->clientlist
->IsBannedClient(uClientIP
)) {
1382 AddDebugLogLineM(false, logClient
, wxT("Refused to connect to banned client ") + Uint32toStringIP(uClientIP
));
1383 if (Disconnected(wxT("Banned IP"))) {
1391 if (GetKadState() == KS_QUEUED_FWCHECK
) {
1392 SetKadState(KS_CONNECTING_FWCHECK
);
1393 } else if (GetKadState() == KS_QUEUED_FWCHECK_UDP
) {
1394 SetKadState(KS_CONNECTING_FWCHECK_UDP
);
1398 if (!theApp
->DoCallback(this)) {
1399 //We cannot do a callback!
1400 if (GetDownloadState() == DS_CONNECTING
) {
1401 SetDownloadState(DS_LOWTOLOWIP
);
1402 } else if (GetDownloadState() == DS_REQHASHSET
) {
1403 SetDownloadState(DS_ONQUEUE
);
1404 m_reqfile
->SetHashSetNeeded(true);
1406 if (GetUploadState() == US_CONNECTING
) {
1407 if(Disconnected(wxT("LowID->LowID and US_CONNECTING"))) {
1415 //We already know we are not firewalled here as the above condition already detected LowID->LowID and returned.
1416 //If ANYTHING changes with the "if(!theApp->DoCallback(this))" above that will let you fall through
1417 //with the condition that the source is firewalled and we are firewalled, we must
1418 //recheck it before the this check..
1419 if (HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp
->serverconnect
->IsLocalServer(GetServerIP(), GetServerPort())
1420 && !(SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0)) {
1421 //This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort.
1422 if( Kademlia::CKademlia::IsConnected() ) {
1423 //We are connect to Kad
1424 if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID()))) {
1425 //There are too many source lookups already or we are already searching this key.
1426 SetDownloadState(DS_TOOMANYCONNSKAD
);
1433 if (!m_socket
|| !m_socket
->IsConnected()) {
1435 m_socket
->Safe_Delete();
1437 m_socket
= new CClientTCPSocket(this, thePrefs::GetProxyData());
1439 ConnectionEstablished();
1444 if (HasLowID() && SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0 && GetConnectIP() != 0) { // LOWID with DirectCallback
1445 if (m_dwDirectCallbackTimeout
!= 0) {
1446 AddDebugLogLineM(false, logClient
, wxT("ERROR: Trying Direct UDP Callback while already trying to connect to client ") + GetUserHash().Encode());
1447 return true; // We're already trying a direct connection to this client
1449 // a direct callback is possible - since no other parties are involved and only one additional packet overhead
1450 // is used we basically handle it like a normal connection try, no restrictions apply
1451 // we already check above with !theApp->DoCallback(this) if any callback is possible at all
1452 m_dwDirectCallbackTimeout
= ::GetTickCount() + SEC2MS(45);
1453 theApp
->clientlist
->AddDirectCallbackClient(this);
1455 AddDebugLogLineM(false, logClient
, wxString::Format(wxT("Direct Callback on port %u to client "), GetKadPort()) + GetUserHash().Encode());
1458 data
.WriteUInt16(thePrefs::GetPort()); // needs to know our port
1459 data
.WriteHash(thePrefs::GetUserHash()); // and userhash
1460 // our connection settings
1461 data
.WriteUInt8(Kademlia::CPrefs::GetMyConnectOptions(true, false));
1462 AddDebugLogLineM(false, logClientUDP
, wxT("Sending OP_DIRECTCALLBACKREQ to ") + Uint32_16toStringIP_Port(GetConnectIP(), GetKadPort()));
1463 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_DIRECTCALLBACKREQ
);
1464 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1465 theApp
->clientudp
->SendPacket(packet
, GetConnectIP(), GetKadPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0);
1466 } else if (HasLowID()) { // LOWID
1467 if (GetDownloadState() == DS_CONNECTING
) {
1468 SetDownloadState(DS_WAITCALLBACK
);
1470 if (GetUploadState() == US_CONNECTING
) {
1471 if(Disconnected(wxT("LowID and US_CONNECTING"))) {
1478 if (theApp
->serverconnect
->IsLocalServer(m_dwServerIP
,m_nServerPort
)) {
1480 // AFAICS, this id must be reversed to be sent to clients
1481 // But if I reverse it, we do a serve violation ;)
1482 data
.WriteUInt32(m_nUserIDHybrid
);
1483 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_CALLBACKREQUEST
);
1484 theStats::AddUpOverheadServer(packet
->GetPacketSize());
1485 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_CALLBACKREQUEST to ") + GetFullIP());
1486 theApp
->serverconnect
->SendPacket(packet
);
1487 SetDownloadState(DS_WAITCALLBACK
);
1489 if (GetUploadState() == US_NONE
&& (!GetRemoteQueueRank() || m_bReaskPending
)) {
1491 if( !HasValidBuddyID() ) {
1492 theApp
->downloadqueue
->RemoveSource(this);
1493 if (Disconnected(wxT("LowID and US_NONE and QR=0"))) {
1500 if( !Kademlia::CKademlia::IsConnected() ) {
1501 //We are not connected to Kad and this is a Kad Firewalled source..
1502 theApp
->downloadqueue
->RemoveSource(this);
1503 if(Disconnected(wxT("Kad Firewalled source but not connected to Kad."))) {
1510 if( GetDownloadState() == DS_WAITCALLBACK
) {
1511 if( GetBuddyIP() && GetBuddyPort()) {
1513 bio
.WriteUInt128(Kademlia::CUInt128(GetBuddyID()));
1514 bio
.WriteUInt128(Kademlia::CUInt128(m_reqfile
->GetFileHash().GetHash()));
1515 bio
.WriteUInt16(thePrefs::GetPort());
1516 CPacket
* packet
= new CPacket(bio
, OP_KADEMLIAHEADER
, KADEMLIA_CALLBACK_REQ
);
1517 // eMule FIXME: We dont know which kadversion the buddy has, so we need to send unencrypted
1518 theApp
->clientudp
->SendPacket(packet
, GetBuddyIP(), GetBuddyPort(), false, NULL
, true, 0);
1519 AddDebugLogLineM(false,logLocalClient
, wxString::Format(wxT("KADEMLIA_CALLBACK_REQ (%i) to"),packet
->GetPacketSize()) + GetFullIP());
1520 theStats::AddUpOverheadKad(packet
->GetRealPacketSize());
1521 SetDownloadState(DS_WAITCALLBACKKAD
);
1523 printf("Searching buddy for lowid connection\n");
1524 //Create search to find buddy.
1525 Kademlia::CSearch
*findSource
= new Kademlia::CSearch
;
1526 findSource
->SetSearchTypes(Kademlia::CSearch::FINDSOURCE
);
1527 findSource
->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
1528 findSource
->AddFileID(Kademlia::CUInt128(m_reqfile
->GetFileHash().GetHash()));
1529 if(Kademlia::CSearchManager::StartSearch(findSource
)) {
1531 SetDownloadState(DS_WAITCALLBACKKAD
);
1533 //This should never happen..
1539 if (GetDownloadState() == DS_WAITCALLBACK
) {
1540 m_bReaskPending
= true;
1541 SetDownloadState(DS_ONQUEUE
);
1553 bool CUpDownClient::Connect()
1555 m_hasbeenobfuscatinglately
= false;
1557 if (!m_socket
->IsOk()) {
1558 // Enable or disable crypting based on our and the remote clients preference
1559 if (HasValidHash() && SupportsCryptLayer() && thePrefs::IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested())){
1560 // printf("Set connection encryption for socket\n");
1561 //DebugLog(_T("Enabling CryptLayer on outgoing connection to client %s"), DbgGetClientInfo()); // to be removed later
1562 m_socket
->SetConnectionEncryption(true, GetUserHash().GetHash(), false);
1564 m_socket
->SetConnectionEncryption(false, NULL
, false);
1566 amuleIPV4Address tmp
;
1567 tmp
.Hostname(GetConnectIP());
1568 tmp
.Service(GetUserPort());
1569 AddDebugLogLineM(false, logClient
, wxT("Trying to connect to ") + Uint32_16toStringIP_Port(GetConnectIP(),GetUserPort()));
1570 m_socket
->Connect(tmp
, false);
1571 // We should send hello packets AFTER connecting!
1572 // so I moved it to OnConnect
1579 void CUpDownClient::ConnectionEstablished()
1582 /* Kry - First thing, check if this client was just used to retrieve
1583 info. That's some debug thing for myself... check connection_reason
1586 m_hasbeenobfuscatinglately
= (m_socket
&& m_socket
->IsConnected() && m_socket
->IsObfusicating());
1589 if (!connection_reason
.IsEmpty()) {
1590 printf("Got client info checking for %s: %s\nDisconnecting and deleting.\n",(const char*)unicode2char(connection_reason
),(const char*)unicode2char(GetClientFullInfo()));
1591 connection_reason
.Clear(); // So we don't re-printf on destructor.
1597 // Check if we should use this client to retrieve our public IP
1598 // Ignore local ip on GetPublicIP (could be wrong)
1599 if (theApp
->GetPublicIP(true) == 0 && theApp
->IsConnectedED2K()) {
1600 SendPublicIPRequest();
1603 // was this a direct callback?
1604 if (m_dwDirectCallbackTimeout
!= 0){
1605 theApp
->clientlist
->RemoveDirectCallback(this);
1606 m_dwDirectCallbackTimeout
= 0;
1608 AddDebugLogLineM(false, logClient
, wxT("Direct Callback succeeded, connection established to ") + GetUserHash().Encode());
1611 switch (GetKadState()) {
1612 case KS_CONNECTING_FWCHECK
:
1613 SetKadState(KS_CONNECTED_FWCHECK
);
1615 case KS_CONNECTING_BUDDY
:
1616 case KS_INCOMING_BUDDY
:
1617 SetKadState(KS_CONNECTED_BUDDY
);
1619 case KS_CONNECTING_FWCHECK_UDP
:
1620 SetKadState(KS_FWCHECK_UDP
);
1621 SendFirewallCheckUDPRequest();
1627 // ok we have a connection, lets see if we want anything from this client
1628 if (GetChatState() == MS_CONNECTING
) {
1629 SetChatState( MS_CHATTING
);
1632 if (GetChatState() == MS_CHATTING
) {
1634 if (!m_pendingMessage
.IsEmpty()) {
1635 result
= SendMessage(m_pendingMessage
);
1637 Notify_ChatConnResult(result
,GUI_ID(GetIP(),GetUserPort()),m_pendingMessage
);
1638 m_pendingMessage
.Clear();
1641 switch(GetDownloadState()) {
1643 case DS_WAITCALLBACK
:
1644 case DS_WAITCALLBACKKAD
:
1645 m_bReaskPending
= false;
1646 SetDownloadState(DS_CONNECTED
);
1649 if (m_bReaskPending
){
1650 m_bReaskPending
= false;
1651 if (GetDownloadState() != DS_NONE
&& GetDownloadState() != DS_DOWNLOADING
) {
1652 SetDownloadState(DS_CONNECTED
);
1656 switch(GetUploadState()){
1658 case US_WAITCALLBACK
:
1659 if (theApp
->uploadqueue
->IsDownloading(this)) {
1660 SetUploadState(US_UPLOADING
);
1661 CPacket
* packet
= new CPacket(OP_ACCEPTUPLOADREQ
, 0, OP_EDONKEYPROT
);
1662 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1663 SendPacket(packet
,true);
1664 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + GetFullIP() );
1667 if (m_iFileListRequested
== 1) {
1668 CPacket
* packet
= new CPacket(m_fSharedDirectories
? OP_ASKSHAREDDIRS
: OP_ASKSHAREDFILES
, 0, OP_EDONKEYPROT
);
1669 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1670 SendPacket(packet
,true,true);
1671 if (m_fSharedDirectories
) {
1672 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRS to ") + GetFullIP() );
1674 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILES to ") + GetFullIP() );
1678 while (!m_WaitingPackets_list
.empty()) {
1679 CPacket
* packet
= m_WaitingPackets_list
.front();
1680 m_WaitingPackets_list
.pop_front();
1687 int CUpDownClient::GetHashType() const
1689 if ( m_UserHash
[5] == 13 && m_UserHash
[14] == 110 ) {
1693 if ( m_UserHash
[5] == 14 && m_UserHash
[14] == 111 ) {
1697 if ( m_UserHash
[5] == 'M' && m_UserHash
[14] == 'L' ) {
1705 void CUpDownClient::SetSocket(CClientTCPSocket
* socket
)
1707 #if defined(__DEBUG__) && !defined(EC_REMOTE)
1708 if (m_socket
== NULL
&& socket
!= NULL
) {
1709 theStats::SocketAssignedToClient();
1710 } else if (m_socket
!= NULL
&& socket
== NULL
) {
1711 theStats::SocketUnassignedFromClient();
1718 void CUpDownClient::ReGetClientSoft()
1720 if (m_Username
.IsEmpty()) {
1721 m_clientSoft
=SO_UNKNOWN
;
1722 m_clientVerString
= m_clientSoftString
= m_clientVersionString
= m_fullClientVerString
= _("Unknown");
1727 int iHashType
= GetHashType();
1728 wxString clientModString
;
1729 if (iHashType
== SO_EMULE
) {
1731 m_clientSoft
= m_byCompatibleClient
;
1732 m_clientSoftString
= GetSoftName(m_clientSoft
);
1734 if(!GetClientModString().IsEmpty() && (m_clientSoft
!= SO_EMULE
)) {
1735 m_clientSoftString
= GetClientModString();
1737 // Isn't xMule annoying?
1738 if ((m_clientSoft
== SO_LXMULE
) && (GetMuleVersion() > 0x26) && (GetMuleVersion() != 0x99)) {
1739 m_clientSoftString
+= wxString::Format(_(" (Fake eMule version %#x)"),GetMuleVersion());
1741 if ((m_clientSoft
== SO_EMULE
) &&
1743 wxString(GetClientModString()).MakeLower().Find(wxT("xmule")) != -1
1744 || GetUserName().Find(wxT("xmule.")) != -1
1747 // FAKE eMule -a newer xMule faking is ident.
1748 m_clientSoft
= SO_LXMULE
;
1749 if (GetClientModString().IsEmpty() == false) {
1750 m_clientSoftString
= GetClientModString() + _(" (Fake eMule)");
1752 m_clientSoftString
= _("xMule (Fake eMule)"); // don't use GetSoftName, it's not lmule.
1755 // Now, what if we don't know this SO_ID?
1756 if (m_clientSoftString
.IsEmpty()) {
1758 m_clientSoft
= SO_MLDONKEY
;
1759 m_clientSoftString
= GetSoftName(m_clientSoft
);
1760 } else if (m_bIsHybrid
) {
1761 m_clientSoft
= SO_EDONKEYHYBRID
;
1762 m_clientSoftString
= GetSoftName(m_clientSoft
);
1763 } else if (m_byCompatibleClient
!= 0) {
1764 m_clientSoft
= SO_COMPAT_UNK
;
1768 (m_byCompatibleClient
!= 0xf0) // Chinese leech mod
1769 && (1==1) // Your ad here
1771 printf("Compatible client found with ET_COMPATIBLECLIENT of %#x\n",m_byCompatibleClient
);
1774 m_clientSoftString
= GetSoftName(m_clientSoft
) + wxString::Format(wxT("(%#x)"),m_byCompatibleClient
);
1776 // If we step here, it might mean 2 things:
1778 // a Compat Client that has sent no MuleInfo packet yet.
1779 m_clientSoft
= SO_EMULE
;
1780 m_clientSoftString
= wxT("eMule");
1784 if (m_byEmuleVersion
== 0) {
1785 m_nClientVersion
= MAKE_CLIENT_VERSION(0,0,0);
1786 } else if (m_byEmuleVersion
!= 0x99) {
1787 uint32 nClientMinVersion
= (m_byEmuleVersion
>> 4)*10 + (m_byEmuleVersion
& 0x0f);
1788 m_nClientVersion
= MAKE_CLIENT_VERSION(0,nClientMinVersion
,0);
1789 switch (m_clientSoft
) {
1791 m_clientVerString
= wxString::Format(_("1.x (based on eMule v0.%u)"), nClientMinVersion
);
1794 m_clientVerString
= wxT("< v0.05");
1797 clientModString
= GetClientModString();
1798 m_clientVerString
= wxString::Format(wxT("v0.%u"), nClientMinVersion
);
1802 uint32 nClientMajVersion
= (m_nClientVersion
>> 17) & 0x7f;
1803 uint32 nClientMinVersion
= (m_nClientVersion
>> 10) & 0x7f;
1804 uint32 nClientUpVersion
= (m_nClientVersion
>> 7) & 0x07;
1806 m_nClientVersion
= MAKE_CLIENT_VERSION(nClientMajVersion
, nClientMinVersion
, nClientUpVersion
);
1808 switch (m_clientSoft
) {
1812 // Kry - xMule started sending correct version tags on 1.9.1b.
1813 // It only took them 4 months, and being told by me and the
1814 // eMule+ developers, so I think they're slowly getting smarter.
1815 // They are based on our implementation, so we use the same format
1816 // for the version string.
1817 m_clientVerString
= wxString::Format(wxT("v%u.%u.%u"), nClientMajVersion
, nClientMinVersion
, nClientUpVersion
);
1820 m_clientVerString
= wxString::Format(wxT(" v%u.%.2u%c"), nClientMajVersion
-1, nClientMinVersion
, 'a' + nClientUpVersion
);
1823 m_clientVerString
= wxString::Format(wxT("v%u"), nClientMajVersion
);
1824 if(nClientMinVersion
!= 0) {
1825 m_clientVerString
+= wxString::Format(wxT(".%u"), nClientMinVersion
);
1827 if(nClientUpVersion
!= 0) {
1828 m_clientVerString
+= wxString::Format(wxT("%c"), 'a' + nClientUpVersion
- 1);
1832 clientModString
= GetClientModString();
1833 m_clientVerString
= wxString::Format(wxT("v%u.%u%c"), nClientMajVersion
, nClientMinVersion
, 'a' + nClientUpVersion
);
1837 } else if (m_bIsHybrid
) {
1844 m_clientSoft
= SO_EDONKEYHYBRID
;
1845 m_clientSoftString
= GetSoftName(m_clientSoft
);
1847 uint32 nClientMajVersion
;
1848 uint32 nClientMinVersion
;
1849 uint32 nClientUpVersion
;
1850 if (m_nClientVersion
> 100000) {
1851 uint32 uMaj
= m_nClientVersion
/100000;
1852 nClientMajVersion
= uMaj
- 1;
1853 nClientMinVersion
= (m_nClientVersion
- uMaj
*100000) / 100;
1854 nClientUpVersion
= m_nClientVersion
% 100;
1856 else if (m_nClientVersion
> 10000) {
1857 uint32 uMaj
= m_nClientVersion
/10000;
1858 nClientMajVersion
= uMaj
- 1;
1859 nClientMinVersion
= (m_nClientVersion
- uMaj
*10000) / 10;
1860 nClientUpVersion
= m_nClientVersion
% 10;
1862 else if (m_nClientVersion
> 1000) {
1863 uint32 uMaj
= m_nClientVersion
/1000;
1864 nClientMajVersion
= uMaj
- 1;
1865 nClientMinVersion
= m_nClientVersion
- uMaj
*1000;
1866 nClientUpVersion
= 0;
1868 else if (m_nClientVersion
> 100) {
1869 uint32 uMin
= m_nClientVersion
/10;
1870 nClientMajVersion
= 0;
1871 nClientMinVersion
= uMin
;
1872 nClientUpVersion
= m_nClientVersion
- uMin
*10;
1875 nClientMajVersion
= 0;
1876 nClientMinVersion
= m_nClientVersion
;
1877 nClientUpVersion
= 0;
1879 m_nClientVersion
= MAKE_CLIENT_VERSION(nClientMajVersion
, nClientMinVersion
, nClientUpVersion
);
1880 if (nClientUpVersion
) {
1881 m_clientVerString
= wxString::Format(wxT("v%u.%u.%u"), nClientMajVersion
, nClientMinVersion
, nClientUpVersion
);
1883 m_clientVerString
= wxString::Format(wxT("v%u.%u"), nClientMajVersion
, nClientMinVersion
);
1885 } else if (m_bIsML
|| (iHashType
== SO_MLDONKEY
)) {
1886 m_clientSoft
= SO_MLDONKEY
;
1887 m_clientSoftString
= GetSoftName(m_clientSoft
);
1888 uint32 nClientMinVersion
= m_nClientVersion
;
1889 m_nClientVersion
= MAKE_CLIENT_VERSION(0, nClientMinVersion
, 0);
1890 m_clientVerString
= wxString::Format(wxT("v0.%u"), nClientMinVersion
);
1891 } else if (iHashType
== SO_OLDEMULE
) {
1892 m_clientSoft
= SO_OLDEMULE
;
1893 m_clientSoftString
= GetSoftName(m_clientSoft
);
1894 uint32 nClientMinVersion
= m_nClientVersion
;
1895 m_nClientVersion
= MAKE_CLIENT_VERSION(0, nClientMinVersion
, 0);
1896 m_clientVerString
= wxString::Format(wxT("v0.%u"), nClientMinVersion
);
1898 m_clientSoft
= SO_EDONKEY
;
1899 m_clientSoftString
= GetSoftName(m_clientSoft
);
1900 m_nClientVersion
*= 10;
1901 m_clientVerString
= wxString::Format(wxT("v%u.%u"), m_nClientVersion
/ 100000, (m_nClientVersion
/ 1000) % 100);
1904 m_clientVersionString
= m_clientVerString
;
1905 if (!clientModString
.IsEmpty()) {
1906 m_clientVerString
+= wxT(" - ") + clientModString
;
1908 m_fullClientVerString
= m_clientSoftString
+ wxT(" ") + m_clientVerString
;
1913 void CUpDownClient::RequestSharedFileList()
1915 if (m_iFileListRequested
== 0) {
1916 AddDebugLogLineM( false, logClient
, wxString( wxT("Requesting shared files from ") ) + GetUserName() );
1917 m_iFileListRequested
= 1;
1920 AddDebugLogLineM( false, logClient
, CFormat( wxT("Requesting shared files from user %s (%u) is already in progress") ) % GetUserName() % GetUserIDHybrid() );
1925 void CUpDownClient::ProcessSharedFileList(const byte
* pachPacket
, uint32 nSize
, wxString
& pszDirectory
)
1927 if (m_iFileListRequested
> 0) {
1928 m_iFileListRequested
--;
1929 theApp
->searchlist
->ProcessSharedFileList(pachPacket
, nSize
, this, NULL
, pszDirectory
);
1934 void CUpDownClient::ResetFileStatusInfo()
1939 m_reqfile
->UpdatePartsFrequency( this, false );
1941 m_downPartStatus
.clear();
1943 m_clientFilename
.Clear();
1945 m_bCompleteSource
= false;
1946 m_dwLastAskedTime
= 0;
1948 m_strComment
.Clear();
1950 if (m_pReqFileAICHHash
!= NULL
) {
1951 delete m_pReqFileAICHHash
;
1952 m_pReqFileAICHHash
= NULL
;
1957 wxString
CUpDownClient::GetUploadFileInfo()
1959 // build info text and display it
1961 sRet
= (CFormat(_("NickName: %s ID: %u")) % GetUserName() % GetUserIDHybrid()) + wxT(" ");
1963 sRet
+= CFormat(_("Requested: %s\n")) % m_reqfile
->GetFileName();
1965 wxPLURAL("Filestats for this session: Accepted %d of %d request, %s transferred\n", "Filestats for this session: Accepted %d of %d requests, %s transferred\n", m_reqfile
->statistic
.GetRequests())
1966 ) % m_reqfile
->statistic
.GetAccepts() % m_reqfile
->statistic
.GetRequests() % CastItoXBytes(m_reqfile
->statistic
.GetTransferred());
1968 wxPLURAL("Filestats for all sessions: Accepted %d of %d request, %s transferred\n", "Filestats for all sessions: Accepted %d of %d requests, %s transferred\n", m_reqfile
->statistic
.GetAllTimeRequests())
1969 ) % m_reqfile
->statistic
.GetAllTimeAccepts() % m_reqfile
->statistic
.GetAllTimeRequests() % CastItoXBytes(m_reqfile
->statistic
.GetAllTimeTransferred());
1971 sRet
+= _("Requested unknown file");
1976 // sends a packet, if needed it will establish a connection before
1977 // options used: ignore max connections, control packet, delete packet
1978 // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails
1979 bool CUpDownClient::SafeSendPacket(CPacket
* packet
)
1981 if (IsConnected()) {
1982 SendPacket(packet
, true);
1985 m_WaitingPackets_list
.push_back(packet
);
1986 return TryToConnect(true);
1990 void CUpDownClient::SendPublicKeyPacket(){
1991 // send our public key to the client who requested it
1992 if (m_socket
== NULL
|| credits
== NULL
|| m_SecureIdentState
!= IS_KEYANDSIGNEEDED
){
1996 if (!theApp
->CryptoAvailable())
2000 data
.WriteUInt8(theApp
->clientcredits
->GetPubKeyLen());
2001 data
.Write(theApp
->clientcredits
->GetPublicKey(), theApp
->clientcredits
->GetPubKeyLen());
2002 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_PUBLICKEY
);
2004 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2005 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_PUBLICKEY to ") + GetFullIP() );
2006 SendPacket(packet
,true,true);
2007 m_SecureIdentState
= IS_SIGNATURENEEDED
;
2011 void CUpDownClient::SendSignaturePacket(){
2012 // signate the public key of this client and send it
2013 if (m_socket
== NULL
|| credits
== NULL
|| m_SecureIdentState
== 0){
2018 if (!theApp
->CryptoAvailable()) {
2021 if (credits
->GetSecIDKeyLen() == 0) {
2022 return; // We don't have his public key yet, will be back here later
2024 // do we have a challenge value received (actually we should if we are in this function)
2025 if (credits
->m_dwCryptRndChallengeFrom
== 0){
2026 AddDebugLogLineM( false, logClient
, wxString(wxT("Want to send signature but challenge value is invalid - User ")) + GetUserName());
2030 // we will use v1 as default, except if only v2 is supported
2032 if ( (m_bySupportSecIdent
&1) == 1 )
2037 uint8 byChaIPKind
= 0;
2038 uint32 ChallengeIP
= 0;
2040 if (::IsLowID(theApp
->GetED2KID())) {
2041 // we cannot do not know for sure our public ip, so use the remote clients one
2042 ChallengeIP
= GetIP();
2043 byChaIPKind
= CRYPT_CIP_REMOTECLIENT
;
2045 ChallengeIP
= theApp
->GetED2KID();
2046 byChaIPKind
= CRYPT_CIP_LOCALCLIENT
;
2050 byte achBuffer
[250];
2052 uint8 siglen
= theApp
->clientcredits
->CreateSignature(credits
, achBuffer
, 250, ChallengeIP
, byChaIPKind
);
2058 data
.WriteUInt8(siglen
);
2059 data
.Write(achBuffer
, siglen
);
2061 data
.WriteUInt8(byChaIPKind
);
2064 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_SIGNATURE
);
2066 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2067 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_SIGNATURE to ") + GetFullIP() );
2068 SendPacket(packet
,true,true);
2069 m_SecureIdentState
= IS_ALLREQUESTSSEND
;
2073 void CUpDownClient::ProcessPublicKeyPacket(const byte
* pachPacket
, uint32 nSize
)
2075 theApp
->clientlist
->AddTrackClient(this);
2077 if (m_socket
== NULL
|| credits
== NULL
|| pachPacket
[0] != nSize
-1
2078 || nSize
== 0 || nSize
> 250){
2082 if (!theApp
->CryptoAvailable())
2084 // the function will handle everything (mulitple key etc)
2085 if (credits
->SetSecureIdent(pachPacket
+1, pachPacket
[0])){
2086 // if this client wants a signature, now we can send him one
2087 if (m_SecureIdentState
== IS_SIGNATURENEEDED
){
2088 SendSignaturePacket();
2090 else if(m_SecureIdentState
== IS_KEYANDSIGNEEDED
){
2091 // something is wrong
2092 AddDebugLogLineM( false, logClient
, wxT("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket") );
2095 AddDebugLogLineM( false, logClient
, wxT("Failed to use new received public key") );
2100 void CUpDownClient::ProcessSignaturePacket(const byte
* pachPacket
, uint32 nSize
)
2102 // here we spread the good guys from the bad ones ;)
2104 if (m_socket
== NULL
|| credits
== NULL
|| nSize
== 0 || nSize
> 250){
2110 if (pachPacket
[0] == nSize
-1)
2112 else if (pachPacket
[0] == nSize
-2 && (m_bySupportSecIdent
& 2) > 0) //v2
2113 byChaIPKind
= pachPacket
[nSize
-1];
2119 if (!theApp
->CryptoAvailable())
2122 // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
2123 if (m_dwLastSignatureIP
== GetIP()){
2124 AddDebugLogLineM( false, logClient
, wxT("received multiple signatures from one client") );
2127 // also make sure this client has a public key
2128 if (credits
->GetSecIDKeyLen() == 0){
2129 AddDebugLogLineM( false, logClient
, wxT("received signature for client without public key") );
2132 // and one more check: did we ask for a signature and sent a challange packet?
2133 if (credits
->m_dwCryptRndChallengeFor
== 0){
2134 AddDebugLogLineM( false, logClient
, wxT("received signature for client with invalid challenge value - User ") + GetUserName() );
2138 if (theApp
->clientcredits
->VerifyIdent(credits
, pachPacket
+1, pachPacket
[0], GetIP(), byChaIPKind
) ){
2139 // result is saved in function above
2140 AddDebugLogLineM( false, logClient
, CFormat( wxT("'%s' has passed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind
);
2142 AddDebugLogLineM( false, logClient
, CFormat( wxT("'%s' has failed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind
);
2145 m_dwLastSignatureIP
= GetIP();
2148 void CUpDownClient::SendSecIdentStatePacket(){
2149 // check if we need public key and signature
2152 if (theApp
->CryptoAvailable()){
2153 if (credits
->GetSecIDKeyLen() == 0) {
2154 nValue
= IS_KEYANDSIGNEEDED
;
2155 } else if (m_dwLastSignatureIP
!= GetIP()) {
2156 nValue
= IS_SIGNATURENEEDED
;
2160 AddDebugLogLineM( false, logClient
, wxT("Not sending SecIdentState Packet, because State is Zero") );
2163 // crypt: send random data to sign
2164 uint32 dwRandom
= rand()+1;
2165 credits
->m_dwCryptRndChallengeFor
= dwRandom
;
2168 data
.WriteUInt8(nValue
);
2169 data
.WriteUInt32(dwRandom
);
2170 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_SECIDENTSTATE
);
2172 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2173 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_SECIDENTSTATE to ") + GetFullIP() );
2174 SendPacket(packet
,true,true);
2181 void CUpDownClient::ProcessSecIdentStatePacket(const byte
* pachPacket
, uint32 nSize
)
2188 wxASSERT( credits
);
2192 CMemFile
data(pachPacket
,nSize
);
2194 switch ( data
.ReadUInt8() ) {
2196 m_SecureIdentState
= IS_UNAVAILABLE
;
2199 m_SecureIdentState
= IS_SIGNATURENEEDED
;
2202 m_SecureIdentState
= IS_KEYANDSIGNEEDED
;
2208 credits
->m_dwCryptRndChallengeFrom
= data
.ReadUInt32();
2212 void CUpDownClient::InfoPacketsReceived()
2214 // indicates that both Information Packets has been received
2215 // needed for actions, which process data from both packets
2216 wxASSERT ( m_byInfopacketsReceived
== IP_BOTH
);
2217 m_byInfopacketsReceived
= IP_NONE
;
2219 if (m_bySupportSecIdent
){
2220 SendSecIdentStatePacket();
2225 bool CUpDownClient::CheckHandshakeFinished(uint32
WXUNUSED(protocol
), uint32
WXUNUSED(opcode
)) const
2227 if (m_bHelloAnswerPending
){
2228 // this triggers way too often.. need more time to look at this -> only create a warning
2229 AddDebugLogLineM( false, logClient
, wxT("Handshake not finished while processing packet.") );
2237 wxString
CUpDownClient::GetClientFullInfo() {
2239 if (m_clientVerString
.IsEmpty()) {
2243 return CFormat( _("Client %s on IP:Port %s:%d using %s %s %s") )
2244 % ( m_Username
.IsEmpty() ? wxString(_("Unknown")) : m_Username
)
2247 % m_clientSoftString
2254 void CUpDownClient::SendPublicIPRequest(){
2256 CPacket
* packet
= new CPacket(OP_PUBLICIP_REQ
,0,OP_EMULEPROT
);
2257 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2258 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_PUBLICIP_REQ to") + GetFullIP());
2259 SendPacket(packet
,true);
2260 m_fNeedOurPublicIP
= true;
2264 void CUpDownClient::ProcessPublicIPAnswer(const byte
* pbyData
, uint32 uSize
){
2266 throw wxString(wxT("Wrong Packet size on Public IP answer"));
2268 uint32 dwIP
= PeekUInt32(pbyData
);
2269 if (m_fNeedOurPublicIP
== true){ // did we?
2270 m_fNeedOurPublicIP
= false;
2271 // Ignore local ip on GetPublicIP (could be wrong)
2272 if (theApp
->GetPublicIP(true) == 0 && !IsLowID(dwIP
) ) {
2273 theApp
->SetPublicIP(dwIP
);
2279 bool CUpDownClient::IsConnected() const
2281 return m_socket
&& m_socket
->IsConnected();
2284 bool CUpDownClient::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
)
2287 m_socket
->SendPacket(packet
, delpacket
, controlpacket
);
2290 printf("CAUGHT DEAD SOCKET IN SENDPACKET()\n");
2295 float CUpDownClient::SetDownloadLimit(uint32 reducedownload
)
2298 // lfroen: in daemon it actually can happen
2299 wxASSERT( m_socket
);
2301 float kBpsClient
= CalculateKBpsDown();
2305 if (reducedownload
) {
2306 // (% to reduce * current speed) / 100 and THEN, / 10 because this
2307 // gets called 10 times per second.
2308 uint32 limit
= (uint32
)(((float)reducedownload
*(kBpsClient
*1024.0))/1000);
2310 if(limit
<1024 && reducedownload
>= 200) {
2311 // If we're going up and this download is < 1kB,
2312 // we want it to go up fast. Can be reduced later,
2313 // and it'll probably be in a more fair way with
2314 // other downloads that are faster.
2316 } else if(limit
== 0) {
2317 // This download is not transferring yet... make it
2318 // 1024 so we don't fill the TCP stack and lose the
2323 m_socket
->SetDownloadLimit(limit
);
2325 m_socket
->DisableDownloadLimit();
2329 printf("CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f\n", kBpsClient
);
2336 void CUpDownClient::SetUserIDHybrid(uint32 nUserID
)
2338 theApp
->clientlist
->UpdateClientID( this, nUserID
);
2340 m_nUserIDHybrid
= nUserID
;
2344 void CUpDownClient::SetIP( uint32 val
)
2346 theApp
->clientlist
->UpdateClientIP( this, val
);
2352 m_FullUserIP
= Uint32toStringIP(val
);
2356 void CUpDownClient::SetUserHash(const CMD4Hash
& userhash
)
2358 theApp
->clientlist
->UpdateClientHash( this, userhash
);
2360 m_UserHash
= userhash
;
2365 EUtf8Str
CUpDownClient::GetUnicodeSupport() const
2367 return m_bUnicodeSupport
? utf8strRaw
: utf8strNone
;
2371 uint8
CUpDownClient::GetSecureIdentState() {
2372 if (m_SecureIdentState
!= IS_UNAVAILABLE
) {
2373 if (!SecIdentSupRec
) {
2374 // This can be caused by a 0.30x based client which sends the old
2375 // style Hello packet, and the mule info packet, but between them they
2376 // send a secure ident state packet (after a hello but before we have
2377 // the SUI capabilities). This is a misbehaving client, and somehow I
2378 // Feel like ti should be dropped. But then again, it won't harm to use
2379 // this SUI state if they are reporting no SUI (won't be used) and if
2380 // they report using SUI on the mule info packet, it's ok to use it.
2382 AddDebugLogLineM(false, logClient
, wxT("A client sent secure ident state before telling us the SUI capabilities"));
2383 AddDebugLogLineM(false, logClient
, wxT("Client info: ") + GetClientFullInfo());
2384 AddDebugLogLineM(false, logClient
, wxT("This client won't be disconnected, but it should be. :P"));
2388 return m_SecureIdentState
;
2392 bool CUpDownClient::SendMessage(const wxString
& message
)
2394 // Already connecting?
2395 if (GetChatState() == MS_CONNECTING
) {
2396 // Queue all messages till we're able to send them (or discard them)
2397 if (!m_pendingMessage
.IsEmpty()) {
2398 m_pendingMessage
+= wxT("\n");
2400 // There must be a message to send
2403 m_pendingMessage
+= message
;
2406 if (IsConnected()) {
2408 data
.WriteString(message
, GetUnicodeSupport());
2409 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_MESSAGE
);
2410 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2411 AddDebugLogLineM( false, logLocalClient
, wxT("Local Client: OP_MESSAGE to ") + GetFullIP());
2412 SendPacket(packet
, true, true);
2415 m_pendingMessage
= message
;
2416 SetChatState(MS_CONNECTING
);
2417 // True to ignore "Too Many Connections"
2425 void CUpDownClient::SetBuddyID(const byte
* pucBuddyID
)
2427 if( pucBuddyID
== NULL
){
2428 md4clr(m_achBuddyID
);
2429 m_bBuddyIDValid
= false;
2432 m_bBuddyIDValid
= true;
2433 md4cpy(m_achBuddyID
, pucBuddyID
);
2438 bool CUpDownClient::SendBuddyPing() {
2439 SetLastBuddyPingPongTime();
2440 CPacket
* buddyPing
= new CPacket(OP_BUDDYPING
, 0, OP_EMULEPROT
);
2441 theStats::AddUpOverheadKad(buddyPing
->GetPacketSize());
2442 AddDebugLogLineM(false, logLocalClient
,wxT("Local Client: OP_BUDDYPING to ") + GetFullIP());
2443 return SafeSendPacket(buddyPing
);
2449 void CUpDownClient::UpdateStats()
2451 if (m_lastClientSoft
!= m_clientSoft
|| m_lastClientVersion
!= m_nClientVersion
|| m_lastOSInfo
!= m_sClientOSInfo
) {
2452 if (m_lastClientSoft
== SO_UNKNOWN
) {
2453 theStats::RemoveUnknownClient();
2454 } else if (m_lastClientSoft
!= (uint32
)(-1)) {
2455 theStats::RemoveKnownClient(m_lastClientSoft
, m_lastClientVersion
, m_lastOSInfo
);
2458 m_lastClientSoft
= m_clientSoft
;
2459 m_lastClientVersion
= m_nClientVersion
;
2460 m_lastOSInfo
= m_sClientOSInfo
;
2462 if (m_clientSoft
== SO_UNKNOWN
) {
2463 theStats::AddUnknownClient();
2465 theStats::AddKnownClient(this);
2470 bool CUpDownClient::IsIdentified() const
2472 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED
);
2475 bool CUpDownClient::IsBadGuy() const
2477 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDBADGUY
);
2480 bool CUpDownClient::SUIFailed() const
2482 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDFAILED
);
2485 bool CUpDownClient::SUINeeded() const
2487 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDNEEDED
);
2490 bool CUpDownClient::SUINotSupported() const
2492 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_NOTAVAILABLE
);
2495 uint64
CUpDownClient::GetDownloadedTotal() const
2497 return credits
? credits
->GetDownloadedTotal() : 0;
2500 uint64
CUpDownClient::GetUploadedTotal() const
2502 return credits
? credits
->GetUploadedTotal() : 0;
2505 double CUpDownClient::GetScoreRatio() const {
2506 return credits
? credits
->GetScoreRatio(GetIP(), theApp
->CryptoAvailable()) : 0;
2509 const wxString
CUpDownClient::GetServerName() const
2512 wxString srvaddr
= Uint32toStringIP(GetServerIP());
2513 CServer
* cserver
= theApp
->serverlist
->GetServerByAddress(
2514 srvaddr
, GetServerPort());
2516 ret
= cserver
->GetListName();
2524 bool CUpDownClient::ShouldReceiveCryptUDPPackets() const {
2525 return (thePrefs::IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp
->GetPublicIP() != 0
2526 && HasValidHash() && (thePrefs::IsClientCryptLayerRequested() || RequestsCryptLayer()) );
2529 void CUpDownClient::SendFirewallCheckUDPRequest()
2531 wxASSERT(GetKadState() == KS_FWCHECK_UDP
);
2533 if (!Kademlia::CKademlia::IsRunning()) {
2534 SetKadState(KS_NONE
);
2536 } else if (GetUploadState() != US_NONE
|| GetDownloadState() != DS_NONE
|| GetChatState() != MS_NONE
|| GetKadVersion() <= 5 || GetKadPort() == 0) {
2537 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetIP()), 0); // inform the tester that this test was cancelled
2538 SetKadState(KS_NONE
);
2542 wxASSERT(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0);
2544 data
.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetInternKadPort());
2545 data
.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort());
2546 data
.WriteUInt32(Kademlia::CKademlia::GetPrefs()->GetUDPVerifyKey(GetConnectIP()));
2547 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_FWCHECKUDPREQ
);
2548 theStats::AddUpOverheadKad(packet
->GetPacketSize());
2549 SafeSendPacket(packet
);
2552 void CUpDownClient::ProcessFirewallCheckUDPRequest(CMemFile
* data
)
2554 if (!Kademlia::CKademlia::IsRunning() || Kademlia::CKademlia::GetUDPListener() == NULL
) {
2555 //DebugLogWarning(_T("Ignored Kad Firewallrequest UDP because Kad is not running (%s)"), DbgGetClientInfo());
2559 // first search if we know this IP already, if so the result might be biased and we need tell the requester
2560 bool errorAlreadyKnown
= false;
2561 if (GetUploadState() != US_NONE
|| GetDownloadState() != DS_NONE
|| GetChatState() != MS_NONE
) {
2562 errorAlreadyKnown
= true;
2563 } else if (Kademlia::CKademlia::GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0, false) != NULL
) {
2564 errorAlreadyKnown
= true;
2567 uint16_t remoteInternPort
= data
->ReadUInt16();
2568 uint16_t remoteExternPort
= data
->ReadUInt16();
2569 uint32_t senderKey
= data
->ReadUInt32();
2570 if (remoteInternPort
== 0) {
2571 //DebugLogError(_T("UDP Firewallcheck requested with Intern Port == 0 (%s)"), DbgGetClientInfo());
2574 // if (senderKey == 0)
2575 // DebugLogWarning(_T("UDP Firewallcheck requested with SenderKey == 0 (%s)"), DbgGetClientInfo());
2577 CMemFile testPacket1
;
2578 testPacket1
.WriteUInt8(errorAlreadyKnown
? 1 : 0);
2579 testPacket1
.WriteUInt16(remoteInternPort
);
2580 DebugSend(Kad2FirewallUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort
);
2581 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket1
, KADEMLIA2_FIREWALLUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort
, Kademlia::CKadUDPKey(senderKey
, theApp
->GetPublicIP(false)), NULL
);
2583 // if the client has a router with PAT (and therefore a different extern port than intern), test this port too
2584 if (remoteExternPort
!= 0 && remoteExternPort
!= remoteInternPort
) {
2585 CMemFile testPacket2
;
2586 testPacket2
.WriteUInt8(errorAlreadyKnown
? 1 : 0);
2587 testPacket2
.WriteUInt16(remoteExternPort
);
2588 DebugSend(Kad2FirewalledUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort
);
2589 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket2
, KADEMLIA2_FIREWALLUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort
, Kademlia::CKadUDPKey(senderKey
, theApp
->GetPublicIP(false)), NULL
);
2591 //DebugLog(_T("Answered UDP Firewallcheck request (%s)"), DbgGetClientInfo());
2594 void CUpDownClient::SetConnectOptions(uint8_t options
, bool encryption
, bool callback
)
2596 SetCryptLayerSupport((options
& 0x01) != 0 && encryption
);
2597 SetCryptLayerRequest((options
& 0x02) != 0 && encryption
);
2598 SetCryptLayerRequires((options
& 0x04) != 0 && encryption
);
2599 SetDirectUDPCallbackSupport((options
& 0x08) != 0 && callback
);
2601 // File_checked_for_headers