Upstream tarball 9408
[amule.git] / src / BaseClient.cpp
blob77140397122d4facaa92015755b1f843e2a77745
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2008 Merkur ( devs@emule-project.net / http://www.emule-project.net )
6 //
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
9 // respective authors.
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.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include <wx/wx.h>
28 #include "updownclient.h" // Needed for CUpDownClient
30 #include <protocol/Protocols.h>
31 #include <protocol/ed2k/Client2Client/TCP.h>
32 #include <protocol/ed2k/ClientSoftware.h>
33 #include <protocol/kad/Client2Client/UDP.h>
34 #include <protocol/kad2/Constants.h>
35 #include <protocol/kad2/Client2Client/TCP.h>
36 #include <protocol/kad2/Client2Client/UDP.h>
38 #include <common/ClientVersion.h>
40 #include <tags/ClientTags.h>
42 #include <zlib.h> // Needed for inflateEnd
44 #include <common/Format.h> // Needed for CFormat
46 #include "SearchList.h" // Needed for CSearchList
47 #include "DownloadQueue.h" // Needed for CDownloadQueue
48 #include "UploadQueue.h" // Needed for CUploadQueue
49 #include "IPFilter.h" // Needed for CIPFilter
50 #include "ServerConnect.h" // Needed for CServerConnect
51 #include "ClientCredits.h" // Needed for CClientCredits
52 #include "ClientCreditsList.h" // Needed for CClientCreditsList
53 #include "Server.h" // Needed for CServer
54 #include "Preferences.h" // Needed for CPreferences
55 #include "MemFile.h" // Needed for CMemFile
56 #include "Packet.h" // Needed for CPacket
57 #include "Friend.h" // Needed for CFriend
58 #include "ClientList.h" // Needed for CClientList
59 #include "amule.h" // Needed for theApp
60 #include "PartFile.h" // Needed for CPartFile
61 #include "ClientTCPSocket.h" // Needed for CClientTCPSocket
62 #include "ListenSocket.h" // Needed for CListenSocket
63 #include "FriendList.h" // Needed for CFriendList
64 #include "Statistics.h" // Needed for theStats
65 #include "ClientUDPSocket.h"
66 #include "Logger.h"
67 #include "DataToText.h" // Needed for GetSoftName()
68 #include "GuiEvents.h" // Needed for Notify_
69 #include "ServerList.h" // For CServerList
71 #include "kademlia/kademlia/Kademlia.h"
72 #include "kademlia/kademlia/Prefs.h"
73 #include "kademlia/kademlia/Search.h"
74 #include "kademlia/kademlia/UDPFirewallTester.h"
75 #include "kademlia/routing/RoutingZone.h"
78 //#define __PACKET_DEBUG__
81 // some client testing variables
82 static wxString crash_name = wxT("[Invalid User Name]");
83 static wxString empty_name = wxT("[Empty User Name]");
85 // members of CUpDownClient
86 // which are used by down and uploading functions
89 CUpDownClient::CUpDownClient(CClientTCPSocket* sender)
91 #ifdef __DEBUG__
92 m_socket = NULL;
93 SetSocket(sender);
94 #else
95 m_socket = sender;
96 #endif
97 Init();
100 CUpDownClient::CUpDownClient(uint16 in_port, uint32 in_userid, uint32 in_serverip, uint16 in_serverport, CPartFile* in_reqfile, bool ed2kID, bool checkfriend)
102 m_socket = NULL;
103 Init();
104 m_nUserPort = in_port;
106 if(ed2kID && !IsLowID(in_userid)) {
107 SetUserIDHybrid( wxUINT32_SWAP_ALWAYS(in_userid) );
108 } else {
109 SetUserIDHybrid( in_userid);
112 //If highID and ED2K source, incoming ID and IP are equal..
113 //If highID and Kad source, incoming IP needs swap for the IP
115 if (!HasLowID()) {
116 if (ed2kID) {
117 m_nConnectIP = in_userid;
118 } else {
119 m_nConnectIP = wxUINT32_SWAP_ALWAYS(in_userid);
121 // Will be on right endianess now
122 m_FullUserIP = m_nConnectIP;
125 m_dwServerIP = in_serverip;
126 m_nServerPort = in_serverport;
127 SetRequestFile( in_reqfile );
128 ReGetClientSoft();
130 if (checkfriend) {
131 if ((m_Friend = theApp->friendlist->FindFriend(CMD4Hash(), m_dwUserIP, m_nUserPort)) != NULL){
132 m_Friend->LinkClient(this);
133 } else{
134 // avoid that an unwanted client instance keeps a friend slot
135 m_bFriendSlot = false;
141 void CUpDownClient::Init()
143 m_bAddNextConnect = false;
144 credits = NULL;
145 m_byChatstate = MS_NONE;
146 m_nKadState = KS_NONE;
147 m_cShowDR = 0;
148 m_reqfile = NULL; // No file required yet
149 m_nTransferredUp = 0;
150 m_cSendblock = 0;
151 m_cAsked = 0;
152 msReceivedPrev = 0;
153 kBpsDown = 0.0;
154 bytesReceivedCycle = 0;
155 m_nServerPort = 0;
156 m_iFileListRequested = 0;
157 m_dwLastUpRequest = 0;
158 m_bEmuleProtocol = false;
159 m_bCompleteSource = false;
160 m_bFriendSlot = false;
161 m_bCommentDirty = false;
162 m_bReaskPending = false;
163 m_bUDPPending = false;
164 m_nUserPort = 0;
165 m_nPartCount = 0;
166 m_dwLastAskedTime = 0;
167 m_nDownloadState = DS_NONE;
168 m_dwUploadTime = 0;
169 m_nTransferredDown = 0;
170 m_nUploadState = US_NONE;
171 m_dwLastBlockReceived = 0;
172 m_bUnicodeSupport = false;
174 m_fSentOutOfPartReqs = 0;
175 m_nCurQueueSessionPayloadUp = 0;
176 m_addedPayloadQueueSession = 0;
177 m_nUpDatarate = 0;
178 m_nSumForAvgUpDataRate = 0;
180 m_nRemoteQueueRank = 0;
181 m_nOldRemoteQueueRank = 0;
182 m_dwLastSourceRequest = 0;
183 m_dwLastSourceAnswer = 0;
184 m_dwLastAskedForSources = 0;
186 m_SecureIdentState = IS_UNAVAILABLE;
187 m_dwLastSignatureIP = 0;
189 m_byInfopacketsReceived = IP_NONE;
191 m_bIsHybrid = false;
192 m_bIsML = false;
193 m_Friend = NULL;
194 m_iRating = 0;
195 m_nCurSessionUp = 0;
196 m_clientSoft=SO_UNKNOWN;
198 m_bRemoteQueueFull = false;
199 m_HasValidHash = false;
200 SetWaitStartTime();
202 m_fHashsetRequesting = 0;
203 m_fSharedDirectories = 0;
204 m_lastPartAsked = 0xffff;
205 m_nUpCompleteSourcesCount= 0;
206 m_lastRefreshedDLDisplay = 0;
207 m_bHelloAnswerPending = false;
208 m_fSentCancelTransfer = 0;
209 m_Aggressiveness = 0;
210 m_LastFileRequest = 0;
212 m_clientState = CS_NEW;
214 ClearHelloProperties();
216 m_pReqFileAICHHash = NULL;
217 m_fSupportsAICH = 0;
218 m_fAICHRequested = 0;
219 m_fSupportsLargeFiles = 0;
220 m_fExtMultiPacket = 0;
222 m_dwUserIP = 0;
223 m_nConnectIP = 0;
224 m_dwServerIP = 0;
226 m_fNeedOurPublicIP = false;
227 m_bHashsetRequested = false;
229 m_nLastBlockOffset = 0;
231 m_uploadingfile = NULL;
233 m_OSInfo_sent = false;
235 /* Kad stuff */
236 SetBuddyID(NULL);
237 m_nBuddyIP = 0;
238 m_nBuddyPort = 0;
239 m_nUserIDHybrid = 0;
241 m_nSourceFrom = SF_NONE;
243 if (m_socket) {
244 amuleIPV4Address address;
245 m_socket->GetPeer(address);
246 SetIP(StringIPtoUint32(address.IPAddress()));
247 } else {
248 SetIP(0);
251 /* Statistics */
252 m_lastClientSoft = (uint32)(-1);
253 m_lastClientVersion = 0;
255 /* Creation time (for buddies timeout) */
256 m_nCreationTime = ::GetTickCount();
258 m_MaxBlockRequests = STANDARD_BLOCKS_REQUEST; // Safe starting amount
260 m_last_block_start = 0;
261 m_lastaverage = 0;
263 SetLastBuddyPingPongTime();
264 m_fRequestsCryptLayer = 0;
265 m_fSupportsCryptLayer = 0;
266 m_fRequiresCryptLayer = 0;
267 m_fSupportsSourceEx2 = 0;
268 m_fDirectUDPCallback = 0;
269 m_dwDirectCallbackTimeout = 0;
271 m_hasbeenobfuscatinglately = false;
275 CUpDownClient::~CUpDownClient()
277 #ifdef __DEBUG__
278 if (!connection_reason.IsEmpty()) {
279 AddDebugLogLineN(logClient, wxT("Client to check for ") + connection_reason + wxT(" was deleted without connection."));
281 #endif
283 if (m_lastClientSoft == SO_UNKNOWN) {
284 theStats::RemoveUnknownClient();
285 } else if (m_lastClientSoft != (uint32)(-1)) {
286 theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo);
289 // Indicate that we are not anymore on stats
290 m_lastClientSoft = (uint32)(-1);
293 if (IsAICHReqPending()){
294 m_fAICHRequested = FALSE;
295 CAICHHashSet::ClientAICHRequestFailed(this);
298 //theApp->clientlist->RemoveClient(this, wxT("Destructing client object"));
300 if (m_Friend) {
301 m_Friend->UnLinkClient();
302 Notify_ChatRefreshFriend(m_Friend->GetIP(), m_Friend->GetPort(), wxEmptyString);
303 m_Friend = NULL;
306 // The socket should have been removed in Safe_Delete, but it
307 // doesn't hurt to have an extra check.
308 if (m_socket) {
309 m_socket->Safe_Delete();
310 // Paranoia
311 SetSocket(NULL);
315 ClearUploadBlockRequests();
316 ClearDownloadBlockRequests();
318 DeleteContents(m_WaitingPackets_list);
320 if (m_iRating>0 || !m_strComment.IsEmpty()) {
321 m_iRating = 0;
322 m_strComment.Clear();
323 if (m_reqfile) {
324 m_reqfile->UpdateFileRatingCommentAvail();
328 // Ensure that source-counts gets updated in case
329 // of a source not on the download-queue
330 SetRequestFile( NULL );
332 SetUploadFileID(NULL);
334 if (m_pReqFileAICHHash != NULL) {
335 delete m_pReqFileAICHHash;
336 m_pReqFileAICHHash = NULL;
340 void CUpDownClient::ClearHelloProperties()
342 m_nUDPPort = 0;
343 m_byUDPVer = 0;
344 m_byDataCompVer = 0;
345 m_byEmuleVersion = 0;
346 m_bySourceExchange1Ver = 0;
347 m_byAcceptCommentVer = 0;
348 m_byExtendedRequestsVer = 0;
349 m_byCompatibleClient = 0;
350 m_nKadPort = 0;
351 m_bySupportSecIdent = 0;
352 m_bSupportsPreview = 0;
353 m_nClientVersion = 0;
354 m_fSharedDirectories = 0;
355 m_bMultiPacket = 0;
356 m_fOsInfoSupport = 0;
357 m_fValueBasedTypeTags = 0;
358 SecIdentSupRec = 0;
359 m_byKadVersion = 0;
360 m_fRequestsCryptLayer = 0;
361 m_fSupportsCryptLayer = 0;
362 m_fRequiresCryptLayer = 0;
363 m_fSupportsSourceEx2 = 0;
364 m_fDirectUDPCallback = 0;
367 bool CUpDownClient::ProcessHelloPacket(const byte* pachPacket, uint32 nSize)
369 const CMemFile data(pachPacket,nSize);
370 uint8 hashsize = data.ReadUInt8();
371 if ( 16 != hashsize ) {
373 * Hint: We can not accept other sizes here because:
374 * - the magic number is spread all over the source
375 * - the answer packet lacks the size field
377 throw wxString(wxT("Invalid Hello packet: Other userhash sizes than 16 are not implemented"));
379 // eMule 0.42: reset all client properties; a client may not send a particular emule tag any longer
380 ClearHelloProperties();
382 return ProcessHelloTypePacket(data);
385 void CUpDownClient::Safe_Delete()
387 // Because we are delaying the deletion, we might end up trying to delete
388 // it twice, however, this is normal and shouldn't trigger any failures
389 if ( m_clientState == CS_DYING ) {
390 return;
393 m_clientState = CS_DYING;
395 // Close the socket to avoid any more connections and related events
396 if ( m_socket ) {
397 m_socket->Safe_Delete();
398 // Paranoia
399 SetSocket(NULL);
402 // Schedule the client for deletion if we still have the clientlist
403 if ( theApp->clientlist ) {
404 theApp->clientlist->AddToDeleteQueue( this );
405 } else {
406 delete this;
411 bool CUpDownClient::ProcessHelloAnswer(const byte* pachPacket, uint32 nSize)
413 const CMemFile data(pachPacket,nSize);
414 bool bIsMule = ProcessHelloTypePacket(data);
415 m_bHelloAnswerPending = false;
416 return bIsMule;
419 bool CUpDownClient::ProcessHelloTypePacket(const CMemFile& data)
422 m_bIsHybrid = false;
423 m_bIsML = false;
424 m_fNoViewSharedFiles = 0;
425 m_bUnicodeSupport = false;
426 uint32 dwEmuleTags = 0;
428 CMD4Hash hash = data.ReadHash();
429 SetUserHash( hash );
430 SetUserIDHybrid( data.ReadUInt32() );
431 uint16 nUserPort = data.ReadUInt16(); // hmm clientport is sent twice - why?
432 uint32 tagcount = data.ReadUInt32();
433 for (uint32 i = 0;i < tagcount; i++){
434 CTag temptag(data, true);
435 switch(temptag.GetNameID()){
436 case CT_NAME:
437 m_Username = temptag.GetStr();
438 break;
440 case CT_VERSION:
441 m_nClientVersion = temptag.GetInt();
442 break;
444 case ET_MOD_VERSION:
445 if (temptag.IsStr()) {
446 m_strModVersion = temptag.GetStr();
447 } else if (temptag.IsInt()) {
448 m_strModVersion = wxString::Format(wxT("ModID=%u"), temptag.GetInt());
449 } else {
450 m_strModVersion = wxT("ModID=<Unknown>");
453 break;
455 case CT_PORT:
456 nUserPort = temptag.GetInt();
457 break;
459 case CT_EMULE_UDPPORTS:
460 // 16 KAD Port
461 // 16 UDP Port
462 SetKadPort((temptag.GetInt() >> 16) & 0xFFFF);
463 m_nUDPPort = temptag.GetInt() & 0xFFFF;
464 dwEmuleTags |= 1;
465 #ifdef __PACKET_DEBUG__
466 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule ports UDP=%i KAD=%i")) % m_nUDPPort % m_nKadPort);
467 #endif
468 break;
470 case CT_EMULE_BUDDYIP:
471 // 32 BUDDY IP
472 m_nBuddyIP = temptag.GetInt();
473 #ifdef __PACKET_DEBUG__
474 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule BuddyIP=%u (%s)")) % m_nBuddyIP % Uint32toStringIP(m_nBuddyIP));
475 #endif
476 break;
478 case CT_EMULE_BUDDYUDP:
479 // 16 --Reserved for future use--
480 // 16 BUDDY Port
481 m_nBuddyPort = (uint16)temptag.GetInt();
482 #ifdef __PACKET_DEBUG__
483 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule BuddyPort=%u")) % m_nBuddyPort);
484 #endif
485 break;
487 case CT_EMULE_MISCOPTIONS1: {
488 // 3 AICH Version (0 = not supported)
489 // 1 Unicode
490 // 4 UDP version
491 // 4 Data compression version
492 // 4 Secure Ident
493 // 4 Source Exchange
494 // 4 Ext. Requests
495 // 4 Comments
496 // 1 PeerCache supported
497 // 1 No 'View Shared Files' supported
498 // 1 MultiPacket
499 // 1 Preview
500 uint32 flags = temptag.GetInt();
501 m_fSupportsAICH = (flags >> (4*7+1)) & 0x07;
502 m_bUnicodeSupport = (flags >> 4*7) & 0x01;
503 m_byUDPVer = (flags >> 4*6) & 0x0f;
504 m_byDataCompVer = (flags >> 4*5) & 0x0f;
505 m_bySupportSecIdent = (flags >> 4*4) & 0x0f;
506 m_bySourceExchange1Ver = (flags >> 4*3) & 0x0f;
507 m_byExtendedRequestsVer = (flags >> 4*2) & 0x0f;
508 m_byAcceptCommentVer = (flags >> 4*1) & 0x0f;
509 m_fNoViewSharedFiles = (flags >> 1*2) & 0x01;
510 m_bMultiPacket = (flags >> 1*1) & 0x01;
511 m_fSupportsPreview = (flags >> 1*0) & 0x01;
512 dwEmuleTags |= 2;
513 #ifdef __PACKET_DEBUG__
514 AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options:"));
515 AddLogLineNS(CFormat(wxT("m_byUDPVer = %i")) % m_byUDPVer);
516 AddLogLineNS(CFormat(wxT("m_byDataCompVer = %i")) % m_byDataCompVer);
517 AddLogLineNS(CFormat(wxT("m_bySupportSecIdent = %i")) % m_bySupportSecIdent);
518 AddLogLineNS(CFormat(wxT("m_bySourceExchangeVer = %i")) % m_bySourceExchange1Ver);
519 AddLogLineNS(CFormat(wxT("m_byExtendedRequestsVer = %i")) % m_byExtendedRequestsVer);
520 AddLogLineNS(CFormat(wxT("m_byAcceptCommentVer = %i")) % m_byAcceptCommentVer);
521 AddLogLineNS(CFormat(wxT("m_fNoViewSharedFiles = %i")) % m_fNoViewSharedFiles);
522 AddLogLineNS(CFormat(wxT("m_bMultiPacket = %i")) % m_bMultiPacket);
523 AddLogLineNS(CFormat(wxT("m_fSupportsPreview = %i")) % m_fSharedDirectories);
524 AddLogLineNS(wxT("That's all."));
525 #endif
526 SecIdentSupRec += 1;
527 break;
530 case CT_EMULE_MISCOPTIONS2:
531 // 19 Reserved
532 // 1 Direct UDP Callback supported and available
533 // 1 Supports ChatCaptchas
534 // 1 Supports SourceExachnge2 Packets, ignores SX1 Packet Version
535 // 1 Requires CryptLayer
536 // 1 Requests CryptLayer
537 // 1 Supports CryptLayer
538 // 1 Reserved (ModBit)
539 // 1 Ext Multipacket (Hash+Size instead of Hash)
540 // 1 Large Files (includes support for 64bit tags)
541 // 4 Kad Version - will go up to version 15 only (may need to add another field at some point in the future)
542 m_fDirectUDPCallback = (temptag.GetInt() >> 12) & 0x01;
543 // 1 captcha support
544 m_fSupportsSourceEx2 = (temptag.GetInt() >> 10) & 0x01;
545 m_fRequiresCryptLayer = (temptag.GetInt() >> 9) & 0x01;
546 m_fRequestsCryptLayer = (temptag.GetInt() >> 8) & 0x01;
547 m_fSupportsCryptLayer = (temptag.GetInt() >> 7) & 0x01;
548 // reserved 1
549 m_fExtMultiPacket = (temptag.GetInt() >> 5) & 0x01;
550 m_fSupportsLargeFiles = (temptag.GetInt() >> 4) & 0x01;
551 m_byKadVersion = (temptag.GetInt() >> 0) & 0x0f;
552 dwEmuleTags |= 8;
554 m_fRequestsCryptLayer &= m_fSupportsCryptLayer;
555 m_fRequiresCryptLayer &= m_fRequestsCryptLayer;
557 #ifdef __PACKET_DEBUG__
558 AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options 2:"));
559 AddLogLineNS(CFormat(wxT(" m_fDirectUDPCallback = %i")) % m_fDirectUDPCallback);
560 AddLogLineNS(CFormat(wxT(" m_fSupportsSourceEx2 = %i")) % m_fSupportsSourceEx2);
561 AddLogLineNS(CFormat(wxT(" m_fRequiresCryptLayer = %i")) % m_fRequiresCryptLayer);
562 AddLogLineNS(CFormat(wxT(" m_fRequestsCryptLayer = %i")) % m_fRequestsCryptLayer);
563 AddLogLineNS(CFormat(wxT(" m_fSupportsCryptLayer = %i")) % m_fSupportsCryptLayer);
564 AddLogLineNS(CFormat(wxT(" m_fExtMultiPacket = %i")) % m_fExtMultiPacket);
565 AddLogLineNS(CFormat(wxT(" m_fSupportsLargeFiles = %i")) % m_fSupportsLargeFiles);
566 AddLogLineNS(CFormat(wxT(" KadVersion = %u")) % m_byKadVersion);
567 AddLogLineNS(wxT("That's all."));
568 #endif
569 break;
571 // Special tag for Compat. Clients Misc options.
572 case CT_EMULECOMPAT_OPTIONS:
573 // 1 Operative System Info
574 // 1 Value-based-type int tags (experimental!)
575 m_fValueBasedTypeTags = (temptag.GetInt() >> 1*1) & 0x01;
576 m_fOsInfoSupport = (temptag.GetInt() >> 1*0) & 0x01;
577 break;
579 case CT_EMULE_VERSION:
580 // 8 Compatible Client ID
581 // 7 Mjr Version (Doesn't really matter..)
582 // 7 Min Version (Only need 0-99)
583 // 3 Upd Version (Only need 0-5)
584 // 7 Bld Version (Only need 0-99)
585 m_byCompatibleClient = (temptag.GetInt() >> 24);
586 m_nClientVersion = temptag.GetInt() & 0x00ffffff;
587 m_byEmuleVersion = 0x99;
588 m_fSharedDirectories = 1;
589 dwEmuleTags |= 4;
590 break;
594 m_nUserPort = nUserPort;
595 m_dwServerIP = data.ReadUInt32();
596 m_nServerPort = data.ReadUInt16();
597 // Hybrid now has an extra uint32.. What is it for?
598 // Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
599 if ( data.GetLength() - data.GetPosition() == sizeof(uint32) ) {
600 uint32 test = data.ReadUInt32();
601 /*if (test == 'KDLM') below kdlm is converted to ascii values.
602 This fixes a warning with gcc 3.4.
603 K=4b D=44 L=4c M=4d
605 if (test == 0x4b444c4d) { //if it's == "KDLM"
606 m_bIsML=true;
607 } else{
608 m_bIsHybrid = true;
609 m_fSharedDirectories = 1;
613 if (m_socket) {
614 amuleIPV4Address address;
615 m_socket->GetPeer(address);
616 SetIP(StringIPtoUint32(address.IPAddress()));
617 } else {
618 throw wxString(wxT("Huh, socket failure. Avoided crash this time."));
621 if (thePrefs::AddServersFromClient()) {
622 CServer* addsrv = new CServer(m_nServerPort, Uint32toStringIP(m_dwServerIP));
623 addsrv->SetListName(addsrv->GetAddress());
624 if (!theApp->AddServer(addsrv)) {
625 delete addsrv;
629 //(a)If this is a highID user, store the ID in the Hybrid format.
630 //(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
631 //(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
632 //because they will send a ID that is the same as their IP..
633 if(!HasLowID() || m_nUserIDHybrid == 0 || m_nUserIDHybrid == m_dwUserIP ) {
634 SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(m_dwUserIP));
637 // get client credits
638 CClientCredits* pFoundCredits = theApp->clientcredits->GetCredit(m_UserHash);
639 if (credits == NULL){
640 credits = pFoundCredits;
641 if (!theApp->clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, pFoundCredits)){
642 AddDebugLogLineM( false, logClient, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed (Found in TrackedClientsList)") ) % GetUserName() % GetFullIP() );
643 Ban();
645 } else if (credits != pFoundCredits){
646 // userhash change ok, however two hours "waittime" before it can be used
647 credits = pFoundCredits;
648 AddDebugLogLineM( false, logClient, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed") ) % GetUserName() % GetFullIP() );
649 Ban();
652 if ((m_Friend = theApp->friendlist->FindFriend(m_UserHash, m_dwUserIP, m_nUserPort)) != NULL){
653 m_Friend->LinkClient(this);
654 } else{
655 // avoid that an unwanted client instance keeps a friend slot
656 SetFriendSlot(false);
660 ReGetClientSoft();
662 m_byInfopacketsReceived |= IP_EDONKEYPROTPACK;
664 // check if at least CT_EMULEVERSION was received, all other tags are optional
665 bool bIsMule = (dwEmuleTags & 0x04) == 0x04;
666 if (bIsMule) {
667 m_bEmuleProtocol = true;
668 m_byInfopacketsReceived |= IP_EMULEPROTPACK;
671 if( GetKadPort() ) {
672 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(GetIP()), GetKadPort(), GetKadVersion() > 1);
675 return bIsMule;
679 bool CUpDownClient::SendHelloPacket() {
681 if (m_socket == NULL){
682 wxASSERT(0);
683 return true;
686 // if IP is filtered, dont greet him but disconnect...
687 amuleIPV4Address address;
688 m_socket->GetPeer(address);
689 if ( theApp->ipfilter->IsFiltered(StringIPtoUint32(address.IPAddress()))) {
690 if (Disconnected(wxT("IPFilter"))) {
691 Safe_Delete();
692 return false;
694 return true;
697 CMemFile data(128);
698 data.WriteUInt8(16); // size of userhash
699 SendHelloTypePacket(&data);
701 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_HELLO);
702 theStats::AddUpOverheadOther(packet->GetPacketSize());
703 SendPacket(packet,true);
704 m_bHelloAnswerPending = true;
705 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_HELLO to ") + GetFullIP() );
706 return true;
709 void CUpDownClient::SendMuleInfoPacket(bool bAnswer, bool OSInfo) {
711 if (m_socket == NULL){
712 wxASSERT(0);
713 return;
716 CPacket* packet = NULL;
717 CMemFile data;
719 data.WriteUInt8(CURRENT_VERSION_SHORT);
721 if (OSInfo) {
723 // Special MuleInfo packet for clients supporting it.
724 // This means aMule >= 2.0.0 and Hydranode
726 // Violently mark it as special Mule Info packet
727 // Sending this makes non-supporting-osinfo clients to refuse to read this
728 // packet. Anyway, this packet should NEVER get to non-supporting clients.
730 data.WriteUInt8(/*EMULE_PROTOCOL*/ 0xFF);
732 data.WriteUInt32(1); // One Tag (OS_INFO)
734 CTagString tag1(ET_OS_INFO,theApp->GetOSType());
735 tag1.WriteTagToFile(&data);
737 m_OSInfo_sent = true; // So we don't send it again
739 } else {
741 // Normal MuleInfo packet
743 // Kry - There's no point on upgrading to VBT tags here
744 // as no client supporting it uses mule info packet.
746 data.WriteUInt8(EMULE_PROTOCOL);
748 // Tag number
749 data.WriteUInt32(9);
751 CTagInt32 tag1(ET_COMPRESSION,1);
752 tag1.WriteTagToFile(&data);
753 CTagInt32 tag2(ET_UDPVER,4);
754 tag2.WriteTagToFile(&data);
755 CTagInt32 tag3(ET_UDPPORT, thePrefs::GetEffectiveUDPPort());
756 tag3.WriteTagToFile(&data);
757 CTagInt32 tag4(ET_SOURCEEXCHANGE,3);
758 tag4.WriteTagToFile(&data);
759 CTagInt32 tag5(ET_COMMENTS,1);
760 tag5.WriteTagToFile(&data);
761 CTagInt32 tag6(ET_EXTENDEDREQUEST,2);
762 tag6.WriteTagToFile(&data);
764 uint32 dwTagValue = (theApp->CryptoAvailable() ? 3 : 0);
765 // Kry - Needs the preview code from eMule
767 // set 'Preview supported' only if 'View Shared Files' allowed
768 if (thePrefs::CanSeeShares() != vsfaNobody) {
769 dwTagValue |= 128;
772 CTagInt32 tag7(ET_FEATURES, dwTagValue);
773 tag7.WriteTagToFile(&data);
775 CTagInt32 tag8(ET_COMPATIBLECLIENT,SO_AMULE);
776 tag8.WriteTagToFile(&data);
778 // Support for tag ET_MOD_VERSION
779 wxString mod_name(MOD_VERSION_LONG);
780 CTagString tag9(ET_MOD_VERSION, mod_name);
781 tag9.WriteTagToFile(&data);
782 // Maella end
786 packet = new CPacket(data, OP_EMULEPROT, (bAnswer ? OP_EMULEINFOANSWER : OP_EMULEINFO));
788 if (m_socket) {
789 theStats::AddUpOverheadOther(packet->GetPacketSize());
790 SendPacket(packet,true,true);
792 if (!bAnswer) {
793 if (!OSInfo) {
794 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_EMULEINFO to ") + GetFullIP() );
795 } else {
796 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_EMULEINFO/OS_INFO to ") + GetFullIP() );
798 } else {
799 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_EMULEINFOANSWER to ") + GetFullIP() );
804 bool CUpDownClient::ProcessMuleInfoPacket(const byte* pachPacket, uint32 nSize)
806 uint8 protocol_version;
808 const CMemFile data(pachPacket,nSize);
810 // The version number part of this packet will soon be useless since
811 // it is only able to go to v.99. Why the version is a uint8 and why
812 // it was not done as a tag like the eDonkey hello packet is not known.
813 // Therefore, sooner or later, we are going to have to switch over to
814 // using the eDonkey hello packet to set the version. No sense making
815 // a third value sent for versions.
816 uint8 mule_version = data.ReadUInt8();
817 protocol_version = data.ReadUInt8();
818 uint32 tagcount = data.ReadUInt32();
819 if (protocol_version == 0xFF) {
820 // OS Info supporting clients sending a recycled Mule info packet
821 for (uint32 i = 0;i < tagcount; i++){
822 CTag temptag(data, true);
823 switch(temptag.GetNameID()){
824 case ET_OS_INFO:
825 // Special tag, only supporting clients (aMule/Hydranode)
826 // It was recycled from a mod's tag, so if the other side
827 // is not supporting OS Info, we're seriously fucked up :)
828 m_sClientOSInfo = temptag.GetStr();
830 // If we didn't send our OSInfo to this client, just send it
831 if (!m_OSInfo_sent) {
832 SendMuleInfoPacket(false,true);
835 UpdateStats();
837 break;
839 // Your ad... er... I mean TAG, here
841 default:
842 break;
845 } else {
846 // Old eMule sending tags
847 m_byCompatibleClient = 0;
848 m_byEmuleVersion = mule_version;
850 if( m_byEmuleVersion == 0x2B ) {
851 m_byEmuleVersion = 0x22;
854 if (!(m_bEmuleProtocol = (protocol_version == EMULE_PROTOCOL))) {
855 return false;
858 for (uint32 i = 0;i < tagcount; i++){
859 CTag temptag(data, false);
860 switch(temptag.GetNameID()){
861 case ET_COMPRESSION:
862 // Bits 31- 8: 0 - reserved
863 // Bits 7- 0: data compression version
864 m_byDataCompVer = temptag.GetInt();
865 break;
867 case ET_UDPPORT:
868 // Bits 31-16: 0 - reserved
869 // Bits 15- 0: UDP port
870 m_nUDPPort = temptag.GetInt();
871 break;
873 case ET_UDPVER:
874 // Bits 31- 8: 0 - reserved
875 // Bits 7- 0: UDP protocol version
876 m_byUDPVer = temptag.GetInt();
877 break;
879 case ET_SOURCEEXCHANGE:
880 // Bits 31- 8: 0 - reserved
881 // Bits 7- 0: source exchange protocol version
882 m_bySourceExchange1Ver = temptag.GetInt();
883 break;
885 case ET_COMMENTS:
886 // Bits 31- 8: 0 - reserved
887 // Bits 7- 0: comments version
888 m_byAcceptCommentVer = temptag.GetInt();
889 break;
891 case ET_EXTENDEDREQUEST:
892 // Bits 31- 8: 0 - reserved
893 // Bits 7- 0: extended requests version
894 m_byExtendedRequestsVer = temptag.GetInt();
895 break;
897 case ET_COMPATIBLECLIENT:
898 // Bits 31- 8: 0 - reserved
899 // Bits 7- 0: compatible client ID
900 m_byCompatibleClient = temptag.GetInt();
901 break;
903 case ET_FEATURES:
904 // Bits 31- 8: 0 - reserved
905 // Bit 7: Preview
906 // Bit 6- 0: secure identification
907 m_bySupportSecIdent = temptag.GetInt() & 3;
908 m_bSupportsPreview = (temptag.GetInt() & 128) > 0;
909 SecIdentSupRec += 2;
910 break;
912 case ET_MOD_VERSION:
913 if (temptag.IsStr()) {
914 m_strModVersion = temptag.GetStr();
915 } else if (temptag.IsInt()) {
916 m_strModVersion = wxString::Format(wxT("ModID=%u"), temptag.GetInt());
917 } else {
918 m_strModVersion = wxT("ModID=<Unknown>");
921 break;
923 default:
924 AddDebugLogLineM( false, logPacketErrors,
925 CFormat( wxT("Unknown Mule tag (%s) from client: %s") )
926 % temptag.GetFullInfo()
927 % GetClientFullInfo()
930 break;
934 if( m_byDataCompVer == 0 ){
935 m_bySourceExchange1Ver = 0;
936 m_byExtendedRequestsVer = 0;
937 m_byAcceptCommentVer = 0;
938 m_nUDPPort = 0;
941 //implicitly supported options by older clients
942 //in the future do not use version to guess about new features
943 if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x22) {
944 m_byUDPVer = 1;
947 if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21) {
948 m_bySourceExchange1Ver = 1;
951 if(m_byEmuleVersion == 0x24) {
952 m_byAcceptCommentVer = 1;
955 // Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
956 // the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
957 // directory which has a trailing backslash.
958 if(m_byEmuleVersion >= 0x28 && !m_bIsML) {// MLdonkey currently does not support shared directories
959 m_fSharedDirectories = 1;
962 ReGetClientSoft();
964 m_byInfopacketsReceived |= IP_EMULEPROTPACK;
967 return (protocol_version == 0xFF); // This was a OS_Info?
971 void CUpDownClient::SendHelloAnswer()
973 if (m_socket == NULL){
974 wxASSERT(0);
975 return;
978 CMemFile data(128);
979 SendHelloTypePacket(&data);
980 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_HELLOANSWER);
981 theStats::AddUpOverheadOther(packet->GetPacketSize());
982 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_HELLOANSWER to ") + GetFullIP() );
983 SendPacket(packet,true);
987 void CUpDownClient::SendHelloTypePacket(CMemFile* data)
989 data->WriteHash(thePrefs::GetUserHash());
990 data->WriteUInt32(theApp->GetID());
991 data->WriteUInt16(thePrefs::GetPort());
993 uint32 tagcount = 6;
995 if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) {
996 tagcount += 2;
998 tagcount ++; // eMule misc flags 2 (kad version)
1000 #ifdef __SVN__
1001 // Kry - This is the tagcount!!! Be sure to update it!!
1002 // Last update: CT_EMULECOMPAT_OPTIONS included
1003 data->WriteUInt32(tagcount + 1);
1004 #else
1005 data->WriteUInt32(tagcount); // NO MOD_VERSION
1006 #endif
1009 CTagString tagname(CT_NAME,thePrefs::GetUserNick());
1010 tagname.WriteTagToFile(data, utf8strRaw);
1012 CTagVarInt tagversion(CT_VERSION, EDONKEYVERSION, GetVBTTags() ? 0 : 32);
1013 tagversion.WriteTagToFile(data);
1014 // eMule UDP Ports
1016 uint32 kadUDPPort = 0;
1018 if(Kademlia::CKademlia::IsConnected()) {
1019 if (Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0 && Kademlia::CKademlia::GetPrefs()->GetUseExternKadPort() && Kademlia::CUDPFirewallTester::IsVerified()) {
1020 kadUDPPort = Kademlia::CKademlia::GetPrefs()->GetExternalKadPort();
1021 } else {
1022 kadUDPPort = Kademlia::CKademlia::GetPrefs()->GetInternKadPort();
1026 CTagVarInt tagUdpPorts(CT_EMULE_UDPPORTS, (kadUDPPort << 16) | ((uint32)thePrefs::GetEffectiveUDPPort()), GetVBTTags() ? 0 : 32);
1027 tagUdpPorts.WriteTagToFile(data);
1029 if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) {
1030 CTagVarInt tagBuddyIP(CT_EMULE_BUDDYIP, theApp->clientlist->GetBuddy()->GetIP(), GetVBTTags() ? 0 : 32);
1031 tagBuddyIP.WriteTagToFile(data);
1033 CTagVarInt tagBuddyPort(CT_EMULE_BUDDYUDP,
1034 // ( RESERVED )
1035 ((uint32)theApp->clientlist->GetBuddy()->GetUDPPort() )
1036 , GetVBTTags() ? 0 : 32);
1037 tagBuddyPort.WriteTagToFile(data);
1040 // aMule Version
1041 CTagVarInt tagMuleVersion(CT_EMULE_VERSION,
1042 (SO_AMULE << 24) |
1043 make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE)
1044 // | (RESERVED )
1045 , GetVBTTags() ? 0 : 32);
1046 tagMuleVersion.WriteTagToFile(data);
1049 // eMule Misc. Options #1
1050 const uint32 uUdpVer = 4;
1051 const uint32 uDataCompVer = 1;
1052 const uint32 uSupportSecIdent = theApp->CryptoAvailable() ? 3 : 0;
1053 const uint32 uSourceExchangeVer = 3;
1054 const uint32 uExtendedRequestsVer = 2;
1055 const uint32 uAcceptCommentVer = 1;
1056 const uint32 uNoViewSharedFiles = (thePrefs::CanSeeShares() == vsfaNobody) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag
1057 const uint32 uMultiPacket = 1;
1058 const uint32 uSupportPreview = 0; // No network preview at all.
1059 const uint32 uPeerCache = 0; // No peercache for aMule, baby
1060 const uint32 uUnicodeSupport = 1;
1061 const uint32 nAICHVer = 1; // AICH is ENABLED right now.
1063 CTagVarInt tagMisOptions(CT_EMULE_MISCOPTIONS1,
1064 (nAICHVer << ((4*7)+1)) |
1065 (uUnicodeSupport << 4*7) |
1066 (uUdpVer << 4*6) |
1067 (uDataCompVer << 4*5) |
1068 (uSupportSecIdent << 4*4) |
1069 (uSourceExchangeVer << 4*3) |
1070 (uExtendedRequestsVer << 4*2) |
1071 (uAcceptCommentVer << 4*1) |
1072 (uPeerCache << 1*3) |
1073 (uNoViewSharedFiles << 1*2) |
1074 (uMultiPacket << 1*1) |
1075 (uSupportPreview << 1*0)
1076 , GetVBTTags() ? 0 : 32);
1077 tagMisOptions.WriteTagToFile(data);
1079 // eMule Misc. Options #2
1080 const uint32 uKadVersion = KADEMLIA_VERSION;
1081 const uint32 uSupportLargeFiles = 1;
1082 const uint32 uExtMultiPacket = 1;
1083 const uint32 uReserved = 0; // mod bit
1084 const uint32 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1085 const uint32 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1086 const uint32 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1087 const uint32 uSupportsSourceEx2 = 1;
1088 const uint32 uSupportsCaptcha = 0; // No captcha support in aMule, at least for now
1089 // direct callback is only possible if connected to kad, tcp firewalled and verified UDP open (for example on a full cone NAT)
1090 const uint32 uDirectUDPCallback = (Kademlia::CKademlia::IsRunning() && Kademlia::CKademlia::IsFirewalled()
1091 && !Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) && Kademlia::CUDPFirewallTester::IsVerified()) ? 1 : 0;
1093 CTagVarInt tagMisOptions2(CT_EMULE_MISCOPTIONS2,
1094 // (RESERVED )
1095 (uDirectUDPCallback << 12) |
1096 (uSupportsCaptcha << 11) |
1097 (uSupportsSourceEx2 << 10) |
1098 (uRequiresCryptLayer << 9) |
1099 (uRequestsCryptLayer << 8) |
1100 (uSupportsCryptLayer << 7) |
1101 (uReserved << 6) |
1102 (uExtMultiPacket << 5) |
1103 (uSupportLargeFiles << 4) |
1104 (uKadVersion << 0)
1105 , GetVBTTags() ? 0 : 32 );
1106 tagMisOptions2.WriteTagToFile(data);
1108 const uint32 nOSInfoSupport = 1; // We support OS_INFO
1109 const uint32 nValueBasedTypeTags = 0; // Experimental, disabled
1111 CTagVarInt tagMisCompatOptions(CT_EMULECOMPAT_OPTIONS,
1112 (nValueBasedTypeTags << 1*1) |
1113 (nOSInfoSupport << 1*0)
1114 , GetVBTTags() ? 0 : 32);
1116 tagMisCompatOptions.WriteTagToFile(data);
1118 #ifdef __SVN__
1119 wxString mod_name(MOD_VERSION_LONG);
1120 CTagString tagModName(ET_MOD_VERSION, mod_name);
1121 tagModName.WriteTagToFile(data);
1122 #endif
1124 uint32 dwIP = 0;
1125 uint16 nPort = 0;
1126 if (theApp->IsConnectedED2K()) {
1127 dwIP = theApp->serverconnect->GetCurrentServer()->GetIP();
1128 nPort = theApp->serverconnect->GetCurrentServer()->GetPort();
1130 data->WriteUInt32(dwIP);
1131 data->WriteUInt16(nPort);
1135 void CUpDownClient::ProcessMuleCommentPacket(const byte* pachPacket, uint32 nSize)
1137 if (!m_reqfile) {
1138 throw CInvalidPacket(wxT("Comment packet for unknown file"));
1141 if (!m_reqfile->IsPartFile()) {
1142 throw CInvalidPacket(wxT("Comment packet for completed file"));
1145 const CMemFile data(pachPacket, nSize);
1147 uint8 rating = data.ReadUInt8();
1148 if (rating > 5) {
1149 AddDebugLogLineM( false, logClient, wxString(wxT("Invalid Rating for file '")) << m_clientFilename << wxT("' received: ") << rating);
1150 m_iRating = 0;
1151 } else {
1152 m_iRating = rating;
1153 AddDebugLogLineM( false, logClient, wxString(wxT("Rating for file '")) << m_clientFilename << wxT("' received: ") << m_iRating);
1156 // The comment is unicoded, with a uin32 len and safe read
1157 // (won't break if string size is < than advertised len)
1158 // Truncated to MAXFILECOMMENTLEN size
1159 m_strComment = data.ReadString((GetUnicodeSupport() != utf8strNone), 4 /* bytes (it's a uint32)*/, true).Left(MAXFILECOMMENTLEN);
1161 AddDebugLogLineM( false, logClient, wxString(wxT("Description for file '")) << m_clientFilename << wxT("' received: ") << m_strComment);
1163 // Update file rating
1164 m_reqfile->UpdateFileRatingCommentAvail();
1168 void CUpDownClient::ClearDownloadBlockRequests()
1171 std::list<Requested_Block_Struct*>::iterator it = m_DownloadBlocks_list.begin();
1172 for (; it != m_DownloadBlocks_list.end(); ++it) {
1173 Requested_Block_Struct* cur_block = *it;
1175 if (m_reqfile){
1176 m_reqfile->RemoveBlockFromList(cur_block->StartOffset, cur_block->EndOffset);
1179 delete cur_block;
1182 m_DownloadBlocks_list.clear();
1186 std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin();
1187 for (; it != m_PendingBlocks_list.end(); ++it) {
1188 Pending_Block_Struct* pending = *it;
1190 if (m_reqfile) {
1191 m_reqfile->RemoveBlockFromList(pending->block->StartOffset, pending->block->EndOffset);
1194 delete pending->block;
1195 // Not always allocated
1196 if (pending->zStream){
1197 inflateEnd(pending->zStream);
1198 delete pending->zStream;
1201 delete pending;
1204 m_PendingBlocks_list.clear();
1209 bool CUpDownClient::Disconnected(const wxString& strReason, bool bFromSocket)
1211 //wxASSERT(theApp->clientlist->IsValidClient(this));
1213 // was this a direct callback?
1214 if (m_dwDirectCallbackTimeout != 0) {
1215 theApp->clientlist->RemoveDirectCallback(this);
1216 m_dwDirectCallbackTimeout = 0;
1217 theApp->clientlist->AddDeadSource(this);
1218 AddDebugLogLineM(false, logClient, wxT("Direct callback failed to client ") + GetUserHash().Encode() + wxT(" on ip ") + GetFullIP());
1221 if (GetKadState() == KS_QUEUED_FWCHECK_UDP || GetKadState() == KS_CONNECTING_FWCHECK_UDP) {
1222 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test was cancelled
1223 } else if (GetKadState() == KS_FWCHECK_UDP) {
1224 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, false, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test has failed
1225 // } else if (GetKadState() == KS_CONNECTED_BUDDY) {
1226 // AddDebugLogLineM(false, logClient, wxT("Buddy client disconnected - ") + strReason);
1229 //If this is a KAD client object, just delete it!
1230 SetKadState(KS_NONE);
1232 if (GetUploadState() == US_UPLOADING) {
1233 theApp->uploadqueue->RemoveFromUploadQueue(this);
1236 if (GetDownloadState() == DS_DOWNLOADING) {
1237 SetDownloadState(DS_ONQUEUE);
1238 } else{
1239 // ensure that all possible block requests are removed from the partfile
1240 ClearDownloadBlockRequests();
1242 if ( GetDownloadState() == DS_CONNECTED ){
1243 theApp->clientlist->AddDeadSource(this);
1244 theApp->downloadqueue->RemoveSource(this);
1248 // we had still an AICH request pending, handle it
1249 if (IsAICHReqPending()){
1250 m_fAICHRequested = FALSE;
1251 CAICHHashSet::ClientAICHRequestFailed(this);
1254 // The remote client does not have to answer with OP_HASHSETANSWER *immediatly*
1255 // after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client
1256 // is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
1257 if (((GetDownloadState() == DS_REQHASHSET) || m_fHashsetRequesting) && (m_reqfile)) {
1258 m_reqfile->SetHashSetNeeded(true);
1261 //check if this client is needed in any way, if not delete it
1262 bool bDelete = true;
1263 switch(m_nUploadState){
1264 case US_ONUPLOADQUEUE:
1265 bDelete = false;
1266 break;
1268 switch(m_nDownloadState){
1269 case DS_ONQUEUE:
1270 case DS_TOOMANYCONNS:
1271 case DS_NONEEDEDPARTS:
1272 case DS_LOWTOLOWIP:
1273 bDelete = false;
1276 switch(m_nUploadState){
1277 case US_CONNECTING:
1278 case US_WAITCALLBACK:
1279 case US_ERROR:
1280 theApp->clientlist->AddDeadSource(this);
1281 bDelete = true;
1283 switch(m_nDownloadState){
1284 case DS_CONNECTING:
1285 case DS_WAITCALLBACK:
1286 case DS_ERROR:
1287 theApp->clientlist->AddDeadSource(this);
1288 bDelete = true;
1292 if (GetChatState() != MS_NONE){
1293 bDelete = false;
1294 m_pendingMessage.Clear();
1295 Notify_ChatConnResult(false,GUI_ID(GetIP(),GetUserPort()),wxEmptyString);
1298 if (!bFromSocket && m_socket){
1299 wxASSERT (theApp->listensocket->IsValidSocket(m_socket));
1300 m_socket->Safe_Delete();
1303 SetSocket(NULL);
1305 if (m_iFileListRequested){
1306 AddLogLineM( false, CFormat(_("Failed to retrieve shared files from user '%s'")) % GetUserName() );
1307 m_iFileListRequested = 0;
1310 Notify_ClientCtrlRefreshClient( this );
1312 if (bDelete) {
1313 if (m_Friend) {
1314 // Remove the friend linkage
1315 Notify_ChatRefreshFriend(m_Friend->GetIP(), m_Friend->GetPort(), wxEmptyString);
1317 AddDebugLogLineM( false, logClient, wxString() <<
1318 wxT("--- Deleted client \"") << GetClientFullInfo() <<
1319 wxT("\"; Reason was ") << strReason );
1320 } else {
1321 AddDebugLogLineM( false, logClient, wxString() <<
1322 wxT("--- Disconnected client \"") << GetClientFullInfo() <<
1323 wxT("\"; Reason was ") << strReason );
1324 m_fHashsetRequesting = 0;
1325 SetSentCancelTransfer(0);
1326 m_bHelloAnswerPending = false;
1327 m_fSentOutOfPartReqs = 0;
1330 return bDelete;
1333 //Returned bool is not if the TryToConnect is successful or not..
1334 //false means the client was deleted!
1335 //true means the client was not deleted!
1336 bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon)
1338 // Kad reviewed
1339 if (theApp->listensocket->TooManySockets() && !bIgnoreMaxCon ) {
1340 if (!(m_socket && m_socket->IsConnected())) {
1341 if(Disconnected(wxT("Too many connections"))) {
1342 Safe_Delete();
1343 return false;
1345 return true;
1349 // 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)
1350 if ( (RequiresCryptLayer() && !thePrefs::IsClientCryptLayerSupported()) || (thePrefs::IsClientCryptLayerRequired() && !SupportsCryptLayer()) ){
1351 if(Disconnected(wxT("CryptLayer-Settings (Obfuscation) incompatible"))){
1352 Safe_Delete();
1353 return false;
1354 } else {
1355 return true;
1359 // Ipfilter check
1360 uint32 uClientIP = GetIP();
1361 if (uClientIP == 0 && !HasLowID()) {
1362 uClientIP = wxUINT32_SWAP_ALWAYS(m_nUserIDHybrid);
1365 if (uClientIP) {
1366 // Although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
1367 // we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
1368 if (theApp->ipfilter->IsFiltered(uClientIP)) {
1369 AddDebugLogLineM(false, logIPFilter, CFormat(wxT("Filtered ip %u (%s) on TryToConnect\n")) % uClientIP % Uint32toStringIP(uClientIP));
1370 if (Disconnected(wxT("IPFilter"))) {
1371 Safe_Delete();
1372 return false;
1373 } else {
1374 return true;
1378 // for safety: check again whether that IP is banned
1379 if (theApp->clientlist->IsBannedClient(uClientIP)) {
1380 AddDebugLogLineM(false, logClient, wxT("Refused to connect to banned client ") + Uint32toStringIP(uClientIP));
1381 if (Disconnected(wxT("Banned IP"))) {
1382 Safe_Delete();
1383 return false;
1385 return true;
1389 if (GetKadState() == KS_QUEUED_FWCHECK) {
1390 SetKadState(KS_CONNECTING_FWCHECK);
1391 } else if (GetKadState() == KS_QUEUED_FWCHECK_UDP) {
1392 SetKadState(KS_CONNECTING_FWCHECK_UDP);
1395 if ( HasLowID() ) {
1396 if (!theApp->DoCallback(this)) {
1397 //We cannot do a callback!
1398 if (GetDownloadState() == DS_CONNECTING) {
1399 SetDownloadState(DS_LOWTOLOWIP);
1400 } else if (GetDownloadState() == DS_REQHASHSET) {
1401 SetDownloadState(DS_ONQUEUE);
1402 m_reqfile->SetHashSetNeeded(true);
1404 if (GetUploadState() == US_CONNECTING) {
1405 if(Disconnected(wxT("LowID->LowID and US_CONNECTING"))) {
1406 Safe_Delete();
1407 return false;
1410 return true;
1413 //We already know we are not firewalled here as the above condition already detected LowID->LowID and returned.
1414 //If ANYTHING changes with the "if(!theApp->DoCallback(this))" above that will let you fall through
1415 //with the condition that the source is firewalled and we are firewalled, we must
1416 //recheck it before the this check..
1417 if (HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp->serverconnect->IsLocalServer(GetServerIP(), GetServerPort())
1418 && !(SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0)) {
1419 //This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort.
1420 if( Kademlia::CKademlia::IsConnected() ) {
1421 //We are connect to Kad
1422 if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID()))) {
1423 //There are too many source lookups already or we are already searching this key.
1424 SetDownloadState(DS_TOOMANYCONNSKAD);
1425 return true;
1431 if (!m_socket || !m_socket->IsConnected()) {
1432 if (m_socket) {
1433 m_socket->Safe_Delete();
1435 m_socket = new CClientTCPSocket(this, thePrefs::GetProxyData());
1436 } else {
1437 ConnectionEstablished();
1438 return true;
1442 if (HasLowID() && SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0 && GetConnectIP() != 0) { // LOWID with DirectCallback
1443 if (m_dwDirectCallbackTimeout != 0) {
1444 AddDebugLogLineM(false, logClient, wxT("ERROR: Trying Direct UDP Callback while already trying to connect to client ") + GetUserHash().Encode());
1445 return true; // We're already trying a direct connection to this client
1447 // a direct callback is possible - since no other parties are involved and only one additional packet overhead
1448 // is used we basically handle it like a normal connection try, no restrictions apply
1449 // we already check above with !theApp->DoCallback(this) if any callback is possible at all
1450 m_dwDirectCallbackTimeout = ::GetTickCount() + SEC2MS(45);
1451 theApp->clientlist->AddDirectCallbackClient(this);
1452 // TODO LOGREMOVE
1453 AddDebugLogLineM(false, logClient, wxString::Format(wxT("Direct Callback on port %u to client "), GetKadPort()) + GetUserHash().Encode());
1455 CMemFile data;
1456 data.WriteUInt16(thePrefs::GetPort()); // needs to know our port
1457 data.WriteHash(thePrefs::GetUserHash()); // and userhash
1458 // our connection settings
1459 data.WriteUInt8(Kademlia::CPrefs::GetMyConnectOptions(true, false));
1460 AddDebugLogLineM(false, logClientUDP, wxT("Sending OP_DIRECTCALLBACKREQ to ") + Uint32_16toStringIP_Port(GetConnectIP(), GetKadPort()));
1461 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_DIRECTCALLBACKREQ);
1462 theStats::AddUpOverheadOther(packet->GetPacketSize());
1463 theApp->clientudp->SendPacket(packet, GetConnectIP(), GetKadPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0);
1464 } else if (HasLowID()) { // LOWID
1465 if (GetDownloadState() == DS_CONNECTING) {
1466 SetDownloadState(DS_WAITCALLBACK);
1468 if (GetUploadState() == US_CONNECTING) {
1469 if(Disconnected(wxT("LowID and US_CONNECTING"))) {
1470 Safe_Delete();
1471 return false;
1473 return true;
1476 if (theApp->serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)) {
1477 CMemFile data;
1478 // AFAICS, this id must be reversed to be sent to clients
1479 // But if I reverse it, we do a serve violation ;)
1480 data.WriteUInt32(m_nUserIDHybrid);
1481 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_CALLBACKREQUEST);
1482 theStats::AddUpOverheadServer(packet->GetPacketSize());
1483 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CALLBACKREQUEST to ") + GetFullIP());
1484 theApp->serverconnect->SendPacket(packet);
1485 SetDownloadState(DS_WAITCALLBACK);
1486 } else {
1487 if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending)) {
1489 if( !HasValidBuddyID() ) {
1490 theApp->downloadqueue->RemoveSource(this);
1491 if (Disconnected(wxT("LowID and US_NONE and QR=0"))) {
1492 Safe_Delete();
1493 return false;
1495 return true;
1498 if( !Kademlia::CKademlia::IsConnected() ) {
1499 //We are not connected to Kad and this is a Kad Firewalled source..
1500 theApp->downloadqueue->RemoveSource(this);
1501 if(Disconnected(wxT("Kad Firewalled source but not connected to Kad."))) {
1502 Safe_Delete();
1503 return false;
1505 return true;
1508 if( GetDownloadState() == DS_WAITCALLBACK ) {
1509 if( GetBuddyIP() && GetBuddyPort()) {
1510 CMemFile bio(34);
1511 bio.WriteUInt128(Kademlia::CUInt128(GetBuddyID()));
1512 bio.WriteUInt128(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash()));
1513 bio.WriteUInt16(thePrefs::GetPort());
1514 CPacket* packet = new CPacket(bio, OP_KADEMLIAHEADER, KADEMLIA_CALLBACK_REQ);
1515 // eMule FIXME: We dont know which kadversion the buddy has, so we need to send unencrypted
1516 theApp->clientudp->SendPacket(packet, GetBuddyIP(), GetBuddyPort(), false, NULL, true, 0);
1517 AddDebugLogLineM(false,logLocalClient, wxString::Format(wxT("KADEMLIA_CALLBACK_REQ (%i) to"),packet->GetPacketSize()) + GetFullIP());
1518 theStats::AddUpOverheadKad(packet->GetRealPacketSize());
1519 SetDownloadState(DS_WAITCALLBACKKAD);
1520 } else {
1521 AddLogLineN(_("Searching buddy for lowid connection"));
1522 //Create search to find buddy.
1523 Kademlia::CSearch *findSource = new Kademlia::CSearch;
1524 findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE);
1525 findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
1526 findSource->AddFileID(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash()));
1527 if(Kademlia::CSearchManager::StartSearch(findSource)) {
1528 //Started lookup..
1529 SetDownloadState(DS_WAITCALLBACKKAD);
1530 } else {
1531 //This should never happen..
1532 wxASSERT(0);
1536 } else {
1537 if (GetDownloadState() == DS_WAITCALLBACK) {
1538 m_bReaskPending = true;
1539 SetDownloadState(DS_ONQUEUE);
1543 } else { // HIGHID
1544 if (!Connect()) {
1545 return false;
1548 return true;
1551 bool CUpDownClient::Connect()
1553 m_hasbeenobfuscatinglately = false;
1555 if (!m_socket->IsOk()) {
1556 // Enable or disable crypting based on our and the remote clients preference
1557 if (HasValidHash() && SupportsCryptLayer() && thePrefs::IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested())){
1558 m_socket->SetConnectionEncryption(true, GetUserHash().GetHash(), false);
1559 } else {
1560 m_socket->SetConnectionEncryption(false, NULL, false);
1562 amuleIPV4Address tmp;
1563 tmp.Hostname(GetConnectIP());
1564 tmp.Service(GetUserPort());
1565 AddDebugLogLineM(false, logClient, wxT("Trying to connect to ") + Uint32_16toStringIP_Port(GetConnectIP(),GetUserPort()));
1566 m_socket->Connect(tmp, false);
1567 // We should send hello packets AFTER connecting!
1568 // so I moved it to OnConnect
1569 return true;
1570 } else {
1571 return false;
1575 void CUpDownClient::ConnectionEstablished()
1578 /* Kry - First thing, check if this client was just used to retrieve
1579 info. That's some debug thing for myself... check connection_reason
1580 definition */
1582 m_hasbeenobfuscatinglately = (m_socket && m_socket->IsConnected() && m_socket->IsObfusicating());
1584 #ifdef __DEBUG__
1585 if (!connection_reason.IsEmpty()) {
1586 AddLogLineN(CFormat(wxT("Got client info checking for %s: %s\nDisconnecting and deleting.")) % connection_reason % GetClientFullInfo());
1587 connection_reason.Clear(); // So we don't re-print on destructor.
1588 Safe_Delete();
1589 return;
1591 #endif
1593 // Check if we should use this client to retrieve our public IP
1594 // Ignore local ip on GetPublicIP (could be wrong)
1595 if (theApp->GetPublicIP(true) == 0 && theApp->IsConnectedED2K()) {
1596 SendPublicIPRequest();
1599 // was this a direct callback?
1600 if (m_dwDirectCallbackTimeout != 0){
1601 theApp->clientlist->RemoveDirectCallback(this);
1602 m_dwDirectCallbackTimeout = 0;
1603 // TODO LOGREMOVE
1604 AddDebugLogLineM(false, logClient, wxT("Direct Callback succeeded, connection established to ") + GetUserHash().Encode());
1607 switch (GetKadState()) {
1608 case KS_CONNECTING_FWCHECK:
1609 SetKadState(KS_CONNECTED_FWCHECK);
1610 break;
1611 case KS_CONNECTING_BUDDY:
1612 case KS_INCOMING_BUDDY:
1613 SetKadState(KS_CONNECTED_BUDDY);
1614 break;
1615 case KS_CONNECTING_FWCHECK_UDP:
1616 SetKadState(KS_FWCHECK_UDP);
1617 SendFirewallCheckUDPRequest();
1618 break;
1619 default:
1620 break;
1623 // ok we have a connection, lets see if we want anything from this client
1624 if (GetChatState() == MS_CONNECTING) {
1625 SetChatState( MS_CHATTING );
1628 if (GetChatState() == MS_CHATTING) {
1629 bool result = true;
1630 if (!m_pendingMessage.IsEmpty()) {
1631 result = SendMessage(m_pendingMessage);
1633 Notify_ChatConnResult(result,GUI_ID(GetIP(),GetUserPort()),m_pendingMessage);
1634 m_pendingMessage.Clear();
1637 switch(GetDownloadState()) {
1638 case DS_CONNECTING:
1639 case DS_WAITCALLBACK:
1640 case DS_WAITCALLBACKKAD:
1641 m_bReaskPending = false;
1642 SetDownloadState(DS_CONNECTED);
1643 SendFileRequest();
1645 if (m_bReaskPending){
1646 m_bReaskPending = false;
1647 if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING) {
1648 SetDownloadState(DS_CONNECTED);
1649 SendFileRequest();
1652 switch(GetUploadState()){
1653 case US_CONNECTING:
1654 case US_WAITCALLBACK:
1655 if (theApp->uploadqueue->IsDownloading(this)) {
1656 SetUploadState(US_UPLOADING);
1657 CPacket* packet = new CPacket(OP_ACCEPTUPLOADREQ, 0, OP_EDONKEYPROT);
1658 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1659 SendPacket(packet,true);
1660 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + GetFullIP() );
1663 if (m_iFileListRequested == 1) {
1664 CPacket* packet = new CPacket(m_fSharedDirectories ? OP_ASKSHAREDDIRS : OP_ASKSHAREDFILES, 0, OP_EDONKEYPROT);
1665 theStats::AddUpOverheadOther(packet->GetPacketSize());
1666 SendPacket(packet,true,true);
1667 if (m_fSharedDirectories) {
1668 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRS to ") + GetFullIP() );
1669 } else {
1670 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILES to ") + GetFullIP() );
1674 while (!m_WaitingPackets_list.empty()) {
1675 CPacket* packet = m_WaitingPackets_list.front();
1676 m_WaitingPackets_list.pop_front();
1678 SendPacket(packet);
1683 int CUpDownClient::GetHashType() const
1685 if ( m_UserHash[5] == 13 && m_UserHash[14] == 110 ) {
1686 return SO_OLDEMULE;
1689 if ( m_UserHash[5] == 14 && m_UserHash[14] == 111 ) {
1690 return SO_EMULE;
1693 if ( m_UserHash[5] == 'M' && m_UserHash[14] == 'L' ) {
1694 return SO_MLDONKEY;
1697 return SO_UNKNOWN;
1701 void CUpDownClient::SetSocket(CClientTCPSocket* socket)
1703 #if defined(__DEBUG__) && !defined(EC_REMOTE)
1704 if (m_socket == NULL && socket != NULL) {
1705 theStats::SocketAssignedToClient();
1706 } else if (m_socket != NULL && socket == NULL) {
1707 theStats::SocketUnassignedFromClient();
1709 #endif
1710 m_socket = socket;
1714 void CUpDownClient::ReGetClientSoft()
1716 if (m_Username.IsEmpty()) {
1717 m_clientSoft=SO_UNKNOWN;
1718 m_clientVerString = m_clientSoftString = m_clientVersionString = m_fullClientVerString = _("Unknown");
1719 UpdateStats();
1720 return;
1723 int iHashType = GetHashType();
1724 wxString clientModString;
1725 if (iHashType == SO_EMULE) {
1727 m_clientSoft = m_byCompatibleClient;
1728 m_clientSoftString = GetSoftName(m_clientSoft);
1729 // Special issues:
1730 if(!GetClientModString().IsEmpty() && (m_clientSoft != SO_EMULE)) {
1731 m_clientSoftString = GetClientModString();
1733 // Isn't xMule annoying?
1734 if ((m_clientSoft == SO_LXMULE) && (GetMuleVersion() > 0x26) && (GetMuleVersion() != 0x99)) {
1735 m_clientSoftString += wxString::Format(_(" (Fake eMule version %#x)"),GetMuleVersion());
1737 if ((m_clientSoft == SO_EMULE) &&
1739 wxString(GetClientModString()).MakeLower().Find(wxT("xmule")) != -1
1740 || GetUserName().Find(wxT("xmule.")) != -1
1743 // FAKE eMule -a newer xMule faking is ident.
1744 m_clientSoft = SO_LXMULE;
1745 if (GetClientModString().IsEmpty() == false) {
1746 m_clientSoftString = GetClientModString() + _(" (Fake eMule)");
1747 } else {
1748 m_clientSoftString = _("xMule (Fake eMule)"); // don't use GetSoftName, it's not lmule.
1751 // Now, what if we don't know this SO_ID?
1752 if (m_clientSoftString.IsEmpty()) {
1753 if(m_bIsML) {
1754 m_clientSoft = SO_MLDONKEY;
1755 m_clientSoftString = GetSoftName(m_clientSoft);
1756 } else if (m_bIsHybrid) {
1757 m_clientSoft = SO_EDONKEYHYBRID;
1758 m_clientSoftString = GetSoftName(m_clientSoft);
1759 } else if (m_byCompatibleClient != 0) {
1760 m_clientSoft = SO_COMPAT_UNK;
1761 #ifdef __DEBUG__
1762 if (
1763 // Exceptions:
1764 (m_byCompatibleClient != 0xf0) // Chinese leech mod
1765 && (1==1) // Your ad here
1767 AddLogLineNS(CFormat(wxT("Compatible client found with ET_COMPATIBLECLIENT of %x")) % m_byCompatibleClient);
1769 #endif
1770 m_clientSoftString = GetSoftName(m_clientSoft) + wxString::Format(wxT("(%#x)"),m_byCompatibleClient);
1771 } else {
1772 // If we step here, it might mean 2 things:
1773 // a eMule
1774 // a Compat Client that has sent no MuleInfo packet yet.
1775 m_clientSoft = SO_EMULE;
1776 m_clientSoftString = wxT("eMule");
1780 if (m_byEmuleVersion == 0) {
1781 m_nClientVersion = MAKE_CLIENT_VERSION(0,0,0);
1782 } else if (m_byEmuleVersion != 0x99) {
1783 uint32 nClientMinVersion = (m_byEmuleVersion >> 4)*10 + (m_byEmuleVersion & 0x0f);
1784 m_nClientVersion = MAKE_CLIENT_VERSION(0,nClientMinVersion,0);
1785 switch (m_clientSoft) {
1786 case SO_AMULE:
1787 m_clientVerString = wxString::Format(_("1.x (based on eMule v0.%u)"), nClientMinVersion);
1788 break;
1789 case SO_LPHANT:
1790 m_clientVerString = wxT("< v0.05");
1791 break;
1792 default:
1793 clientModString = GetClientModString();
1794 m_clientVerString = wxString::Format(wxT("v0.%u"), nClientMinVersion);
1795 break;
1797 } else {
1798 uint32 nClientMajVersion = (m_nClientVersion >> 17) & 0x7f;
1799 uint32 nClientMinVersion = (m_nClientVersion >> 10) & 0x7f;
1800 uint32 nClientUpVersion = (m_nClientVersion >> 7) & 0x07;
1802 m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
1804 switch (m_clientSoft) {
1805 case SO_AMULE:
1806 case SO_LXMULE:
1807 case SO_HYDRANODE:
1808 // Kry - xMule started sending correct version tags on 1.9.1b.
1809 // It only took them 4 months, and being told by me and the
1810 // eMule+ developers, so I think they're slowly getting smarter.
1811 // They are based on our implementation, so we use the same format
1812 // for the version string.
1813 m_clientVerString = wxString::Format(wxT("v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
1814 break;
1815 case SO_LPHANT:
1816 m_clientVerString = wxString::Format(wxT(" v%u.%.2u%c"), nClientMajVersion-1, nClientMinVersion, 'a' + nClientUpVersion);
1817 break;
1818 case SO_EMULEPLUS:
1819 m_clientVerString = wxString::Format(wxT("v%u"), nClientMajVersion);
1820 if(nClientMinVersion != 0) {
1821 m_clientVerString += wxString::Format(wxT(".%u"), nClientMinVersion);
1823 if(nClientUpVersion != 0) {
1824 m_clientVerString += wxString::Format(wxT("%c"), 'a' + nClientUpVersion - 1);
1826 break;
1827 default:
1828 clientModString = GetClientModString();
1829 m_clientVerString = wxString::Format(wxT("v%u.%u%c"), nClientMajVersion, nClientMinVersion, 'a' + nClientUpVersion);
1830 break;
1833 } else if (m_bIsHybrid) {
1834 // seen:
1835 // 105010 50.10
1836 // 10501 50.1
1837 // 1051 51.0
1838 // 501 50.1
1840 m_clientSoft = SO_EDONKEYHYBRID;
1841 m_clientSoftString = GetSoftName(m_clientSoft);
1843 uint32 nClientMajVersion;
1844 uint32 nClientMinVersion;
1845 uint32 nClientUpVersion;
1846 if (m_nClientVersion > 100000) {
1847 uint32 uMaj = m_nClientVersion/100000;
1848 nClientMajVersion = uMaj - 1;
1849 nClientMinVersion = (m_nClientVersion - uMaj*100000) / 100;
1850 nClientUpVersion = m_nClientVersion % 100;
1852 else if (m_nClientVersion > 10000) {
1853 uint32 uMaj = m_nClientVersion/10000;
1854 nClientMajVersion = uMaj - 1;
1855 nClientMinVersion = (m_nClientVersion - uMaj*10000) / 10;
1856 nClientUpVersion = m_nClientVersion % 10;
1858 else if (m_nClientVersion > 1000) {
1859 uint32 uMaj = m_nClientVersion/1000;
1860 nClientMajVersion = uMaj - 1;
1861 nClientMinVersion = m_nClientVersion - uMaj*1000;
1862 nClientUpVersion = 0;
1864 else if (m_nClientVersion > 100) {
1865 uint32 uMin = m_nClientVersion/10;
1866 nClientMajVersion = 0;
1867 nClientMinVersion = uMin;
1868 nClientUpVersion = m_nClientVersion - uMin*10;
1870 else{
1871 nClientMajVersion = 0;
1872 nClientMinVersion = m_nClientVersion;
1873 nClientUpVersion = 0;
1875 m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
1876 if (nClientUpVersion) {
1877 m_clientVerString = wxString::Format(wxT("v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
1878 } else {
1879 m_clientVerString = wxString::Format(wxT("v%u.%u"), nClientMajVersion, nClientMinVersion);
1881 } else if (m_bIsML || (iHashType == SO_MLDONKEY)) {
1882 m_clientSoft = SO_MLDONKEY;
1883 m_clientSoftString = GetSoftName(m_clientSoft);
1884 uint32 nClientMinVersion = m_nClientVersion;
1885 m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
1886 m_clientVerString = wxString::Format(wxT("v0.%u"), nClientMinVersion);
1887 } else if (iHashType == SO_OLDEMULE) {
1888 m_clientSoft = SO_OLDEMULE;
1889 m_clientSoftString = GetSoftName(m_clientSoft);
1890 uint32 nClientMinVersion = m_nClientVersion;
1891 m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
1892 m_clientVerString = wxString::Format(wxT("v0.%u"), nClientMinVersion);
1893 } else {
1894 m_clientSoft = SO_EDONKEY;
1895 m_clientSoftString = GetSoftName(m_clientSoft);
1896 m_nClientVersion *= 10;
1897 m_clientVerString = wxString::Format(wxT("v%u.%u"), m_nClientVersion / 100000, (m_nClientVersion / 1000) % 100);
1900 m_clientVersionString = m_clientVerString;
1901 if (!clientModString.IsEmpty()) {
1902 m_clientVerString += wxT(" - ") + clientModString;
1904 m_fullClientVerString = m_clientSoftString + wxT(" ") + m_clientVerString;
1906 UpdateStats();
1909 void CUpDownClient::RequestSharedFileList()
1911 if (m_iFileListRequested == 0) {
1912 AddDebugLogLineM( false, logClient, wxString( wxT("Requesting shared files from ") ) + GetUserName() );
1913 m_iFileListRequested = 1;
1914 TryToConnect(true);
1915 } else {
1916 AddDebugLogLineM( false, logClient, CFormat( wxT("Requesting shared files from user %s (%u) is already in progress") ) % GetUserName() % GetUserIDHybrid() );
1921 void CUpDownClient::ProcessSharedFileList(const byte* pachPacket, uint32 nSize, wxString& pszDirectory)
1923 if (m_iFileListRequested > 0) {
1924 m_iFileListRequested--;
1925 theApp->searchlist->ProcessSharedFileList(pachPacket, nSize, this, NULL, pszDirectory);
1930 void CUpDownClient::ResetFileStatusInfo()
1932 m_nPartCount = 0;
1934 if ( m_reqfile ) {
1935 m_reqfile->UpdatePartsFrequency( this, false );
1937 m_downPartStatus.clear();
1939 m_clientFilename.Clear();
1941 m_bCompleteSource = false;
1942 m_dwLastAskedTime = 0;
1943 m_iRating = 0;
1944 m_strComment.Clear();
1946 if (m_pReqFileAICHHash != NULL) {
1947 delete m_pReqFileAICHHash;
1948 m_pReqFileAICHHash = NULL;
1953 wxString CUpDownClient::GetUploadFileInfo()
1955 // build info text and display it
1956 wxString sRet;
1957 sRet = (CFormat(_("NickName: %s ID: %u")) % GetUserName() % GetUserIDHybrid()) + wxT(" ");
1958 if (m_reqfile) {
1959 sRet += CFormat(_("Requested: %s\n")) % m_reqfile->GetFileName();
1960 sRet += CFormat(
1961 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())
1962 ) % m_reqfile->statistic.GetAccepts() % m_reqfile->statistic.GetRequests() % CastItoXBytes(m_reqfile->statistic.GetTransferred());
1963 sRet += CFormat(
1964 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())
1965 ) % m_reqfile->statistic.GetAllTimeAccepts() % m_reqfile->statistic.GetAllTimeRequests() % CastItoXBytes(m_reqfile->statistic.GetAllTimeTransferred());
1966 } else {
1967 sRet += _("Requested unknown file");
1969 return sRet;
1972 // sends a packet, if needed it will establish a connection before
1973 // options used: ignore max connections, control packet, delete packet
1974 // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails
1975 bool CUpDownClient::SafeSendPacket(CPacket* packet)
1977 if (IsConnected()) {
1978 SendPacket(packet, true);
1979 return true;
1980 } else {
1981 m_WaitingPackets_list.push_back(packet);
1982 return TryToConnect(true);
1986 void CUpDownClient::SendPublicKeyPacket(){
1987 // send our public key to the client who requested it
1988 if (m_socket == NULL || credits == NULL || m_SecureIdentState != IS_KEYANDSIGNEEDED){
1989 wxASSERT ( false );
1990 return;
1992 if (!theApp->CryptoAvailable())
1993 return;
1995 CMemFile data;
1996 data.WriteUInt8(theApp->clientcredits->GetPubKeyLen());
1997 data.Write(theApp->clientcredits->GetPublicKey(), theApp->clientcredits->GetPubKeyLen());
1998 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_PUBLICKEY);
2000 theStats::AddUpOverheadOther(packet->GetPacketSize());
2001 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICKEY to ") + GetFullIP() );
2002 SendPacket(packet,true,true);
2003 m_SecureIdentState = IS_SIGNATURENEEDED;
2007 void CUpDownClient::SendSignaturePacket(){
2008 // signate the public key of this client and send it
2009 if (m_socket == NULL || credits == NULL || m_SecureIdentState == 0){
2010 wxASSERT ( false );
2011 return;
2014 if (!theApp->CryptoAvailable()) {
2015 return;
2017 if (credits->GetSecIDKeyLen() == 0) {
2018 return; // We don't have his public key yet, will be back here later
2020 // do we have a challenge value received (actually we should if we are in this function)
2021 if (credits->m_dwCryptRndChallengeFrom == 0){
2022 AddDebugLogLineM( false, logClient, wxString(wxT("Want to send signature but challenge value is invalid - User ")) + GetUserName());
2023 return;
2025 // v2
2026 // we will use v1 as default, except if only v2 is supported
2027 bool bUseV2;
2028 if ( (m_bySupportSecIdent&1) == 1 )
2029 bUseV2 = false;
2030 else
2031 bUseV2 = true;
2033 uint8 byChaIPKind = 0;
2034 uint32 ChallengeIP = 0;
2035 if (bUseV2){
2036 if (::IsLowID(theApp->GetED2KID())) {
2037 // we cannot do not know for sure our public ip, so use the remote clients one
2038 ChallengeIP = GetIP();
2039 byChaIPKind = CRYPT_CIP_REMOTECLIENT;
2040 } else {
2041 ChallengeIP = theApp->GetED2KID();
2042 byChaIPKind = CRYPT_CIP_LOCALCLIENT;
2045 //end v2
2046 byte achBuffer[250];
2048 uint8 siglen = theApp->clientcredits->CreateSignature(credits, achBuffer, 250, ChallengeIP, byChaIPKind );
2049 if (siglen == 0){
2050 wxASSERT ( false );
2051 return;
2053 CMemFile data;
2054 data.WriteUInt8(siglen);
2055 data.Write(achBuffer, siglen);
2056 if (bUseV2) {
2057 data.WriteUInt8(byChaIPKind);
2060 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SIGNATURE);
2062 theStats::AddUpOverheadOther(packet->GetPacketSize());
2063 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_SIGNATURE to ") + GetFullIP() );
2064 SendPacket(packet,true,true);
2065 m_SecureIdentState = IS_ALLREQUESTSSEND;
2069 void CUpDownClient::ProcessPublicKeyPacket(const byte* pachPacket, uint32 nSize)
2071 theApp->clientlist->AddTrackClient(this);
2073 if (m_socket == NULL || credits == NULL || pachPacket[0] != nSize-1
2074 || nSize == 0 || nSize > 250){
2075 wxASSERT ( false );
2076 return;
2078 if (!theApp->CryptoAvailable())
2079 return;
2080 // the function will handle everything (mulitple key etc)
2081 if (credits->SetSecureIdent(pachPacket+1, pachPacket[0])){
2082 // if this client wants a signature, now we can send him one
2083 if (m_SecureIdentState == IS_SIGNATURENEEDED){
2084 SendSignaturePacket();
2086 else if(m_SecureIdentState == IS_KEYANDSIGNEEDED){
2087 // something is wrong
2088 AddDebugLogLineM( false, logClient, wxT("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket") );
2090 } else{
2091 AddDebugLogLineM( false, logClient, wxT("Failed to use new received public key") );
2096 void CUpDownClient::ProcessSignaturePacket(const byte* pachPacket, uint32 nSize)
2098 // here we spread the good guys from the bad ones ;)
2100 if (m_socket == NULL || credits == NULL || nSize == 0 || nSize > 250){
2101 wxASSERT ( false );
2102 return;
2105 uint8 byChaIPKind;
2106 if (pachPacket[0] == nSize-1)
2107 byChaIPKind = 0;
2108 else if (pachPacket[0] == nSize-2 && (m_bySupportSecIdent & 2) > 0) //v2
2109 byChaIPKind = pachPacket[nSize-1];
2110 else{
2111 wxASSERT ( false );
2112 return;
2115 if (!theApp->CryptoAvailable())
2116 return;
2118 // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
2119 if (m_dwLastSignatureIP == GetIP()){
2120 AddDebugLogLineM( false, logClient, wxT("received multiple signatures from one client") );
2121 return;
2123 // also make sure this client has a public key
2124 if (credits->GetSecIDKeyLen() == 0){
2125 AddDebugLogLineM( false, logClient, wxT("received signature for client without public key") );
2126 return;
2128 // and one more check: did we ask for a signature and sent a challange packet?
2129 if (credits->m_dwCryptRndChallengeFor == 0){
2130 AddDebugLogLineM( false, logClient, wxT("received signature for client with invalid challenge value - User ") + GetUserName() );
2131 return;
2134 if (theApp->clientcredits->VerifyIdent(credits, pachPacket+1, pachPacket[0], GetIP(), byChaIPKind ) ){
2135 // result is saved in function above
2136 AddDebugLogLineM( false, logClient, CFormat( wxT("'%s' has passed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind );
2137 } else {
2138 AddDebugLogLineM( false, logClient, CFormat( wxT("'%s' has failed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind );
2141 m_dwLastSignatureIP = GetIP();
2144 void CUpDownClient::SendSecIdentStatePacket(){
2145 // check if we need public key and signature
2146 uint8 nValue = 0;
2147 if (credits){
2148 if (theApp->CryptoAvailable()){
2149 if (credits->GetSecIDKeyLen() == 0) {
2150 nValue = IS_KEYANDSIGNEEDED;
2151 } else if (m_dwLastSignatureIP != GetIP()) {
2152 nValue = IS_SIGNATURENEEDED;
2155 if (nValue == 0){
2156 AddDebugLogLineM( false, logClient, wxT("Not sending SecIdentState Packet, because State is Zero") );
2157 return;
2159 // crypt: send random data to sign
2160 uint32 dwRandom = rand()+1;
2161 credits->m_dwCryptRndChallengeFor = dwRandom;
2163 CMemFile data;
2164 data.WriteUInt8(nValue);
2165 data.WriteUInt32(dwRandom);
2166 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SECIDENTSTATE);
2168 theStats::AddUpOverheadOther(packet->GetPacketSize());
2169 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_SECIDENTSTATE to ") + GetFullIP() );
2170 SendPacket(packet,true,true);
2171 } else {
2172 wxASSERT ( false );
2177 void CUpDownClient::ProcessSecIdentStatePacket(const byte* pachPacket, uint32 nSize)
2179 if ( nSize != 5 ) {
2180 return;
2183 if ( !credits ) {
2184 wxASSERT( credits );
2185 return;
2188 CMemFile data(pachPacket,nSize);
2190 switch ( data.ReadUInt8() ) {
2191 case 0:
2192 m_SecureIdentState = IS_UNAVAILABLE;
2193 break;
2194 case 1:
2195 m_SecureIdentState = IS_SIGNATURENEEDED;
2196 break;
2197 case 2:
2198 m_SecureIdentState = IS_KEYANDSIGNEEDED;
2199 break;
2200 default:
2201 return;
2204 credits->m_dwCryptRndChallengeFrom = data.ReadUInt32();
2208 void CUpDownClient::InfoPacketsReceived()
2210 // indicates that both Information Packets has been received
2211 // needed for actions, which process data from both packets
2212 wxASSERT ( m_byInfopacketsReceived == IP_BOTH );
2213 m_byInfopacketsReceived = IP_NONE;
2215 if (m_bySupportSecIdent){
2216 SendSecIdentStatePacket();
2221 bool CUpDownClient::CheckHandshakeFinished(uint32 WXUNUSED(protocol), uint32 WXUNUSED(opcode)) const
2223 if (m_bHelloAnswerPending){
2224 // this triggers way too often.. need more time to look at this -> only create a warning
2225 AddDebugLogLineM( false, logClient, wxT("Handshake not finished while processing packet.") );
2226 return false;
2229 return true;
2233 wxString CUpDownClient::GetClientFullInfo()
2236 if (m_clientVerString.IsEmpty()) {
2237 ReGetClientSoft();
2240 return CFormat( _("Client %s on IP:Port %s:%d using %s %s %s") )
2241 % ( m_Username.IsEmpty() ? wxString(_("Unknown")) : m_Username )
2242 % GetFullIP()
2243 % GetUserPort()
2244 % m_clientSoftString
2245 % m_clientVerString
2246 % m_strModVersion;
2251 void CUpDownClient::SendPublicIPRequest(){
2252 if (IsConnected()){
2253 CPacket* packet = new CPacket(OP_PUBLICIP_REQ,0,OP_EMULEPROT);
2254 theStats::AddUpOverheadOther(packet->GetPacketSize());
2255 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICIP_REQ to") + GetFullIP());
2256 SendPacket(packet,true);
2257 m_fNeedOurPublicIP = true;
2261 void CUpDownClient::ProcessPublicIPAnswer(const byte* pbyData, uint32 uSize){
2262 if (uSize != 4) {
2263 throw wxString(wxT("Wrong Packet size on Public IP answer"));
2265 uint32 dwIP = PeekUInt32(pbyData);
2266 if (m_fNeedOurPublicIP == true){ // did we?
2267 m_fNeedOurPublicIP = false;
2268 // Ignore local ip on GetPublicIP (could be wrong)
2269 if (theApp->GetPublicIP(true) == 0 && !IsLowID(dwIP) ) {
2270 theApp->SetPublicIP(dwIP);
2276 bool CUpDownClient::IsConnected() const
2278 return m_socket && m_socket->IsConnected();
2281 bool CUpDownClient::SendPacket(CPacket* packet, bool delpacket, bool controlpacket)
2283 if ( m_socket ) {
2284 m_socket->SendPacket(packet, delpacket, controlpacket );
2285 return true;
2286 } else {
2287 AddLogLineN(wxT("CAUGHT DEAD SOCKET IN SENDPACKET()"));
2288 return false;
2292 float CUpDownClient::SetDownloadLimit(uint32 reducedownload)
2295 // lfroen: in daemon it actually can happen
2296 wxASSERT( m_socket );
2298 float kBpsClient = CalculateKBpsDown();
2300 if ( m_socket ) {
2302 if (reducedownload) {
2303 // (% to reduce * current speed) / 100 and THEN, / 10 because this
2304 // gets called 10 times per second.
2305 uint32 limit = (uint32)(((float)reducedownload*(kBpsClient*1024.0))/1000);
2307 if(limit<1024 && reducedownload >= 200) {
2308 // If we're going up and this download is < 1kB,
2309 // we want it to go up fast. Can be reduced later,
2310 // and it'll probably be in a more fair way with
2311 // other downloads that are faster.
2312 limit +=1024;
2313 } else if(limit == 0) {
2314 // This download is not transferring yet... make it
2315 // 1024 so we don't fill the TCP stack and lose the
2316 // connection.
2317 limit = 1024;
2320 m_socket->SetDownloadLimit(limit);
2321 } else {
2322 m_socket->DisableDownloadLimit();
2325 } else {
2326 AddLogLineNS(CFormat(wxT("CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f")) % kBpsClient);
2329 return kBpsClient;
2333 void CUpDownClient::SetUserIDHybrid(uint32 nUserID)
2335 theApp->clientlist->UpdateClientID( this, nUserID );
2337 m_nUserIDHybrid = nUserID;
2341 void CUpDownClient::SetIP( uint32 val )
2343 theApp->clientlist->UpdateClientIP( this, val );
2345 m_dwUserIP = val;
2347 m_nConnectIP = val;
2349 m_FullUserIP = val;
2353 void CUpDownClient::SetUserHash(const CMD4Hash& userhash)
2355 theApp->clientlist->UpdateClientHash( this, userhash );
2357 m_UserHash = userhash;
2359 ValidateHash();
2362 EUtf8Str CUpDownClient::GetUnicodeSupport() const
2364 return m_bUnicodeSupport ? utf8strRaw : utf8strNone;
2368 uint8 CUpDownClient::GetSecureIdentState() {
2369 if (m_SecureIdentState != IS_UNAVAILABLE) {
2370 if (!SecIdentSupRec) {
2371 // This can be caused by a 0.30x based client which sends the old
2372 // style Hello packet, and the mule info packet, but between them they
2373 // send a secure ident state packet (after a hello but before we have
2374 // the SUI capabilities). This is a misbehaving client, and somehow I
2375 // Feel like ti should be dropped. But then again, it won't harm to use
2376 // this SUI state if they are reporting no SUI (won't be used) and if
2377 // they report using SUI on the mule info packet, it's ok to use it.
2379 AddDebugLogLineM(false, logClient, wxT("A client sent secure ident state before telling us the SUI capabilities"));
2380 AddDebugLogLineM(false, logClient, wxT("Client info: ") + GetClientFullInfo());
2381 AddDebugLogLineM(false, logClient, wxT("This client won't be disconnected, but it should be. :P"));
2385 return m_SecureIdentState;
2389 bool CUpDownClient::SendMessage(const wxString& message)
2391 // Already connecting?
2392 if (GetChatState() == MS_CONNECTING) {
2393 // Queue all messages till we're able to send them (or discard them)
2394 if (!m_pendingMessage.IsEmpty()) {
2395 m_pendingMessage += wxT("\n");
2396 } else {
2397 // There must be a message to send
2398 wxASSERT(0);
2400 m_pendingMessage += message;
2401 return false;
2403 if (IsConnected()) {
2404 CMemFile data;
2405 data.WriteString(message, GetUnicodeSupport());
2406 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_MESSAGE);
2407 theStats::AddUpOverheadOther(packet->GetPacketSize());
2408 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_MESSAGE to ") + GetFullIP());
2409 SendPacket(packet, true, true);
2410 return true;
2411 } else {
2412 m_pendingMessage = message;
2413 SetChatState(MS_CONNECTING);
2414 // True to ignore "Too Many Connections"
2415 TryToConnect(true);
2416 return false;
2420 /* Kad stuff */
2422 void CUpDownClient::SetBuddyID(const byte* pucBuddyID)
2424 if( pucBuddyID == NULL ){
2425 md4clr(m_achBuddyID);
2426 m_bBuddyIDValid = false;
2427 return;
2429 m_bBuddyIDValid = true;
2430 md4cpy(m_achBuddyID, pucBuddyID);
2433 // Kad added by me
2435 bool CUpDownClient::SendBuddyPing() {
2436 SetLastBuddyPingPongTime();
2437 CPacket* buddyPing = new CPacket(OP_BUDDYPING, 0, OP_EMULEPROT);
2438 theStats::AddUpOverheadKad(buddyPing->GetPacketSize());
2439 AddDebugLogLineM(false, logLocalClient,wxT("Local Client: OP_BUDDYPING to ") + GetFullIP());
2440 return SafeSendPacket(buddyPing);
2444 /* Statistics */
2446 void CUpDownClient::UpdateStats()
2448 if (m_lastClientSoft != m_clientSoft || m_lastClientVersion != m_nClientVersion || m_lastOSInfo != m_sClientOSInfo) {
2449 if (m_lastClientSoft == SO_UNKNOWN) {
2450 theStats::RemoveUnknownClient();
2451 } else if (m_lastClientSoft != (uint32)(-1)) {
2452 theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo);
2455 m_lastClientSoft = m_clientSoft;
2456 m_lastClientVersion = m_nClientVersion;
2457 m_lastOSInfo = m_sClientOSInfo;
2459 if (m_clientSoft == SO_UNKNOWN) {
2460 theStats::AddUnknownClient();
2461 } else {
2462 theStats::AddKnownClient(this);
2467 bool CUpDownClient::IsIdentified() const
2469 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED);
2472 bool CUpDownClient::IsBadGuy() const
2474 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY);
2477 bool CUpDownClient::SUIFailed() const
2479 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDFAILED);
2482 bool CUpDownClient::SUINeeded() const
2484 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDNEEDED);
2487 bool CUpDownClient::SUINotSupported() const
2489 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_NOTAVAILABLE);
2492 uint64 CUpDownClient::GetDownloadedTotal() const
2494 return credits ? credits->GetDownloadedTotal() : 0;
2497 uint64 CUpDownClient::GetUploadedTotal() const
2499 return credits ? credits->GetUploadedTotal() : 0;
2502 double CUpDownClient::GetScoreRatio() const {
2503 return credits ? credits->GetScoreRatio(GetIP(), theApp->CryptoAvailable()) : 0;
2506 const wxString CUpDownClient::GetServerName() const
2508 wxString ret;
2509 wxString srvaddr = Uint32toStringIP(GetServerIP());
2510 CServer* cserver = theApp->serverlist->GetServerByAddress(
2511 srvaddr, GetServerPort());
2512 if (cserver) {
2513 ret = cserver->GetListName();
2514 } else {
2515 ret = _("Unknown");
2518 return ret;
2521 bool CUpDownClient::ShouldReceiveCryptUDPPackets() const {
2522 return (thePrefs::IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp->GetPublicIP() != 0
2523 && HasValidHash() && (thePrefs::IsClientCryptLayerRequested() || RequestsCryptLayer()) );
2526 void CUpDownClient::SendFirewallCheckUDPRequest()
2528 wxASSERT(GetKadState() == KS_FWCHECK_UDP);
2530 if (!Kademlia::CKademlia::IsRunning()) {
2531 SetKadState(KS_NONE);
2532 return;
2533 } else if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE || GetKadVersion() <= 5 || GetKadPort() == 0) {
2534 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetIP()), 0); // inform the tester that this test was cancelled
2535 SetKadState(KS_NONE);
2536 return;
2539 wxASSERT(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0);
2540 CMemFile data;
2541 data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetInternKadPort());
2542 data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort());
2543 data.WriteUInt32(Kademlia::CKademlia::GetPrefs()->GetUDPVerifyKey(GetConnectIP()));
2544 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_FWCHECKUDPREQ);
2545 theStats::AddUpOverheadKad(packet->GetPacketSize());
2546 SafeSendPacket(packet);
2549 void CUpDownClient::ProcessFirewallCheckUDPRequest(CMemFile* data)
2551 if (!Kademlia::CKademlia::IsRunning() || Kademlia::CKademlia::GetUDPListener() == NULL) {
2552 //DebugLogWarning(_T("Ignored Kad Firewallrequest UDP because Kad is not running (%s)"), DbgGetClientInfo());
2553 return;
2556 // first search if we know this IP already, if so the result might be biased and we need tell the requester
2557 bool errorAlreadyKnown = false;
2558 if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE) {
2559 errorAlreadyKnown = true;
2560 } else if (Kademlia::CKademlia::GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0, false) != NULL) {
2561 errorAlreadyKnown = true;
2564 uint16_t remoteInternPort = data->ReadUInt16();
2565 uint16_t remoteExternPort = data->ReadUInt16();
2566 uint32_t senderKey = data->ReadUInt32();
2567 if (remoteInternPort == 0) {
2568 //DebugLogError(_T("UDP Firewallcheck requested with Intern Port == 0 (%s)"), DbgGetClientInfo());
2569 return;
2571 // if (senderKey == 0)
2572 // DebugLogWarning(_T("UDP Firewallcheck requested with SenderKey == 0 (%s)"), DbgGetClientInfo());
2574 CMemFile testPacket1;
2575 testPacket1.WriteUInt8(errorAlreadyKnown ? 1 : 0);
2576 testPacket1.WriteUInt16(remoteInternPort);
2577 DebugSend(Kad2FirewallUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort);
2578 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket1, KADEMLIA2_FIREWALLUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort, Kademlia::CKadUDPKey(senderKey, theApp->GetPublicIP(false)), NULL);
2580 // if the client has a router with PAT (and therefore a different extern port than intern), test this port too
2581 if (remoteExternPort != 0 && remoteExternPort != remoteInternPort) {
2582 CMemFile testPacket2;
2583 testPacket2.WriteUInt8(errorAlreadyKnown ? 1 : 0);
2584 testPacket2.WriteUInt16(remoteExternPort);
2585 DebugSend(Kad2FirewalledUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort);
2586 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket2, KADEMLIA2_FIREWALLUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort, Kademlia::CKadUDPKey(senderKey, theApp->GetPublicIP(false)), NULL);
2588 //DebugLog(_T("Answered UDP Firewallcheck request (%s)"), DbgGetClientInfo());
2591 void CUpDownClient::SetConnectOptions(uint8_t options, bool encryption, bool callback)
2593 SetCryptLayerSupport((options & 0x01) != 0 && encryption);
2594 SetCryptLayerRequest((options & 0x02) != 0 && encryption);
2595 SetCryptLayerRequires((options & 0x04) != 0 && encryption);
2596 SetDirectUDPCallbackSupport((options & 0x08) != 0 && callback);
2598 // File_checked_for_headers