| File: | rootdir/src/BaseClient.cpp |
| Warning: | line 2921, column 1 Potential leak of memory pointed to by 'replypacket' |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 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. | |||
| 10 | // | |||
| 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. | |||
| 15 | // | |||
| 16 | // This program is distributed in the hope that it will be useful, | |||
| 17 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
| 18 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
| 19 | // GNU General Public License for more details. | |||
| 20 | // | |||
| 21 | // You should have received a copy of the GNU General Public License | |||
| 22 | // along with this program; if not, write to the Free Software | |||
| 23 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | |||
| 24 | // | |||
| 25 | ||||
| 26 | #include <wx/wx.h> | |||
| 27 | #include <wx/mstream.h> | |||
| 28 | #include <wx/tokenzr.h> | |||
| 29 | ||||
| 30 | #include "updownclient.h" // Needed for CUpDownClient | |||
| 31 | #include "SharedFileList.h" // Needed for CSharedFileList | |||
| 32 | ||||
| 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> | |||
| 40 | ||||
| 41 | #include <common/ClientVersion.h> | |||
| 42 | ||||
| 43 | #include <tags/ClientTags.h> | |||
| 44 | ||||
| 45 | #include <zlib.h> // Needed for inflateEnd | |||
| 46 | ||||
| 47 | #include <common/Format.h> // Needed for CFormat | |||
| 48 | ||||
| 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 | |||
| 79 | ||||
| 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" | |||
| 85 | ||||
| 86 | ||||
| 87 | //#define __PACKET_DEBUG__ | |||
| 88 | ||||
| 89 | ||||
| 90 | // some client testing variables | |||
| 91 | static wxString crash_name = wxT("[Invalid User Name]")L"[Invalid User Name]"; | |||
| 92 | static wxString empty_name = wxT("[Empty User Name]")L"[Empty User Name]"; | |||
| 93 | ||||
| 94 | // members of CUpDownClient | |||
| 95 | // which are used by down and uploading functions | |||
| 96 | ||||
| 97 | ||||
| 98 | CUpDownClient::CUpDownClient(CClientTCPSocket* sender) | |||
| 99 | { | |||
| 100 | #ifdef __DEBUG__ | |||
| 101 | m_socket = NULL__null; | |||
| 102 | SetSocket(sender); | |||
| 103 | #else | |||
| 104 | m_socket = sender; | |||
| 105 | #endif | |||
| 106 | Init(); | |||
| 107 | } | |||
| 108 | ||||
| 109 | CUpDownClient::CUpDownClient(uint16 in_port, uint32 in_userid, uint32 in_serverip, uint16 in_serverport, CPartFile* in_reqfile, bool ed2kID, bool checkfriend) | |||
| 110 | { | |||
| 111 | m_socket = NULL__null; | |||
| 112 | Init(); | |||
| 113 | m_nUserPort = in_port; | |||
| 114 | ||||
| 115 | if(ed2kID && !IsLowID(in_userid)) { | |||
| 116 | SetUserIDHybrid( wxUINT32_SWAP_ALWAYS(in_userid)((wxUint32) ( (((wxUint32) (in_userid) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (in_userid) & (wxUint32) 0x0000ff00U ) << 8) | (((wxUint32) (in_userid) & (wxUint32) 0x00ff0000U ) >> 8) | (((wxUint32) (in_userid) & (wxUint32) 0xff000000U ) >> 24))) ); | |||
| 117 | } else { | |||
| 118 | SetUserIDHybrid( in_userid); | |||
| 119 | } | |||
| 120 | ||||
| 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 | |||
| 123 | ||||
| 124 | if (!HasLowID()) { | |||
| 125 | if (ed2kID) { | |||
| 126 | m_nConnectIP = in_userid; | |||
| 127 | } else { | |||
| 128 | m_nConnectIP = wxUINT32_SWAP_ALWAYS(in_userid)((wxUint32) ( (((wxUint32) (in_userid) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (in_userid) & (wxUint32) 0x0000ff00U ) << 8) | (((wxUint32) (in_userid) & (wxUint32) 0x00ff0000U ) >> 8) | (((wxUint32) (in_userid) & (wxUint32) 0xff000000U ) >> 24))); | |||
| 129 | } | |||
| 130 | // Will be on right endianness now | |||
| 131 | m_FullUserIP = m_nConnectIP; | |||
| 132 | } | |||
| 133 | ||||
| 134 | m_dwServerIP = in_serverip; | |||
| 135 | m_nServerPort = in_serverport; | |||
| 136 | SetRequestFile( in_reqfile ); | |||
| 137 | ReGetClientSoft(); | |||
| 138 | ||||
| 139 | if (checkfriend) { | |||
| 140 | if ((m_Friend = theApp->friendlist->FindFriend(CMD4Hash(), m_dwUserIP, m_nUserPort)) != NULL__null){ | |||
| 141 | m_Friend->LinkClient(CCLIENTREF(this, wxT("CUpDownClient::CUpDownClient m_Friend->LinkClient"))CClientRef(this)); | |||
| 142 | } else{ | |||
| 143 | // avoid that an unwanted client instance keeps a friend slot | |||
| 144 | m_bFriendSlot = false; | |||
| 145 | } | |||
| 146 | } | |||
| 147 | ||||
| 148 | } | |||
| 149 | ||||
| 150 | void CUpDownClient::Init() | |||
| 151 | { | |||
| 152 | m_linked = 0; | |||
| 153 | #ifdef DEBUG_ZOMBIE_CLIENTS | |||
| 154 | m_linkedDebug = false; | |||
| 155 | #endif | |||
| 156 | m_bAddNextConnect = false; | |||
| 157 | credits = NULL__null; | |||
| 158 | m_byChatstate = MS_NONE; | |||
| 159 | m_nKadState = KS_NONE; | |||
| 160 | m_nChatCaptchaState = CA_NONE; | |||
| 161 | m_cShowDR = 0; | |||
| 162 | m_reqfile = NULL__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; | |||
| 187 | ||||
| 188 | m_fSentOutOfPartReqs = 0; | |||
| 189 | m_nCurQueueSessionPayloadUp = 0; | |||
| 190 | m_addedPayloadQueueSession = 0; | |||
| 191 | m_nUpDatarate = 0; | |||
| 192 | m_nSumForAvgUpDataRate = 0; | |||
| 193 | ||||
| 194 | m_nRemoteQueueRank = 0; | |||
| 195 | m_nOldRemoteQueueRank = 0; | |||
| 196 | m_dwLastSourceRequest = 0; | |||
| 197 | m_dwLastSourceAnswer = 0; | |||
| 198 | m_dwLastAskedForSources = 0; | |||
| 199 | ||||
| 200 | m_SecureIdentState = IS_UNAVAILABLE; | |||
| 201 | m_dwLastSignatureIP = 0; | |||
| 202 | ||||
| 203 | m_byInfopacketsReceived = IP_NONE; | |||
| 204 | ||||
| 205 | m_bIsHybrid = false; | |||
| 206 | m_bIsML = false; | |||
| 207 | m_Friend = NULL__null; | |||
| 208 | m_iRating = 0; | |||
| 209 | m_nCurSessionUp = 0; | |||
| 210 | m_clientSoft=SO_UNKNOWN; | |||
| 211 | ||||
| 212 | m_bRemoteQueueFull = false; | |||
| 213 | m_HasValidHash = false; | |||
| 214 | SetWaitStartTime(); | |||
| 215 | ||||
| 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; | |||
| 227 | ||||
| 228 | m_clientState = CS_NEW; | |||
| 229 | ||||
| 230 | ClearHelloProperties(); | |||
| 231 | ||||
| 232 | m_pReqFileAICHHash = NULL__null; | |||
| 233 | m_fSupportsAICH = 0; | |||
| 234 | m_fAICHRequested = 0; | |||
| 235 | m_fSupportsLargeFiles = 0; | |||
| 236 | m_fExtMultiPacket = 0; | |||
| 237 | m_fIsSpammer = 0; | |||
| 238 | ||||
| 239 | m_dwUserIP = 0; | |||
| 240 | m_nConnectIP = 0; | |||
| 241 | m_dwServerIP = 0; | |||
| 242 | ||||
| 243 | m_fNeedOurPublicIP = false; | |||
| 244 | m_bHashsetRequested = false; | |||
| 245 | ||||
| 246 | m_lastDownloadingPart = 0; | |||
| 247 | ||||
| 248 | m_uploadingfile = NULL__null; | |||
| 249 | ||||
| 250 | m_OSInfo_sent = false; | |||
| 251 | ||||
| 252 | /* Kad stuff */ | |||
| 253 | SetBuddyID(NULL__null); | |||
| 254 | m_nBuddyIP = 0; | |||
| 255 | m_nBuddyPort = 0; | |||
| 256 | m_nUserIDHybrid = 0; | |||
| 257 | ||||
| 258 | m_nSourceFrom = SF_NONE; | |||
| 259 | ||||
| 260 | if (m_socket) { | |||
| 261 | SetIP(m_socket->GetPeerInt()); | |||
| 262 | } else { | |||
| 263 | SetIP(0); | |||
| 264 | } | |||
| 265 | ||||
| 266 | /* Statistics */ | |||
| 267 | m_lastClientSoft = (uint32)(-1); | |||
| 268 | m_lastClientVersion = 0; | |||
| 269 | ||||
| 270 | /* Creation time (for buddies timeout) */ | |||
| 271 | m_nCreationTime = ::GetTickCount(); | |||
| 272 | ||||
| 273 | m_MaxBlockRequests = STANDARD_BLOCKS_REQUEST3; // Safe starting amount | |||
| 274 | ||||
| 275 | m_last_block_start = 0; | |||
| 276 | m_lastaverage = 0; | |||
| 277 | ||||
| 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; | |||
| 286 | ||||
| 287 | m_hasbeenobfuscatinglately = false; | |||
| 288 | ||||
| 289 | m_cCaptchasSent = 0; | |||
| 290 | m_cMessagesReceived = 0; | |||
| 291 | m_cMessagesSent = 0; | |||
| 292 | ||||
| 293 | } | |||
| 294 | ||||
| 295 | ||||
| 296 | CUpDownClient::~CUpDownClient() | |||
| 297 | { | |||
| 298 | #ifdef __DEBUG__ | |||
| 299 | if (!connection_reason.IsEmpty()) { | |||
| 300 | AddDebugLogLineN(logClient, wxT("Client to check for ") + connection_reason + wxT(" was deleted without connection."))do {} while (false); | |||
| 301 | } | |||
| 302 | #endif | |||
| 303 | ||||
| 304 | ||||
| 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); | |||
| 309 | } | |||
| 310 | ||||
| 311 | // Indicate that we are not anymore on stats | |||
| 312 | m_lastClientSoft = (uint32)(-1); | |||
| 313 | ||||
| 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__null); | |||
| 320 | } | |||
| 321 | ||||
| 322 | ClearUploadBlockRequests(); | |||
| 323 | ClearDownloadBlockRequests(); | |||
| 324 | ||||
| 325 | DeleteContents(m_WaitingPackets_list); | |||
| 326 | ||||
| 327 | // Allow detection of deleted clients that didn't go through Safe_Delete | |||
| 328 | m_clientState = CS_DYING; | |||
| 329 | } | |||
| 330 | ||||
| 331 | ||||
| 332 | void CUpDownClient::ClearHelloProperties() | |||
| 333 | { | |||
| 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; | |||
| 362 | } | |||
| 363 | ||||
| 364 | bool CUpDownClient::ProcessHelloPacket(const uint8_t* pachPacket, uint32 nSize) | |||
| 365 | { | |||
| 366 | const CMemFile data(pachPacket,nSize); | |||
| 367 | uint8 hashsize = data.ReadUInt8(); | |||
| 368 | if ( 16 != hashsize ) { | |||
| 369 | /* | |||
| 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 | |||
| 373 | */ | |||
| 374 | throw wxString(wxT("Invalid Hello packet: Other userhash sizes than 16 are not implemented")L"Invalid Hello packet: Other userhash sizes than 16 are not implemented"); | |||
| 375 | } | |||
| 376 | // eMule 0.42: reset all client properties; a client may not send a particular emule tag any longer | |||
| 377 | ClearHelloProperties(); | |||
| 378 | ||||
| 379 | return ProcessHelloTypePacket(data); | |||
| 380 | } | |||
| 381 | ||||
| 382 | void CUpDownClient::Safe_Delete() | |||
| 383 | { | |||
| 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; | |||
| 388 | } | |||
| 389 | ||||
| 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")))MuleNotify::DoNotify(&MuleNotify::Client_Delete, CClientRef (this)); | |||
| 393 | return; | |||
| 394 | } | |||
| 395 | ||||
| 396 | m_clientState = CS_DYING; | |||
| 397 | ||||
| 398 | // Make sure client doesn't get deleted until this method is finished | |||
| 399 | CClientRef ref(CCLIENTREF(this, wxT("CUpDownClient::Safe_Delete reflocker"))CClientRef(this)); | |||
| 400 | ||||
| 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__null); | |||
| 406 | } | |||
| 407 | ||||
| 408 | // Remove the client from the clientlist if we still have it | |||
| 409 | if ( theApp->clientlist ) { | |||
| 410 | theApp->clientlist->RemoveClient( this ); | |||
| 411 | } | |||
| 412 | ||||
| 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); | |||
| 417 | } | |||
| 418 | if (theApp->downloadqueue) { | |||
| 419 | theApp->downloadqueue->RemoveSource(this); | |||
| 420 | } | |||
| 421 | ||||
| 422 | // For security, remove it from the lists unconditionally. | |||
| 423 | Notify_SharedCtrlRemoveClient(ECID(), (CKnownFile*)NULL)MuleNotify::DoNotify(&MuleNotify::SharedCtrlRemoveClient, ECID(), (CKnownFile*)__null); | |||
| 424 | Notify_SourceCtrlRemoveSource(ECID(), (CPartFile*)NULL)MuleNotify::DoNotify(&MuleNotify::SourceCtrlRemoveSource, ECID(), (CPartFile*)__null); | |||
| 425 | ||||
| 426 | if (IsAICHReqPending()){ | |||
| 427 | m_fAICHRequested = FALSE0; | |||
| 428 | CAICHHashSet::ClientAICHRequestFailed(this); | |||
| 429 | } | |||
| 430 | ||||
| 431 | if (m_Friend) { | |||
| 432 | m_Friend->UnLinkClient(); // this notifies | |||
| 433 | m_Friend = NULL__null; | |||
| 434 | } | |||
| 435 | ||||
| 436 | if (m_iRating>0 || !m_strComment.IsEmpty()) { | |||
| 437 | m_iRating = 0; | |||
| 438 | m_strComment.Clear(); | |||
| 439 | if (m_reqfile) { | |||
| 440 | m_reqfile->UpdateFileRatingCommentAvail(); | |||
| 441 | } | |||
| 442 | } | |||
| 443 | ||||
| 444 | // Ensure that source-counts gets updated in case | |||
| 445 | // of a source not on the download-queue | |||
| 446 | SetRequestFile( NULL__null ); | |||
| 447 | ||||
| 448 | SetUploadFileID(NULL__null); | |||
| 449 | ||||
| 450 | delete m_pReqFileAICHHash; | |||
| 451 | m_pReqFileAICHHash = NULL__null; | |||
| 452 | ||||
| 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())theLogger.AddLogLine(L"BaseClient.cpp", 455, true, logStandard , CFormat(L"Client %d still linked in %d places: %s") % ECID( ) % (m_linked - 1) % GetLinkedFrom()); | |||
| 456 | m_linkedDebug = true; | |||
| 457 | } | |||
| 458 | #endif | |||
| 459 | } | |||
| 460 | ||||
| 461 | ||||
| 462 | bool CUpDownClient::ProcessHelloAnswer(const uint8_t* pachPacket, uint32 nSize) | |||
| 463 | { | |||
| 464 | const CMemFile data(pachPacket,nSize); | |||
| 465 | bool bIsMule = ProcessHelloTypePacket(data); | |||
| 466 | m_bHelloAnswerPending = false; | |||
| 467 | return bIsMule; | |||
| 468 | } | |||
| 469 | ||||
| 470 | bool CUpDownClient::ProcessHelloTypePacket(const CMemFile& data) | |||
| 471 | { | |||
| 472 | uint32 dwEmuleTags = 0; | |||
| 473 | ||||
| 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; | |||
| 485 | ||||
| 486 | case CT_VERSION: | |||
| 487 | m_nClientVersion = temptag.GetInt(); | |||
| 488 | break; | |||
| 489 | ||||
| 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")L"ModID=%u") % temptag.GetInt(); | |||
| 495 | } else { | |||
| 496 | m_strModVersion = wxT("ModID=<Unknown>")L"ModID=<Unknown>"; | |||
| 497 | } | |||
| 498 | ||||
| 499 | break; | |||
| 500 | ||||
| 501 | case CT_PORT: | |||
| 502 | nUserPort = temptag.GetInt(); | |||
| 503 | break; | |||
| 504 | ||||
| 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)theLogger.AddLogLine(L"BaseClient.cpp", 512, false, logStandard , CFormat(L"Hello type packet processing with eMule ports UDP=%i KAD=%i" ) % m_nUDPPort % m_nKadPort, true); | |||
| 513 | #endif | |||
| 514 | break; | |||
| 515 | ||||
| 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))theLogger.AddLogLine(L"BaseClient.cpp", 520, false, logStandard , CFormat(L"Hello type packet processing with eMule BuddyIP=%u (%s)" ) % m_nBuddyIP % Uint32toStringIP(m_nBuddyIP), true); | |||
| 521 | #endif | |||
| 522 | break; | |||
| 523 | ||||
| 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)theLogger.AddLogLine(L"BaseClient.cpp", 529, false, logStandard , CFormat(L"Hello type packet processing with eMule BuddyPort=%u" ) % m_nBuddyPort, true); | |||
| 530 | #endif | |||
| 531 | break; | |||
| 532 | ||||
| 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:"))theLogger.AddLogLine(L"BaseClient.cpp", 560, false, logStandard , L"Hello type packet processing with eMule Misc Options:", true ); | |||
| 561 | AddLogLineNS(CFormat(wxT("m_byUDPVer = %i")) % m_byUDPVer)theLogger.AddLogLine(L"BaseClient.cpp", 561, false, logStandard , CFormat(L"m_byUDPVer = %i") % m_byUDPVer, true); | |||
| 562 | AddLogLineNS(CFormat(wxT("m_byDataCompVer = %i")) % m_byDataCompVer)theLogger.AddLogLine(L"BaseClient.cpp", 562, false, logStandard , CFormat(L"m_byDataCompVer = %i") % m_byDataCompVer, true); | |||
| 563 | AddLogLineNS(CFormat(wxT("m_bySupportSecIdent = %i")) % m_bySupportSecIdent)theLogger.AddLogLine(L"BaseClient.cpp", 563, false, logStandard , CFormat(L"m_bySupportSecIdent = %i") % m_bySupportSecIdent, true); | |||
| 564 | AddLogLineNS(CFormat(wxT("m_bySourceExchangeVer = %i")) % m_bySourceExchange1Ver)theLogger.AddLogLine(L"BaseClient.cpp", 564, false, logStandard , CFormat(L"m_bySourceExchangeVer = %i") % m_bySourceExchange1Ver , true); | |||
| 565 | AddLogLineNS(CFormat(wxT("m_byExtendedRequestsVer = %i")) % m_byExtendedRequestsVer)theLogger.AddLogLine(L"BaseClient.cpp", 565, false, logStandard , CFormat(L"m_byExtendedRequestsVer = %i") % m_byExtendedRequestsVer , true); | |||
| 566 | AddLogLineNS(CFormat(wxT("m_byAcceptCommentVer = %i")) % m_byAcceptCommentVer)theLogger.AddLogLine(L"BaseClient.cpp", 566, false, logStandard , CFormat(L"m_byAcceptCommentVer = %i") % m_byAcceptCommentVer , true); | |||
| 567 | AddLogLineNS(CFormat(wxT("m_fNoViewSharedFiles = %i")) % m_fNoViewSharedFiles)theLogger.AddLogLine(L"BaseClient.cpp", 567, false, logStandard , CFormat(L"m_fNoViewSharedFiles = %i") % m_fNoViewSharedFiles , true); | |||
| 568 | AddLogLineNS(CFormat(wxT("m_bMultiPacket = %i")) % m_bMultiPacket)theLogger.AddLogLine(L"BaseClient.cpp", 568, false, logStandard , CFormat(L"m_bMultiPacket = %i") % m_bMultiPacket, true); | |||
| 569 | AddLogLineNS(CFormat(wxT("m_fSupportsPreview = %i")) % m_fSharedDirectories)theLogger.AddLogLine(L"BaseClient.cpp", 569, false, logStandard , CFormat(L"m_fSupportsPreview = %i") % m_fSharedDirectories, true); | |||
| 570 | AddLogLineNS(wxT("That's all."))theLogger.AddLogLine(L"BaseClient.cpp", 570, false, logStandard , L"That's all.", true); | |||
| 571 | #endif | |||
| 572 | SecIdentSupRec += 1; | |||
| 573 | break; | |||
| 574 | } | |||
| 575 | ||||
| 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; | |||
| 599 | ||||
| 600 | m_fRequestsCryptLayer &= m_fSupportsCryptLayer; | |||
| 601 | m_fRequiresCryptLayer &= m_fRequestsCryptLayer; | |||
| 602 | ||||
| 603 | #ifdef __PACKET_DEBUG__ | |||
| 604 | AddLogLineNS(wxT("Hello type packet processing with eMule Misc Options 2:"))theLogger.AddLogLine(L"BaseClient.cpp", 604, false, logStandard , L"Hello type packet processing with eMule Misc Options 2:", true); | |||
| 605 | AddLogLineNS(CFormat(wxT(" m_fDirectUDPCallback = %i")) % m_fDirectUDPCallback)theLogger.AddLogLine(L"BaseClient.cpp", 605, false, logStandard , CFormat(L" m_fDirectUDPCallback = %i") % m_fDirectUDPCallback , true); | |||
| 606 | AddLogLineNS(CFormat(wxT(" m_fSupportsCaptcha = %i")) % m_fSupportsCaptcha)theLogger.AddLogLine(L"BaseClient.cpp", 606, false, logStandard , CFormat(L" m_fSupportsCaptcha = %i") % m_fSupportsCaptcha, true); | |||
| 607 | AddLogLineNS(CFormat(wxT(" m_fSupportsSourceEx2 = %i")) % m_fSupportsSourceEx2)theLogger.AddLogLine(L"BaseClient.cpp", 607, false, logStandard , CFormat(L" m_fSupportsSourceEx2 = %i") % m_fSupportsSourceEx2 , true); | |||
| 608 | AddLogLineNS(CFormat(wxT(" m_fRequiresCryptLayer = %i")) % m_fRequiresCryptLayer)theLogger.AddLogLine(L"BaseClient.cpp", 608, false, logStandard , CFormat(L" m_fRequiresCryptLayer = %i") % m_fRequiresCryptLayer , true); | |||
| 609 | AddLogLineNS(CFormat(wxT(" m_fRequestsCryptLayer = %i")) % m_fRequestsCryptLayer)theLogger.AddLogLine(L"BaseClient.cpp", 609, false, logStandard , CFormat(L" m_fRequestsCryptLayer = %i") % m_fRequestsCryptLayer , true); | |||
| 610 | AddLogLineNS(CFormat(wxT(" m_fSupportsCryptLayer = %i")) % m_fSupportsCryptLayer)theLogger.AddLogLine(L"BaseClient.cpp", 610, false, logStandard , CFormat(L" m_fSupportsCryptLayer = %i") % m_fSupportsCryptLayer , true); | |||
| 611 | AddLogLineNS(CFormat(wxT(" m_fExtMultiPacket = %i")) % m_fExtMultiPacket)theLogger.AddLogLine(L"BaseClient.cpp", 611, false, logStandard , CFormat(L" m_fExtMultiPacket = %i") % m_fExtMultiPacket, true ); | |||
| 612 | AddLogLineNS(CFormat(wxT(" m_fSupportsLargeFiles = %i")) % m_fSupportsLargeFiles)theLogger.AddLogLine(L"BaseClient.cpp", 612, false, logStandard , CFormat(L" m_fSupportsLargeFiles = %i") % m_fSupportsLargeFiles , true); | |||
| 613 | AddLogLineNS(CFormat(wxT(" KadVersion = %u")) % m_byKadVersion)theLogger.AddLogLine(L"BaseClient.cpp", 613, false, logStandard , CFormat(L" KadVersion = %u") % m_byKadVersion, true); | |||
| 614 | AddLogLineNS(wxT("That's all."))theLogger.AddLogLine(L"BaseClient.cpp", 614, false, logStandard , L"That's all.", true); | |||
| 615 | #endif | |||
| 616 | break; | |||
| 617 | ||||
| 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; | |||
| 625 | ||||
| 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; | |||
| 638 | } | |||
| 639 | } | |||
| 640 | ||||
| 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 | |||
| 651 | */ | |||
| 652 | if (test == 0x4b444c4d) { //if it's == "KDLM" | |||
| 653 | m_bIsML=true; | |||
| 654 | } else{ | |||
| 655 | m_bIsHybrid = true; | |||
| 656 | m_fSharedDirectories = 1; | |||
| 657 | } | |||
| 658 | } | |||
| 659 | ||||
| 660 | if (m_socket) { | |||
| 661 | SetIP(m_socket->GetPeerInt()); | |||
| 662 | } else { | |||
| 663 | throw wxString(wxT("Huh, socket failure. Avoided crash this time.")L"Huh, socket failure. Avoided crash this time."); | |||
| 664 | } | |||
| 665 | ||||
| 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; | |||
| 671 | } | |||
| 672 | } | |||
| 673 | ||||
| 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)((wxUint32) ( (((wxUint32) (m_dwUserIP) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (m_dwUserIP) & (wxUint32) 0x0000ff00U ) << 8) | (((wxUint32) (m_dwUserIP) & (wxUint32) 0x00ff0000U ) >> 8) | (((wxUint32) (m_dwUserIP) & (wxUint32) 0xff000000U ) >> 24)))); | |||
| 680 | } | |||
| 681 | ||||
| 682 | // get client credits | |||
| 683 | CClientCredits* pFoundCredits = theApp->clientcredits->GetCredit(m_UserHash); | |||
| 684 | if (credits == NULL__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() )do {} while (false); | |||
| 688 | Ban(); | |||
| 689 | } | |||
| 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() )do {} while (false); | |||
| 694 | Ban(); | |||
| 695 | } | |||
| 696 | ||||
| 697 | if ((m_Friend = theApp->friendlist->FindFriend(m_UserHash, m_dwUserIP, m_nUserPort)) != NULL__null){ | |||
| 698 | m_Friend->LinkClient(CCLIENTREF(this, wxT("CUpDownClient::ProcessHelloTypePacket m_Friend->LinkClient"))CClientRef(this)); | |||
| 699 | } else{ | |||
| 700 | // avoid that an unwanted client instance keeps a friend slot | |||
| 701 | SetFriendSlot(false); | |||
| 702 | } | |||
| 703 | ||||
| 704 | ||||
| 705 | ReGetClientSoft(); | |||
| 706 | ||||
| 707 | m_byInfopacketsReceived |= IP_EDONKEYPROTPACK; | |||
| 708 | ||||
| 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; | |||
| 714 | } | |||
| 715 | ||||
| 716 | if (GetKadPort() && GetKadVersion() > 1) { | |||
| 717 | Kademlia::CKademlia::Bootstrap(wxUINT32_SWAP_ALWAYS(GetIP())((wxUint32) ( (((wxUint32) (GetIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetIP()) & (wxUint32) 0x0000ff00U ) << 8) | (((wxUint32) (GetIP()) & (wxUint32) 0x00ff0000U ) >> 8) | (((wxUint32) (GetIP()) & (wxUint32) 0xff000000U ) >> 24))), GetKadPort()); | |||
| 718 | } | |||
| 719 | ||||
| 720 | return bIsMule; | |||
| 721 | } | |||
| 722 | ||||
| 723 | ||||
| 724 | bool CUpDownClient::SendHelloPacket() | |||
| 725 | { | |||
| 726 | wxCHECK(m_socket != NULL, true)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 726, __FUNCTION__, "\"m_socket != __null\"" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); return true ; } struct wxDummyCheckStruct726; | |||
| 727 | ||||
| 728 | // if IP is filtered, don't greet him but disconnect... | |||
| 729 | if (theApp->ipfilter->IsFiltered(m_socket->GetPeerInt())) { | |||
| 730 | if (Disconnected(wxT("IPFilter")L"IPFilter")) { | |||
| 731 | Safe_Delete(); | |||
| 732 | return false; | |||
| 733 | } | |||
| 734 | return true; | |||
| 735 | } | |||
| 736 | ||||
| 737 | CMemFile data(128); | |||
| 738 | data.WriteUInt8(16); // size of userhash | |||
| 739 | SendHelloTypePacket(&data); | |||
| 740 | ||||
| 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() )do {} while (false); | |||
| 746 | return true; | |||
| 747 | } | |||
| 748 | ||||
| 749 | void CUpDownClient::SendMuleInfoPacket(bool bAnswer, bool OSInfo) | |||
| 750 | { | |||
| 751 | wxCHECK2(m_socket != NULL, return)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 751, __FUNCTION__, "\"m_socket != __null\"" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct751; | |||
| 752 | ||||
| 753 | CPacket* packet = NULL__null; | |||
| 754 | CMemFile data; | |||
| 755 | ||||
| 756 | data.WriteUInt8(CURRENT_VERSION_SHORT0x47); | |||
| 757 | ||||
| 758 | if (OSInfo) { | |||
| 759 | ||||
| 760 | // Special MuleInfo packet for clients supporting it. | |||
| 761 | // This means aMule >= 2.0.0 and Hydranode | |||
| 762 | ||||
| 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. | |||
| 766 | ||||
| 767 | data.WriteUInt8(/*EMULE_PROTOCOL*/ 0xFF); | |||
| 768 | ||||
| 769 | data.WriteUInt32(1); // One Tag (OS_INFO) | |||
| 770 | ||||
| 771 | CTagString tag1(ET_OS_INFO,theApp->GetOSType()); | |||
| 772 | tag1.WriteTagToFile(&data); | |||
| 773 | ||||
| 774 | m_OSInfo_sent = true; // So we don't send it again | |||
| 775 | ||||
| 776 | } else { | |||
| 777 | ||||
| 778 | // Normal MuleInfo packet | |||
| 779 | ||||
| 780 | // Kry - There's no point on upgrading to VBT tags here | |||
| 781 | // as no client supporting it uses mule info packet. | |||
| 782 | ||||
| 783 | data.WriteUInt8(EMULE_PROTOCOL0x01); | |||
| 784 | ||||
| 785 | // Tag number | |||
| 786 | data.WriteUInt32(9); | |||
| 787 | ||||
| 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); | |||
| 800 | ||||
| 801 | uint32 dwTagValue = (theApp->CryptoAvailable() ? 3 : 0); | |||
| 802 | // Kry - Needs the preview code from eMule | |||
| 803 | /* | |||
| 804 | // set 'Preview supported' only if 'View Shared Files' allowed | |||
| 805 | if (thePrefs::CanSeeShares() != vsfaNobody) { | |||
| 806 | dwTagValue |= 128; | |||
| 807 | } | |||
| 808 | */ | |||
| 809 | CTagInt32 tag7(ET_FEATURES, dwTagValue); | |||
| 810 | tag7.WriteTagToFile(&data); | |||
| 811 | ||||
| 812 | CTagInt32 tag8(ET_COMPATIBLECLIENT,SO_AMULE); | |||
| 813 | tag8.WriteTagToFile(&data); | |||
| 814 | ||||
| 815 | // Support for tag ET_MOD_VERSION | |||
| 816 | wxString mod_name(MOD_VERSION_LONGL"aMule SVN"); | |||
| 817 | CTagString tag9(ET_MOD_VERSION, mod_name); | |||
| 818 | tag9.WriteTagToFile(&data); | |||
| 819 | // Maella end | |||
| 820 | ||||
| 821 | } | |||
| 822 | ||||
| 823 | packet = new CPacket(data, OP_EMULEPROT, (bAnswer ? OP_EMULEINFOANSWER : OP_EMULEINFO)); | |||
| 824 | ||||
| 825 | if (m_socket) { | |||
| 826 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 827 | SendPacket(packet,true,true); | |||
| 828 | ||||
| 829 | #ifdef __DEBUG__ | |||
| 830 | if (!bAnswer) { | |||
| 831 | if (!OSInfo) { | |||
| 832 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_EMULEINFO to ") + GetFullIP() )do {} while (false); | |||
| 833 | } else { | |||
| 834 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_EMULEINFO/OS_INFO to ") + GetFullIP() )do {} while (false); | |||
| 835 | } | |||
| 836 | } else { | |||
| 837 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_EMULEINFOANSWER to ") + GetFullIP() )do {} while (false); | |||
| 838 | } | |||
| 839 | #endif | |||
| 840 | } | |||
| 841 | } | |||
| 842 | ||||
| 843 | bool CUpDownClient::ProcessMuleInfoPacket(const uint8_t* pachPacket, uint32 nSize) | |||
| 844 | { | |||
| 845 | uint8 protocol_version; | |||
| 846 | ||||
| 847 | const CMemFile data(pachPacket,nSize); | |||
| 848 | ||||
| 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(); | |||
| 868 | ||||
| 869 | // If we didn't send our OSInfo to this client, just send it | |||
| 870 | if (!m_OSInfo_sent) { | |||
| 871 | SendMuleInfoPacket(false,true); | |||
| 872 | } | |||
| 873 | ||||
| 874 | UpdateStats(); | |||
| 875 | ||||
| 876 | break; | |||
| 877 | ||||
| 878 | // Your ad... er... I mean TAG, here | |||
| 879 | ||||
| 880 | default: | |||
| 881 | break; | |||
| 882 | } | |||
| 883 | } | |||
| 884 | } else { | |||
| 885 | // Old eMule sending tags | |||
| 886 | m_byCompatibleClient = 0; | |||
| 887 | m_byEmuleVersion = mule_version; | |||
| 888 | ||||
| 889 | if( m_byEmuleVersion == 0x2B ) { | |||
| 890 | m_byEmuleVersion = 0x22; | |||
| 891 | } | |||
| 892 | ||||
| 893 | if (!(m_bEmuleProtocol = (protocol_version == EMULE_PROTOCOL0x01))) { | |||
| 894 | return false; | |||
| 895 | } | |||
| 896 | ||||
| 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; | |||
| 905 | ||||
| 906 | case ET_UDPPORT: | |||
| 907 | // Bits 31-16: 0 - reserved | |||
| 908 | // Bits 15- 0: UDP port | |||
| 909 | m_nUDPPort = temptag.GetInt(); | |||
| 910 | break; | |||
| 911 | ||||
| 912 | case ET_UDPVER: | |||
| 913 | // Bits 31- 8: 0 - reserved | |||
| 914 | // Bits 7- 0: UDP protocol version | |||
| 915 | m_byUDPVer = temptag.GetInt(); | |||
| 916 | break; | |||
| 917 | ||||
| 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; | |||
| 923 | ||||
| 924 | case ET_COMMENTS: | |||
| 925 | // Bits 31- 8: 0 - reserved | |||
| 926 | // Bits 7- 0: comments version | |||
| 927 | m_byAcceptCommentVer = temptag.GetInt(); | |||
| 928 | break; | |||
| 929 | ||||
| 930 | case ET_EXTENDEDREQUEST: | |||
| 931 | // Bits 31- 8: 0 - reserved | |||
| 932 | // Bits 7- 0: extended requests version | |||
| 933 | m_byExtendedRequestsVer = temptag.GetInt(); | |||
| 934 | break; | |||
| 935 | ||||
| 936 | case ET_COMPATIBLECLIENT: | |||
| 937 | // Bits 31- 8: 0 - reserved | |||
| 938 | // Bits 7- 0: compatible client ID | |||
| 939 | m_byCompatibleClient = temptag.GetInt(); | |||
| 940 | break; | |||
| 941 | ||||
| 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; | |||
| 950 | ||||
| 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")L"ModID=%u") % temptag.GetInt(); | |||
| 956 | } else { | |||
| 957 | m_strModVersion = wxT("ModID=<Unknown>")L"ModID=<Unknown>"; | |||
| 958 | } | |||
| 959 | ||||
| 960 | break; | |||
| 961 | ||||
| 962 | default: | |||
| 963 | AddDebugLogLineN( logPacketErrors,do {} while (false) | |||
| 964 | CFormat( wxT("Unknown Mule tag (%s) from client: %s") )do {} while (false) | |||
| 965 | % temptag.GetFullInfo()do {} while (false) | |||
| 966 | % GetClientFullInfo()do {} while (false) | |||
| 967 | )do {} while (false); | |||
| 968 | ||||
| 969 | break; | |||
| 970 | } | |||
| 971 | } | |||
| 972 | ||||
| 973 | if( m_byDataCompVer == 0 ){ | |||
| 974 | m_bySourceExchange1Ver = 0; | |||
| 975 | m_byExtendedRequestsVer = 0; | |||
| 976 | m_byAcceptCommentVer = 0; | |||
| 977 | m_nUDPPort = 0; | |||
| 978 | } | |||
| 979 | ||||
| 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; | |||
| 984 | } | |||
| 985 | ||||
| 986 | if(m_byEmuleVersion < 0x25 && m_byEmuleVersion > 0x21) { | |||
| 987 | m_bySourceExchange1Ver = 1; | |||
| 988 | } | |||
| 989 | ||||
| 990 | if(m_byEmuleVersion == 0x24) { | |||
| 991 | m_byAcceptCommentVer = 1; | |||
| 992 | } | |||
| 993 | ||||
| 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; | |||
| 999 | } | |||
| 1000 | ||||
| 1001 | ReGetClientSoft(); | |||
| 1002 | ||||
| 1003 | m_byInfopacketsReceived |= IP_EMULEPROTPACK; | |||
| 1004 | } | |||
| 1005 | ||||
| 1006 | return (protocol_version == 0xFF); // This was a OS_Info? | |||
| 1007 | } | |||
| 1008 | ||||
| 1009 | ||||
| 1010 | void CUpDownClient::SendHelloAnswer() | |||
| 1011 | { | |||
| 1012 | wxCHECK2(m_socket != NULL, return)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 1012, __FUNCTION__, "\"m_socket != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct1012; | |||
| 1013 | ||||
| 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() )do {} while (false); | |||
| 1019 | SendPacket(packet,true); | |||
| 1020 | } | |||
| 1021 | ||||
| 1022 | ||||
| 1023 | void CUpDownClient::SendHelloTypePacket(CMemFile* data) | |||
| 1024 | { | |||
| 1025 | data->WriteHash(thePrefs::GetUserHash()); | |||
| 1026 | data->WriteUInt32(theApp->GetID()); | |||
| 1027 | data->WriteUInt16(thePrefs::GetPort()); | |||
| 1028 | ||||
| 1029 | uint32 tagcount = 6; | |||
| 1030 | ||||
| 1031 | if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) { | |||
| 1032 | tagcount += 2; | |||
| 1033 | } | |||
| 1034 | tagcount ++; // eMule misc flags 2 (kad version) | |||
| 1035 | ||||
| 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 | |||
| 1043 | ||||
| 1044 | ||||
| 1045 | CTagString tagname(CT_NAME,thePrefs::GetUserNick()); | |||
| 1046 | tagname.WriteTagToFile(data, utf8strRaw); | |||
| 1047 | ||||
| 1048 | CTagVarInt tagversion(CT_VERSION, EDONKEYVERSION0x3c, GetVBTTags() ? 0 : 32); | |||
| 1049 | tagversion.WriteTagToFile(data); | |||
| 1050 | // eMule UDP Ports | |||
| 1051 | ||||
| 1052 | uint32 kadUDPPort = 0; | |||
| 1053 | ||||
| 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(); | |||
| 1059 | } | |||
| 1060 | } | |||
| 1061 | ||||
| 1062 | CTagVarInt tagUdpPorts(CT_EMULE_UDPPORTS, (kadUDPPort << 16) | ((uint32)thePrefs::GetEffectiveUDPPort()), GetVBTTags() ? 0 : 32); | |||
| 1063 | tagUdpPorts.WriteTagToFile(data); | |||
| 1064 | ||||
| 1065 | if( theApp->clientlist->GetBuddy() && theApp->IsFirewalled() ) { | |||
| 1066 | CTagVarInt tagBuddyIP(CT_EMULE_BUDDYIP, theApp->clientlist->GetBuddy()->GetIP(), GetVBTTags() ? 0 : 32); | |||
| 1067 | tagBuddyIP.WriteTagToFile(data); | |||
| 1068 | ||||
| 1069 | CTagVarInt tagBuddyPort(CT_EMULE_BUDDYUDP, | |||
| 1070 | // ( RESERVED ) | |||
| 1071 | ((uint32)theApp->clientlist->GetBuddy()->GetUDPPort() ) | |||
| 1072 | , GetVBTTags() ? 0 : 32); | |||
| 1073 | tagBuddyPort.WriteTagToFile(data); | |||
| 1074 | } | |||
| 1075 | ||||
| 1076 | // aMule Version | |||
| 1077 | CTagVarInt tagMuleVersion(CT_EMULE_VERSION, | |||
| 1078 | (SO_AMULE << 24) | | |||
| 1079 | make_full_ed2k_version(VERSION_MJR2, VERSION_MIN4, VERSION_UPDATE0) | |||
| 1080 | // | (RESERVED ) | |||
| 1081 | , GetVBTTags() ? 0 : 32); | |||
| 1082 | tagMuleVersion.WriteTagToFile(data); | |||
| 1083 | ||||
| 1084 | ||||
| 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. | |||
| 1098 | ||||
| 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); | |||
| 1114 | ||||
| 1115 | // eMule Misc. Options #2 | |||
| 1116 | const uint32 uKadVersion = KADEMLIA_VERSION0x08; | |||
| 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; | |||
| 1133 | ||||
| 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); | |||
| 1148 | ||||
| 1149 | const uint32 nOSInfoSupport = 1; // We support OS_INFO | |||
| 1150 | const uint32 nValueBasedTypeTags = 0; // Experimental, disabled | |||
| 1151 | ||||
| 1152 | CTagVarInt tagMisCompatOptions(CT_EMULECOMPAT_OPTIONS, | |||
| 1153 | (nValueBasedTypeTags << 1*1) | | |||
| 1154 | (nOSInfoSupport << 1*0) | |||
| 1155 | , GetVBTTags() ? 0 : 32); | |||
| 1156 | ||||
| 1157 | tagMisCompatOptions.WriteTagToFile(data); | |||
| 1158 | ||||
| 1159 | #ifdef __SVN__ | |||
| 1160 | wxString mod_name(MOD_VERSION_LONGL"aMule SVN"); | |||
| 1161 | CTagString tagModName(ET_MOD_VERSION, mod_name); | |||
| 1162 | tagModName.WriteTagToFile(data); | |||
| 1163 | #endif | |||
| 1164 | ||||
| 1165 | uint32 dwIP = 0; | |||
| 1166 | uint16 nPort = 0; | |||
| 1167 | if (theApp->IsConnectedED2K()) { | |||
| 1168 | dwIP = theApp->serverconnect->GetCurrentServer()->GetIP(); | |||
| 1169 | nPort = theApp->serverconnect->GetCurrentServer()->GetPort(); | |||
| 1170 | } | |||
| 1171 | data->WriteUInt32(dwIP); | |||
| 1172 | data->WriteUInt16(nPort); | |||
| 1173 | } | |||
| 1174 | ||||
| 1175 | ||||
| 1176 | void CUpDownClient::ProcessMuleCommentPacket(const uint8_t* pachPacket, uint32 nSize) | |||
| 1177 | { | |||
| 1178 | if (!m_reqfile) { | |||
| 1179 | throw CInvalidPacket(wxT("Comment packet for unknown file")L"Comment packet for unknown file"); | |||
| 1180 | } | |||
| 1181 | ||||
| 1182 | if (!m_reqfile->IsPartFile()) { | |||
| 1183 | throw CInvalidPacket(wxT("Comment packet for completed file")L"Comment packet for completed file"); | |||
| 1184 | } | |||
| 1185 | ||||
| 1186 | const CMemFile data(pachPacket, nSize); | |||
| 1187 | ||||
| 1188 | uint8 rating = data.ReadUInt8(); | |||
| 1189 | if (rating > 5) { | |||
| 1190 | AddDebugLogLineN( logClient, wxString(wxT("Invalid Rating for file '")) << m_clientFilename << wxT("' received: ") << rating)do {} while (false); | |||
| 1191 | m_iRating = 0; | |||
| 1192 | } else { | |||
| 1193 | m_iRating = rating; | |||
| 1194 | AddDebugLogLineN( logClient, wxString(wxT("Rating for file '")) << m_clientFilename << wxT("' received: ") << m_iRating)do {} while (false); | |||
| 1195 | } | |||
| 1196 | ||||
| 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(MAXFILECOMMENTLEN50); | |||
| 1201 | ||||
| 1202 | AddDebugLogLineN( logClient, wxString(wxT("Description for file '")) << m_clientFilename << wxT("' received: ") << m_strComment)do {} while (false); | |||
| 1203 | ||||
| 1204 | // Update file rating | |||
| 1205 | m_reqfile->UpdateFileRatingCommentAvail(); | |||
| 1206 | } | |||
| 1207 | ||||
| 1208 | ||||
| 1209 | void CUpDownClient::ClearDownloadBlockRequests() | |||
| 1210 | { | |||
| 1211 | { | |||
| 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; | |||
| 1215 | ||||
| 1216 | if (m_reqfile){ | |||
| 1217 | m_reqfile->RemoveBlockFromList(cur_block->StartOffset, cur_block->EndOffset); | |||
| 1218 | } | |||
| 1219 | ||||
| 1220 | delete cur_block; | |||
| 1221 | } | |||
| 1222 | ||||
| 1223 | m_DownloadBlocks_list.clear(); | |||
| 1224 | } | |||
| 1225 | ||||
| 1226 | { | |||
| 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; | |||
| 1230 | ||||
| 1231 | if (m_reqfile) { | |||
| 1232 | m_reqfile->RemoveBlockFromList(pending->block->StartOffset, pending->block->EndOffset); | |||
| 1233 | } | |||
| 1234 | ||||
| 1235 | delete pending->block; | |||
| 1236 | // Not always allocated | |||
| 1237 | if (pending->zStream){ | |||
| 1238 | inflateEnd(pending->zStream); | |||
| 1239 | delete pending->zStream; | |||
| 1240 | } | |||
| 1241 | ||||
| 1242 | delete pending; | |||
| 1243 | } | |||
| 1244 | ||||
| 1245 | m_PendingBlocks_list.clear(); | |||
| 1246 | } | |||
| 1247 | } | |||
| 1248 | ||||
| 1249 | ||||
| 1250 | bool CUpDownClient::Disconnected(const wxString& DEBUG_ONLY(strReason), bool bFromSocket) | |||
| 1251 | { | |||
| 1252 | //wxASSERT(theApp->clientlist->IsValidClient(this)); | |||
| 1253 | ||||
| 1254 | if (HasBeenDeleted()) { | |||
| 1255 | AddDebugLogLineN(logClient, wxT("Disconnected() called for already deleted client on ip ") + Uint32toStringIP(GetConnectIP()))do {} while (false); | |||
| 1256 | return false; | |||
| 1257 | } | |||
| 1258 | ||||
| 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()))do {} while (false); | |||
| 1265 | } | |||
| 1266 | ||||
| 1267 | if (GetKadState() == KS_QUEUED_FWCHECK_UDP || GetKadState() == KS_CONNECTING_FWCHECK_UDP) { | |||
| 1268 | Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetConnectIP())((wxUint32) ( (((wxUint32) (GetConnectIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetConnectIP()) & (wxUint32 ) 0x0000ff00U) << 8) | (((wxUint32) (GetConnectIP()) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (GetConnectIP ()) & (wxUint32) 0xff000000U) >> 24))), 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())((wxUint32) ( (((wxUint32) (GetConnectIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetConnectIP()) & (wxUint32 ) 0x0000ff00U) << 8) | (((wxUint32) (GetConnectIP()) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (GetConnectIP ()) & (wxUint32) 0xff000000U) >> 24))), 0); // inform the tester that this test has failed | |||
| 1271 | } else if (GetKadState() == KS_CONNECTED_BUDDY) { | |||
| 1272 | AddDebugLogLineN(logClient, wxT("Buddy client disconnected - ") + strReason)do {} while (false); | |||
| 1273 | } | |||
| 1274 | ||||
| 1275 | //If this is a KAD client object, just delete it! | |||
| 1276 | SetKadState(KS_NONE); | |||
| 1277 | ||||
| 1278 | if (GetUploadState() == US_UPLOADING) { | |||
| 1279 | // sets US_NONE | |||
| 1280 | theApp->uploadqueue->RemoveFromUploadQueue(this); | |||
| 1281 | } | |||
| 1282 | ||||
| 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(); | |||
| 1288 | ||||
| 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); | |||
| 1293 | } | |||
| 1294 | } | |||
| 1295 | ||||
| 1296 | // we had still an AICH request pending, handle it | |||
| 1297 | if (IsAICHReqPending()) { | |||
| 1298 | m_fAICHRequested = FALSE0; | |||
| 1299 | CAICHHashSet::ClientAICHRequestFailed(this); | |||
| 1300 | } | |||
| 1301 | ||||
| 1302 | // The remote client does not have to answer with OP_HASHSETANSWER *immediately* | |||
| 1303 | // after we've sent OP_HASHSETREQUEST. It may occur 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); | |||
| 1307 | } | |||
| 1308 | ||||
| 1309 | SourceItemType source_type = UNAVAILABLE_SOURCE; | |||
| 1310 | SourceItemType peer_type = UNAVAILABLE_SOURCE; | |||
| 1311 | ||||
| 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; | |||
| 1319 | }; | |||
| 1320 | ||||
| 1321 | switch (m_nDownloadState) { | |||
| 1322 | case DS_ONQUEUE: | |||
| 1323 | source_type = A4AF_SOURCE; // Will be checked. | |||
| 1324 | /* fall through */ | |||
| 1325 | case DS_TOOMANYCONNS: | |||
| 1326 | case DS_NONEEDEDPARTS: | |||
| 1327 | case DS_LOWTOLOWIP: | |||
| 1328 | bDelete = false; | |||
| 1329 | break; | |||
| 1330 | }; | |||
| 1331 | ||||
| 1332 | switch (m_nUploadState) { | |||
| 1333 | case US_CONNECTING: | |||
| 1334 | case US_WAITCALLBACK: | |||
| 1335 | case US_ERROR: | |||
| 1336 | theApp->clientlist->AddDeadSource(this); | |||
| 1337 | bDelete = true; | |||
| 1338 | }; | |||
| 1339 | ||||
| 1340 | switch (m_nDownloadState) { | |||
| 1341 | case DS_CONNECTING: | |||
| 1342 | case DS_WAITCALLBACK: | |||
| 1343 | case DS_ERROR: | |||
| 1344 | case DS_BANNED: | |||
| 1345 | theApp->clientlist->AddDeadSource(this); | |||
| 1346 | bDelete = true; | |||
| 1347 | }; | |||
| 1348 | ||||
| 1349 | ||||
| 1350 | // We keep chat partners in any case | |||
| 1351 | if (GetChatState() != MS_NONE) { | |||
| 1352 | bDelete = false; | |||
| 1353 | m_pendingMessage.Clear(); | |||
| 1354 | Notify_ChatConnResult(false,GUI_ID(GetIP(),GetUserPort()),wxEmptyString)MuleNotify::DoNotify(&MuleNotify::ChatConnResult, false, ( uint64)((((uint64)GetIP())<<16) + (uint64)GetUserPort() ), wxEmptyString); | |||
| 1355 | } | |||
| 1356 | ||||
| 1357 | // Delete socket | |||
| 1358 | if (!bFromSocket && m_socket) { | |||
| 1359 | wxASSERT (theApp->listensocket->IsValidSocket(m_socket))do { if ( theApp->listensocket->IsValidSocket(m_socket) ) { } else if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp" , 1359, __FUNCTION__, "theApp->listensocket->IsValidSocket(m_socket)" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 1360 | m_socket->Safe_Delete(); | |||
| 1361 | } | |||
| 1362 | ||||
| 1363 | SetSocket(NULL__null); | |||
| 1364 | ||||
| 1365 | if (m_iFileListRequested) { | |||
| 1366 | AddLogLineC(CFormat(_("Failed to retrieve shared files from user '%s'")) % GetUserName() )theLogger.AddLogLine(L"BaseClient.cpp", 1366, true, logStandard , CFormat(wxGetTranslation(("Failed to retrieve shared files from user '%s'" ))) % GetUserName()); | |||
| 1367 | m_iFileListRequested = 0; | |||
| 1368 | } | |||
| 1369 | ||||
| 1370 | ||||
| 1371 | if (bDelete) { | |||
| 1372 | if (m_Friend) { | |||
| 1373 | // Remove the friend linkage | |||
| 1374 | m_Friend->UnLinkClient(); // this notifies | |||
| 1375 | } | |||
| 1376 | } else { | |||
| 1377 | Notify_SharedCtrlRefreshClient(ECID(), peer_type)MuleNotify::DoNotify(&MuleNotify::SharedCtrlRefreshClient , ECID(), peer_type); | |||
| 1378 | Notify_SourceCtrlUpdateSource(ECID(), source_type)MuleNotify::DoNotify(&MuleNotify::SourceCtrlUpdateSource, ECID(), source_type); | |||
| 1379 | ||||
| 1380 | m_fHashsetRequesting = 0; | |||
| 1381 | SetSentCancelTransfer(0); | |||
| 1382 | m_bHelloAnswerPending = false; | |||
| 1383 | m_fSentOutOfPartReqs = 0; | |||
| 1384 | } | |||
| 1385 | AddDebugLogLineN(logClient, CFormat(wxT("--- %s client D:%d U:%d \"%s\"; Reason was %s"))do {} while (false) | |||
| 1386 | % (bDelete ? wxT("Deleted") : wxT("Disconnected"))do {} while (false) | |||
| 1387 | % m_nDownloadState % m_nUploadState % GetClientFullInfo() % strReason )do {} while (false); | |||
| 1388 | ||||
| 1389 | return bDelete; | |||
| 1390 | } | |||
| 1391 | ||||
| 1392 | //Returned bool is not if the TryToConnect is successful or not.. | |||
| 1393 | //false means the client was deleted! | |||
| 1394 | //true means the client was not deleted! | |||
| 1395 | bool CUpDownClient::TryToConnect(bool bIgnoreMaxCon) | |||
| 1396 | { | |||
| 1397 | // Kad reviewed | |||
| 1398 | if (theApp->listensocket->TooManySockets() && !bIgnoreMaxCon ) { | |||
| 1399 | if (!(m_socket && m_socket->IsConnected())) { | |||
| 1400 | if(Disconnected(wxT("Too many connections")L"Too many connections")) { | |||
| 1401 | Safe_Delete(); | |||
| 1402 | return false; | |||
| 1403 | } | |||
| 1404 | return true; | |||
| 1405 | } | |||
| 1406 | } | |||
| 1407 | ||||
| 1408 | // Do not try to connect to source which are incompatible with our encryption setting (one requires it, and the other one doesn't supports it) | |||
| 1409 | if ( (RequiresCryptLayer() && !thePrefs::IsClientCryptLayerSupported()) || (thePrefs::IsClientCryptLayerRequired() && !SupportsCryptLayer()) ){ | |||
| 1410 | if(Disconnected(wxT("CryptLayer-Settings (Obfuscation) incompatible")L"CryptLayer-Settings (Obfuscation) incompatible")){ | |||
| 1411 | Safe_Delete(); | |||
| 1412 | return false; | |||
| 1413 | } else { | |||
| 1414 | return true; | |||
| 1415 | } | |||
| 1416 | } | |||
| 1417 | ||||
| 1418 | // Ipfilter check | |||
| 1419 | uint32 uClientIP = GetIP(); | |||
| 1420 | if (uClientIP == 0 && !HasLowID()) { | |||
| 1421 | uClientIP = wxUINT32_SWAP_ALWAYS(m_nUserIDHybrid)((wxUint32) ( (((wxUint32) (m_nUserIDHybrid) & (wxUint32) 0x000000ffU) << 24) | (((wxUint32) (m_nUserIDHybrid) & (wxUint32) 0x0000ff00U) << 8) | (((wxUint32) (m_nUserIDHybrid ) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (m_nUserIDHybrid ) & (wxUint32) 0xff000000U) >> 24))); | |||
| 1422 | } | |||
| 1423 | ||||
| 1424 | if (uClientIP) { | |||
| 1425 | // Although we filter all received IPs (server sources, source exchange) and all incoming connection attempts, | |||
| 1426 | // we do have to filter outgoing connection attempts here too, because we may have updated the ip filter list | |||
| 1427 | if (theApp->ipfilter->IsFiltered(uClientIP)) { | |||
| 1428 | AddDebugLogLineN(logIPFilter, CFormat(wxT("Filtered ip %u (%s) on TryToConnect\n")) % uClientIP % Uint32toStringIP(uClientIP))do {} while (false); | |||
| 1429 | if (Disconnected(wxT("IPFilter")L"IPFilter")) { | |||
| 1430 | Safe_Delete(); | |||
| 1431 | return false; | |||
| 1432 | } | |||
| 1433 | return true; | |||
| 1434 | } | |||
| 1435 | ||||
| 1436 | // for safety: check again whether that IP is banned | |||
| 1437 | if (theApp->clientlist->IsBannedClient(uClientIP)) { | |||
| 1438 | AddDebugLogLineN(logClient, wxT("Refused to connect to banned client ") + Uint32toStringIP(uClientIP))do {} while (false); | |||
| 1439 | if (Disconnected(wxT("Banned IP")L"Banned IP")) { | |||
| 1440 | Safe_Delete(); | |||
| 1441 | return false; | |||
| 1442 | } | |||
| 1443 | return true; | |||
| 1444 | } | |||
| 1445 | } | |||
| 1446 | ||||
| 1447 | if (GetKadState() == KS_QUEUED_FWCHECK) { | |||
| 1448 | SetKadState(KS_CONNECTING_FWCHECK); | |||
| 1449 | } else if (GetKadState() == KS_QUEUED_FWCHECK_UDP) { | |||
| 1450 | SetKadState(KS_CONNECTING_FWCHECK_UDP); | |||
| 1451 | } | |||
| 1452 | ||||
| 1453 | if (HasLowID()) { | |||
| 1454 | if (!theApp->CanDoCallback(GetServerIP(), GetServerPort())) { | |||
| 1455 | //We cannot do a callback! | |||
| 1456 | if (GetDownloadState() == DS_CONNECTING) { | |||
| 1457 | SetDownloadState(DS_LOWTOLOWIP); | |||
| 1458 | } else if (GetDownloadState() == DS_REQHASHSET) { | |||
| 1459 | SetDownloadState(DS_ONQUEUE); | |||
| 1460 | m_reqfile->SetHashSetNeeded(true); | |||
| 1461 | } | |||
| 1462 | if (GetUploadState() == US_CONNECTING) { | |||
| 1463 | if(Disconnected(wxT("LowID->LowID and US_CONNECTING")L"LowID->LowID and US_CONNECTING")) { | |||
| 1464 | Safe_Delete(); | |||
| 1465 | return false; | |||
| 1466 | } | |||
| 1467 | } | |||
| 1468 | return true; | |||
| 1469 | } | |||
| 1470 | ||||
| 1471 | //We already know we are not firewalled here as the above condition already detected LowID->LowID and returned. | |||
| 1472 | //If ANYTHING changes with the "if(!theApp->CanDoCallback(this))" above that will let you fall through | |||
| 1473 | //with the condition that the source is firewalled and we are firewalled, we must | |||
| 1474 | //recheck it before the this check.. | |||
| 1475 | if (HasValidBuddyID() && !GetBuddyIP() && !GetBuddyPort() && !theApp->serverconnect->IsLocalServer(GetServerIP(), GetServerPort()) | |||
| 1476 | && !(SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0)) { | |||
| 1477 | //This is a Kad firewalled source that we want to do a special callback because it has no buddyIP or buddyPort. | |||
| 1478 | if( Kademlia::CKademlia::IsConnected() ) { | |||
| 1479 | //We are connect to Kad | |||
| 1480 | if( Kademlia::CKademlia::GetPrefs()->GetTotalSource() > 0 || Kademlia::CSearchManager::AlreadySearchingFor(Kademlia::CUInt128(GetBuddyID()))) { | |||
| 1481 | //There are too many source lookups already or we are already searching this key. | |||
| 1482 | SetDownloadState(DS_TOOMANYCONNSKAD); | |||
| 1483 | return true; | |||
| 1484 | } | |||
| 1485 | } | |||
| 1486 | } | |||
| 1487 | } | |||
| 1488 | ||||
| 1489 | if (!m_socket || !m_socket->IsConnected()) { | |||
| 1490 | if (m_socket) { | |||
| 1491 | m_socket->Safe_Delete(); | |||
| 1492 | } | |||
| 1493 | m_socket = new CClientTCPSocket(this, thePrefs::GetProxyData()); | |||
| 1494 | } else { | |||
| 1495 | ConnectionEstablished(); | |||
| 1496 | return true; | |||
| 1497 | } | |||
| 1498 | ||||
| 1499 | ||||
| 1500 | if (HasLowID() && SupportsDirectUDPCallback() && thePrefs::GetEffectiveUDPPort() != 0 && GetConnectIP() != 0) { // LOWID with DirectCallback | |||
| 1501 | if (m_dwDirectCallbackTimeout != 0) { | |||
| 1502 | AddDebugLogLineN(logClient, wxT("ERROR: Trying Direct UDP Callback while already trying to connect to client on ip ") + Uint32toStringIP(GetConnectIP()))do {} while (false); | |||
| 1503 | return true; // We're already trying a direct connection to this client | |||
| 1504 | } | |||
| 1505 | // a direct callback is possible - since no other parties are involved and only one additional packet overhead | |||
| 1506 | // is used we basically handle it like a normal connection try, no restrictions apply | |||
| 1507 | // we already check above with !theApp->CanDoCallback(this) if any callback is possible at all | |||
| 1508 | m_dwDirectCallbackTimeout = ::GetTickCount() + SEC2MS(45)((45)*1000); | |||
| 1509 | theApp->clientlist->AddDirectCallbackClient(this); | |||
| 1510 | AddDebugLogLineN(logClient, CFormat(wxT("Direct Callback on port %u to client on ip %s")) % GetKadPort() % Uint32toStringIP(GetConnectIP()))do {} while (false); | |||
| 1511 | ||||
| 1512 | CMemFile data; | |||
| 1513 | data.WriteUInt16(thePrefs::GetPort()); // needs to know our port | |||
| 1514 | data.WriteHash(thePrefs::GetUserHash()); // and userhash | |||
| 1515 | // our connection settings | |||
| 1516 | data.WriteUInt8(Kademlia::CPrefs::GetMyConnectOptions(true, false)); | |||
| 1517 | AddDebugLogLineN(logClientUDP, wxT("Sending OP_DIRECTCALLBACKREQ to ") + Uint32_16toStringIP_Port(GetConnectIP(), GetKadPort()))do {} while (false); | |||
| 1518 | CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_DIRECTCALLBACKREQ); | |||
| 1519 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 1520 | theApp->clientudp->SendPacket(packet, GetConnectIP(), GetKadPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0); | |||
| 1521 | } else if (HasLowID()) { // LOWID | |||
| 1522 | if (GetDownloadState() == DS_CONNECTING) { | |||
| 1523 | SetDownloadState(DS_WAITCALLBACK); | |||
| 1524 | } | |||
| 1525 | if (GetUploadState() == US_CONNECTING) { | |||
| 1526 | if(Disconnected(wxT("LowID and US_CONNECTING")L"LowID and US_CONNECTING")) { | |||
| 1527 | Safe_Delete(); | |||
| 1528 | return false; | |||
| 1529 | } | |||
| 1530 | return true; | |||
| 1531 | } | |||
| 1532 | ||||
| 1533 | if (theApp->serverconnect->IsLocalServer(m_dwServerIP,m_nServerPort)) { | |||
| 1534 | CMemFile data; | |||
| 1535 | // AFAICS, this id must be reversed to be sent to clients | |||
| 1536 | // But if I reverse it, we do a serve violation ;) | |||
| 1537 | data.WriteUInt32(m_nUserIDHybrid); | |||
| 1538 | CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_CALLBACKREQUEST); | |||
| 1539 | theStats::AddUpOverheadServer(packet->GetPacketSize()); | |||
| 1540 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_CALLBACKREQUEST to ") + GetFullIP())do {} while (false); | |||
| 1541 | theApp->serverconnect->SendPacket(packet); | |||
| 1542 | SetDownloadState(DS_WAITCALLBACK); | |||
| 1543 | } else { | |||
| 1544 | if (GetUploadState() == US_NONE && (!GetRemoteQueueRank() || m_bReaskPending)) { | |||
| 1545 | ||||
| 1546 | if( !HasValidBuddyID() ) { | |||
| 1547 | theApp->downloadqueue->RemoveSource(this); | |||
| 1548 | if (Disconnected(wxT("LowID and US_NONE and QR=0")L"LowID and US_NONE and QR=0")) { | |||
| 1549 | Safe_Delete(); | |||
| 1550 | return false; | |||
| 1551 | } | |||
| 1552 | return true; | |||
| 1553 | } | |||
| 1554 | ||||
| 1555 | if( !Kademlia::CKademlia::IsConnected() ) { | |||
| 1556 | //We are not connected to Kad and this is a Kad Firewalled source.. | |||
| 1557 | theApp->downloadqueue->RemoveSource(this); | |||
| 1558 | if(Disconnected(wxT("Kad Firewalled source but not connected to Kad.")L"Kad Firewalled source but not connected to Kad.")) { | |||
| 1559 | Safe_Delete(); | |||
| 1560 | return false; | |||
| 1561 | } | |||
| 1562 | return true; | |||
| 1563 | } | |||
| 1564 | ||||
| 1565 | if( GetDownloadState() == DS_WAITCALLBACK ) { | |||
| 1566 | if( GetBuddyIP() && GetBuddyPort()) { | |||
| 1567 | CMemFile bio(34); | |||
| 1568 | bio.WriteUInt128(Kademlia::CUInt128(GetBuddyID())); | |||
| 1569 | bio.WriteUInt128(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash())); | |||
| 1570 | bio.WriteUInt16(thePrefs::GetPort()); | |||
| 1571 | CPacket* packet = new CPacket(bio, OP_KADEMLIAHEADER, KADEMLIA_CALLBACK_REQ); | |||
| 1572 | // eMule FIXME: We don't know which kadversion the buddy has, so we need to send unencrypted | |||
| 1573 | theApp->clientudp->SendPacket(packet, GetBuddyIP(), GetBuddyPort(), false, NULL__null, true, 0); | |||
| 1574 | AddDebugLogLineN(logClientKadUDP, CFormat(wxT("KadCallbackReq (size=%i) to %s")) % packet->GetPacketSize() % Uint32_16toStringIP_Port(GetBuddyIP(), GetBuddyPort()))do {} while (false); | |||
| 1575 | theStats::AddUpOverheadKad(packet->GetRealPacketSize()); | |||
| 1576 | SetDownloadState(DS_WAITCALLBACKKAD); | |||
| 1577 | } else { | |||
| 1578 | AddLogLineN(_("Searching buddy for lowid connection"))theLogger.AddLogLine(L"BaseClient.cpp", 1578, false, logStandard , wxGetTranslation(("Searching buddy for lowid connection"))); | |||
| 1579 | //Create search to find buddy. | |||
| 1580 | Kademlia::CSearch *findSource = new Kademlia::CSearch; | |||
| 1581 | findSource->SetSearchTypes(Kademlia::CSearch::FINDSOURCE); | |||
| 1582 | findSource->SetTargetID(Kademlia::CUInt128(GetBuddyID())); | |||
| 1583 | findSource->AddFileID(Kademlia::CUInt128(m_reqfile->GetFileHash().GetHash())); | |||
| 1584 | if(Kademlia::CSearchManager::StartSearch(findSource)) { | |||
| 1585 | //Started lookup.. | |||
| 1586 | SetDownloadState(DS_WAITCALLBACKKAD); | |||
| 1587 | } else { | |||
| 1588 | //This should never happen.. | |||
| 1589 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp" , 1589, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 1590 | } | |||
| 1591 | } | |||
| 1592 | } | |||
| 1593 | } else { | |||
| 1594 | if (GetDownloadState() == DS_WAITCALLBACK) { | |||
| 1595 | m_bReaskPending = true; | |||
| 1596 | SetDownloadState(DS_ONQUEUE); | |||
| 1597 | } | |||
| 1598 | } | |||
| 1599 | } | |||
| 1600 | } else { // HIGHID | |||
| 1601 | if (!Connect()) { | |||
| 1602 | return false; | |||
| 1603 | } | |||
| 1604 | } | |||
| 1605 | return true; | |||
| 1606 | } | |||
| 1607 | ||||
| 1608 | bool CUpDownClient::Connect() | |||
| 1609 | { | |||
| 1610 | m_hasbeenobfuscatinglately = false; | |||
| 1611 | ||||
| 1612 | if (!m_socket->IsOk()) { | |||
| 1613 | // Enable or disable crypting based on our and the remote clients preference | |||
| 1614 | if (HasValidHash() && SupportsCryptLayer() && thePrefs::IsClientCryptLayerSupported() && (RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested())){ | |||
| 1615 | m_socket->SetConnectionEncryption(true, GetUserHash().GetHash(), false); | |||
| 1616 | } else { | |||
| 1617 | m_socket->SetConnectionEncryption(false, NULL__null, false); | |||
| 1618 | } | |||
| 1619 | amuleIPV4Address tmp; | |||
| 1620 | tmp.Hostname(GetConnectIP()); | |||
| 1621 | tmp.Service(GetUserPort()); | |||
| 1622 | AddDebugLogLineN(logClient, wxT("Trying to connect to ") + Uint32_16toStringIP_Port(GetConnectIP(),GetUserPort()))do {} while (false); | |||
| 1623 | m_socket->Connect(tmp, false); | |||
| 1624 | // We should send hello packets AFTER connecting! | |||
| 1625 | // so I moved it to OnConnect | |||
| 1626 | return true; | |||
| 1627 | } else { | |||
| 1628 | return false; | |||
| 1629 | } | |||
| 1630 | } | |||
| 1631 | ||||
| 1632 | void CUpDownClient::ConnectionEstablished() | |||
| 1633 | { | |||
| 1634 | /* Kry - First thing, check if this client was just used to retrieve | |||
| 1635 | info. That's some debug thing for myself... check connection_reason | |||
| 1636 | definition */ | |||
| 1637 | ||||
| 1638 | m_hasbeenobfuscatinglately = (m_socket && m_socket->IsConnected() && m_socket->IsObfusicating()); | |||
| 1639 | ||||
| 1640 | #ifdef __DEBUG__ | |||
| 1641 | if (!connection_reason.IsEmpty()) { | |||
| 1642 | AddLogLineN(CFormat(wxT("Got client info checking for %s: %s\nDisconnecting and deleting.")) % connection_reason % GetClientFullInfo())theLogger.AddLogLine(L"BaseClient.cpp", 1642, false, logStandard , CFormat(L"Got client info checking for %s: %s\nDisconnecting and deleting." ) % connection_reason % GetClientFullInfo()); | |||
| 1643 | connection_reason.Clear(); // So we don't re-print on destructor. | |||
| 1644 | Safe_Delete(); | |||
| 1645 | return; | |||
| 1646 | } | |||
| 1647 | #endif | |||
| 1648 | ||||
| 1649 | // Check if we should use this client to retrieve our public IP | |||
| 1650 | // Ignore local ip on GetPublicIP (could be wrong) | |||
| 1651 | if (theApp->GetPublicIP(true) == 0 && theApp->IsConnectedED2K()) { | |||
| 1652 | SendPublicIPRequest(); | |||
| 1653 | } | |||
| 1654 | ||||
| 1655 | // was this a direct callback? | |||
| 1656 | if (m_dwDirectCallbackTimeout != 0){ | |||
| 1657 | theApp->clientlist->RemoveDirectCallback(this); | |||
| 1658 | m_dwDirectCallbackTimeout = 0; | |||
| 1659 | AddDebugLogLineN(logClient, wxT("Direct Callback succeeded, connection established to ") + Uint32toStringIP(GetConnectIP()))do {} while (false); | |||
| 1660 | } | |||
| 1661 | ||||
| 1662 | switch (GetKadState()) { | |||
| 1663 | case KS_CONNECTING_FWCHECK: | |||
| 1664 | SetKadState(KS_CONNECTED_FWCHECK); | |||
| 1665 | break; | |||
| 1666 | case KS_CONNECTING_BUDDY: | |||
| 1667 | case KS_INCOMING_BUDDY: | |||
| 1668 | SetKadState(KS_CONNECTED_BUDDY); | |||
| 1669 | break; | |||
| 1670 | case KS_CONNECTING_FWCHECK_UDP: | |||
| 1671 | SetKadState(KS_FWCHECK_UDP); | |||
| 1672 | SendFirewallCheckUDPRequest(); | |||
| 1673 | break; | |||
| 1674 | default: | |||
| 1675 | break; | |||
| 1676 | } | |||
| 1677 | ||||
| 1678 | // ok we have a connection, lets see if we want anything from this client | |||
| 1679 | if (GetChatState() == MS_CONNECTING) { | |||
| 1680 | SetChatState( MS_CHATTING ); | |||
| 1681 | } | |||
| 1682 | ||||
| 1683 | if (GetChatState() == MS_CHATTING) { | |||
| 1684 | bool result = true; | |||
| 1685 | if (!m_pendingMessage.IsEmpty()) { | |||
| 1686 | result = SendChatMessage(m_pendingMessage); | |||
| 1687 | } | |||
| 1688 | Notify_ChatConnResult(result,GUI_ID(GetIP(),GetUserPort()),m_pendingMessage)MuleNotify::DoNotify(&MuleNotify::ChatConnResult, result, (uint64)((((uint64)GetIP())<<16) + (uint64)GetUserPort ()), m_pendingMessage); | |||
| 1689 | m_pendingMessage.Clear(); | |||
| 1690 | } | |||
| 1691 | ||||
| 1692 | switch(GetDownloadState()) { | |||
| 1693 | case DS_CONNECTING: | |||
| 1694 | case DS_WAITCALLBACK: | |||
| 1695 | case DS_WAITCALLBACKKAD: | |||
| 1696 | m_bReaskPending = false; | |||
| 1697 | SetDownloadState(DS_CONNECTED); | |||
| 1698 | SendFileRequest(); | |||
| 1699 | } | |||
| 1700 | if (m_bReaskPending){ | |||
| 1701 | m_bReaskPending = false; | |||
| 1702 | if (GetDownloadState() != DS_NONE && GetDownloadState() != DS_DOWNLOADING) { | |||
| 1703 | SetDownloadState(DS_CONNECTED); | |||
| 1704 | SendFileRequest(); | |||
| 1705 | } | |||
| 1706 | } | |||
| 1707 | switch(GetUploadState()){ | |||
| 1708 | case US_CONNECTING: | |||
| 1709 | case US_WAITCALLBACK: | |||
| 1710 | if (theApp->uploadqueue->IsDownloading(this)) { | |||
| 1711 | SetUploadState(US_UPLOADING); | |||
| 1712 | CPacket* packet = new CPacket(OP_ACCEPTUPLOADREQ, 0, OP_EDONKEYPROT); | |||
| 1713 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 1714 | SendPacket(packet,true); | |||
| 1715 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ACCEPTUPLOADREQ to ") + GetFullIP() )do {} while (false); | |||
| 1716 | } | |||
| 1717 | } | |||
| 1718 | if (m_iFileListRequested == 1) { | |||
| 1719 | CPacket* packet = new CPacket(m_fSharedDirectories ? OP_ASKSHAREDDIRS : OP_ASKSHAREDFILES, 0, OP_EDONKEYPROT); | |||
| 1720 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 1721 | SendPacket(packet,true,true); | |||
| 1722 | #ifdef __DEBUG__ | |||
| 1723 | if (m_fSharedDirectories) { | |||
| 1724 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRS to ") + GetFullIP() )do {} while (false); | |||
| 1725 | } else { | |||
| 1726 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILES to ") + GetFullIP() )do {} while (false); | |||
| 1727 | } | |||
| 1728 | #endif | |||
| 1729 | } | |||
| 1730 | ||||
| 1731 | while (!m_WaitingPackets_list.empty()) { | |||
| 1732 | CPacket* packet = m_WaitingPackets_list.front(); | |||
| 1733 | m_WaitingPackets_list.pop_front(); | |||
| 1734 | ||||
| 1735 | SendPacket(packet); | |||
| 1736 | } | |||
| 1737 | } | |||
| 1738 | ||||
| 1739 | ||||
| 1740 | int CUpDownClient::GetHashType() const | |||
| 1741 | { | |||
| 1742 | if ( m_UserHash[5] == 13 && m_UserHash[14] == 110 ) { | |||
| 1743 | return SO_OLDEMULE; | |||
| 1744 | } | |||
| 1745 | ||||
| 1746 | if ( m_UserHash[5] == 14 && m_UserHash[14] == 111 ) { | |||
| 1747 | return SO_EMULE; | |||
| 1748 | } | |||
| 1749 | ||||
| 1750 | if ( m_UserHash[5] == 'M' && m_UserHash[14] == 'L' ) { | |||
| 1751 | return SO_MLDONKEY; | |||
| 1752 | } | |||
| 1753 | ||||
| 1754 | return SO_UNKNOWN; | |||
| 1755 | } | |||
| 1756 | ||||
| 1757 | ||||
| 1758 | void CUpDownClient::SetSocket(CClientTCPSocket* socket) | |||
| 1759 | { | |||
| 1760 | #ifdef __DEBUG__ | |||
| 1761 | if (m_socket == NULL__null && socket != NULL__null) { | |||
| 1762 | theStats::SocketAssignedToClient(); | |||
| 1763 | } else if (m_socket != NULL__null && socket == NULL__null) { | |||
| 1764 | theStats::SocketUnassignedFromClient(); | |||
| 1765 | } | |||
| 1766 | #endif | |||
| 1767 | m_socket = socket; | |||
| 1768 | } | |||
| 1769 | ||||
| 1770 | ||||
| 1771 | void CUpDownClient::ReGetClientSoft() | |||
| 1772 | { | |||
| 1773 | if (m_Username.IsEmpty()) { | |||
| 1774 | m_clientSoft=SO_UNKNOWN; | |||
| 1775 | m_clientVerString = m_clientSoftString = m_clientVersionString = m_fullClientVerString = _("Unknown")wxGetTranslation(("Unknown")); | |||
| 1776 | UpdateStats(); | |||
| 1777 | return; | |||
| 1778 | } | |||
| 1779 | ||||
| 1780 | int iHashType = GetHashType(); | |||
| 1781 | wxString clientModString; | |||
| 1782 | if (iHashType == SO_EMULE) { | |||
| 1783 | ||||
| 1784 | m_clientSoft = m_byCompatibleClient; | |||
| 1785 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1786 | // Special issues: | |||
| 1787 | if(!GetClientModString().IsEmpty() && (m_clientSoft != SO_EMULE)) { | |||
| 1788 | m_clientSoftString = GetClientModString(); | |||
| 1789 | } | |||
| 1790 | // Isn't xMule annoying? | |||
| 1791 | if ((m_clientSoft == SO_LXMULE) && (GetMuleVersion() > 0x26) && (GetMuleVersion() != 0x99)) { | |||
| 1792 | m_clientSoftString += CFormat(_(" (Fake eMule version %#x)")wxGetTranslation((" (Fake eMule version %#x)"))) % GetMuleVersion(); | |||
| 1793 | } | |||
| 1794 | if ((m_clientSoft == SO_EMULE) && | |||
| 1795 | ( | |||
| 1796 | wxString(GetClientModString()).MakeLower().Find(wxT("xmule")L"xmule") != -1 | |||
| 1797 | || GetUserName().Find(wxT("xmule.")L"xmule.") != -1 | |||
| 1798 | ) | |||
| 1799 | ) { | |||
| 1800 | // FAKE eMule -a newer xMule faking is ident. | |||
| 1801 | m_clientSoft = SO_LXMULE; | |||
| 1802 | if (GetClientModString().IsEmpty() == false) { | |||
| 1803 | m_clientSoftString = GetClientModString() + _(" (Fake eMule)")wxGetTranslation((" (Fake eMule)")); | |||
| 1804 | } else { | |||
| 1805 | m_clientSoftString = _("xMule (Fake eMule)")wxGetTranslation(("xMule (Fake eMule)")); // don't use GetSoftName, it's not lmule. | |||
| 1806 | } | |||
| 1807 | } | |||
| 1808 | // Now, what if we don't know this SO_ID? | |||
| 1809 | if (m_clientSoftString.IsEmpty()) { | |||
| 1810 | if(m_bIsML) { | |||
| 1811 | m_clientSoft = SO_MLDONKEY; | |||
| 1812 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1813 | } else if (m_bIsHybrid) { | |||
| 1814 | m_clientSoft = SO_EDONKEYHYBRID; | |||
| 1815 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1816 | } else if (m_byCompatibleClient != 0) { | |||
| 1817 | m_clientSoft = SO_COMPAT_UNK; | |||
| 1818 | #ifdef __DEBUG__ | |||
| 1819 | if ( | |||
| 1820 | // Exceptions: | |||
| 1821 | (m_byCompatibleClient != 0xf0) // Chinese leech mod | |||
| 1822 | && (1==1) // Your ad here | |||
| 1823 | ) { | |||
| 1824 | AddLogLineNS(CFormat(wxT("Compatible client found with ET_COMPATIBLECLIENT of %x")) % m_byCompatibleClient)theLogger.AddLogLine(L"BaseClient.cpp", 1824, false, logStandard , CFormat(L"Compatible client found with ET_COMPATIBLECLIENT of %x" ) % m_byCompatibleClient, true); | |||
| 1825 | } | |||
| 1826 | #endif | |||
| 1827 | m_clientSoftString = CFormat(wxT("%s(%#x)")L"%s(%#x)") % GetSoftName(m_clientSoft) % m_byCompatibleClient; | |||
| 1828 | } else { | |||
| 1829 | // If we step here, it might mean 2 things: | |||
| 1830 | // a eMule | |||
| 1831 | // a Compat Client that has sent no MuleInfo packet yet. | |||
| 1832 | m_clientSoft = SO_EMULE; | |||
| 1833 | m_clientSoftString = wxT("eMule")L"eMule"; | |||
| 1834 | } | |||
| 1835 | } | |||
| 1836 | ||||
| 1837 | if (m_byEmuleVersion == 0) { | |||
| 1838 | m_nClientVersion = MAKE_CLIENT_VERSION(0,0,0)((uint32)(0)*100U*10U*100U + (uint32)(0)*100U*10U + (uint32)( 0)*100U); | |||
| 1839 | } else if (m_byEmuleVersion != 0x99) { | |||
| 1840 | uint32 nClientMinVersion = (m_byEmuleVersion >> 4)*10 + (m_byEmuleVersion & 0x0f); | |||
| 1841 | m_nClientVersion = MAKE_CLIENT_VERSION(0,nClientMinVersion,0)((uint32)(0)*100U*10U*100U + (uint32)(nClientMinVersion)*100U *10U + (uint32)(0)*100U); | |||
| 1842 | switch (m_clientSoft) { | |||
| 1843 | case SO_AMULE: | |||
| 1844 | m_clientVerString = CFormat(_("1.x (based on eMule v0.%u)")wxGetTranslation(("1.x (based on eMule v0.%u)"))) % nClientMinVersion; | |||
| 1845 | break; | |||
| 1846 | case SO_LPHANT: | |||
| 1847 | m_clientVerString = wxT("< v0.05")L"< v0.05"; | |||
| 1848 | break; | |||
| 1849 | default: | |||
| 1850 | clientModString = GetClientModString(); | |||
| 1851 | m_clientVerString = CFormat(wxT("v0.%u")L"v0.%u") % nClientMinVersion; | |||
| 1852 | break; | |||
| 1853 | } | |||
| 1854 | } else { | |||
| 1855 | uint32 nClientMajVersion = (m_nClientVersion >> 17) & 0x7f; | |||
| 1856 | uint32 nClientMinVersion = (m_nClientVersion >> 10) & 0x7f; | |||
| 1857 | uint32 nClientUpVersion = (m_nClientVersion >> 7) & 0x07; | |||
| 1858 | ||||
| 1859 | m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion)((uint32)(nClientMajVersion)*100U*10U*100U + (uint32)(nClientMinVersion )*100U*10U + (uint32)(nClientUpVersion)*100U); | |||
| 1860 | ||||
| 1861 | switch (m_clientSoft) { | |||
| 1862 | case SO_AMULE: | |||
| 1863 | case SO_LXMULE: | |||
| 1864 | case SO_HYDRANODE: | |||
| 1865 | case SO_MLDONKEY: | |||
| 1866 | case SO_NEW_MLDONKEY: | |||
| 1867 | case SO_NEW2_MLDONKEY: | |||
| 1868 | // Kry - xMule started sending correct version tags on 1.9.1b. | |||
| 1869 | // It only took them 4 months, and being told by me and the | |||
| 1870 | // eMule+ developers, so I think they're slowly getting smarter. | |||
| 1871 | // They are based on our implementation, so we use the same format | |||
| 1872 | // for the version string. | |||
| 1873 | m_clientVerString = CFormat(wxT("v%u.%u.%u")L"v%u.%u.%u") % nClientMajVersion % nClientMinVersion % nClientUpVersion; | |||
| 1874 | break; | |||
| 1875 | case SO_LPHANT: | |||
| 1876 | m_clientVerString = CFormat(wxT(" v%u.%.2u%c")L" v%u.%.2u%c") % (nClientMajVersion-1) % nClientMinVersion % ('a' + nClientUpVersion); | |||
| 1877 | break; | |||
| 1878 | case SO_EMULEPLUS: | |||
| 1879 | m_clientVerString = CFormat(wxT("v%u")L"v%u") % nClientMajVersion; | |||
| 1880 | if(nClientMinVersion != 0) { | |||
| 1881 | m_clientVerString += CFormat(wxT(".%u")L".%u") % nClientMinVersion; | |||
| 1882 | } | |||
| 1883 | if(nClientUpVersion != 0) { | |||
| 1884 | m_clientVerString += CFormat(wxT("%c")L"%c") % ('a' + nClientUpVersion - 1); | |||
| 1885 | } | |||
| 1886 | break; | |||
| 1887 | default: | |||
| 1888 | clientModString = GetClientModString(); | |||
| 1889 | m_clientVerString = CFormat(wxT("v%u.%u%c")L"v%u.%u%c") % nClientMajVersion % nClientMinVersion % ('a' + nClientUpVersion); | |||
| 1890 | break; | |||
| 1891 | } | |||
| 1892 | } | |||
| 1893 | } else if (m_bIsHybrid) { | |||
| 1894 | // seen: | |||
| 1895 | // 105010 50.10 | |||
| 1896 | // 10501 50.1 | |||
| 1897 | // 1051 51.0 | |||
| 1898 | // 501 50.1 | |||
| 1899 | ||||
| 1900 | m_clientSoft = SO_EDONKEYHYBRID; | |||
| 1901 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1902 | ||||
| 1903 | uint32 nClientMajVersion; | |||
| 1904 | uint32 nClientMinVersion; | |||
| 1905 | uint32 nClientUpVersion; | |||
| 1906 | if (m_nClientVersion > 100000) { | |||
| 1907 | uint32 uMaj = m_nClientVersion/100000; | |||
| 1908 | nClientMajVersion = uMaj - 1; | |||
| 1909 | nClientMinVersion = (m_nClientVersion - uMaj*100000) / 100; | |||
| 1910 | nClientUpVersion = m_nClientVersion % 100; | |||
| 1911 | } | |||
| 1912 | else if (m_nClientVersion > 10000) { | |||
| 1913 | uint32 uMaj = m_nClientVersion/10000; | |||
| 1914 | nClientMajVersion = uMaj - 1; | |||
| 1915 | nClientMinVersion = (m_nClientVersion - uMaj*10000) / 10; | |||
| 1916 | nClientUpVersion = m_nClientVersion % 10; | |||
| 1917 | } | |||
| 1918 | else if (m_nClientVersion > 1000) { | |||
| 1919 | uint32 uMaj = m_nClientVersion/1000; | |||
| 1920 | nClientMajVersion = uMaj - 1; | |||
| 1921 | nClientMinVersion = m_nClientVersion - uMaj*1000; | |||
| 1922 | nClientUpVersion = 0; | |||
| 1923 | } | |||
| 1924 | else if (m_nClientVersion > 100) { | |||
| 1925 | uint32 uMin = m_nClientVersion/10; | |||
| 1926 | nClientMajVersion = 0; | |||
| 1927 | nClientMinVersion = uMin; | |||
| 1928 | nClientUpVersion = m_nClientVersion - uMin*10; | |||
| 1929 | } | |||
| 1930 | else{ | |||
| 1931 | nClientMajVersion = 0; | |||
| 1932 | nClientMinVersion = m_nClientVersion; | |||
| 1933 | nClientUpVersion = 0; | |||
| 1934 | } | |||
| 1935 | m_nClientVersion = MAKE_CLIENT_VERSION(nClientMajVersion, nClientMinVersion, nClientUpVersion)((uint32)(nClientMajVersion)*100U*10U*100U + (uint32)(nClientMinVersion )*100U*10U + (uint32)(nClientUpVersion)*100U); | |||
| 1936 | if (nClientUpVersion) { | |||
| 1937 | m_clientVerString = CFormat(wxT("v%u.%u.%u")L"v%u.%u.%u") % nClientMajVersion % nClientMinVersion % nClientUpVersion; | |||
| 1938 | } else { | |||
| 1939 | m_clientVerString = CFormat(wxT("v%u.%u")L"v%u.%u") % nClientMajVersion % nClientMinVersion; | |||
| 1940 | } | |||
| 1941 | } else if (m_bIsML || (iHashType == SO_MLDONKEY)) { | |||
| 1942 | m_clientSoft = SO_MLDONKEY; | |||
| 1943 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1944 | uint32 nClientMinVersion = m_nClientVersion; | |||
| 1945 | m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0)((uint32)(0)*100U*10U*100U + (uint32)(nClientMinVersion)*100U *10U + (uint32)(0)*100U); | |||
| 1946 | m_clientVerString = CFormat(wxT("v0.%u")L"v0.%u") % nClientMinVersion; | |||
| 1947 | } else if (iHashType == SO_OLDEMULE) { | |||
| 1948 | m_clientSoft = SO_OLDEMULE; | |||
| 1949 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1950 | uint32 nClientMinVersion = m_nClientVersion; | |||
| 1951 | m_nClientVersion = MAKE_CLIENT_VERSION(0, nClientMinVersion, 0)((uint32)(0)*100U*10U*100U + (uint32)(nClientMinVersion)*100U *10U + (uint32)(0)*100U); | |||
| 1952 | m_clientVerString = CFormat(wxT("v0.%u")L"v0.%u") % nClientMinVersion; | |||
| 1953 | } else { | |||
| 1954 | m_clientSoft = SO_EDONKEY; | |||
| 1955 | m_clientSoftString = GetSoftName(m_clientSoft); | |||
| 1956 | m_nClientVersion *= 10; | |||
| 1957 | m_clientVerString = CFormat(wxT("v%u.%u")L"v%u.%u") % (m_nClientVersion / 100000) % ((m_nClientVersion / 1000) % 100); | |||
| 1958 | } | |||
| 1959 | ||||
| 1960 | m_clientVersionString = m_clientVerString; | |||
| 1961 | if (!clientModString.IsEmpty()) { | |||
| 1962 | m_clientVerString += wxT(" - ")L" - " + clientModString; | |||
| 1963 | } | |||
| 1964 | m_fullClientVerString = m_clientSoftString + wxT(" ")L" " + m_clientVerString; | |||
| 1965 | ||||
| 1966 | UpdateStats(); | |||
| 1967 | } | |||
| 1968 | ||||
| 1969 | void CUpDownClient::RequestSharedFileList() | |||
| 1970 | { | |||
| 1971 | if (m_iFileListRequested == 0) { | |||
| 1972 | AddDebugLogLineN( logClient, wxString( wxT("Requesting shared files from ") ) + GetUserName() )do {} while (false); | |||
| 1973 | m_iFileListRequested = 1; | |||
| 1974 | TryToConnect(true); | |||
| 1975 | } else { | |||
| 1976 | AddDebugLogLineN( logClient, CFormat( wxT("Requesting shared files from user %s (%u) is already in progress") ) % GetUserName() % GetUserIDHybrid() )do {} while (false); | |||
| 1977 | } | |||
| 1978 | } | |||
| 1979 | ||||
| 1980 | ||||
| 1981 | void CUpDownClient::ProcessSharedFileList(const uint8_t* pachPacket, uint32 nSize, wxString& pszDirectory) | |||
| 1982 | { | |||
| 1983 | if (m_iFileListRequested > 0) { | |||
| 1984 | m_iFileListRequested--; | |||
| 1985 | theApp->searchlist->ProcessSharedFileList(pachPacket, nSize, this, NULL__null, pszDirectory); | |||
| 1986 | } | |||
| 1987 | } | |||
| 1988 | ||||
| 1989 | ||||
| 1990 | void CUpDownClient::ResetFileStatusInfo() | |||
| 1991 | { | |||
| 1992 | m_nPartCount = 0; | |||
| 1993 | ||||
| 1994 | if ( m_reqfile ) { | |||
| 1995 | m_reqfile->UpdatePartsFrequency( this, false ); | |||
| 1996 | } | |||
| 1997 | m_downPartStatus.clear(); | |||
| 1998 | ||||
| 1999 | m_clientFilename.Clear(); | |||
| 2000 | ||||
| 2001 | m_bCompleteSource = false; | |||
| 2002 | m_dwLastAskedTime = 0; | |||
| 2003 | m_iRating = 0; | |||
| 2004 | m_strComment.Clear(); | |||
| 2005 | ||||
| 2006 | if (m_pReqFileAICHHash != NULL__null) { | |||
| 2007 | delete m_pReqFileAICHHash; | |||
| 2008 | m_pReqFileAICHHash = NULL__null; | |||
| 2009 | } | |||
| 2010 | ||||
| 2011 | } | |||
| 2012 | ||||
| 2013 | wxString CUpDownClient::GetUploadFileInfo() | |||
| 2014 | { | |||
| 2015 | // build info text and display it | |||
| 2016 | wxString sRet; | |||
| 2017 | sRet = (CFormat(_("NickName: %s ID: %u")wxGetTranslation(("NickName: %s ID: %u"))) % GetUserName() % GetUserIDHybrid()) + wxT(" ")L" "; | |||
| 2018 | if (m_reqfile) { | |||
| 2019 | sRet += CFormat(_("Requested: %s\n")wxGetTranslation(("Requested: %s\n"))) % m_reqfile->GetFileName(); | |||
| 2020 | sRet += CFormat( | |||
| 2021 | wxPLURAL("Filestats for this session: Accepted %d of %d request, %s transferred\n", "Filestats for this session: Accepted %d of %d requests, %s transferred\n", m_reqfile->statistic.GetRequests())wxGetTranslation(("Filestats for this session: Accepted %d of %d request, %s transferred\n" ), ("Filestats for this session: Accepted %d of %d requests, %s transferred\n" ), m_reqfile->statistic.GetRequests()) | |||
| 2022 | ) % m_reqfile->statistic.GetAccepts() % m_reqfile->statistic.GetRequests() % CastItoXBytes(m_reqfile->statistic.GetTransferred()); | |||
| 2023 | sRet += CFormat( | |||
| 2024 | wxPLURAL("Filestats for all sessions: Accepted %d of %d request, %s transferred\n", "Filestats for all sessions: Accepted %d of %d requests, %s transferred\n", m_reqfile->statistic.GetAllTimeRequests())wxGetTranslation(("Filestats for all sessions: Accepted %d of %d request, %s transferred\n" ), ("Filestats for all sessions: Accepted %d of %d requests, %s transferred\n" ), m_reqfile->statistic.GetAllTimeRequests()) | |||
| 2025 | ) % m_reqfile->statistic.GetAllTimeAccepts() % m_reqfile->statistic.GetAllTimeRequests() % CastItoXBytes(m_reqfile->statistic.GetAllTimeTransferred()); | |||
| 2026 | } else { | |||
| 2027 | sRet += _("Requested unknown file")wxGetTranslation(("Requested unknown file")); | |||
| 2028 | } | |||
| 2029 | return sRet; | |||
| 2030 | } | |||
| 2031 | ||||
| 2032 | // sends a packet, if needed it will establish a connection before | |||
| 2033 | // options used: ignore max connections, control packet, delete packet | |||
| 2034 | // !if the functions returns false it is _possible_ that this clientobject was deleted, because the connectiontry fails | |||
| 2035 | bool CUpDownClient::SafeSendPacket(CPacket* packet) | |||
| 2036 | { | |||
| 2037 | if (IsConnected()) { | |||
| 2038 | SendPacket(packet, true); | |||
| 2039 | return true; | |||
| 2040 | } else { | |||
| 2041 | m_WaitingPackets_list.push_back(packet); | |||
| 2042 | return TryToConnect(true); | |||
| 2043 | } | |||
| 2044 | } | |||
| 2045 | ||||
| 2046 | void CUpDownClient::SendPublicKeyPacket() | |||
| 2047 | { | |||
| 2048 | // send our public key to the client who requested it | |||
| 2049 | wxCHECK2(m_socket != NULL, return)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2049, __FUNCTION__, "\"m_socket != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2049; | |||
| 2050 | wxCHECK2(credits != NULL, return)if ( credits != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2050, __FUNCTION__, "\"credits != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2050; | |||
| 2051 | wxCHECK2(m_SecureIdentState == IS_KEYANDSIGNEEDED, return)if ( m_SecureIdentState == IS_KEYANDSIGNEEDED ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp" , 2051, __FUNCTION__, "\"m_SecureIdentState == IS_KEYANDSIGNEEDED\"" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2051; | |||
| 2052 | ||||
| 2053 | if (!theApp->CryptoAvailable()) | |||
| 2054 | return; | |||
| 2055 | ||||
| 2056 | CMemFile data; | |||
| 2057 | data.WriteUInt8(theApp->clientcredits->GetPubKeyLen()); | |||
| 2058 | data.Write(theApp->clientcredits->GetPublicKey(), theApp->clientcredits->GetPubKeyLen()); | |||
| 2059 | CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_PUBLICKEY); | |||
| 2060 | ||||
| 2061 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2062 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICKEY to ") + GetFullIP() )do {} while (false); | |||
| 2063 | SendPacket(packet,true,true); | |||
| 2064 | m_SecureIdentState = IS_SIGNATURENEEDED; | |||
| 2065 | } | |||
| 2066 | ||||
| 2067 | ||||
| 2068 | void CUpDownClient::SendSignaturePacket() | |||
| 2069 | { | |||
| 2070 | // signate the public key of this client and send it | |||
| 2071 | wxCHECK2(m_socket != NULL, return)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2071, __FUNCTION__, "\"m_socket != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2071; | |||
| 2072 | wxCHECK2(credits != NULL, return)if ( credits != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2072, __FUNCTION__, "\"credits != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2072; | |||
| 2073 | wxCHECK2(m_SecureIdentState != 0, return)if ( m_SecureIdentState != 0 ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2073, __FUNCTION__, "\"m_SecureIdentState != 0\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2073; | |||
| 2074 | ||||
| 2075 | if (!theApp->CryptoAvailable()) { | |||
| 2076 | return; | |||
| 2077 | } | |||
| 2078 | if (credits->GetSecIDKeyLen() == 0) { | |||
| 2079 | return; // We don't have his public key yet, will be back here later | |||
| 2080 | } | |||
| 2081 | // do we have a challenge value received (actually we should if we are in this function) | |||
| 2082 | if (credits->m_dwCryptRndChallengeFrom == 0){ | |||
| 2083 | AddDebugLogLineN( logClient, wxString(wxT("Want to send signature but challenge value is invalid - User ")) + GetUserName())do {} while (false); | |||
| 2084 | return; | |||
| 2085 | } | |||
| 2086 | // v2 | |||
| 2087 | // we will use v1 as default, except if only v2 is supported | |||
| 2088 | bool bUseV2; | |||
| 2089 | if ( (m_bySupportSecIdent&1) == 1 ) | |||
| 2090 | bUseV2 = false; | |||
| 2091 | else | |||
| 2092 | bUseV2 = true; | |||
| 2093 | ||||
| 2094 | uint8 byChaIPKind = 0; | |||
| 2095 | uint32 ChallengeIP = 0; | |||
| 2096 | if (bUseV2){ | |||
| 2097 | if (::IsLowID(theApp->GetED2KID())) { | |||
| 2098 | // we cannot do not know for sure our public ip, so use the remote clients one | |||
| 2099 | ChallengeIP = GetIP(); | |||
| 2100 | byChaIPKind = CRYPT_CIP_REMOTECLIENT10; | |||
| 2101 | } else { | |||
| 2102 | ChallengeIP = theApp->GetED2KID(); | |||
| 2103 | byChaIPKind = CRYPT_CIP_LOCALCLIENT20; | |||
| 2104 | } | |||
| 2105 | } | |||
| 2106 | //end v2 | |||
| 2107 | uint8_t achBuffer[250]; | |||
| 2108 | ||||
| 2109 | uint8 siglen = theApp->clientcredits->CreateSignature(credits, achBuffer, 250, ChallengeIP, byChaIPKind ); | |||
| 2110 | wxCHECK2(siglen != 0, return)if ( siglen != 0 ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2110, __FUNCTION__, "\"siglen != 0\"" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2110; | |||
| 2111 | ||||
| 2112 | CMemFile data; | |||
| 2113 | data.WriteUInt8(siglen); | |||
| 2114 | data.Write(achBuffer, siglen); | |||
| 2115 | if (bUseV2) { | |||
| 2116 | data.WriteUInt8(byChaIPKind); | |||
| 2117 | } | |||
| 2118 | ||||
| 2119 | CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SIGNATURE); | |||
| 2120 | ||||
| 2121 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2122 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_SIGNATURE to ") + GetFullIP() )do {} while (false); | |||
| 2123 | SendPacket(packet,true,true); | |||
| 2124 | m_SecureIdentState = IS_ALLREQUESTSSEND; | |||
| 2125 | } | |||
| 2126 | ||||
| 2127 | ||||
| 2128 | void CUpDownClient::ProcessPublicKeyPacket(const uint8_t* pachPacket, uint32 nSize) | |||
| 2129 | { | |||
| 2130 | theApp->clientlist->AddTrackClient(this); | |||
| 2131 | ||||
| 2132 | wxCHECK2(m_socket != NULL, return)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2132, __FUNCTION__, "\"m_socket != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2132; | |||
| 2133 | wxCHECK2(credits != NULL, return)if ( credits != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2133, __FUNCTION__, "\"credits != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2133; | |||
| 2134 | if (pachPacket[0] != nSize - 1) { | |||
| 2135 | AddDebugLogLineN(logClient, CFormat(wxT("Inconsistent packet size (%d != %d)")) % pachPacket[0] % (nSize - 1))do {} while (false); | |||
| 2136 | return; | |||
| 2137 | } | |||
| 2138 | if (nSize == 0) { | |||
| 2139 | AddDebugLogLineN(logClient, wxT("Invalid packet size (0)"))do {} while (false); | |||
| 2140 | return; | |||
| 2141 | } | |||
| 2142 | if (nSize > 250) { | |||
| 2143 | AddDebugLogLineN(logClient, CFormat(wxT("Invalid packet size (%d > 250)")) % nSize)do {} while (false); | |||
| 2144 | return; | |||
| 2145 | } | |||
| 2146 | if (!theApp->CryptoAvailable()) | |||
| 2147 | return; | |||
| 2148 | // the function will handle everything (multiple key etc) | |||
| 2149 | if (credits->SetSecureIdent(pachPacket+1, pachPacket[0])){ | |||
| 2150 | // if this client wants a signature, now we can send him one | |||
| 2151 | if (m_SecureIdentState == IS_SIGNATURENEEDED){ | |||
| 2152 | SendSignaturePacket(); | |||
| 2153 | } | |||
| 2154 | else if (m_SecureIdentState == IS_KEYANDSIGNEEDED) { | |||
| 2155 | // something is wrong | |||
| 2156 | AddDebugLogLineN( logClient, wxT("Invalid State error: IS_KEYANDSIGNEEDED in ProcessPublicKeyPacket") )do {} while (false); | |||
| 2157 | } | |||
| 2158 | } else { | |||
| 2159 | AddDebugLogLineN( logClient, wxT("Failed to use new received public key") )do {} while (false); | |||
| 2160 | } | |||
| 2161 | } | |||
| 2162 | ||||
| 2163 | ||||
| 2164 | void CUpDownClient::ProcessSignaturePacket(const uint8_t* pachPacket, uint32 nSize) | |||
| 2165 | { | |||
| 2166 | // here we spread the good guys from the bad ones ;) | |||
| 2167 | ||||
| 2168 | wxCHECK2(m_socket != NULL, return)if ( m_socket != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2168, __FUNCTION__, "\"m_socket != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2168; | |||
| 2169 | wxCHECK2(credits != NULL, return)if ( credits != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2169, __FUNCTION__, "\"credits != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2169; | |||
| 2170 | if (nSize == 0) { | |||
| 2171 | AddDebugLogLineN(logClient, wxT("Invalid packet size (0)"))do {} while (false); | |||
| 2172 | return; | |||
| 2173 | } | |||
| 2174 | if (nSize > 250) { | |||
| 2175 | AddDebugLogLineN(logClient, CFormat(wxT("Invalid packet size (%d > 250)")) % nSize)do {} while (false); | |||
| 2176 | return; | |||
| 2177 | } | |||
| 2178 | ||||
| 2179 | uint8 byChaIPKind; | |||
| 2180 | if (pachPacket[0] == nSize-1) | |||
| 2181 | byChaIPKind = 0; | |||
| 2182 | else if (pachPacket[0] == nSize-2 && (m_bySupportSecIdent & 2) > 0) //v2 | |||
| 2183 | byChaIPKind = pachPacket[nSize-1]; | |||
| 2184 | else { | |||
| 2185 | // Unknown or invalid format | |||
| 2186 | AddDebugLogLineN(logClient, wxT("Invalid or unknown challenge format - ignoring"))do {} while (false); | |||
| 2187 | return; | |||
| 2188 | } | |||
| 2189 | ||||
| 2190 | if (!theApp->CryptoAvailable()) | |||
| 2191 | return; | |||
| 2192 | ||||
| 2193 | // we accept only one signature per IP, to avoid floods which need a lot cpu time for cryptfunctions | |||
| 2194 | if (m_dwLastSignatureIP == GetIP()){ | |||
| 2195 | AddDebugLogLineN( logClient, wxT("received multiple signatures from one client") )do {} while (false); | |||
| 2196 | return; | |||
| 2197 | } | |||
| 2198 | // also make sure this client has a public key | |||
| 2199 | if (credits->GetSecIDKeyLen() == 0){ | |||
| 2200 | AddDebugLogLineN( logClient, wxT("received signature for client without public key") )do {} while (false); | |||
| 2201 | return; | |||
| 2202 | } | |||
| 2203 | // and one more check: did we ask for a signature and sent a challenge packet? | |||
| 2204 | if (credits->m_dwCryptRndChallengeFor == 0){ | |||
| 2205 | AddDebugLogLineN( logClient, wxT("received signature for client with invalid challenge value - User ") + GetUserName() )do {} while (false); | |||
| 2206 | return; | |||
| 2207 | } | |||
| 2208 | ||||
| 2209 | // cppcheck-suppress duplicateBranch | |||
| 2210 | if (theApp->clientcredits->VerifyIdent(credits, pachPacket+1, pachPacket[0], GetIP(), byChaIPKind ) ) { | |||
| 2211 | // result is saved in function above | |||
| 2212 | AddDebugLogLineN( logClient, CFormat( wxT("'%s' has passed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind )do {} while (false); | |||
| 2213 | } else { | |||
| 2214 | AddDebugLogLineN( logClient, CFormat( wxT("'%s' has failed the secure identification, V2 State: %i") ) % GetUserName() % byChaIPKind )do {} while (false); | |||
| 2215 | } | |||
| 2216 | ||||
| 2217 | m_dwLastSignatureIP = GetIP(); | |||
| 2218 | } | |||
| 2219 | ||||
| 2220 | void CUpDownClient::SendSecIdentStatePacket() | |||
| 2221 | { | |||
| 2222 | wxCHECK2(credits != NULL, return)if ( credits != __null ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2222, __FUNCTION__, "\"credits != __null\"", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2222; | |||
| 2223 | ||||
| 2224 | // check if we need public key and signature | |||
| 2225 | uint8 nValue = 0; | |||
| 2226 | if (theApp->CryptoAvailable()){ | |||
| 2227 | if (credits->GetSecIDKeyLen() == 0) { | |||
| 2228 | nValue = IS_KEYANDSIGNEEDED; | |||
| 2229 | } else if (m_dwLastSignatureIP != GetIP()) { | |||
| 2230 | nValue = IS_SIGNATURENEEDED; | |||
| 2231 | } | |||
| 2232 | } | |||
| 2233 | if (nValue == 0){ | |||
| 2234 | AddDebugLogLineN( logClient, wxT("Not sending SecIdentState Packet, because State is Zero") )do {} while (false); | |||
| 2235 | return; | |||
| 2236 | } | |||
| 2237 | // crypt: send random data to sign | |||
| 2238 | uint32 dwRandom = rand()+1; | |||
| 2239 | credits->m_dwCryptRndChallengeFor = dwRandom; | |||
| 2240 | ||||
| 2241 | CMemFile data; | |||
| 2242 | data.WriteUInt8(nValue); | |||
| 2243 | data.WriteUInt32(dwRandom); | |||
| 2244 | CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_SECIDENTSTATE); | |||
| 2245 | ||||
| 2246 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2247 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_SECIDENTSTATE to ") + GetFullIP() )do {} while (false); | |||
| 2248 | SendPacket(packet,true,true); | |||
| 2249 | } | |||
| 2250 | ||||
| 2251 | ||||
| 2252 | void CUpDownClient::ProcessSecIdentStatePacket(const uint8_t* pachPacket, uint32 nSize) | |||
| 2253 | { | |||
| 2254 | if ( nSize != 5 ) { | |||
| 2255 | return; | |||
| 2256 | } | |||
| 2257 | ||||
| 2258 | wxCHECK2(credits, return)if ( credits ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2258, __FUNCTION__, "\"credits\"" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct2258; | |||
| 2259 | ||||
| 2260 | CMemFile data(pachPacket,nSize); | |||
| 2261 | ||||
| 2262 | switch ( data.ReadUInt8() ) { | |||
| 2263 | case 0: | |||
| 2264 | m_SecureIdentState = IS_UNAVAILABLE; | |||
| 2265 | break; | |||
| 2266 | case 1: | |||
| 2267 | m_SecureIdentState = IS_SIGNATURENEEDED; | |||
| 2268 | break; | |||
| 2269 | case 2: | |||
| 2270 | m_SecureIdentState = IS_KEYANDSIGNEEDED; | |||
| 2271 | break; | |||
| 2272 | default: | |||
| 2273 | return; | |||
| 2274 | } | |||
| 2275 | ||||
| 2276 | credits->m_dwCryptRndChallengeFrom = data.ReadUInt32(); | |||
| 2277 | } | |||
| 2278 | ||||
| 2279 | ||||
| 2280 | void CUpDownClient::InfoPacketsReceived() | |||
| 2281 | { | |||
| 2282 | // indicates that both Information Packets has been received | |||
| 2283 | // needed for actions, which process data from both packets | |||
| 2284 | wxASSERT ( m_byInfopacketsReceived == IP_BOTH )do { if ( m_byInfopacketsReceived == IP_BOTH ) { } else if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2284, __FUNCTION__, "m_byInfopacketsReceived == IP_BOTH", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 2285 | m_byInfopacketsReceived = IP_NONE; | |||
| 2286 | ||||
| 2287 | if (m_bySupportSecIdent){ | |||
| 2288 | SendSecIdentStatePacket(); | |||
| 2289 | } | |||
| 2290 | } | |||
| 2291 | ||||
| 2292 | ||||
| 2293 | bool CUpDownClient::CheckHandshakeFinished() const | |||
| 2294 | { | |||
| 2295 | if (m_bHelloAnswerPending) { | |||
| 2296 | // this triggers way too often.. need more time to look at this -> only create a warning | |||
| 2297 | // The reason for this is that 2 clients are connecting to each other at the same time.. | |||
| 2298 | AddDebugLogLineN( logClient, wxT("Handshake not finished while processing packet.") )do {} while (false); | |||
| 2299 | return false; | |||
| 2300 | } | |||
| 2301 | ||||
| 2302 | return true; | |||
| 2303 | } | |||
| 2304 | ||||
| 2305 | ||||
| 2306 | #ifdef __DEBUG__ | |||
| 2307 | wxString CUpDownClient::GetClientFullInfo() | |||
| 2308 | { | |||
| 2309 | if (m_clientVerString.IsEmpty()) { | |||
| 2310 | ReGetClientSoft(); | |||
| 2311 | } | |||
| 2312 | ||||
| 2313 | return CFormat( wxT("Client %s on IP:Port %s:%d using %s %s %s")L"Client %s on IP:Port %s:%d using %s %s %s" ) | |||
| 2314 | % ( m_Username.IsEmpty() ? wxString(_("Unknown")wxGetTranslation(("Unknown"))) : m_Username ) | |||
| 2315 | % GetFullIP() | |||
| 2316 | % GetUserPort() | |||
| 2317 | % m_clientSoftString | |||
| 2318 | % m_clientVerString | |||
| 2319 | % m_strModVersion; | |||
| 2320 | } | |||
| 2321 | #endif | |||
| 2322 | ||||
| 2323 | wxString CUpDownClient::GetClientShortInfo() | |||
| 2324 | { | |||
| 2325 | if (m_clientVerString.IsEmpty()) { | |||
| 2326 | ReGetClientSoft(); | |||
| 2327 | } | |||
| 2328 | ||||
| 2329 | return CFormat( wxT("'%s' (%s %s %s)")L"'%s' (%s %s %s)" ) | |||
| 2330 | % ( m_Username.IsEmpty() ? wxString(_("Unknown")wxGetTranslation(("Unknown"))) : m_Username ) | |||
| 2331 | % m_clientSoftString | |||
| 2332 | % m_clientVerString | |||
| 2333 | % m_strModVersion; | |||
| 2334 | } | |||
| 2335 | ||||
| 2336 | ||||
| 2337 | void CUpDownClient::SendPublicIPRequest() | |||
| 2338 | { | |||
| 2339 | if (IsConnected()){ | |||
| 2340 | CPacket* packet = new CPacket(OP_PUBLICIP_REQ,0,OP_EMULEPROT); | |||
| 2341 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2342 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_PUBLICIP_REQ to ") + GetFullIP())do {} while (false); | |||
| 2343 | SendPacket(packet,true); | |||
| 2344 | m_fNeedOurPublicIP = true; | |||
| 2345 | } | |||
| 2346 | } | |||
| 2347 | ||||
| 2348 | void CUpDownClient::ProcessPublicIPAnswer(const uint8_t* pbyData, uint32 uSize) | |||
| 2349 | { | |||
| 2350 | if (uSize != 4) { | |||
| 2351 | throw wxString(wxT("Wrong Packet size on Public IP answer")L"Wrong Packet size on Public IP answer"); | |||
| 2352 | } | |||
| 2353 | uint32 dwIP = PeekUInt32(pbyData); | |||
| 2354 | if (m_fNeedOurPublicIP == true){ // did we? | |||
| 2355 | m_fNeedOurPublicIP = false; | |||
| 2356 | // Ignore local ip on GetPublicIP (could be wrong) | |||
| 2357 | if (theApp->GetPublicIP(true) == 0 && !IsLowID(dwIP) ) { | |||
| 2358 | theApp->SetPublicIP(dwIP); | |||
| 2359 | } | |||
| 2360 | } | |||
| 2361 | } | |||
| 2362 | ||||
| 2363 | ||||
| 2364 | bool CUpDownClient::IsConnected() const | |||
| 2365 | { | |||
| 2366 | return m_socket && m_socket->IsConnected(); | |||
| 2367 | } | |||
| 2368 | ||||
| 2369 | bool CUpDownClient::SendPacket(CPacket* packet, bool delpacket, bool controlpacket) | |||
| 2370 | { | |||
| 2371 | if ( m_socket ) { | |||
| 2372 | m_socket->SendPacket(packet, delpacket, controlpacket ); | |||
| 2373 | return true; | |||
| 2374 | } else { | |||
| 2375 | AddLogLineN(wxT("CAUGHT DEAD SOCKET IN SENDPACKET()"))theLogger.AddLogLine(L"BaseClient.cpp", 2375, false, logStandard , L"CAUGHT DEAD SOCKET IN SENDPACKET()"); | |||
| 2376 | return false; | |||
| 2377 | } | |||
| 2378 | } | |||
| 2379 | ||||
| 2380 | float CUpDownClient::SetDownloadLimit(uint32 reducedownload) | |||
| 2381 | { | |||
| 2382 | // lfroen: in daemon it actually can happen | |||
| 2383 | wxASSERT( m_socket )do { if ( m_socket ) { } else if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2383, __FUNCTION__, "m_socket" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 2384 | ||||
| 2385 | float kBpsClient = CalculateKBpsDown(); | |||
| 2386 | ||||
| 2387 | if ( m_socket ) { | |||
| 2388 | ||||
| 2389 | if (reducedownload) { | |||
| 2390 | // (% to reduce * current speed) / 100 and THEN, / (1000 / CORE_TIMER_PERIOD) | |||
| 2391 | // which is how often it is called per second. | |||
| 2392 | uint32 limit = (uint32)(reducedownload * kBpsClient * 1024.0 / 100000.0 * CORE_TIMER_PERIOD100); | |||
| 2393 | ||||
| 2394 | if(limit<1024 && reducedownload >= 200) { | |||
| 2395 | // If we're going up and this download is < 1kB, | |||
| 2396 | // we want it to go up fast. Can be reduced later, | |||
| 2397 | // and it'll probably be in a more fair way with | |||
| 2398 | // other downloads that are faster. | |||
| 2399 | limit +=1024; | |||
| 2400 | } else if(limit == 0) { | |||
| 2401 | // This download is not transferring yet... make it | |||
| 2402 | // 1024 so we don't fill the TCP stack and lose the | |||
| 2403 | // connection. | |||
| 2404 | limit = 1024; | |||
| 2405 | } | |||
| 2406 | ||||
| 2407 | m_socket->SetDownloadLimit(limit); | |||
| 2408 | } else { | |||
| 2409 | m_socket->DisableDownloadLimit(); | |||
| 2410 | } | |||
| 2411 | ||||
| 2412 | } else { | |||
| 2413 | AddLogLineNS(CFormat(wxT("CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f")) % kBpsClient)theLogger.AddLogLine(L"BaseClient.cpp", 2413, false, logStandard , CFormat(L"CAUGHT DEAD SOCKET IN SETDOWNLOADLIMIT() WITH SPEED %f" ) % kBpsClient, true); | |||
| 2414 | } | |||
| 2415 | ||||
| 2416 | return kBpsClient; | |||
| 2417 | } | |||
| 2418 | ||||
| 2419 | void CUpDownClient::SetUserIDHybrid(uint32 nUserID) | |||
| 2420 | { | |||
| 2421 | theApp->clientlist->UpdateClientID( this, nUserID ); | |||
| 2422 | ||||
| 2423 | m_nUserIDHybrid = nUserID; | |||
| 2424 | } | |||
| 2425 | ||||
| 2426 | ||||
| 2427 | void CUpDownClient::SetIP( uint32 val ) | |||
| 2428 | { | |||
| 2429 | theApp->clientlist->UpdateClientIP( this, val ); | |||
| 2430 | ||||
| 2431 | m_dwUserIP = val; | |||
| 2432 | ||||
| 2433 | m_nConnectIP = val; | |||
| 2434 | ||||
| 2435 | m_FullUserIP = val; | |||
| 2436 | } | |||
| 2437 | ||||
| 2438 | ||||
| 2439 | void CUpDownClient::SetUserHash(const CMD4Hash& userhash) | |||
| 2440 | { | |||
| 2441 | theApp->clientlist->UpdateClientHash( this, userhash ); | |||
| 2442 | ||||
| 2443 | m_UserHash = userhash; | |||
| 2444 | ||||
| 2445 | ValidateHash(); | |||
| 2446 | } | |||
| 2447 | ||||
| 2448 | EUtf8Str CUpDownClient::GetUnicodeSupport() const | |||
| 2449 | { | |||
| 2450 | return m_bUnicodeSupport ? utf8strRaw : utf8strNone; | |||
| 2451 | } | |||
| 2452 | ||||
| 2453 | void CUpDownClient::SetSpammer(bool bVal) | |||
| 2454 | { | |||
| 2455 | if (bVal) { | |||
| 2456 | Ban(); | |||
| 2457 | } else if (IsBanned() && m_fIsSpammer) { | |||
| 2458 | UnBan(); | |||
| 2459 | } | |||
| 2460 | m_fIsSpammer = bVal; | |||
| 2461 | } | |||
| 2462 | ||||
| 2463 | uint8 CUpDownClient::GetSecureIdentState() | |||
| 2464 | { | |||
| 2465 | if (m_SecureIdentState != IS_UNAVAILABLE) { | |||
| 2466 | if (!SecIdentSupRec) { | |||
| 2467 | // This can be caused by a 0.30x based client which sends the old | |||
| 2468 | // style Hello packet, and the mule info packet, but between them they | |||
| 2469 | // send a secure ident state packet (after a hello but before we have | |||
| 2470 | // the SUI capabilities). This is a misbehaving client, and somehow I | |||
| 2471 | // feel like it should be dropped. But then again, it won't harm to use | |||
| 2472 | // this SUI state if they are reporting no SUI (won't be used) and if | |||
| 2473 | // they report using SUI on the mule info packet, it's ok to use it. | |||
| 2474 | ||||
| 2475 | AddDebugLogLineN(logClient, wxT("A client sent secure ident state before telling us the SUI capabilities"))do {} while (false); | |||
| 2476 | AddDebugLogLineN(logClient, wxT("Client info: ") + GetClientFullInfo())do {} while (false); | |||
| 2477 | AddDebugLogLineN(logClient, wxT("This client won't be disconnected, but it should be. :P"))do {} while (false); | |||
| 2478 | } | |||
| 2479 | } | |||
| 2480 | ||||
| 2481 | return m_SecureIdentState; | |||
| 2482 | } | |||
| 2483 | ||||
| 2484 | ||||
| 2485 | bool CUpDownClient::SendChatMessage(const wxString& message) | |||
| 2486 | { | |||
| 2487 | if (GetChatCaptchaState() == CA_CAPTCHARECV) { | |||
| 2488 | m_nChatCaptchaState = CA_SOLUTIONSENT; | |||
| 2489 | } else if (GetChatCaptchaState() == CA_SOLUTIONSENT) { | |||
| 2490 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp" , 2490, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); // we responded to a captcha but didn't hear from the client afterwards - hopefully it's just lag and this message will get through | |||
| 2491 | } else { | |||
| 2492 | m_nChatCaptchaState = CA_ACCEPTING; | |||
| 2493 | } | |||
| 2494 | ||||
| 2495 | SetSpammer(false); | |||
| 2496 | IncMessagesSent(); | |||
| 2497 | // Already connecting? | |||
| 2498 | if (GetChatState() == MS_CONNECTING) { | |||
| 2499 | // Queue all messages till we're able to send them (or discard them) | |||
| 2500 | if (!m_pendingMessage.IsEmpty()) { | |||
| 2501 | m_pendingMessage += wxT("\n")L"\n"; | |||
| 2502 | } else { | |||
| 2503 | // There must be a message to send | |||
| 2504 | // - except if we got disconnected. No need to assert therefore. | |||
| 2505 | } | |||
| 2506 | m_pendingMessage += message; | |||
| 2507 | return false; | |||
| 2508 | } | |||
| 2509 | if (IsConnected()) { | |||
| 2510 | // If we are already connected when we send the first message, | |||
| 2511 | // we have to update the chat status. | |||
| 2512 | SetChatState(MS_CHATTING); | |||
| 2513 | CMemFile data; | |||
| 2514 | data.WriteString(message, GetUnicodeSupport()); | |||
| 2515 | CPacket* packet = new CPacket(data, OP_EDONKEYPROT, OP_MESSAGE); | |||
| 2516 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2517 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_MESSAGE to ") + GetFullIP())do {} while (false); | |||
| 2518 | SendPacket(packet, true, true); | |||
| 2519 | return true; | |||
| 2520 | } else { | |||
| 2521 | m_pendingMessage = message; | |||
| 2522 | SetChatState(MS_CONNECTING); | |||
| 2523 | // True to ignore "Too Many Connections" | |||
| 2524 | TryToConnect(true); | |||
| 2525 | return false; | |||
| 2526 | } | |||
| 2527 | } | |||
| 2528 | ||||
| 2529 | /* Kad stuff */ | |||
| 2530 | ||||
| 2531 | void CUpDownClient::SetBuddyID(const uint8_t* pucBuddyID) | |||
| 2532 | { | |||
| 2533 | if( pucBuddyID == NULL__null ){ | |||
| 2534 | md4clr(m_achBuddyID); | |||
| 2535 | m_bBuddyIDValid = false; | |||
| 2536 | return; | |||
| 2537 | } | |||
| 2538 | m_bBuddyIDValid = true; | |||
| 2539 | md4cpy(m_achBuddyID, pucBuddyID); | |||
| 2540 | } | |||
| 2541 | ||||
| 2542 | // Kad added by me | |||
| 2543 | ||||
| 2544 | bool CUpDownClient::SendBuddyPing() { | |||
| 2545 | SetLastBuddyPingPongTime(); | |||
| 2546 | CPacket* buddyPing = new CPacket(OP_BUDDYPING, 0, OP_EMULEPROT); | |||
| 2547 | theStats::AddUpOverheadKad(buddyPing->GetPacketSize()); | |||
| 2548 | AddDebugLogLineN(logLocalClient,wxT("Local Client: OP_BUDDYPING to ") + GetFullIP())do {} while (false); | |||
| 2549 | return SafeSendPacket(buddyPing); | |||
| 2550 | } | |||
| 2551 | ||||
| 2552 | ||||
| 2553 | /* Statistics */ | |||
| 2554 | ||||
| 2555 | void CUpDownClient::UpdateStats() | |||
| 2556 | { | |||
| 2557 | if (m_lastClientSoft != m_clientSoft || m_lastClientVersion != m_nClientVersion || m_lastOSInfo != m_sClientOSInfo) { | |||
| 2558 | if (m_lastClientSoft == SO_UNKNOWN) { | |||
| 2559 | theStats::RemoveUnknownClient(); | |||
| 2560 | } else if (m_lastClientSoft != (uint32)(-1)) { | |||
| 2561 | theStats::RemoveKnownClient(m_lastClientSoft, m_lastClientVersion, m_lastOSInfo); | |||
| 2562 | } | |||
| 2563 | ||||
| 2564 | m_lastClientSoft = m_clientSoft; | |||
| 2565 | m_lastClientVersion = m_nClientVersion; | |||
| 2566 | m_lastOSInfo = m_sClientOSInfo; | |||
| 2567 | ||||
| 2568 | if (m_clientSoft == SO_UNKNOWN) { | |||
| 2569 | theStats::AddUnknownClient(); | |||
| 2570 | } else { | |||
| 2571 | theStats::AddKnownClient(this); | |||
| 2572 | } | |||
| 2573 | } | |||
| 2574 | } | |||
| 2575 | ||||
| 2576 | bool CUpDownClient::IsIdentified() const | |||
| 2577 | { | |||
| 2578 | return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDENTIFIED); | |||
| 2579 | } | |||
| 2580 | ||||
| 2581 | bool CUpDownClient::IsBadGuy() const | |||
| 2582 | { | |||
| 2583 | return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDBADGUY); | |||
| 2584 | } | |||
| 2585 | ||||
| 2586 | bool CUpDownClient::SUIFailed() const | |||
| 2587 | { | |||
| 2588 | return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDFAILED); | |||
| 2589 | } | |||
| 2590 | ||||
| 2591 | bool CUpDownClient::SUINeeded() const | |||
| 2592 | { | |||
| 2593 | return (credits && credits->GetCurrentIdentState(GetIP()) == IS_IDNEEDED); | |||
| 2594 | } | |||
| 2595 | ||||
| 2596 | bool CUpDownClient::SUINotSupported() const | |||
| 2597 | { | |||
| 2598 | return (credits && credits->GetCurrentIdentState(GetIP()) == IS_NOTAVAILABLE); | |||
| 2599 | } | |||
| 2600 | ||||
| 2601 | uint64 CUpDownClient::GetDownloadedTotal() const | |||
| 2602 | { | |||
| 2603 | return credits ? credits->GetDownloadedTotal() : 0; | |||
| 2604 | } | |||
| 2605 | ||||
| 2606 | uint64 CUpDownClient::GetUploadedTotal() const | |||
| 2607 | { | |||
| 2608 | return credits ? credits->GetUploadedTotal() : 0; | |||
| 2609 | } | |||
| 2610 | ||||
| 2611 | double CUpDownClient::GetScoreRatio() const | |||
| 2612 | { | |||
| 2613 | return credits ? credits->GetScoreRatio(GetIP(), theApp->CryptoAvailable()) : 0; | |||
| 2614 | } | |||
| 2615 | ||||
| 2616 | const wxString CUpDownClient::GetServerName() const | |||
| 2617 | { | |||
| 2618 | wxString ret; | |||
| 2619 | wxString srvaddr = Uint32toStringIP(GetServerIP()); | |||
| 2620 | CServer* cserver = theApp->serverlist->GetServerByAddress( | |||
| 2621 | srvaddr, GetServerPort()); | |||
| 2622 | if (cserver) { | |||
| 2623 | ret = cserver->GetListName(); | |||
| 2624 | } else { | |||
| 2625 | ret = _("Unknown")wxGetTranslation(("Unknown")); | |||
| 2626 | } | |||
| 2627 | ||||
| 2628 | return ret; | |||
| 2629 | } | |||
| 2630 | ||||
| 2631 | bool CUpDownClient::ShouldReceiveCryptUDPPackets() const | |||
| 2632 | { | |||
| 2633 | return (thePrefs::IsClientCryptLayerSupported() && SupportsCryptLayer() && theApp->GetPublicIP() != 0 | |||
| 2634 | && HasValidHash() && (thePrefs::IsClientCryptLayerRequested() || RequestsCryptLayer()) ); | |||
| 2635 | } | |||
| 2636 | ||||
| 2637 | #ifdef AMULE_DAEMON | |||
| 2638 | ||||
| 2639 | void CUpDownClient::ProcessCaptchaRequest(CMemFile* WXUNUSED(data)) {} | |||
| 2640 | void CUpDownClient::ProcessCaptchaReqRes(uint8 WXUNUSED(nStatus)) {} | |||
| 2641 | void CUpDownClient::ProcessChatMessage(const wxString WXUNUSED(message)) {} | |||
| 2642 | ||||
| 2643 | #else | |||
| 2644 | ||||
| 2645 | void CUpDownClient::ProcessCaptchaRequest(CMemFile* data) | |||
| 2646 | { | |||
| 2647 | uint64 id = GUI_ID(GetIP(),GetUserPort())(uint64)((((uint64)GetIP())<<16) + (uint64)GetUserPort( )); | |||
| 2648 | // received a captcha request, check if we actually accept it (only after sending a message ourself to this client) | |||
| 2649 | if (GetChatCaptchaState() == CA_ACCEPTING && GetChatState() != MS_NONE | |||
| 2650 | && theApp->amuledlg->m_chatwnd->IsIdValid(id)) { | |||
| 2651 | // read tags (for future use) | |||
| 2652 | uint8 nTagCount = data->ReadUInt8(); | |||
| 2653 | if (nTagCount) { | |||
| 2654 | AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client (%s) with (%u) tags")) % GetFullIP() % nTagCount)do {} while (false); | |||
| 2655 | // and ignore them for now | |||
| 2656 | for (uint32 i = 0; i < nTagCount; i++) { | |||
| 2657 | CTag tag(*data, true); | |||
| 2658 | } | |||
| 2659 | } | |||
| 2660 | ||||
| 2661 | // sanitize checks - we want a small captcha not a wallpaper | |||
| 2662 | uint32 nSize = (uint32)(data->GetLength() - data->GetPosition()); | |||
| 2663 | ||||
| 2664 | if ( nSize > 128 && nSize < 4096 ) { | |||
| 2665 | uint64 pos = data->GetPosition(); | |||
| 2666 | wxMemoryInputStream memstr(data->GetRawBuffer() + pos, nSize); | |||
| 2667 | wxImage imgCaptcha(memstr, wxBITMAP_TYPE_BMP); | |||
| 2668 | ||||
| 2669 | if (imgCaptcha.IsOk() && imgCaptcha.GetHeight() > 10 && imgCaptcha.GetHeight() < 50 | |||
| 2670 | && imgCaptcha.GetWidth() > 10 && imgCaptcha.GetWidth() < 150 ) { | |||
| 2671 | m_nChatCaptchaState = CA_CAPTCHARECV; | |||
| 2672 | CCaptchaDialog * dialog = new CCaptchaDialog(theApp->amuledlg, imgCaptcha, id); | |||
| 2673 | dialog->Show(); | |||
| 2674 | ||||
| 2675 | } else { | |||
| 2676 | AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client, processing image failed or invalid pixel size (%s)")) % GetFullIP())do {} while (false); | |||
| 2677 | } | |||
| 2678 | } else { | |||
| 2679 | AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client, size sanitize check failed (%u) (%s)")) % nSize % GetFullIP())do {} while (false); | |||
| 2680 | } | |||
| 2681 | } else { | |||
| 2682 | AddDebugLogLineN(logClient, CFormat(wxT("Received captcha request from client, but don't accepting it at this time (%s)")) % GetFullIP())do {} while (false); | |||
| 2683 | } | |||
| 2684 | } | |||
| 2685 | ||||
| 2686 | void CUpDownClient::ProcessCaptchaReqRes(uint8 nStatus) | |||
| 2687 | { | |||
| 2688 | uint64 id = GUI_ID(GetIP(),GetUserPort())(uint64)((((uint64)GetIP())<<16) + (uint64)GetUserPort( )); | |||
| 2689 | if (GetChatCaptchaState() == CA_SOLUTIONSENT && GetChatState() != MS_NONE | |||
| 2690 | && theApp->amuledlg->m_chatwnd->IsIdValid(id)) { | |||
| 2691 | wxASSERT( nStatus < 3 )do { if ( nStatus < 3 ) { } else if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2691, __FUNCTION__, "nStatus < 3" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 2692 | m_nChatCaptchaState = CA_NONE; | |||
| 2693 | theApp->amuledlg->m_chatwnd->ShowCaptchaResult(id, nStatus == 0); | |||
| 2694 | } else { | |||
| 2695 | m_nChatCaptchaState = CA_NONE; | |||
| 2696 | AddDebugLogLineN(logClient, CFormat(wxT("Received captcha result from client, but not accepting it at this time (%s)")) % GetFullIP())do {} while (false); | |||
| 2697 | } | |||
| 2698 | } | |||
| 2699 | ||||
| 2700 | void CUpDownClient::ProcessChatMessage(wxString message) | |||
| 2701 | { | |||
| 2702 | if (IsMessageFiltered(message)) { | |||
| 2703 | AddLogLineC(CFormat(_("Message filtered from '%s' (IP:%s)")) % GetUserName() % GetFullIP())theLogger.AddLogLine(L"BaseClient.cpp", 2703, true, logStandard , CFormat(wxGetTranslation(("Message filtered from '%s' (IP:%s)" ))) % GetUserName() % GetFullIP()); | |||
| 2704 | return; | |||
| 2705 | } | |||
| 2706 | ||||
| 2707 | // advanced spamfilter check | |||
| 2708 | if (thePrefs::IsChatCaptchaEnabled() && !IsFriend()) { | |||
| 2709 | // captcha checks outrank any further checks - if the captcha has been solved, we assume it's not spam | |||
| 2710 | // first check if we need to send a captcha request to this client | |||
| 2711 | if (GetMessagesSent() == 0 && GetMessagesReceived() == 0 && GetChatCaptchaState() != CA_CAPTCHASOLVED) { | |||
| 2712 | // we have never sent a message to this client, and no message from him has ever passed our filters | |||
| 2713 | if (GetChatCaptchaState() != CA_CHALLENGESENT) { | |||
| 2714 | // we also aren't currently expecting a captcha response | |||
| 2715 | if (m_fSupportsCaptcha) { | |||
| 2716 | // and he supports captcha, so send him one and store the message (without showing for now) | |||
| 2717 | if (m_cCaptchasSent < 3) { // no more than 3 tries | |||
| 2718 | m_strCaptchaPendingMsg = message; | |||
| 2719 | wxMemoryOutputStream memstr; | |||
| 2720 | memstr.PutC(0); // no tags, for future use | |||
| 2721 | CCaptchaGenerator captcha(4); | |||
| 2722 | if (captcha.WriteCaptchaImage(memstr)){ | |||
| 2723 | m_strCaptchaChallenge = captcha.GetCaptchaText(); | |||
| 2724 | m_nChatCaptchaState = CA_CHALLENGESENT; | |||
| 2725 | m_cCaptchasSent++; | |||
| 2726 | CMemFile fileAnswer((uint8_t*) memstr.GetOutputStreamBuffer()->GetBufferStart(), memstr.GetLength()); | |||
| 2727 | CPacket* packet = new CPacket(fileAnswer, OP_EMULEPROT, OP_CHATCAPTCHAREQ); | |||
| 2728 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2729 | AddLogLineN(CFormat(wxT("sent Captcha %s (%d)")) % m_strCaptchaChallenge % packet->GetPacketSize())theLogger.AddLogLine(L"BaseClient.cpp", 2729, false, logStandard , CFormat(L"sent Captcha %s (%d)") % m_strCaptchaChallenge % packet ->GetPacketSize()); | |||
| 2730 | SafeSendPacket(packet); | |||
| 2731 | } else { | |||
| 2732 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp" , 2732, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 2733 | } | |||
| 2734 | } | |||
| 2735 | } else { | |||
| 2736 | // client doesn't support captchas, but we require them, tell him that it's not going to work out | |||
| 2737 | // with an answer message (will not be shown and doesn't count as sent message) | |||
| 2738 | if (m_cCaptchasSent < 1) { // don't send this notifier more than once | |||
| 2739 | m_cCaptchasSent++; | |||
| 2740 | // always sent in english | |||
| 2741 | SendChatMessage(wxT("In order to avoid spam messages, this user requires you to solve a captcha before you can send a message to him. However your client does not supports captchas, so you will not be able to chat with this user.")L"In order to avoid spam messages, this user requires you to solve a captcha before you can send a message to him. However your client does not supports captchas, so you will not be able to chat with this user."); | |||
| 2742 | AddDebugLogLineN(logClient, CFormat(wxT("Received message from client not supporting captchas, filtered and sent notifier (%s)")) % GetClientFullInfo())do {} while (false); | |||
| 2743 | } else { | |||
| 2744 | AddDebugLogLineN(logClient, CFormat(wxT("Received message from client not supporting captchas, filtered, didn't send notifier (%s)")) % GetClientFullInfo())do {} while (false); | |||
| 2745 | } | |||
| 2746 | } | |||
| 2747 | return; | |||
| 2748 | } else { // (GetChatCaptchaState() == CA_CHALLENGESENT) | |||
| 2749 | // this message must be the answer to the captcha request we sent him, let's verify | |||
| 2750 | wxASSERT( !m_strCaptchaChallenge.IsEmpty() )do { if ( !m_strCaptchaChallenge.IsEmpty() ) { } else if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2750, __FUNCTION__, "!m_strCaptchaChallenge.IsEmpty()", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 2751 | if (m_strCaptchaChallenge.CmpNoCase(message.Trim().Right(std::min(message.Length(), m_strCaptchaChallenge.Length()))) == 0) { | |||
| 2752 | // allright | |||
| 2753 | AddDebugLogLineN(logClient, CFormat(wxT("Captcha solved, showing withheld message (%s)")) % GetClientFullInfo())do {} while (false); | |||
| 2754 | m_nChatCaptchaState = CA_CAPTCHASOLVED; // this state isn't persitent, but the messagecounter will be used to determine later if the captcha has been solved | |||
| 2755 | // replace captchaanswer with withheld message and show it | |||
| 2756 | message = m_strCaptchaPendingMsg; | |||
| 2757 | m_cCaptchasSent = 0; | |||
| 2758 | m_strCaptchaChallenge.Clear(); | |||
| 2759 | CPacket* packet = new CPacket(OP_CHATCAPTCHARES, 1, OP_EMULEPROT, false); | |||
| 2760 | uint8_t statusResponse = 0; // status response | |||
| 2761 | packet->CopyToDataBuffer(0, &statusResponse, 1); | |||
| 2762 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2763 | SafeSendPacket(packet); | |||
| 2764 | } else { // wrong, cleanup and ignore | |||
| 2765 | AddDebugLogLineN(logClient, CFormat(wxT("Captcha answer failed (%s)")) % GetClientFullInfo())do {} while (false); | |||
| 2766 | m_nChatCaptchaState = CA_NONE; | |||
| 2767 | m_strCaptchaChallenge.Clear(); | |||
| 2768 | m_strCaptchaPendingMsg.Clear(); | |||
| 2769 | CPacket* packet = new CPacket(OP_CHATCAPTCHARES, 1, OP_EMULEPROT, false); | |||
| 2770 | uint8_t statusResponse = (m_cCaptchasSent < 3) ? 1 : 2; // status response | |||
| 2771 | packet->CopyToDataBuffer(0, &statusResponse, 1); | |||
| 2772 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 2773 | SafeSendPacket(packet); | |||
| 2774 | return; // nothing more todo | |||
| 2775 | } | |||
| 2776 | } | |||
| 2777 | } | |||
| 2778 | } | |||
| 2779 | ||||
| 2780 | if (thePrefs::IsAdvancedSpamfilterEnabled() && !IsFriend()) { // friends are never spammer... (but what if two spammers are friends :P ) | |||
| 2781 | bool bIsSpam = false; | |||
| 2782 | if (m_fIsSpammer) { | |||
| 2783 | bIsSpam = true; | |||
| 2784 | } else { | |||
| 2785 | // first fixed criteria: If a client sends me an URL in his first message before I respond to him | |||
| 2786 | // there is a 99,9% chance that it is some poor guy advising his leech mod, or selling you .. well you know :P | |||
| 2787 | if (GetMessagesSent() == 0) { | |||
| 2788 | static wxArrayString urlindicators(wxStringTokenize(wxT("http:|www.|.de |.net |.com |.org |.to |.tk |.cc |.fr |ftp:|ed2k:|https:|ftp.|.info|.biz|.uk|.eu|.es|.tv|.cn|.tw|.ws|.nu|.jp")L"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("|")L"|")); | |||
| 2789 | for (size_t pos = urlindicators.GetCount(); pos--;) { | |||
| 2790 | if (message.Find(urlindicators[pos]) != wxNOT_FOUND(-1)) { | |||
| 2791 | bIsSpam = true; | |||
| 2792 | break; | |||
| 2793 | } | |||
| 2794 | } | |||
| 2795 | // second fixed criteria: he sent me 4 or more messages and I didn't answer him once | |||
| 2796 | if (GetMessagesReceived() > 3) { | |||
| 2797 | bIsSpam = true; | |||
| 2798 | } | |||
| 2799 | } | |||
| 2800 | } | |||
| 2801 | if (bIsSpam) { | |||
| 2802 | AddDebugLogLineN(logClient, CFormat(wxT("'%s' has been marked as spammer")) % GetUserName())do {} while (false); | |||
| 2803 | SetSpammer(true); | |||
| 2804 | theApp->amuledlg->m_chatwnd->EndSession(GUI_ID(GetIP(),GetUserPort())(uint64)((((uint64)GetIP())<<16) + (uint64)GetUserPort( ))); | |||
| 2805 | return; | |||
| 2806 | } | |||
| 2807 | } | |||
| 2808 | ||||
| 2809 | ||||
| 2810 | wxString logMsg = CFormat(_("New message from '%s' (IP:%s)")wxGetTranslation(("New message from '%s' (IP:%s)"))) % GetUserName() % GetFullIP(); | |||
| 2811 | if(thePrefs::ShowMessagesInLog()) { | |||
| 2812 | logMsg += wxT(": ")L": " + message; | |||
| 2813 | } | |||
| 2814 | AddLogLineC(logMsg)theLogger.AddLogLine(L"BaseClient.cpp", 2814, true, logStandard , logMsg); | |||
| 2815 | IncMessagesReceived(); | |||
| 2816 | ||||
| 2817 | Notify_ChatProcessMsg(GUI_ID(GetIP(), GetUserPort()), GetUserName() + wxT("|") + message)MuleNotify::DoNotify(&MuleNotify::ChatProcessMsg, (uint64 )((((uint64)GetIP())<<16) + (uint64)GetUserPort()), GetUserName () + L"|" + message); | |||
| 2818 | } | |||
| 2819 | ||||
| 2820 | bool CUpDownClient::IsMessageFiltered(const wxString& message) | |||
| 2821 | { | |||
| 2822 | bool filtered = false; | |||
| 2823 | // If we're chatting to the guy, we don't want to filter! | |||
| 2824 | if (GetChatState() != MS_CHATTING) { | |||
| 2825 | if (thePrefs::MsgOnlyFriends() && !IsFriend()) { | |||
| 2826 | filtered = true; | |||
| 2827 | } else if (thePrefs::MsgOnlySecure() && GetUserName().IsEmpty() ) { | |||
| 2828 | filtered = true; | |||
| 2829 | } else if (thePrefs::MustFilterMessages()) { | |||
| 2830 | filtered = thePrefs::IsMessageFiltered(message); | |||
| 2831 | } | |||
| 2832 | } | |||
| 2833 | if (filtered) { | |||
| 2834 | SetSpammer(true); | |||
| 2835 | } | |||
| 2836 | return filtered; | |||
| 2837 | } | |||
| 2838 | ||||
| 2839 | #endif | |||
| 2840 | ||||
| 2841 | void CUpDownClient::SendSharedDirectories() | |||
| 2842 | { | |||
| 2843 | // This list will contain all (unique) folders. | |||
| 2844 | PathList foldersToSend; | |||
| 2845 | ||||
| 2846 | // The shared folders | |||
| 2847 | const unsigned folderCount = theApp->glob_prefs->shareddir_list.size(); | |||
| 2848 | for (unsigned i = 0; i < folderCount; ++i) { | |||
| 2849 | foldersToSend.push_back(theApp->glob_prefs->shareddir_list[i]); | |||
| 2850 | } | |||
| 2851 | ||||
| 2852 | // ... the categories folders ... (category 0 -> incoming) | |||
| 2853 | for (unsigned i = 0; i < theApp->glob_prefs->GetCatCount(); ++i) { | |||
| 2854 | foldersToSend.push_back(theApp->glob_prefs->GetCategory(i)->path); | |||
| 2855 | } | |||
| 2856 | ||||
| 2857 | // Strip duplicates | |||
| 2858 | foldersToSend.sort(); | |||
| 2859 | foldersToSend.unique(); | |||
| 2860 | ||||
| 2861 | // Build packet | |||
| 2862 | CMemFile tempfile(80); | |||
| 2863 | tempfile.WriteUInt32(foldersToSend.size() + 1); // + 1 for the incomplete files | |||
| 2864 | ||||
| 2865 | PathList::iterator it = foldersToSend.begin(); | |||
| 2866 | for (; it != foldersToSend.end(); ++it) { | |||
| 2867 | // Note: the public shared name contains the 'raw' path, so we can recognize it again. | |||
| 2868 | // the 'raw' path is determined using CPath::GetRaw() | |||
| 2869 | tempfile.WriteString( theApp->sharedfiles->GetPublicSharedDirName(*it), GetUnicodeSupport() ); | |||
| 2870 | } | |||
| 2871 | ||||
| 2872 | // ... and the Magic thing from the eDonkey Hybrids... | |||
| 2873 | tempfile.WriteString(OP_INCOMPLETE_SHARED_FILESL"!Incomplete Files", GetUnicodeSupport()); | |||
| 2874 | ||||
| 2875 | // Send the packet. | |||
| 2876 | CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDDIRSANS); | |||
| 2877 | theStats::AddUpOverheadOther(replypacket->GetPacketSize()); | |||
| 2878 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDDIRSANS to ") + GetFullIP() )do {} while (false); | |||
| 2879 | SendPacket(replypacket, true, true); | |||
| 2880 | } | |||
| 2881 | ||||
| 2882 | void CUpDownClient::SendSharedFilesOfDirectory(const wxString& strReqDir) | |||
| 2883 | { | |||
| 2884 | CKnownFilePtrList list; | |||
| 2885 | ||||
| 2886 | if (strReqDir == OP_INCOMPLETE_SHARED_FILESL"!Incomplete Files") { | |||
| ||||
| 2887 | // get all shared files from download queue | |||
| 2888 | int iQueuedFiles = theApp->downloadqueue->GetFileCount(); | |||
| 2889 | for (int i = 0; i < iQueuedFiles; i++) { | |||
| 2890 | CPartFile* pFile = theApp->downloadqueue->GetFileByIndex(i); | |||
| 2891 | if (pFile == NULL__null || pFile->GetStatus(true) != PS_READY0) { | |||
| 2892 | continue; | |||
| 2893 | } | |||
| 2894 | list.push_back(pFile); | |||
| 2895 | } | |||
| 2896 | } else { | |||
| 2897 | // get all shared files for the requested directory | |||
| 2898 | const CPath *sharedDir = theApp->sharedfiles->GetDirForPublicSharedDirName(strReqDir); | |||
| 2899 | if (sharedDir) { | |||
| 2900 | theApp->sharedfiles->GetSharedFilesByDirectory(sharedDir->GetRaw(), list); | |||
| 2901 | } else { | |||
| 2902 | AddLogLineC(CFormat(_("User %s (%u) requested sharedfiles-list for not existing directory '%s' -> Ignored")) % GetUserName() % GetUserIDHybrid() % strReqDir)theLogger.AddLogLine(L"BaseClient.cpp", 2902, true, logStandard , CFormat(wxGetTranslation(("User %s (%u) requested sharedfiles-list for not existing directory '%s' -> Ignored" ))) % GetUserName() % GetUserIDHybrid() % strReqDir); | |||
| 2903 | } | |||
| 2904 | } | |||
| 2905 | ||||
| 2906 | CMemFile tempfile(80); | |||
| 2907 | tempfile.WriteString(strReqDir, GetUnicodeSupport()); | |||
| 2908 | tempfile.WriteUInt32(list.size()); | |||
| 2909 | ||||
| 2910 | while (!list.empty()) { | |||
| 2911 | if (!list.front()->IsLargeFile() || SupportsLargeFiles()) { | |||
| 2912 | list.front()->CreateOfferedFilePacket(&tempfile, NULL__null, this); | |||
| 2913 | } | |||
| 2914 | list.pop_front(); | |||
| 2915 | } | |||
| 2916 | ||||
| 2917 | CPacket* replypacket = new CPacket(tempfile, OP_EDONKEYPROT, OP_ASKSHAREDFILESDIRANS); | |||
| 2918 | theStats::AddUpOverheadOther(replypacket->GetPacketSize()); | |||
| 2919 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_ASKSHAREDFILESDIRANS to ") + GetFullIP() )do {} while (false); | |||
| 2920 | SendPacket(replypacket, true, true); | |||
| 2921 | } | |||
| ||||
| 2922 | ||||
| 2923 | void CUpDownClient::SendFirewallCheckUDPRequest() | |||
| 2924 | { | |||
| 2925 | wxASSERT(GetKadState() == KS_FWCHECK_UDP)do { if ( GetKadState() == KS_FWCHECK_UDP ) { } else if ( wxTheAssertHandler && (wxOnAssert("BaseClient.cpp", 2925, __FUNCTION__, "GetKadState() == KS_FWCHECK_UDP", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 2926 | ||||
| 2927 | if (!Kademlia::CKademlia::IsRunning()) { | |||
| 2928 | SetKadState(KS_NONE); | |||
| 2929 | return; | |||
| 2930 | } else if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE || GetKadVersion() <= 5 || GetKadPort() == 0) { | |||
| 2931 | Kademlia::CUDPFirewallTester::SetUDPFWCheckResult(false, true, wxUINT32_SWAP_ALWAYS(GetIP())((wxUint32) ( (((wxUint32) (GetIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetIP()) & (wxUint32) 0x0000ff00U ) << 8) | (((wxUint32) (GetIP()) & (wxUint32) 0x00ff0000U ) >> 8) | (((wxUint32) (GetIP()) & (wxUint32) 0xff000000U ) >> 24))), 0); // inform the tester that this test was cancelled | |||
| 2932 | SetKadState(KS_NONE); | |||
| 2933 | return; | |||
| 2934 | } | |||
| 2935 | ||||
| 2936 | CMemFile data; | |||
| 2937 | data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetInternKadPort()); | |||
| 2938 | data.WriteUInt16(Kademlia::CKademlia::GetPrefs()->GetExternalKadPort()); | |||
| 2939 | data.WriteUInt32(Kademlia::CKademlia::GetPrefs()->GetUDPVerifyKey(GetConnectIP())); | |||
| 2940 | CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_FWCHECKUDPREQ); | |||
| 2941 | theStats::AddUpOverheadKad(packet->GetPacketSize()); | |||
| 2942 | SafeSendPacket(packet); | |||
| 2943 | } | |||
| 2944 | ||||
| 2945 | void CUpDownClient::ProcessFirewallCheckUDPRequest(CMemFile* data) | |||
| 2946 | { | |||
| 2947 | if (!Kademlia::CKademlia::IsRunning() || Kademlia::CKademlia::GetUDPListener() == NULL__null) { | |||
| 2948 | //DebugLogWarning(_T("Ignored Kad Firewallrequest UDP because Kad is not running (%s)"), GetClientFullInfo()); | |||
| 2949 | return; | |||
| 2950 | } | |||
| 2951 | ||||
| 2952 | // first search if we know this IP already, if so the result might be biased and we need tell the requester | |||
| 2953 | bool errorAlreadyKnown = false; | |||
| 2954 | if (GetUploadState() != US_NONE || GetDownloadState() != DS_NONE || GetChatState() != MS_NONE) { | |||
| 2955 | errorAlreadyKnown = true; | |||
| 2956 | } else if (Kademlia::CKademlia::GetRoutingZone()->GetContact(wxUINT32_SWAP_ALWAYS(GetConnectIP())((wxUint32) ( (((wxUint32) (GetConnectIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetConnectIP()) & (wxUint32 ) 0x0000ff00U) << 8) | (((wxUint32) (GetConnectIP()) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (GetConnectIP ()) & (wxUint32) 0xff000000U) >> 24))), 0, false) != NULL__null) { | |||
| 2957 | errorAlreadyKnown = true; | |||
| 2958 | } | |||
| 2959 | ||||
| 2960 | uint16_t remoteInternPort = data->ReadUInt16(); | |||
| 2961 | uint16_t remoteExternPort = data->ReadUInt16(); | |||
| 2962 | uint32_t senderKey = data->ReadUInt32(); | |||
| 2963 | if (remoteInternPort == 0) { | |||
| 2964 | //DebugLogError(_T("UDP Firewallcheck requested with Intern Port == 0 (%s)"), GetClientFullInfo()); | |||
| 2965 | return; | |||
| 2966 | } | |||
| 2967 | // if (senderKey == 0) | |||
| 2968 | // DebugLogWarning(_T("UDP Firewallcheck requested with SenderKey == 0 (%s)"), GetClientFullInfo()); | |||
| 2969 | ||||
| 2970 | CMemFile testPacket1; | |||
| 2971 | testPacket1.WriteUInt8(errorAlreadyKnown ? 1 : 0); | |||
| 2972 | testPacket1.WriteUInt16(remoteInternPort); | |||
| 2973 | DebugSend(Kad2FirewallUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteInternPort)do {} while (false); | |||
| 2974 | Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket1, KADEMLIA2_FIREWALLUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP())((wxUint32) ( (((wxUint32) (GetConnectIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetConnectIP()) & (wxUint32 ) 0x0000ff00U) << 8) | (((wxUint32) (GetConnectIP()) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (GetConnectIP ()) & (wxUint32) 0xff000000U) >> 24))), remoteInternPort, Kademlia::CKadUDPKey(senderKey, theApp->GetPublicIP(false)), NULL__null); | |||
| 2975 | ||||
| 2976 | // if the client has a router with PAT (and therefore a different extern port than intern), test this port too | |||
| 2977 | if (remoteExternPort != 0 && remoteExternPort != remoteInternPort) { | |||
| 2978 | CMemFile testPacket2; | |||
| 2979 | testPacket2.WriteUInt8(errorAlreadyKnown ? 1 : 0); | |||
| 2980 | testPacket2.WriteUInt16(remoteExternPort); | |||
| 2981 | DebugSend(Kad2FirewalledUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP()), remoteExternPort)do {} while (false); | |||
| 2982 | Kademlia::CKademlia::GetUDPListener()->SendPacket(testPacket2, KADEMLIA2_FIREWALLUDP, wxUINT32_SWAP_ALWAYS(GetConnectIP())((wxUint32) ( (((wxUint32) (GetConnectIP()) & (wxUint32) 0x000000ffU ) << 24) | (((wxUint32) (GetConnectIP()) & (wxUint32 ) 0x0000ff00U) << 8) | (((wxUint32) (GetConnectIP()) & (wxUint32) 0x00ff0000U) >> 8) | (((wxUint32) (GetConnectIP ()) & (wxUint32) 0xff000000U) >> 24))), remoteExternPort, Kademlia::CKadUDPKey(senderKey, theApp->GetPublicIP(false)), NULL__null); | |||
| 2983 | } | |||
| 2984 | //DebugLog(_T("Answered UDP Firewallcheck request (%s)"), GetClientFullInfo()); | |||
| 2985 | } | |||
| 2986 | ||||
| 2987 | void CUpDownClient::SetConnectOptions(uint8_t options, bool encryption, bool callback) | |||
| 2988 | { | |||
| 2989 | SetCryptLayerSupport((options & 0x01) != 0 && encryption); | |||
| 2990 | SetCryptLayerRequest((options & 0x02) != 0 && encryption); | |||
| 2991 | SetCryptLayerRequires((options & 0x04) != 0 && encryption); | |||
| 2992 | SetDirectUDPCallbackSupport((options & 0x08) != 0 && callback); | |||
| 2993 | } | |||
| 2994 | ||||
| 2995 | ||||
| 2996 | #ifdef DEBUG_ZOMBIE_CLIENTS | |||
| 2997 | void CUpDownClient::Unlink(const wxString& from) | |||
| 2998 | { | |||
| 2999 | std::multiset<wxString>::iterator it = m_linkedFrom.find(from); | |||
| 3000 | if (it != m_linkedFrom.end()) { | |||
| 3001 | m_linkedFrom.erase(it); | |||
| 3002 | } | |||
| 3003 | m_linked--; | |||
| 3004 | if (!m_linked) { | |||
| 3005 | if (m_linkedDebug) { | |||
| 3006 | AddLogLineN(CFormat(wxT("Last reference to client %d %p unlinked, delete it.")) % ECID() % this)theLogger.AddLogLine(L"BaseClient.cpp", 3006, false, logStandard , CFormat(L"Last reference to client %d %p unlinked, delete it." ) % ECID() % this); | |||
| 3007 | } | |||
| 3008 | delete this; | |||
| 3009 | } | |||
| 3010 | } | |||
| 3011 | ||||
| 3012 | #else | |||
| 3013 | ||||
| 3014 | void CUpDownClient::Unlink() | |||
| 3015 | { | |||
| 3016 | m_linked--; | |||
| 3017 | if (!m_linked) { | |||
| 3018 | delete this; | |||
| 3019 | } | |||
| 3020 | } | |||
| 3021 | #endif | |||
| 3022 | ||||
| 3023 | ||||
| 3024 | // File_checked_for_headers |