2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
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
27 #include <wx/mstream.h>
28 #include <wx/tokenzr.h>
30 #include "updownclient.h" // Needed for CUpDownClient
31 #include "SharedFileList.h" // Needed for CSharedFileList
33 #include <protocol/Protocols.h>
34 #include <protocol/ed2k/Client2Client/TCP.h>
35 #include <protocol/ed2k/ClientSoftware.h>
36 #include <protocol/kad/Client2Client/UDP.h>
37 #include <protocol/kad2/Constants.h>
38 #include <protocol/kad2/Client2Client/TCP.h>
39 #include <protocol/kad2/Client2Client/UDP.h>
41 #include <common/ClientVersion.h>
43 #include <tags/ClientTags.h>
45 #include <zlib.h> // Needed for inflateEnd
47 #include <common/Format.h> // Needed for CFormat
49 #include "SearchList.h" // Needed for CSearchList
50 #include "DownloadQueue.h" // Needed for CDownloadQueue
51 #include "UploadQueue.h" // Needed for CUploadQueue
52 #include "IPFilter.h" // Needed for CIPFilter
53 #include "ServerConnect.h" // Needed for CServerConnect
54 #include "ClientCredits.h" // Needed for CClientCredits
55 #include "ClientCreditsList.h" // Needed for CClientCreditsList
56 #include "Server.h" // Needed for CServer
57 #include "Preferences.h" // Needed for CPreferences
58 #include "MemFile.h" // Needed for CMemFile
59 #include "Packet.h" // Needed for CPacket
60 #include "Friend.h" // Needed for CFriend
61 #include "ClientList.h" // Needed for CClientList
63 #include "amuleDlg.h" // Needed for CamuleDlg
64 #include "CaptchaDialog.h" // Needed for CCaptchaDialog
65 #include "CaptchaGenerator.h"
66 #include "ChatWnd.h" // Needed for CChatWnd
68 #include "amule.h" // Needed for theApp
69 #include "PartFile.h" // Needed for CPartFile
70 #include "ClientTCPSocket.h" // Needed for CClientTCPSocket
71 #include "ListenSocket.h" // Needed for CListenSocket
72 #include "FriendList.h" // Needed for CFriendList
73 #include "Statistics.h" // Needed for theStats
74 #include "ClientUDPSocket.h"
76 #include "DataToText.h" // Needed for GetSoftName()
77 #include "GuiEvents.h" // Needed for Notify_
78 #include "ServerList.h" // For CServerList
80 #include "kademlia/kademlia/Kademlia.h"
81 #include "kademlia/kademlia/Prefs.h"
82 #include "kademlia/kademlia/Search.h"
83 #include "kademlia/kademlia/UDPFirewallTester.h"
84 #include "kademlia/routing/RoutingZone.h"
87 //#define __PACKET_DEBUG__
90 // some client testing variables
91 static wxString crash_name
= wxT("[Invalid User Name]");
92 static wxString empty_name
= wxT("[Empty User Name]");
94 // members of CUpDownClient
95 // which are used by down and uploading functions
98 CUpDownClient::CUpDownClient(CClientTCPSocket
* sender
)
109 CUpDownClient::CUpDownClient(uint16 in_port
, uint32 in_userid
, uint32 in_serverip
, uint16 in_serverport
, CPartFile
* in_reqfile
, bool ed2kID
, bool checkfriend
)
113 m_nUserPort
= in_port
;
115 if(ed2kID
&& !IsLowID(in_userid
)) {
116 SetUserIDHybrid( wxUINT32_SWAP_ALWAYS(in_userid
) );
118 SetUserIDHybrid( in_userid
);
121 //If highID and ED2K source, incoming ID and IP are equal..
122 //If highID and Kad source, incoming IP needs swap for the IP
126 m_nConnectIP
= in_userid
;
128 m_nConnectIP
= wxUINT32_SWAP_ALWAYS(in_userid
);
130 // Will be on right endianess now
131 m_FullUserIP
= m_nConnectIP
;
134 m_dwServerIP
= in_serverip
;
135 m_nServerPort
= in_serverport
;
136 SetRequestFile( in_reqfile
);
140 if ((m_Friend
= theApp
->friendlist
->FindFriend(CMD4Hash(), m_dwUserIP
, m_nUserPort
)) != NULL
){
141 m_Friend
->LinkClient(CCLIENTREF(this, wxT("CUpDownClient::CUpDownClient m_Friend->LinkClient")));
143 // avoid that an unwanted client instance keeps a friend slot
144 m_bFriendSlot
= false;
150 void CUpDownClient::Init()
153 #ifdef DEBUG_ZOMBIE_CLIENTS
154 m_linkedDebug
= false;
156 m_bAddNextConnect
= false;
158 m_byChatstate
= MS_NONE
;
159 m_nKadState
= KS_NONE
;
160 m_nChatCaptchaState
= CA_NONE
;
162 m_reqfile
= NULL
; // No file required yet
163 m_nTransferredUp
= 0;
168 bytesReceivedCycle
= 0;
170 m_iFileListRequested
= 0;
171 m_dwLastUpRequest
= 0;
172 m_bEmuleProtocol
= false;
173 m_bCompleteSource
= false;
174 m_bFriendSlot
= false;
175 m_bCommentDirty
= false;
176 m_bReaskPending
= false;
177 m_bUDPPending
= false;
180 m_dwLastAskedTime
= 0;
181 m_nDownloadState
= DS_NONE
;
183 m_nTransferredDown
= 0;
184 m_nUploadState
= US_NONE
;
185 m_dwLastBlockReceived
= 0;
186 m_bUnicodeSupport
= false;
188 m_fSentOutOfPartReqs
= 0;
189 m_nCurQueueSessionPayloadUp
= 0;
190 m_addedPayloadQueueSession
= 0;
192 m_nSumForAvgUpDataRate
= 0;
194 m_nRemoteQueueRank
= 0;
195 m_nOldRemoteQueueRank
= 0;
196 m_dwLastSourceRequest
= 0;
197 m_dwLastSourceAnswer
= 0;
198 m_dwLastAskedForSources
= 0;
200 m_SecureIdentState
= IS_UNAVAILABLE
;
201 m_dwLastSignatureIP
= 0;
203 m_byInfopacketsReceived
= IP_NONE
;
210 m_clientSoft
=SO_UNKNOWN
;
212 m_bRemoteQueueFull
= false;
213 m_HasValidHash
= false;
216 m_fHashsetRequesting
= 0;
217 m_fSharedDirectories
= 0;
218 m_lastPartAsked
= 0xffff;
219 m_nUpCompleteSourcesCount
= 0;
220 m_waitingPosition
= 0;
222 m_lastRefreshedDLDisplay
= 0;
223 m_bHelloAnswerPending
= false;
224 m_fSentCancelTransfer
= 0;
225 m_Aggressiveness
= 0;
226 m_LastFileRequest
= 0;
228 m_clientState
= CS_NEW
;
230 ClearHelloProperties();
232 m_pReqFileAICHHash
= NULL
;
234 m_fAICHRequested
= 0;
235 m_fSupportsLargeFiles
= 0;
236 m_fExtMultiPacket
= 0;
243 m_fNeedOurPublicIP
= false;
244 m_bHashsetRequested
= false;
246 m_lastDownloadingPart
= 0;
248 m_uploadingfile
= NULL
;
250 m_OSInfo_sent
= false;
258 m_nSourceFrom
= SF_NONE
;
261 SetIP(m_socket
->GetPeerInt());
267 m_lastClientSoft
= (uint32
)(-1);
268 m_lastClientVersion
= 0;
270 /* Creation time (for buddies timeout) */
271 m_nCreationTime
= ::GetTickCount();
273 m_MaxBlockRequests
= STANDARD_BLOCKS_REQUEST
; // Safe starting amount
275 m_last_block_start
= 0;
278 SetLastBuddyPingPongTime();
279 m_fRequestsCryptLayer
= 0;
280 m_fSupportsCryptLayer
= 0;
281 m_fRequiresCryptLayer
= 0;
282 m_fSupportsSourceEx2
= 0;
283 m_fSupportsCaptcha
= 0;
284 m_fDirectUDPCallback
= 0;
285 m_dwDirectCallbackTimeout
= 0;
287 m_hasbeenobfuscatinglately
= false;
290 m_cMessagesReceived
= 0;
296 CUpDownClient::~CUpDownClient()
299 if (!connection_reason
.IsEmpty()) {
300 AddDebugLogLineN(logClient
, wxT("Client to check for ") + connection_reason
+ wxT(" was deleted without connection."));
305 if (m_lastClientSoft
== SO_UNKNOWN
) {
306 theStats::RemoveUnknownClient();
307 } else if (m_lastClientSoft
!= (uint32
)(-1)) {
308 theStats::RemoveKnownClient(m_lastClientSoft
, m_lastClientVersion
, m_lastOSInfo
);
311 // Indicate that we are not anymore on stats
312 m_lastClientSoft
= (uint32
)(-1);
314 // The socket should have been removed in Safe_Delete, but it
315 // doesn't hurt to have an extra check.
317 m_socket
->Safe_Delete();
322 ClearUploadBlockRequests();
323 ClearDownloadBlockRequests();
325 DeleteContents(m_WaitingPackets_list
);
327 // Allow detection of deleted clients that didn't go through Safe_Delete
328 m_clientState
= CS_DYING
;
332 void CUpDownClient::ClearHelloProperties()
337 m_byEmuleVersion
= 0;
338 m_bySourceExchange1Ver
= 0;
339 m_byAcceptCommentVer
= 0;
340 m_byExtendedRequestsVer
= 0;
341 m_byCompatibleClient
= 0;
343 m_bySupportSecIdent
= 0;
344 m_bSupportsPreview
= 0;
345 m_nClientVersion
= 0;
346 m_fSharedDirectories
= 0;
348 m_fOsInfoSupport
= 0;
349 m_fValueBasedTypeTags
= 0;
352 m_fRequestsCryptLayer
= 0;
353 m_fSupportsCryptLayer
= 0;
354 m_fRequiresCryptLayer
= 0;
355 m_fSupportsSourceEx2
= 0;
356 m_fSupportsCaptcha
= 0;
357 m_fDirectUDPCallback
= 0;
360 m_fNoViewSharedFiles
= true; // that's a sensible default to assume until we get the real value
361 m_bUnicodeSupport
= false;
364 bool CUpDownClient::ProcessHelloPacket(const byte
* pachPacket
, uint32 nSize
)
366 const CMemFile
data(pachPacket
,nSize
);
367 uint8 hashsize
= data
.ReadUInt8();
368 if ( 16 != hashsize
) {
370 * Hint: We can not accept other sizes here because:
371 * - the magic number is spread all over the source
372 * - the answer packet lacks the size field
374 throw wxString(wxT("Invalid Hello packet: Other userhash sizes than 16 are not implemented"));
376 // eMule 0.42: reset all client properties; a client may not send a particular emule tag any longer
377 ClearHelloProperties();
379 return ProcessHelloTypePacket(data
);
382 void CUpDownClient::Safe_Delete()
384 // Because we are delaying the deletion, we might end up trying to delete
385 // it twice, however, this is normal and shouldn't trigger any failures
386 if ( m_clientState
== CS_DYING
) {
390 // If called from background, post an event to process it in main thread
391 if (!wxThread::IsMain()) {
392 CoreNotify_Client_Delete(CCLIENTREF(this, wxT("CUpDownClient::Safe_Delete CoreNotify_Client_Delete")));
396 m_clientState
= CS_DYING
;
398 // Make sure client doesn't get deleted until this method is finished
399 CClientRef
ref(CCLIENTREF(this, wxT("CUpDownClient::Safe_Delete reflocker")));
401 // Close the socket to avoid any more connections and related events
403 m_socket
->Safe_Delete();
408 // Remove the client from the clientlist if we still have it
409 if ( theApp
->clientlist
) {
410 theApp
->clientlist
->RemoveClient( this );
413 // Doing what RemoveClient used to do. Just to be sure...
414 if (theApp
->uploadqueue
) {
415 theApp
->uploadqueue
->RemoveFromUploadQueue(this);
416 theApp
->uploadqueue
->RemoveFromWaitingQueue(this);
418 if (theApp
->downloadqueue
) {
419 theApp
->downloadqueue
->RemoveSource(this);
422 // For security, remove it from the lists unconditionally.
423 Notify_SharedCtrlRemoveClient(ECID(), (CKnownFile
*)NULL
);
424 Notify_SourceCtrlRemoveSource(ECID(), (CPartFile
*)NULL
);
426 if (IsAICHReqPending()){
427 m_fAICHRequested
= FALSE
;
428 CAICHHashSet::ClientAICHRequestFailed(this);
432 m_Friend
->UnLinkClient(); // this notifies
436 if (m_iRating
>0 || !m_strComment
.IsEmpty()) {
438 m_strComment
.Clear();
440 m_reqfile
->UpdateFileRatingCommentAvail();
444 // Ensure that source-counts gets updated in case
445 // of a source not on the download-queue
446 SetRequestFile( NULL
);
448 SetUploadFileID(NULL
);
450 delete m_pReqFileAICHHash
;
451 m_pReqFileAICHHash
= NULL
;
453 #ifdef DEBUG_ZOMBIE_CLIENTS
455 AddLogLineC(CFormat(wxT("Client %d still linked in %d places: %s")) % ECID() % (m_linked
- 1) % GetLinkedFrom());
456 m_linkedDebug
= true;
462 bool CUpDownClient::ProcessHelloAnswer(const byte
* pachPacket
, uint32 nSize
)
464 const CMemFile
data(pachPacket
,nSize
);
465 bool bIsMule
= ProcessHelloTypePacket(data
);
466 m_bHelloAnswerPending
= false;
470 bool CUpDownClient::ProcessHelloTypePacket(const CMemFile
& data
)
472 uint32 dwEmuleTags
= 0;
474 CMD4Hash hash
= data
.ReadHash();
476 SetUserIDHybrid( data
.ReadUInt32() );
477 uint16 nUserPort
= data
.ReadUInt16(); // hmm clientport is sent twice - why?
478 uint32 tagcount
= data
.ReadUInt32();
479 for (uint32 i
= 0;i
< tagcount
; i
++){
480 CTag
temptag(data
, true);
481 switch(temptag
.GetNameID()){
483 m_Username
= temptag
.GetStr();
487 m_nClientVersion
= temptag
.GetInt();
491 if (temptag
.IsStr()) {
492 m_strModVersion
= temptag
.GetStr();
493 } else if (temptag
.IsInt()) {
494 m_strModVersion
= CFormat(wxT("ModID=%u")) % temptag
.GetInt();
496 m_strModVersion
= wxT("ModID=<Unknown>");
502 nUserPort
= temptag
.GetInt();
505 case CT_EMULE_UDPPORTS
:
508 SetKadPort((temptag
.GetInt() >> 16) & 0xFFFF);
509 m_nUDPPort
= temptag
.GetInt() & 0xFFFF;
511 #ifdef __PACKET_DEBUG__
512 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule ports UDP=%i KAD=%i")) % m_nUDPPort
% m_nKadPort
);
516 case CT_EMULE_BUDDYIP
:
518 m_nBuddyIP
= temptag
.GetInt();
519 #ifdef __PACKET_DEBUG__
520 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule BuddyIP=%u (%s)")) % m_nBuddyIP
% Uint32toStringIP(m_nBuddyIP
));
524 case CT_EMULE_BUDDYUDP
:
525 // 16 --Reserved for future use--
527 m_nBuddyPort
= (uint16
)temptag
.GetInt();
528 #ifdef __PACKET_DEBUG__
529 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule BuddyPort=%u")) % m_nBuddyPort
);
533 case CT_EMULE_MISCOPTIONS1
: {
534 // 3 AICH Version (0 = not supported)
537 // 4 Data compression version
542 // 1 PeerCache supported
543 // 1 No 'View Shared Files' supported
546 uint32 flags
= temptag
.GetInt();
547 m_fSupportsAICH
= (flags
>> (4*7+1)) & 0x07;
548 m_bUnicodeSupport
= (flags
>> 4*7) & 0x01;
549 m_byUDPVer
= (flags
>> 4*6) & 0x0f;
550 m_byDataCompVer
= (flags
>> 4*5) & 0x0f;
551 m_bySupportSecIdent
= (flags
>> 4*4) & 0x0f;
552 m_bySourceExchange1Ver
= (flags
>> 4*3) & 0x0f;
553 m_byExtendedRequestsVer
= (flags
>> 4*2) & 0x0f;
554 m_byAcceptCommentVer
= (flags
>> 4*1) & 0x0f;
555 m_fNoViewSharedFiles
= (flags
>> 1*2) & 0x01;
556 m_bMultiPacket
= (flags
>> 1*1) & 0x01;
557 m_fSupportsPreview
= (flags
>> 1*0) & 0x01;
559 #ifdef __PACKET_DEBUG__
560 AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options:"));
561 AddLogLineNS(CFormat(wxT("m_byUDPVer = %i")) % m_byUDPVer
);
562 AddLogLineNS(CFormat(wxT("m_byDataCompVer = %i")) % m_byDataCompVer
);
563 AddLogLineNS(CFormat(wxT("m_bySupportSecIdent = %i")) % m_bySupportSecIdent
);
564 AddLogLineNS(CFormat(wxT("m_bySourceExchangeVer = %i")) % m_bySourceExchange1Ver
);
565 AddLogLineNS(CFormat(wxT("m_byExtendedRequestsVer = %i")) % m_byExtendedRequestsVer
);
566 AddLogLineNS(CFormat(wxT("m_byAcceptCommentVer = %i")) % m_byAcceptCommentVer
);
567 AddLogLineNS(CFormat(wxT("m_fNoViewSharedFiles = %i")) % m_fNoViewSharedFiles
);
568 AddLogLineNS(CFormat(wxT("m_bMultiPacket = %i")) % m_bMultiPacket
);
569 AddLogLineNS(CFormat(wxT("m_fSupportsPreview = %i")) % m_fSharedDirectories
);
570 AddLogLineNS(wxT("That's all."));
576 case CT_EMULE_MISCOPTIONS2
:
578 // 1 Direct UDP Callback supported and available
579 // 1 Supports ChatCaptchas
580 // 1 Supports SourceExachnge2 Packets, ignores SX1 Packet Version
581 // 1 Requires CryptLayer
582 // 1 Requests CryptLayer
583 // 1 Supports CryptLayer
584 // 1 Reserved (ModBit)
585 // 1 Ext Multipacket (Hash+Size instead of Hash)
586 // 1 Large Files (includes support for 64bit tags)
587 // 4 Kad Version - will go up to version 15 only (may need to add another field at some point in the future)
588 m_fDirectUDPCallback
= (temptag
.GetInt() >> 12) & 0x01;
589 m_fSupportsCaptcha
= (temptag
.GetInt() >> 11) & 0x01;
590 m_fSupportsSourceEx2
= (temptag
.GetInt() >> 10) & 0x01;
591 m_fRequiresCryptLayer
= (temptag
.GetInt() >> 9) & 0x01;
592 m_fRequestsCryptLayer
= (temptag
.GetInt() >> 8) & 0x01;
593 m_fSupportsCryptLayer
= (temptag
.GetInt() >> 7) & 0x01;
595 m_fExtMultiPacket
= (temptag
.GetInt() >> 5) & 0x01;
596 m_fSupportsLargeFiles
= (temptag
.GetInt() >> 4) & 0x01;
597 m_byKadVersion
= (temptag
.GetInt() >> 0) & 0x0f;
600 m_fRequestsCryptLayer
&= m_fSupportsCryptLayer
;
601 m_fRequiresCryptLayer
&= m_fRequestsCryptLayer
;
603 #ifdef __PACKET_DEBUG__
604 AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options 2:"));
605 AddLogLineNS(CFormat(wxT(" m_fDirectUDPCallback = %i")) % m_fDirectUDPCallback
);
606 AddLogLineNS(CFormat(wxT(" m_fSupportsCaptcha = %i")) % m_fSupportsCaptcha
);
607 AddLogLineNS(CFormat(wxT(" m_fSupportsSourceEx2 = %i")) % m_fSupportsSourceEx2
);
608 AddLogLineNS(CFormat(wxT(" m_fRequiresCryptLayer = %i")) % m_fRequiresCryptLayer
);
609 AddLogLineNS(CFormat(wxT(" m_fRequestsCryptLayer = %i")) % m_fRequestsCryptLayer
);
610 AddLogLineNS(CFormat(wxT(" m_fSupportsCryptLayer = %i")) % m_fSupportsCryptLayer
);
611 AddLogLineNS(CFormat(wxT(" m_fExtMultiPacket = %i")) % m_fExtMultiPacket
);
612 AddLogLineNS(CFormat(wxT(" m_fSupportsLargeFiles = %i")) % m_fSupportsLargeFiles
);
613 AddLogLineNS(CFormat(wxT(" KadVersion = %u")) % m_byKadVersion
);
614 AddLogLineNS(wxT("That's all."));
618 // Special tag for Compat. Clients Misc options.
619 case CT_EMULECOMPAT_OPTIONS
:
620 // 1 Operative System Info
621 // 1 Value-based-type int tags (experimental!)
622 m_fValueBasedTypeTags
= (temptag
.GetInt() >> 1*1) & 0x01;
623 m_fOsInfoSupport
= (temptag
.GetInt() >> 1*0) & 0x01;
626 case CT_EMULE_VERSION
:
627 // 8 Compatible Client ID
628 // 7 Mjr Version (Doesn't really matter..)
629 // 7 Min Version (Only need 0-99)
630 // 3 Upd Version (Only need 0-5)
631 // 7 Bld Version (Only need 0-99)
632 m_byCompatibleClient
= (temptag
.GetInt() >> 24);
633 m_nClientVersion
= temptag
.GetInt() & 0x00ffffff;
634 m_byEmuleVersion
= 0x99;
635 m_fSharedDirectories
= 1;
641 m_nUserPort
= nUserPort
;
642 m_dwServerIP
= data
.ReadUInt32();
643 m_nServerPort
= data
.ReadUInt16();
644 // Hybrid now has an extra uint32.. What is it for?
645 // Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
646 if ( data
.GetLength() - data
.GetPosition() == sizeof(uint32
) ) {
647 uint32 test
= data
.ReadUInt32();
648 /*if (test == 'KDLM') below kdlm is converted to ascii values.
649 This fixes a warning with gcc 3.4.
652 if (test
== 0x4b444c4d) { //if it's == "KDLM"
656 m_fSharedDirectories
= 1;
661 SetIP(m_socket
->GetPeerInt());
663 throw wxString(wxT("Huh, socket failure. Avoided crash this time."));
666 if (thePrefs::AddServersFromClient()) {
667 CServer
* addsrv
= new CServer(m_nServerPort
, Uint32toStringIP(m_dwServerIP
));
668 addsrv
->SetListName(addsrv
->GetAddress());
669 if (!theApp
->AddServer(addsrv
)) {
674 //(a)If this is a highID user, store the ID in the Hybrid format.
675 //(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
676 //(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
677 //because they will send a ID that is the same as their IP..
678 if(!HasLowID() || m_nUserIDHybrid
== 0 || m_nUserIDHybrid
== m_dwUserIP
) {
679 SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(m_dwUserIP
));
682 // get client credits
683 CClientCredits
* pFoundCredits
= theApp
->clientcredits
->GetCredit(m_UserHash
);
684 if (credits
== NULL
){
685 credits
= pFoundCredits
;
686 if (!theApp
->clientlist
->ComparePriorUserhash(m_dwUserIP
, m_nUserPort
, pFoundCredits
)){
687 AddDebugLogLineN( logClient
, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed (Found in TrackedClientsList)") ) % GetUserName() % GetFullIP() );
690 } else if (credits
!= pFoundCredits
){
691 // userhash change ok, however two hours "waittime" before it can be used
692 credits
= pFoundCredits
;
693 AddDebugLogLineN( logClient
, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed") ) % GetUserName() % GetFullIP() );
697 if ((m_Friend
= theApp
->friendlist
->FindFriend(m_UserHash
, m_dwUserIP
, m_nUserPort
)) != NULL
){
698 m_Friend
->LinkClient(CCLIENTREF(this, wxT("CUpDownClient::ProcessHelloTypePacket m_Friend->LinkClient")));
700 // avoid that an unwanted client instance keeps a friend slot
701 SetFriendSlot(false);
707 m_byInfopacketsReceived
|= IP_EDONKEYPROTPACK
;
709 // check if at least CT_EMULEVERSION was received, all other tags are optional
710 bool bIsMule
= (dwEmuleTags
& 0x04) == 0x04;
712 m_bEmuleProtocol
= true;
713 m_byInfopacketsReceived
|= IP_EMULEPROTPACK
;
716 if (GetKadPort() && GetKadVersion() > 1) {
717 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(GetIP()), GetKadPort());
724 bool CUpDownClient::SendHelloPacket()
726 wxCHECK(m_socket
!= NULL
, true);
728 // if IP is filtered, don't greet him but disconnect...
729 if (theApp
->ipfilter
->IsFiltered(m_socket
->GetPeerInt())) {
730 if (Disconnected(wxT("IPFilter"))) {
738 data
.WriteUInt8(16); // size of userhash
739 SendHelloTypePacket(&data
);
741 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_HELLO
);
742 theStats::AddUpOverheadOther(packet
->GetPacketSize());
743 SendPacket(packet
,true);
744 m_bHelloAnswerPending
= true;
745 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_HELLO to ") + GetFullIP() );
749 void CUpDownClient::SendMuleInfoPacket(bool bAnswer
, bool OSInfo
)
751 wxCHECK2(m_socket
!= NULL
, return);
753 CPacket
* packet
= NULL
;
756 data
.WriteUInt8(CURRENT_VERSION_SHORT
);
760 // Special MuleInfo packet for clients supporting it.
761 // This means aMule >= 2.0.0 and Hydranode
763 // Violently mark it as special Mule Info packet
764 // Sending this makes non-supporting-osinfo clients to refuse to read this
765 // packet. Anyway, this packet should NEVER get to non-supporting clients.
767 data
.WriteUInt8(/*EMULE_PROTOCOL*/ 0xFF);
769 data
.WriteUInt32(1); // One Tag (OS_INFO)
771 CTagString
tag1(ET_OS_INFO
,theApp
->GetOSType());
772 tag1
.WriteTagToFile(&data
);
774 m_OSInfo_sent
= true; // So we don't send it again
778 // Normal MuleInfo packet
780 // Kry - There's no point on upgrading to VBT tags here
781 // as no client supporting it uses mule info packet.
783 data
.WriteUInt8(EMULE_PROTOCOL
);
788 CTagInt32
tag1(ET_COMPRESSION
,1);
789 tag1
.WriteTagToFile(&data
);
790 CTagInt32
tag2(ET_UDPVER
,4);
791 tag2
.WriteTagToFile(&data
);
792 CTagInt32
tag3(ET_UDPPORT
, thePrefs::GetEffectiveUDPPort());
793 tag3
.WriteTagToFile(&data
);
794 CTagInt32
tag4(ET_SOURCEEXCHANGE
,3);
795 tag4
.WriteTagToFile(&data
);
796 CTagInt32
tag5(ET_COMMENTS
,1);
797 tag5
.WriteTagToFile(&data
);
798 CTagInt32
tag6(ET_EXTENDEDREQUEST
,2);
799 tag6
.WriteTagToFile(&data
);
801 uint32 dwTagValue
= (theApp
->CryptoAvailable() ? 3 : 0);
802 // Kry - Needs the preview code from eMule
804 // set 'Preview supported' only if 'View Shared Files' allowed
805 if (thePrefs::CanSeeShares() != vsfaNobody) {
809 CTagInt32
tag7(ET_FEATURES
, dwTagValue
);
810 tag7
.WriteTagToFile(&data
);
812 CTagInt32
tag8(ET_COMPATIBLECLIENT
,SO_AMULE
);
813 tag8
.WriteTagToFile(&data
);
815 // Support for tag ET_MOD_VERSION
816 wxString
mod_name(MOD_VERSION_LONG
);
817 CTagString
tag9(ET_MOD_VERSION
, mod_name
);
818 tag9
.WriteTagToFile(&data
);
823 packet
= new CPacket(data
, OP_EMULEPROT
, (bAnswer
? OP_EMULEINFOANSWER
: OP_EMULEINFO
));
826 theStats::AddUpOverheadOther(packet
->GetPacketSize());
827 SendPacket(packet
,true,true);
832 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_EMULEINFO to ") + GetFullIP() );
834 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_EMULEINFO/OS_INFO to ") + GetFullIP() );
837 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_EMULEINFOANSWER to ") + GetFullIP() );
843 bool CUpDownClient::ProcessMuleInfoPacket(const byte
* pachPacket
, uint32 nSize
)
845 uint8 protocol_version
;
847 const CMemFile
data(pachPacket
,nSize
);
849 // The version number part of this packet will soon be useless since
850 // it is only able to go to v.99. Why the version is a uint8 and why
851 // it was not done as a tag like the eDonkey hello packet is not known.
852 // Therefore, sooner or later, we are going to have to switch over to
853 // using the eDonkey hello packet to set the version. No sense making
854 // a third value sent for versions.
855 uint8 mule_version
= data
.ReadUInt8();
856 protocol_version
= data
.ReadUInt8();
857 uint32 tagcount
= data
.ReadUInt32();
858 if (protocol_version
== 0xFF) {
859 // OS Info supporting clients sending a recycled Mule info packet
860 for (uint32 i
= 0;i
< tagcount
; i
++){
861 CTag
temptag(data
, true);
862 switch(temptag
.GetNameID()){
864 // Special tag, only supporting clients (aMule/Hydranode)
865 // It was recycled from a mod's tag, so if the other side
866 // is not supporting OS Info, we're seriously fucked up :)
867 m_sClientOSInfo
= temptag
.GetStr();
869 // If we didn't send our OSInfo to this client, just send it
870 if (!m_OSInfo_sent
) {
871 SendMuleInfoPacket(false,true);
878 // Your ad... er... I mean TAG, here
885 // Old eMule sending tags
886 m_byCompatibleClient
= 0;
887 m_byEmuleVersion
= mule_version
;
889 if( m_byEmuleVersion
== 0x2B ) {
890 m_byEmuleVersion
= 0x22;
893 if (!(m_bEmuleProtocol
= (protocol_version
== EMULE_PROTOCOL
))) {
897 for (uint32 i
= 0;i
< tagcount
; i
++){
898 CTag
temptag(data
, false);
899 switch(temptag
.GetNameID()){
901 // Bits 31- 8: 0 - reserved
902 // Bits 7- 0: data compression version
903 m_byDataCompVer
= temptag
.GetInt();
907 // Bits 31-16: 0 - reserved
908 // Bits 15- 0: UDP port
909 m_nUDPPort
= temptag
.GetInt();
913 // Bits 31- 8: 0 - reserved
914 // Bits 7- 0: UDP protocol version
915 m_byUDPVer
= temptag
.GetInt();
918 case ET_SOURCEEXCHANGE
:
919 // Bits 31- 8: 0 - reserved
920 // Bits 7- 0: source exchange protocol version
921 m_bySourceExchange1Ver
= temptag
.GetInt();
925 // Bits 31- 8: 0 - reserved
926 // Bits 7- 0: comments version
927 m_byAcceptCommentVer
= temptag
.GetInt();
930 case ET_EXTENDEDREQUEST
:
931 // Bits 31- 8: 0 - reserved
932 // Bits 7- 0: extended requests version
933 m_byExtendedRequestsVer
= temptag
.GetInt();
936 case ET_COMPATIBLECLIENT
:
937 // Bits 31- 8: 0 - reserved
938 // Bits 7- 0: compatible client ID
939 m_byCompatibleClient
= temptag
.GetInt();
943 // Bits 31- 8: 0 - reserved
945 // Bit 6- 0: secure identification
946 m_bySupportSecIdent
= temptag
.GetInt() & 3;
947 m_bSupportsPreview
= (temptag
.GetInt() & 128) > 0;
952 if (temptag
.IsStr()) {
953 m_strModVersion
= temptag
.GetStr();
954 } else if (temptag
.IsInt()) {
955 m_strModVersion
= CFormat(wxT("ModID=%u")) % temptag
.GetInt();
957 m_strModVersion
= wxT("ModID=<Unknown>");
963 AddDebugLogLineN( logPacketErrors
,
964 CFormat( wxT("Unknown Mule tag (%s) from client: %s") )
965 % temptag
.GetFullInfo()
966 % GetClientFullInfo()
973 if( m_byDataCompVer
== 0 ){
974 m_bySourceExchange1Ver
= 0;
975 m_byExtendedRequestsVer
= 0;
976 m_byAcceptCommentVer
= 0;
980 //implicitly supported options by older clients
981 //in the future do not use version to guess about new features
982 if(m_byEmuleVersion
< 0x25 && m_byEmuleVersion
> 0x22) {
986 if(m_byEmuleVersion
< 0x25 && m_byEmuleVersion
> 0x21) {
987 m_bySourceExchange1Ver
= 1;
990 if(m_byEmuleVersion
== 0x24) {
991 m_byAcceptCommentVer
= 1;
994 // Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
995 // the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
996 // directory which has a trailing backslash.
997 if(m_byEmuleVersion
>= 0x28 && !m_bIsML
) {// MLdonkey currently does not support shared directories
998 m_fSharedDirectories
= 1;
1003 m_byInfopacketsReceived
|= IP_EMULEPROTPACK
;
1006 return (protocol_version
== 0xFF); // This was a OS_Info?
1010 void CUpDownClient::SendHelloAnswer()
1012 wxCHECK2(m_socket
!= NULL
, return);
1015 SendHelloTypePacket(&data
);
1016 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_HELLOANSWER
);
1017 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1018 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_HELLOANSWER to ") + GetFullIP() );
1019 SendPacket(packet
,true);
1023 void CUpDownClient::SendHelloTypePacket(CMemFile
* data
)
1025 data
->WriteHash(thePrefs::GetUserHash());
1026 data
->WriteUInt32(theApp
->GetID());
1027 data
->WriteUInt16(thePrefs::GetPort());
1029 uint32 tagcount
= 6;
1031 if( theApp
->clientlist
->GetBuddy() && theApp
->IsFirewalled() ) {
1034 tagcount
++; // eMule misc flags 2 (kad version)
1037 // Kry - This is the tagcount!!! Be sure to update it!!
1038 // Last update: CT_EMULECOMPAT_OPTIONS included
1039 data
->WriteUInt32(tagcount
+ 1);
1041 data
->WriteUInt32(tagcount
); // NO MOD_VERSION
1045 CTagString
tagname(CT_NAME
,thePrefs::GetUserNick());
1046 tagname
.WriteTagToFile(data
, utf8strRaw
);
1048 CTagVarInt
tagversion(CT_VERSION
, EDONKEYVERSION
, GetVBTTags() ? 0 : 32);
1049 tagversion
.WriteTagToFile(data
);
1052 uint32 kadUDPPort
= 0;
1054 if(Kademlia::CKademlia::IsConnected()) {
1055 if (Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0 && Kademlia::CKademlia::GetPrefs()->GetUseExternKadPort() && Kademlia::CUDPFirewallTester::IsVerified()) {
1056 kadUDPPort
= Kademlia::CKademlia::GetPrefs()->GetExternalKadPort();
1058 kadUDPPort
= Kademlia::CKademlia::GetPrefs()->GetInternKadPort();
1062 CTagVarInt
tagUdpPorts(CT_EMULE_UDPPORTS
, (kadUDPPort
<< 16) | ((uint32
)thePrefs::GetEffectiveUDPPort()), GetVBTTags() ? 0 : 32);
1063 tagUdpPorts
.WriteTagToFile(data
);
1065 if( theApp
->clientlist
->GetBuddy() && theApp
->IsFirewalled() ) {
1066 CTagVarInt
tagBuddyIP(CT_EMULE_BUDDYIP
, theApp
->clientlist
->GetBuddy()->GetIP(), GetVBTTags() ? 0 : 32);
1067 tagBuddyIP
.WriteTagToFile(data
);
1069 CTagVarInt
tagBuddyPort(CT_EMULE_BUDDYUDP
,
1071 ((uint32
)theApp
->clientlist
->GetBuddy()->GetUDPPort() )
1072 , GetVBTTags() ? 0 : 32);
1073 tagBuddyPort
.WriteTagToFile(data
);
1077 CTagVarInt
tagMuleVersion(CT_EMULE_VERSION
,
1079 make_full_ed2k_version(VERSION_MJR
, VERSION_MIN
, VERSION_UPDATE
)
1081 , GetVBTTags() ? 0 : 32);
1082 tagMuleVersion
.WriteTagToFile(data
);
1085 // eMule Misc. Options #1
1086 const uint32 uUdpVer
= 4;
1087 const uint32 uDataCompVer
= 1;
1088 const uint32 uSupportSecIdent
= theApp
->CryptoAvailable() ? 3 : 0;
1089 const uint32 uSourceExchangeVer
= 3;
1090 const uint32 uExtendedRequestsVer
= 2;
1091 const uint32 uAcceptCommentVer
= 1;
1092 const uint32 uNoViewSharedFiles
= (thePrefs::CanSeeShares() == vsfaNobody
) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag
1093 const uint32 uMultiPacket
= 1;
1094 const uint32 uSupportPreview
= 0; // No network preview at all.
1095 const uint32 uPeerCache
= 0; // No peercache for aMule, baby
1096 const uint32 uUnicodeSupport
= 1;
1097 const uint32 nAICHVer
= 1; // AICH is ENABLED right now.
1099 CTagVarInt
tagMisOptions(CT_EMULE_MISCOPTIONS1
,
1100 (nAICHVer
<< ((4*7)+1)) |
1101 (uUnicodeSupport
<< 4*7) |
1103 (uDataCompVer
<< 4*5) |
1104 (uSupportSecIdent
<< 4*4) |
1105 (uSourceExchangeVer
<< 4*3) |
1106 (uExtendedRequestsVer
<< 4*2) |
1107 (uAcceptCommentVer
<< 4*1) |
1108 (uPeerCache
<< 1*3) |
1109 (uNoViewSharedFiles
<< 1*2) |
1110 (uMultiPacket
<< 1*1) |
1111 (uSupportPreview
<< 1*0)
1112 , GetVBTTags() ? 0 : 32);
1113 tagMisOptions
.WriteTagToFile(data
);
1115 // eMule Misc. Options #2
1116 const uint32 uKadVersion
= KADEMLIA_VERSION
;
1117 const uint32 uSupportLargeFiles
= 1;
1118 const uint32 uExtMultiPacket
= 1;
1119 const uint32 uReserved
= 0; // mod bit
1120 const uint32 uSupportsCryptLayer
= thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1121 const uint32 uRequestsCryptLayer
= thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1122 const uint32 uRequiresCryptLayer
= thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1123 const uint32 uSupportsSourceEx2
= 1;
1125 // captcha for daemon/remotegui not supported for now
1126 const uint32 uSupportsCaptcha
= 0;
1128 const uint32 uSupportsCaptcha
= 1;
1130 // direct callback is only possible if connected to kad, tcp firewalled and verified UDP open (for example on a full cone NAT)
1131 const uint32 uDirectUDPCallback
= (Kademlia::CKademlia::IsRunning() && Kademlia::CKademlia::IsFirewalled()
1132 && !Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) && Kademlia::CUDPFirewallTester::IsVerified()) ? 1 : 0;
1134 CTagVarInt
tagMisOptions2(CT_EMULE_MISCOPTIONS2
,
1136 (uDirectUDPCallback
<< 12) |
1137 (uSupportsCaptcha
<< 11) |
1138 (uSupportsSourceEx2
<< 10) |
1139 (uRequiresCryptLayer
<< 9) |
1140 (uRequestsCryptLayer
<< 8) |
1141 (uSupportsCryptLayer
<< 7) |
1143 (uExtMultiPacket
<< 5) |
1144 (uSupportLargeFiles
<< 4) |
1146 , GetVBTTags() ? 0 : 32 );
1147 tagMisOptions2
.WriteTagToFile(data
);
1149 const uint32 nOSInfoSupport
= 1; // We support OS_INFO
1150 const uint32 nValueBasedTypeTags
= 0; // Experimental, disabled
1152 CTagVarInt
tagMisCompatOptions(CT_EMULECOMPAT_OPTIONS
,
1153 (nValueBasedTypeTags
<< 1*1) |
1154 (nOSInfoSupport
<< 1*0)
1155 , GetVBTTags() ? 0 : 32);
1157 tagMisCompatOptions
.WriteTagToFile(data
);
1160 wxString
mod_name(MOD_VERSION_LONG
);
1161 CTagString
tagModName(ET_MOD_VERSION
, mod_name
);
1162 tagModName
.WriteTagToFile(data
);
1167 if (theApp
->IsConnectedED2K()) {
1168 dwIP
= theApp
->serverconnect
->GetCurrentServer()->GetIP();
1169 nPort
= theApp
->serverconnect
->GetCurrentServer()->GetPort();
1171 data
->WriteUInt32(dwIP
);
1172 data
->WriteUInt16(nPort
);
1176 void CUpDownClient::ProcessMuleCommentPacket(const byte
* pachPacket
, uint32 nSize
)
1179 throw CInvalidPacket(wxT("Comment packet for unknown file"));
1182 if (!m_reqfile
->IsPartFile()) {
1183 throw CInvalidPacket(wxT("Comment packet for completed file"));
1186 const CMemFile
data(pachPacket
, nSize
);
1188 uint8 rating
= data
.ReadUInt8();
1190 AddDebugLogLineN( logClient
, wxString(wxT("Invalid Rating for file '")) << m_clientFilename
<< wxT("' received: ") << rating
);
1194 AddDebugLogLineN( logClient
, wxString(wxT("Rating for file '")) << m_clientFilename
<< wxT("' received: ") << m_iRating
);
1197 // The comment is unicoded, with a uin32 len and safe read
1198 // (won't break if string size is < than advertised len)
1199 // Truncated to MAXFILECOMMENTLEN size
1200 m_strComment
= data
.ReadString((GetUnicodeSupport() != utf8strNone
), 4 /* bytes (it's a uint32)*/, true).Left(MAXFILECOMMENTLEN
);
1202 AddDebugLogLineN( logClient
, wxString(wxT("Description for file '")) << m_clientFilename
<< wxT("' received: ") << m_strComment
);
1204 // Update file rating
1205 m_reqfile
->UpdateFileRatingCommentAvail();
1209 void CUpDownClient::ClearDownloadBlockRequests()
1212 std::list
<Requested_Block_Struct
*>::iterator it
= m_DownloadBlocks_list
.begin();
1213 for (; it
!= m_DownloadBlocks_list
.end(); ++it
) {
1214 Requested_Block_Struct
* cur_block
= *it
;
1217 m_reqfile
->RemoveBlockFromList(cur_block
->StartOffset
, cur_block
->EndOffset
);
1223 m_DownloadBlocks_list
.clear();
1227 std::list
<Pending_Block_Struct
*>::iterator it
= m_PendingBlocks_list
.begin();
1228 for (; it
!= m_PendingBlocks_list
.end(); ++it
) {
1229 Pending_Block_Struct
* pending
= *it
;
1232 m_reqfile
->RemoveBlockFromList(pending
->block
->StartOffset
, pending
->block
->EndOffset
);
1235 delete pending
->block
;
1236 // Not always allocated
1237 if (pending
->zStream
){
1238 inflateEnd(pending
->zStream
);
1239 delete pending
->zStream
;
1245 m_PendingBlocks_list
.clear();
1250 bool CUpDownClient::Disconnected(const wxString
& DEBUG_ONLY(strReason
), bool bFromSocket
)
1252 //wxASSERT(theApp->clientlist->IsValidClient(this));
1254 if (HasBeenDeleted()) {
1255 AddDebugLogLineN(logClient
, wxT("Disconnected() called for already deleted client on ip ") + Uint32toStringIP(GetConnectIP()));
1259 // was this a direct callback?
1260 if (m_dwDirectCallbackTimeout
!= 0) {
1261 theApp
->clientlist
->RemoveDirectCallback(this);
1262 m_dwDirectCallbackTimeout
= 0;
1263 theApp
->clientlist
->AddDeadSource(this);
1264 AddDebugLogLineN(logClient
, wxT("Direct callback failed to client on ip ") + Uint32toStringIP(GetConnectIP()));
1267 if (GetKadState() == KS_QUEUED_FWCHECK_UDP
|| GetKadState() == KS_CONNECTING_FWCHECK_UDP
) {
1268 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test was cancelled
1269 } else if (GetKadState() == KS_FWCHECK_UDP
) {
1270 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, false, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test has failed
1271 } else if (GetKadState() == KS_CONNECTED_BUDDY
) {
1272 AddDebugLogLineN(logClient
, wxT("Buddy client disconnected - ") + strReason
);
1275 //If this is a KAD client object, just delete it!
1276 SetKadState(KS_NONE
);
1278 if (GetUploadState() == US_UPLOADING
) {
1280 theApp
->uploadqueue
->RemoveFromUploadQueue(this);
1283 if (GetDownloadState() == DS_DOWNLOADING
) {
1284 SetDownloadState(DS_ONQUEUE
);
1286 // ensure that all possible block requests are removed from the partfile
1287 ClearDownloadBlockRequests();
1289 if (GetDownloadState() == DS_CONNECTED
) {
1290 // successfully connected, but probably didn't respond to our filerequest
1291 theApp
->clientlist
->AddDeadSource(this);
1292 theApp
->downloadqueue
->RemoveSource(this);
1296 // we had still an AICH request pending, handle it
1297 if (IsAICHReqPending()) {
1298 m_fAICHRequested
= FALSE
;
1299 CAICHHashSet::ClientAICHRequestFailed(this);
1302 // The remote client does not have to answer with OP_HASHSETANSWER *immediatly*
1303 // after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client
1304 // is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
1305 if (((GetDownloadState() == DS_REQHASHSET
) || m_fHashsetRequesting
) && (m_reqfile
)) {
1306 m_reqfile
->SetHashSetNeeded(true);
1309 SourceItemType source_type
= UNAVAILABLE_SOURCE
;
1310 SourceItemType peer_type
= UNAVAILABLE_SOURCE
;
1312 //check if this client is needed in any way, if not delete it
1313 bool bDelete
= true;
1314 switch (m_nUploadState
) {
1315 case US_ONUPLOADQUEUE
:
1317 peer_type
= AVAILABLE_SOURCE
;
1321 switch (m_nDownloadState
) {
1323 source_type
= A4AF_SOURCE
; // Will be checked.
1325 case DS_TOOMANYCONNS
:
1326 case DS_NONEEDEDPARTS
:
1332 switch (m_nUploadState
) {
1334 case US_WAITCALLBACK
:
1336 theApp
->clientlist
->AddDeadSource(this);
1340 switch (m_nDownloadState
) {
1342 case DS_WAITCALLBACK
:
1345 theApp
->clientlist
->AddDeadSource(this);
1350 // We keep chat partners in any case
1351 if (GetChatState() != MS_NONE
) {
1353 m_pendingMessage
.Clear();
1354 Notify_ChatConnResult(false,GUI_ID(GetIP(),GetUserPort()),wxEmptyString
);
1358 if (!bFromSocket
&& m_socket
) {
1359 wxASSERT (theApp
->listensocket
->IsValidSocket(m_socket
));
1360 m_socket
->Safe_Delete();
1365 if (m_iFileListRequested
) {
1366 AddLogLineC(CFormat(_("Failed to retrieve shared files from user '%s'")) % GetUserName() );
1367 m_iFileListRequested
= 0;
1373 // Remove the friend linkage
1374 m_Friend
->UnLinkClient(); // this notifies
1377 Notify_SharedCtrlRefreshClient(ECID(), peer_type
);
1378 Notify_SourceCtrlUpdateSource(ECID(), source_type
);
1380 m_fHashsetRequesting
= 0;
1381 SetSentCancelTransfer(0);
1382 m_bHelloAnswerPending
= false;
1383 m_fSentOutOfPartReqs
= 0;
1385 AddDebugLogLineN(logClient
, CFormat(wxT("--- %s client D:%d U:%d \"%s\"; Reason was %s"))
1386 % (bDelete
? wxT("Deleted") : wxT("Disconnected"))
1387 % m_nDownloadState
% m_nUploadState
% GetClientFullInfo() % strReason
);
1392 //Returned bool is not if the TryToConnect is successful or not..
1393 //false means the client was deleted!
1394 //true means the client was not deleted!
1395 bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon
)
1398 if (theApp
->listensocket
->TooManySockets() && !bIgnoreMaxCon
) {
1399 if (!(m_socket
&& m_socket
->IsConnected())) {
1400 if(Disconnected(wxT("Too many connections"))) {
1408 // 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)
1409 if ( (RequiresCryptLayer() && !thePrefs::IsClientCryptLayerSupported()) || (thePrefs::IsClientCryptLayerRequired() && !SupportsCryptLayer()) ){
1410 if(Disconnected(wxT("CryptLayer-Settings (Obfuscation) incompatible"))){
1419 uint32 uClientIP
= GetIP();
1420 if (uClientIP
== 0 && !HasLowID()) {
1421 uClientIP
= wxUINT32_SWAP_ALWAYS(m_nUserIDHybrid
);
1425 // Although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
1426 // we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
1427 if (theApp
->ipfilter
->IsFiltered(uClientIP
)) {
1428 AddDebugLogLineN(logIPFilter
, CFormat(wxT("Filtered ip %u (%s) on TryToConnect\n")) % uClientIP
% Uint32toStringIP(uClientIP
));
1429 if (Disconnected(wxT("IPFilter"))) {
1436 // for safety: check again whether that IP is banned
1437 if (theApp
->clientlist
->IsBannedClient(uClientIP
)) {
1438 AddDebugLogLineN(logClient
, wxT("Refused to connect to banned client ") + Uint32toStringIP(uClientIP
));
1439 if (Disconnected(wxT("Banned IP"))) {
1447 if (GetKadState() == KS_QUEUED_FWCHECK
) {
1448 SetKadState(KS_CONNECTING_FWCHECK
);
1449 } else if (GetKadState() == KS_QUEUED_FWCHECK_UDP
) {
1450 SetKadState(KS_CONNECTING_FWCHECK_UDP
);
1454 if (!theApp
->CanDoCallback(GetServerIP(), GetServerPort())) {
1455 //We cannot do a callback!
1456 if (GetDownloadState() == DS_CONNECTING
) {
1457 SetDownloadState(DS_LOWTOLOWIP
);
1458 } else if (GetDownloadState() == DS_REQHASHSET
) {
1459 SetDownloadState(DS_ONQUEUE
);
1460 m_reqfile
->SetHashSetNeeded(true);
1462 if (GetUploadState() == US_CONNECTING
) {
1463 if(Disconnected(wxT("LowID->LowID and US_CONNECTING"))) {
1471 //We already know we are not firewalled here as the above condition already detected LowID->LowID and returned.
1472 //If ANYTHING changes with the "if(!theApp->CanDoCallback(this))" above that will let you fall through
1473 //with the condition that the source is firewalled and we are firewalled, we must
1474 //recheck it before the this check..
1475 if (HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp
->serverconnect
->IsLocalServer(GetServerIP(), GetServerPort())
1476 && !(SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0)) {
1477 //This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort.
1478 if( Kademlia::CKademlia::IsConnected() ) {
1479 //We are connect to Kad
1480 if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID()))) {
1481 //There are too many source lookups already or we are already searching this key.
1482 SetDownloadState(DS_TOOMANYCONNSKAD
);
1489 if (!m_socket
|| !m_socket
->IsConnected()) {
1491 m_socket
->Safe_Delete();
1493 m_socket
= new CClientTCPSocket(this, thePrefs::GetProxyData());
1495 ConnectionEstablished();
1500 if (HasLowID() && SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0 && GetConnectIP() != 0) { // LOWID with DirectCallback
1501 if (m_dwDirectCallbackTimeout
!= 0) {
1502 AddDebugLogLineN(logClient
, wxT("ERROR: Trying Direct UDP Callback while already trying to connect to client on ip ") + Uint32toStringIP(GetConnectIP()));
1503 return true; // We're already trying a direct connection to this client
1505 // a direct callback is possible - since no other parties are involved and only one additional packet overhead
1506 // is used we basically handle it like a normal connection try, no restrictions apply
1507 // we already check above with !theApp->CanDoCallback(this) if any callback is possible at all
1508 m_dwDirectCallbackTimeout
= ::GetTickCount() + SEC2MS(45);
1509 theApp
->clientlist
->AddDirectCallbackClient(this);
1510 AddDebugLogLineN(logClient
, CFormat(wxT("Direct Callback on port %u to client on ip %s")) % GetKadPort() % Uint32toStringIP(GetConnectIP()));
1513 data
.WriteUInt16(thePrefs::GetPort()); // needs to know our port
1514 data
.WriteHash(thePrefs::GetUserHash()); // and userhash
1515 // our connection settings
1516 data
.WriteUInt8(Kademlia::CPrefs::GetMyConnectOptions(true, false));
1517 AddDebugLogLineN(logClientUDP
, wxT("Sending OP_DIRECTCALLBACKREQ to ") + Uint32_16toStringIP_Port(GetConnectIP(), GetKadPort()));
1518 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_DIRECTCALLBACKREQ
);
1519 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1520 theApp
->clientudp
->SendPacket(packet
, GetConnectIP(), GetKadPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0);
1521 } else if (HasLowID()) { // LOWID
1522 if (GetDownloadState() == DS_CONNECTING
) {
1523 SetDownloadState(DS_WAITCALLBACK
);
1525 if (GetUploadState() == US_CONNECTING
) {
1526 if(Disconnected(wxT("LowID and US_CONNECTING"))) {
1533 if (theApp
->serverconnect
->IsLocalServer(m_dwServerIP
,m_nServerPort
)) {
1535 // AFAICS, this id must be reversed to be sent to clients
1536 // But if I reverse it, we do a serve violation ;)
1537 data
.WriteUInt32(m_nUserIDHybrid
);
1538 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_CALLBACKREQUEST
);
1539 theStats::AddUpOverheadServer(packet
->GetPacketSize());
1540 AddDebugLogLineN(logLocalClient
, wxT("Local Client: OP_CALLBACKREQUEST to ") + GetFullIP());
1541 theApp
->serverconnect
->SendPacket(packet
);
1542 SetDownloadState(DS_WAITCALLBACK
);
1544 if (GetUploadState() == US_NONE
&& (!GetRemoteQueueRank() || m_bReaskPending
)) {
1546 if( !HasValidBuddyID() ) {
1547 theApp
->downloadqueue
->RemoveSource(this);
1548 if (Disconnected(wxT("LowID and US_NONE and QR=0"))) {
1555 if( !Kademlia::CKademlia::IsConnected() ) {
1556 //We are not connected to Kad and this is a Kad Firewalled source..
1557 theApp
->downloadqueue
->RemoveSource(this);
1558 if(Disconnected(wxT("Kad Firewalled source but not connected to Kad."))) {
1565 if( GetDownloadState() == DS_WAITCALLBACK
) {
1566 if( GetBuddyIP() && GetBuddyPort()) {
1568 bio
.WriteUInt128(Kademlia::CUInt128(GetBuddyID()));
1569 bio
.WriteUInt128(Kademlia::CUInt128(m_reqfile
->GetFileHash().GetHash()));
1570 bio
.WriteUInt16(thePrefs::GetPort());
1571 CPacket
* packet
= new CPacket(bio
, OP_KADEMLIAHEADER
, KADEMLIA_CALLBACK_REQ
);
1572 // eMule FIXME: We don't know which kadversion the buddy has, so we need to send unencrypted
1573 theApp
->clientudp
->SendPacket(packet
, GetBuddyIP(), GetBuddyPort(), false, NULL
, true, 0);
1574 AddDebugLogLineN(logClientKadUDP
, CFormat(wxT("KadCallbackReq (size=%i) to %s")) % packet
->GetPacketSize() % Uint32_16toStringIP_Port(GetBuddyIP(), GetBuddyPort()));
1575 theStats::AddUpOverheadKad(packet
->GetRealPacketSize());
1576 SetDownloadState(DS_WAITCALLBACKKAD
);
1578 AddLogLineN(_("Searching buddy for lowid connection"));
1579 //Create search to find buddy.
1580 Kademlia::CSearch
*findSource
= new Kademlia::CSearch
;
1581 findSource
->SetSearchTypes(Kademlia::CSearch::FINDSOURCE
);
1582 findSource
->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
1583 findSource
->AddFileID(Kademlia::CUInt128(m_reqfile
->GetFileHash().GetHash()));
1584 if(Kademlia::CSearchManager::StartSearch(findSource
)) {
1586 SetDownloadState(DS_WAITCALLBACKKAD
);
1588 //This should never happen..
1594 if (GetDownloadState() == DS_WAITCALLBACK
) {
1595 m_bReaskPending
= true;
1596 SetDownloadState(DS_ONQUEUE
);
1608 bool CUpDownClient::Connect()
1610 m_hasbeenobfuscatinglately
= false;
1612 if (!m_socket
->IsOk()) {
1613 // Enable or disable crypting based on our and the remote clients preference
1614 if (HasValidHash() && SupportsCryptLayer() && thePrefs::IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested())){
1615 m_socket
->SetConnectionEncryption(true, GetUserHash().GetHash(), false);
1617 m_socket
->SetConnectionEncryption(false, NULL
, false);
1619 amuleIPV4Address tmp
;
1620 tmp
.Hostname(GetConnectIP());
1621 tmp
.Service(GetUserPort());
1622 AddDebugLogLineN(logClient
, wxT("Trying to connect to ") + Uint32_16toStringIP_Port(GetConnectIP(),GetUserPort()));
1623 m_socket
->Connect(tmp
, false);
1624 // We should send hello packets AFTER connecting!
1625 // so I moved it to OnConnect
1632 void CUpDownClient::ConnectionEstablished()
1634 /* Kry - First thing, check if this client was just used to retrieve
1635 info. That's some debug thing for myself... check connection_reason
1638 m_hasbeenobfuscatinglately
= (m_socket
&& m_socket
->IsConnected() && m_socket
->IsObfusicating());
1641 if (!connection_reason
.IsEmpty()) {
1642 AddLogLineN(CFormat(wxT("Got client info checking for %s: %s\nDisconnecting and deleting.")) % connection_reason
% GetClientFullInfo());
1643 connection_reason
.Clear(); // So we don't re-print on destructor.
1649 // Check if we should use this client to retrieve our public IP
1650 // Ignore local ip on GetPublicIP (could be wrong)
1651 if (theApp
->GetPublicIP(true) == 0 && theApp
->IsConnectedED2K()) {
1652 SendPublicIPRequest();
1655 // was this a direct callback?
1656 if (m_dwDirectCallbackTimeout
!= 0){
1657 theApp
->clientlist
->RemoveDirectCallback(this);
1658 m_dwDirectCallbackTimeout
= 0;
1659 AddDebugLogLineN(logClient
, wxT("Direct Callback succeeded, connection established to ") + Uint32toStringIP(GetConnectIP()));
1662 switch (GetKadState()) {
1663 case KS_CONNECTING_FWCHECK
:
1664 SetKadState(KS_CONNECTED_FWCHECK
);
1666 case KS_CONNECTING_BUDDY
:
1667 case KS_INCOMING_BUDDY
:
1668 SetKadState(KS_CONNECTED_BUDDY
);
1670 case KS_CONNECTING_FWCHECK_UDP
:
1671 SetKadState(KS_FWCHECK_UDP
);
1672 SendFirewallCheckUDPRequest();
1678 // ok we have a connection, lets see if we want anything from this client
1679 if (GetChatState() == MS_CONNECTING
) {
1680 SetChatState( MS_CHATTING
);
1683 if (GetChatState() == MS_CHATTING
) {
1685 if (!m_pendingMessage
.IsEmpty()) {
1686 result
= SendChatMessage(m_pendingMessage
);
1688 Notify_ChatConnResult(result
,GUI_ID(GetIP(),GetUserPort()),m_pendingMessage
);
1689 m_pendingMessage
.Clear();
1692 switch(GetDownloadState()) {
1694 case DS_WAITCALLBACK
:
1695 case DS_WAITCALLBACKKAD
:
1696 m_bReaskPending
= false;
1697 SetDownloadState(DS_CONNECTED
);
1700 if (m_bReaskPending
){
1701 m_bReaskPending
= false;
1702 if (GetDownloadState() != DS_NONE
&& GetDownloadState() != DS_DOWNLOADING
) {
1703 SetDownloadState(DS_CONNECTED
);
1707 switch(GetUploadState()){
1709 case US_WAITCALLBACK
:
1710 if (theApp
->uploadqueue
->IsDownloading(this)) {
1711 SetUploadState(US_UPLOADING
);
1712 CPacket
* packet
= new CPacket(OP_ACCEPTUPLOADREQ
, 0, OP_EDONKEYPROT
);
1713 theStats::AddUpOverheadFileRequest(packet
->GetPacketSize());
1714 SendPacket(packet
,true);
1715 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + GetFullIP() );
1718 if (m_iFileListRequested
== 1) {
1719 CPacket
* packet
= new CPacket(m_fSharedDirectories
? OP_ASKSHAREDDIRS
: OP_ASKSHAREDFILES
, 0, OP_EDONKEYPROT
);
1720 theStats::AddUpOverheadOther(packet
->GetPacketSize());
1721 SendPacket(packet
,true,true);
1723 if (m_fSharedDirectories
) {
1724 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRS to ") + GetFullIP() );
1726 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILES to ") + GetFullIP() );
1731 while (!m_WaitingPackets_list
.empty()) {
1732 CPacket
* packet
= m_WaitingPackets_list
.front();
1733 m_WaitingPackets_list
.pop_front();
1740 int CUpDownClient::GetHashType() const
1742 if ( m_UserHash
[5] == 13 && m_UserHash
[14] == 110 ) {
1746 if ( m_UserHash
[5] == 14 && m_UserHash
[14] == 111 ) {
1750 if ( m_UserHash
[5] == 'M' && m_UserHash
[14] == 'L' ) {
1758 void CUpDownClient::SetSocket(CClientTCPSocket
* socket
)
1761 if (m_socket
== NULL
&& socket
!= NULL
) {
1762 theStats::SocketAssignedToClient();
1763 } else if (m_socket
!= NULL
&& socket
== NULL
) {
1764 theStats::SocketUnassignedFromClient();
1771 void CUpDownClient::ReGetClientSoft()
1773 if (m_Username
.IsEmpty()) {
1774 m_clientSoft
=SO_UNKNOWN
;
1775 m_clientVerString
= m_clientSoftString
= m_clientVersionString
= m_fullClientVerString
= _("Unknown");
1780 int iHashType
= GetHashType();
1781 wxString clientModString
;
1782 if (iHashType
== SO_EMULE
) {
1784 m_clientSoft
= m_byCompatibleClient
;
1785 m_clientSoftString
= GetSoftName(m_clientSoft
);
1787 if(!GetClientModString().IsEmpty() && (m_clientSoft
!= SO_EMULE
)) {
1788 m_clientSoftString
= GetClientModString();
1790 // Isn't xMule annoying?
1791 if ((m_clientSoft
== SO_LXMULE
) && (GetMuleVersion() > 0x26) && (GetMuleVersion() != 0x99)) {
1792 m_clientSoftString
+= CFormat(_(" (Fake eMule version %#x)")) % GetMuleVersion();
1794 if ((m_clientSoft
== SO_EMULE
) &&
1796 wxString(GetClientModString()).MakeLower().Find(wxT("xmule")) != -1
1797 || GetUserName().Find(wxT("xmule.")) != -1
1800 // FAKE eMule -a newer xMule faking is ident.
1801 m_clientSoft
= SO_LXMULE
;
1802 if (GetClientModString().IsEmpty() == false) {
1803 m_clientSoftString
= GetClientModString() + _(" (Fake eMule)");
1805 m_clientSoftString
= _("xMule (Fake eMule)"); // don't use GetSoftName, it's not lmule.
1808 // Now, what if we don't know this SO_ID?
1809 if (m_clientSoftString
.IsEmpty()) {
1811 m_clientSoft
= SO_MLDONKEY
;
1812 m_clientSoftString
= GetSoftName(m_clientSoft
);
1813 } else if (m_bIsHybrid
) {
1814 m_clientSoft
= SO_EDONKEYHYBRID
;
1815 m_clientSoftString
= GetSoftName(m_clientSoft
);
1816 } else if (m_byCompatibleClient
!= 0) {
1817 m_clientSoft
= SO_COMPAT_UNK
;
1821 (m_byCompatibleClient
!= 0xf0) // Chinese leech mod
1822 && (1==1) // Your ad here
1824 AddLogLineNS(CFormat(wxT("Compatible client found with ET_COMPATIBLECLIENT of %x")) % m_byCompatibleClient
);
1827 m_clientSoftString
= CFormat(wxT("%s(%#x)")) % GetSoftName(m_clientSoft
) % m_byCompatibleClient
;
1829 // If we step here, it might mean 2 things:
1831 // a Compat Client that has sent no MuleInfo packet yet.
1832 m_clientSoft
= SO_EMULE
;
1833 m_clientSoftString
= wxT("eMule");
1837 if (m_byEmuleVersion
== 0) {
1838 m_nClientVersion
= MAKE_CLIENT_VERSION(0,0,0);
1839 } else if (m_byEmuleVersion
!= 0x99) {
1840 uint32 nClientMinVersion
= (m_byEmuleVersion
>> 4)*10 + (m_byEmuleVersion
& 0x0f);
1841 m_nClientVersion
= MAKE_CLIENT_VERSION(0,nClientMinVersion
,0);
1842 switch (m_clientSoft
) {
1844 m_clientVerString
= CFormat(_("1.x (based on eMule v0.%u)")) % nClientMinVersion
;
1847 m_clientVerString
= wxT("< v0.05");
1850 clientModString
= GetClientModString();
1851 m_clientVerString
= CFormat(wxT("v0.%u")) % nClientMinVersion
;
1855 uint32 nClientMajVersion
= (m_nClientVersion
>> 17) & 0x7f;
1856 uint32 nClientMinVersion
= (m_nClientVersion
>> 10) & 0x7f;
1857 uint32 nClientUpVersion
= (m_nClientVersion
>> 7) & 0x07;
1859 m_nClientVersion
= MAKE_CLIENT_VERSION(nClientMajVersion
, nClientMinVersion
, nClientUpVersion
);
1861 switch (m_clientSoft
) {
1866 case SO_NEW_MLDONKEY
:
1867 case SO_NEW2_MLDONKEY
:
1868 // Kry - xMule started sending correct version tags on 1.9.1b.
1869 // It only took them 4 months, and being told by me and the
1870 // eMule+ developers, so I think they're slowly getting smarter.
1871 // They are based on our implementation, so we use the same format
1872 // for the version string.
1873 m_clientVerString
= CFormat(wxT("v%u.%u.%u")) % nClientMajVersion
% nClientMinVersion
% nClientUpVersion
;
1876 m_clientVerString
= CFormat(wxT(" v%u.%.2u%c")) % (nClientMajVersion
-1) % nClientMinVersion
% ('a' + nClientUpVersion
);
1879 m_clientVerString
= CFormat(wxT("v%u")) % nClientMajVersion
;
1880 if(nClientMinVersion
!= 0) {
1881 m_clientVerString
+= CFormat(wxT(".%u")) % nClientMinVersion
;
1883 if(nClientUpVersion
!= 0) {
1884 m_clientVerString
+= CFormat(wxT("%c")) % ('a' + nClientUpVersion
- 1);
1888 clientModString
= GetClientModString();
1889 m_clientVerString
= CFormat(wxT("v%u.%u%c")) % nClientMajVersion
% nClientMinVersion
% ('a' + nClientUpVersion
);
1893 } else if (m_bIsHybrid
) {
1900 m_clientSoft
= SO_EDONKEYHYBRID
;
1901 m_clientSoftString
= GetSoftName(m_clientSoft
);
1903 uint32 nClientMajVersion
;
1904 uint32 nClientMinVersion
;
1905 uint32 nClientUpVersion
;
1906 if (m_nClientVersion
> 100000) {
1907 uint32 uMaj
= m_nClientVersion
/100000;
1908 nClientMajVersion
= uMaj
- 1;
1909 nClientMinVersion
= (m_nClientVersion
- uMaj
*100000) / 100;
1910 nClientUpVersion
= m_nClientVersion
% 100;
1912 else if (m_nClientVersion
> 10000) {
1913 uint32 uMaj
= m_nClientVersion
/10000;
1914 nClientMajVersion
= uMaj
- 1;
1915 nClientMinVersion
= (m_nClientVersion
- uMaj
*10000) / 10;
1916 nClientUpVersion
= m_nClientVersion
% 10;
1918 else if (m_nClientVersion
> 1000) {
1919 uint32 uMaj
= m_nClientVersion
/1000;
1920 nClientMajVersion
= uMaj
- 1;
1921 nClientMinVersion
= m_nClientVersion
- uMaj
*1000;
1922 nClientUpVersion
= 0;
1924 else if (m_nClientVersion
> 100) {
1925 uint32 uMin
= m_nClientVersion
/10;
1926 nClientMajVersion
= 0;
1927 nClientMinVersion
= uMin
;
1928 nClientUpVersion
= m_nClientVersion
- uMin
*10;
1931 nClientMajVersion
= 0;
1932 nClientMinVersion
= m_nClientVersion
;
1933 nClientUpVersion
= 0;
1935 m_nClientVersion
= MAKE_CLIENT_VERSION(nClientMajVersion
, nClientMinVersion
, nClientUpVersion
);
1936 if (nClientUpVersion
) {
1937 m_clientVerString
= CFormat(wxT("v%u.%u.%u")) % nClientMajVersion
% nClientMinVersion
% nClientUpVersion
;
1939 m_clientVerString
= CFormat(wxT("v%u.%u")) % nClientMajVersion
% nClientMinVersion
;
1941 } else if (m_bIsML
|| (iHashType
== SO_MLDONKEY
)) {
1942 m_clientSoft
= SO_MLDONKEY
;
1943 m_clientSoftString
= GetSoftName(m_clientSoft
);
1944 uint32 nClientMinVersion
= m_nClientVersion
;
1945 m_nClientVersion
= MAKE_CLIENT_VERSION(0, nClientMinVersion
, 0);
1946 m_clientVerString
= CFormat(wxT("v0.%u")) % nClientMinVersion
;
1947 } else if (iHashType
== SO_OLDEMULE
) {
1948 m_clientSoft
= SO_OLDEMULE
;
1949 m_clientSoftString
= GetSoftName(m_clientSoft
);
1950 uint32 nClientMinVersion
= m_nClientVersion
;
1951 m_nClientVersion
= MAKE_CLIENT_VERSION(0, nClientMinVersion
, 0);
1952 m_clientVerString
= CFormat(wxT("v0.%u")) % nClientMinVersion
;
1954 m_clientSoft
= SO_EDONKEY
;
1955 m_clientSoftString
= GetSoftName(m_clientSoft
);
1956 m_nClientVersion
*= 10;
1957 m_clientVerString
= CFormat(wxT("v%u.%u")) % (m_nClientVersion
/ 100000) % ((m_nClientVersion
/ 1000) % 100);
1960 m_clientVersionString
= m_clientVerString
;
1961 if (!clientModString
.IsEmpty()) {
1962 m_clientVerString
+= wxT(" - ") + clientModString
;
1964 m_fullClientVerString
= m_clientSoftString
+ wxT(" ") + m_clientVerString
;
1969 void CUpDownClient::RequestSharedFileList()
1971 if (m_iFileListRequested
== 0) {
1972 AddDebugLogLineN( logClient
, wxString( wxT("Requesting shared files from ") ) + GetUserName() );
1973 m_iFileListRequested
= 1;
1976 AddDebugLogLineN( logClient
, CFormat( wxT("Requesting shared files from user %s (%u) is already in progress") ) % GetUserName() % GetUserIDHybrid() );
1981 void CUpDownClient::ProcessSharedFileList(const byte
* pachPacket
, uint32 nSize
, wxString
& pszDirectory
)
1983 if (m_iFileListRequested
> 0) {
1984 m_iFileListRequested
--;
1985 theApp
->searchlist
->ProcessSharedFileList(pachPacket
, nSize
, this, NULL
, pszDirectory
);
1990 void CUpDownClient::ResetFileStatusInfo()
1995 m_reqfile
->UpdatePartsFrequency( this, false );
1997 m_downPartStatus
.clear();
1999 m_clientFilename
.Clear();
2001 m_bCompleteSource
= false;
2002 m_dwLastAskedTime
= 0;
2004 m_strComment
.Clear();
2006 if (m_pReqFileAICHHash
!= NULL
) {
2007 delete m_pReqFileAICHHash
;
2008 m_pReqFileAICHHash
= NULL
;
2013 wxString
CUpDownClient::GetUploadFileInfo()
2015 // build info text and display it
2017 sRet
= (CFormat(_("NickName: %s ID: %u")) % GetUserName() % GetUserIDHybrid()) + wxT(" ");
2019 sRet
+= CFormat(_("Requested: %s\n")) % m_reqfile
->GetFileName();
2021 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())
2022 ) % m_reqfile
->statistic
.GetAccepts() % m_reqfile
->statistic
.GetRequests() % CastItoXBytes(m_reqfile
->statistic
.GetTransferred());
2024 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())
2025 ) % m_reqfile
->statistic
.GetAllTimeAccepts() % m_reqfile
->statistic
.GetAllTimeRequests() % CastItoXBytes(m_reqfile
->statistic
.GetAllTimeTransferred());
2027 sRet
+= _("Requested unknown file");
2032 // sends a packet, if needed it will establish a connection before
2033 // options used: ignore max connections, control packet, delete packet
2034 // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails
2035 bool CUpDownClient::SafeSendPacket(CPacket
* packet
)
2037 if (IsConnected()) {
2038 SendPacket(packet
, true);
2041 m_WaitingPackets_list
.push_back(packet
);
2042 return TryToConnect(true);
2046 void CUpDownClient::SendPublicKeyPacket()
2048 // send our public key to the client who requested it
2049 wxCHECK2(m_socket
!= NULL
, return);
2050 wxCHECK2(credits
!= NULL
, return);
2051 wxCHECK2(m_SecureIdentState
== IS_KEYANDSIGNEEDED
, return);
2053 if (!theApp
->CryptoAvailable())
2057 data
.WriteUInt8(theApp
->clientcredits
->GetPubKeyLen());
2058 data
.Write(theApp
->clientcredits
->GetPublicKey(), theApp
->clientcredits
->GetPubKeyLen());
2059 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_PUBLICKEY
);
2061 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2062 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_PUBLICKEY to ") + GetFullIP() );
2063 SendPacket(packet
,true,true);
2064 m_SecureIdentState
= IS_SIGNATURENEEDED
;
2068 void CUpDownClient::SendSignaturePacket()
2070 // signate the public key of this client and send it
2071 wxCHECK2(m_socket
!= NULL
, return);
2072 wxCHECK2(credits
!= NULL
, return);
2073 wxCHECK2(m_SecureIdentState
!= 0, return);
2075 if (!theApp
->CryptoAvailable()) {
2078 if (credits
->GetSecIDKeyLen() == 0) {
2079 return; // We don't have his public key yet, will be back here later
2081 // do we have a challenge value received (actually we should if we are in this function)
2082 if (credits
->m_dwCryptRndChallengeFrom
== 0){
2083 AddDebugLogLineN( logClient
, wxString(wxT("Want to send signature but challenge value is invalid - User ")) + GetUserName());
2087 // we will use v1 as default, except if only v2 is supported
2089 if ( (m_bySupportSecIdent
&1) == 1 )
2094 uint8 byChaIPKind
= 0;
2095 uint32 ChallengeIP
= 0;
2097 if (::IsLowID(theApp
->GetED2KID())) {
2098 // we cannot do not know for sure our public ip, so use the remote clients one
2099 ChallengeIP
= GetIP();
2100 byChaIPKind
= CRYPT_CIP_REMOTECLIENT
;
2102 ChallengeIP
= theApp
->GetED2KID();
2103 byChaIPKind
= CRYPT_CIP_LOCALCLIENT
;
2107 byte achBuffer
[250];
2109 uint8 siglen
= theApp
->clientcredits
->CreateSignature(credits
, achBuffer
, 250, ChallengeIP
, byChaIPKind
);
2110 wxCHECK2(siglen
!= 0, return);
2113 data
.WriteUInt8(siglen
);
2114 data
.Write(achBuffer
, siglen
);
2116 data
.WriteUInt8(byChaIPKind
);
2119 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_SIGNATURE
);
2121 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2122 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_SIGNATURE to ") + GetFullIP() );
2123 SendPacket(packet
,true,true);
2124 m_SecureIdentState
= IS_ALLREQUESTSSEND
;
2128 void CUpDownClient::ProcessPublicKeyPacket(const byte
* pachPacket
, uint32 nSize
)
2130 theApp
->clientlist
->AddTrackClient(this);
2132 wxCHECK2(m_socket
!= NULL
, return);
2133 wxCHECK2(credits
!= NULL
, return);
2134 if (pachPacket
[0] != nSize
- 1) {
2135 AddDebugLogLineN(logClient
, CFormat(wxT("Inconsistent packet size (%d != %d)")) % pachPacket
[0] % (nSize
- 1));
2139 AddDebugLogLineN(logClient
, wxT("Invalid packet size (0)"));
2143 AddDebugLogLineN(logClient
, CFormat(wxT("Invalid packet size (%d > 250)")) % nSize
);
2146 if (!theApp
->CryptoAvailable())
2148 // the function will handle everything (mulitple key etc)
2149 if (credits
->SetSecureIdent(pachPacket
+1, pachPacket
[0])){
2150 // if this client wants a signature, now we can send him one
2151 if (m_SecureIdentState
== IS_SIGNATURENEEDED
){
2152 SendSignaturePacket();
2154 else if (m_SecureIdentState
== IS_KEYANDSIGNEEDED
) {
2155 // something is wrong
2156 AddDebugLogLineN( logClient
, wxT("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket") );
2159 AddDebugLogLineN( logClient
, wxT("Failed to use new received public key") );
2164 void CUpDownClient::ProcessSignaturePacket(const byte
* pachPacket
, uint32 nSize
)
2166 // here we spread the good guys from the bad ones ;)
2168 wxCHECK2(m_socket
!= NULL
, return);
2169 wxCHECK2(credits
!= NULL
, return);
2171 AddDebugLogLineN(logClient
, wxT("Invalid packet size (0)"));
2175 AddDebugLogLineN(logClient
, CFormat(wxT("Invalid packet size (%d > 250)")) % nSize
);
2180 if (pachPacket
[0] == nSize
-1)
2182 else if (pachPacket
[0] == nSize
-2 && (m_bySupportSecIdent
& 2) > 0) //v2
2183 byChaIPKind
= pachPacket
[nSize
-1];
2185 // Unknown or invalid format
2186 AddDebugLogLineN(logClient
, wxT("Invalid or unknown challenge format - ignoring"));
2190 if (!theApp
->CryptoAvailable())
2193 // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
2194 if (m_dwLastSignatureIP
== GetIP()){
2195 AddDebugLogLineN( logClient
, wxT("received multiple signatures from one client") );
2198 // also make sure this client has a public key
2199 if (credits
->GetSecIDKeyLen() == 0){
2200 AddDebugLogLineN( logClient
, wxT("received signature for client without public key") );
2203 // and one more check: did we ask for a signature and sent a challange packet?
2204 if (credits
->m_dwCryptRndChallengeFor
== 0){
2205 AddDebugLogLineN( logClient
, wxT("received signature for client with invalid challenge value - User ") + GetUserName() );
2209 // cppcheck-suppress duplicateBranch
2210 if (theApp
->clientcredits
->VerifyIdent(credits
, pachPacket
+1, pachPacket
[0], GetIP(), byChaIPKind
) ) {
2211 // result is saved in function above
2212 AddDebugLogLineN( logClient
, CFormat( wxT("'%s' has passed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind
);
2214 AddDebugLogLineN( logClient
, CFormat( wxT("'%s' has failed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind
);
2217 m_dwLastSignatureIP
= GetIP();
2220 void CUpDownClient::SendSecIdentStatePacket()
2222 wxCHECK2(credits
!= NULL
, return);
2224 // check if we need public key and signature
2226 if (theApp
->CryptoAvailable()){
2227 if (credits
->GetSecIDKeyLen() == 0) {
2228 nValue
= IS_KEYANDSIGNEEDED
;
2229 } else if (m_dwLastSignatureIP
!= GetIP()) {
2230 nValue
= IS_SIGNATURENEEDED
;
2234 AddDebugLogLineN( logClient
, wxT("Not sending SecIdentState Packet, because State is Zero") );
2237 // crypt: send random data to sign
2238 uint32 dwRandom
= rand()+1;
2239 credits
->m_dwCryptRndChallengeFor
= dwRandom
;
2242 data
.WriteUInt8(nValue
);
2243 data
.WriteUInt32(dwRandom
);
2244 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_SECIDENTSTATE
);
2246 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2247 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_SECIDENTSTATE to ") + GetFullIP() );
2248 SendPacket(packet
,true,true);
2252 void CUpDownClient::ProcessSecIdentStatePacket(const byte
* pachPacket
, uint32 nSize
)
2258 wxCHECK2(credits
, return);
2260 CMemFile
data(pachPacket
,nSize
);
2262 switch ( data
.ReadUInt8() ) {
2264 m_SecureIdentState
= IS_UNAVAILABLE
;
2267 m_SecureIdentState
= IS_SIGNATURENEEDED
;
2270 m_SecureIdentState
= IS_KEYANDSIGNEEDED
;
2276 credits
->m_dwCryptRndChallengeFrom
= data
.ReadUInt32();
2280 void CUpDownClient::InfoPacketsReceived()
2282 // indicates that both Information Packets has been received
2283 // needed for actions, which process data from both packets
2284 wxASSERT ( m_byInfopacketsReceived
== IP_BOTH
);
2285 m_byInfopacketsReceived
= IP_NONE
;
2287 if (m_bySupportSecIdent
){
2288 SendSecIdentStatePacket();
2293 bool CUpDownClient::CheckHandshakeFinished() const
2295 if (m_bHelloAnswerPending
) {
2296 // this triggers way too often.. need more time to look at this -> only create a warning
2297 // The reason for this is that 2 clients are connecting to each other at the same time..
2298 AddDebugLogLineN( logClient
, wxT("Handshake not finished while processing packet.") );
2307 wxString
CUpDownClient::GetClientFullInfo()
2309 if (m_clientVerString
.IsEmpty()) {
2313 return CFormat( wxT("Client %s on IP:Port %s:%d using %s %s %s") )
2314 % ( m_Username
.IsEmpty() ? wxString(_("Unknown")) : m_Username
)
2317 % m_clientSoftString
2323 wxString
CUpDownClient::GetClientShortInfo()
2325 if (m_clientVerString
.IsEmpty()) {
2329 return CFormat( wxT("'%s' (%s %s %s)") )
2330 % ( m_Username
.IsEmpty() ? wxString(_("Unknown")) : m_Username
)
2331 % m_clientSoftString
2337 void CUpDownClient::SendPublicIPRequest()
2340 CPacket
* packet
= new CPacket(OP_PUBLICIP_REQ
,0,OP_EMULEPROT
);
2341 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2342 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_PUBLICIP_REQ to ") + GetFullIP());
2343 SendPacket(packet
,true);
2344 m_fNeedOurPublicIP
= true;
2348 void CUpDownClient::ProcessPublicIPAnswer(const byte
* pbyData
, uint32 uSize
)
2351 throw wxString(wxT("Wrong Packet size on Public IP answer"));
2353 uint32 dwIP
= PeekUInt32(pbyData
);
2354 if (m_fNeedOurPublicIP
== true){ // did we?
2355 m_fNeedOurPublicIP
= false;
2356 // Ignore local ip on GetPublicIP (could be wrong)
2357 if (theApp
->GetPublicIP(true) == 0 && !IsLowID(dwIP
) ) {
2358 theApp
->SetPublicIP(dwIP
);
2364 bool CUpDownClient::IsConnected() const
2366 return m_socket
&& m_socket
->IsConnected();
2369 bool CUpDownClient::SendPacket(CPacket
* packet
, bool delpacket
, bool controlpacket
)
2372 m_socket
->SendPacket(packet
, delpacket
, controlpacket
);
2375 AddLogLineN(wxT("CAUGHT DEAD SOCKET IN SENDPACKET()"));
2380 float CUpDownClient::SetDownloadLimit(uint32 reducedownload
)
2382 // lfroen: in daemon it actually can happen
2383 wxASSERT( m_socket
);
2385 float kBpsClient
= CalculateKBpsDown();
2389 if (reducedownload
) {
2390 // (% to reduce * current speed) / 100 and THEN, / (1000 / CORE_TIMER_PERIOD)
2391 // which is how often it is called per second.
2392 uint32 limit
= (uint32
)(reducedownload
* kBpsClient
* 1024.0 / 100000.0 * CORE_TIMER_PERIOD
);
2394 if(limit
<1024 && reducedownload
>= 200) {
2395 // If we're going up and this download is < 1kB,
2396 // we want it to go up fast. Can be reduced later,
2397 // and it'll probably be in a more fair way with
2398 // other downloads that are faster.
2400 } else if(limit
== 0) {
2401 // This download is not transferring yet... make it
2402 // 1024 so we don't fill the TCP stack and lose the
2407 m_socket
->SetDownloadLimit(limit
);
2409 m_socket
->DisableDownloadLimit();
2413 AddLogLineNS(CFormat(wxT("CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f")) % kBpsClient
);
2419 void CUpDownClient::SetUserIDHybrid(uint32 nUserID
)
2421 theApp
->clientlist
->UpdateClientID( this, nUserID
);
2423 m_nUserIDHybrid
= nUserID
;
2427 void CUpDownClient::SetIP( uint32 val
)
2429 theApp
->clientlist
->UpdateClientIP( this, val
);
2439 void CUpDownClient::SetUserHash(const CMD4Hash
& userhash
)
2441 theApp
->clientlist
->UpdateClientHash( this, userhash
);
2443 m_UserHash
= userhash
;
2448 EUtf8Str
CUpDownClient::GetUnicodeSupport() const
2450 return m_bUnicodeSupport
? utf8strRaw
: utf8strNone
;
2453 void CUpDownClient::SetSpammer(bool bVal
)
2457 } else if (IsBanned() && m_fIsSpammer
) {
2460 m_fIsSpammer
= bVal
;
2463 uint8
CUpDownClient::GetSecureIdentState()
2465 if (m_SecureIdentState
!= IS_UNAVAILABLE
) {
2466 if (!SecIdentSupRec
) {
2467 // This can be caused by a 0.30x based client which sends the old
2468 // style Hello packet, and the mule info packet, but between them they
2469 // send a secure ident state packet (after a hello but before we have
2470 // the SUI capabilities). This is a misbehaving client, and somehow I
2471 // feel like it should be dropped. But then again, it won't harm to use
2472 // this SUI state if they are reporting no SUI (won't be used) and if
2473 // they report using SUI on the mule info packet, it's ok to use it.
2475 AddDebugLogLineN(logClient
, wxT("A client sent secure ident state before telling us the SUI capabilities"));
2476 AddDebugLogLineN(logClient
, wxT("Client info: ") + GetClientFullInfo());
2477 AddDebugLogLineN(logClient
, wxT("This client won't be disconnected, but it should be. :P"));
2481 return m_SecureIdentState
;
2485 bool CUpDownClient::SendChatMessage(const wxString
& message
)
2487 if (GetChatCaptchaState() == CA_CAPTCHARECV
) {
2488 m_nChatCaptchaState
= CA_SOLUTIONSENT
;
2489 } else if (GetChatCaptchaState() == CA_SOLUTIONSENT
) {
2490 wxFAIL
; // we responsed to a captcha but didn't heard from the client afterwards - hopefully its just lag and this message will get through
2492 m_nChatCaptchaState
= CA_ACCEPTING
;
2497 // Already connecting?
2498 if (GetChatState() == MS_CONNECTING
) {
2499 // Queue all messages till we're able to send them (or discard them)
2500 if (!m_pendingMessage
.IsEmpty()) {
2501 m_pendingMessage
+= wxT("\n");
2503 // There must be a message to send
2504 // - except if we got disconnected. No need to assert therefore.
2506 m_pendingMessage
+= message
;
2509 if (IsConnected()) {
2510 // If we are already connected when we send the first message,
2511 // we have to update the chat status.
2512 SetChatState(MS_CHATTING
);
2514 data
.WriteString(message
, GetUnicodeSupport());
2515 CPacket
* packet
= new CPacket(data
, OP_EDONKEYPROT
, OP_MESSAGE
);
2516 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2517 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_MESSAGE to ") + GetFullIP());
2518 SendPacket(packet
, true, true);
2521 m_pendingMessage
= message
;
2522 SetChatState(MS_CONNECTING
);
2523 // True to ignore "Too Many Connections"
2531 void CUpDownClient::SetBuddyID(const byte
* pucBuddyID
)
2533 if( pucBuddyID
== NULL
){
2534 md4clr(m_achBuddyID
);
2535 m_bBuddyIDValid
= false;
2538 m_bBuddyIDValid
= true;
2539 md4cpy(m_achBuddyID
, pucBuddyID
);
2544 bool CUpDownClient::SendBuddyPing() {
2545 SetLastBuddyPingPongTime();
2546 CPacket
* buddyPing
= new CPacket(OP_BUDDYPING
, 0, OP_EMULEPROT
);
2547 theStats::AddUpOverheadKad(buddyPing
->GetPacketSize());
2548 AddDebugLogLineN(logLocalClient
,wxT("Local Client: OP_BUDDYPING to ") + GetFullIP());
2549 return SafeSendPacket(buddyPing
);
2555 void CUpDownClient::UpdateStats()
2557 if (m_lastClientSoft
!= m_clientSoft
|| m_lastClientVersion
!= m_nClientVersion
|| m_lastOSInfo
!= m_sClientOSInfo
) {
2558 if (m_lastClientSoft
== SO_UNKNOWN
) {
2559 theStats::RemoveUnknownClient();
2560 } else if (m_lastClientSoft
!= (uint32
)(-1)) {
2561 theStats::RemoveKnownClient(m_lastClientSoft
, m_lastClientVersion
, m_lastOSInfo
);
2564 m_lastClientSoft
= m_clientSoft
;
2565 m_lastClientVersion
= m_nClientVersion
;
2566 m_lastOSInfo
= m_sClientOSInfo
;
2568 if (m_clientSoft
== SO_UNKNOWN
) {
2569 theStats::AddUnknownClient();
2571 theStats::AddKnownClient(this);
2576 bool CUpDownClient::IsIdentified() const
2578 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED
);
2581 bool CUpDownClient::IsBadGuy() const
2583 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDBADGUY
);
2586 bool CUpDownClient::SUIFailed() const
2588 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDFAILED
);
2591 bool CUpDownClient::SUINeeded() const
2593 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_IDNEEDED
);
2596 bool CUpDownClient::SUINotSupported() const
2598 return (credits
&& credits
->GetCurrentIdentState(GetIP()) == IS_NOTAVAILABLE
);
2601 uint64
CUpDownClient::GetDownloadedTotal() const
2603 return credits
? credits
->GetDownloadedTotal() : 0;
2606 uint64
CUpDownClient::GetUploadedTotal() const
2608 return credits
? credits
->GetUploadedTotal() : 0;
2611 double CUpDownClient::GetScoreRatio() const
2613 return credits
? credits
->GetScoreRatio(GetIP(), theApp
->CryptoAvailable()) : 0;
2616 const wxString
CUpDownClient::GetServerName() const
2619 wxString srvaddr
= Uint32toStringIP(GetServerIP());
2620 CServer
* cserver
= theApp
->serverlist
->GetServerByAddress(
2621 srvaddr
, GetServerPort());
2623 ret
= cserver
->GetListName();
2631 bool CUpDownClient::ShouldReceiveCryptUDPPackets() const
2633 return (thePrefs::IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp
->GetPublicIP() != 0
2634 && HasValidHash() && (thePrefs::IsClientCryptLayerRequested() || RequestsCryptLayer()) );
2639 void CUpDownClient::ProcessCaptchaRequest(CMemFile
* WXUNUSED(data
)) {}
2640 void CUpDownClient::ProcessCaptchaReqRes(uint8
WXUNUSED(nStatus
)) {}
2641 void CUpDownClient::ProcessChatMessage(const wxString
WXUNUSED(message
)) {}
2645 void CUpDownClient::ProcessCaptchaRequest(CMemFile
* data
)
2647 uint64 id
= GUI_ID(GetIP(),GetUserPort());
2648 // received a captcha request, check if we actually accept it (only after sending a message ourself to this client)
2649 if (GetChatCaptchaState() == CA_ACCEPTING
&& GetChatState() != MS_NONE
2650 && theApp
->amuledlg
->m_chatwnd
->IsIdValid(id
)) {
2651 // read tags (for future use)
2652 uint8 nTagCount
= data
->ReadUInt8();
2654 AddDebugLogLineN(logClient
, CFormat(wxT("Received captcha request from client (%s) with (%u) tags")) % GetFullIP() % nTagCount
);
2655 // and ignore them for now
2656 for (uint32 i
= 0; i
< nTagCount
; i
++) {
2657 CTag
tag(*data
, true);
2661 // sanitize checks - we want a small captcha not a wallpaper
2662 uint32 nSize
= (uint32
)(data
->GetLength() - data
->GetPosition());
2664 if ( nSize
> 128 && nSize
< 4096 ) {
2665 uint64 pos
= data
->GetPosition();
2666 wxMemoryInputStream
memstr(data
->GetRawBuffer() + pos
, nSize
);
2667 wxImage
imgCaptcha(memstr
, wxBITMAP_TYPE_BMP
);
2669 if (imgCaptcha
.IsOk() && imgCaptcha
.GetHeight() > 10 && imgCaptcha
.GetHeight() < 50
2670 && imgCaptcha
.GetWidth() > 10 && imgCaptcha
.GetWidth() < 150 ) {
2671 m_nChatCaptchaState
= CA_CAPTCHARECV
;
2672 CCaptchaDialog
* dialog
= new CCaptchaDialog(theApp
->amuledlg
, imgCaptcha
, id
);
2676 AddDebugLogLineN(logClient
, CFormat(wxT("Received captcha request from client, processing image failed or invalid pixel size (%s)")) % GetFullIP());
2679 AddDebugLogLineN(logClient
, CFormat(wxT("Received captcha request from client, size sanitize check failed (%u) (%s)")) % nSize
% GetFullIP());
2682 AddDebugLogLineN(logClient
, CFormat(wxT("Received captcha request from client, but don't accepting it at this time (%s)")) % GetFullIP());
2686 void CUpDownClient::ProcessCaptchaReqRes(uint8 nStatus
)
2688 uint64 id
= GUI_ID(GetIP(),GetUserPort());
2689 if (GetChatCaptchaState() == CA_SOLUTIONSENT
&& GetChatState() != MS_NONE
2690 && theApp
->amuledlg
->m_chatwnd
->IsIdValid(id
)) {
2691 wxASSERT( nStatus
< 3 );
2692 m_nChatCaptchaState
= CA_NONE
;
2693 theApp
->amuledlg
->m_chatwnd
->ShowCaptchaResult(id
, nStatus
== 0);
2695 m_nChatCaptchaState
= CA_NONE
;
2696 AddDebugLogLineN(logClient
, CFormat(wxT("Received captcha result from client, but not accepting it at this time (%s)")) % GetFullIP());
2700 void CUpDownClient::ProcessChatMessage(wxString message
)
2702 if (IsMessageFiltered(message
)) {
2703 AddLogLineC(CFormat(_("Message filtered from '%s' (IP:%s)")) % GetUserName() % GetFullIP());
2707 // advanced spamfilter check
2708 if (thePrefs::IsChatCaptchaEnabled() && !IsFriend()) {
2709 // captcha checks outrank any further checks - if the captcha has been solved, we assume it's not spam
2710 // first check if we need to send a captcha request to this client
2711 if (GetMessagesSent() == 0 && GetMessagesReceived() == 0 && GetChatCaptchaState() != CA_CAPTCHASOLVED
) {
2712 // we have never sent a message to this client, and no message from him has ever passed our filters
2713 if (GetChatCaptchaState() != CA_CHALLENGESENT
) {
2714 // we also aren't currently expecting a captcha response
2715 if (m_fSupportsCaptcha
) {
2716 // and he supports captcha, so send him one and store the message (without showing for now)
2717 if (m_cCaptchasSent
< 3) { // no more than 3 tries
2718 m_strCaptchaPendingMsg
= message
;
2719 wxMemoryOutputStream memstr
;
2720 memstr
.PutC(0); // no tags, for future use
2721 CCaptchaGenerator
captcha(4);
2722 if (captcha
.WriteCaptchaImage(memstr
)){
2723 m_strCaptchaChallenge
= captcha
.GetCaptchaText();
2724 m_nChatCaptchaState
= CA_CHALLENGESENT
;
2726 CMemFile
fileAnswer((byte
*) memstr
.GetOutputStreamBuffer()->GetBufferStart(), memstr
.GetLength());
2727 CPacket
* packet
= new CPacket(fileAnswer
, OP_EMULEPROT
, OP_CHATCAPTCHAREQ
);
2728 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2729 AddLogLineN(CFormat(wxT("sent Captcha %s (%d)")) % m_strCaptchaChallenge
% packet
->GetPacketSize());
2730 SafeSendPacket(packet
);
2736 // client doesn't support captchas, but we require them, tell him that it's not going to work out
2737 // with an answer message (will not be shown and doesn't count as sent message)
2738 if (m_cCaptchasSent
< 1) { // don't send this notifier more than once
2740 // always sent in english
2741 SendChatMessage(wxT("In order to avoid spam messages, this user requires you to solve a captcha before you can send a message to him. However your client does not supports captchas, so you will not be able to chat with this user."));
2742 AddDebugLogLineN(logClient
, CFormat(wxT("Received message from client not supporting captchas, filtered and sent notifier (%s)")) % GetClientFullInfo());
2744 AddDebugLogLineN(logClient
, CFormat(wxT("Received message from client not supporting captchas, filtered, didn't send notifier (%s)")) % GetClientFullInfo());
2748 } else { // (GetChatCaptchaState() == CA_CHALLENGESENT)
2749 // this message must be the answer to the captcha request we sent him, let's verify
2750 wxASSERT( !m_strCaptchaChallenge
.IsEmpty() );
2751 if (m_strCaptchaChallenge
.CmpNoCase(message
.Trim().Right(std::min(message
.Length(), m_strCaptchaChallenge
.Length()))) == 0) {
2753 AddDebugLogLineN(logClient
, CFormat(wxT("Captcha solved, showing withheld message (%s)")) % GetClientFullInfo());
2754 m_nChatCaptchaState
= CA_CAPTCHASOLVED
; // this state isn't persitent, but the messagecounter will be used to determine later if the captcha has been solved
2755 // replace captchaanswer with withheld message and show it
2756 message
= m_strCaptchaPendingMsg
;
2757 m_cCaptchasSent
= 0;
2758 m_strCaptchaChallenge
.Clear();
2759 CPacket
* packet
= new CPacket(OP_CHATCAPTCHARES
, 1, OP_EMULEPROT
, false);
2760 byte statusResponse
= 0; // status response
2761 packet
->CopyToDataBuffer(0, &statusResponse
, 1);
2762 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2763 SafeSendPacket(packet
);
2764 } else { // wrong, cleanup and ignore
2765 AddDebugLogLineN(logClient
, CFormat(wxT("Captcha answer failed (%s)")) % GetClientFullInfo());
2766 m_nChatCaptchaState
= CA_NONE
;
2767 m_strCaptchaChallenge
.Clear();
2768 m_strCaptchaPendingMsg
.Clear();
2769 CPacket
* packet
= new CPacket(OP_CHATCAPTCHARES
, 1, OP_EMULEPROT
, false);
2770 byte statusResponse
= (m_cCaptchasSent
< 3) ? 1 : 2; // status response
2771 packet
->CopyToDataBuffer(0, &statusResponse
, 1);
2772 theStats::AddUpOverheadOther(packet
->GetPacketSize());
2773 SafeSendPacket(packet
);
2774 return; // nothing more todo
2780 if (thePrefs::IsAdvancedSpamfilterEnabled() && !IsFriend()) { // friends are never spammer... (but what if two spammers are friends :P )
2781 bool bIsSpam
= false;
2785 // first fixed criteria: If a client sends me an URL in his first message before I respond to him
2786 // there is a 99,9% chance that it is some poor guy advising his leech mod, or selling you .. well you know :P
2787 if (GetMessagesSent() == 0) {
2788 static wxArrayString
urlindicators(wxStringTokenize(wxT("http:|www.|.de |.net |.com |.org |.to |.tk |.cc |.fr |ftp:|ed2k:|https:|ftp.|.info|.biz|.uk|.eu|.es|.tv|.cn|.tw|.ws|.nu|.jp"), wxT("|")));
2789 for (size_t pos
= urlindicators
.GetCount(); pos
--;) {
2790 if (message
.Find(urlindicators
[pos
]) != wxNOT_FOUND
) {
2795 // second fixed criteria: he sent me 4 or more messages and I didn't answer him once
2796 if (GetMessagesReceived() > 3) {
2802 AddDebugLogLineN(logClient
, CFormat(wxT("'%s' has been marked as spammer")) % GetUserName());
2804 theApp
->amuledlg
->m_chatwnd
->EndSession(GUI_ID(GetIP(),GetUserPort()));
2810 wxString logMsg
= CFormat(_("New message from '%s' (IP:%s)")) % GetUserName() % GetFullIP();
2811 if(thePrefs::ShowMessagesInLog()) {
2812 logMsg
+= wxT(": ") + message
;
2814 AddLogLineC(logMsg
);
2815 IncMessagesReceived();
2817 Notify_ChatProcessMsg(GUI_ID(GetIP(), GetUserPort()), GetUserName() + wxT("|") + message
);
2820 bool CUpDownClient::IsMessageFiltered(const wxString
& message
)
2822 bool filtered
= false;
2823 // If we're chatting to the guy, we don't want to filter!
2824 if (GetChatState() != MS_CHATTING
) {
2825 if (thePrefs::MsgOnlyFriends() && !IsFriend()) {
2827 } else if (thePrefs::MsgOnlySecure() && GetUserName().IsEmpty() ) {
2829 } else if (thePrefs::MustFilterMessages()) {
2830 filtered
= thePrefs::IsMessageFiltered(message
);
2841 void CUpDownClient::SendSharedDirectories()
2843 // This list will contain all (unique) folders.
2844 PathList foldersToSend
;
2846 // The shared folders
2847 const unsigned folderCount
= theApp
->glob_prefs
->shareddir_list
.size();
2848 for (unsigned i
= 0; i
< folderCount
; ++i
) {
2849 foldersToSend
.push_back(theApp
->glob_prefs
->shareddir_list
[i
]);
2852 // ... the categories folders ... (category 0 -> incoming)
2853 for (unsigned i
= 0; i
< theApp
->glob_prefs
->GetCatCount(); ++i
) {
2854 foldersToSend
.push_back(theApp
->glob_prefs
->GetCategory(i
)->path
);
2858 foldersToSend
.sort();
2859 foldersToSend
.unique();
2862 CMemFile
tempfile(80);
2863 tempfile
.WriteUInt32(foldersToSend
.size() + 1); // + 1 for the incomplete files
2865 PathList::iterator it
= foldersToSend
.begin();
2866 for (; it
!= foldersToSend
.end(); ++it
) {
2867 // Note: the public shared name contains the 'raw' path, so we can recognize it again.
2868 // the 'raw' path is determined using CPath::GetRaw()
2869 tempfile
.WriteString( theApp
->sharedfiles
->GetPublicSharedDirName(*it
), GetUnicodeSupport() );
2872 // ... and the Magic thing from the eDonkey Hybrids...
2873 tempfile
.WriteString(OP_INCOMPLETE_SHARED_FILES
, GetUnicodeSupport());
2876 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDDIRSANS
);
2877 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
2878 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + GetFullIP() );
2879 SendPacket(replypacket
, true, true);
2882 void CUpDownClient::SendSharedFilesOfDirectory(const wxString
& strReqDir
)
2884 CKnownFilePtrList list
;
2886 if (strReqDir
== OP_INCOMPLETE_SHARED_FILES
) {
2887 // get all shared files from download queue
2888 int iQueuedFiles
= theApp
->downloadqueue
->GetFileCount();
2889 for (int i
= 0; i
< iQueuedFiles
; i
++) {
2890 CPartFile
* pFile
= theApp
->downloadqueue
->GetFileByIndex(i
);
2891 if (pFile
== NULL
|| pFile
->GetStatus(true) != PS_READY
) {
2894 list
.push_back(pFile
);
2897 // get all shared files for the requested directory
2898 const CPath
*sharedDir
= theApp
->sharedfiles
->GetDirForPublicSharedDirName(strReqDir
);
2900 theApp
->sharedfiles
->GetSharedFilesByDirectory(sharedDir
->GetRaw(), list
);
2902 AddLogLineC(CFormat(_("User %s (%u) requested sharedfiles-list for not existing directory '%s' -> Ignored")) % GetUserName() % GetUserIDHybrid() % strReqDir
);
2906 CMemFile
tempfile(80);
2907 tempfile
.WriteString(strReqDir
, GetUnicodeSupport());
2908 tempfile
.WriteUInt32(list
.size());
2910 while (!list
.empty()) {
2911 if (!list
.front()->IsLargeFile() || SupportsLargeFiles()) {
2912 list
.front()->CreateOfferedFilePacket(&tempfile
, NULL
, this);
2917 CPacket
* replypacket
= new CPacket(tempfile
, OP_EDONKEYPROT
, OP_ASKSHAREDFILESDIRANS
);
2918 theStats::AddUpOverheadOther(replypacket
->GetPacketSize());
2919 AddDebugLogLineN( logLocalClient
, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + GetFullIP() );
2920 SendPacket(replypacket
, true, true);
2923 void CUpDownClient::SendFirewallCheckUDPRequest()
2925 wxASSERT(GetKadState() == KS_FWCHECK_UDP
);
2927 if (!Kademlia::CKademlia::IsRunning()) {
2928 SetKadState(KS_NONE
);
2930 } else if (GetUploadState() != US_NONE
|| GetDownloadState() != DS_NONE
|| GetChatState() != MS_NONE
|| GetKadVersion() <= 5 || GetKadPort() == 0) {
2931 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetIP()), 0); // inform the tester that this test was cancelled
2932 SetKadState(KS_NONE
);
2937 data
.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetInternKadPort());
2938 data
.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort());
2939 data
.WriteUInt32(Kademlia::CKademlia::GetPrefs()->GetUDPVerifyKey(GetConnectIP()));
2940 CPacket
* packet
= new CPacket(data
, OP_EMULEPROT
, OP_FWCHECKUDPREQ
);
2941 theStats::AddUpOverheadKad(packet
->GetPacketSize());
2942 SafeSendPacket(packet
);
2945 void CUpDownClient::ProcessFirewallCheckUDPRequest(CMemFile
* data
)
2947 if (!Kademlia::CKademlia::IsRunning() || Kademlia::CKademlia::GetUDPListener() == NULL
) {
2948 //DebugLogWarning(_T("Ignored Kad Firewallrequest UDP because Kad is not running (%s)"), GetClientFullInfo());
2952 // first search if we know this IP already, if so the result might be biased and we need tell the requester
2953 bool errorAlreadyKnown
= false;
2954 if (GetUploadState() != US_NONE
|| GetDownloadState() != DS_NONE
|| GetChatState() != MS_NONE
) {
2955 errorAlreadyKnown
= true;
2956 } else if (Kademlia::CKademlia::GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0, false) != NULL
) {
2957 errorAlreadyKnown
= true;
2960 uint16_t remoteInternPort
= data
->ReadUInt16();
2961 uint16_t remoteExternPort
= data
->ReadUInt16();
2962 uint32_t senderKey
= data
->ReadUInt32();
2963 if (remoteInternPort
== 0) {
2964 //DebugLogError(_T("UDP Firewallcheck requested with Intern Port == 0 (%s)"), GetClientFullInfo());
2967 // if (senderKey == 0)
2968 // DebugLogWarning(_T("UDP Firewallcheck requested with SenderKey == 0 (%s)"), GetClientFullInfo());
2970 CMemFile testPacket1
;
2971 testPacket1
.WriteUInt8(errorAlreadyKnown
? 1 : 0);
2972 testPacket1
.WriteUInt16(remoteInternPort
);
2973 DebugSend(Kad2FirewallUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort
);
2974 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket1
, KADEMLIA2_FIREWALLUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort
, Kademlia::CKadUDPKey(senderKey
, theApp
->GetPublicIP(false)), NULL
);
2976 // if the client has a router with PAT (and therefore a different extern port than intern), test this port too
2977 if (remoteExternPort
!= 0 && remoteExternPort
!= remoteInternPort
) {
2978 CMemFile testPacket2
;
2979 testPacket2
.WriteUInt8(errorAlreadyKnown
? 1 : 0);
2980 testPacket2
.WriteUInt16(remoteExternPort
);
2981 DebugSend(Kad2FirewalledUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort
);
2982 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket2
, KADEMLIA2_FIREWALLUDP
, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort
, Kademlia::CKadUDPKey(senderKey
, theApp
->GetPublicIP(false)), NULL
);
2984 //DebugLog(_T("Answered UDP Firewallcheck request (%s)"), GetClientFullInfo());
2987 void CUpDownClient::SetConnectOptions(uint8_t options
, bool encryption
, bool callback
)
2989 SetCryptLayerSupport((options
& 0x01) != 0 && encryption
);
2990 SetCryptLayerRequest((options
& 0x02) != 0 && encryption
);
2991 SetCryptLayerRequires((options
& 0x04) != 0 && encryption
);
2992 SetDirectUDPCallbackSupport((options
& 0x08) != 0 && callback
);
2996 #ifdef DEBUG_ZOMBIE_CLIENTS
2997 void CUpDownClient::Unlink(const wxString
& from
)
2999 std::multiset
<wxString
>::iterator it
= m_linkedFrom
.find(from
);
3000 if (it
!= m_linkedFrom
.end()) {
3001 m_linkedFrom
.erase(it
);
3005 if (m_linkedDebug
) {
3006 AddLogLineN(CFormat(wxT("Last reference to client %d %p unlinked, delete it.")) % ECID() % this);
3014 void CUpDownClient::Unlink()
3024 // File_checked_for_headers