Fix compilation with wxWidgets 2.8.12
[amule.git] / src / BaseClient.cpp
blobcf1093a32ad27f1ac4e4804b179b8911fdfa7db0
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2003-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002-2011 Merkur ( devs@emule-project.net / http://www.emule-project.net )
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.
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>
27 #include <wx/mstream.h>
28 #include <wx/tokenzr.h>
30 #include "updownclient.h" // Needed for CUpDownClient
31 #include "SharedFileList.h" // Needed for CSharedFileList
33 #include <protocol/Protocols.h>
34 #include <protocol/ed2k/Client2Client/TCP.h>
35 #include <protocol/ed2k/ClientSoftware.h>
36 #include <protocol/kad/Client2Client/UDP.h>
37 #include <protocol/kad2/Constants.h>
38 #include <protocol/kad2/Client2Client/TCP.h>
39 #include <protocol/kad2/Client2Client/UDP.h>
41 #include <common/ClientVersion.h>
43 #include <tags/ClientTags.h>
45 #include <zlib.h> // Needed for inflateEnd
47 #include <common/Format.h> // Needed for CFormat
49 #include "SearchList.h" // Needed for CSearchList
50 #include "DownloadQueue.h" // Needed for CDownloadQueue
51 #include "UploadQueue.h" // Needed for CUploadQueue
52 #include "IPFilter.h" // Needed for CIPFilter
53 #include "ServerConnect.h" // Needed for CServerConnect
54 #include "ClientCredits.h" // Needed for CClientCredits
55 #include "ClientCreditsList.h" // Needed for CClientCreditsList
56 #include "Server.h" // Needed for CServer
57 #include "Preferences.h" // Needed for CPreferences
58 #include "MemFile.h" // Needed for CMemFile
59 #include "Packet.h" // Needed for CPacket
60 #include "Friend.h" // Needed for CFriend
61 #include "ClientList.h" // Needed for CClientList
62 #ifndef AMULE_DAEMON
63 #include "amuleDlg.h" // Needed for CamuleDlg
64 #include "CaptchaDialog.h" // Needed for CCaptchaDialog
65 #include "CaptchaGenerator.h"
66 #include "ChatWnd.h" // Needed for CChatWnd
67 #endif
68 #include "amule.h" // Needed for theApp
69 #include "PartFile.h" // Needed for CPartFile
70 #include "ClientTCPSocket.h" // Needed for CClientTCPSocket
71 #include "ListenSocket.h" // Needed for CListenSocket
72 #include "FriendList.h" // Needed for CFriendList
73 #include "Statistics.h" // Needed for theStats
74 #include "ClientUDPSocket.h"
75 #include "Logger.h"
76 #include "DataToText.h" // Needed for GetSoftName()
77 #include "GuiEvents.h" // Needed for Notify_
78 #include "ServerList.h" // For CServerList
80 #include "kademlia/kademlia/Kademlia.h"
81 #include "kademlia/kademlia/Prefs.h"
82 #include "kademlia/kademlia/Search.h"
83 #include "kademlia/kademlia/UDPFirewallTester.h"
84 #include "kademlia/routing/RoutingZone.h"
87 //#define __PACKET_DEBUG__
90 // some client testing variables
91 static wxString crash_name = wxT("[Invalid User Name]");
92 static wxString empty_name = wxT("[Empty User Name]");
94 // members of CUpDownClient
95 // which are used by down and uploading functions
98 CUpDownClient::CUpDownClient(CClientTCPSocket* sender)
100 #ifdef __DEBUG__
101 m_socket = NULL;
102 SetSocket(sender);
103 #else
104 m_socket = sender;
105 #endif
106 Init();
109 CUpDownClient::CUpDownClient(uint16 in_port, uint32 in_userid, uint32 in_serverip, uint16 in_serverport, CPartFile* in_reqfile, bool ed2kID, bool checkfriend)
111 m_socket = NULL;
112 Init();
113 m_nUserPort = in_port;
115 if(ed2kID && !IsLowID(in_userid)) {
116 SetUserIDHybrid( wxUINT32_SWAP_ALWAYS(in_userid) );
117 } else {
118 SetUserIDHybrid( in_userid);
121 //If highID and ED2K source, incoming ID and IP are equal..
122 //If highID and Kad source, incoming IP needs swap for the IP
124 if (!HasLowID()) {
125 if (ed2kID) {
126 m_nConnectIP = in_userid;
127 } else {
128 m_nConnectIP = wxUINT32_SWAP_ALWAYS(in_userid);
130 // Will be on right endianess now
131 m_FullUserIP = m_nConnectIP;
134 m_dwServerIP = in_serverip;
135 m_nServerPort = in_serverport;
136 SetRequestFile( in_reqfile );
137 ReGetClientSoft();
139 if (checkfriend) {
140 if ((m_Friend = theApp->friendlist->FindFriend(CMD4Hash(), m_dwUserIP, m_nUserPort)) != NULL){
141 m_Friend->LinkClient(CCLIENTREF(this, wxT("CUpDownClient::CUpDownClient m_Friend->LinkClient")));
142 } else{
143 // avoid that an unwanted client instance keeps a friend slot
144 m_bFriendSlot = false;
150 void CUpDownClient::Init()
152 m_linked = 0;
153 #ifdef DEBUG_ZOMBIE_CLIENTS
154 m_linkedDebug = false;
155 #endif
156 m_bAddNextConnect = false;
157 credits = NULL;
158 m_byChatstate = MS_NONE;
159 m_nKadState = KS_NONE;
160 m_nChatCaptchaState = CA_NONE;
161 m_cShowDR = 0;
162 m_reqfile = NULL; // No file required yet
163 m_nTransferredUp = 0;
164 m_cSendblock = 0;
165 m_cAsked = 0;
166 msReceivedPrev = 0;
167 kBpsDown = 0.0;
168 bytesReceivedCycle = 0;
169 m_nServerPort = 0;
170 m_iFileListRequested = 0;
171 m_dwLastUpRequest = 0;
172 m_bEmuleProtocol = false;
173 m_bCompleteSource = false;
174 m_bFriendSlot = false;
175 m_bCommentDirty = false;
176 m_bReaskPending = false;
177 m_bUDPPending = false;
178 m_nUserPort = 0;
179 m_nPartCount = 0;
180 m_dwLastAskedTime = 0;
181 m_nDownloadState = DS_NONE;
182 m_dwUploadTime = 0;
183 m_nTransferredDown = 0;
184 m_nUploadState = US_NONE;
185 m_dwLastBlockReceived = 0;
186 m_bUnicodeSupport = false;
188 m_fSentOutOfPartReqs = 0;
189 m_nCurQueueSessionPayloadUp = 0;
190 m_addedPayloadQueueSession = 0;
191 m_nUpDatarate = 0;
192 m_nSumForAvgUpDataRate = 0;
194 m_nRemoteQueueRank = 0;
195 m_nOldRemoteQueueRank = 0;
196 m_dwLastSourceRequest = 0;
197 m_dwLastSourceAnswer = 0;
198 m_dwLastAskedForSources = 0;
200 m_SecureIdentState = IS_UNAVAILABLE;
201 m_dwLastSignatureIP = 0;
203 m_byInfopacketsReceived = IP_NONE;
205 m_bIsHybrid = false;
206 m_bIsML = false;
207 m_Friend = NULL;
208 m_iRating = 0;
209 m_nCurSessionUp = 0;
210 m_clientSoft=SO_UNKNOWN;
212 m_bRemoteQueueFull = false;
213 m_HasValidHash = false;
214 SetWaitStartTime();
216 m_fHashsetRequesting = 0;
217 m_fSharedDirectories = 0;
218 m_lastPartAsked = 0xffff;
219 m_nUpCompleteSourcesCount= 0;
220 m_waitingPosition = 0;
221 m_score = 0;
222 m_lastRefreshedDLDisplay = 0;
223 m_bHelloAnswerPending = false;
224 m_fSentCancelTransfer = 0;
225 m_Aggressiveness = 0;
226 m_LastFileRequest = 0;
228 m_clientState = CS_NEW;
230 ClearHelloProperties();
232 m_pReqFileAICHHash = NULL;
233 m_fSupportsAICH = 0;
234 m_fAICHRequested = 0;
235 m_fSupportsLargeFiles = 0;
236 m_fExtMultiPacket = 0;
237 m_fIsSpammer = 0;
239 m_dwUserIP = 0;
240 m_nConnectIP = 0;
241 m_dwServerIP = 0;
243 m_fNeedOurPublicIP = false;
244 m_bHashsetRequested = false;
246 m_lastDownloadingPart = 0;
248 m_uploadingfile = NULL;
250 m_OSInfo_sent = false;
252 /* Kad stuff */
253 SetBuddyID(NULL);
254 m_nBuddyIP = 0;
255 m_nBuddyPort = 0;
256 m_nUserIDHybrid = 0;
258 m_nSourceFrom = SF_NONE;
260 if (m_socket) {
261 SetIP(m_socket->GetPeerInt());
262 } else {
263 SetIP(0);
266 /* Statistics */
267 m_lastClientSoft = (uint32)(-1);
268 m_lastClientVersion = 0;
270 /* Creation time (for buddies timeout) */
271 m_nCreationTime = ::GetTickCount();
273 m_MaxBlockRequests = STANDARD_BLOCKS_REQUEST; // Safe starting amount
275 m_last_block_start = 0;
276 m_lastaverage = 0;
278 SetLastBuddyPingPongTime();
279 m_fRequestsCryptLayer = 0;
280 m_fSupportsCryptLayer = 0;
281 m_fRequiresCryptLayer = 0;
282 m_fSupportsSourceEx2 = 0;
283 m_fSupportsCaptcha = 0;
284 m_fDirectUDPCallback = 0;
285 m_dwDirectCallbackTimeout = 0;
287 m_hasbeenobfuscatinglately = false;
289 m_cCaptchasSent = 0;
290 m_cMessagesReceived = 0;
291 m_cMessagesSent = 0;
296 CUpDownClient::~CUpDownClient()
298 #ifdef __DEBUG__
299 if (!connection_reason.IsEmpty()) {
300 AddDebugLogLineN(logClient, wxT("Client to check for ") + connection_reason + wxT(" was deleted without connection."));
302 #endif
305 if (m_lastClientSoft == SO_UNKNOWN) {
306 theStats::RemoveUnknownClient();
307 } else if (m_lastClientSoft != (uint32)(-1)) {
308 theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo);
311 // Indicate that we are not anymore on stats
312 m_lastClientSoft = (uint32)(-1);
314 // The socket should have been removed in Safe_Delete, but it
315 // doesn't hurt to have an extra check.
316 if (m_socket) {
317 m_socket->Safe_Delete();
318 // Paranoia
319 SetSocket(NULL);
322 ClearUploadBlockRequests();
323 ClearDownloadBlockRequests();
325 DeleteContents(m_WaitingPackets_list);
327 // Allow detection of deleted clients that didn't go through Safe_Delete
328 m_clientState = CS_DYING;
332 void CUpDownClient::ClearHelloProperties()
334 m_nUDPPort = 0;
335 m_byUDPVer = 0;
336 m_byDataCompVer = 0;
337 m_byEmuleVersion = 0;
338 m_bySourceExchange1Ver = 0;
339 m_byAcceptCommentVer = 0;
340 m_byExtendedRequestsVer = 0;
341 m_byCompatibleClient = 0;
342 m_nKadPort = 0;
343 m_bySupportSecIdent = 0;
344 m_bSupportsPreview = 0;
345 m_nClientVersion = 0;
346 m_fSharedDirectories = 0;
347 m_bMultiPacket = 0;
348 m_fOsInfoSupport = 0;
349 m_fValueBasedTypeTags = 0;
350 SecIdentSupRec = 0;
351 m_byKadVersion = 0;
352 m_fRequestsCryptLayer = 0;
353 m_fSupportsCryptLayer = 0;
354 m_fRequiresCryptLayer = 0;
355 m_fSupportsSourceEx2 = 0;
356 m_fSupportsCaptcha = 0;
357 m_fDirectUDPCallback = 0;
358 m_bIsHybrid = false;
359 m_bIsML = false;
360 m_fNoViewSharedFiles = true; // that's a sensible default to assume until we get the real value
361 m_bUnicodeSupport = false;
364 bool CUpDownClient::ProcessHelloPacket(const byte* pachPacket, uint32 nSize)
366 const CMemFile data(pachPacket,nSize);
367 uint8 hashsize = data.ReadUInt8();
368 if ( 16 != hashsize ) {
370 * Hint: We can not accept other sizes here because:
371 * - the magic number is spread all over the source
372 * - the answer packet lacks the size field
374 throw wxString(wxT("Invalid Hello packet: Other userhash sizes than 16 are not implemented"));
376 // eMule 0.42: reset all client properties; a client may not send a particular emule tag any longer
377 ClearHelloProperties();
379 return ProcessHelloTypePacket(data);
382 void CUpDownClient::Safe_Delete()
384 // Because we are delaying the deletion, we might end up trying to delete
385 // it twice, however, this is normal and shouldn't trigger any failures
386 if ( m_clientState == CS_DYING ) {
387 return;
390 // If called from background, post an event to process it in main thread
391 if (!wxThread::IsMain()) {
392 CoreNotify_Client_Delete(CCLIENTREF(this, wxT("CUpDownClient::Safe_Delete CoreNotify_Client_Delete")));
393 return;
396 m_clientState = CS_DYING;
398 // Make sure client doesn't get deleted until this method is finished
399 CClientRef ref(CCLIENTREF(this, wxT("CUpDownClient::Safe_Delete reflocker")));
401 // Close the socket to avoid any more connections and related events
402 if ( m_socket ) {
403 m_socket->Safe_Delete();
404 // Paranoia
405 SetSocket(NULL);
408 // Remove the client from the clientlist if we still have it
409 if ( theApp->clientlist ) {
410 theApp->clientlist->RemoveClient( this );
413 // Doing what RemoveClient used to do. Just to be sure...
414 if (theApp->uploadqueue) {
415 theApp->uploadqueue->RemoveFromUploadQueue(this);
416 theApp->uploadqueue->RemoveFromWaitingQueue(this);
418 if (theApp->downloadqueue) {
419 theApp->downloadqueue->RemoveSource(this);
422 // For security, remove it from the lists unconditionally.
423 Notify_SharedCtrlRemoveClient(ECID(), (CKnownFile*)NULL);
424 Notify_SourceCtrlRemoveSource(ECID(), (CPartFile*)NULL);
426 if (IsAICHReqPending()){
427 m_fAICHRequested = FALSE;
428 CAICHHashSet::ClientAICHRequestFailed(this);
431 if (m_Friend) {
432 m_Friend->UnLinkClient(); // this notifies
433 m_Friend = NULL;
436 if (m_iRating>0 || !m_strComment.IsEmpty()) {
437 m_iRating = 0;
438 m_strComment.Clear();
439 if (m_reqfile) {
440 m_reqfile->UpdateFileRatingCommentAvail();
444 // Ensure that source-counts gets updated in case
445 // of a source not on the download-queue
446 SetRequestFile( NULL );
448 SetUploadFileID(NULL);
450 delete m_pReqFileAICHHash;
451 m_pReqFileAICHHash = NULL;
453 #ifdef DEBUG_ZOMBIE_CLIENTS
454 if (m_linked > 1) {
455 AddLogLineC(CFormat(wxT("Client %d still linked in %d places: %s")) % ECID() % (m_linked - 1) % GetLinkedFrom());
456 m_linkedDebug = true;
458 #endif
462 bool CUpDownClient::ProcessHelloAnswer(const byte* pachPacket, uint32 nSize)
464 const CMemFile data(pachPacket,nSize);
465 bool bIsMule = ProcessHelloTypePacket(data);
466 m_bHelloAnswerPending = false;
467 return bIsMule;
470 bool CUpDownClient::ProcessHelloTypePacket(const CMemFile& data)
472 uint32 dwEmuleTags = 0;
474 CMD4Hash hash = data.ReadHash();
475 SetUserHash( hash );
476 SetUserIDHybrid( data.ReadUInt32() );
477 uint16 nUserPort = data.ReadUInt16(); // hmm clientport is sent twice - why?
478 uint32 tagcount = data.ReadUInt32();
479 for (uint32 i = 0;i < tagcount; i++){
480 CTag temptag(data, true);
481 switch(temptag.GetNameID()){
482 case CT_NAME:
483 m_Username = temptag.GetStr();
484 break;
486 case CT_VERSION:
487 m_nClientVersion = temptag.GetInt();
488 break;
490 case ET_MOD_VERSION:
491 if (temptag.IsStr()) {
492 m_strModVersion = temptag.GetStr();
493 } else if (temptag.IsInt()) {
494 m_strModVersion = CFormat(wxT("ModID=%u")) % temptag.GetInt();
495 } else {
496 m_strModVersion = wxT("ModID=<Unknown>");
499 break;
501 case CT_PORT:
502 nUserPort = temptag.GetInt();
503 break;
505 case CT_EMULE_UDPPORTS:
506 // 16 KAD Port
507 // 16 UDP Port
508 SetKadPort((temptag.GetInt() >> 16) & 0xFFFF);
509 m_nUDPPort = temptag.GetInt() & 0xFFFF;
510 dwEmuleTags |= 1;
511 #ifdef __PACKET_DEBUG__
512 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule ports UDP=%i KAD=%i")) % m_nUDPPort % m_nKadPort);
513 #endif
514 break;
516 case CT_EMULE_BUDDYIP:
517 // 32 BUDDY IP
518 m_nBuddyIP = temptag.GetInt();
519 #ifdef __PACKET_DEBUG__
520 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule BuddyIP=%u (%s)")) % m_nBuddyIP % Uint32toStringIP(m_nBuddyIP));
521 #endif
522 break;
524 case CT_EMULE_BUDDYUDP:
525 // 16 --Reserved for future use--
526 // 16 BUDDY Port
527 m_nBuddyPort = (uint16)temptag.GetInt();
528 #ifdef __PACKET_DEBUG__
529 AddLogLineNS(CFormat(wxT("Hello type packet processing with eMule BuddyPort=%u")) % m_nBuddyPort);
530 #endif
531 break;
533 case CT_EMULE_MISCOPTIONS1: {
534 // 3 AICH Version (0 = not supported)
535 // 1 Unicode
536 // 4 UDP version
537 // 4 Data compression version
538 // 4 Secure Ident
539 // 4 Source Exchange
540 // 4 Ext. Requests
541 // 4 Comments
542 // 1 PeerCache supported
543 // 1 No 'View Shared Files' supported
544 // 1 MultiPacket
545 // 1 Preview
546 uint32 flags = temptag.GetInt();
547 m_fSupportsAICH = (flags >> (4*7+1)) & 0x07;
548 m_bUnicodeSupport = (flags >> 4*7) & 0x01;
549 m_byUDPVer = (flags >> 4*6) & 0x0f;
550 m_byDataCompVer = (flags >> 4*5) & 0x0f;
551 m_bySupportSecIdent = (flags >> 4*4) & 0x0f;
552 m_bySourceExchange1Ver = (flags >> 4*3) & 0x0f;
553 m_byExtendedRequestsVer = (flags >> 4*2) & 0x0f;
554 m_byAcceptCommentVer = (flags >> 4*1) & 0x0f;
555 m_fNoViewSharedFiles = (flags >> 1*2) & 0x01;
556 m_bMultiPacket = (flags >> 1*1) & 0x01;
557 m_fSupportsPreview = (flags >> 1*0) & 0x01;
558 dwEmuleTags |= 2;
559 #ifdef __PACKET_DEBUG__
560 AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options:"));
561 AddLogLineNS(CFormat(wxT("m_byUDPVer = %i")) % m_byUDPVer);
562 AddLogLineNS(CFormat(wxT("m_byDataCompVer = %i")) % m_byDataCompVer);
563 AddLogLineNS(CFormat(wxT("m_bySupportSecIdent = %i")) % m_bySupportSecIdent);
564 AddLogLineNS(CFormat(wxT("m_bySourceExchangeVer = %i")) % m_bySourceExchange1Ver);
565 AddLogLineNS(CFormat(wxT("m_byExtendedRequestsVer = %i")) % m_byExtendedRequestsVer);
566 AddLogLineNS(CFormat(wxT("m_byAcceptCommentVer = %i")) % m_byAcceptCommentVer);
567 AddLogLineNS(CFormat(wxT("m_fNoViewSharedFiles = %i")) % m_fNoViewSharedFiles);
568 AddLogLineNS(CFormat(wxT("m_bMultiPacket = %i")) % m_bMultiPacket);
569 AddLogLineNS(CFormat(wxT("m_fSupportsPreview = %i")) % m_fSharedDirectories);
570 AddLogLineNS(wxT("That's all."));
571 #endif
572 SecIdentSupRec += 1;
573 break;
576 case CT_EMULE_MISCOPTIONS2:
577 // 19 Reserved
578 // 1 Direct UDP Callback supported and available
579 // 1 Supports ChatCaptchas
580 // 1 Supports SourceExachnge2 Packets, ignores SX1 Packet Version
581 // 1 Requires CryptLayer
582 // 1 Requests CryptLayer
583 // 1 Supports CryptLayer
584 // 1 Reserved (ModBit)
585 // 1 Ext Multipacket (Hash+Size instead of Hash)
586 // 1 Large Files (includes support for 64bit tags)
587 // 4 Kad Version - will go up to version 15 only (may need to add another field at some point in the future)
588 m_fDirectUDPCallback = (temptag.GetInt() >> 12) & 0x01;
589 m_fSupportsCaptcha = (temptag.GetInt() >> 11) & 0x01;
590 m_fSupportsSourceEx2 = (temptag.GetInt() >> 10) & 0x01;
591 m_fRequiresCryptLayer = (temptag.GetInt() >> 9) & 0x01;
592 m_fRequestsCryptLayer = (temptag.GetInt() >> 8) & 0x01;
593 m_fSupportsCryptLayer = (temptag.GetInt() >> 7) & 0x01;
594 // reserved 1
595 m_fExtMultiPacket = (temptag.GetInt() >> 5) & 0x01;
596 m_fSupportsLargeFiles = (temptag.GetInt() >> 4) & 0x01;
597 m_byKadVersion = (temptag.GetInt() >> 0) & 0x0f;
598 dwEmuleTags |= 8;
600 m_fRequestsCryptLayer &= m_fSupportsCryptLayer;
601 m_fRequiresCryptLayer &= m_fRequestsCryptLayer;
603 #ifdef __PACKET_DEBUG__
604 AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options 2:"));
605 AddLogLineNS(CFormat(wxT(" m_fDirectUDPCallback = %i")) % m_fDirectUDPCallback);
606 AddLogLineNS(CFormat(wxT(" m_fSupportsCaptcha = %i")) % m_fSupportsCaptcha);
607 AddLogLineNS(CFormat(wxT(" m_fSupportsSourceEx2 = %i")) % m_fSupportsSourceEx2);
608 AddLogLineNS(CFormat(wxT(" m_fRequiresCryptLayer = %i")) % m_fRequiresCryptLayer);
609 AddLogLineNS(CFormat(wxT(" m_fRequestsCryptLayer = %i")) % m_fRequestsCryptLayer);
610 AddLogLineNS(CFormat(wxT(" m_fSupportsCryptLayer = %i")) % m_fSupportsCryptLayer);
611 AddLogLineNS(CFormat(wxT(" m_fExtMultiPacket = %i")) % m_fExtMultiPacket);
612 AddLogLineNS(CFormat(wxT(" m_fSupportsLargeFiles = %i")) % m_fSupportsLargeFiles);
613 AddLogLineNS(CFormat(wxT(" KadVersion = %u")) % m_byKadVersion);
614 AddLogLineNS(wxT("That's all."));
615 #endif
616 break;
618 // Special tag for Compat. Clients Misc options.
619 case CT_EMULECOMPAT_OPTIONS:
620 // 1 Operative System Info
621 // 1 Value-based-type int tags (experimental!)
622 m_fValueBasedTypeTags = (temptag.GetInt() >> 1*1) & 0x01;
623 m_fOsInfoSupport = (temptag.GetInt() >> 1*0) & 0x01;
624 break;
626 case CT_EMULE_VERSION:
627 // 8 Compatible Client ID
628 // 7 Mjr Version (Doesn't really matter..)
629 // 7 Min Version (Only need 0-99)
630 // 3 Upd Version (Only need 0-5)
631 // 7 Bld Version (Only need 0-99)
632 m_byCompatibleClient = (temptag.GetInt() >> 24);
633 m_nClientVersion = temptag.GetInt() & 0x00ffffff;
634 m_byEmuleVersion = 0x99;
635 m_fSharedDirectories = 1;
636 dwEmuleTags |= 4;
637 break;
641 m_nUserPort = nUserPort;
642 m_dwServerIP = data.ReadUInt32();
643 m_nServerPort = data.ReadUInt16();
644 // Hybrid now has an extra uint32.. What is it for?
645 // Also, many clients seem to send an extra 6? These are not eDonkeys or Hybrids..
646 if ( data.GetLength() - data.GetPosition() == sizeof(uint32) ) {
647 uint32 test = data.ReadUInt32();
648 /*if (test == 'KDLM') below kdlm is converted to ascii values.
649 This fixes a warning with gcc 3.4.
650 K=4b D=44 L=4c M=4d
652 if (test == 0x4b444c4d) { //if it's == "KDLM"
653 m_bIsML=true;
654 } else{
655 m_bIsHybrid = true;
656 m_fSharedDirectories = 1;
660 if (m_socket) {
661 SetIP(m_socket->GetPeerInt());
662 } else {
663 throw wxString(wxT("Huh, socket failure. Avoided crash this time."));
666 if (thePrefs::AddServersFromClient()) {
667 CServer* addsrv = new CServer(m_nServerPort, Uint32toStringIP(m_dwServerIP));
668 addsrv->SetListName(addsrv->GetAddress());
669 if (!theApp->AddServer(addsrv)) {
670 delete addsrv;
674 //(a)If this is a highID user, store the ID in the Hybrid format.
675 //(b)Some older clients will not send a ID, these client are HighID users that are not connected to a server.
676 //(c)Kad users with a *.*.*.0 IPs will look like a lowID user they are actually a highID user.. They can be detected easily
677 //because they will send a ID that is the same as their IP..
678 if(!HasLowID() || m_nUserIDHybrid == 0 || m_nUserIDHybrid == m_dwUserIP ) {
679 SetUserIDHybrid(wxUINT32_SWAP_ALWAYS(m_dwUserIP));
682 // get client credits
683 CClientCredits* pFoundCredits = theApp->clientcredits->GetCredit(m_UserHash);
684 if (credits == NULL){
685 credits = pFoundCredits;
686 if (!theApp->clientlist->ComparePriorUserhash(m_dwUserIP, m_nUserPort, pFoundCredits)){
687 AddDebugLogLineN( logClient, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed (Found in TrackedClientsList)") ) % GetUserName() % GetFullIP() );
688 Ban();
690 } else if (credits != pFoundCredits){
691 // userhash change ok, however two hours "waittime" before it can be used
692 credits = pFoundCredits;
693 AddDebugLogLineN( logClient, CFormat( wxT("Client: %s (%s) Banreason: Userhash changed") ) % GetUserName() % GetFullIP() );
694 Ban();
697 if ((m_Friend = theApp->friendlist->FindFriend(m_UserHash, m_dwUserIP, m_nUserPort)) != NULL){
698 m_Friend->LinkClient(CCLIENTREF(this, wxT("CUpDownClient::ProcessHelloTypePacket m_Friend->LinkClient")));
699 } else{
700 // avoid that an unwanted client instance keeps a friend slot
701 SetFriendSlot(false);
705 ReGetClientSoft();
707 m_byInfopacketsReceived |= IP_EDONKEYPROTPACK;
709 // check if at least CT_EMULEVERSION was received, all other tags are optional
710 bool bIsMule = (dwEmuleTags & 0x04) == 0x04;
711 if (bIsMule) {
712 m_bEmuleProtocol = true;
713 m_byInfopacketsReceived |= IP_EMULEPROTPACK;
716 if (GetKadPort() && GetKadVersion() > 1) {
717 Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(GetIP()), GetKadPort());
720 return bIsMule;
724 bool CUpDownClient::SendHelloPacket()
726 wxCHECK(m_socket != NULL, true);
728 // if IP is filtered, don't greet him but disconnect...
729 if (theApp->ipfilter->IsFiltered(m_socket->GetPeerInt())) {
730 if (Disconnected(wxT("IPFilter"))) {
731 Safe_Delete();
732 return false;
734 return true;
737 CMemFile data(128);
738 data.WriteUInt8(16); // size of userhash
739 SendHelloTypePacket(&data);
741 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_HELLO);
742 theStats::AddUpOverheadOther(packet->GetPacketSize());
743 SendPacket(packet,true);
744 m_bHelloAnswerPending = true;
745 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_HELLO to ") + GetFullIP() );
746 return true;
749 void CUpDownClient::SendMuleInfoPacket(bool bAnswer, bool OSInfo)
751 wxCHECK2(m_socket != NULL, return);
753 CPacket* packet = NULL;
754 CMemFile data;
756 data.WriteUInt8(CURRENT_VERSION_SHORT);
758 if (OSInfo) {
760 // Special MuleInfo packet for clients supporting it.
761 // This means aMule >= 2.0.0 and Hydranode
763 // Violently mark it as special Mule Info packet
764 // Sending this makes non-supporting-osinfo clients to refuse to read this
765 // packet. Anyway, this packet should NEVER get to non-supporting clients.
767 data.WriteUInt8(/*EMULE_PROTOCOL*/ 0xFF);
769 data.WriteUInt32(1); // One Tag (OS_INFO)
771 CTagString tag1(ET_OS_INFO,theApp->GetOSType());
772 tag1.WriteTagToFile(&data);
774 m_OSInfo_sent = true; // So we don't send it again
776 } else {
778 // Normal MuleInfo packet
780 // Kry - There's no point on upgrading to VBT tags here
781 // as no client supporting it uses mule info packet.
783 data.WriteUInt8(EMULE_PROTOCOL);
785 // Tag number
786 data.WriteUInt32(9);
788 CTagInt32 tag1(ET_COMPRESSION,1);
789 tag1.WriteTagToFile(&data);
790 CTagInt32 tag2(ET_UDPVER,4);
791 tag2.WriteTagToFile(&data);
792 CTagInt32 tag3(ET_UDPPORT, thePrefs::GetEffectiveUDPPort());
793 tag3.WriteTagToFile(&data);
794 CTagInt32 tag4(ET_SOURCEEXCHANGE,3);
795 tag4.WriteTagToFile(&data);
796 CTagInt32 tag5(ET_COMMENTS,1);
797 tag5.WriteTagToFile(&data);
798 CTagInt32 tag6(ET_EXTENDEDREQUEST,2);
799 tag6.WriteTagToFile(&data);
801 uint32 dwTagValue = (theApp->CryptoAvailable() ? 3 : 0);
802 // Kry - Needs the preview code from eMule
804 // set 'Preview supported' only if 'View Shared Files' allowed
805 if (thePrefs::CanSeeShares() != vsfaNobody) {
806 dwTagValue |= 128;
809 CTagInt32 tag7(ET_FEATURES, dwTagValue);
810 tag7.WriteTagToFile(&data);
812 CTagInt32 tag8(ET_COMPATIBLECLIENT,SO_AMULE);
813 tag8.WriteTagToFile(&data);
815 // Support for tag ET_MOD_VERSION
816 wxString mod_name(MOD_VERSION_LONG);
817 CTagString tag9(ET_MOD_VERSION, mod_name);
818 tag9.WriteTagToFile(&data);
819 // Maella end
823 packet = new CPacket(data, OP_EMULEPROT, (bAnswer ? OP_EMULEINFOANSWER : OP_EMULEINFO));
825 if (m_socket) {
826 theStats::AddUpOverheadOther(packet->GetPacketSize());
827 SendPacket(packet,true,true);
829 #ifdef __DEBUG__
830 if (!bAnswer) {
831 if (!OSInfo) {
832 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_EMULEINFO to ") + GetFullIP() );
833 } else {
834 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_EMULEINFO/OS_INFO to ") + GetFullIP() );
836 } else {
837 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_EMULEINFOANSWER to ") + GetFullIP() );
839 #endif
843 bool CUpDownClient::ProcessMuleInfoPacket(const byte* pachPacket, uint32 nSize)
845 uint8 protocol_version;
847 const CMemFile data(pachPacket,nSize);
849 // The version number part of this packet will soon be useless since
850 // it is only able to go to v.99. Why the version is a uint8 and why
851 // it was not done as a tag like the eDonkey hello packet is not known.
852 // Therefore, sooner or later, we are going to have to switch over to
853 // using the eDonkey hello packet to set the version. No sense making
854 // a third value sent for versions.
855 uint8 mule_version = data.ReadUInt8();
856 protocol_version = data.ReadUInt8();
857 uint32 tagcount = data.ReadUInt32();
858 if (protocol_version == 0xFF) {
859 // OS Info supporting clients sending a recycled Mule info packet
860 for (uint32 i = 0;i < tagcount; i++){
861 CTag temptag(data, true);
862 switch(temptag.GetNameID()){
863 case ET_OS_INFO:
864 // Special tag, only supporting clients (aMule/Hydranode)
865 // It was recycled from a mod's tag, so if the other side
866 // is not supporting OS Info, we're seriously fucked up :)
867 m_sClientOSInfo = temptag.GetStr();
869 // If we didn't send our OSInfo to this client, just send it
870 if (!m_OSInfo_sent) {
871 SendMuleInfoPacket(false,true);
874 UpdateStats();
876 break;
878 // Your ad... er... I mean TAG, here
880 default:
881 break;
884 } else {
885 // Old eMule sending tags
886 m_byCompatibleClient = 0;
887 m_byEmuleVersion = mule_version;
889 if( m_byEmuleVersion == 0x2B ) {
890 m_byEmuleVersion = 0x22;
893 if (!(m_bEmuleProtocol = (protocol_version == EMULE_PROTOCOL))) {
894 return false;
897 for (uint32 i = 0;i < tagcount; i++){
898 CTag temptag(data, false);
899 switch(temptag.GetNameID()){
900 case ET_COMPRESSION:
901 // Bits 31- 8: 0 - reserved
902 // Bits 7- 0: data compression version
903 m_byDataCompVer = temptag.GetInt();
904 break;
906 case ET_UDPPORT:
907 // Bits 31-16: 0 - reserved
908 // Bits 15- 0: UDP port
909 m_nUDPPort = temptag.GetInt();
910 break;
912 case ET_UDPVER:
913 // Bits 31- 8: 0 - reserved
914 // Bits 7- 0: UDP protocol version
915 m_byUDPVer = temptag.GetInt();
916 break;
918 case ET_SOURCEEXCHANGE:
919 // Bits 31- 8: 0 - reserved
920 // Bits 7- 0: source exchange protocol version
921 m_bySourceExchange1Ver = temptag.GetInt();
922 break;
924 case ET_COMMENTS:
925 // Bits 31- 8: 0 - reserved
926 // Bits 7- 0: comments version
927 m_byAcceptCommentVer = temptag.GetInt();
928 break;
930 case ET_EXTENDEDREQUEST:
931 // Bits 31- 8: 0 - reserved
932 // Bits 7- 0: extended requests version
933 m_byExtendedRequestsVer = temptag.GetInt();
934 break;
936 case ET_COMPATIBLECLIENT:
937 // Bits 31- 8: 0 - reserved
938 // Bits 7- 0: compatible client ID
939 m_byCompatibleClient = temptag.GetInt();
940 break;
942 case ET_FEATURES:
943 // Bits 31- 8: 0 - reserved
944 // Bit 7: Preview
945 // Bit 6- 0: secure identification
946 m_bySupportSecIdent = temptag.GetInt() & 3;
947 m_bSupportsPreview = (temptag.GetInt() & 128) > 0;
948 SecIdentSupRec += 2;
949 break;
951 case ET_MOD_VERSION:
952 if (temptag.IsStr()) {
953 m_strModVersion = temptag.GetStr();
954 } else if (temptag.IsInt()) {
955 m_strModVersion = CFormat(wxT("ModID=%u")) % temptag.GetInt();
956 } else {
957 m_strModVersion = wxT("ModID=<Unknown>");
960 break;
962 default:
963 AddDebugLogLineN( logPacketErrors,
964 CFormat( wxT("Unknown Mule tag (%s) from client: %s") )
965 % temptag.GetFullInfo()
966 % GetClientFullInfo()
969 break;
973 if( m_byDataCompVer == 0 ){
974 m_bySourceExchange1Ver = 0;
975 m_byExtendedRequestsVer = 0;
976 m_byAcceptCommentVer = 0;
977 m_nUDPPort = 0;
980 //implicitly supported options by older clients
981 //in the future do not use version to guess about new features
982 if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x22) {
983 m_byUDPVer = 1;
986 if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21) {
987 m_bySourceExchange1Ver = 1;
990 if(m_byEmuleVersion == 0x24) {
991 m_byAcceptCommentVer = 1;
994 // Shared directories are requested from eMule 0.28+ because eMule 0.27 has a bug in
995 // the OP_ASKSHAREDFILESDIR handler, which does not return the shared files for a
996 // directory which has a trailing backslash.
997 if(m_byEmuleVersion >= 0x28 && !m_bIsML) {// MLdonkey currently does not support shared directories
998 m_fSharedDirectories = 1;
1001 ReGetClientSoft();
1003 m_byInfopacketsReceived |= IP_EMULEPROTPACK;
1006 return (protocol_version == 0xFF); // This was a OS_Info?
1010 void CUpDownClient::SendHelloAnswer()
1012 wxCHECK2(m_socket != NULL, return);
1014 CMemFile data(128);
1015 SendHelloTypePacket(&data);
1016 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_HELLOANSWER);
1017 theStats::AddUpOverheadOther(packet->GetPacketSize());
1018 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_HELLOANSWER to ") + GetFullIP() );
1019 SendPacket(packet,true);
1023 void CUpDownClient::SendHelloTypePacket(CMemFile* data)
1025 data->WriteHash(thePrefs::GetUserHash());
1026 data->WriteUInt32(theApp->GetID());
1027 data->WriteUInt16(thePrefs::GetPort());
1029 uint32 tagcount = 6;
1031 if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) {
1032 tagcount += 2;
1034 tagcount ++; // eMule misc flags 2 (kad version)
1036 #ifdef __SVN__
1037 // Kry - This is the tagcount!!! Be sure to update it!!
1038 // Last update: CT_EMULECOMPAT_OPTIONS included
1039 data->WriteUInt32(tagcount + 1);
1040 #else
1041 data->WriteUInt32(tagcount); // NO MOD_VERSION
1042 #endif
1045 CTagString tagname(CT_NAME,thePrefs::GetUserNick());
1046 tagname.WriteTagToFile(data, utf8strRaw);
1048 CTagVarInt tagversion(CT_VERSION, EDONKEYVERSION, GetVBTTags() ? 0 : 32);
1049 tagversion.WriteTagToFile(data);
1050 // eMule UDP Ports
1052 uint32 kadUDPPort = 0;
1054 if(Kademlia::CKademlia::IsConnected()) {
1055 if (Kademlia::CKademlia::GetPrefs()->GetExternalKadPort() != 0 && Kademlia::CKademlia::GetPrefs()->GetUseExternKadPort() && Kademlia::CUDPFirewallTester::IsVerified()) {
1056 kadUDPPort = Kademlia::CKademlia::GetPrefs()->GetExternalKadPort();
1057 } else {
1058 kadUDPPort = Kademlia::CKademlia::GetPrefs()->GetInternKadPort();
1062 CTagVarInt tagUdpPorts(CT_EMULE_UDPPORTS, (kadUDPPort << 16) | ((uint32)thePrefs::GetEffectiveUDPPort()), GetVBTTags() ? 0 : 32);
1063 tagUdpPorts.WriteTagToFile(data);
1065 if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) {
1066 CTagVarInt tagBuddyIP(CT_EMULE_BUDDYIP, theApp->clientlist->GetBuddy()->GetIP(), GetVBTTags() ? 0 : 32);
1067 tagBuddyIP.WriteTagToFile(data);
1069 CTagVarInt tagBuddyPort(CT_EMULE_BUDDYUDP,
1070 // ( RESERVED )
1071 ((uint32)theApp->clientlist->GetBuddy()->GetUDPPort() )
1072 , GetVBTTags() ? 0 : 32);
1073 tagBuddyPort.WriteTagToFile(data);
1076 // aMule Version
1077 CTagVarInt tagMuleVersion(CT_EMULE_VERSION,
1078 (SO_AMULE << 24) |
1079 make_full_ed2k_version(VERSION_MJR, VERSION_MIN, VERSION_UPDATE)
1080 // | (RESERVED )
1081 , GetVBTTags() ? 0 : 32);
1082 tagMuleVersion.WriteTagToFile(data);
1085 // eMule Misc. Options #1
1086 const uint32 uUdpVer = 4;
1087 const uint32 uDataCompVer = 1;
1088 const uint32 uSupportSecIdent = theApp->CryptoAvailable() ? 3 : 0;
1089 const uint32 uSourceExchangeVer = 3;
1090 const uint32 uExtendedRequestsVer = 2;
1091 const uint32 uAcceptCommentVer = 1;
1092 const uint32 uNoViewSharedFiles = (thePrefs::CanSeeShares() == vsfaNobody) ? 1 : 0; // for backward compatibility this has to be a 'negative' flag
1093 const uint32 uMultiPacket = 1;
1094 const uint32 uSupportPreview = 0; // No network preview at all.
1095 const uint32 uPeerCache = 0; // No peercache for aMule, baby
1096 const uint32 uUnicodeSupport = 1;
1097 const uint32 nAICHVer = 1; // AICH is ENABLED right now.
1099 CTagVarInt tagMisOptions(CT_EMULE_MISCOPTIONS1,
1100 (nAICHVer << ((4*7)+1)) |
1101 (uUnicodeSupport << 4*7) |
1102 (uUdpVer << 4*6) |
1103 (uDataCompVer << 4*5) |
1104 (uSupportSecIdent << 4*4) |
1105 (uSourceExchangeVer << 4*3) |
1106 (uExtendedRequestsVer << 4*2) |
1107 (uAcceptCommentVer << 4*1) |
1108 (uPeerCache << 1*3) |
1109 (uNoViewSharedFiles << 1*2) |
1110 (uMultiPacket << 1*1) |
1111 (uSupportPreview << 1*0)
1112 , GetVBTTags() ? 0 : 32);
1113 tagMisOptions.WriteTagToFile(data);
1115 // eMule Misc. Options #2
1116 const uint32 uKadVersion = KADEMLIA_VERSION;
1117 const uint32 uSupportLargeFiles = 1;
1118 const uint32 uExtMultiPacket = 1;
1119 const uint32 uReserved = 0; // mod bit
1120 const uint32 uSupportsCryptLayer = thePrefs::IsClientCryptLayerSupported() ? 1 : 0;
1121 const uint32 uRequestsCryptLayer = thePrefs::IsClientCryptLayerRequested() ? 1 : 0;
1122 const uint32 uRequiresCryptLayer = thePrefs::IsClientCryptLayerRequired() ? 1 : 0;
1123 const uint32 uSupportsSourceEx2 = 1;
1124 #ifdef AMULE_DAEMON
1125 // captcha for daemon/remotegui not supported for now
1126 const uint32 uSupportsCaptcha = 0;
1127 #else
1128 const uint32 uSupportsCaptcha = 1;
1129 #endif
1130 // direct callback is only possible if connected to kad, tcp firewalled and verified UDP open (for example on a full cone NAT)
1131 const uint32 uDirectUDPCallback = (Kademlia::CKademlia::IsRunning() && Kademlia::CKademlia::IsFirewalled()
1132 && !Kademlia::CUDPFirewallTester::IsFirewalledUDP(true) && Kademlia::CUDPFirewallTester::IsVerified()) ? 1 : 0;
1134 CTagVarInt tagMisOptions2(CT_EMULE_MISCOPTIONS2,
1135 // (RESERVED )
1136 (uDirectUDPCallback << 12) |
1137 (uSupportsCaptcha << 11) |
1138 (uSupportsSourceEx2 << 10) |
1139 (uRequiresCryptLayer << 9) |
1140 (uRequestsCryptLayer << 8) |
1141 (uSupportsCryptLayer << 7) |
1142 (uReserved << 6) |
1143 (uExtMultiPacket << 5) |
1144 (uSupportLargeFiles << 4) |
1145 (uKadVersion << 0)
1146 , GetVBTTags() ? 0 : 32 );
1147 tagMisOptions2.WriteTagToFile(data);
1149 const uint32 nOSInfoSupport = 1; // We support OS_INFO
1150 const uint32 nValueBasedTypeTags = 0; // Experimental, disabled
1152 CTagVarInt tagMisCompatOptions(CT_EMULECOMPAT_OPTIONS,
1153 (nValueBasedTypeTags << 1*1) |
1154 (nOSInfoSupport << 1*0)
1155 , GetVBTTags() ? 0 : 32);
1157 tagMisCompatOptions.WriteTagToFile(data);
1159 #ifdef __SVN__
1160 wxString mod_name(MOD_VERSION_LONG);
1161 CTagString tagModName(ET_MOD_VERSION, mod_name);
1162 tagModName.WriteTagToFile(data);
1163 #endif
1165 uint32 dwIP = 0;
1166 uint16 nPort = 0;
1167 if (theApp->IsConnectedED2K()) {
1168 dwIP = theApp->serverconnect->GetCurrentServer()->GetIP();
1169 nPort = theApp->serverconnect->GetCurrentServer()->GetPort();
1171 data->WriteUInt32(dwIP);
1172 data->WriteUInt16(nPort);
1176 void CUpDownClient::ProcessMuleCommentPacket(const byte* pachPacket, uint32 nSize)
1178 if (!m_reqfile) {
1179 throw CInvalidPacket(wxT("Comment packet for unknown file"));
1182 if (!m_reqfile->IsPartFile()) {
1183 throw CInvalidPacket(wxT("Comment packet for completed file"));
1186 const CMemFile data(pachPacket, nSize);
1188 uint8 rating = data.ReadUInt8();
1189 if (rating > 5) {
1190 AddDebugLogLineN( logClient, wxString(wxT("Invalid Rating for file '")) << m_clientFilename << wxT("' received: ") << rating);
1191 m_iRating = 0;
1192 } else {
1193 m_iRating = rating;
1194 AddDebugLogLineN( logClient, wxString(wxT("Rating for file '")) << m_clientFilename << wxT("' received: ") << m_iRating);
1197 // The comment is unicoded, with a uin32 len and safe read
1198 // (won't break if string size is < than advertised len)
1199 // Truncated to MAXFILECOMMENTLEN size
1200 m_strComment = data.ReadString((GetUnicodeSupport() != utf8strNone), 4 /* bytes (it's a uint32)*/, true).Left(MAXFILECOMMENTLEN);
1202 AddDebugLogLineN( logClient, wxString(wxT("Description for file '")) << m_clientFilename << wxT("' received: ") << m_strComment);
1204 // Update file rating
1205 m_reqfile->UpdateFileRatingCommentAvail();
1209 void CUpDownClient::ClearDownloadBlockRequests()
1212 std::list<Requested_Block_Struct*>::iterator it = m_DownloadBlocks_list.begin();
1213 for (; it != m_DownloadBlocks_list.end(); ++it) {
1214 Requested_Block_Struct* cur_block = *it;
1216 if (m_reqfile){
1217 m_reqfile->RemoveBlockFromList(cur_block->StartOffset, cur_block->EndOffset);
1220 delete cur_block;
1223 m_DownloadBlocks_list.clear();
1227 std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin();
1228 for (; it != m_PendingBlocks_list.end(); ++it) {
1229 Pending_Block_Struct* pending = *it;
1231 if (m_reqfile) {
1232 m_reqfile->RemoveBlockFromList(pending->block->StartOffset, pending->block->EndOffset);
1235 delete pending->block;
1236 // Not always allocated
1237 if (pending->zStream){
1238 inflateEnd(pending->zStream);
1239 delete pending->zStream;
1242 delete pending;
1245 m_PendingBlocks_list.clear();
1250 bool CUpDownClient::Disconnected(const wxString& DEBUG_ONLY(strReason), bool bFromSocket)
1252 //wxASSERT(theApp->clientlist->IsValidClient(this));
1254 if (HasBeenDeleted()) {
1255 AddDebugLogLineN(logClient, wxT("Disconnected() called for already deleted client on ip ") + Uint32toStringIP(GetConnectIP()));
1256 return false;
1259 // was this a direct callback?
1260 if (m_dwDirectCallbackTimeout != 0) {
1261 theApp->clientlist->RemoveDirectCallback(this);
1262 m_dwDirectCallbackTimeout = 0;
1263 theApp->clientlist->AddDeadSource(this);
1264 AddDebugLogLineN(logClient, wxT("Direct callback failed to client on ip ") + Uint32toStringIP(GetConnectIP()));
1267 if (GetKadState() == KS_QUEUED_FWCHECK_UDP || GetKadState() == KS_CONNECTING_FWCHECK_UDP) {
1268 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test was cancelled
1269 } else if (GetKadState() == KS_FWCHECK_UDP) {
1270 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, false, wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0); // inform the tester that this test has failed
1271 } else if (GetKadState() == KS_CONNECTED_BUDDY) {
1272 AddDebugLogLineN(logClient, wxT("Buddy client disconnected - ") + strReason);
1275 //If this is a KAD client object, just delete it!
1276 SetKadState(KS_NONE);
1278 if (GetUploadState() == US_UPLOADING) {
1279 // sets US_NONE
1280 theApp->uploadqueue->RemoveFromUploadQueue(this);
1283 if (GetDownloadState() == DS_DOWNLOADING) {
1284 SetDownloadState(DS_ONQUEUE);
1285 } else {
1286 // ensure that all possible block requests are removed from the partfile
1287 ClearDownloadBlockRequests();
1289 if (GetDownloadState() == DS_CONNECTED) {
1290 // successfully connected, but probably didn't respond to our filerequest
1291 theApp->clientlist->AddDeadSource(this);
1292 theApp->downloadqueue->RemoveSource(this);
1296 // we had still an AICH request pending, handle it
1297 if (IsAICHReqPending()) {
1298 m_fAICHRequested = FALSE;
1299 CAICHHashSet::ClientAICHRequestFailed(this);
1302 // The remote client does not have to answer with OP_HASHSETANSWER *immediatly*
1303 // after we've sent OP_HASHSETREQUEST. It may occure that a (buggy) remote client
1304 // is sending use another OP_FILESTATUS which would let us change to DL-state to DS_ONQUEUE.
1305 if (((GetDownloadState() == DS_REQHASHSET) || m_fHashsetRequesting) && (m_reqfile)) {
1306 m_reqfile->SetHashSetNeeded(true);
1309 SourceItemType source_type = UNAVAILABLE_SOURCE;
1310 SourceItemType peer_type = UNAVAILABLE_SOURCE;
1312 //check if this client is needed in any way, if not delete it
1313 bool bDelete = true;
1314 switch (m_nUploadState) {
1315 case US_ONUPLOADQUEUE:
1316 bDelete = false;
1317 peer_type = AVAILABLE_SOURCE;
1318 break;
1321 switch (m_nDownloadState) {
1322 case DS_ONQUEUE:
1323 source_type = A4AF_SOURCE; // Will be checked.
1324 case DS_TOOMANYCONNS:
1325 case DS_NONEEDEDPARTS:
1326 case DS_LOWTOLOWIP:
1327 bDelete = false;
1328 break;
1331 switch (m_nUploadState) {
1332 case US_CONNECTING:
1333 case US_WAITCALLBACK:
1334 case US_ERROR:
1335 theApp->clientlist->AddDeadSource(this);
1336 bDelete = true;
1339 switch (m_nDownloadState) {
1340 case DS_CONNECTING:
1341 case DS_WAITCALLBACK:
1342 case DS_ERROR:
1343 case DS_BANNED:
1344 theApp->clientlist->AddDeadSource(this);
1345 bDelete = true;
1349 // We keep chat partners in any case
1350 if (GetChatState() != MS_NONE) {
1351 bDelete = false;
1352 m_pendingMessage.Clear();
1353 Notify_ChatConnResult(false,GUI_ID(GetIP(),GetUserPort()),wxEmptyString);
1356 // Delete socket
1357 if (!bFromSocket && m_socket) {
1358 wxASSERT (theApp->listensocket->IsValidSocket(m_socket));
1359 m_socket->Safe_Delete();
1362 SetSocket(NULL);
1364 if (m_iFileListRequested) {
1365 AddLogLineC(CFormat(_("Failed to retrieve shared files from user '%s'")) % GetUserName() );
1366 m_iFileListRequested = 0;
1370 if (bDelete) {
1371 if (m_Friend) {
1372 // Remove the friend linkage
1373 m_Friend->UnLinkClient(); // this notifies
1375 } else {
1376 Notify_SharedCtrlRefreshClient(ECID(), peer_type);
1377 Notify_SourceCtrlUpdateSource(ECID(), source_type);
1379 m_fHashsetRequesting = 0;
1380 SetSentCancelTransfer(0);
1381 m_bHelloAnswerPending = false;
1382 m_fSentOutOfPartReqs = 0;
1384 AddDebugLogLineN(logClient, CFormat(wxT("--- %s client D:%d U:%d \"%s\"; Reason was %s"))
1385 % (bDelete ? wxT("Deleted") : wxT("Disconnected"))
1386 % m_nDownloadState % m_nUploadState % GetClientFullInfo() % strReason );
1388 return bDelete;
1391 //Returned bool is not if the TryToConnect is successful or not..
1392 //false means the client was deleted!
1393 //true means the client was not deleted!
1394 bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon)
1396 // Kad reviewed
1397 if (theApp->listensocket->TooManySockets() && !bIgnoreMaxCon ) {
1398 if (!(m_socket && m_socket->IsConnected())) {
1399 if(Disconnected(wxT("Too many connections"))) {
1400 Safe_Delete();
1401 return false;
1403 return true;
1407 // 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)
1408 if ( (RequiresCryptLayer() && !thePrefs::IsClientCryptLayerSupported()) || (thePrefs::IsClientCryptLayerRequired() && !SupportsCryptLayer()) ){
1409 if(Disconnected(wxT("CryptLayer-Settings (Obfuscation) incompatible"))){
1410 Safe_Delete();
1411 return false;
1412 } else {
1413 return true;
1417 // Ipfilter check
1418 uint32 uClientIP = GetIP();
1419 if (uClientIP == 0 && !HasLowID()) {
1420 uClientIP = wxUINT32_SWAP_ALWAYS(m_nUserIDHybrid);
1423 if (uClientIP) {
1424 // Although we filter all received IPs (server sources, source exchange) and all incomming connection attempts,
1425 // we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list
1426 if (theApp->ipfilter->IsFiltered(uClientIP)) {
1427 AddDebugLogLineN(logIPFilter, CFormat(wxT("Filtered ip %u (%s) on TryToConnect\n")) % uClientIP % Uint32toStringIP(uClientIP));
1428 if (Disconnected(wxT("IPFilter"))) {
1429 Safe_Delete();
1430 return false;
1432 return true;
1435 // for safety: check again whether that IP is banned
1436 if (theApp->clientlist->IsBannedClient(uClientIP)) {
1437 AddDebugLogLineN(logClient, wxT("Refused to connect to banned client ") + Uint32toStringIP(uClientIP));
1438 if (Disconnected(wxT("Banned IP"))) {
1439 Safe_Delete();
1440 return false;
1442 return true;
1446 if (GetKadState() == KS_QUEUED_FWCHECK) {
1447 SetKadState(KS_CONNECTING_FWCHECK);
1448 } else if (GetKadState() == KS_QUEUED_FWCHECK_UDP) {
1449 SetKadState(KS_CONNECTING_FWCHECK_UDP);
1452 if (HasLowID()) {
1453 if (!theApp->CanDoCallback(GetServerIP(), GetServerPort())) {
1454 //We cannot do a callback!
1455 if (GetDownloadState() == DS_CONNECTING) {
1456 SetDownloadState(DS_LOWTOLOWIP);
1457 } else if (GetDownloadState() == DS_REQHASHSET) {
1458 SetDownloadState(DS_ONQUEUE);
1459 m_reqfile->SetHashSetNeeded(true);
1461 if (GetUploadState() == US_CONNECTING) {
1462 if(Disconnected(wxT("LowID->LowID and US_CONNECTING"))) {
1463 Safe_Delete();
1464 return false;
1467 return true;
1470 //We already know we are not firewalled here as the above condition already detected LowID->LowID and returned.
1471 //If ANYTHING changes with the "if(!theApp->CanDoCallback(this))" above that will let you fall through
1472 //with the condition that the source is firewalled and we are firewalled, we must
1473 //recheck it before the this check..
1474 if (HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp->serverconnect->IsLocalServer(GetServerIP(), GetServerPort())
1475 && !(SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0)) {
1476 //This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort.
1477 if( Kademlia::CKademlia::IsConnected() ) {
1478 //We are connect to Kad
1479 if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID()))) {
1480 //There are too many source lookups already or we are already searching this key.
1481 SetDownloadState(DS_TOOMANYCONNSKAD);
1482 return true;
1488 if (!m_socket || !m_socket->IsConnected()) {
1489 if (m_socket) {
1490 m_socket->Safe_Delete();
1492 m_socket = new CClientTCPSocket(this, thePrefs::GetProxyData());
1493 } else {
1494 ConnectionEstablished();
1495 return true;
1499 if (HasLowID() && SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0 && GetConnectIP() != 0) { // LOWID with DirectCallback
1500 if (m_dwDirectCallbackTimeout != 0) {
1501 AddDebugLogLineN(logClient, wxT("ERROR: Trying Direct UDP Callback while already trying to connect to client on ip ") + Uint32toStringIP(GetConnectIP()));
1502 return true; // We're already trying a direct connection to this client
1504 // a direct callback is possible - since no other parties are involved and only one additional packet overhead
1505 // is used we basically handle it like a normal connection try, no restrictions apply
1506 // we already check above with !theApp->CanDoCallback(this) if any callback is possible at all
1507 m_dwDirectCallbackTimeout = ::GetTickCount() + SEC2MS(45);
1508 theApp->clientlist->AddDirectCallbackClient(this);
1509 AddDebugLogLineN(logClient, CFormat(wxT("Direct Callback on port %u to client on ip %s")) % GetKadPort() % Uint32toStringIP(GetConnectIP()));
1511 CMemFile data;
1512 data.WriteUInt16(thePrefs::GetPort()); // needs to know our port
1513 data.WriteHash(thePrefs::GetUserHash()); // and userhash
1514 // our connection settings
1515 data.WriteUInt8(Kademlia::CPrefs::GetMyConnectOptions(true, false));
1516 AddDebugLogLineN(logClientUDP, wxT("Sending OP_DIRECTCALLBACKREQ to ") + Uint32_16toStringIP_Port(GetConnectIP(), GetKadPort()));
1517 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_DIRECTCALLBACKREQ);
1518 theStats::AddUpOverheadOther(packet->GetPacketSize());
1519 theApp->clientudp->SendPacket(packet, GetConnectIP(), GetKadPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0);
1520 } else if (HasLowID()) { // LOWID
1521 if (GetDownloadState() == DS_CONNECTING) {
1522 SetDownloadState(DS_WAITCALLBACK);
1524 if (GetUploadState() == US_CONNECTING) {
1525 if(Disconnected(wxT("LowID and US_CONNECTING"))) {
1526 Safe_Delete();
1527 return false;
1529 return true;
1532 if (theApp->serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)) {
1533 CMemFile data;
1534 // AFAICS, this id must be reversed to be sent to clients
1535 // But if I reverse it, we do a serve violation ;)
1536 data.WriteUInt32(m_nUserIDHybrid);
1537 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_CALLBACKREQUEST);
1538 theStats::AddUpOverheadServer(packet->GetPacketSize());
1539 AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_CALLBACKREQUEST to ") + GetFullIP());
1540 theApp->serverconnect->SendPacket(packet);
1541 SetDownloadState(DS_WAITCALLBACK);
1542 } else {
1543 if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending)) {
1545 if( !HasValidBuddyID() ) {
1546 theApp->downloadqueue->RemoveSource(this);
1547 if (Disconnected(wxT("LowID and US_NONE and QR=0"))) {
1548 Safe_Delete();
1549 return false;
1551 return true;
1554 if( !Kademlia::CKademlia::IsConnected() ) {
1555 //We are not connected to Kad and this is a Kad Firewalled source..
1556 theApp->downloadqueue->RemoveSource(this);
1557 if(Disconnected(wxT("Kad Firewalled source but not connected to Kad."))) {
1558 Safe_Delete();
1559 return false;
1561 return true;
1564 if( GetDownloadState() == DS_WAITCALLBACK ) {
1565 if( GetBuddyIP() && GetBuddyPort()) {
1566 CMemFile bio(34);
1567 bio.WriteUInt128(Kademlia::CUInt128(GetBuddyID()));
1568 bio.WriteUInt128(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash()));
1569 bio.WriteUInt16(thePrefs::GetPort());
1570 CPacket* packet = new CPacket(bio, OP_KADEMLIAHEADER, KADEMLIA_CALLBACK_REQ);
1571 // eMule FIXME: We don't know which kadversion the buddy has, so we need to send unencrypted
1572 theApp->clientudp->SendPacket(packet, GetBuddyIP(), GetBuddyPort(), false, NULL, true, 0);
1573 AddDebugLogLineN(logClientKadUDP, CFormat(wxT("KadCallbackReq (size=%i) to %s")) % packet->GetPacketSize() % Uint32_16toStringIP_Port(GetBuddyIP(), GetBuddyPort()));
1574 theStats::AddUpOverheadKad(packet->GetRealPacketSize());
1575 SetDownloadState(DS_WAITCALLBACKKAD);
1576 } else {
1577 AddLogLineN(_("Searching buddy for lowid connection"));
1578 //Create search to find buddy.
1579 Kademlia::CSearch *findSource = new Kademlia::CSearch;
1580 findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE);
1581 findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID()));
1582 findSource->AddFileID(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash()));
1583 if(Kademlia::CSearchManager::StartSearch(findSource)) {
1584 //Started lookup..
1585 SetDownloadState(DS_WAITCALLBACKKAD);
1586 } else {
1587 //This should never happen..
1588 wxFAIL;
1592 } else {
1593 if (GetDownloadState() == DS_WAITCALLBACK) {
1594 m_bReaskPending = true;
1595 SetDownloadState(DS_ONQUEUE);
1599 } else { // HIGHID
1600 if (!Connect()) {
1601 return false;
1604 return true;
1607 bool CUpDownClient::Connect()
1609 m_hasbeenobfuscatinglately = false;
1611 if (!m_socket->IsOk()) {
1612 // Enable or disable crypting based on our and the remote clients preference
1613 if (HasValidHash() && SupportsCryptLayer() && thePrefs::IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested())){
1614 m_socket->SetConnectionEncryption(true, GetUserHash().GetHash(), false);
1615 } else {
1616 m_socket->SetConnectionEncryption(false, NULL, false);
1618 amuleIPV4Address tmp;
1619 tmp.Hostname(GetConnectIP());
1620 tmp.Service(GetUserPort());
1621 AddDebugLogLineN(logClient, wxT("Trying to connect to ") + Uint32_16toStringIP_Port(GetConnectIP(),GetUserPort()));
1622 m_socket->Connect(tmp, false);
1623 // We should send hello packets AFTER connecting!
1624 // so I moved it to OnConnect
1625 return true;
1626 } else {
1627 return false;
1631 void CUpDownClient::ConnectionEstablished()
1633 /* Kry - First thing, check if this client was just used to retrieve
1634 info. That's some debug thing for myself... check connection_reason
1635 definition */
1637 m_hasbeenobfuscatinglately = (m_socket && m_socket->IsConnected() && m_socket->IsObfusicating());
1639 #ifdef __DEBUG__
1640 if (!connection_reason.IsEmpty()) {
1641 AddLogLineN(CFormat(wxT("Got client info checking for %s: %s\nDisconnecting and deleting.")) % connection_reason % GetClientFullInfo());
1642 connection_reason.Clear(); // So we don't re-print on destructor.
1643 Safe_Delete();
1644 return;
1646 #endif
1648 // Check if we should use this client to retrieve our public IP
1649 // Ignore local ip on GetPublicIP (could be wrong)
1650 if (theApp->GetPublicIP(true) == 0 && theApp->IsConnectedED2K()) {
1651 SendPublicIPRequest();
1654 // was this a direct callback?
1655 if (m_dwDirectCallbackTimeout != 0){
1656 theApp->clientlist->RemoveDirectCallback(this);
1657 m_dwDirectCallbackTimeout = 0;
1658 AddDebugLogLineN(logClient, wxT("Direct Callback succeeded, connection established to ") + Uint32toStringIP(GetConnectIP()));
1661 switch (GetKadState()) {
1662 case KS_CONNECTING_FWCHECK:
1663 SetKadState(KS_CONNECTED_FWCHECK);
1664 break;
1665 case KS_CONNECTING_BUDDY:
1666 case KS_INCOMING_BUDDY:
1667 SetKadState(KS_CONNECTED_BUDDY);
1668 break;
1669 case KS_CONNECTING_FWCHECK_UDP:
1670 SetKadState(KS_FWCHECK_UDP);
1671 SendFirewallCheckUDPRequest();
1672 break;
1673 default:
1674 break;
1677 // ok we have a connection, lets see if we want anything from this client
1678 if (GetChatState() == MS_CONNECTING) {
1679 SetChatState( MS_CHATTING );
1682 if (GetChatState() == MS_CHATTING) {
1683 bool result = true;
1684 if (!m_pendingMessage.IsEmpty()) {
1685 result = SendChatMessage(m_pendingMessage);
1687 Notify_ChatConnResult(result,GUI_ID(GetIP(),GetUserPort()),m_pendingMessage);
1688 m_pendingMessage.Clear();
1691 switch(GetDownloadState()) {
1692 case DS_CONNECTING:
1693 case DS_WAITCALLBACK:
1694 case DS_WAITCALLBACKKAD:
1695 m_bReaskPending = false;
1696 SetDownloadState(DS_CONNECTED);
1697 SendFileRequest();
1699 if (m_bReaskPending){
1700 m_bReaskPending = false;
1701 if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING) {
1702 SetDownloadState(DS_CONNECTED);
1703 SendFileRequest();
1706 switch(GetUploadState()){
1707 case US_CONNECTING:
1708 case US_WAITCALLBACK:
1709 if (theApp->uploadqueue->IsDownloading(this)) {
1710 SetUploadState(US_UPLOADING);
1711 CPacket* packet = new CPacket(OP_ACCEPTUPLOADREQ, 0, OP_EDONKEYPROT);
1712 theStats::AddUpOverheadFileRequest(packet->GetPacketSize());
1713 SendPacket(packet,true);
1714 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + GetFullIP() );
1717 if (m_iFileListRequested == 1) {
1718 CPacket* packet = new CPacket(m_fSharedDirectories ? OP_ASKSHAREDDIRS : OP_ASKSHAREDFILES, 0, OP_EDONKEYPROT);
1719 theStats::AddUpOverheadOther(packet->GetPacketSize());
1720 SendPacket(packet,true,true);
1721 #ifdef __DEBUG__
1722 if (m_fSharedDirectories) {
1723 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRS to ") + GetFullIP() );
1724 } else {
1725 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILES to ") + GetFullIP() );
1727 #endif
1730 while (!m_WaitingPackets_list.empty()) {
1731 CPacket* packet = m_WaitingPackets_list.front();
1732 m_WaitingPackets_list.pop_front();
1734 SendPacket(packet);
1739 int CUpDownClient::GetHashType() const
1741 if ( m_UserHash[5] == 13 && m_UserHash[14] == 110 ) {
1742 return SO_OLDEMULE;
1745 if ( m_UserHash[5] == 14 && m_UserHash[14] == 111 ) {
1746 return SO_EMULE;
1749 if ( m_UserHash[5] == 'M' && m_UserHash[14] == 'L' ) {
1750 return SO_MLDONKEY;
1753 return SO_UNKNOWN;
1757 void CUpDownClient::SetSocket(CClientTCPSocket* socket)
1759 #ifdef __DEBUG__
1760 if (m_socket == NULL && socket != NULL) {
1761 theStats::SocketAssignedToClient();
1762 } else if (m_socket != NULL && socket == NULL) {
1763 theStats::SocketUnassignedFromClient();
1765 #endif
1766 m_socket = socket;
1770 void CUpDownClient::ReGetClientSoft()
1772 if (m_Username.IsEmpty()) {
1773 m_clientSoft=SO_UNKNOWN;
1774 m_clientVerString = m_clientSoftString = m_clientVersionString = m_fullClientVerString = _("Unknown");
1775 UpdateStats();
1776 return;
1779 int iHashType = GetHashType();
1780 wxString clientModString;
1781 if (iHashType == SO_EMULE) {
1783 m_clientSoft = m_byCompatibleClient;
1784 m_clientSoftString = GetSoftName(m_clientSoft);
1785 // Special issues:
1786 if(!GetClientModString().IsEmpty() && (m_clientSoft != SO_EMULE)) {
1787 m_clientSoftString = GetClientModString();
1789 // Isn't xMule annoying?
1790 if ((m_clientSoft == SO_LXMULE) && (GetMuleVersion() > 0x26) && (GetMuleVersion() != 0x99)) {
1791 m_clientSoftString += CFormat(_(" (Fake eMule version %#x)")) % GetMuleVersion();
1793 if ((m_clientSoft == SO_EMULE) &&
1795 wxString(GetClientModString()).MakeLower().Find(wxT("xmule")) != -1
1796 || GetUserName().Find(wxT("xmule.")) != -1
1799 // FAKE eMule -a newer xMule faking is ident.
1800 m_clientSoft = SO_LXMULE;
1801 if (GetClientModString().IsEmpty() == false) {
1802 m_clientSoftString = GetClientModString() + _(" (Fake eMule)");
1803 } else {
1804 m_clientSoftString = _("xMule (Fake eMule)"); // don't use GetSoftName, it's not lmule.
1807 // Now, what if we don't know this SO_ID?
1808 if (m_clientSoftString.IsEmpty()) {
1809 if(m_bIsML) {
1810 m_clientSoft = SO_MLDONKEY;
1811 m_clientSoftString = GetSoftName(m_clientSoft);
1812 } else if (m_bIsHybrid) {
1813 m_clientSoft = SO_EDONKEYHYBRID;
1814 m_clientSoftString = GetSoftName(m_clientSoft);
1815 } else if (m_byCompatibleClient != 0) {
1816 m_clientSoft = SO_COMPAT_UNK;
1817 #ifdef __DEBUG__
1818 if (
1819 // Exceptions:
1820 (m_byCompatibleClient != 0xf0) // Chinese leech mod
1821 && (1==1) // Your ad here
1823 AddLogLineNS(CFormat(wxT("Compatible client found with ET_COMPATIBLECLIENT of %x")) % m_byCompatibleClient);
1825 #endif
1826 m_clientSoftString = CFormat(wxT("%s(%#x)")) % GetSoftName(m_clientSoft) % m_byCompatibleClient;
1827 } else {
1828 // If we step here, it might mean 2 things:
1829 // a eMule
1830 // a Compat Client that has sent no MuleInfo packet yet.
1831 m_clientSoft = SO_EMULE;
1832 m_clientSoftString = wxT("eMule");
1836 if (m_byEmuleVersion == 0) {
1837 m_nClientVersion = MAKE_CLIENT_VERSION(0,0,0);
1838 } else if (m_byEmuleVersion != 0x99) {
1839 uint32 nClientMinVersion = (m_byEmuleVersion >> 4)*10 + (m_byEmuleVersion & 0x0f);
1840 m_nClientVersion = MAKE_CLIENT_VERSION(0,nClientMinVersion,0);
1841 switch (m_clientSoft) {
1842 case SO_AMULE:
1843 m_clientVerString = CFormat(_("1.x (based on eMule v0.%u)")) % nClientMinVersion;
1844 break;
1845 case SO_LPHANT:
1846 m_clientVerString = wxT("< v0.05");
1847 break;
1848 default:
1849 clientModString = GetClientModString();
1850 m_clientVerString = CFormat(wxT("v0.%u")) % nClientMinVersion;
1851 break;
1853 } else {
1854 uint32 nClientMajVersion = (m_nClientVersion >> 17) & 0x7f;
1855 uint32 nClientMinVersion = (m_nClientVersion >> 10) & 0x7f;
1856 uint32 nClientUpVersion = (m_nClientVersion >> 7) & 0x07;
1858 m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
1860 switch (m_clientSoft) {
1861 case SO_AMULE:
1862 case SO_LXMULE:
1863 case SO_HYDRANODE:
1864 case SO_MLDONKEY:
1865 case SO_NEW_MLDONKEY:
1866 case SO_NEW2_MLDONKEY:
1867 // Kry - xMule started sending correct version tags on 1.9.1b.
1868 // It only took them 4 months, and being told by me and the
1869 // eMule+ developers, so I think they're slowly getting smarter.
1870 // They are based on our implementation, so we use the same format
1871 // for the version string.
1872 m_clientVerString = CFormat(wxT("v%u.%u.%u")) % nClientMajVersion % nClientMinVersion % nClientUpVersion;
1873 break;
1874 case SO_LPHANT:
1875 m_clientVerString = CFormat(wxT(" v%u.%.2u%c")) % (nClientMajVersion-1) % nClientMinVersion % ('a' + nClientUpVersion);
1876 break;
1877 case SO_EMULEPLUS:
1878 m_clientVerString = CFormat(wxT("v%u")) % nClientMajVersion;
1879 if(nClientMinVersion != 0) {
1880 m_clientVerString += CFormat(wxT(".%u")) % nClientMinVersion;
1882 if(nClientUpVersion != 0) {
1883 m_clientVerString += CFormat(wxT("%c")) % ('a' + nClientUpVersion - 1);
1885 break;
1886 default:
1887 clientModString = GetClientModString();
1888 m_clientVerString = CFormat(wxT("v%u.%u%c")) % nClientMajVersion % nClientMinVersion % ('a' + nClientUpVersion);
1889 break;
1892 } else if (m_bIsHybrid) {
1893 // seen:
1894 // 105010 50.10
1895 // 10501 50.1
1896 // 1051 51.0
1897 // 501 50.1
1899 m_clientSoft = SO_EDONKEYHYBRID;
1900 m_clientSoftString = GetSoftName(m_clientSoft);
1902 uint32 nClientMajVersion;
1903 uint32 nClientMinVersion;
1904 uint32 nClientUpVersion;
1905 if (m_nClientVersion > 100000) {
1906 uint32 uMaj = m_nClientVersion/100000;
1907 nClientMajVersion = uMaj - 1;
1908 nClientMinVersion = (m_nClientVersion - uMaj*100000) / 100;
1909 nClientUpVersion = m_nClientVersion % 100;
1911 else if (m_nClientVersion > 10000) {
1912 uint32 uMaj = m_nClientVersion/10000;
1913 nClientMajVersion = uMaj - 1;
1914 nClientMinVersion = (m_nClientVersion - uMaj*10000) / 10;
1915 nClientUpVersion = m_nClientVersion % 10;
1917 else if (m_nClientVersion > 1000) {
1918 uint32 uMaj = m_nClientVersion/1000;
1919 nClientMajVersion = uMaj - 1;
1920 nClientMinVersion = m_nClientVersion - uMaj*1000;
1921 nClientUpVersion = 0;
1923 else if (m_nClientVersion > 100) {
1924 uint32 uMin = m_nClientVersion/10;
1925 nClientMajVersion = 0;
1926 nClientMinVersion = uMin;
1927 nClientUpVersion = m_nClientVersion - uMin*10;
1929 else{
1930 nClientMajVersion = 0;
1931 nClientMinVersion = m_nClientVersion;
1932 nClientUpVersion = 0;
1934 m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion);
1935 if (nClientUpVersion) {
1936 m_clientVerString = CFormat(wxT("v%u.%u.%u")) % nClientMajVersion % nClientMinVersion % nClientUpVersion;
1937 } else {
1938 m_clientVerString = CFormat(wxT("v%u.%u")) % nClientMajVersion % nClientMinVersion;
1940 } else if (m_bIsML || (iHashType == SO_MLDONKEY)) {
1941 m_clientSoft = SO_MLDONKEY;
1942 m_clientSoftString = GetSoftName(m_clientSoft);
1943 uint32 nClientMinVersion = m_nClientVersion;
1944 m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
1945 m_clientVerString = CFormat(wxT("v0.%u")) % nClientMinVersion;
1946 } else if (iHashType == SO_OLDEMULE) {
1947 m_clientSoft = SO_OLDEMULE;
1948 m_clientSoftString = GetSoftName(m_clientSoft);
1949 uint32 nClientMinVersion = m_nClientVersion;
1950 m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0);
1951 m_clientVerString = CFormat(wxT("v0.%u")) % nClientMinVersion;
1952 } else {
1953 m_clientSoft = SO_EDONKEY;
1954 m_clientSoftString = GetSoftName(m_clientSoft);
1955 m_nClientVersion *= 10;
1956 m_clientVerString = CFormat(wxT("v%u.%u")) % (m_nClientVersion / 100000) % ((m_nClientVersion / 1000) % 100);
1959 m_clientVersionString = m_clientVerString;
1960 if (!clientModString.IsEmpty()) {
1961 m_clientVerString += wxT(" - ") + clientModString;
1963 m_fullClientVerString = m_clientSoftString + wxT(" ") + m_clientVerString;
1965 UpdateStats();
1968 void CUpDownClient::RequestSharedFileList()
1970 if (m_iFileListRequested == 0) {
1971 AddDebugLogLineN( logClient, wxString( wxT("Requesting shared files from ") ) + GetUserName() );
1972 m_iFileListRequested = 1;
1973 TryToConnect(true);
1974 } else {
1975 AddDebugLogLineN( logClient, CFormat( wxT("Requesting shared files from user %s (%u) is already in progress") ) % GetUserName() % GetUserIDHybrid() );
1980 void CUpDownClient::ProcessSharedFileList(const byte* pachPacket, uint32 nSize, wxString& pszDirectory)
1982 if (m_iFileListRequested > 0) {
1983 m_iFileListRequested--;
1984 theApp->searchlist->ProcessSharedFileList(pachPacket, nSize, this, NULL, pszDirectory);
1989 void CUpDownClient::ResetFileStatusInfo()
1991 m_nPartCount = 0;
1993 if ( m_reqfile ) {
1994 m_reqfile->UpdatePartsFrequency( this, false );
1996 m_downPartStatus.clear();
1998 m_clientFilename.Clear();
2000 m_bCompleteSource = false;
2001 m_dwLastAskedTime = 0;
2002 m_iRating = 0;
2003 m_strComment.Clear();
2005 if (m_pReqFileAICHHash != NULL) {
2006 delete m_pReqFileAICHHash;
2007 m_pReqFileAICHHash = NULL;
2012 wxString CUpDownClient::GetUploadFileInfo()
2014 // build info text and display it
2015 wxString sRet;
2016 sRet = (CFormat(_("NickName: %s ID: %u")) % GetUserName() % GetUserIDHybrid()) + wxT(" ");
2017 if (m_reqfile) {
2018 sRet += CFormat(_("Requested: %s\n")) % m_reqfile->GetFileName();
2019 sRet += CFormat(
2020 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())
2021 ) % m_reqfile->statistic.GetAccepts() % m_reqfile->statistic.GetRequests() % CastItoXBytes(m_reqfile->statistic.GetTransferred());
2022 sRet += CFormat(
2023 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())
2024 ) % m_reqfile->statistic.GetAllTimeAccepts() % m_reqfile->statistic.GetAllTimeRequests() % CastItoXBytes(m_reqfile->statistic.GetAllTimeTransferred());
2025 } else {
2026 sRet += _("Requested unknown file");
2028 return sRet;
2031 // sends a packet, if needed it will establish a connection before
2032 // options used: ignore max connections, control packet, delete packet
2033 // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails
2034 bool CUpDownClient::SafeSendPacket(CPacket* packet)
2036 if (IsConnected()) {
2037 SendPacket(packet, true);
2038 return true;
2039 } else {
2040 m_WaitingPackets_list.push_back(packet);
2041 return TryToConnect(true);
2045 void CUpDownClient::SendPublicKeyPacket()
2047 // send our public key to the client who requested it
2048 wxCHECK2(m_socket != NULL, return);
2049 wxCHECK2(credits != NULL, return);
2050 wxCHECK2(m_SecureIdentState == IS_KEYANDSIGNEEDED, return);
2052 if (!theApp->CryptoAvailable())
2053 return;
2055 CMemFile data;
2056 data.WriteUInt8(theApp->clientcredits->GetPubKeyLen());
2057 data.Write(theApp->clientcredits->GetPublicKey(), theApp->clientcredits->GetPubKeyLen());
2058 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_PUBLICKEY);
2060 theStats::AddUpOverheadOther(packet->GetPacketSize());
2061 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICKEY to ") + GetFullIP() );
2062 SendPacket(packet,true,true);
2063 m_SecureIdentState = IS_SIGNATURENEEDED;
2067 void CUpDownClient::SendSignaturePacket()
2069 // signate the public key of this client and send it
2070 wxCHECK2(m_socket != NULL, return);
2071 wxCHECK2(credits != NULL, return);
2072 wxCHECK2(m_SecureIdentState != 0, return);
2074 if (!theApp->CryptoAvailable()) {
2075 return;
2077 if (credits->GetSecIDKeyLen() == 0) {
2078 return; // We don't have his public key yet, will be back here later
2080 // do we have a challenge value received (actually we should if we are in this function)
2081 if (credits->m_dwCryptRndChallengeFrom == 0){
2082 AddDebugLogLineN( logClient, wxString(wxT("Want to send signature but challenge value is invalid - User ")) + GetUserName());
2083 return;
2085 // v2
2086 // we will use v1 as default, except if only v2 is supported
2087 bool bUseV2;
2088 if ( (m_bySupportSecIdent&1) == 1 )
2089 bUseV2 = false;
2090 else
2091 bUseV2 = true;
2093 uint8 byChaIPKind = 0;
2094 uint32 ChallengeIP = 0;
2095 if (bUseV2){
2096 if (::IsLowID(theApp->GetED2KID())) {
2097 // we cannot do not know for sure our public ip, so use the remote clients one
2098 ChallengeIP = GetIP();
2099 byChaIPKind = CRYPT_CIP_REMOTECLIENT;
2100 } else {
2101 ChallengeIP = theApp->GetED2KID();
2102 byChaIPKind = CRYPT_CIP_LOCALCLIENT;
2105 //end v2
2106 byte achBuffer[250];
2108 uint8 siglen = theApp->clientcredits->CreateSignature(credits, achBuffer, 250, ChallengeIP, byChaIPKind );
2109 wxCHECK2(siglen != 0, return);
2111 CMemFile data;
2112 data.WriteUInt8(siglen);
2113 data.Write(achBuffer, siglen);
2114 if (bUseV2) {
2115 data.WriteUInt8(byChaIPKind);
2118 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SIGNATURE);
2120 theStats::AddUpOverheadOther(packet->GetPacketSize());
2121 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_SIGNATURE to ") + GetFullIP() );
2122 SendPacket(packet,true,true);
2123 m_SecureIdentState = IS_ALLREQUESTSSEND;
2127 void CUpDownClient::ProcessPublicKeyPacket(const byte* pachPacket, uint32 nSize)
2129 theApp->clientlist->AddTrackClient(this);
2131 wxCHECK2(m_socket != NULL, return);
2132 wxCHECK2(credits != NULL, return);
2133 if (pachPacket[0] != nSize - 1) {
2134 AddDebugLogLineN(logClient, CFormat(wxT("Inconsistent packet size (%d != %d)")) % pachPacket[0] % (nSize - 1));
2135 return;
2137 if (nSize == 0) {
2138 AddDebugLogLineN(logClient, wxT("Invalid packet size (0)"));
2139 return;
2141 if (nSize > 250) {
2142 AddDebugLogLineN(logClient, CFormat(wxT("Invalid packet size (%d > 250)")) % nSize);
2143 return;
2145 if (!theApp->CryptoAvailable())
2146 return;
2147 // the function will handle everything (mulitple key etc)
2148 if (credits->SetSecureIdent(pachPacket+1, pachPacket[0])){
2149 // if this client wants a signature, now we can send him one
2150 if (m_SecureIdentState == IS_SIGNATURENEEDED){
2151 SendSignaturePacket();
2153 else if (m_SecureIdentState == IS_KEYANDSIGNEEDED) {
2154 // something is wrong
2155 AddDebugLogLineN( logClient, wxT("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket") );
2157 } else {
2158 AddDebugLogLineN( logClient, wxT("Failed to use new received public key") );
2163 void CUpDownClient::ProcessSignaturePacket(const byte* pachPacket, uint32 nSize)
2165 // here we spread the good guys from the bad ones ;)
2167 wxCHECK2(m_socket != NULL, return);
2168 wxCHECK2(credits != NULL, return);
2169 if (nSize == 0) {
2170 AddDebugLogLineN(logClient, wxT("Invalid packet size (0)"));
2171 return;
2173 if (nSize > 250) {
2174 AddDebugLogLineN(logClient, CFormat(wxT("Invalid packet size (%d > 250)")) % nSize);
2175 return;
2178 uint8 byChaIPKind;
2179 if (pachPacket[0] == nSize-1)
2180 byChaIPKind = 0;
2181 else if (pachPacket[0] == nSize-2 && (m_bySupportSecIdent & 2) > 0) //v2
2182 byChaIPKind = pachPacket[nSize-1];
2183 else {
2184 // Unknown or invalid format
2185 AddDebugLogLineN(logClient, wxT("Invalid or unknown challenge format - ignoring"));
2186 return;
2189 if (!theApp->CryptoAvailable())
2190 return;
2192 // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions
2193 if (m_dwLastSignatureIP == GetIP()){
2194 AddDebugLogLineN( logClient, wxT("received multiple signatures from one client") );
2195 return;
2197 // also make sure this client has a public key
2198 if (credits->GetSecIDKeyLen() == 0){
2199 AddDebugLogLineN( logClient, wxT("received signature for client without public key") );
2200 return;
2202 // and one more check: did we ask for a signature and sent a challange packet?
2203 if (credits->m_dwCryptRndChallengeFor == 0){
2204 AddDebugLogLineN( logClient, wxT("received signature for client with invalid challenge value - User ") + GetUserName() );
2205 return;
2208 // cppcheck-suppress duplicateBranch
2209 if (theApp->clientcredits->VerifyIdent(credits, pachPacket+1, pachPacket[0], GetIP(), byChaIPKind ) ) {
2210 // result is saved in function above
2211 AddDebugLogLineN( logClient, CFormat( wxT("'%s' has passed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind );
2212 } else {
2213 AddDebugLogLineN( logClient, CFormat( wxT("'%s' has failed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind );
2216 m_dwLastSignatureIP = GetIP();
2219 void CUpDownClient::SendSecIdentStatePacket()
2221 wxCHECK2(credits != NULL, return);
2223 // check if we need public key and signature
2224 uint8 nValue = 0;
2225 if (theApp->CryptoAvailable()){
2226 if (credits->GetSecIDKeyLen() == 0) {
2227 nValue = IS_KEYANDSIGNEEDED;
2228 } else if (m_dwLastSignatureIP != GetIP()) {
2229 nValue = IS_SIGNATURENEEDED;
2232 if (nValue == 0){
2233 AddDebugLogLineN( logClient, wxT("Not sending SecIdentState Packet, because State is Zero") );
2234 return;
2236 // crypt: send random data to sign
2237 uint32 dwRandom = rand()+1;
2238 credits->m_dwCryptRndChallengeFor = dwRandom;
2240 CMemFile data;
2241 data.WriteUInt8(nValue);
2242 data.WriteUInt32(dwRandom);
2243 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SECIDENTSTATE);
2245 theStats::AddUpOverheadOther(packet->GetPacketSize());
2246 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_SECIDENTSTATE to ") + GetFullIP() );
2247 SendPacket(packet,true,true);
2251 void CUpDownClient::ProcessSecIdentStatePacket(const byte* pachPacket, uint32 nSize)
2253 if ( nSize != 5 ) {
2254 return;
2257 wxCHECK2(credits, return);
2259 CMemFile data(pachPacket,nSize);
2261 switch ( data.ReadUInt8() ) {
2262 case 0:
2263 m_SecureIdentState = IS_UNAVAILABLE;
2264 break;
2265 case 1:
2266 m_SecureIdentState = IS_SIGNATURENEEDED;
2267 break;
2268 case 2:
2269 m_SecureIdentState = IS_KEYANDSIGNEEDED;
2270 break;
2271 default:
2272 return;
2275 credits->m_dwCryptRndChallengeFrom = data.ReadUInt32();
2279 void CUpDownClient::InfoPacketsReceived()
2281 // indicates that both Information Packets has been received
2282 // needed for actions, which process data from both packets
2283 wxASSERT ( m_byInfopacketsReceived == IP_BOTH );
2284 m_byInfopacketsReceived = IP_NONE;
2286 if (m_bySupportSecIdent){
2287 SendSecIdentStatePacket();
2292 bool CUpDownClient::CheckHandshakeFinished() const
2294 if (m_bHelloAnswerPending) {
2295 // this triggers way too often.. need more time to look at this -> only create a warning
2296 // The reason for this is that 2 clients are connecting to each other at the same time..
2297 AddDebugLogLineN( logClient, wxT("Handshake not finished while processing packet.") );
2298 return false;
2301 return true;
2305 #ifdef __DEBUG__
2306 wxString CUpDownClient::GetClientFullInfo()
2308 if (m_clientVerString.IsEmpty()) {
2309 ReGetClientSoft();
2312 return CFormat( wxT("Client %s on IP:Port %s:%d using %s %s %s") )
2313 % ( m_Username.IsEmpty() ? wxString(_("Unknown")) : m_Username )
2314 % GetFullIP()
2315 % GetUserPort()
2316 % m_clientSoftString
2317 % m_clientVerString
2318 % m_strModVersion;
2320 #endif
2322 wxString CUpDownClient::GetClientShortInfo()
2324 if (m_clientVerString.IsEmpty()) {
2325 ReGetClientSoft();
2328 return CFormat( wxT("'%s' (%s %s %s)") )
2329 % ( m_Username.IsEmpty() ? wxString(_("Unknown")) : m_Username )
2330 % m_clientSoftString
2331 % m_clientVerString
2332 % m_strModVersion;
2336 void CUpDownClient::SendPublicIPRequest()
2338 if (IsConnected()){
2339 CPacket* packet = new CPacket(OP_PUBLICIP_REQ,0,OP_EMULEPROT);
2340 theStats::AddUpOverheadOther(packet->GetPacketSize());
2341 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICIP_REQ to ") + GetFullIP());
2342 SendPacket(packet,true);
2343 m_fNeedOurPublicIP = true;
2347 void CUpDownClient::ProcessPublicIPAnswer(const byte* pbyData, uint32 uSize)
2349 if (uSize != 4) {
2350 throw wxString(wxT("Wrong Packet size on Public IP answer"));
2352 uint32 dwIP = PeekUInt32(pbyData);
2353 if (m_fNeedOurPublicIP == true){ // did we?
2354 m_fNeedOurPublicIP = false;
2355 // Ignore local ip on GetPublicIP (could be wrong)
2356 if (theApp->GetPublicIP(true) == 0 && !IsLowID(dwIP) ) {
2357 theApp->SetPublicIP(dwIP);
2363 bool CUpDownClient::IsConnected() const
2365 return m_socket && m_socket->IsConnected();
2368 bool CUpDownClient::SendPacket(CPacket* packet, bool delpacket, bool controlpacket)
2370 if ( m_socket ) {
2371 m_socket->SendPacket(packet, delpacket, controlpacket );
2372 return true;
2373 } else {
2374 AddLogLineN(wxT("CAUGHT DEAD SOCKET IN SENDPACKET()"));
2375 return false;
2379 float CUpDownClient::SetDownloadLimit(uint32 reducedownload)
2381 // lfroen: in daemon it actually can happen
2382 wxASSERT( m_socket );
2384 float kBpsClient = CalculateKBpsDown();
2386 if ( m_socket ) {
2388 if (reducedownload) {
2389 // (% to reduce * current speed) / 100 and THEN, / (1000 / CORE_TIMER_PERIOD)
2390 // which is how often it is called per second.
2391 uint32 limit = (uint32)(reducedownload * kBpsClient * 1024.0 / 100000.0 * CORE_TIMER_PERIOD);
2393 if(limit<1024 && reducedownload >= 200) {
2394 // If we're going up and this download is < 1kB,
2395 // we want it to go up fast. Can be reduced later,
2396 // and it'll probably be in a more fair way with
2397 // other downloads that are faster.
2398 limit +=1024;
2399 } else if(limit == 0) {
2400 // This download is not transferring yet... make it
2401 // 1024 so we don't fill the TCP stack and lose the
2402 // connection.
2403 limit = 1024;
2406 m_socket->SetDownloadLimit(limit);
2407 } else {
2408 m_socket->DisableDownloadLimit();
2411 } else {
2412 AddLogLineNS(CFormat(wxT("CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f")) % kBpsClient);
2415 return kBpsClient;
2418 void CUpDownClient::SetUserIDHybrid(uint32 nUserID)
2420 theApp->clientlist->UpdateClientID( this, nUserID );
2422 m_nUserIDHybrid = nUserID;
2426 void CUpDownClient::SetIP( uint32 val )
2428 theApp->clientlist->UpdateClientIP( this, val );
2430 m_dwUserIP = val;
2432 m_nConnectIP = val;
2434 m_FullUserIP = val;
2438 void CUpDownClient::SetUserHash(const CMD4Hash& userhash)
2440 theApp->clientlist->UpdateClientHash( this, userhash );
2442 m_UserHash = userhash;
2444 ValidateHash();
2447 EUtf8Str CUpDownClient::GetUnicodeSupport() const
2449 return m_bUnicodeSupport ? utf8strRaw : utf8strNone;
2452 void CUpDownClient::SetSpammer(bool bVal)
2454 if (bVal) {
2455 Ban();
2456 } else if (IsBanned() && m_fIsSpammer) {
2457 UnBan();
2459 m_fIsSpammer = bVal;
2462 uint8 CUpDownClient::GetSecureIdentState()
2464 if (m_SecureIdentState != IS_UNAVAILABLE) {
2465 if (!SecIdentSupRec) {
2466 // This can be caused by a 0.30x based client which sends the old
2467 // style Hello packet, and the mule info packet, but between them they
2468 // send a secure ident state packet (after a hello but before we have
2469 // the SUI capabilities). This is a misbehaving client, and somehow I
2470 // feel like it should be dropped. But then again, it won't harm to use
2471 // this SUI state if they are reporting no SUI (won't be used) and if
2472 // they report using SUI on the mule info packet, it's ok to use it.
2474 AddDebugLogLineN(logClient, wxT("A client sent secure ident state before telling us the SUI capabilities"));
2475 AddDebugLogLineN(logClient, wxT("Client info: ") + GetClientFullInfo());
2476 AddDebugLogLineN(logClient, wxT("This client won't be disconnected, but it should be. :P"));
2480 return m_SecureIdentState;
2484 bool CUpDownClient::SendChatMessage(const wxString& message)
2486 if (GetChatCaptchaState() == CA_CAPTCHARECV) {
2487 m_nChatCaptchaState = CA_SOLUTIONSENT;
2488 } else if (GetChatCaptchaState() == CA_SOLUTIONSENT) {
2489 wxFAIL; // we responsed to a captcha but didn't heard from the client afterwards - hopefully its just lag and this message will get through
2490 } else {
2491 m_nChatCaptchaState = CA_ACCEPTING;
2494 SetSpammer(false);
2495 IncMessagesSent();
2496 // Already connecting?
2497 if (GetChatState() == MS_CONNECTING) {
2498 // Queue all messages till we're able to send them (or discard them)
2499 if (!m_pendingMessage.IsEmpty()) {
2500 m_pendingMessage += wxT("\n");
2501 } else {
2502 // There must be a message to send
2503 // - except if we got disconnected. No need to assert therefore.
2505 m_pendingMessage += message;
2506 return false;
2508 if (IsConnected()) {
2509 // If we are already connected when we send the first message,
2510 // we have to update the chat status.
2511 SetChatState(MS_CHATTING);
2512 CMemFile data;
2513 data.WriteString(message, GetUnicodeSupport());
2514 CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_MESSAGE);
2515 theStats::AddUpOverheadOther(packet->GetPacketSize());
2516 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_MESSAGE to ") + GetFullIP());
2517 SendPacket(packet, true, true);
2518 return true;
2519 } else {
2520 m_pendingMessage = message;
2521 SetChatState(MS_CONNECTING);
2522 // True to ignore "Too Many Connections"
2523 TryToConnect(true);
2524 return false;
2528 /* Kad stuff */
2530 void CUpDownClient::SetBuddyID(const byte* pucBuddyID)
2532 if( pucBuddyID == NULL ){
2533 md4clr(m_achBuddyID);
2534 m_bBuddyIDValid = false;
2535 return;
2537 m_bBuddyIDValid = true;
2538 md4cpy(m_achBuddyID, pucBuddyID);
2541 // Kad added by me
2543 bool CUpDownClient::SendBuddyPing() {
2544 SetLastBuddyPingPongTime();
2545 CPacket* buddyPing = new CPacket(OP_BUDDYPING, 0, OP_EMULEPROT);
2546 theStats::AddUpOverheadKad(buddyPing->GetPacketSize());
2547 AddDebugLogLineN(logLocalClient,wxT("Local Client: OP_BUDDYPING to ") + GetFullIP());
2548 return SafeSendPacket(buddyPing);
2552 /* Statistics */
2554 void CUpDownClient::UpdateStats()
2556 if (m_lastClientSoft != m_clientSoft || m_lastClientVersion != m_nClientVersion || m_lastOSInfo != m_sClientOSInfo) {
2557 if (m_lastClientSoft == SO_UNKNOWN) {
2558 theStats::RemoveUnknownClient();
2559 } else if (m_lastClientSoft != (uint32)(-1)) {
2560 theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo);
2563 m_lastClientSoft = m_clientSoft;
2564 m_lastClientVersion = m_nClientVersion;
2565 m_lastOSInfo = m_sClientOSInfo;
2567 if (m_clientSoft == SO_UNKNOWN) {
2568 theStats::AddUnknownClient();
2569 } else {
2570 theStats::AddKnownClient(this);
2575 bool CUpDownClient::IsIdentified() const
2577 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED);
2580 bool CUpDownClient::IsBadGuy() const
2582 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY);
2585 bool CUpDownClient::SUIFailed() const
2587 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDFAILED);
2590 bool CUpDownClient::SUINeeded() const
2592 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDNEEDED);
2595 bool CUpDownClient::SUINotSupported() const
2597 return (credits && credits->GetCurrentIdentState(GetIP()) == IS_NOTAVAILABLE);
2600 uint64 CUpDownClient::GetDownloadedTotal() const
2602 return credits ? credits->GetDownloadedTotal() : 0;
2605 uint64 CUpDownClient::GetUploadedTotal() const
2607 return credits ? credits->GetUploadedTotal() : 0;
2610 double CUpDownClient::GetScoreRatio() const
2612 return credits ? credits->GetScoreRatio(GetIP(), theApp->CryptoAvailable()) : 0;
2615 const wxString CUpDownClient::GetServerName() const
2617 wxString ret;
2618 wxString srvaddr = Uint32toStringIP(GetServerIP());
2619 CServer* cserver = theApp->serverlist->GetServerByAddress(
2620 srvaddr, GetServerPort());
2621 if (cserver) {
2622 ret = cserver->GetListName();
2623 } else {
2624 ret = _("Unknown");
2627 return ret;
2630 bool CUpDownClient::ShouldReceiveCryptUDPPackets() const
2632 return (thePrefs::IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp->GetPublicIP() != 0
2633 && HasValidHash() && (thePrefs::IsClientCryptLayerRequested() || RequestsCryptLayer()) );
2636 #ifdef AMULE_DAEMON
2638 void CUpDownClient::ProcessCaptchaRequest(CMemFile* WXUNUSED(data)) {}
2639 void CUpDownClient::ProcessCaptchaReqRes(uint8 WXUNUSED(nStatus)) {}
2640 void CUpDownClient::ProcessChatMessage(const wxString WXUNUSED(message)) {}
2642 #else
2644 void CUpDownClient::ProcessCaptchaRequest(CMemFile* data)
2646 uint64 id = GUI_ID(GetIP(),GetUserPort());
2647 // received a captcha request, check if we actually accept it (only after sending a message ourself to this client)
2648 if (GetChatCaptchaState() == CA_ACCEPTING && GetChatState() != MS_NONE
2649 && theApp->amuledlg->m_chatwnd->IsIdValid(id)) {
2650 // read tags (for future use)
2651 uint8 nTagCount = data->ReadUInt8();
2652 if (nTagCount) {
2653 AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client (%s) with (%u) tags")) % GetFullIP() % nTagCount);
2654 // and ignore them for now
2655 for (uint32 i = 0; i < nTagCount; i++) {
2656 CTag tag(*data, true);
2660 // sanitize checks - we want a small captcha not a wallpaper
2661 uint32 nSize = (uint32)(data->GetLength() - data->GetPosition());
2663 if ( nSize > 128 && nSize < 4096 ) {
2664 uint64 pos = data->GetPosition();
2665 wxMemoryInputStream memstr(data->GetRawBuffer() + pos, nSize);
2666 wxImage imgCaptcha(memstr, wxBITMAP_TYPE_BMP);
2668 if (imgCaptcha.IsOk() && imgCaptcha.GetHeight() > 10 && imgCaptcha.GetHeight() < 50
2669 && imgCaptcha.GetWidth() > 10 && imgCaptcha.GetWidth() < 150 ) {
2670 m_nChatCaptchaState = CA_CAPTCHARECV;
2671 CCaptchaDialog * dialog = new CCaptchaDialog(theApp->amuledlg, imgCaptcha, id);
2672 dialog->Show();
2674 } else {
2675 AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client, processing image failed or invalid pixel size (%s)")) % GetFullIP());
2677 } else {
2678 AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client, size sanitize check failed (%u) (%s)")) % nSize % GetFullIP());
2680 } else {
2681 AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client, but don't accepting it at this time (%s)")) % GetFullIP());
2685 void CUpDownClient::ProcessCaptchaReqRes(uint8 nStatus)
2687 uint64 id = GUI_ID(GetIP(),GetUserPort());
2688 if (GetChatCaptchaState() == CA_SOLUTIONSENT && GetChatState() != MS_NONE
2689 && theApp->amuledlg->m_chatwnd->IsIdValid(id)) {
2690 wxASSERT( nStatus < 3 );
2691 m_nChatCaptchaState = CA_NONE;
2692 theApp->amuledlg->m_chatwnd->ShowCaptchaResult(id, nStatus == 0);
2693 } else {
2694 m_nChatCaptchaState = CA_NONE;
2695 AddDebugLogLineN(logClient, CFormat(wxT("Received captcha result from client, but not accepting it at this time (%s)")) % GetFullIP());
2699 void CUpDownClient::ProcessChatMessage(wxString message)
2701 if (IsMessageFiltered(message)) {
2702 AddLogLineC(CFormat(_("Message filtered from '%s' (IP:%s)")) % GetUserName() % GetFullIP());
2703 return;
2706 // advanced spamfilter check
2707 if (thePrefs::IsChatCaptchaEnabled() && !IsFriend()) {
2708 // captcha checks outrank any further checks - if the captcha has been solved, we assume it's not spam
2709 // first check if we need to send a captcha request to this client
2710 if (GetMessagesSent() == 0 && GetMessagesReceived() == 0 && GetChatCaptchaState() != CA_CAPTCHASOLVED) {
2711 // we have never sent a message to this client, and no message from him has ever passed our filters
2712 if (GetChatCaptchaState() != CA_CHALLENGESENT) {
2713 // we also aren't currently expecting a captcha response
2714 if (m_fSupportsCaptcha) {
2715 // and he supports captcha, so send him one and store the message (without showing for now)
2716 if (m_cCaptchasSent < 3) { // no more than 3 tries
2717 m_strCaptchaPendingMsg = message;
2718 wxMemoryOutputStream memstr;
2719 memstr.PutC(0); // no tags, for future use
2720 CCaptchaGenerator captcha(4);
2721 if (captcha.WriteCaptchaImage(memstr)){
2722 m_strCaptchaChallenge = captcha.GetCaptchaText();
2723 m_nChatCaptchaState = CA_CHALLENGESENT;
2724 m_cCaptchasSent++;
2725 CMemFile fileAnswer((byte*) memstr.GetOutputStreamBuffer()->GetBufferStart(), memstr.GetLength());
2726 CPacket* packet = new CPacket(fileAnswer, OP_EMULEPROT, OP_CHATCAPTCHAREQ);
2727 theStats::AddUpOverheadOther(packet->GetPacketSize());
2728 AddLogLineN(CFormat(wxT("sent Captcha %s (%d)")) % m_strCaptchaChallenge % packet->GetPacketSize());
2729 SafeSendPacket(packet);
2730 } else {
2731 wxFAIL;
2734 } else {
2735 // client doesn't support captchas, but we require them, tell him that it's not going to work out
2736 // with an answer message (will not be shown and doesn't count as sent message)
2737 if (m_cCaptchasSent < 1) { // don't send this notifier more than once
2738 m_cCaptchasSent++;
2739 // always sent in english
2740 SendChatMessage(wxT("In order to avoid spam messages, this user requires you to solve a captcha before you can send a message to him. However your client does not supports captchas, so you will not be able to chat with this user."));
2741 AddDebugLogLineN(logClient, CFormat(wxT("Received message from client not supporting captchas, filtered and sent notifier (%s)")) % GetClientFullInfo());
2742 } else {
2743 AddDebugLogLineN(logClient, CFormat(wxT("Received message from client not supporting captchas, filtered, didn't send notifier (%s)")) % GetClientFullInfo());
2746 return;
2747 } else { // (GetChatCaptchaState() == CA_CHALLENGESENT)
2748 // this message must be the answer to the captcha request we sent him, let's verify
2749 wxASSERT( !m_strCaptchaChallenge.IsEmpty() );
2750 if (m_strCaptchaChallenge.CmpNoCase(message.Trim().Right(std::min(message.Length(), m_strCaptchaChallenge.Length()))) == 0) {
2751 // allright
2752 AddDebugLogLineN(logClient, CFormat(wxT("Captcha solved, showing withheld message (%s)")) % GetClientFullInfo());
2753 m_nChatCaptchaState = CA_CAPTCHASOLVED; // this state isn't persitent, but the messagecounter will be used to determine later if the captcha has been solved
2754 // replace captchaanswer with withheld message and show it
2755 message = m_strCaptchaPendingMsg;
2756 m_cCaptchasSent = 0;
2757 m_strCaptchaChallenge.Clear();
2758 CPacket* packet = new CPacket(OP_CHATCAPTCHARES, 1, OP_EMULEPROT, false);
2759 byte statusResponse = 0; // status response
2760 packet->CopyToDataBuffer(0, &statusResponse, 1);
2761 theStats::AddUpOverheadOther(packet->GetPacketSize());
2762 SafeSendPacket(packet);
2763 } else { // wrong, cleanup and ignore
2764 AddDebugLogLineN(logClient, CFormat(wxT("Captcha answer failed (%s)")) % GetClientFullInfo());
2765 m_nChatCaptchaState = CA_NONE;
2766 m_strCaptchaChallenge.Clear();
2767 m_strCaptchaPendingMsg.Clear();
2768 CPacket* packet = new CPacket(OP_CHATCAPTCHARES, 1, OP_EMULEPROT, false);
2769 byte statusResponse = (m_cCaptchasSent < 3) ? 1 : 2; // status response
2770 packet->CopyToDataBuffer(0, &statusResponse, 1);
2771 theStats::AddUpOverheadOther(packet->GetPacketSize());
2772 SafeSendPacket(packet);
2773 return; // nothing more todo
2779 if (thePrefs::IsAdvancedSpamfilterEnabled() && !IsFriend()) { // friends are never spammer... (but what if two spammers are friends :P )
2780 bool bIsSpam = false;
2781 if (m_fIsSpammer) {
2782 bIsSpam = true;
2783 } else {
2784 // first fixed criteria: If a client sends me an URL in his first message before I respond to him
2785 // there is a 99,9% chance that it is some poor guy advising his leech mod, or selling you .. well you know :P
2786 if (GetMessagesSent() == 0) {
2787 static wxArrayString urlindicators(wxStringTokenize(wxT("http:|www.|.de |.net |.com |.org |.to |.tk |.cc |.fr |ftp:|ed2k:|https:|ftp.|.info|.biz|.uk|.eu|.es|.tv|.cn|.tw|.ws|.nu|.jp"), wxT("|")));
2788 for (size_t pos = urlindicators.GetCount(); pos--;) {
2789 if (message.Find(urlindicators[pos]) != wxNOT_FOUND) {
2790 bIsSpam = true;
2791 break;
2794 // second fixed criteria: he sent me 4 or more messages and I didn't answer him once
2795 if (GetMessagesReceived() > 3) {
2796 bIsSpam = true;
2800 if (bIsSpam) {
2801 AddDebugLogLineN(logClient, CFormat(wxT("'%s' has been marked as spammer")) % GetUserName());
2802 SetSpammer(true);
2803 theApp->amuledlg->m_chatwnd->EndSession(GUI_ID(GetIP(),GetUserPort()));
2804 return;
2809 wxString logMsg = CFormat(_("New message from '%s' (IP:%s)")) % GetUserName() % GetFullIP();
2810 if(thePrefs::ShowMessagesInLog()) {
2811 logMsg += wxT(": ") + message;
2813 AddLogLineC(logMsg);
2814 IncMessagesReceived();
2816 Notify_ChatProcessMsg(GUI_ID(GetIP(), GetUserPort()), GetUserName() + wxT("|") + message);
2819 bool CUpDownClient::IsMessageFiltered(const wxString& message)
2821 bool filtered = false;
2822 // If we're chatting to the guy, we don't want to filter!
2823 if (GetChatState() != MS_CHATTING) {
2824 if (thePrefs::MsgOnlyFriends() && !IsFriend()) {
2825 filtered = true;
2826 } else if (thePrefs::MsgOnlySecure() && GetUserName().IsEmpty() ) {
2827 filtered = true;
2828 } else if (thePrefs::MustFilterMessages()) {
2829 filtered = thePrefs::IsMessageFiltered(message);
2832 if (filtered) {
2833 SetSpammer(true);
2835 return filtered;
2838 #endif
2840 void CUpDownClient::SendSharedDirectories()
2842 // This list will contain all (unique) folders.
2843 PathList foldersToSend;
2845 // The shared folders
2846 const unsigned folderCount = theApp->glob_prefs->shareddir_list.size();
2847 for (unsigned i = 0; i < folderCount; ++i) {
2848 foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]);
2851 // ... the categories folders ... (category 0 -> incoming)
2852 for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) {
2853 foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path);
2856 // Strip duplicates
2857 foldersToSend.sort();
2858 foldersToSend.unique();
2860 // Build packet
2861 CMemFile tempfile(80);
2862 tempfile.WriteUInt32(foldersToSend.size() + 1); // + 1 for the incomplete files
2864 PathList::iterator it = foldersToSend.begin();
2865 for (; it != foldersToSend.end(); ++it) {
2866 // Note: the public shared name contains the 'raw' path, so we can recognize it again.
2867 // the 'raw' path is determined using CPath::GetRaw()
2868 tempfile.WriteString( theApp->sharedfiles->GetPublicSharedDirName(*it), GetUnicodeSupport() );
2871 // ... and the Magic thing from the eDonkey Hybrids...
2872 tempfile.WriteString(OP_INCOMPLETE_SHARED_FILES, GetUnicodeSupport());
2874 // Send the packet.
2875 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS);
2876 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
2877 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + GetFullIP() );
2878 SendPacket(replypacket, true, true);
2881 void CUpDownClient::SendSharedFilesOfDirectory(const wxString& strReqDir)
2883 CKnownFilePtrList list;
2885 if (strReqDir == OP_INCOMPLETE_SHARED_FILES) {
2886 // get all shared files from download queue
2887 int iQueuedFiles = theApp->downloadqueue->GetFileCount();
2888 for (int i = 0; i < iQueuedFiles; i++) {
2889 CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i);
2890 if (pFile == NULL || pFile->GetStatus(true) != PS_READY) {
2891 continue;
2893 list.push_back(pFile);
2895 } else {
2896 // get all shared files for the requested directory
2897 const CPath *sharedDir = theApp->sharedfiles->GetDirForPublicSharedDirName(strReqDir);
2898 if (sharedDir) {
2899 theApp->sharedfiles->GetSharedFilesByDirectory(sharedDir->GetRaw(), list);
2900 } else {
2901 AddLogLineC(CFormat(_("User %s (%u) requested sharedfiles-list for not existing directory '%s' -> Ignored")) % GetUserName() % GetUserIDHybrid() % strReqDir);
2905 CMemFile tempfile(80);
2906 tempfile.WriteString(strReqDir, GetUnicodeSupport());
2907 tempfile.WriteUInt32(list.size());
2909 while (!list.empty()) {
2910 if (!list.front()->IsLargeFile() || SupportsLargeFiles()) {
2911 list.front()->CreateOfferedFilePacket(&tempfile, NULL, this);
2913 list.pop_front();
2916 CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS);
2917 theStats::AddUpOverheadOther(replypacket->GetPacketSize());
2918 AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + GetFullIP() );
2919 SendPacket(replypacket, true, true);
2922 void CUpDownClient::SendFirewallCheckUDPRequest()
2924 wxASSERT(GetKadState() == KS_FWCHECK_UDP);
2926 if (!Kademlia::CKademlia::IsRunning()) {
2927 SetKadState(KS_NONE);
2928 return;
2929 } else if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE || GetKadVersion() <= 5 || GetKadPort() == 0) {
2930 Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetIP()), 0); // inform the tester that this test was cancelled
2931 SetKadState(KS_NONE);
2932 return;
2935 CMemFile data;
2936 data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetInternKadPort());
2937 data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort());
2938 data.WriteUInt32(Kademlia::CKademlia::GetPrefs()->GetUDPVerifyKey(GetConnectIP()));
2939 CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_FWCHECKUDPREQ);
2940 theStats::AddUpOverheadKad(packet->GetPacketSize());
2941 SafeSendPacket(packet);
2944 void CUpDownClient::ProcessFirewallCheckUDPRequest(CMemFile* data)
2946 if (!Kademlia::CKademlia::IsRunning() || Kademlia::CKademlia::GetUDPListener() == NULL) {
2947 //DebugLogWarning(_T("Ignored Kad Firewallrequest UDP because Kad is not running (%s)"), GetClientFullInfo());
2948 return;
2951 // first search if we know this IP already, if so the result might be biased and we need tell the requester
2952 bool errorAlreadyKnown = false;
2953 if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE) {
2954 errorAlreadyKnown = true;
2955 } else if (Kademlia::CKademlia::GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(GetConnectIP()), 0, false) != NULL) {
2956 errorAlreadyKnown = true;
2959 uint16_t remoteInternPort = data->ReadUInt16();
2960 uint16_t remoteExternPort = data->ReadUInt16();
2961 uint32_t senderKey = data->ReadUInt32();
2962 if (remoteInternPort == 0) {
2963 //DebugLogError(_T("UDP Firewallcheck requested with Intern Port == 0 (%s)"), GetClientFullInfo());
2964 return;
2966 // if (senderKey == 0)
2967 // DebugLogWarning(_T("UDP Firewallcheck requested with SenderKey == 0 (%s)"), GetClientFullInfo());
2969 CMemFile testPacket1;
2970 testPacket1.WriteUInt8(errorAlreadyKnown ? 1 : 0);
2971 testPacket1.WriteUInt16(remoteInternPort);
2972 DebugSend(Kad2FirewallUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort);
2973 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket1, KADEMLIA2_FIREWALLUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort, Kademlia::CKadUDPKey(senderKey, theApp->GetPublicIP(false)), NULL);
2975 // if the client has a router with PAT (and therefore a different extern port than intern), test this port too
2976 if (remoteExternPort != 0 && remoteExternPort != remoteInternPort) {
2977 CMemFile testPacket2;
2978 testPacket2.WriteUInt8(errorAlreadyKnown ? 1 : 0);
2979 testPacket2.WriteUInt16(remoteExternPort);
2980 DebugSend(Kad2FirewalledUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort);
2981 Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket2, KADEMLIA2_FIREWALLUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort, Kademlia::CKadUDPKey(senderKey, theApp->GetPublicIP(false)), NULL);
2983 //DebugLog(_T("Answered UDP Firewallcheck request (%s)"), GetClientFullInfo());
2986 void CUpDownClient::SetConnectOptions(uint8_t options, bool encryption, bool callback)
2988 SetCryptLayerSupport((options & 0x01) != 0 && encryption);
2989 SetCryptLayerRequest((options & 0x02) != 0 && encryption);
2990 SetCryptLayerRequires((options & 0x04) != 0 && encryption);
2991 SetDirectUDPCallbackSupport((options & 0x08) != 0 && callback);
2995 #ifdef DEBUG_ZOMBIE_CLIENTS
2996 void CUpDownClient::Unlink(const wxString& from)
2998 std::multiset<wxString>::iterator it = m_linkedFrom.find(from);
2999 if (it != m_linkedFrom.end()) {
3000 m_linkedFrom.erase(it);
3002 m_linked--;
3003 if (!m_linked) {
3004 if (m_linkedDebug) {
3005 AddLogLineN(CFormat(wxT("Last reference to client %d %p unlinked, delete it.")) % ECID() % this);
3007 delete this;
3011 #else
3013 void CUpDownClient::Unlink()
3015 m_linked--;
3016 if (!m_linked) {
3017 delete this;
3020 #endif
3023 // File_checked_for_headers