Upstream tarball 20080415
[amule.git] / src / BaseClient.cpp
blobcf5c6547082453aee07136cdfc8e0f02806bdc71
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 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>
35 #include <common/ClientVersion.h>
37 #include <tags/ClientTags.h>
39 #include <zlib.h> // Needed for inflateEnd
41 #include <common/Format.h> // Needed for CFormat
43 #include "SearchList.h" // Needed for CSearchList
44 #include "DownloadQueue.h" // Needed for CDownloadQueue
45 #include "UploadQueue.h" // Needed for CUploadQueue
46 #include "IPFilter.h" // Needed for CIPFilter
47 #include "ServerConnect.h" // Needed for CServerConnect
48 #include "ClientCredits.h" // Needed for CClientCredits
49 #include "ClientCreditsList.h" // Needed for CClientCreditsList
50 #include "Server.h" // Needed for CServer
51 #include "Preferences.h" // Needed for CPreferences
52 #include "MemFile.h" // Needed for CMemFile
53 #include "Packet.h" // Needed for CPacket
54 #include "Friend.h" // Needed for CFriend
55 #include "ClientList.h" // Needed for CClientList
56 #include "amule.h" // Needed for theApp
57 #include "PartFile.h" // Needed for CPartFile
58 #include "ClientTCPSocket.h" // Needed for CClientTCPSocket
59 #include "ListenSocket.h" // Needed for CListenSocket
60 #include "FriendList.h" // Needed for CFriendList
61 #include "Statistics.h" // Needed for theStats
62 #include "ClientUDPSocket.h"
63 #include "Logger.h"
64 #include "DataToText.h" // Needed for GetSoftName()
65 #include "GuiEvents.h" // Needed for Notify_
66 #include "ServerList.h" // For CServerList
68 #include "kademlia/kademlia/Kademlia.h"
69 #include "kademlia/kademlia/Prefs.h"
70 #include "kademlia/kademlia/Search.h"
73 //#define __PACKET_DEBUG__
76 // some client testing variables
77 static wxString crash_name = wxT("[Invalid User Name]");
78 static wxString empty_name = wxT("[Empty User Name]");
80 // members of CUpDownClient
81 // which are used by down and uploading functions
84 CUpDownClient::CUpDownClient(CClientTCPSocket* sender)
86 #ifdef __DEBUG__
87 m_socket = NULL;
88 SetSocket(sender);
89 #else
90 m_socket = sender;
91 #endif
92 Init();
95 CUpDownClient::CUpDownClient(uint16 in_port, uint32 in_userid, uint32 in_serverip, uint16 in_serverport, CPartFile* in_reqfile, bool ed2kID, bool checkfriend)
97 m_socket = NULL;
98 Init();
99 m_nUserPort = in_port;
101 if(ed2kID && !IsLowID(in_userid)) {
102 SetUserIDHybrid( wxUINT32_SWAP_ALWAYS(in_userid) );
103 } else {
104 SetUserIDHybrid( in_userid);
107 //If highID and ED2K source, incoming ID and IP are equal..
108 //If highID and Kad source, incoming IP needs swap for the IP
110 if (!HasLowID()) {
111 if (ed2kID) {
112 m_nConnectIP = in_userid;
113 } else {
114 m_nConnectIP = wxUINT32_SWAP_ALWAYS(in_userid);
116 // Will be on right endianess now
117 m_FullUserIP = Uint32toStringIP(m_nConnectIP);
120 m_dwServerIP = in_serverip;
121 m_nServerPort = in_serverport;
122 SetRequestFile( in_reqfile );
123 ReGetClientSoft();
125 if (checkfriend) {
126 if ((m_Friend = theApp->friendlist->FindFriend(CMD4Hash(), m_dwUserIP, m_nUserPort)) != NULL){
127 m_Friend->LinkClient(this);
128 } else{
129 // avoid that an unwanted client instance keeps a friend slot
130 m_bFriendSlot = false;
136 void CUpDownClient::Init()
138 m_bAddNextConnect = false;
139 credits = NULL;
140 m_byChatstate = MS_NONE;
141 m_nKadState = KS_NONE;
142 m_cShowDR = 0;
143 m_reqfile = NULL; // No file required yet
144 m_nTransferredUp = 0;
145 m_cSendblock = 0;
146 m_cAsked = 0;
147 msReceivedPrev = 0;
148 kBpsDown = 0.0;
149 fDownAvgFilter = 1.0;
150 bytesReceivedCycle = 0;
151 m_nServerPort = 0;
152 m_iFileListRequested = 0;
153 m_dwLastUpRequest = 0;
154 m_bEmuleProtocol = false;
155 m_bCompleteSource = false;
156 m_bFriendSlot = false;
157 m_bCommentDirty = false;
158 m_bReaskPending = false;
159 m_bUDPPending = false;
160 m_nUserPort = 0;
161 m_nPartCount = 0;
162 m_dwLastAskedTime = 0;
163 m_nDownloadState = DS_NONE;
164 m_dwUploadTime = 0;
165 m_nTransferredDown = 0;
166 m_nUploadState = US_NONE;
167 m_dwLastBlockReceived = 0;
168 m_bUnicodeSupport = false;
170 m_fSentOutOfPartReqs = 0;
171 m_nCurQueueSessionPayloadUp = 0;
172 m_addedPayloadQueueSession = 0;
173 m_nUpDatarate = 0;
174 m_nSumForAvgUpDataRate = 0;
176 m_nRemoteQueueRank = 0;
177 m_nOldRemoteQueueRank = 0;
178 m_dwLastSourceRequest = 0;
179 m_dwLastSourceAnswer = 0;
180 m_dwLastAskedForSources = 0;
182 m_SecureIdentState = IS_UNAVAILABLE;
183 m_dwLastSignatureIP = 0;
185 m_byInfopacketsReceived = IP_NONE;
187 m_bIsHybrid = false;
188 m_bIsML = false;
189 m_Friend = NULL;
190 m_iRating = 0;
191 m_nCurSessionUp = 0;
192 m_clientSoft=SO_UNKNOWN;
194 m_bRemoteQueueFull = false;
195 m_HasValidHash = false;
196 SetWaitStartTime();
198 m_fHashsetRequesting = 0;
199 m_fSharedDirectories = 0;
200 m_lastPartAsked = 0xffff;
201 m_nUpCompleteSourcesCount= 0;
202 m_lastRefreshedDLDisplay = 0;
203 m_bHelloAnswerPending = false;
204 m_fSentCancelTransfer = 0;
205 m_Aggressiveness = 0;
206 m_LastFileRequest = 0;
208 m_clientState = CS_NEW;
210 ClearHelloProperties();
212 m_pReqFileAICHHash = NULL;
213 m_fSupportsAICH = 0;
214 m_fAICHRequested = 0;
215 m_fSupportsLargeFiles = 0;
216 m_fExtMultiPacket = 0;
218 m_dwUserIP = 0;
219 m_nConnectIP = 0;
220 m_dwServerIP = 0;
222 m_fNeedOurPublicIP = false;
223 m_bHashsetRequested = false;
225 m_nLastBlockOffset = 0;
227 m_uploadingfile = NULL;
229 m_OSInfo_sent = false;
231 /* Kad stuff */
232 SetBuddyID(NULL);
233 m_nBuddyIP = 0;
234 m_nBuddyPort = 0;
235 m_nUserIDHybrid = 0;
237 m_nSourceFrom = SF_NONE;
239 if (m_socket) {
240 amuleIPV4Address address;
241 m_socket->GetPeer(address);
242 m_FullUserIP = address.IPAddress();
243 SetIP(StringIPtoUint32(m_FullUserIP));
244 } else {
245 SetIP(0);
248 /* Statistics */
249 m_lastClientSoft = (uint32)(-1);
250 m_lastClientVersion = 0;
252 /* Creation time (for buddies timeout) */
253 m_nCreationTime = ::GetTickCount();
255 m_MaxBlockRequests = STANDARD_BLOCKS_REQUEST; // Safe starting amount
257 m_last_block_start = 0;
258 m_lastaverage = 0;
260 SetLastBuddyPingPongTime();
261 m_fRequestsCryptLayer = 0;
262 m_fSupportsCryptLayer = 0;
263 m_fRequiresCryptLayer = 0;
264 m_fSupportsSourceEx2 = 0;
266 m_hasbeenobfuscatinglately = false;
270 CUpDownClient::~CUpDownClient()
272 #ifdef __DEBUG__
273 if (!connection_reason.IsEmpty()) {
274 printf("Client to check for %s was deleted without connection.\n",(const char*)unicode2char(connection_reason));
276 #endif
278 if (m_lastClientSoft == SO_UNKNOWN) {
279 theStats::RemoveUnknownClient();
280 } else if (m_lastClientSoft != (uint32)(-1)) {
281 theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo);
284 // Indicate that we are not anymore on stats
285 m_lastClientSoft = (uint32)(-1);
288 if (IsAICHReqPending()){
289 m_fAICHRequested = FALSE;
290 CAICHHashSet::ClientAICHRequestFailed(this);
293 //theApp->clientlist->RemoveClient(this, wxT("Destructing client object"));
295 if (m_Friend) {
296 m_Friend->UnLinkClient();
297 Notify_ChatRefreshFriend(m_Friend->GetIP(), m_Friend->GetPort(), wxEmptyString);
298 m_Friend = NULL;
301 // The socket should have been removed in Safe_Delete, but it
302 // doesn't hurt to have an extra check.
303 if (m_socket) {
304 m_socket->Safe_Delete();
305 // Paranoia
306 SetSocket(NULL);
310 ClearUploadBlockRequests();
311 ClearDownloadBlockRequests();
313 DeleteContents(m_WaitingPackets_list);
315 if (m_iRating>0 || !m_strComment.IsEmpty()) {
316 m_iRating = 0;
317 m_strComment.Clear();
318 if (m_reqfile) {
319 m_reqfile->UpdateFileRatingCommentAvail();
323 // Ensure that source-counts gets updated in case
324 // of a source not on the download-queue
325 SetRequestFile( NULL );
327 SetUploadFileID(NULL);
329 if (m_pReqFileAICHHash != NULL) {
330 delete m_pReqFileAICHHash;
331 m_pReqFileAICHHash = NULL;
335 void CUpDownClient::ClearHelloProperties()
337 m_nUDPPort = 0;
338 m_byUDPVer = 0;
339 m_byDataCompVer = 0;
340 m_byEmuleVersion = 0;
341 m_bySourceExchange1Ver = 0;
342 m_byAcceptCommentVer = 0;
343 m_byExtendedRequestsVer = 0;
344 m_byCompatibleClient = 0;
345 m_nKadPort = 0;
346 m_bySupportSecIdent = 0;
347 m_bSupportsPreview = 0;
348 m_nClientVersion = 0;
349 m_fSharedDirectories = 0;
350 m_bMultiPacket = 0;
351 m_fOsInfoSupport = 0;
352 m_fValueBasedTypeTags = 0;
353 SecIdentSupRec = 0;
354 m_byKadVersion = 0;
355 m_fRequestsCryptLayer = 0;
356 m_fSupportsCryptLayer = 0;
357 m_fRequiresCryptLayer = 0;
358 m_fSupportsSourceEx2 = 0;
361 bool CUpDownClient::ProcessHelloPacket(const byte* pachPacket, uint32 nSize)
363 const CMemFile data(pachPacket,nSize);
364 uint8 hashsize = data.ReadUInt8();
365 if ( 16 != hashsize ) {
367 * Hint: We can not accept other sizes here because:
368 * - the magic number is spread all over the source
369 * - the answer packet lacks the size field
371 throw wxString(wxT("Invalid Hello packet: Other userhash sizes than 16 are not implemented"));
373 // eMule 0.42: reset all client properties; a client may not send a particular emule tag any longer
374 ClearHelloProperties();
376 return ProcessHelloTypePacket(data);
379 void CUpDownClient::Safe_Delete()
381 // Because we are delaying the deletion, we might end up trying to delete
382 // it twice, however, this is normal and shouldn't trigger any failures
383 if ( m_clientState == CS_DYING ) {
384 return;
387 m_clientState = CS_DYING;
389 // Close the socket to avoid any more connections and related events
390 if ( m_socket ) {
391 m_socket->Safe_Delete();
392 // Paranoia
393 SetSocket(NULL);
396 // Schedule the client for deletion if we still have the clientlist
397 if ( theApp->clientlist ) {
398 theApp->clientlist->AddToDeleteQueue( this );
399 } else {
400 delete this;
405 bool CUpDownClient::ProcessHelloAnswer(const byte* pachPacket, uint32 nSize)
407 const CMemFile data(pachPacket,nSize);
408 bool bIsMule = ProcessHelloTypePacket(data);
409 m_bHelloAnswerPending = false;
410 return bIsMule;
413 bool CUpDownClient::ProcessHelloTypePacket(const CMemFile& data)
416 m_bIsHybrid = false;
417 m_bIsML = false;
418 m_fNoViewSharedFiles = 0;
419 m_bUnicodeSupport = false;
420 uint32 dwEmuleTags = 0;
422 CMD4Hash hash = data.ReadHash();
423 SetUserHash( hash );
424 SetUserIDHybrid( data.ReadUInt32() );
425 uint16 nUserPort = data.ReadUInt16(); // hmm clientport is sent twice - why?
426 uint32 tagcount = data.ReadUInt32();
427 for (uint32 i = 0;i < tagcount; i++){
428 CTag temptag(data, true);
429 switch(temptag.GetNameID()){
430 case CT_NAME:
431 m_Username = temptag.GetStr();
432 break;
434 case CT_VERSION:
435 m_nClientVersion = temptag.GetInt();
436 break;
438 case ET_MOD_VERSION:
439 if (temptag.IsStr()) {
440 m_strModVersion = temptag.GetStr();
441 } else if (temptag.IsInt()) {
442 m_strModVersion = wxString::Format(wxT("ModID=%u"), temptag.GetInt());
443 } else {
444 m_strModVersion = wxT("ModID=<Unknown>");
447 break;
449 case CT_PORT:
450 nUserPort = temptag.GetInt();
451 break;
453 case CT_EMULE_UDPPORTS:
454 // 16 KAD Port
455 // 16 UDP Port
456 SetKadPort((temptag.GetInt() >> 16) & 0xFFFF);
457 m_nUDPPort = temptag.GetInt() & 0xFFFF;
458 dwEmuleTags |= 1;
459 #ifdef __PACKET_DEBUG__
460 printf("Hello type packet processing with eMule ports UDP=%i KAD=%i\n",m_nUDPPort,m_nKadPort);
461 #endif
462 break;
464 case CT_EMULE_BUDDYIP:
465 // 32 BUDDY IP
466 m_nBuddyIP = temptag.GetInt();
467 #ifdef __PACKET_DEBUG__
468 printf("Hello type packet processing with eMule BuddyIP=%u (%s)\n",m_nBuddyIP, (const char*)unicode2char(Uint32toStringIP(m_nBuddyIP)));
469 #endif
470 break;
472 case CT_EMULE_BUDDYUDP:
473 // 16 --Reserved for future use--
474 // 16 BUDDY Port
475 m_nBuddyPort = (uint16)temptag.GetInt();
476 #ifdef __PACKET_DEBUG__
477 printf("Hello type packet processing with eMule BuddyPort=%u\n",m_nBuddyPort);
478 #endif
479 break;
481 case CT_EMULE_MISCOPTIONS1: {
482 // 3 AICH Version (0 = not supported)
483 // 1 Unicode
484 // 4 UDP version
485 // 4 Data compression version
486 // 4 Secure Ident
487 // 4 Source Exchange
488 // 4 Ext. Requests
489 // 4 Comments
490 // 1 PeerChache supported
491 // 1 No 'View Shared Files' supported
492 // 1 MultiPacket
493 // 1 Preview
494 uint32 flags = temptag.GetInt();
495 m_fSupportsAICH = (flags >> (4*7+1)) & 0x07;
496 m_bUnicodeSupport = (flags >> 4*7) & 0x01;
497 m_byUDPVer = (flags >> 4*6) & 0x0f;
498 m_byDataCompVer = (flags >> 4*5) & 0x0f;
499 m_bySupportSecIdent = (flags >> 4*4) & 0x0f;
500 m_bySourceExchange1Ver = (flags >> 4*3) & 0x0f;
501 m_byExtendedRequestsVer = (flags >> 4*2) & 0x0f;
502 m_byAcceptCommentVer = (flags >> 4*1) & 0x0f;
503 m_fNoViewSharedFiles = (flags >> 1*2) & 0x01;
504 m_bMultiPacket = (flags >> 1*1) & 0x01;
505 m_fSupportsPreview = (flags >> 1*0) & 0x01;
506 dwEmuleTags |= 2;
507 #ifdef __PACKET_DEBUG__
508 printf("Hello type packet processing with eMule Misc Options:\n");
509 printf("m_byUDPVer = %i\n",m_byUDPVer);
510 printf("m_byDataCompVer = %i\n",m_byDataCompVer);
511 printf("m_bySupportSecIdent = %i\n",m_bySupportSecIdent);
512 printf("m_bySourceExchangeVer = %i\n",m_bySourceExchange1Ver);
513 printf("m_byExtendedRequestsVer = %i\n",m_byExtendedRequestsVer);
514 printf("m_byAcceptCommentVer = %i\n",m_byAcceptCommentVer);
515 printf("m_fNoViewSharedFiles = %i\n",m_fNoViewSharedFiles);
516 printf("m_bMultiPacket = %i\n",m_bMultiPacket);
517 printf("m_fSupportsPreview = %i\n",m_fSharedDirectories);
518 printf("That's all.\n");
519 #endif
520 SecIdentSupRec += 1;
521 break;
524 case CT_EMULE_MISCOPTIONS2:
525 // 22 Reserved
526 m_fSupportsSourceEx2 = (temptag.GetInt() >> 10) & 0x01;
527 m_fRequiresCryptLayer = (temptag.GetInt() >> 9) & 0x01;
528 m_fRequestsCryptLayer = (temptag.GetInt() >> 8) & 0x01;
529 m_fSupportsCryptLayer = (temptag.GetInt() >> 7) & 0x01;
530 // reserved 1
531 m_fExtMultiPacket = (temptag.GetInt() >> 5) & 0x01;
532 m_fSupportsLargeFiles = (temptag.GetInt() >> 4) & 0x01;
533 m_byKadVersion = (temptag.GetInt() >> 0) & 0x0f;
534 dwEmuleTags |= 8;
536 m_fRequestsCryptLayer &= m_fSupportsCryptLayer;
537 m_fRequiresCryptLayer &= m_fRequestsCryptLayer;
539 #ifdef __PACKET_DEBUG__
540 printf("Hello type packet processing with eMule Misc Options 2:\n");
541 printf(" KadVersion = %u\n" , m_byKadVersion );
542 printf("That's all.\n");
543 #endif
544 break;
546 // Special tag fo Compat. Clients Misc options.
547 case CT_EMULECOMPAT_OPTIONS:
548 // 1 Operative System Info
549 // 1 Value-based-type int tags (experimental!)
550 m_fValueBasedTypeTags = (temptag.GetInt() >> 1*1) & 0x01;
551 m_fOsInfoSupport = (temptag.GetInt() >> 1*0) & 0x01;
552 break;
554 case CT_EMULE_VERSION:
555 // 8 Compatible Client ID
556 // 7 Mjr Version (Doesn't really matter..)
557 // 7 Min Version (Only need 0-99)
558 // 3 Upd Version (Only need 0-5)
559 // 7 Bld Version (Only need 0-99)
560 m_byCompatibleClient = (temptag.GetInt() >> 24);
561 m_nClientVersion = temptag.GetInt() & 0x00ffffff;
562 m_byEmuleVersion = 0x99;
563 m_fSharedDirectories = 1;
564 dwEmuleTags |= 4;
565 break;
569 m_nUserPort = nUserPort;
570 m_dwServerIP = data.ReadUInt32();
571 m_nServerPort = data.ReadUInt16();
572 // Hybrid now has an extra uint32.. What is it for?
573 // Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
574 if ( data.GetLength() - data.GetPosition() == sizeof(uint32) ) {
575 uint32 test = data.ReadUInt32();
576 /*if (test == 'KDLM') below kdlm is converted to ascii values.
577 This fixes a warning with gcc 3.4.
578 K=4b D=44 L=4c M=4d
580 if (test == 0x4b444c4d) { //if it's == "KDLM"
581 m_bIsML=true;
582 } else{
583 m_bIsHybrid = true;
584 m_fSharedDirectories = 1;
588 if (m_socket) {
589 amuleIPV4Address address;
590 m_socket->GetPeer(address);
591 m_FullUserIP = address.IPAddress();
592 SetIP(StringIPtoUint32(m_FullUserIP));
593 } else {
594 throw wxString(wxT("Huh, socket failure. Avoided crash this time."));
597 if (thePrefs::AddServersFromClient()) {
598 CServer* addsrv = new CServer(m_nServerPort, Uint32toStringIP(m_dwServerIP));
599 addsrv->SetListName(addsrv->GetAddress());
600 if (!theApp->AddServer(addsrv)) {
601 delete addsrv;
605 //(a)If this is a highID user, store the ID in the Hybrid format.
606 //(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
607 //(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
608 //because they will send a ID that is the same as their IP..
609 if(!HasLowID() || m_nUserIDHybrid == 0 || m_nUserIDHybrid == m_dwUserIP ) {
610 SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(m_dwUserIP));
613 // get client credits
614 CClientCredits* pFoundCredits = theApp->clientcredits->GetCredit(m_UserHash);
615 if (credits == NULL){
616 credits = pFoundCredits;
617 if (!theApp->clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, pFoundCredits)){
618 AddDebugLogLineM( false, logClient, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed (Found in TrackedClientsList)") ) % GetUserName() % GetFullIP() );
619 Ban();
621 } else if (credits != pFoundCredits){
622 // userhash change ok, however two hours "waittime" before it can be used
623 credits = pFoundCredits;
624 AddDebugLogLineM( false, logClient, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed") ) % GetUserName() % GetFullIP() );
625 Ban();
628 if ((m_Friend = theApp->friendlist->FindFriend(m_UserHash, m_dwUserIP, m_nUserPort)) != NULL){
629 m_Friend->LinkClient(this);
630 } else{
631 // avoid that an unwanted client instance keeps a friend slot
632 SetFriendSlot(false);
636 ReGetClientSoft();
638 m_byInfopacketsReceived |= IP_EDONKEYPROTPACK;
640 // check if at least CT_EMULEVERSION was received, all other tags are optional
641 bool bIsMule = (dwEmuleTags & 0x04) == 0x04;
642 if (bIsMule) {
643 m_bEmuleProtocol = true;
644 m_byInfopacketsReceived |= IP_EMULEPROTPACK;
647 if( GetKadPort() ) {
648 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(GetIP()), GetKadPort(), GetKadVersion() > 1);
651 return bIsMule;
655 bool CUpDownClient::SendHelloPacket() {
657 if (m_socket == NULL){
658 wxASSERT(0);
659 return true;
662 // if IP is filtered, dont greet him but disconnect...
663 amuleIPV4Address address;
664 m_socket->GetPeer(address);
665 if ( theApp->ipfilter->IsFiltered(StringIPtoUint32(address.IPAddress()))) {
666 if (Disconnected(wxT("IPFilter"))) {
667 Safe_Delete();
668 return false;
670 return true;
673 CMemFile data(128);
674 data.WriteUInt8(16); // size of userhash
675 SendHelloTypePacket(&data);
677 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_HELLO);
678 theStats::AddUpOverheadOther(packet->GetPacketSize());
679 SendPacket(packet,true);
680 m_bHelloAnswerPending = true;
681 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_HELLO to ") + GetFullIP() );
682 return true;
685 void CUpDownClient::SendMuleInfoPacket(bool bAnswer, bool OSInfo) {
687 if (m_socket == NULL){
688 wxASSERT(0);
689 return;
692 CPacket* packet = NULL;
693 CMemFile data;
695 data.WriteUInt8(CURRENT_VERSION_SHORT);
697 if (OSInfo) {
699 // Special MuleInfo packet for clients supporting it.
700 // This means aMule >= 2.0.0 and Hydranode
702 // Violently mark it as special Mule Info packet
703 // Sending this makes non-supporting-osinfo clients to refuse to read this
704 // packet. Anyway, this packet should NEVER get to non-supporting clients.
706 data.WriteUInt8(/*EMULE_PROTOCOL*/ 0xFF);
708 data.WriteUInt32(1); // One Tag (OS_INFO)
710 CTagString tag1(ET_OS_INFO,theApp->GetOSType());
711 tag1.WriteTagToFile(&data);
713 m_OSInfo_sent = true; // So we don't send it again
715 } else {
717 // Normal MuleInfo packet
719 // Kry - There's no point on upgrading to VBT tags here
720 // as no client supporting it uses mule info packet.
722 data.WriteUInt8(EMULE_PROTOCOL);
724 // Tag number
725 data.WriteUInt32(9);
727 CTagInt32 tag1(ET_COMPRESSION,1);
728 tag1.WriteTagToFile(&data);
729 CTagInt32 tag2(ET_UDPVER,4);
730 tag2.WriteTagToFile(&data);
731 CTagInt32 tag3(ET_UDPPORT, thePrefs::GetEffectiveUDPPort());
732 tag3.WriteTagToFile(&data);
733 CTagInt32 tag4(ET_SOURCEEXCHANGE,3);
734 tag4.WriteTagToFile(&data);
735 CTagInt32 tag5(ET_COMMENTS,1);
736 tag5.WriteTagToFile(&data);
737 CTagInt32 tag6(ET_EXTENDEDREQUEST,2);
738 tag6.WriteTagToFile(&data);
740 uint32 dwTagValue = (theApp->CryptoAvailable() ? 3 : 0);
741 // Kry - Needs the preview code from eMule
743 // set 'Preview supported' only if 'View Shared Files' allowed
744 if (thePrefs::CanSeeShares() != vsfaNobody) {
745 dwTagValue |= 128;
748 CTagInt32 tag7(ET_FEATURES, dwTagValue);
749 tag7.WriteTagToFile(&data);
751 CTagInt32 tag8(ET_COMPATIBLECLIENT,SO_AMULE);
752 tag8.WriteTagToFile(&data);
754 // Support for tag ET_MOD_VERSION
755 wxString mod_name(MOD_VERSION_LONG);
756 CTagString tag9(ET_MOD_VERSION, mod_name);
757 tag9.WriteTagToFile(&data);
758 // Maella end
762 packet = new CPacket(data, OP_EMULEPROT, (bAnswer ? OP_EMULEINFOANSWER : OP_EMULEINFO));
764 if (m_socket) {
765 theStats::AddUpOverheadOther(packet->GetPacketSize());
766 SendPacket(packet,true,true);
768 if (!bAnswer) {
769 if (!OSInfo) {
770 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_EMULEINFO to ") + GetFullIP() );
771 } else {
772 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_EMULEINFO/OS_INFO to ") + GetFullIP() );
774 } else {
775 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_EMULEINFOANSWER to ") + GetFullIP() );
780 bool CUpDownClient::ProcessMuleInfoPacket(const byte* pachPacket, uint32 nSize)
782 uint8 protocol_version;
784 const CMemFile data(pachPacket,nSize);
786 // The version number part of this packet will soon be useless since
787 // it is only able to go to v.99. Why the version is a uint8 and why
788 // it was not done as a tag like the eDonkey hello packet is not known.
789 // Therefore, sooner or later, we are going to have to switch over to
790 // using the eDonkey hello packet to set the version. No sense making
791 // a third value sent for versions.
792 uint8 mule_version = data.ReadUInt8();
793 protocol_version = data.ReadUInt8();
794 uint32 tagcount = data.ReadUInt32();
795 if (protocol_version == 0xFF) {
796 // OS Info supporting clients sending a recycled Mule info packet
797 for (uint32 i = 0;i < tagcount; i++){
798 CTag temptag(data, true);
799 switch(temptag.GetNameID()){
800 case ET_OS_INFO:
801 // Special tag, only supporting clients (aMule/Hydranode)
802 // It was recycled from a mod's tag, so if the other side
803 // is not supporting OS Info, we're seriously fucked up :)
804 m_sClientOSInfo = temptag.GetStr();
806 // If we didn't send our OSInfo to this client, just send it
807 if (!m_OSInfo_sent) {
808 SendMuleInfoPacket(false,true);
811 UpdateStats();
813 break;
815 // Your ad... er... I mean TAG, here
817 default:
818 break;
821 } else {
822 // Old eMule sending tags
823 m_byCompatibleClient = 0;
824 m_byEmuleVersion = mule_version;
826 if( m_byEmuleVersion == 0x2B ) {
827 m_byEmuleVersion = 0x22;
830 if (!(m_bEmuleProtocol = (protocol_version == EMULE_PROTOCOL))) {
831 return false;
834 for (uint32 i = 0;i < tagcount; i++){
835 CTag temptag(data, false);
836 switch(temptag.GetNameID()){
837 case ET_COMPRESSION:
838 // Bits 31- 8: 0 - reserved
839 // Bits 7- 0: data compression version
840 m_byDataCompVer = temptag.GetInt();
841 break;
843 case ET_UDPPORT:
844 // Bits 31-16: 0 - reserved
845 // Bits 15- 0: UDP port
846 m_nUDPPort = temptag.GetInt();
847 break;
849 case ET_UDPVER:
850 // Bits 31- 8: 0 - reserved
851 // Bits 7- 0: UDP protocol version
852 m_byUDPVer = temptag.GetInt();
853 break;
855 case ET_SOURCEEXCHANGE:
856 // Bits 31- 8: 0 - reserved
857 // Bits 7- 0: source exchange protocol version
858 m_bySourceExchange1Ver = temptag.GetInt();
859 break;
861 case ET_COMMENTS:
862 // Bits 31- 8: 0 - reserved
863 // Bits 7- 0: comments version
864 m_byAcceptCommentVer = temptag.GetInt();
865 break;
867 case ET_EXTENDEDREQUEST:
868 // Bits 31- 8: 0 - reserved
869 // Bits 7- 0: extended requests version
870 m_byExtendedRequestsVer = temptag.GetInt();
871 break;
873 case ET_COMPATIBLECLIENT:
874 // Bits 31- 8: 0 - reserved
875 // Bits 7- 0: compatible client ID
876 m_byCompatibleClient = temptag.GetInt();
877 break;
879 case ET_FEATURES:
880 // Bits 31- 8: 0 - reserved
881 // Bit 7: Preview
882 // Bit 6- 0: secure identification
883 m_bySupportSecIdent = temptag.GetInt() & 3;
884 m_bSupportsPreview = (temptag.GetInt() & 128) > 0;
885 SecIdentSupRec += 2;
886 break;
888 case ET_MOD_VERSION:
889 if (temptag.IsStr()) {
890 m_strModVersion = temptag.GetStr();
891 } else if (temptag.IsInt()) {
892 m_strModVersion = wxString::Format(wxT("ModID=%u"), temptag.GetInt());
893 } else {
894 m_strModVersion = wxT("ModID=<Unknown>");
897 break;
899 default:
900 AddDebugLogLineM( false, logPacketErrors,
901 CFormat( wxT("Unknown Mule tag (%s) from client: %s") )
902 % temptag.GetFullInfo()
903 % GetClientFullInfo()
906 break;
910 if( m_byDataCompVer == 0 ){
911 m_bySourceExchange1Ver = 0;
912 m_byExtendedRequestsVer = 0;
913 m_byAcceptCommentVer = 0;
914 m_nUDPPort = 0;
917 //implicitly supported options by older clients
918 //in the future do not use version to guess about new features
919 if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x22) {
920 m_byUDPVer = 1;
923 if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21) {
924 m_bySourceExchange1Ver = 1;
927 if(m_byEmuleVersion == 0x24) {
928 m_byAcceptCommentVer = 1;
931 // Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
932 // the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
933 // directory which has a trailing backslash.
934 if(m_byEmuleVersion >= 0x28 && !m_bIsML) {// MLdonkey currently does not support shared directories
935 m_fSharedDirectories = 1;
938 ReGetClientSoft();
940 m_byInfopacketsReceived |= IP_EMULEPROTPACK;
943 return (protocol_version == 0xFF); // This was a OS_Info?
947 void CUpDownClient::SendHelloAnswer()
949 if (m_socket == NULL){
950 wxASSERT(0);
951 return;
954 CMemFile data(128);
955 SendHelloTypePacket(&data);
956 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_HELLOANSWER);
957 theStats::AddUpOverheadOther(packet->GetPacketSize());
958 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_HELLOANSWER to ") + GetFullIP() );
959 SendPacket(packet,true);
963 void CUpDownClient::SendHelloTypePacket(CMemFile* data)
965 data->WriteHash(thePrefs::GetUserHash());
966 data->WriteUInt32(theApp->GetID());
967 data->WriteUInt16(thePrefs::GetPort());
969 uint32 tagcount = 6;
971 if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) {
972 tagcount += 2;
974 tagcount ++; // eMule misc flags 2 (kad version)
976 #ifdef __SVN__
977 // Kry - This is the tagcount!!! Be sure to update it!!
978 // Last update: CT_EMULECOMPAT_OPTIONS included
979 data->WriteUInt32(tagcount + 1);
980 #else
981 data->WriteUInt32(tagcount); // NO MOD_VERSION
982 #endif
985 CTagString tagname(CT_NAME,thePrefs::GetUserNick());
986 tagname.WriteTagToFile(data, utf8strRaw);
988 CTagVarInt tagversion(CT_VERSION, EDONKEYVERSION, GetVBTTags() ? 0 : 32);
989 tagversion.WriteTagToFile(data);
990 // eMule UDP Ports
992 uint32 kadUDPPort = 0;
994 if(Kademlia::CKademlia::IsConnected()) {
995 kadUDPPort = thePrefs::GetEffectiveUDPPort();
998 CTagVarInt tagUdpPorts(CT_EMULE_UDPPORTS,
999 (kadUDPPort << 16) |
1000 ((uint32)thePrefs::GetEffectiveUDPPort() ),
1001 GetVBTTags() ? 0 : 32);
1002 tagUdpPorts.WriteTagToFile(data);
1004 if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) {
1005 CTagVarInt tagBuddyIP(CT_EMULE_BUDDYIP, theApp->clientlist->GetBuddy()->GetIP(), GetVBTTags() ? 0 : 32);
1006 tagBuddyIP.WriteTagToFile(data);
1008 CTagVarInt tagBuddyPort(CT_EMULE_BUDDYUDP,
1009 // ( RESERVED )
1010 ((uint32)theApp->clientlist->GetBuddy()->GetUDPPort() )
1011 , GetVBTTags() ? 0 : 32);
1012 tagBuddyPort.WriteTagToFile(data);
1015 // aMule Version
1016 CTagVarInt tagMuleVersion(CT_EMULE_VERSION,
1017 (SO_AMULE << 24) |
1018 make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE)
1019 // | (RESERVED )
1020 , GetVBTTags() ? 0 : 32);
1021 tagMuleVersion.WriteTagToFile(data);
1024 // eMule Misc. Options #1
1025 const uint32 uUdpVer = 4;
1026 const uint32 uDataCompVer = 1;
1027 const uint32 uSupportSecIdent = theApp->CryptoAvailable() ? 3 : 0;
1028 const uint32 uSourceExchangeVer = 3;
1029 const uint32 uExtendedRequestsVer = 2;
1030 const uint32 uAcceptCommentVer = 1;
1031 const uint32 uNoViewSharedFiles = (thePrefs::CanSeeShares() == vsfaNobody) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag
1032 const uint32 uMultiPacket = 1;
1033 const uint32 uSupportPreview = 0; // No network preview at all.
1034 const uint32 uPeerCache = 0; // No peercache for aMule, baby
1035 const uint32 uUnicodeSupport = 1;
1036 const uint32 nAICHVer = 1; // AICH is ENABLED right now.
1038 CTagVarInt tagMisOptions(CT_EMULE_MISCOPTIONS1,
1039 (nAICHVer << ((4*7)+1)) |
1040 (uUnicodeSupport << 4*7) |
1041 (uUdpVer << 4*6) |
1042 (uDataCompVer << 4*5) |
1043 (uSupportSecIdent << 4*4) |
1044 (uSourceExchangeVer << 4*3) |
1045 (uExtendedRequestsVer << 4*2) |
1046 (uAcceptCommentVer << 4*1) |
1047 (uPeerCache << 1*3) |
1048 (uNoViewSharedFiles << 1*2) |
1049 (uMultiPacket << 1*1) |
1050 (uSupportPreview << 1*0)
1051 , GetVBTTags() ? 0 : 32);
1052 tagMisOptions.WriteTagToFile(data);
1054 // eMule Misc. Options #2
1055 const uint32 uKadVersion = 1;
1056 const uint32 uSupportLargeFiles = 1;
1057 const uint32 uExtMultiPacket = 1;
1058 const uint32 uReserved = 0; // mod bit
1059 const uint32 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1060 const uint32 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1061 const uint32 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1062 const uint32 uSupportsSourceEx2 = 1;
1063 CTagVarInt tagMisOptions2(CT_EMULE_MISCOPTIONS2,
1064 // (RESERVED )
1065 (uSupportsSourceEx2 << 10) |
1066 (uRequiresCryptLayer << 9) |
1067 (uRequestsCryptLayer << 8) |
1068 (uSupportsCryptLayer << 7) |
1069 (uReserved << 6) |
1070 (uExtMultiPacket << 5) |
1071 (uSupportLargeFiles << 4) |
1072 (uKadVersion << 0)
1073 , GetVBTTags() ? 0 : 32 );
1074 tagMisOptions2.WriteTagToFile(data);
1076 const uint32 nOSInfoSupport = 1; // We support OS_INFO
1077 const uint32 nValueBasedTypeTags = 0; // Experimental, disabled
1079 CTagVarInt tagMisCompatOptions(CT_EMULECOMPAT_OPTIONS,
1080 (nValueBasedTypeTags << 1*1) |
1081 (nOSInfoSupport << 1*0)
1082 , GetVBTTags() ? 0 : 32);
1084 tagMisCompatOptions.WriteTagToFile(data);
1086 #ifdef __SVN__
1087 wxString mod_name(MOD_VERSION_LONG);
1088 CTagString tagModName(ET_MOD_VERSION, mod_name);
1089 tagModName.WriteTagToFile(data);
1090 #endif
1092 uint32 dwIP = 0;
1093 uint16 nPort = 0;
1094 if (theApp->IsConnectedED2K()) {
1095 dwIP = theApp->serverconnect->GetCurrentServer()->GetIP();
1096 nPort = theApp->serverconnect->GetCurrentServer()->GetPort();
1098 data->WriteUInt32(dwIP);
1099 data->WriteUInt16(nPort);
1103 void CUpDownClient::ProcessMuleCommentPacket(const byte* pachPacket, uint32 nSize)
1105 if (!m_reqfile) {
1106 throw CInvalidPacket(wxT("Comment packet for unknown file"));
1109 if (!m_reqfile->IsPartFile()) {
1110 throw CInvalidPacket(wxT("Comment packet for completed file"));
1113 const CMemFile data(pachPacket, nSize);
1115 uint8 rating = data.ReadUInt8();
1116 if (rating > 5) {
1117 AddDebugLogLineM( false, logClient, wxString(wxT("Invalid Rating for file '")) << m_clientFilename << wxT("' received: ") << rating);
1118 m_iRating = 0;
1119 } else {
1120 m_iRating = rating;
1121 AddDebugLogLineM( false, logClient, wxString(wxT("Rating for file '")) << m_clientFilename << wxT("' received: ") << m_iRating);
1124 // The comment is unicoded, with a uin32 len and safe read
1125 // (won't break if string size is < than advertised len)
1126 // Truncated to MAXFILECOMMENTLEN size
1127 m_strComment = data.ReadString((GetUnicodeSupport() != utf8strNone), 4 /* bytes (it's a uint32)*/, true).Left(MAXFILECOMMENTLEN);
1129 AddDebugLogLineM( false, logClient, wxString(wxT("Description for file '")) << m_clientFilename << wxT("' received: ") << m_strComment);
1131 // Update file rating
1132 m_reqfile->UpdateFileRatingCommentAvail();
1136 void CUpDownClient::ClearDownloadBlockRequests()
1139 std::list<Requested_Block_Struct*>::iterator it = m_DownloadBlocks_list.begin();
1140 for (; it != m_DownloadBlocks_list.end(); ++it) {
1141 Requested_Block_Struct* cur_block = *it;
1143 if (m_reqfile){
1144 m_reqfile->RemoveBlockFromList(cur_block->StartOffset, cur_block->EndOffset);
1147 delete cur_block;
1150 m_DownloadBlocks_list.clear();
1154 std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin();
1155 for (; it != m_PendingBlocks_list.end(); ++it) {
1156 Pending_Block_Struct* pending = *it;
1158 if (m_reqfile) {
1159 m_reqfile->RemoveBlockFromList(pending->block->StartOffset, pending->block->EndOffset);
1162 delete pending->block;
1163 // Not always allocated
1164 if (pending->zStream){
1165 inflateEnd(pending->zStream);
1166 delete pending->zStream;
1169 delete pending;
1172 m_PendingBlocks_list.clear();
1177 bool CUpDownClient::Disconnected(const wxString& strReason, bool bFromSocket){
1179 // Kad reviewed
1181 //If this is a KAD client object, just delete it!
1182 SetKadState(KS_NONE);
1184 if (GetUploadState() == US_UPLOADING) {
1185 theApp->uploadqueue->RemoveFromUploadQueue(this);
1188 if (GetDownloadState() == DS_DOWNLOADING) {
1189 SetDownloadState(DS_ONQUEUE);
1190 } else{
1191 // ensure that all possible block requests are removed from the partfile
1192 ClearDownloadBlockRequests();
1194 if ( GetDownloadState() == DS_CONNECTED ){
1195 theApp->clientlist->AddDeadSource(this);
1196 theApp->downloadqueue->RemoveSource(this);
1200 // we had still an AICH request pending, handle it
1201 if (IsAICHReqPending()){
1202 m_fAICHRequested = FALSE;
1203 CAICHHashSet::ClientAICHRequestFailed(this);
1206 // The remote client does not have to answer with OP_HASHSETANSWER *immediatly*
1207 // after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client
1208 // is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
1209 if (((GetDownloadState() == DS_REQHASHSET) || m_fHashsetRequesting) && (m_reqfile)) {
1210 m_reqfile->SetHashSetNeeded(true);
1213 //check if this client is needed in any way, if not delete it
1214 bool bDelete = true;
1215 switch(m_nUploadState){
1216 case US_ONUPLOADQUEUE:
1217 bDelete = false;
1218 break;
1220 switch(m_nDownloadState){
1221 case DS_ONQUEUE:
1222 case DS_TOOMANYCONNS:
1223 case DS_NONEEDEDPARTS:
1224 case DS_LOWTOLOWIP:
1225 bDelete = false;
1228 switch(m_nUploadState){
1229 case US_CONNECTING:
1230 case US_WAITCALLBACK:
1231 case US_ERROR:
1232 theApp->clientlist->AddDeadSource(this);
1233 bDelete = true;
1235 switch(m_nDownloadState){
1236 case DS_CONNECTING:
1237 case DS_WAITCALLBACK:
1238 case DS_ERROR:
1239 theApp->clientlist->AddDeadSource(this);
1240 bDelete = true;
1244 if (GetChatState() != MS_NONE){
1245 bDelete = false;
1246 m_pendingMessage.Clear();
1247 Notify_ChatConnResult(false,GUI_ID(GetIP(),GetUserPort()),wxEmptyString);
1250 if (!bFromSocket && m_socket){
1251 wxASSERT (theApp->listensocket->IsValidSocket(m_socket));
1252 m_socket->Safe_Delete();
1255 SetSocket(NULL);
1257 if (m_iFileListRequested){
1258 AddLogLineM( false, CFormat(_("Failed to retrieve shared files from user '%s'")) % GetUserName() );
1259 m_iFileListRequested = 0;
1262 Notify_ClientCtrlRefreshClient( this );
1264 if (bDelete) {
1265 if (m_Friend) {
1266 // Remove the friend linkage
1267 Notify_ChatRefreshFriend(m_Friend->GetIP(), m_Friend->GetPort(), wxEmptyString);
1269 AddDebugLogLineM( false, logClient, wxString() <<
1270 wxT("--- Deleted client \"") << GetClientFullInfo() <<
1271 wxT("\"; Reason was ") << strReason );
1272 } else {
1273 AddDebugLogLineM( false, logClient, wxString() <<
1274 wxT("--- Disconnected client \"") << GetClientFullInfo() <<
1275 wxT("\"; Reason was ") << strReason );
1276 m_fHashsetRequesting = 0;
1277 SetSentCancelTransfer(0);
1278 m_bHelloAnswerPending = false;
1279 m_fSentOutOfPartReqs = 0;
1282 return bDelete;
1285 //Returned bool is not if the TryToConnect is successful or not..
1286 //false means the client was deleted!
1287 //true means the client was not deleted!
1288 bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon)
1290 // Kad reviewed
1291 if (theApp->listensocket->TooManySockets() && !bIgnoreMaxCon ) {
1292 if (!(m_socket && m_socket->IsConnected())) {
1293 if(Disconnected(wxT("Too many connections"))) {
1294 Safe_Delete();
1295 return false;
1297 return true;
1301 // 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)
1302 if ( (RequiresCryptLayer() && !thePrefs::IsClientCryptLayerSupported()) || (thePrefs::IsClientCryptLayerRequired() && !SupportsCryptLayer()) ){
1303 if(Disconnected(wxT("CryptLayer-Settings (Obfuscation) incompatible"))){
1304 Safe_Delete();
1305 return false;
1306 } else {
1307 return true;
1311 // Ipfilter check
1312 uint32 uClientIP = GetIP();
1313 if (uClientIP == 0 && !HasLowID()) {
1314 uClientIP = wxUINT32_SWAP_ALWAYS(m_nUserIDHybrid);
1317 if (uClientIP) {
1318 // Although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
1319 // we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
1320 if (theApp->ipfilter->IsFiltered(uClientIP)) {
1321 AddDebugLogLineM(false, logIPFilter, CFormat(wxT("Filtered ip %u (%s) on TryToConnect\n")) % uClientIP % Uint32toStringIP(uClientIP));
1322 if (Disconnected(wxT("IPFilter"))) {
1323 Safe_Delete();
1324 return false;
1325 } else {
1326 return true;
1330 // for safety: check again whether that IP is banned
1331 if (theApp->clientlist->IsBannedClient(uClientIP)) {
1332 AddDebugLogLineM(false, logClient, wxT("Refused to connect to banned client ") + Uint32toStringIP(uClientIP));
1333 if (Disconnected(wxT("Banned IP"))) {
1334 Safe_Delete();
1335 return false;
1337 return true;
1341 if( GetKadState() == KS_QUEUED_FWCHECK ) {
1342 SetKadState(KS_CONNECTING_FWCHECK);
1345 if ( HasLowID() ) {
1346 if (!theApp->DoCallback(this)) {
1347 //We cannot do a callback!
1348 if (GetDownloadState() == DS_CONNECTING) {
1349 SetDownloadState(DS_LOWTOLOWIP);
1350 } else if (GetDownloadState() == DS_REQHASHSET) {
1351 SetDownloadState(DS_ONQUEUE);
1352 m_reqfile->SetHashSetNeeded(true);
1354 if (GetUploadState() == US_CONNECTING) {
1355 if(Disconnected(wxT("LowID->LowID and US_CONNECTING"))) {
1356 Safe_Delete();
1357 return false;
1360 return true;
1363 //We already know we are not firewalled here as the above condition already detected LowID->LowID and returned.
1364 //If ANYTHING changes with the "if(!theApp->DoCallback(this))" above that will let you fall through
1365 //with the condition that the source is firewalled and we are firewalled, we must
1366 //recheck it before the this check..
1367 if( HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp->serverconnect->IsLocalServer(GetServerIP(), GetServerPort())) {
1368 //This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort.
1369 if( Kademlia::CKademlia::IsConnected() ) {
1370 //We are connect to Kad
1371 if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID()))) {
1372 //There are too many source lookups already or we are already searching this key.
1373 SetDownloadState(DS_TOOMANYCONNSKAD);
1374 return true;
1380 if (!m_socket || !m_socket->IsConnected()) {
1381 if (m_socket) {
1382 m_socket->Safe_Delete();
1384 m_socket = new CClientTCPSocket(this, thePrefs::GetProxyData());
1385 } else {
1386 ConnectionEstablished();
1387 return true;
1391 if (HasLowID()) {
1392 if (GetDownloadState() == DS_CONNECTING) {
1393 SetDownloadState(DS_WAITCALLBACK);
1395 if (GetUploadState() == US_CONNECTING) {
1396 if(Disconnected(wxT("LowID and US_CONNECTING"))) {
1397 Safe_Delete();
1398 return false;
1400 return true;
1403 if (theApp->serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)) {
1404 CMemFile data;
1405 // AFAICS, this id must be reversed to be sent to clients
1406 // But if I reverse it, we do a serve violation ;)
1407 data.WriteUInt32(m_nUserIDHybrid);
1408 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_CALLBACKREQUEST);
1409 theStats::AddUpOverheadServer(packet->GetPacketSize());
1410 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_CALLBACKREQUEST to ") + GetFullIP());
1411 theApp->serverconnect->SendPacket(packet);
1412 SetDownloadState(DS_WAITCALLBACK);
1413 } else {
1414 if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending)) {
1416 if( !HasValidBuddyID() ) {
1417 theApp->downloadqueue->RemoveSource(this);
1418 if (Disconnected(wxT("LowID and US_NONE and QR=0"))) {
1419 Safe_Delete();
1420 return false;
1422 return true;
1425 if( !Kademlia::CKademlia::IsConnected() ) {
1426 //We are not connected to Kad and this is a Kad Firewalled source..
1427 theApp->downloadqueue->RemoveSource(this);
1428 if(Disconnected(wxT("Kad Firewalled source but not connected to Kad."))) {
1429 Safe_Delete();
1430 return false;
1432 return true;
1435 if( GetDownloadState() == DS_WAITCALLBACK ) {
1436 if( GetBuddyIP() && GetBuddyPort()) {
1437 CMemFile bio(34);
1438 bio.WriteUInt128(Kademlia::CUInt128(GetBuddyID()));
1439 bio.WriteUInt128(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash()));
1440 bio.WriteUInt16(thePrefs::GetPort());
1441 CPacket* packet = new CPacket(bio, OP_KADEMLIAHEADER, KADEMLIA_CALLBACK_REQ);
1442 // eMule FIXME: We dont know which kadversion the buddy has, so we need to send unencrypted
1443 theApp->clientudp->SendPacket(packet, GetBuddyIP(), GetBuddyPort(), false, NULL, true, 0);
1444 AddDebugLogLineM(false,logLocalClient, wxString::Format(wxT("KADEMLIA_CALLBACK_REQ (%i) to"),packet->GetPacketSize()) + GetFullIP());
1445 theStats::AddUpOverheadKad(packet->GetRealPacketSize());
1446 SetDownloadState(DS_WAITCALLBACKKAD);
1447 } else {
1448 printf("Searching buddy for lowid connection\n");
1449 //Create search to find buddy.
1450 Kademlia::CSearch *findSource = new Kademlia::CSearch;
1451 findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE);
1452 findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
1453 findSource->AddFileID(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash()));
1454 if(Kademlia::CSearchManager::StartSearch(findSource)) {
1455 //Started lookup..
1456 SetDownloadState(DS_WAITCALLBACKKAD);
1457 } else {
1458 //This should never happen..
1459 wxASSERT(0);
1463 } else {
1464 if (GetDownloadState() == DS_WAITCALLBACK) {
1465 m_bReaskPending = true;
1466 SetDownloadState(DS_ONQUEUE);
1470 } else {
1471 if (!Connect()) {
1472 return false;
1475 return true;
1478 bool CUpDownClient::Connect()
1480 m_hasbeenobfuscatinglately = false;
1482 if (!m_socket->IsOk()) {
1483 // Enable or disable crypting based on our and the remote clients preference
1484 if (HasValidHash() && SupportsCryptLayer() && thePrefs::IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested())){
1485 // printf("Set connection encryption for socket\n");
1486 //DebugLog(_T("Enabling CryptLayer on outgoing connection to client %s"), DbgGetClientInfo()); // to be removed later
1487 m_socket->SetConnectionEncryption(true, GetUserHash().GetHash(), false);
1488 } else {
1489 m_socket->SetConnectionEncryption(false, NULL, false);
1491 amuleIPV4Address tmp;
1492 tmp.Hostname(GetConnectIP());
1493 tmp.Service(GetUserPort());
1494 AddDebugLogLineM(false, logClient, wxT("Trying to connect to ") + Uint32_16toStringIP_Port(GetConnectIP(),GetUserPort()));
1495 m_socket->Connect(tmp, false);
1496 // We should send hello packets AFTER connecting!
1497 // so I moved it to OnConnect
1498 return true;
1499 } else {
1500 return false;
1504 void CUpDownClient::ConnectionEstablished()
1507 /* Kry - First thing, check if this client was just used to retrieve
1508 info. That's some debug thing for myself... check connection_reason
1509 definition */
1511 m_hasbeenobfuscatinglately = (m_socket && m_socket->IsConnected() && m_socket->IsObfusicating());
1513 #ifdef __DEBUG__
1514 if (!connection_reason.IsEmpty()) {
1515 printf("Got client info checking for %s: %s\nDisconnecting and deleting.\n",(const char*)unicode2char(connection_reason),(const char*)unicode2char(GetClientFullInfo()));
1516 connection_reason.Clear(); // So we don't re-printf on destructor.
1517 Safe_Delete();
1518 return;
1520 #endif
1522 // Check if we should use this client to retrieve our public IP
1523 // Ignore local ip on GetPublicIP (could be wrong)
1524 if (theApp->GetPublicIP(true) == 0 && theApp->IsConnectedED2K()) {
1525 SendPublicIPRequest();
1528 switch (GetKadState()) {
1529 case KS_CONNECTING_FWCHECK:
1530 SetKadState(KS_CONNECTED_FWCHECK);
1531 break;
1532 case KS_CONNECTING_BUDDY:
1533 case KS_INCOMING_BUDDY:
1534 SetKadState(KS_CONNECTED_BUDDY);
1535 break;
1536 default:
1537 break;
1540 // ok we have a connection, lets see if we want anything from this client
1541 if (GetChatState() == MS_CONNECTING) {
1542 SetChatState( MS_CHATTING );
1545 if (GetChatState() == MS_CHATTING) {
1546 bool result = true;
1547 if (!m_pendingMessage.IsEmpty()) {
1548 result = SendMessage(m_pendingMessage);
1550 Notify_ChatConnResult(result,GUI_ID(GetIP(),GetUserPort()),m_pendingMessage);
1551 m_pendingMessage.Clear();
1554 switch(GetDownloadState()) {
1555 case DS_CONNECTING:
1556 case DS_WAITCALLBACK:
1557 case DS_WAITCALLBACKKAD:
1558 m_bReaskPending = false;
1559 SetDownloadState(DS_CONNECTED);
1560 SendFileRequest();
1562 if (m_bReaskPending){
1563 m_bReaskPending = false;
1564 if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING) {
1565 SetDownloadState(DS_CONNECTED);
1566 SendFileRequest();
1569 switch(GetUploadState()){
1570 case US_CONNECTING:
1571 case US_WAITCALLBACK:
1572 if (theApp->uploadqueue->IsDownloading(this)) {
1573 SetUploadState(US_UPLOADING);
1574 CPacket* packet = new CPacket(OP_ACCEPTUPLOADREQ, 0, OP_EDONKEYPROT);
1575 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1576 SendPacket(packet,true);
1577 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + GetFullIP() );
1580 if (m_iFileListRequested == 1) {
1581 CPacket* packet = new CPacket(m_fSharedDirectories ? OP_ASKSHAREDDIRS : OP_ASKSHAREDFILES, 0, OP_EDONKEYPROT);
1582 theStats::AddUpOverheadOther(packet->GetPacketSize());
1583 SendPacket(packet,true,true);
1584 if (m_fSharedDirectories) {
1585 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRS to ") + GetFullIP() );
1586 } else {
1587 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_ASKSHAREDFILES to ") + GetFullIP() );
1591 while (!m_WaitingPackets_list.empty()) {
1592 CPacket* packet = m_WaitingPackets_list.front();
1593 m_WaitingPackets_list.pop_front();
1595 SendPacket(packet);
1600 int CUpDownClient::GetHashType() const
1602 if ( m_UserHash[5] == 13 && m_UserHash[14] == 110 ) {
1603 return SO_OLDEMULE;
1606 if ( m_UserHash[5] == 14 && m_UserHash[14] == 111 ) {
1607 return SO_EMULE;
1610 if ( m_UserHash[5] == 'M' && m_UserHash[14] == 'L' ) {
1611 return SO_MLDONKEY;
1614 return SO_UNKNOWN;
1618 void CUpDownClient::SetSocket(CClientTCPSocket* socket)
1620 #if defined(__DEBUG__) && !defined(EC_REMOTE)
1621 if (m_socket == NULL && socket != NULL) {
1622 theStats::SocketAssignedToClient();
1623 } else if (m_socket != NULL && socket == NULL) {
1624 theStats::SocketUnassignedFromClient();
1626 #endif
1627 m_socket = socket;
1631 void CUpDownClient::ReGetClientSoft()
1633 if (m_Username.IsEmpty()) {
1634 m_clientSoft=SO_UNKNOWN;
1635 m_clientVerString = m_clientSoftString = m_clientVersionString = m_fullClientVerString = _("Unknown");
1636 UpdateStats();
1637 return;
1640 int iHashType = GetHashType();
1641 wxString clientModString;
1642 if (iHashType == SO_EMULE) {
1644 m_clientSoft = m_byCompatibleClient;
1645 m_clientSoftString = GetSoftName(m_clientSoft);
1646 // Special issues:
1647 if(!GetClientModString().IsEmpty() && (m_clientSoft != SO_EMULE)) {
1648 m_clientSoftString = GetClientModString();
1650 // Isn't xMule annoying?
1651 if ((m_clientSoft == SO_LXMULE) && (GetMuleVersion() > 0x26) && (GetMuleVersion() != 0x99)) {
1652 m_clientSoftString += wxString::Format(_(" (Fake eMule version %#x)"),GetMuleVersion());
1654 if ((m_clientSoft == SO_EMULE) &&
1656 wxString(GetClientModString()).MakeLower().Find(wxT("xmule")) != -1
1657 || GetUserName().Find(wxT("xmule.")) != -1
1660 // FAKE eMule -a newer xMule faking is ident.
1661 m_clientSoft = SO_LXMULE;
1662 if (GetClientModString().IsEmpty() == false) {
1663 m_clientSoftString = GetClientModString() + _(" (Fake eMule)");
1664 } else {
1665 m_clientSoftString = _("xMule (Fake eMule)"); // don't use GetSoftName, it's not lmule.
1668 // Now, what if we don't know this SO_ID?
1669 if (m_clientSoftString.IsEmpty()) {
1670 if(m_bIsML) {
1671 m_clientSoft = SO_MLDONKEY;
1672 m_clientSoftString = GetSoftName(m_clientSoft);
1673 } else if (m_bIsHybrid) {
1674 m_clientSoft = SO_EDONKEYHYBRID;
1675 m_clientSoftString = GetSoftName(m_clientSoft);
1676 } else if (m_byCompatibleClient != 0) {
1677 m_clientSoft = SO_COMPAT_UNK;
1678 #ifdef __DEBUG__
1679 if (
1680 // Exceptions:
1681 (m_byCompatibleClient != 0xf0) // Chinese leech mod
1682 && (1==1) // Your ad here
1684 printf("Compatible client found with ET_COMPATIBLECLIENT of %#x\n",m_byCompatibleClient);
1686 #endif
1687 m_clientSoftString = GetSoftName(m_clientSoft) + wxString::Format(wxT("(%#x)"),m_byCompatibleClient);
1688 } else {
1689 // If we step here, it might mean 2 things:
1690 // a eMule
1691 // a Compat Client that has sent no MuleInfo packet yet.
1692 m_clientSoft = SO_EMULE;
1693 m_clientSoftString = wxT("eMule");
1697 if (m_byEmuleVersion == 0) {
1698 m_nClientVersion = MAKE_CLIENT_VERSION(0,0,0);
1699 } else if (m_byEmuleVersion != 0x99) {
1700 uint32 nClientMinVersion = (m_byEmuleVersion >> 4)*10 + (m_byEmuleVersion & 0x0f);
1701 m_nClientVersion = MAKE_CLIENT_VERSION(0,nClientMinVersion,0);
1702 switch (m_clientSoft) {
1703 case SO_AMULE:
1704 m_clientVerString = wxString::Format(_("1.x (based on eMule v0.%u)"), nClientMinVersion);
1705 break;
1706 case SO_LPHANT:
1707 m_clientVerString = wxT("< v0.05");
1708 break;
1709 default:
1710 clientModString = GetClientModString();
1711 m_clientVerString = wxString::Format(wxT("v0.%u"), nClientMinVersion);
1712 break;
1714 } else {
1715 uint32 nClientMajVersion = (m_nClientVersion >> 17) & 0x7f;
1716 uint32 nClientMinVersion = (m_nClientVersion >> 10) & 0x7f;
1717 uint32 nClientUpVersion = (m_nClientVersion >> 7) & 0x07;
1719 m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
1721 switch (m_clientSoft) {
1722 case SO_AMULE:
1723 case SO_LXMULE:
1724 case SO_HYDRANODE:
1725 // Kry - xMule started sending correct version tags on 1.9.1b.
1726 // It only took them 4 months, and being told by me and the
1727 // eMule+ developers, so I think they're slowly getting smarter.
1728 // They are based on our implementation, so we use the same format
1729 // for the version string.
1730 m_clientVerString = wxString::Format(wxT("v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
1731 break;
1732 case SO_LPHANT:
1733 m_clientVerString = wxString::Format(wxT(" v%u.%.2u%c"), nClientMajVersion-1, nClientMinVersion, 'a' + nClientUpVersion);
1734 break;
1735 case SO_EMULEPLUS:
1736 m_clientVerString = wxString::Format(wxT("v%u"), nClientMajVersion);
1737 if(nClientMinVersion != 0) {
1738 m_clientVerString += wxString::Format(wxT(".%u"), nClientMinVersion);
1740 if(nClientUpVersion != 0) {
1741 m_clientVerString += wxString::Format(wxT("%c"), 'a' + nClientUpVersion - 1);
1743 break;
1744 default:
1745 clientModString = GetClientModString();
1746 m_clientVerString = wxString::Format(wxT("v%u.%u%c"), nClientMajVersion, nClientMinVersion, 'a' + nClientUpVersion);
1747 break;
1750 } else if (m_bIsHybrid) {
1751 // seen:
1752 // 105010 50.10
1753 // 10501 50.1
1754 // 1051 51.0
1755 // 501 50.1
1757 m_clientSoft = SO_EDONKEYHYBRID;
1758 m_clientSoftString = GetSoftName(m_clientSoft);
1760 uint32 nClientMajVersion;
1761 uint32 nClientMinVersion;
1762 uint32 nClientUpVersion;
1763 if (m_nClientVersion > 100000) {
1764 uint32 uMaj = m_nClientVersion/100000;
1765 nClientMajVersion = uMaj - 1;
1766 nClientMinVersion = (m_nClientVersion - uMaj*100000) / 100;
1767 nClientUpVersion = m_nClientVersion % 100;
1769 else if (m_nClientVersion > 10000) {
1770 uint32 uMaj = m_nClientVersion/10000;
1771 nClientMajVersion = uMaj - 1;
1772 nClientMinVersion = (m_nClientVersion - uMaj*10000) / 10;
1773 nClientUpVersion = m_nClientVersion % 10;
1775 else if (m_nClientVersion > 1000) {
1776 uint32 uMaj = m_nClientVersion/1000;
1777 nClientMajVersion = uMaj - 1;
1778 nClientMinVersion = m_nClientVersion - uMaj*1000;
1779 nClientUpVersion = 0;
1781 else if (m_nClientVersion > 100) {
1782 uint32 uMin = m_nClientVersion/10;
1783 nClientMajVersion = 0;
1784 nClientMinVersion = uMin;
1785 nClientUpVersion = m_nClientVersion - uMin*10;
1787 else{
1788 nClientMajVersion = 0;
1789 nClientMinVersion = m_nClientVersion;
1790 nClientUpVersion = 0;
1792 m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
1793 if (nClientUpVersion) {
1794 m_clientVerString = wxString::Format(wxT("v%u.%u.%u"), nClientMajVersion, nClientMinVersion, nClientUpVersion);
1795 } else {
1796 m_clientVerString = wxString::Format(wxT("v%u.%u"), nClientMajVersion, nClientMinVersion);
1798 } else if (m_bIsML || (iHashType == SO_MLDONKEY)) {
1799 m_clientSoft = SO_MLDONKEY;
1800 m_clientSoftString = GetSoftName(m_clientSoft);
1801 uint32 nClientMinVersion = m_nClientVersion;
1802 m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
1803 m_clientVerString = wxString::Format(wxT("v0.%u"), nClientMinVersion);
1804 } else if (iHashType == SO_OLDEMULE) {
1805 m_clientSoft = SO_OLDEMULE;
1806 m_clientSoftString = GetSoftName(m_clientSoft);
1807 uint32 nClientMinVersion = m_nClientVersion;
1808 m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
1809 m_clientVerString = wxString::Format(wxT("v0.%u"), nClientMinVersion);
1810 } else {
1811 m_clientSoft = SO_EDONKEY;
1812 m_clientSoftString = GetSoftName(m_clientSoft);
1813 m_nClientVersion *= 10;
1814 m_clientVerString = wxString::Format(wxT("v%u.%u"), m_nClientVersion / 100000, (m_nClientVersion / 1000) % 100);
1817 m_clientVersionString = m_clientVerString;
1818 if (!clientModString.IsEmpty()) {
1819 m_clientVerString += wxT(" - ") + clientModString;
1821 m_fullClientVerString = m_clientSoftString + wxT(" ") + m_clientVerString;
1823 UpdateStats();
1826 void CUpDownClient::RequestSharedFileList()
1828 if (m_iFileListRequested == 0) {
1829 AddDebugLogLineM( false, logClient, wxString( wxT("Requesting shared files from ") ) + GetUserName() );
1830 m_iFileListRequested = 1;
1831 TryToConnect(true);
1832 } else {
1833 AddDebugLogLineM( false, logClient, CFormat( wxT("Requesting shared files from user %s (%u) is already in progress") ) % GetUserName() % GetUserIDHybrid() );
1838 void CUpDownClient::ProcessSharedFileList(const byte* pachPacket, uint32 nSize, wxString& pszDirectory)
1840 if (m_iFileListRequested > 0) {
1841 m_iFileListRequested--;
1842 theApp->searchlist->ProcessSharedFileList(pachPacket, nSize, this, NULL, pszDirectory);
1847 void CUpDownClient::ResetFileStatusInfo()
1849 m_nPartCount = 0;
1851 if ( m_reqfile ) {
1852 m_reqfile->UpdatePartsFrequency( this, false );
1854 m_downPartStatus.clear();
1856 m_clientFilename.Clear();
1858 m_bCompleteSource = false;
1859 m_dwLastAskedTime = 0;
1860 m_iRating = 0;
1861 m_strComment.Clear();
1863 if (m_pReqFileAICHHash != NULL) {
1864 delete m_pReqFileAICHHash;
1865 m_pReqFileAICHHash = NULL;
1870 wxString CUpDownClient::GetUploadFileInfo()
1872 // build info text and display it
1873 wxString sRet;
1874 sRet = (CFormat(_("NickName: %s ID: %u")) % GetUserName() % GetUserIDHybrid()) + wxT(" ");
1875 if (m_reqfile) {
1876 sRet += CFormat(_("Requested: %s\n")) % m_reqfile->GetFileName();
1877 sRet += CFormat(
1878 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())
1879 ) % m_reqfile->statistic.GetAccepts() % m_reqfile->statistic.GetRequests() % CastItoXBytes(m_reqfile->statistic.GetTransferred());
1880 sRet += CFormat(
1881 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())
1882 ) % m_reqfile->statistic.GetAllTimeAccepts() % m_reqfile->statistic.GetAllTimeRequests() % CastItoXBytes(m_reqfile->statistic.GetAllTimeTransferred());
1883 } else {
1884 sRet += _("Requested unknown file");
1886 return sRet;
1889 // sends a packet, if needed it will establish a connection before
1890 // options used: ignore max connections, control packet, delete packet
1891 // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails
1892 bool CUpDownClient::SafeSendPacket(CPacket* packet)
1894 if (IsConnected()) {
1895 SendPacket(packet);
1896 return true;
1897 } else {
1898 m_WaitingPackets_list.push_back(packet);
1899 return TryToConnect(true);
1903 void CUpDownClient::SendPublicKeyPacket(){
1904 // send our public key to the client who requested it
1905 if (m_socket == NULL || credits == NULL || m_SecureIdentState != IS_KEYANDSIGNEEDED){
1906 wxASSERT ( false );
1907 return;
1909 if (!theApp->CryptoAvailable())
1910 return;
1912 CMemFile data;
1913 data.WriteUInt8(theApp->clientcredits->GetPubKeyLen());
1914 data.Write(theApp->clientcredits->GetPublicKey(), theApp->clientcredits->GetPubKeyLen());
1915 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_PUBLICKEY);
1917 theStats::AddUpOverheadOther(packet->GetPacketSize());
1918 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICKEY to ") + GetFullIP() );
1919 SendPacket(packet,true,true);
1920 m_SecureIdentState = IS_SIGNATURENEEDED;
1924 void CUpDownClient::SendSignaturePacket(){
1925 // signate the public key of this client and send it
1926 if (m_socket == NULL || credits == NULL || m_SecureIdentState == 0){
1927 wxASSERT ( false );
1928 return;
1931 if (!theApp->CryptoAvailable()) {
1932 return;
1934 if (credits->GetSecIDKeyLen() == 0) {
1935 return; // We don't have his public key yet, will be back here later
1937 // do we have a challenge value received (actually we should if we are in this function)
1938 if (credits->m_dwCryptRndChallengeFrom == 0){
1939 AddDebugLogLineM( false, logClient, wxString(wxT("Want to send signature but challenge value is invalid - User ")) + GetUserName());
1940 return;
1942 // v2
1943 // we will use v1 as default, except if only v2 is supported
1944 bool bUseV2;
1945 if ( (m_bySupportSecIdent&1) == 1 )
1946 bUseV2 = false;
1947 else
1948 bUseV2 = true;
1950 uint8 byChaIPKind = 0;
1951 uint32 ChallengeIP = 0;
1952 if (bUseV2){
1953 if (::IsLowID(theApp->GetED2KID())) {
1954 // we cannot do not know for sure our public ip, so use the remote clients one
1955 ChallengeIP = GetIP();
1956 byChaIPKind = CRYPT_CIP_REMOTECLIENT;
1957 } else {
1958 ChallengeIP = theApp->GetED2KID();
1959 byChaIPKind = CRYPT_CIP_LOCALCLIENT;
1962 //end v2
1963 byte achBuffer[250];
1965 uint8 siglen = theApp->clientcredits->CreateSignature(credits, achBuffer, 250, ChallengeIP, byChaIPKind );
1966 if (siglen == 0){
1967 wxASSERT ( false );
1968 return;
1970 CMemFile data;
1971 data.WriteUInt8(siglen);
1972 data.Write(achBuffer, siglen);
1973 if (bUseV2) {
1974 data.WriteUInt8(byChaIPKind);
1977 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SIGNATURE);
1979 theStats::AddUpOverheadOther(packet->GetPacketSize());
1980 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_SIGNATURE to ") + GetFullIP() );
1981 SendPacket(packet,true,true);
1982 m_SecureIdentState = IS_ALLREQUESTSSEND;
1986 void CUpDownClient::ProcessPublicKeyPacket(const byte* pachPacket, uint32 nSize)
1988 theApp->clientlist->AddTrackClient(this);
1990 if (m_socket == NULL || credits == NULL || pachPacket[0] != nSize-1
1991 || nSize == 0 || nSize > 250){
1992 wxASSERT ( false );
1993 return;
1995 if (!theApp->CryptoAvailable())
1996 return;
1997 // the function will handle everything (mulitple key etc)
1998 if (credits->SetSecureIdent(pachPacket+1, pachPacket[0])){
1999 // if this client wants a signature, now we can send him one
2000 if (m_SecureIdentState == IS_SIGNATURENEEDED){
2001 SendSignaturePacket();
2003 else if(m_SecureIdentState == IS_KEYANDSIGNEEDED){
2004 // something is wrong
2005 AddDebugLogLineM( false, logClient, wxT("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket") );
2007 } else{
2008 AddDebugLogLineM( false, logClient, wxT("Failed to use new received public key") );
2013 void CUpDownClient::ProcessSignaturePacket(const byte* pachPacket, uint32 nSize)
2015 // here we spread the good guys from the bad ones ;)
2017 if (m_socket == NULL || credits == NULL || nSize == 0 || nSize > 250){
2018 wxASSERT ( false );
2019 return;
2022 uint8 byChaIPKind;
2023 if (pachPacket[0] == nSize-1)
2024 byChaIPKind = 0;
2025 else if (pachPacket[0] == nSize-2 && (m_bySupportSecIdent & 2) > 0) //v2
2026 byChaIPKind = pachPacket[nSize-1];
2027 else{
2028 wxASSERT ( false );
2029 return;
2032 if (!theApp->CryptoAvailable())
2033 return;
2035 // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
2036 if (m_dwLastSignatureIP == GetIP()){
2037 AddDebugLogLineM( false, logClient, wxT("received multiple signatures from one client") );
2038 return;
2040 // also make sure this client has a public key
2041 if (credits->GetSecIDKeyLen() == 0){
2042 AddDebugLogLineM( false, logClient, wxT("received signature for client without public key") );
2043 return;
2045 // and one more check: did we ask for a signature and sent a challange packet?
2046 if (credits->m_dwCryptRndChallengeFor == 0){
2047 AddDebugLogLineM( false, logClient, wxT("received signature for client with invalid challenge value - User ") + GetUserName() );
2048 return;
2051 if (theApp->clientcredits->VerifyIdent(credits, pachPacket+1, pachPacket[0], GetIP(), byChaIPKind ) ){
2052 // result is saved in function above
2053 AddDebugLogLineM( false, logClient, CFormat( wxT("'%s' has passed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind );
2054 } else {
2055 AddDebugLogLineM( false, logClient, CFormat( wxT("'%s' has failed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind );
2058 m_dwLastSignatureIP = GetIP();
2061 void CUpDownClient::SendSecIdentStatePacket(){
2062 // check if we need public key and signature
2063 uint8 nValue = 0;
2064 if (credits){
2065 if (theApp->CryptoAvailable()){
2066 if (credits->GetSecIDKeyLen() == 0) {
2067 nValue = IS_KEYANDSIGNEEDED;
2068 } else if (m_dwLastSignatureIP != GetIP()) {
2069 nValue = IS_SIGNATURENEEDED;
2072 if (nValue == 0){
2073 AddDebugLogLineM( false, logClient, wxT("Not sending SecIdentState Packet, because State is Zero") );
2074 return;
2076 // crypt: send random data to sign
2077 uint32 dwRandom = rand()+1;
2078 credits->m_dwCryptRndChallengeFor = dwRandom;
2080 CMemFile data;
2081 data.WriteUInt8(nValue);
2082 data.WriteUInt32(dwRandom);
2083 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SECIDENTSTATE);
2085 theStats::AddUpOverheadOther(packet->GetPacketSize());
2086 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_SECIDENTSTATE to ") + GetFullIP() );
2087 SendPacket(packet,true,true);
2088 } else {
2089 wxASSERT ( false );
2094 void CUpDownClient::ProcessSecIdentStatePacket(const byte* pachPacket, uint32 nSize)
2096 if ( nSize != 5 ) {
2097 return;
2100 if ( !credits ) {
2101 wxASSERT( credits );
2102 return;
2105 CMemFile data(pachPacket,nSize);
2107 switch ( data.ReadUInt8() ) {
2108 case 0:
2109 m_SecureIdentState = IS_UNAVAILABLE;
2110 break;
2111 case 1:
2112 m_SecureIdentState = IS_SIGNATURENEEDED;
2113 break;
2114 case 2:
2115 m_SecureIdentState = IS_KEYANDSIGNEEDED;
2116 break;
2117 default:
2118 return;
2121 credits->m_dwCryptRndChallengeFrom = data.ReadUInt32();
2125 void CUpDownClient::InfoPacketsReceived()
2127 // indicates that both Information Packets has been received
2128 // needed for actions, which process data from both packets
2129 wxASSERT ( m_byInfopacketsReceived == IP_BOTH );
2130 m_byInfopacketsReceived = IP_NONE;
2132 if (m_bySupportSecIdent){
2133 SendSecIdentStatePacket();
2138 bool CUpDownClient::CheckHandshakeFinished(uint32 WXUNUSED(protocol), uint32 WXUNUSED(opcode)) const
2140 if (m_bHelloAnswerPending){
2141 // this triggers way too often.. need more time to look at this -> only create a warning
2142 AddDebugLogLineM( false, logClient, wxT("Handshake not finished while processing packet.") );
2143 return false;
2146 return true;
2150 wxString CUpDownClient::GetClientFullInfo() {
2152 if (m_clientVerString.IsEmpty()) {
2153 ReGetClientSoft();
2156 return CFormat( _("Client %s on IP:Port %s:%d using %s %s %s") )
2157 % ( m_Username.IsEmpty() ? wxString(_("Unknown")) : m_Username )
2158 % GetFullIP()
2159 % GetUserPort()
2160 % m_clientSoftString
2161 % m_clientVerString
2162 % m_strModVersion;
2167 void CUpDownClient::SendPublicIPRequest(){
2168 if (IsConnected()){
2169 CPacket* packet = new CPacket(OP_PUBLICIP_REQ,0,OP_EMULEPROT);
2170 theStats::AddUpOverheadOther(packet->GetPacketSize());
2171 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_PUBLICIP_REQ to") + GetFullIP());
2172 SendPacket(packet,true);
2173 m_fNeedOurPublicIP = true;
2177 void CUpDownClient::ProcessPublicIPAnswer(const byte* pbyData, uint32 uSize){
2178 if (uSize != 4) {
2179 throw wxString(wxT("Wrong Packet size on Public IP answer"));
2181 uint32 dwIP = PeekUInt32(pbyData);
2182 if (m_fNeedOurPublicIP == true){ // did we?
2183 m_fNeedOurPublicIP = false;
2184 // Ignore local ip on GetPublicIP (could be wrong)
2185 if (theApp->GetPublicIP(true) == 0 && !IsLowID(dwIP) ) {
2186 theApp->SetPublicIP(dwIP);
2192 bool CUpDownClient::IsConnected() const
2194 return m_socket && m_socket->IsConnected();
2197 bool CUpDownClient::SendPacket(CPacket* packet, bool delpacket, bool controlpacket)
2199 if ( m_socket ) {
2200 m_socket->SendPacket(packet, delpacket, controlpacket );
2201 return true;
2202 } else {
2203 printf("CAUGHT DEAD SOCKET IN SENDPACKET()\n");
2204 return false;
2208 float CUpDownClient::SetDownloadLimit(uint32 reducedownload)
2211 // lfroen: in daemon it actually can happen
2212 wxASSERT( m_socket );
2214 float kBpsClient = CalculateKBpsDown();
2216 if ( m_socket ) {
2218 if (reducedownload) {
2219 // (% to reduce * current speed) / 100 and THEN, / 10 because this
2220 // gets called 10 times per second.
2221 uint32 limit = (uint32)(((float)reducedownload*(kBpsClient*1024.0))/1000);
2223 if(limit<1024 && reducedownload >= 200) {
2224 // If we're going up and this download is < 1kB,
2225 // we want it to go up fast. Can be reduced later,
2226 // and it'll probably be in a more fair way with
2227 // other downloads that are faster.
2228 limit +=1024;
2229 } else if(limit == 0) {
2230 // This download is not transferring yet... make it
2231 // 1024 so we don't fill the TCP stack and lose the
2232 // connection.
2233 limit = 1024;
2236 m_socket->SetDownloadLimit(limit);
2237 } else {
2238 m_socket->DisableDownloadLimit();
2241 } else {
2242 printf("CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f\n", kBpsClient);
2245 return kBpsClient;
2249 void CUpDownClient::SetUserIDHybrid(uint32 nUserID)
2251 theApp->clientlist->UpdateClientID( this, nUserID );
2253 m_nUserIDHybrid = nUserID;
2257 void CUpDownClient::SetIP( uint32 val )
2259 theApp->clientlist->UpdateClientIP( this, val );
2261 m_dwUserIP = val;
2263 m_nConnectIP = val;
2267 void CUpDownClient::SetUserHash(const CMD4Hash& userhash)
2269 theApp->clientlist->UpdateClientHash( this, userhash );
2271 m_UserHash = userhash;
2273 ValidateHash();
2276 EUtf8Str CUpDownClient::GetUnicodeSupport() const
2278 return m_bUnicodeSupport ? utf8strRaw : utf8strNone;
2282 uint8 CUpDownClient::GetSecureIdentState() {
2283 if (m_SecureIdentState != IS_UNAVAILABLE) {
2284 if (!SecIdentSupRec) {
2285 // This can be caused by a 0.30x based client which sends the old
2286 // style Hello packet, and the mule info packet, but between them they
2287 // send a secure ident state packet (after a hello but before we have
2288 // the SUI capabilities). This is a misbehaving client, and somehow I
2289 // Feel like ti should be dropped. But then again, it won't harm to use
2290 // this SUI state if they are reporting no SUI (won't be used) and if
2291 // they report using SUI on the mule info packet, it's ok to use it.
2293 AddDebugLogLineM(false, logClient, wxT("A client sent secure ident state before telling us the SUI capabilities"));
2294 AddDebugLogLineM(false, logClient, wxT("Client info: ") + GetClientFullInfo());
2295 AddDebugLogLineM(false, logClient, wxT("This client won't be disconnected, but it should be. :P"));
2299 return m_SecureIdentState;
2303 bool CUpDownClient::SendMessage(const wxString& message)
2305 // Already connecting?
2306 if (GetChatState() == MS_CONNECTING) {
2307 // Queue all messages till we're able to send them (or discard them)
2308 if (!m_pendingMessage.IsEmpty()) {
2309 m_pendingMessage += wxT("\n");
2310 } else {
2311 // There must be a message to send
2312 wxASSERT(0);
2314 m_pendingMessage += message;
2315 return false;
2317 if (IsConnected()) {
2318 CMemFile data;
2319 data.WriteString(message, GetUnicodeSupport());
2320 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_MESSAGE);
2321 theStats::AddUpOverheadOther(packet->GetPacketSize());
2322 AddDebugLogLineM( false, logLocalClient, wxT("Local Client: OP_MESSAGE to ") + GetFullIP());
2323 SendPacket(packet, true, true);
2324 return true;
2325 } else {
2326 m_pendingMessage = message;
2327 SetChatState(MS_CONNECTING);
2328 // True to ignore "Too Many Connections"
2329 TryToConnect(true);
2330 return false;
2334 /* Kad stuff */
2336 void CUpDownClient::SetBuddyID(const byte* pucBuddyID)
2338 if( pucBuddyID == NULL ){
2339 md4clr(m_achBuddyID);
2340 m_bBuddyIDValid = false;
2341 return;
2343 m_bBuddyIDValid = true;
2344 md4cpy(m_achBuddyID, pucBuddyID);
2347 // Kad added by me
2349 bool CUpDownClient::SendBuddyPing() {
2350 SetLastBuddyPingPongTime();
2351 CPacket* buddyPing = new CPacket(OP_BUDDYPING, 0, OP_EMULEPROT);
2352 theStats::AddUpOverheadKad(buddyPing->GetPacketSize());
2353 AddDebugLogLineM(false, logLocalClient,wxT("Local Client: OP_BUDDYPING to ") + GetFullIP());
2354 return SafeSendPacket(buddyPing);
2358 /* Statistics */
2360 void CUpDownClient::UpdateStats()
2362 if (m_lastClientSoft != m_clientSoft || m_lastClientVersion != m_nClientVersion || m_lastOSInfo != m_sClientOSInfo) {
2363 if (m_lastClientSoft == SO_UNKNOWN) {
2364 theStats::RemoveUnknownClient();
2365 } else if (m_lastClientSoft != (uint32)(-1)) {
2366 theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo);
2369 m_lastClientSoft = m_clientSoft;
2370 m_lastClientVersion = m_nClientVersion;
2371 m_lastOSInfo = m_sClientOSInfo;
2373 if (m_clientSoft == SO_UNKNOWN) {
2374 theStats::AddUnknownClient();
2375 } else {
2376 theStats::AddKnownClient(this);
2381 bool CUpDownClient::IsIdentified() const
2383 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED);
2386 bool CUpDownClient::IsBadGuy() const
2388 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY);
2391 bool CUpDownClient::SUIFailed() const
2393 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDFAILED);
2396 bool CUpDownClient::SUINeeded() const
2398 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDNEEDED);
2401 bool CUpDownClient::SUINotSupported() const
2403 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_NOTAVAILABLE);
2406 uint64 CUpDownClient::GetDownloadedTotal() const
2408 return credits ? credits->GetDownloadedTotal() : 0;
2411 uint64 CUpDownClient::GetUploadedTotal() const
2413 return credits ? credits->GetUploadedTotal() : 0;
2416 double CUpDownClient::GetScoreRatio() const {
2417 return credits ? credits->GetScoreRatio(GetIP(), theApp->CryptoAvailable()) : 0;
2420 const wxString CUpDownClient::GetServerName() const
2422 wxString ret;
2423 wxString srvaddr = Uint32toStringIP(GetServerIP());
2424 CServer* cserver = theApp->serverlist->GetServerByAddress(
2425 srvaddr, GetServerPort());
2426 if (cserver) {
2427 ret = cserver->GetListName();
2428 } else {
2429 ret = _("Unknown");
2432 return ret;
2435 bool CUpDownClient::ShouldReceiveCryptUDPPackets() const {
2436 return (thePrefs::IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp->GetPublicIP() != 0
2437 && HasValidHash() && (thePrefs::IsClientCryptLayerRequested() || RequestsCryptLayer()) );
2440 // File_checked_for_headers