| File: | rootdir/src/DownloadClient.cpp |
| Warning: | line 1117, column 3 Memory copy function accesses out-of-bound array element |
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 "updownclient.h" // Needed for CUpDownClient | |||
| 27 | ||||
| 28 | #include <protocol/Protocols.h> | |||
| 29 | #include <protocol/ed2k/Client2Client/TCP.h> | |||
| 30 | #include <protocol/ed2k/Client2Client/UDP.h> | |||
| 31 | #include <common/EventIDs.h> | |||
| 32 | #include <common/Macros.h> | |||
| 33 | #include <common/Constants.h> | |||
| 34 | ||||
| 35 | #include <zlib.h> | |||
| 36 | #include <cmath> // Needed for std:exp | |||
| 37 | ||||
| 38 | #include "ClientCredits.h" // Needed for CClientCredits | |||
| 39 | #include "ClientUDPSocket.h" // Needed for CClientUDPSocket | |||
| 40 | #include "DownloadQueue.h" // Needed for CDownloadQueue | |||
| 41 | #include "Preferences.h" // Needed for thePrefs | |||
| 42 | #include "Packet.h" // Needed for CPacket | |||
| 43 | #include "MemFile.h" // Needed for CMemFile | |||
| 44 | #include "ClientTCPSocket.h"// Needed for CClientTCPSocket | |||
| 45 | #include "ListenSocket.h" // Needed for CListenSocket | |||
| 46 | #include "amule.h" // Needed for theApp | |||
| 47 | #include "PartFile.h" // Needed for CPartFile | |||
| 48 | #include "SharedFileList.h" | |||
| 49 | #include "Statistics.h" // Needed for theStats | |||
| 50 | #include "Logger.h" | |||
| 51 | #include "GuiEvents.h" // Needed for Notify_* | |||
| 52 | #include "UploadQueue.h" // Needed for CUploadQueue | |||
| 53 | ||||
| 54 | ||||
| 55 | #ifdef __MULE_UNUSED_CODE__ | |||
| 56 | // This function is left as a reminder. | |||
| 57 | // Changes here _must_ be reflected in CClientList::FindMatchingClient. | |||
| 58 | bool CUpDownClient::Compare(const CUpDownClient* tocomp, bool bIgnoreUserhash) const | |||
| 59 | { | |||
| 60 | if (!tocomp) { | |||
| 61 | // should we wxASSERT here? | |||
| 62 | return false; | |||
| 63 | } | |||
| 64 | ||||
| 65 | //Compare only the user hash.. | |||
| 66 | if(!bIgnoreUserhash && HasValidHash() && tocomp->HasValidHash()) { | |||
| 67 | return GetUserHash() == tocomp->GetUserHash(); | |||
| 68 | } | |||
| 69 | ||||
| 70 | if (HasLowID()) { | |||
| 71 | //User is firewalled.. Must do two checks.. | |||
| 72 | if (GetIP()!=0 && GetIP() == tocomp->GetIP()) { | |||
| 73 | //The IP of both match | |||
| 74 | if (GetUserPort()!=0 && GetUserPort() == tocomp->GetUserPort()) { | |||
| 75 | //IP-UserPort matches | |||
| 76 | return true; | |||
| 77 | } | |||
| 78 | if (GetKadPort()!=0 && GetKadPort() == tocomp->GetKadPort()) { | |||
| 79 | //IP-KadPort Matches | |||
| 80 | return true; | |||
| 81 | } | |||
| 82 | } | |||
| 83 | ||||
| 84 | if (GetUserIDHybrid()!=0 | |||
| 85 | && GetUserIDHybrid() == tocomp->GetUserIDHybrid() | |||
| 86 | && GetServerIP()!=0 | |||
| 87 | && GetServerIP() == tocomp->GetServerIP() | |||
| 88 | && GetServerPort()!=0 | |||
| 89 | && GetServerPort() == tocomp->GetServerPort()) { | |||
| 90 | //Both have the same lowID, Same serverIP and Port.. | |||
| 91 | return true; | |||
| 92 | } | |||
| 93 | ||||
| 94 | //Both IP, and Server do not match.. | |||
| 95 | return false; | |||
| 96 | } | |||
| 97 | ||||
| 98 | //User is not firewalled. | |||
| 99 | if (GetUserPort()!=0) { | |||
| 100 | //User has a Port, lets check the rest. | |||
| 101 | if (GetIP() != 0 && tocomp->GetIP() != 0) { | |||
| 102 | //Both clients have a verified IP.. | |||
| 103 | if(GetIP() == tocomp->GetIP() && GetUserPort() == tocomp->GetUserPort()) { | |||
| 104 | //IP and UserPort match.. | |||
| 105 | return true; | |||
| 106 | } | |||
| 107 | } else { | |||
| 108 | //One of the two clients do not have a verified IP | |||
| 109 | if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetUserPort() == tocomp->GetUserPort()) { | |||
| 110 | //ID and Port Match.. | |||
| 111 | return true; | |||
| 112 | } | |||
| 113 | } | |||
| 114 | } | |||
| 115 | ||||
| 116 | if(GetKadPort()!=0) { | |||
| 117 | //User has a Kad Port. | |||
| 118 | if(GetIP() != 0 && tocomp->GetIP() != 0) { | |||
| 119 | //Both clients have a verified IP. | |||
| 120 | if(GetIP() == tocomp->GetIP() && GetKadPort() == tocomp->GetKadPort()) { | |||
| 121 | //IP and KadPort Match.. | |||
| 122 | return true; | |||
| 123 | } | |||
| 124 | } else { | |||
| 125 | //One of the users do not have a verified IP. | |||
| 126 | if (GetUserIDHybrid() == tocomp->GetUserIDHybrid() && GetKadPort() == tocomp->GetKadPort()) { | |||
| 127 | //ID and KadProt Match.. | |||
| 128 | return true; | |||
| 129 | } | |||
| 130 | } | |||
| 131 | } | |||
| 132 | ||||
| 133 | //No Matches.. | |||
| 134 | return false; | |||
| 135 | } | |||
| 136 | #endif | |||
| 137 | ||||
| 138 | ||||
| 139 | bool CUpDownClient::AskForDownload() | |||
| 140 | { | |||
| 141 | // 0.42e | |||
| 142 | if (theApp->listensocket->TooManySockets()) { | |||
| 143 | if (!m_socket) { | |||
| 144 | if (GetDownloadState() != DS_TOOMANYCONNS) { | |||
| 145 | SetDownloadState(DS_TOOMANYCONNS); | |||
| 146 | } | |||
| 147 | return true; | |||
| 148 | } else if (!m_socket->IsConnected()) { | |||
| 149 | if (GetDownloadState() != DS_TOOMANYCONNS) { | |||
| 150 | SetDownloadState(DS_TOOMANYCONNS); | |||
| 151 | } | |||
| 152 | return true; | |||
| 153 | } | |||
| 154 | } | |||
| 155 | m_bUDPPending = false; | |||
| 156 | m_dwLastAskedTime = ::GetTickCount(); | |||
| 157 | SetDownloadState(DS_CONNECTING); | |||
| 158 | SetSentCancelTransfer(0); | |||
| 159 | return TryToConnect(); | |||
| 160 | } | |||
| 161 | ||||
| 162 | ||||
| 163 | void CUpDownClient::SendStartupLoadReq() | |||
| 164 | { | |||
| 165 | // 0.42e | |||
| 166 | if (m_socket==NULL__null || m_reqfile==NULL__null) { | |||
| 167 | return; | |||
| 168 | } | |||
| 169 | SetDownloadState(DS_ONQUEUE); | |||
| 170 | CMemFile dataStartupLoadReq(16); | |||
| 171 | dataStartupLoadReq.WriteHash(m_reqfile->GetFileHash()); | |||
| 172 | CPacket* packet = new CPacket(dataStartupLoadReq, OP_EDONKEYPROT, OP_STARTUPLOADREQ); | |||
| 173 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 174 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_STARTUPLOADREQ to ") + GetFullIP())do {} while (false); | |||
| 175 | SendPacket(packet, true, true); | |||
| 176 | } | |||
| 177 | ||||
| 178 | ||||
| 179 | bool CUpDownClient::IsSourceRequestAllowed() | |||
| 180 | { | |||
| 181 | //#warning REWRITE - Source swapping from eMule. | |||
| 182 | // 0.42e | |||
| 183 | uint32 dwTickCount = ::GetTickCount() + CONNECTION_LATENCY22050; | |||
| 184 | uint32 nTimePassedClient = dwTickCount - GetLastSrcAnswerTime(); | |||
| 185 | uint32 nTimePassedFile = dwTickCount - m_reqfile->GetLastAnsweredTime(); | |||
| 186 | bool bNeverAskedBefore = (GetLastAskedForSources() == 0); | |||
| 187 | ||||
| 188 | uint32 uSources = m_reqfile->GetSourceCount(); | |||
| 189 | return ( | |||
| 190 | // if client has the correct extended protocol | |||
| 191 | ExtProtocolAvailable() && (SupportsSourceExchange2() || GetSourceExchange1Version() > 1) && | |||
| 192 | // AND if we need more sources | |||
| 193 | thePrefs::GetMaxSourcePerFileSoft() > uSources && | |||
| 194 | // AND if... | |||
| 195 | ( | |||
| 196 | //source is not complete and file is very rare | |||
| 197 | ( !m_bCompleteSource | |||
| 198 | && (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASKS(((40)*60)*1000)) | |||
| 199 | && (uSources <= RARE_FILE50/5) | |||
| 200 | ) || | |||
| 201 | //source is not complete and file is rare | |||
| 202 | ( !m_bCompleteSource | |||
| 203 | && (bNeverAskedBefore || nTimePassedClient > SOURCECLIENTREASKS(((40)*60)*1000)) | |||
| 204 | && (uSources <= RARE_FILE50 || uSources - m_reqfile->GetValidSourcesCount() <= RARE_FILE50 / 2) | |||
| 205 | && (nTimePassedFile > SOURCECLIENTREASKF(((5)*60)*1000)) | |||
| 206 | ) || | |||
| 207 | // OR if file is not rare | |||
| 208 | ( (bNeverAskedBefore || nTimePassedClient > (unsigned)(SOURCECLIENTREASKS(((40)*60)*1000) * MINCOMMONPENALTY4)) | |||
| 209 | && (nTimePassedFile > (unsigned)(SOURCECLIENTREASKF(((5)*60)*1000) * MINCOMMONPENALTY4)) | |||
| 210 | ) | |||
| 211 | ) | |||
| 212 | ); | |||
| 213 | } | |||
| 214 | ||||
| 215 | ||||
| 216 | void CUpDownClient::SendFileRequest() | |||
| 217 | { | |||
| 218 | wxCHECK_RET(m_reqfile, wxT("Cannot request file when no reqfile is set"))if ( m_reqfile ) {} else { do { if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 218, __FUNCTION__, "\"m_reqfile\"" , L"Cannot request file when no reqfile is set"), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); return; } struct wxDummyCheckStruct218; | |||
| 219 | ||||
| 220 | CMemFile dataFileReq(16+16); | |||
| 221 | dataFileReq.WriteHash(m_reqfile->GetFileHash()); | |||
| 222 | ||||
| 223 | if (SupportMultiPacket()) { | |||
| 224 | DEBUG_ONLY( wxString sent_opcodes; ) | |||
| 225 | ||||
| 226 | if (SupportExtMultiPacket()) { | |||
| 227 | dataFileReq.WriteUInt64(m_reqfile->GetFileSize()); | |||
| 228 | } | |||
| 229 | ||||
| 230 | AddDebugLogLineN(logClient, wxT("Sending file request to client"))do {} while (false); | |||
| 231 | ||||
| 232 | dataFileReq.WriteUInt8(OP_REQUESTFILENAME); | |||
| 233 | DEBUG_ONLY( sent_opcodes += wxT("|RFNM|"); ) | |||
| 234 | // Extended information | |||
| 235 | if (GetExtendedRequestsVersion() > 0) { | |||
| 236 | m_reqfile->WritePartStatus(&dataFileReq); | |||
| 237 | } | |||
| 238 | if (GetExtendedRequestsVersion() > 1) { | |||
| 239 | m_reqfile->WriteCompleteSourcesCount(&dataFileReq); | |||
| 240 | } | |||
| 241 | if (m_reqfile->GetPartCount() > 1) { | |||
| 242 | DEBUG_ONLY( sent_opcodes += wxT("|RFID|"); ) | |||
| 243 | dataFileReq.WriteUInt8(OP_SETREQFILEID); | |||
| 244 | } | |||
| 245 | if (IsEmuleClient()) { | |||
| 246 | SetRemoteQueueFull( true ); | |||
| 247 | SetRemoteQueueRank(0); | |||
| 248 | } | |||
| 249 | if (IsSourceRequestAllowed()) { | |||
| 250 | if (SupportsSourceExchange2()){ | |||
| 251 | DEBUG_ONLY( sent_opcodes += wxT("|RSRC2|"); ) | |||
| 252 | dataFileReq.WriteUInt8(OP_REQUESTSOURCES2); | |||
| 253 | dataFileReq.WriteUInt8(SOURCEEXCHANGE2_VERSION4); | |||
| 254 | const uint16 nOptions = 0; // 16 ... Reserved | |||
| 255 | dataFileReq.WriteUInt16(nOptions); | |||
| 256 | } else { | |||
| 257 | DEBUG_ONLY( sent_opcodes += wxT("|RSRC|"); ) | |||
| 258 | dataFileReq.WriteUInt8(OP_REQUESTSOURCES); | |||
| 259 | } | |||
| 260 | m_reqfile->SetLastAnsweredTimeTimeout(); | |||
| 261 | SetLastAskedForSources(); | |||
| 262 | } | |||
| 263 | if (IsSupportingAICH()) { | |||
| 264 | DEBUG_ONLY( sent_opcodes += wxT("|AFHR|"); ) | |||
| 265 | dataFileReq.WriteUInt8(OP_AICHFILEHASHREQ); | |||
| 266 | } | |||
| 267 | CPacket* packet = new CPacket(dataFileReq, OP_EMULEPROT, (SupportExtMultiPacket() ? OP_MULTIPACKET_EXT : OP_MULTIPACKET)); | |||
| 268 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 269 | AddDebugLogLineN(logLocalClient, CFormat(wxT("Local Client: %s (%s) to %s"))do {} while (false) | |||
| 270 | % (SupportExtMultiPacket() ? wxT("OP_MULTIPACKET_EXT") : wxT("OP_MULTIPACKET")) % sent_opcodes % GetFullIP())do {} while (false); | |||
| 271 | SendPacket(packet, true); | |||
| 272 | } else { | |||
| 273 | //This is extended information | |||
| 274 | if (GetExtendedRequestsVersion() > 0 ) { | |||
| 275 | m_reqfile->WritePartStatus(&dataFileReq); | |||
| 276 | } | |||
| 277 | if (GetExtendedRequestsVersion() > 1 ) { | |||
| 278 | m_reqfile->WriteCompleteSourcesCount(&dataFileReq); | |||
| 279 | } | |||
| 280 | CPacket* packet = new CPacket(dataFileReq, OP_EDONKEYPROT, OP_REQUESTFILENAME); | |||
| 281 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 282 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQUESTFILENAME to ") + GetFullIP() )do {} while (false); | |||
| 283 | SendPacket(packet, true); | |||
| 284 | ||||
| 285 | // 26-Jul-2003: removed requesting the file status for files <= PARTSIZE for better compatibility with ed2k protocol (eDonkeyHybrid). | |||
| 286 | // if the remote client answers the OP_REQUESTFILENAME with OP_REQFILENAMEANSWER the file is shared by the remote client. if we | |||
| 287 | // know that the file is shared, we know also that the file is complete and don't need to request the file status. | |||
| 288 | ||||
| 289 | // Sending the packet could have deleted the client, check m_reqfile | |||
| 290 | if (m_reqfile && (m_reqfile->GetPartCount() > 1)) { | |||
| 291 | CMemFile dataSetReqFileID(16); | |||
| 292 | dataSetReqFileID.WriteHash(m_reqfile->GetFileHash()); | |||
| 293 | packet = new CPacket(dataSetReqFileID, OP_EDONKEYPROT, OP_SETREQFILEID); | |||
| 294 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 295 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_SETREQFILEID to ") + GetFullIP())do {} while (false); | |||
| 296 | SendPacket(packet, true); | |||
| 297 | } | |||
| 298 | ||||
| 299 | if (IsEmuleClient()) { | |||
| 300 | SetRemoteQueueFull( true ); | |||
| 301 | SetRemoteQueueRank(0); | |||
| 302 | } | |||
| 303 | ||||
| 304 | // Sending the packet could have deleted the client, check m_reqfile | |||
| 305 | if (m_reqfile && IsSourceRequestAllowed()) { | |||
| 306 | m_reqfile->SetLastAnsweredTimeTimeout(); | |||
| 307 | ||||
| 308 | CMemFile packetdata; | |||
| 309 | ||||
| 310 | if (SupportsSourceExchange2()) { | |||
| 311 | packetdata.WriteUInt8(SOURCEEXCHANGE2_VERSION4); | |||
| 312 | packetdata.WriteUInt16(0 /* Reserved */); | |||
| 313 | } | |||
| 314 | ||||
| 315 | packetdata.WriteHash(m_reqfile->GetFileHash()); | |||
| 316 | ||||
| 317 | packet = new CPacket(packetdata, OP_EMULEPROT, SupportsSourceExchange2() ? OP_REQUESTSOURCES2 : OP_REQUESTSOURCES); | |||
| 318 | ||||
| 319 | theStats::AddUpOverheadSourceExchange(packet->GetPacketSize()); | |||
| 320 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_REQUESTSOURCES to ") + GetFullIP() )do {} while (false); | |||
| 321 | SendPacket(packet,true,true); | |||
| 322 | SetLastAskedForSources(); | |||
| 323 | } | |||
| 324 | ||||
| 325 | // Sending the packet could have deleted the client, check m_reqfile | |||
| 326 | if (m_reqfile && IsSupportingAICH()) { | |||
| 327 | packet = new CPacket(OP_AICHFILEHASHREQ,16,OP_EMULEPROT); | |||
| 328 | packet->Copy16ToDataBuffer((const char *)m_reqfile->GetFileHash().GetHash()); | |||
| 329 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 330 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHFILEHASHREQ to ") + GetFullIP())do {} while (false); | |||
| 331 | SendPacket(packet,true,true); | |||
| 332 | } | |||
| 333 | } | |||
| 334 | } | |||
| 335 | ||||
| 336 | ||||
| 337 | void CUpDownClient::ProcessFileInfo(const CMemFile* data, const CPartFile* file) | |||
| 338 | { | |||
| 339 | // 0.42e | |||
| 340 | if (file==NULL__null) { | |||
| 341 | throw wxString(wxT("ERROR: Wrong file ID (ProcessFileInfo; file==NULL)")L"ERROR: Wrong file ID (ProcessFileInfo; file==NULL)"); | |||
| 342 | } | |||
| 343 | if (m_reqfile==NULL__null) { | |||
| 344 | throw wxString(wxT("ERROR: Wrong file ID (ProcessFileInfo; m_reqfile==NULL)")L"ERROR: Wrong file ID (ProcessFileInfo; m_reqfile==NULL)"); | |||
| 345 | } | |||
| 346 | if (file != m_reqfile) { | |||
| 347 | throw wxString(wxT("ERROR: Wrong file ID (ProcessFileInfo; m_reqfile!=file)")L"ERROR: Wrong file ID (ProcessFileInfo; m_reqfile!=file)"); | |||
| 348 | } | |||
| 349 | ||||
| 350 | m_clientFilename = data->ReadString((GetUnicodeSupport() != utf8strNone)); | |||
| 351 | ||||
| 352 | // 26-Jul-2003: removed requesting the file status for files <= PARTSIZE for better compatibility with ed2k protocol (eDonkeyHybrid). | |||
| 353 | // if the remote client answers the OP_REQUESTFILENAME with OP_REQFILENAMEANSWER the file is shared by the remote client. if we | |||
| 354 | // know that the file is shared, we know also that the file is complete and don't need to request the file status. | |||
| 355 | if (m_reqfile->GetPartCount() == 1) { | |||
| 356 | m_nPartCount = m_reqfile->GetPartCount(); | |||
| 357 | ||||
| 358 | m_reqfile->UpdatePartsFrequency( this, false ); // Decrement | |||
| 359 | m_downPartStatus.setsize( m_nPartCount, 1 ); | |||
| 360 | m_reqfile->UpdatePartsFrequency( this, true ); // Increment | |||
| 361 | ||||
| 362 | m_bCompleteSource = true; | |||
| 363 | ||||
| 364 | UpdateDisplayedInfo(); | |||
| 365 | // even if the file is <= PARTSIZE, we _may_ need the hashset for that file (if the file size == PARTSIZE) | |||
| 366 | if (m_reqfile->IsHashSetNeeded()) { | |||
| 367 | if (m_socket) { | |||
| 368 | CPacket* packet = new CPacket(OP_HASHSETREQUEST,16, OP_EDONKEYPROT); | |||
| 369 | packet->Copy16ToDataBuffer((const char *)m_reqfile->GetFileHash().GetHash()); | |||
| 370 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 371 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_HASHSETREQUEST to ") + GetFullIP())do {} while (false); | |||
| 372 | SendPacket(packet,true,true); | |||
| 373 | SetDownloadState(DS_REQHASHSET); | |||
| 374 | m_fHashsetRequesting = 1; | |||
| 375 | m_reqfile->SetHashSetNeeded(false); | |||
| 376 | } else { | |||
| 377 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp" , 377, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 378 | } | |||
| 379 | } else { | |||
| 380 | SendStartupLoadReq(); | |||
| 381 | } | |||
| 382 | m_reqfile->UpdatePartsInfo(); | |||
| 383 | } | |||
| 384 | } | |||
| 385 | ||||
| 386 | void CUpDownClient::ProcessFileStatus(bool bUdpPacket, const CMemFile* data, const CPartFile* file) | |||
| 387 | { | |||
| 388 | // 0.42e | |||
| 389 | wxString strReqFileNull(wxT("ERROR: Wrong file ID (ProcessFileStatus; m_reqfile==NULL)")L"ERROR: Wrong file ID (ProcessFileStatus; m_reqfile==NULL)"); | |||
| 390 | ||||
| 391 | if ( !m_reqfile || file != m_reqfile ){ | |||
| 392 | if (!m_reqfile) { | |||
| 393 | throw strReqFileNull; | |||
| 394 | } | |||
| 395 | throw wxString(wxT("ERROR: Wrong file ID (ProcessFileStatus; m_reqfile!=file)")L"ERROR: Wrong file ID (ProcessFileStatus; m_reqfile!=file)"); | |||
| 396 | } | |||
| 397 | ||||
| 398 | uint16 nED2KPartCount = data->ReadUInt16(); | |||
| 399 | ||||
| 400 | m_reqfile->UpdatePartsFrequency( this, false ); // Decrement | |||
| 401 | m_downPartStatus.clear(); | |||
| 402 | ||||
| 403 | bool bPartsNeeded = false; | |||
| 404 | if (!nED2KPartCount) | |||
| 405 | { | |||
| 406 | m_nPartCount = m_reqfile->GetPartCount(); | |||
| 407 | m_downPartStatus.setsize( m_nPartCount, 1); | |||
| 408 | bPartsNeeded = true; | |||
| 409 | m_bCompleteSource = true; | |||
| 410 | } | |||
| 411 | else | |||
| 412 | { | |||
| 413 | // Somehow this happened. | |||
| 414 | if (!m_reqfile) { | |||
| 415 | throw strReqFileNull; | |||
| 416 | } | |||
| 417 | if (m_reqfile->GetED2KPartCount() != nED2KPartCount) | |||
| 418 | { | |||
| 419 | wxString strError; | |||
| 420 | strError << wxT("ProcessFileStatus - wrong part number recv=")L"ProcessFileStatus - wrong part number recv=" << nED2KPartCount << | |||
| 421 | wxT(" expected=")L" expected=" << m_reqfile->GetED2KPartCount() << wxT(" ")L" " << | |||
| 422 | m_reqfile->GetFileHash().Encode(); | |||
| 423 | m_nPartCount = 0; | |||
| 424 | throw strError; | |||
| 425 | } | |||
| 426 | m_nPartCount = m_reqfile->GetPartCount(); | |||
| 427 | ||||
| 428 | m_bCompleteSource = false; | |||
| 429 | m_downPartStatus.setsize( m_nPartCount, 0 ); | |||
| 430 | uint16 done = 0; | |||
| 431 | ||||
| 432 | try { | |||
| 433 | while (done != m_nPartCount) { | |||
| 434 | uint8 toread = data->ReadUInt8(); | |||
| 435 | ||||
| 436 | for ( uint8 i = 0;i < 8; i++ ) { | |||
| 437 | bool status = ((toread>>i)&1)? 1:0; | |||
| 438 | m_downPartStatus.set(done, status); | |||
| 439 | ||||
| 440 | if (status) { | |||
| 441 | if (!m_reqfile->IsComplete(done)){ | |||
| 442 | bPartsNeeded = true; | |||
| 443 | } | |||
| 444 | } | |||
| 445 | done++; | |||
| 446 | if (done == m_nPartCount) { | |||
| 447 | break; | |||
| 448 | } | |||
| 449 | } | |||
| 450 | } | |||
| 451 | } catch( ... ) { | |||
| 452 | // We want the counts to be updated, even if we fail to read everything | |||
| 453 | m_reqfile->UpdatePartsFrequency( this, true ); // Increment | |||
| 454 | ||||
| 455 | throw; | |||
| 456 | } | |||
| 457 | } | |||
| 458 | ||||
| 459 | m_reqfile->UpdatePartsFrequency( this, true ); // Increment | |||
| 460 | ||||
| 461 | UpdateDisplayedInfo(); | |||
| 462 | ||||
| 463 | // NOTE: This function is invoked from TCP and UDP socket! | |||
| 464 | if (!bUdpPacket) { | |||
| 465 | if (!bPartsNeeded) { | |||
| 466 | SetDownloadState(DS_NONEEDEDPARTS); | |||
| 467 | } else if (m_reqfile->IsHashSetNeeded()) { | |||
| 468 | //If we are using the eMule filerequest packets, this is taken care of in the Multipacket! | |||
| 469 | if (m_socket) { | |||
| 470 | CPacket* packet = new CPacket(OP_HASHSETREQUEST,16, OP_EDONKEYPROT); | |||
| 471 | packet->Copy16ToDataBuffer((const char *)m_reqfile->GetFileHash().GetHash()); | |||
| 472 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 473 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_HASHSETREQUEST to ") + GetFullIP())do {} while (false); | |||
| 474 | SendPacket(packet, true, true); | |||
| 475 | SetDownloadState(DS_REQHASHSET); | |||
| 476 | m_fHashsetRequesting = 1; | |||
| 477 | m_reqfile->SetHashSetNeeded(false); | |||
| 478 | } else { | |||
| 479 | wxFAILdo { if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp" , 479, __FUNCTION__, "\"Assert failure\"", (const char*)__null ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 480 | } | |||
| 481 | } | |||
| 482 | else { | |||
| 483 | SendStartupLoadReq(); | |||
| 484 | } | |||
| 485 | } | |||
| 486 | else { | |||
| 487 | if (!bPartsNeeded) { | |||
| 488 | SetDownloadState(DS_NONEEDEDPARTS); | |||
| 489 | } else { | |||
| 490 | SetDownloadState(DS_ONQUEUE); | |||
| 491 | } | |||
| 492 | } | |||
| 493 | m_reqfile->UpdatePartsInfo(); | |||
| 494 | } | |||
| 495 | ||||
| 496 | bool CUpDownClient::AddRequestForAnotherFile(CPartFile* file) | |||
| 497 | { | |||
| 498 | if ( m_A4AF_list.find( file ) == m_A4AF_list.end() ) { | |||
| 499 | // When we access a non-existing entry entry, it will be zeroed by default, | |||
| 500 | // so we have to set NeededParts. All in one go. | |||
| 501 | m_A4AF_list[file].NeededParts = true; | |||
| 502 | file->AddA4AFSource( this ); | |||
| 503 | return true; | |||
| 504 | } else { | |||
| 505 | return false; | |||
| 506 | } | |||
| 507 | } | |||
| 508 | ||||
| 509 | bool CUpDownClient::DeleteFileRequest(CPartFile* file) | |||
| 510 | { | |||
| 511 | return (m_A4AF_list.erase( file ) > 0); | |||
| 512 | } | |||
| 513 | ||||
| 514 | void CUpDownClient::DeleteAllFileRequests() | |||
| 515 | { | |||
| 516 | m_A4AF_list.clear(); | |||
| 517 | } | |||
| 518 | ||||
| 519 | ||||
| 520 | /* eMule 0.30c implementation, i give it a try (Creteil) BEGIN ... */ | |||
| 521 | void CUpDownClient::SetDownloadState(uint8 byNewState) | |||
| 522 | { | |||
| 523 | if (m_nDownloadState != byNewState) { | |||
| 524 | if (m_reqfile) { | |||
| 525 | // Notify the client that this source has changed its state | |||
| 526 | m_reqfile->ClientStateChanged( m_nDownloadState, byNewState ); | |||
| 527 | ||||
| 528 | if (byNewState == DS_DOWNLOADING) { | |||
| 529 | m_reqfile->AddDownloadingSource(this); | |||
| 530 | } else if (m_nDownloadState == DS_DOWNLOADING) { | |||
| 531 | m_reqfile->RemoveDownloadingSource(this); | |||
| 532 | } | |||
| 533 | } | |||
| 534 | if (byNewState == DS_DOWNLOADING) { | |||
| 535 | msReceivedPrev = GetTickCount(); | |||
| 536 | theStats::AddDownloadingSource(); | |||
| 537 | } else if (m_nDownloadState == DS_DOWNLOADING) { | |||
| 538 | theStats::RemoveDownloadingSource(); | |||
| 539 | } | |||
| 540 | ||||
| 541 | if (m_nDownloadState == DS_DOWNLOADING) { | |||
| 542 | m_nDownloadState = byNewState; | |||
| 543 | ClearDownloadBlockRequests(); | |||
| 544 | ||||
| 545 | kBpsDown = 0.0; | |||
| 546 | bytesReceivedCycle = 0; | |||
| 547 | msReceivedPrev = 0; | |||
| 548 | if (byNewState == DS_NONE) { | |||
| 549 | if (m_reqfile) { | |||
| 550 | m_reqfile->UpdatePartsFrequency( this, false ); // Decrement | |||
| 551 | } | |||
| 552 | m_downPartStatus.clear(); | |||
| 553 | m_nPartCount = 0; | |||
| 554 | } | |||
| 555 | if (m_socket && byNewState != DS_ERROR) { | |||
| 556 | m_socket->DisableDownloadLimit(); | |||
| 557 | } | |||
| 558 | } | |||
| 559 | m_nDownloadState = byNewState; | |||
| 560 | if(GetDownloadState() == DS_DOWNLOADING) { | |||
| 561 | if (IsEmuleClient()) { | |||
| 562 | SetRemoteQueueFull(false); | |||
| 563 | } | |||
| 564 | SetRemoteQueueRank(0); // eMule 0.30c set like this ... | |||
| 565 | } | |||
| 566 | UpdateDisplayedInfo(true); | |||
| 567 | } | |||
| 568 | } | |||
| 569 | /* eMule 0.30c implementation, i give it a try (Creteil) END ... */ | |||
| 570 | ||||
| 571 | void CUpDownClient::ProcessHashSet(const uint8_t* packet, uint32 size) | |||
| 572 | { | |||
| 573 | if ((!m_reqfile) || md4cmp(packet,m_reqfile->GetFileHash().GetHash())) { | |||
| 574 | throw wxString(wxT("Wrong fileid sent (ProcessHashSet)")L"Wrong fileid sent (ProcessHashSet)"); | |||
| 575 | } | |||
| 576 | if (!m_fHashsetRequesting) { | |||
| 577 | throw wxString(wxT("Received unsolicited hashset, ignoring it.")L"Received unsolicited hashset, ignoring it."); | |||
| 578 | } | |||
| 579 | CMemFile data(packet,size); | |||
| 580 | if (m_reqfile->LoadHashsetFromFile(&data,true)) { | |||
| 581 | m_fHashsetRequesting = 0; | |||
| 582 | } else { | |||
| 583 | m_reqfile->SetHashSetNeeded(true); | |||
| 584 | throw wxString(wxT("Corrupted or invalid hashset received")L"Corrupted or invalid hashset received"); | |||
| 585 | } | |||
| 586 | SendStartupLoadReq(); | |||
| 587 | } | |||
| 588 | ||||
| 589 | void CUpDownClient::SendBlockRequests() | |||
| 590 | { | |||
| 591 | uint32 current_time = ::GetTickCount(); | |||
| 592 | if (GetVBTTags()) { | |||
| 593 | ||||
| 594 | // Ask new blocks only when all completed | |||
| 595 | if (!m_PendingBlocks_list.empty()) { | |||
| 596 | return; | |||
| 597 | } | |||
| 598 | ||||
| 599 | if ((m_dwLastBlockReceived + SEC2MS(5)((5)*1000)) > current_time) { | |||
| 600 | // We received last block in less than 5 secs? Let's request faster. | |||
| 601 | m_MaxBlockRequests = m_MaxBlockRequests << 1; | |||
| 602 | if ( m_MaxBlockRequests > 0x20) { | |||
| 603 | m_MaxBlockRequests = 0x20; | |||
| 604 | } | |||
| 605 | } else { | |||
| 606 | m_MaxBlockRequests = m_MaxBlockRequests >> 1; | |||
| 607 | if ( m_MaxBlockRequests < STANDARD_BLOCKS_REQUEST3) { | |||
| 608 | m_MaxBlockRequests = STANDARD_BLOCKS_REQUEST3; | |||
| 609 | } | |||
| 610 | } | |||
| 611 | } | |||
| 612 | ||||
| 613 | m_dwLastBlockReceived = current_time; | |||
| 614 | ||||
| 615 | if (!m_reqfile) { | |||
| 616 | return; | |||
| 617 | } | |||
| 618 | ||||
| 619 | if (m_DownloadBlocks_list.empty()) { | |||
| 620 | // Barry - instead of getting 3, just get how many is needed | |||
| 621 | uint16 count = m_MaxBlockRequests - m_PendingBlocks_list.size(); | |||
| 622 | std::vector<Requested_Block_Struct*> toadd; | |||
| 623 | if (m_reqfile->GetNextRequestedBlock(this, toadd, count)) { | |||
| 624 | for (int i = 0; i != count; i++) { | |||
| 625 | m_DownloadBlocks_list.push_back(toadd[i]); | |||
| 626 | } | |||
| 627 | } | |||
| 628 | } | |||
| 629 | ||||
| 630 | // Barry - Why are unfinished blocks requested again, not just new ones? | |||
| 631 | ||||
| 632 | while (m_PendingBlocks_list.size() < m_MaxBlockRequests && !m_DownloadBlocks_list.empty()) { | |||
| 633 | Pending_Block_Struct* pblock = new Pending_Block_Struct; | |||
| 634 | pblock->block = m_DownloadBlocks_list.front(); | |||
| 635 | pblock->zStream = NULL__null; | |||
| 636 | pblock->totalUnzipped = 0; | |||
| 637 | pblock->fZStreamError = 0; | |||
| 638 | pblock->fRecovered = 0; | |||
| 639 | m_PendingBlocks_list.push_back(pblock); | |||
| 640 | m_DownloadBlocks_list.pop_front(); | |||
| 641 | } | |||
| 642 | ||||
| 643 | ||||
| 644 | if (m_PendingBlocks_list.empty()) { | |||
| 645 | ||||
| 646 | CUpDownClient* slower_client = NULL__null; | |||
| 647 | ||||
| 648 | if (thePrefs::GetDropSlowSources()) { | |||
| 649 | slower_client = m_reqfile->GetSlowerDownloadingClient(m_lastaverage, this); | |||
| 650 | } | |||
| 651 | ||||
| 652 | if (slower_client == NULL__null) { | |||
| 653 | slower_client = this; | |||
| 654 | } | |||
| 655 | ||||
| 656 | if (!slower_client->GetSentCancelTransfer()) { | |||
| 657 | CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT); | |||
| 658 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 659 | // if (slower_client != this) { | |||
| 660 | // printf("Dropped client %p to allow client %p to download\n",slower_client, this); | |||
| 661 | // } | |||
| 662 | slower_client->ClearDownloadBlockRequests(); | |||
| 663 | slower_client->SendPacket(packet,true,true); | |||
| 664 | slower_client->SetSentCancelTransfer(1); | |||
| 665 | } | |||
| 666 | ||||
| 667 | slower_client->SetDownloadState(DS_NONEEDEDPARTS); | |||
| 668 | ||||
| 669 | if (slower_client != this) { | |||
| 670 | // Re-request freed blocks. | |||
| 671 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER (faster source eager to transfer) to ") + slower_client->GetFullIP() )do {} while (false); | |||
| 672 | wxASSERT(m_DownloadBlocks_list.empty())do { if ( m_DownloadBlocks_list.empty() ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 672, __FUNCTION__ , "m_DownloadBlocks_list.empty()", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 673 | wxASSERT(m_PendingBlocks_list.empty())do { if ( m_PendingBlocks_list.empty() ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 673, __FUNCTION__ , "m_PendingBlocks_list.empty()", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 674 | uint16 count = m_MaxBlockRequests; | |||
| 675 | std::vector<Requested_Block_Struct*> toadd; | |||
| 676 | if (m_reqfile->GetNextRequestedBlock(this, toadd, count)) { | |||
| 677 | for (int i = 0; i != count; i++) { | |||
| 678 | Pending_Block_Struct* pblock = new Pending_Block_Struct; | |||
| 679 | pblock->block = toadd[i]; | |||
| 680 | pblock->zStream = NULL__null; | |||
| 681 | pblock->totalUnzipped = 0; | |||
| 682 | pblock->fZStreamError = 0; | |||
| 683 | pblock->fRecovered = 0; | |||
| 684 | m_PendingBlocks_list.push_back(pblock); | |||
| 685 | } | |||
| 686 | } else { | |||
| 687 | // WTF, we just freed blocks. | |||
| 688 | wxFAIL_MSG(wxT("No free blocks to request after freeing some blocks"))do { if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp" , 688, __FUNCTION__, "\"Assert failure\"", L"No free blocks to request after freeing some blocks" ), wxTrapInAssert) ) { wxTrapInAssert = false; asm volatile ( "int $3"); } } while ( (void)0, 0 ); | |||
| 689 | return; | |||
| 690 | } | |||
| 691 | } else { | |||
| 692 | // Drop this one. | |||
| 693 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER (no free blocks) to ") + GetFullIP() )do {} while (false); | |||
| 694 | //#warning Kry - Would be nice to swap A4AF here. | |||
| 695 | return; | |||
| 696 | } | |||
| 697 | } | |||
| 698 | ||||
| 699 | CPacket* packet = NULL__null; | |||
| 700 | ||||
| 701 | if (GetVBTTags()) { | |||
| 702 | // ED2Kv2 packet... | |||
| 703 | // Most common scenario: hash + blocks to request + every one | |||
| 704 | // having 2 uint32 tags | |||
| 705 | ||||
| 706 | uint8 nBlocks = m_PendingBlocks_list.size(); | |||
| 707 | if (nBlocks > m_MaxBlockRequests) { | |||
| 708 | nBlocks = m_MaxBlockRequests; | |||
| 709 | } | |||
| 710 | ||||
| 711 | CMemFile data(16 + 1 + nBlocks*((2+4)*2)); | |||
| 712 | ||||
| 713 | data.WriteHash(m_reqfile->GetFileHash()); | |||
| 714 | ||||
| 715 | data.WriteUInt8(nBlocks); | |||
| 716 | ||||
| 717 | std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin(); | |||
| 718 | while (nBlocks) { | |||
| 719 | wxASSERT(it != m_PendingBlocks_list.end())do { if ( it != m_PendingBlocks_list.end() ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 719, __FUNCTION__ , "it != m_PendingBlocks_list.end()", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 720 | wxASSERT( (*it)->block->StartOffset <= (*it)->block->EndOffset )do { if ( (*it)->block->StartOffset <= (*it)->block ->EndOffset ) { } else if ( wxTheAssertHandler && ( wxOnAssert("DownloadClient.cpp", 720, __FUNCTION__, "(*it)->block->StartOffset <= (*it)->block->EndOffset" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 721 | (*it)->fZStreamError = 0; | |||
| 722 | (*it)->fRecovered = 0; | |||
| 723 | CTagVarInt(/*Noname*/0,(*it)->block->StartOffset).WriteTagToFile(&data); | |||
| 724 | CTagVarInt(/*Noname*/0,(*it)->block->EndOffset).WriteTagToFile(&data); | |||
| 725 | ++it; | |||
| 726 | nBlocks--; | |||
| 727 | } | |||
| 728 | ||||
| 729 | packet = new CPacket(data, OP_ED2KV2HEADER, OP_REQUESTPARTS); | |||
| 730 | AddDebugLogLineN( logLocalClient, CFormat(wxT("Local Client ED2Kv2: OP_REQUESTPARTS(%i) to %s"))do {} while (false) | |||
| 731 | % (m_PendingBlocks_list.size()<m_MaxBlockRequests ? m_PendingBlocks_list.size() : m_MaxBlockRequests) % GetFullIP() )do {} while (false); | |||
| 732 | ||||
| 733 | } else { | |||
| 734 | wxASSERT(m_MaxBlockRequests == STANDARD_BLOCKS_REQUEST)do { if ( m_MaxBlockRequests == 3 ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 734, __FUNCTION__ , "m_MaxBlockRequests == 3", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 735 | ||||
| 736 | //#warning Kry - I dont specially like this approach, we iterate one time too many | |||
| 737 | ||||
| 738 | bool bHasLongBlocks = false; | |||
| 739 | ||||
| 740 | std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin(); | |||
| 741 | for (uint32 i = 0; i != m_MaxBlockRequests; i++){ | |||
| 742 | if (it != m_PendingBlocks_list.end()) { | |||
| 743 | Pending_Block_Struct* pending = *it++; | |||
| 744 | wxASSERT( pending->block->StartOffset <= pending->block->EndOffset )do { if ( pending->block->StartOffset <= pending-> block->EndOffset ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 744, __FUNCTION__, "pending->block->StartOffset <= pending->block->EndOffset" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 745 | if (pending->block->StartOffset > 0xFFFFFFFF || pending->block->EndOffset > 0xFFFFFFFF){ | |||
| 746 | bHasLongBlocks = true; | |||
| 747 | if (!SupportsLargeFiles()){ | |||
| 748 | // Requesting a large block from a client that doesn't support large files? | |||
| 749 | if (!GetSentCancelTransfer()){ | |||
| 750 | CPacket* cancel_packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT); | |||
| 751 | theStats::AddUpOverheadFileRequest(cancel_packet->GetPacketSize()); | |||
| 752 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + GetFullIP() )do {} while (false); | |||
| 753 | SendPacket(cancel_packet,true,true); | |||
| 754 | SetSentCancelTransfer(1); | |||
| 755 | } | |||
| 756 | SetDownloadState(DS_ERROR); | |||
| 757 | return; | |||
| 758 | } | |||
| 759 | break; | |||
| 760 | } | |||
| 761 | } | |||
| 762 | } | |||
| 763 | ||||
| 764 | CMemFile data(16 /*Hash*/ + (m_MaxBlockRequests*(bHasLongBlocks ? 8 : 4) /* uint32/64 start*/) + (3*(bHasLongBlocks ? 8 : 4)/* uint32/64 end*/)); | |||
| 765 | data.WriteHash(m_reqfile->GetFileHash()); | |||
| 766 | ||||
| 767 | it = m_PendingBlocks_list.begin(); | |||
| 768 | for (uint32 i = 0; i != m_MaxBlockRequests; i++) { | |||
| 769 | if (it != m_PendingBlocks_list.end()) { | |||
| 770 | Pending_Block_Struct* pending = *it++; | |||
| 771 | wxASSERT( pending->block->StartOffset <= pending->block->EndOffset )do { if ( pending->block->StartOffset <= pending-> block->EndOffset ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 771, __FUNCTION__, "pending->block->StartOffset <= pending->block->EndOffset" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 772 | pending->fZStreamError = 0; | |||
| 773 | pending->fRecovered = 0; | |||
| 774 | if (bHasLongBlocks) { | |||
| 775 | data.WriteUInt64(pending->block->StartOffset); | |||
| 776 | } else { | |||
| 777 | data.WriteUInt32(pending->block->StartOffset); | |||
| 778 | } | |||
| 779 | } else { | |||
| 780 | if (bHasLongBlocks) { | |||
| 781 | data.WriteUInt64(0); | |||
| 782 | } else { | |||
| 783 | data.WriteUInt32(0); | |||
| 784 | } | |||
| 785 | } | |||
| 786 | } | |||
| 787 | ||||
| 788 | it = m_PendingBlocks_list.begin(); | |||
| 789 | for (uint32 i = 0; i != m_MaxBlockRequests; i++) { | |||
| 790 | if (it != m_PendingBlocks_list.end()) { | |||
| 791 | Requested_Block_Struct* block = (*it++)->block; | |||
| 792 | if (bHasLongBlocks) { | |||
| 793 | data.WriteUInt64(block->EndOffset+1); | |||
| 794 | } else { | |||
| 795 | data.WriteUInt32(block->EndOffset+1); | |||
| 796 | } | |||
| 797 | } else { | |||
| 798 | if (bHasLongBlocks) { | |||
| 799 | data.WriteUInt64(0); | |||
| 800 | } else { | |||
| 801 | data.WriteUInt32(0); | |||
| 802 | } | |||
| 803 | } | |||
| 804 | } | |||
| 805 | packet = new CPacket(data, (bHasLongBlocks ? OP_EMULEPROT : OP_EDONKEYPROT), (bHasLongBlocks ? (uint8)OP_REQUESTPARTS_I64 : (uint8)OP_REQUESTPARTS)); | |||
| 806 | AddDebugLogLineN(logLocalClient, CFormat(wxT("Local Client: %s to %s")) % (bHasLongBlocks ? wxT("OP_REQUESTPARTS_I64") : wxT("OP_REQUESTPARTS")) % GetFullIP())do {} while (false); | |||
| 807 | } | |||
| 808 | ||||
| 809 | if (packet) { | |||
| 810 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 811 | SendPacket(packet, true, true); | |||
| 812 | } | |||
| 813 | } | |||
| 814 | ||||
| 815 | /* | |||
| 816 | Barry - Originally this only wrote to disk when a full 180k block | |||
| 817 | had been received from a client, and only asked for data in | |||
| 818 | 180k blocks. | |||
| 819 | ||||
| 820 | This meant that on average 90k was lost for every connection | |||
| 821 | to a client data source. That is a lot of wasted data. | |||
| 822 | ||||
| 823 | To reduce the lost data, packets are now written to a buffer | |||
| 824 | and flushed to disk regularly regardless of size downloaded. | |||
| 825 | ||||
| 826 | This includes compressed packets. | |||
| 827 | ||||
| 828 | Data is also requested only where gaps are, not in 180k blocks. | |||
| 829 | The requests will still not exceed 180k, but may be smaller to | |||
| 830 | fill a gap. | |||
| 831 | */ | |||
| 832 | ||||
| 833 | void CUpDownClient::ProcessBlockPacket(const uint8_t* packet, uint32 size, bool packed, bool largeblocks) | |||
| 834 | { | |||
| 835 | // Ignore if no data required | |||
| 836 | if (!(GetDownloadState() == DS_DOWNLOADING || GetDownloadState() == DS_NONEEDEDPARTS)) { | |||
| ||||
| 837 | return; | |||
| 838 | } | |||
| 839 | ||||
| 840 | // This vars are defined here to be able to use them on the catch | |||
| 841 | int header_size = 16; | |||
| 842 | uint64 nStartPos = 0; | |||
| 843 | uint64 nEndPos = 0; | |||
| 844 | uint32 nBlockSize = 0; | |||
| 845 | uint32 lenUnzipped = 0; | |||
| 846 | ||||
| 847 | // Update stats | |||
| 848 | m_dwLastBlockReceived = ::GetTickCount(); | |||
| 849 | ||||
| 850 | try { | |||
| 851 | ||||
| 852 | // Read data from packet | |||
| 853 | const CMemFile data(packet, size); | |||
| 854 | ||||
| 855 | // Check that this data is for the correct file | |||
| 856 | if ((!m_reqfile) || data.ReadHash() != m_reqfile->GetFileHash()) { | |||
| 857 | throw wxString(wxT("Wrong fileid sent (ProcessBlockPacket)")L"Wrong fileid sent (ProcessBlockPacket)"); | |||
| 858 | } | |||
| 859 | ||||
| 860 | // Find the start & end positions, and size of this chunk of data | |||
| 861 | ||||
| 862 | if (largeblocks) { | |||
| 863 | nStartPos = data.ReadUInt64(); | |||
| 864 | header_size += 8; | |||
| 865 | } else { | |||
| 866 | nStartPos = data.ReadUInt32(); | |||
| 867 | header_size += 4; | |||
| 868 | } | |||
| 869 | ||||
| 870 | if (packed) { | |||
| 871 | nBlockSize = data.ReadUInt32(); | |||
| 872 | header_size += 4; | |||
| 873 | nEndPos = nStartPos + (size - header_size); | |||
| 874 | } else { | |||
| 875 | if (largeblocks) { | |||
| 876 | nEndPos = data.ReadUInt64(); | |||
| 877 | header_size += 8; | |||
| 878 | } else { | |||
| 879 | nEndPos = data.ReadUInt32(); | |||
| 880 | header_size += 4; | |||
| 881 | } | |||
| 882 | } | |||
| 883 | ||||
| 884 | // Check that packet size matches the declared data size + header size | |||
| 885 | if ( nEndPos == nStartPos || size != ((nEndPos - nStartPos) + header_size)) { | |||
| 886 | throw wxString(wxT("Corrupted or invalid DataBlock received (ProcessBlockPacket)")L"Corrupted or invalid DataBlock received (ProcessBlockPacket)"); | |||
| 887 | } | |||
| 888 | theStats::AddDownloadFromSoft(GetClientSoft(),size - header_size); | |||
| 889 | bytesReceivedCycle += size - header_size; | |||
| 890 | ||||
| 891 | credits->AddDownloaded(size - header_size, GetIP(), theApp->CryptoAvailable()); | |||
| 892 | ||||
| 893 | // Move end back one, should be inclusive | |||
| 894 | nEndPos--; | |||
| 895 | ||||
| 896 | // Loop through to find the reserved block that this is within | |||
| 897 | std::list<Pending_Block_Struct*>::iterator it = m_PendingBlocks_list.begin(); | |||
| 898 | for (; it != m_PendingBlocks_list.end(); ++it) { | |||
| 899 | Pending_Block_Struct* cur_block = *it; | |||
| 900 | ||||
| 901 | if ((cur_block->block->StartOffset <= nStartPos) && (cur_block->block->EndOffset >= nStartPos)) { | |||
| 902 | // Found reserved block | |||
| 903 | ||||
| 904 | if (cur_block->block->StartOffset == nStartPos) { | |||
| 905 | // This block just started transferring. Set the start time. | |||
| 906 | m_last_block_start = ::GetTickCountFullRes(); | |||
| 907 | } | |||
| 908 | ||||
| 909 | if (cur_block->fZStreamError){ | |||
| 910 | AddDebugLogLineN(logZLib,do {} while (false) | |||
| 911 | CFormat(wxT("Ignoring %u bytes of block %u-%u because of erroneous zstream state for file: %s"))do {} while (false) | |||
| 912 | % (size - header_size) % nStartPos % nEndPos % m_reqfile->GetFileName())do {} while (false); | |||
| 913 | m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset); | |||
| 914 | return; | |||
| 915 | } | |||
| 916 | ||||
| 917 | // Remember this start pos, used to draw part downloading in list | |||
| 918 | m_lastDownloadingPart = nStartPos / PARTSIZE; | |||
| 919 | ||||
| 920 | // Occasionally packets are duplicated, no point writing it twice | |||
| 921 | // This will be 0 in these cases, or the length written otherwise | |||
| 922 | uint32 lenWritten = 0; | |||
| 923 | ||||
| 924 | // Handle differently depending on whether packed or not | |||
| 925 | if (!packed
| |||
| 926 | // security sanitize check | |||
| 927 | if (nEndPos > cur_block->block->EndOffset) { | |||
| 928 | AddDebugLogLineN(logRemoteClient, CFormat(wxT("Received Blockpacket exceeds requested boundaries (requested end: %u, Part: %u, received end: %u, Part: %u), file: %s remote IP: %s")) % cur_block->block->EndOffset % (uint32)(cur_block->block->EndOffset / PARTSIZE) % nEndPos % (uint32)(nEndPos / PARTSIZE) % m_reqfile->GetFileName() % Uint32toStringIP(GetIP()))do {} while (false); | |||
| 929 | m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset); | |||
| 930 | return; | |||
| 931 | } | |||
| 932 | // Write to disk (will be buffered in part file class) | |||
| 933 | lenWritten = m_reqfile->WriteToBuffer( size - header_size, (uint8_t*)(packet + header_size), nStartPos, nEndPos, cur_block->block, this); | |||
| 934 | } else { | |||
| 935 | // Packed | |||
| 936 | wxASSERT( (long int)size > 0 )do { if ( (long int)size > 0 ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 936, __FUNCTION__ , "(long int)size > 0", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 937 | // Create space to store unzipped data, the size is | |||
| 938 | // only an initial guess, will be resized in unzip() | |||
| 939 | // if not big enough | |||
| 940 | lenUnzipped = (size * 2); | |||
| 941 | // Don't get too big | |||
| 942 | if (lenUnzipped > (BLOCKSIZE + 300)) { | |||
| 943 | lenUnzipped = (BLOCKSIZE + 300); | |||
| 944 | } | |||
| 945 | uint8_t *unzipped = new uint8_t[lenUnzipped]; | |||
| 946 | ||||
| 947 | // Try to unzip the packet | |||
| 948 | int result = unzip(cur_block, (uint8_t*)(packet + header_size), (size - header_size), &unzipped, &lenUnzipped); | |||
| 949 | ||||
| 950 | // no block can be uncompressed to >2GB, 'lenUnzipped' is obviously erroneous. | |||
| 951 | if (result == Z_OK0 && ((int)lenUnzipped >= 0)) { | |||
| 952 | ||||
| 953 | // Write any unzipped data to disk | |||
| 954 | if (lenUnzipped > 0) { | |||
| 955 | wxASSERT( (int)lenUnzipped > 0 )do { if ( (int)lenUnzipped > 0 ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 955, __FUNCTION__ , "(int)lenUnzipped > 0", (const char*)__null), wxTrapInAssert ) ) { wxTrapInAssert = false; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 956 | ||||
| 957 | // Use the current start and end positions for the uncompressed data | |||
| 958 | nStartPos = cur_block->block->StartOffset + cur_block->totalUnzipped - lenUnzipped; | |||
| 959 | nEndPos = cur_block->block->StartOffset + cur_block->totalUnzipped - 1; | |||
| 960 | ||||
| 961 | if (nStartPos > cur_block->block->EndOffset || nEndPos > cur_block->block->EndOffset) { | |||
| 962 | AddDebugLogLineN(logZLib,do {} while (false) | |||
| 963 | CFormat(wxT("Corrupted compressed packet for '%s' received (error 666)")) % m_reqfile->GetFileName())do {} while (false); | |||
| 964 | m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset); | |||
| 965 | } else { | |||
| 966 | // Write uncompressed data to file | |||
| 967 | lenWritten = m_reqfile->WriteToBuffer( size - header_size, | |||
| 968 | unzipped, | |||
| 969 | nStartPos, | |||
| 970 | nEndPos, | |||
| 971 | cur_block->block, | |||
| 972 | this); | |||
| 973 | } | |||
| 974 | } | |||
| 975 | } else { | |||
| 976 | wxString strZipError; | |||
| 977 | if (cur_block->zStream && cur_block->zStream->msg) { | |||
| 978 | strZipError = wxT(" - ")L" - " + wxString::FromAscii(cur_block->zStream->msg); | |||
| 979 | } | |||
| 980 | ||||
| 981 | AddDebugLogLineN(logZLib,do {} while (false) | |||
| 982 | CFormat(wxT("Corrupted compressed packet for '%s' received (error %i): %s"))do {} while (false) | |||
| 983 | % m_reqfile->GetFileName() % result % strZipError)do {} while (false); | |||
| 984 | ||||
| 985 | m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset); | |||
| 986 | ||||
| 987 | // If we had an zstream error, there is no chance that we could recover from it nor that we | |||
| 988 | // could use the current zstream (which is in error state) any longer. | |||
| 989 | if (cur_block->zStream){ | |||
| 990 | inflateEnd(cur_block->zStream); | |||
| 991 | delete cur_block->zStream; | |||
| 992 | cur_block->zStream = NULL__null; | |||
| 993 | } | |||
| 994 | ||||
| 995 | // Although we can't further use the current zstream, there is no need to disconnect the sending | |||
| 996 | // client because the next zstream (a series of 10K-blocks which build a 180K-block) could be | |||
| 997 | // valid again. Just ignore all further blocks for the current zstream. | |||
| 998 | cur_block->fZStreamError = 1; | |||
| 999 | cur_block->totalUnzipped = 0; // bluecow's fix | |||
| 1000 | } | |||
| 1001 | delete [] unzipped; | |||
| 1002 | } | |||
| 1003 | // These checks only need to be done if any data was written | |||
| 1004 | if (lenWritten > 0) { | |||
| 1005 | m_nTransferredDown += lenWritten; | |||
| 1006 | ||||
| 1007 | // If finished reserved block | |||
| 1008 | if (nEndPos == cur_block->block->EndOffset) { | |||
| 1009 | ||||
| 1010 | // Save last average speed based on data and time. | |||
| 1011 | // This should do bytes/sec. | |||
| 1012 | uint32 average_time = (::GetTickCountFullRes() - m_last_block_start); | |||
| 1013 | ||||
| 1014 | // Avoid divide by 0. | |||
| 1015 | if (average_time == 0) { | |||
| 1016 | average_time++; | |||
| 1017 | } | |||
| 1018 | ||||
| 1019 | m_lastaverage = ((cur_block->block->EndOffset - cur_block->block->StartOffset) * 1000) / average_time; | |||
| 1020 | ||||
| 1021 | m_reqfile->RemoveBlockFromList(cur_block->block->StartOffset, cur_block->block->EndOffset); | |||
| 1022 | delete cur_block->block; | |||
| 1023 | // Not always allocated | |||
| 1024 | if (cur_block->zStream) { | |||
| 1025 | inflateEnd(cur_block->zStream); | |||
| 1026 | delete cur_block->zStream; | |||
| 1027 | } | |||
| 1028 | delete cur_block; | |||
| 1029 | m_PendingBlocks_list.erase(it); | |||
| 1030 | ||||
| 1031 | // Request next block | |||
| 1032 | SendBlockRequests(); | |||
| 1033 | } | |||
| 1034 | } | |||
| 1035 | // Stop looping and exit method | |||
| 1036 | return; | |||
| 1037 | } | |||
| 1038 | } | |||
| 1039 | } catch (const CEOFException& e) { | |||
| 1040 | wxString error = wxString(wxT("Error reading ")L"Error reading "); | |||
| 1041 | if (packed) error += CFormat(wxT("packed (LU: %i) largeblocks ")L"packed (LU: %i) largeblocks ") % lenUnzipped; | |||
| 1042 | error += CFormat(wxT("data packet: RS: %i HS: %i SP: %i EP: %i BS: %i -> ")L"data packet: RS: %i HS: %i SP: %i EP: %i BS: %i -> ") | |||
| 1043 | % size % header_size % nStartPos % nEndPos % nBlockSize; | |||
| 1044 | AddDebugLogLineC(logRemoteClient, error + e.what())theLogger.AddLogLine(L"DownloadClient.cpp", 1044, true, logRemoteClient , error + e.what()); | |||
| 1045 | return; | |||
| 1046 | } | |||
| 1047 | } | |||
| 1048 | ||||
| 1049 | int CUpDownClient::unzip(Pending_Block_Struct *block, uint8_t *zipped, uint32 lenZipped, uint8_t **unzipped, uint32 *lenUnzipped, int iRecursion) | |||
| 1050 | { | |||
| 1051 | int err = Z_DATA_ERROR(-3); | |||
| 1052 | ||||
| 1053 | // Save some typing | |||
| 1054 | z_stream *zS = block->zStream; | |||
| 1055 | ||||
| 1056 | // Is this the first time this block has been unzipped | |||
| 1057 | if (zS == NULL__null) { | |||
| 1058 | // Create stream | |||
| 1059 | block->zStream = new z_stream; | |||
| 1060 | zS = block->zStream; | |||
| 1061 | ||||
| 1062 | // Initialise stream values | |||
| 1063 | zS->zalloc = (alloc_func)0; | |||
| 1064 | zS->zfree = (free_func)0; | |||
| 1065 | zS->opaque = (voidpf)0; | |||
| 1066 | ||||
| 1067 | // Set output data streams, do this here to avoid overwriting on recursive calls | |||
| 1068 | zS->next_out = (*unzipped); | |||
| 1069 | zS->avail_out = (*lenUnzipped); | |||
| 1070 | ||||
| 1071 | // Initialise the z_stream | |||
| 1072 | err = inflateInit(zS)inflateInit_((zS), "1.3.1", (int)sizeof(z_stream)); | |||
| 1073 | if (err != Z_OK0) { | |||
| 1074 | return err; | |||
| 1075 | } | |||
| 1076 | } | |||
| 1077 | ||||
| 1078 | // Use whatever input is provided | |||
| 1079 | zS->next_in = zipped; | |||
| 1080 | zS->avail_in = lenZipped; | |||
| 1081 | ||||
| 1082 | // Only set the output if not being called recursively | |||
| 1083 | if (iRecursion
| |||
| 1084 | zS->next_out = (*unzipped); | |||
| 1085 | zS->avail_out = (*lenUnzipped); | |||
| 1086 | } | |||
| 1087 | ||||
| 1088 | // Try to unzip the data | |||
| 1089 | err = inflate(zS, Z_SYNC_FLUSH2); | |||
| 1090 | ||||
| 1091 | // Is zip finished reading all currently available input and writing | |||
| 1092 | // all generated output | |||
| 1093 | if (err == Z_STREAM_END1) { | |||
| 1094 | // Finish up | |||
| 1095 | err = inflateEnd(zS); | |||
| 1096 | if (err != Z_OK0) { | |||
| 1097 | return err; | |||
| 1098 | } | |||
| 1099 | ||||
| 1100 | // Got a good result, set the size to the amount unzipped in this call | |||
| 1101 | // (including all recursive calls) | |||
| 1102 | (*lenUnzipped) = (zS->total_out - block->totalUnzipped); | |||
| 1103 | block->totalUnzipped = zS->total_out; | |||
| 1104 | } else if ((err == Z_OK0) && (zS->avail_out == 0) && (zS->avail_in != 0)) { | |||
| 1105 | ||||
| 1106 | // Output array was not big enough, | |||
| 1107 | // call recursively until there is enough space | |||
| 1108 | ||||
| 1109 | // What size should we try next | |||
| 1110 | uint32 newLength = (*lenUnzipped) *= 2; | |||
| 1111 | if (newLength
| |||
| 1112 | newLength = lenZipped * 2; | |||
| 1113 | } | |||
| 1114 | // Copy any data that was successfully unzipped to new array | |||
| 1115 | uint8_t *temp = new uint8_t[newLength]; | |||
| 1116 | wxASSERT( zS->total_out - block->totalUnzipped <= newLength )do { if ( zS->total_out - block->totalUnzipped <= newLength ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp" , 1116, __FUNCTION__, "zS->total_out - block->totalUnzipped <= newLength" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 1117 | memcpy(temp, (*unzipped), (zS->total_out - block->totalUnzipped)); | |||
| ||||
| 1118 | delete [] (*unzipped); | |||
| 1119 | (*unzipped) = temp; | |||
| 1120 | (*lenUnzipped) = newLength; | |||
| 1121 | ||||
| 1122 | // Position stream output to correct place in new array | |||
| 1123 | zS->next_out = (*unzipped) + (zS->total_out - block->totalUnzipped); | |||
| 1124 | zS->avail_out = (*lenUnzipped) - (zS->total_out - block->totalUnzipped); | |||
| 1125 | ||||
| 1126 | // Try again | |||
| 1127 | err = unzip(block, zS->next_in, zS->avail_in, unzipped, lenUnzipped, iRecursion + 1); | |||
| 1128 | } else if ((err == Z_OK0) && (zS->avail_in == 0)) { | |||
| 1129 | // All available input has been processed, everything ok. | |||
| 1130 | // Set the size to the amount unzipped in this call | |||
| 1131 | // (including all recursive calls) | |||
| 1132 | (*lenUnzipped) = (zS->total_out - block->totalUnzipped); | |||
| 1133 | block->totalUnzipped = zS->total_out; | |||
| 1134 | } else { | |||
| 1135 | // Should not get here unless input data is corrupt | |||
| 1136 | wxString strZipError; | |||
| 1137 | ||||
| 1138 | if ( zS->msg ) { | |||
| 1139 | strZipError = CFormat(wxT(" %d '%s'")L" %d '%s'") % err % wxString::FromAscii(zS->msg); | |||
| 1140 | } else if (err != Z_OK0) { | |||
| 1141 | strZipError = CFormat(wxT(" %d")L" %d") % err; | |||
| 1142 | } | |||
| 1143 | ||||
| 1144 | AddDebugLogLineN(logZLib,do {} while (false) | |||
| 1145 | CFormat(wxT("Unexpected zip error %s in file '%s'"))do {} while (false) | |||
| 1146 | % strZipError % (m_reqfile ? m_reqfile->GetFileName() : CPath(wxT("?"))))do {} while (false); | |||
| 1147 | } | |||
| 1148 | ||||
| 1149 | if (err != Z_OK0) { | |||
| 1150 | (*lenUnzipped) = 0; | |||
| 1151 | } | |||
| 1152 | ||||
| 1153 | return err; | |||
| 1154 | } | |||
| 1155 | ||||
| 1156 | ||||
| 1157 | // Speed is now updated only when data was received, calculated as | |||
| 1158 | // (data received) / (time since last reception) | |||
| 1159 | // and slightly filtered (10s average). | |||
| 1160 | // Result is quite precise now and makes the DownloadRateAdjust workaround obsolete. | |||
| 1161 | ||||
| 1162 | float CUpDownClient::CalculateKBpsDown() | |||
| 1163 | { | |||
| 1164 | const float tAverage = 10.0; | |||
| 1165 | uint32 msCur = GetTickCount(); | |||
| 1166 | ||||
| 1167 | if (bytesReceivedCycle) { | |||
| 1168 | float dt = (msCur - msReceivedPrev) / 1000.0; // time since last reception | |||
| 1169 | if (dt < 0.01) { // (safeguard against divide-by-zero) | |||
| 1170 | dt = 0.01f; // diff should be 100ms actually | |||
| 1171 | } | |||
| 1172 | float kBpsDownCur = bytesReceivedCycle / 1024.0 / dt; | |||
| 1173 | if (dt >= tAverage) { | |||
| 1174 | kBpsDown = kBpsDownCur; | |||
| 1175 | } else { | |||
| 1176 | kBpsDown = (kBpsDown * (tAverage - dt) + kBpsDownCur * dt) / tAverage; | |||
| 1177 | } | |||
| 1178 | //AddDebugLogLineN(logLocalClient, CFormat(wxT("CalculateKBpsDown %p kbps %.1f kbpsCur %.1f dt %.3f rcv %d ")) | |||
| 1179 | // % this % kBpsDown % kBpsDownCur % dt % bytesReceivedCycle); | |||
| 1180 | bytesReceivedCycle = 0; | |||
| 1181 | msReceivedPrev = msCur; | |||
| 1182 | } | |||
| 1183 | ||||
| 1184 | m_cShowDR++; | |||
| 1185 | if (m_cShowDR == 30){ | |||
| 1186 | m_cShowDR = 0; | |||
| 1187 | UpdateDisplayedInfo(); | |||
| 1188 | } | |||
| 1189 | if (msCur - m_dwLastBlockReceived > DOWNLOADTIMEOUT100000) { | |||
| 1190 | if (!GetSentCancelTransfer()){ | |||
| 1191 | CPacket* packet = new CPacket(OP_CANCELTRANSFER, 0, OP_EDONKEYPROT); | |||
| 1192 | theStats::AddUpOverheadFileRequest(packet->GetPacketSize()); | |||
| 1193 | AddDebugLogLineN( logLocalClient, wxT("Local Client: OP_CANCELTRANSFER to ") + GetFullIP() )do {} while (false); | |||
| 1194 | SendPacket(packet,true,true); | |||
| 1195 | SetSentCancelTransfer(1); | |||
| 1196 | } | |||
| 1197 | SetDownloadState(DS_ONQUEUE); | |||
| 1198 | } | |||
| 1199 | ||||
| 1200 | return kBpsDown; | |||
| 1201 | } | |||
| 1202 | ||||
| 1203 | uint16 CUpDownClient::GetAvailablePartCount() const | |||
| 1204 | { | |||
| 1205 | uint16 result = 0; | |||
| 1206 | for (int i = 0;i != m_nPartCount;i++){ | |||
| 1207 | if (IsPartAvailable(i)) | |||
| 1208 | result++; | |||
| 1209 | } | |||
| 1210 | return result; | |||
| 1211 | } | |||
| 1212 | ||||
| 1213 | void CUpDownClient::SetRemoteQueueRank(uint16 nr) | |||
| 1214 | { | |||
| 1215 | m_nOldRemoteQueueRank = m_nRemoteQueueRank; | |||
| 1216 | m_nRemoteQueueRank = nr; | |||
| 1217 | UpdateDisplayedInfo(); | |||
| 1218 | } | |||
| 1219 | ||||
| 1220 | void CUpDownClient::UDPReaskACK(uint16 nNewQR) | |||
| 1221 | { | |||
| 1222 | // 0.42e | |||
| 1223 | m_bUDPPending = false; | |||
| 1224 | SetRemoteQueueRank(nNewQR); | |||
| 1225 | m_dwLastAskedTime = ::GetTickCount(); | |||
| 1226 | } | |||
| 1227 | ||||
| 1228 | void CUpDownClient::UDPReaskFNF() | |||
| 1229 | { | |||
| 1230 | m_bUDPPending = false; | |||
| 1231 | ||||
| 1232 | // avoid premature deletion of 'this' client | |||
| 1233 | if (GetDownloadState() != DS_DOWNLOADING){ | |||
| 1234 | if (m_reqfile) { | |||
| 1235 | m_reqfile->AddDeadSource(this); | |||
| 1236 | } | |||
| 1237 | ||||
| 1238 | theApp->downloadqueue->RemoveSource(this); | |||
| 1239 | if (!m_socket) { | |||
| 1240 | if (Disconnected(wxT("UDPReaskFNF m_socket=NULL")L"UDPReaskFNF m_socket=NULL")) { | |||
| 1241 | Safe_Delete(); | |||
| 1242 | } | |||
| 1243 | } | |||
| 1244 | } else { | |||
| 1245 | AddDebugLogLineN( logRemoteClient, wxT("UDP ANSWER FNF : ") + GetUserName() + wxT(" - did not remove client because of current download state") )do {} while (false); | |||
| 1246 | } | |||
| 1247 | } | |||
| 1248 | ||||
| 1249 | void CUpDownClient::UDPReaskForDownload() | |||
| 1250 | { | |||
| 1251 | ||||
| 1252 | wxASSERT(m_reqfile)do { if ( m_reqfile ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp", 1252, __FUNCTION__, "m_reqfile" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 1253 | ||||
| 1254 | if(!m_reqfile || m_bUDPPending ) { | |||
| 1255 | return; | |||
| 1256 | } | |||
| 1257 | ||||
| 1258 | //#warning We should implement the quality tests for udp reliability | |||
| 1259 | /* | |||
| 1260 | if( m_nTotalUDPPackets > 3 && ((float)(m_nFailedUDPPackets/m_nTotalUDPPackets) > .3)) { | |||
| 1261 | return; | |||
| 1262 | } | |||
| 1263 | */ | |||
| 1264 | ||||
| 1265 | if (thePrefs::GetEffectiveUDPPort() == 0) { | |||
| 1266 | return; | |||
| 1267 | } | |||
| 1268 | ||||
| 1269 | if (m_nUDPPort != 0 && !theApp->IsFirewalled() && !IsConnected()) { | |||
| 1270 | //don't use udp to ask for sources | |||
| 1271 | if(IsSourceRequestAllowed()) { | |||
| 1272 | return; | |||
| 1273 | } | |||
| 1274 | ||||
| 1275 | m_bUDPPending = true; | |||
| 1276 | ||||
| 1277 | CMemFile data(128); | |||
| 1278 | data.WriteHash(m_reqfile->GetFileHash()); | |||
| 1279 | ||||
| 1280 | if (GetUDPVersion() > 3) { | |||
| 1281 | if (m_reqfile->IsPartFile()) { | |||
| 1282 | static_cast<CPartFile*>(m_reqfile)->WritePartStatus(&data); | |||
| 1283 | } | |||
| 1284 | else { | |||
| 1285 | data.WriteUInt16(0); | |||
| 1286 | } | |||
| 1287 | } | |||
| 1288 | ||||
| 1289 | if (GetUDPVersion() > 2) { | |||
| 1290 | data.WriteUInt16(m_reqfile->m_nCompleteSourcesCount); | |||
| 1291 | } | |||
| 1292 | ||||
| 1293 | CPacket* response = new CPacket(data, OP_EMULEPROT, OP_REASKFILEPING); | |||
| 1294 | AddDebugLogLineN( logClientUDP, wxT("Client UDP socket: send OP_REASKFILEPING") )do {} while (false); | |||
| 1295 | theStats::AddUpOverheadFileRequest(response->GetPacketSize()); | |||
| 1296 | theApp->clientudp->SendPacket(response,GetConnectIP(),GetUDPPort(), ShouldReceiveCryptUDPPackets(), GetUserHash().GetHash(), false, 0); | |||
| 1297 | } else if (HasLowID() && GetBuddyIP() && GetBuddyPort() && HasValidBuddyID()) { | |||
| 1298 | ||||
| 1299 | m_bUDPPending = true; | |||
| 1300 | ||||
| 1301 | CMemFile data(128); | |||
| 1302 | ||||
| 1303 | data.WriteHash(CMD4Hash(GetBuddyID())); | |||
| 1304 | data.WriteHash(m_reqfile->GetFileHash()); | |||
| 1305 | ||||
| 1306 | if (GetUDPVersion() > 3) { | |||
| 1307 | if (m_reqfile->IsPartFile()) { | |||
| 1308 | static_cast<CPartFile*>(m_reqfile)->WritePartStatus(&data); | |||
| 1309 | } else { | |||
| 1310 | data.WriteUInt16(0); | |||
| 1311 | } | |||
| 1312 | } | |||
| 1313 | ||||
| 1314 | if (GetUDPVersion() > 2) { | |||
| 1315 | data.WriteUInt16(m_reqfile->m_nCompleteSourcesCount); | |||
| 1316 | } | |||
| 1317 | ||||
| 1318 | CPacket* response = new CPacket(data, OP_EMULEPROT, OP_REASKCALLBACKUDP); | |||
| 1319 | AddDebugLogLineN( logClientUDP, wxT("Client UDP socket: send OP_REASKCALLBACKUDP") )do {} while (false); | |||
| 1320 | theStats::AddUpOverheadFileRequest(response->GetPacketSize()); | |||
| 1321 | theApp->clientudp->SendPacket(response, GetBuddyIP(), GetBuddyPort(), false, NULL__null, true, 0 ); | |||
| 1322 | } | |||
| 1323 | } | |||
| 1324 | ||||
| 1325 | ||||
| 1326 | // Get the next part that is requested | |||
| 1327 | uint16 CUpDownClient::GetNextRequestedPart() const | |||
| 1328 | { | |||
| 1329 | uint16 part = 0xffff; | |||
| 1330 | ||||
| 1331 | std::list<Pending_Block_Struct*>::const_iterator it = m_PendingBlocks_list.begin(); | |||
| 1332 | for (; it != m_PendingBlocks_list.end(); ++it) { | |||
| 1333 | part = (*it)->block->StartOffset / PARTSIZE; | |||
| 1334 | if (part != m_lastDownloadingPart) { | |||
| 1335 | break; | |||
| 1336 | } | |||
| 1337 | } | |||
| 1338 | ||||
| 1339 | return part; | |||
| 1340 | } | |||
| 1341 | ||||
| 1342 | ||||
| 1343 | void CUpDownClient::UpdateDisplayedInfo(bool force) | |||
| 1344 | { | |||
| 1345 | uint32 curTick = ::GetTickCount(); | |||
| 1346 | if (force || curTick-m_lastRefreshedDLDisplay > MINWAIT_BEFORE_DLDISPLAY_WINDOWUPDATE1500) { | |||
| 1347 | // Check if we actually need to notify of changes | |||
| 1348 | bool update = m_reqfile && m_reqfile->ShowSources(); | |||
| 1349 | ||||
| 1350 | // Check A4AF files only if needed | |||
| 1351 | if ( !update ) { | |||
| 1352 | A4AFList::iterator it = m_A4AF_list.begin(); | |||
| 1353 | for ( ; it != m_A4AF_list.end(); ++it ) { | |||
| 1354 | if ( it->first->ShowSources() ) { | |||
| 1355 | update = true; | |||
| 1356 | break; | |||
| 1357 | } | |||
| 1358 | } | |||
| 1359 | } | |||
| 1360 | ||||
| 1361 | // And finnaly trigger an event if there's any reason | |||
| 1362 | if ( update ) { | |||
| 1363 | SourceItemType type; | |||
| 1364 | switch (GetDownloadState()) { | |||
| 1365 | case DS_DOWNLOADING: | |||
| 1366 | case DS_ONQUEUE: | |||
| 1367 | // We will send A4AF, which will be checked. | |||
| 1368 | type = A4AF_SOURCE; | |||
| 1369 | break; | |||
| 1370 | default: | |||
| 1371 | type = UNAVAILABLE_SOURCE; | |||
| 1372 | break; | |||
| 1373 | } | |||
| 1374 | ||||
| 1375 | Notify_SourceCtrlUpdateSource(ECID(), type )MuleNotify::DoNotify(&MuleNotify::SourceCtrlUpdateSource, ECID(), type); | |||
| 1376 | } | |||
| 1377 | ||||
| 1378 | // Shared files view | |||
| 1379 | if (m_uploadingfile && m_uploadingfile->ShowPeers()) { | |||
| 1380 | Notify_SharedCtrlRefreshClient(ECID(), AVAILABLE_SOURCE)MuleNotify::DoNotify(&MuleNotify::SharedCtrlRefreshClient , ECID(), AVAILABLE_SOURCE); | |||
| 1381 | } | |||
| 1382 | ||||
| 1383 | m_lastRefreshedDLDisplay = curTick; | |||
| 1384 | } | |||
| 1385 | } | |||
| 1386 | ||||
| 1387 | uint8 CUpDownClient::GetObfuscationStatus() const | |||
| 1388 | { | |||
| 1389 | uint8 ret = OBST_UNDEFINED; | |||
| 1390 | if (thePrefs::IsClientCryptLayerSupported()) { | |||
| 1391 | if (SupportsCryptLayer()) { | |||
| 1392 | if ((RequestsCryptLayer() || thePrefs::IsClientCryptLayerRequested()) && HasObfuscatedConnectionBeenEstablished()) { | |||
| 1393 | ret = OBST_ENABLED; | |||
| 1394 | } else { | |||
| 1395 | ret = OBST_SUPPORTED; | |||
| 1396 | } | |||
| 1397 | } else { | |||
| 1398 | ret = OBST_NOT_SUPPORTED; | |||
| 1399 | } | |||
| 1400 | } else { | |||
| 1401 | ret = OBST_DISABLED; | |||
| 1402 | } | |||
| 1403 | return ret; | |||
| 1404 | } | |||
| 1405 | ||||
| 1406 | // IgnoreNoNeeded = will switch to files of which this source has no needed parts (if no better files found) | |||
| 1407 | // ignoreSuspensions = ignore timelimit for A4Af jumping | |||
| 1408 | // bRemoveCompletely = do not readd the file which the source is swapped from to the A4AF lists (needed if deleting or stopping a file) | |||
| 1409 | // toFile = Try to swap to this partfile only | |||
| 1410 | ||||
| 1411 | bool CUpDownClient::SwapToAnotherFile(bool bIgnoreNoNeeded, bool ignoreSuspensions, bool bRemoveCompletely, CPartFile* toFile) | |||
| 1412 | { | |||
| 1413 | // Fail if m_reqfile is invalid | |||
| 1414 | if ( m_reqfile == NULL__null ) { | |||
| 1415 | return false; | |||
| 1416 | } | |||
| 1417 | ||||
| 1418 | // It would be stupid to swap away a downloading source | |||
| 1419 | if (GetDownloadState() == DS_DOWNLOADING) { | |||
| 1420 | return false; | |||
| 1421 | } | |||
| 1422 | ||||
| 1423 | // The iterator of the final target | |||
| 1424 | A4AFList::iterator target = m_A4AF_list.end(); | |||
| 1425 | ||||
| 1426 | // Do we want to swap to a specific file? | |||
| 1427 | if ( toFile != NULL__null ) { | |||
| 1428 | A4AFList::iterator it = m_A4AF_list.find( toFile ); | |||
| 1429 | if ( it != m_A4AF_list.end() ) { | |||
| 1430 | ||||
| 1431 | // We force ignoring of timestamps | |||
| 1432 | if ( IsValidSwapTarget( it, bIgnoreNoNeeded, true ) ) { | |||
| 1433 | // Set the target | |||
| 1434 | target = it; | |||
| 1435 | } | |||
| 1436 | } | |||
| 1437 | } else { | |||
| 1438 | // We want highest priority possible, but need to start with | |||
| 1439 | // a value less than any other priority | |||
| 1440 | char priority = -1; | |||
| 1441 | ||||
| 1442 | A4AFList::iterator it = m_A4AF_list.begin(); | |||
| 1443 | for ( ; it != m_A4AF_list.end(); ++it ) { | |||
| 1444 | if ( IsValidSwapTarget( it, bIgnoreNoNeeded, ignoreSuspensions ) ) { | |||
| 1445 | char cur_priority = it->first->GetDownPriority(); | |||
| 1446 | ||||
| 1447 | // We would prefer to get files with needed parts, thus rate them higher. | |||
| 1448 | // However, this really only matters if bIgnoreNoNeeded is true. | |||
| 1449 | if ( it->second.NeededParts ) | |||
| 1450 | cur_priority += 10; | |||
| 1451 | ||||
| 1452 | // Change target if the current file has a higher rate than the previous | |||
| 1453 | if ( cur_priority > priority ) { | |||
| 1454 | priority = cur_priority; | |||
| 1455 | ||||
| 1456 | // Set the new target | |||
| 1457 | target = it; | |||
| 1458 | ||||
| 1459 | // Break on the first High-priority file with needed parts | |||
| 1460 | if ( priority == PR_HIGH2 + 10 ) { | |||
| 1461 | break; | |||
| 1462 | } | |||
| 1463 | } | |||
| 1464 | } | |||
| 1465 | } | |||
| 1466 | } | |||
| 1467 | ||||
| 1468 | // Try to swap if we found a valid target | |||
| 1469 | if ( target != m_A4AF_list.end() ) { | |||
| 1470 | ||||
| 1471 | // Sanity check, if reqfile doesn't own the source, then something | |||
| 1472 | // is wrong and the swap cannot proceed. | |||
| 1473 | if ( m_reqfile->DelSource( this ) ) { | |||
| 1474 | CPartFile* SwapTo = target->first; | |||
| 1475 | ||||
| 1476 | // remove this client from the A4AF list of our new m_reqfile | |||
| 1477 | if ( SwapTo->RemoveA4AFSource( this ) ) { | |||
| 1478 | Notify_SourceCtrlRemoveSource(ECID(), SwapTo)MuleNotify::DoNotify(&MuleNotify::SourceCtrlRemoveSource, ECID(), SwapTo); | |||
| 1479 | } | |||
| 1480 | ||||
| 1481 | m_reqfile->RemoveDownloadingSource( this ); | |||
| 1482 | ||||
| 1483 | // Do we want to remove it completely? Say if the old file is getting deleted | |||
| 1484 | if ( !bRemoveCompletely ) { | |||
| 1485 | m_reqfile->AddA4AFSource( this ); | |||
| 1486 | ||||
| 1487 | // Set the status of the old file | |||
| 1488 | m_A4AF_list[m_reqfile].NeededParts = (GetDownloadState() != DS_NONEEDEDPARTS); | |||
| 1489 | ||||
| 1490 | // Avoid swapping to this file for a while | |||
| 1491 | m_A4AF_list[m_reqfile].timestamp = ::GetTickCount(); | |||
| 1492 | ||||
| 1493 | Notify_SourceCtrlAddSource(m_reqfile, CCLIENTREF(this, wxT("CUpDownClient::SwapToAnotherFile Notify_SourceCtrlAddSource 1")), A4AF_SOURCE)MuleNotify::DoNotify(&MuleNotify::SourceCtrlAddSource, m_reqfile , CClientRef(this), A4AF_SOURCE); | |||
| 1494 | } else { | |||
| 1495 | Notify_SourceCtrlRemoveSource(ECID(), m_reqfile)MuleNotify::DoNotify(&MuleNotify::SourceCtrlRemoveSource, ECID(), m_reqfile); | |||
| 1496 | } | |||
| 1497 | ||||
| 1498 | SetDownloadState(DS_NONE); | |||
| 1499 | ResetFileStatusInfo(); | |||
| 1500 | ||||
| 1501 | m_nRemoteQueueRank = 0; | |||
| 1502 | m_nOldRemoteQueueRank = 0; | |||
| 1503 | ||||
| 1504 | m_reqfile->UpdatePartsInfo(); | |||
| 1505 | ||||
| 1506 | SetRequestFile( SwapTo ); | |||
| 1507 | ||||
| 1508 | SwapTo->AddSource( this ); | |||
| 1509 | ||||
| 1510 | Notify_SourceCtrlAddSource(SwapTo, CCLIENTREF(this, wxT("CUpDownClient::SwapToAnotherFile Notify_SourceCtrlAddSource 2")), UNAVAILABLE_SOURCE)MuleNotify::DoNotify(&MuleNotify::SourceCtrlAddSource, SwapTo , CClientRef(this), UNAVAILABLE_SOURCE); | |||
| 1511 | ||||
| 1512 | // Remove the new reqfile from the list of other files | |||
| 1513 | m_A4AF_list.erase( target ); | |||
| 1514 | ||||
| 1515 | return true; | |||
| 1516 | } | |||
| 1517 | } | |||
| 1518 | ||||
| 1519 | return false; | |||
| 1520 | } | |||
| 1521 | ||||
| 1522 | ||||
| 1523 | bool CUpDownClient::IsValidSwapTarget( A4AFList::iterator it, bool ignorenoneeded, bool ignoresuspended ) | |||
| 1524 | { | |||
| 1525 | wxASSERT( it != m_A4AF_list.end() && it->first )do { if ( it != m_A4AF_list.end() && it->first ) { } else if ( wxTheAssertHandler && (wxOnAssert("DownloadClient.cpp" , 1525, __FUNCTION__, "it != m_A4AF_list.end() && it->first" , (const char*)__null), wxTrapInAssert) ) { wxTrapInAssert = false ; asm volatile ("int $3"); } } while ( (void)0, 0 ); | |||
| 1526 | ||||
| 1527 | // Check if this file has been suspended | |||
| 1528 | if ( !ignoresuspended ) { | |||
| 1529 | if ( ::GetTickCount() - it->second.timestamp >= PURGESOURCESWAPSTOP(((15)*60)*1000) ) { | |||
| 1530 | // The wait-time has been exceeded and the file is now a valid target | |||
| 1531 | it->second.timestamp = 0; | |||
| 1532 | } else { | |||
| 1533 | // The file was still suspended and we are not ignoring suspensions | |||
| 1534 | return false; | |||
| 1535 | } | |||
| 1536 | } | |||
| 1537 | ||||
| 1538 | // Check if the client has needed parts | |||
| 1539 | if ( !ignorenoneeded ) { | |||
| 1540 | if ( !it->second.NeededParts ) { | |||
| 1541 | return false; | |||
| 1542 | } | |||
| 1543 | } | |||
| 1544 | ||||
| 1545 | // Final checks to see if the client is a valid target | |||
| 1546 | CPartFile* cur_file = it->first; | |||
| 1547 | if ( ( cur_file != m_reqfile && !cur_file->IsStopped() ) && | |||
| 1548 | ( cur_file->GetStatus() == PS_READY0 || cur_file->GetStatus() == PS_EMPTY1 ) && | |||
| 1549 | ( cur_file->IsPartFile() ) ) | |||
| 1550 | { | |||
| 1551 | return true; | |||
| 1552 | } else { | |||
| 1553 | return false; | |||
| 1554 | } | |||
| 1555 | } | |||
| 1556 | ||||
| 1557 | ||||
| 1558 | void CUpDownClient::SetRequestFile(CPartFile* reqfile) | |||
| 1559 | { | |||
| 1560 | if ( m_reqfile != reqfile ) { | |||
| 1561 | // Decrement the source-count of the old request-file | |||
| 1562 | if ( m_reqfile ) { | |||
| 1563 | m_reqfile->ClientStateChanged( GetDownloadState(), -1 ); | |||
| 1564 | m_reqfile->UpdatePartsFrequency( this, false ); | |||
| 1565 | } | |||
| 1566 | ||||
| 1567 | m_nPartCount = 0; | |||
| 1568 | m_downPartStatus.clear(); | |||
| 1569 | ||||
| 1570 | m_reqfile = reqfile; | |||
| 1571 | ||||
| 1572 | if ( reqfile ) { | |||
| 1573 | // Increment the source-count of the new request-file | |||
| 1574 | m_reqfile->ClientStateChanged( -1, GetDownloadState() ); | |||
| 1575 | ||||
| 1576 | m_nPartCount = reqfile->GetPartCount(); | |||
| 1577 | } | |||
| 1578 | } | |||
| 1579 | } | |||
| 1580 | ||||
| 1581 | void CUpDownClient::SetReqFileAICHHash(CAICHHash* val){ | |||
| 1582 | if(m_pReqFileAICHHash != NULL__null && m_pReqFileAICHHash != val) | |||
| 1583 | delete m_pReqFileAICHHash; | |||
| 1584 | m_pReqFileAICHHash = val; | |||
| 1585 | } | |||
| 1586 | ||||
| 1587 | void CUpDownClient::SendAICHRequest(CPartFile* pForFile, uint16 nPart){ | |||
| 1588 | CAICHRequestedData request; | |||
| 1589 | request.m_nPart = nPart; | |||
| 1590 | request.m_pClient.Link(this CLIENT_DEBUGSTRING("CUpDownClient::SendAICHRequest")); | |||
| 1591 | request.m_pPartFile = pForFile; | |||
| 1592 | CAICHHashSet::m_liRequestedData.push_back(request); | |||
| 1593 | m_fAICHRequested = TRUE1; | |||
| 1594 | CMemFile data; | |||
| 1595 | data.WriteHash(pForFile->GetFileHash()); | |||
| 1596 | data.WriteUInt16(nPart); | |||
| 1597 | pForFile->GetAICHHashset()->GetMasterHash().Write(&data); | |||
| 1598 | CPacket* packet = new CPacket(data, OP_EMULEPROT, OP_AICHREQUEST); | |||
| 1599 | theStats::AddUpOverheadOther(packet->GetPacketSize()); | |||
| 1600 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHREQUEST to") + GetFullIP())do {} while (false); | |||
| 1601 | SafeSendPacket(packet); | |||
| 1602 | } | |||
| 1603 | ||||
| 1604 | void CUpDownClient::ProcessAICHAnswer(const uint8_t* packet, uint32 size) | |||
| 1605 | { | |||
| 1606 | if (m_fAICHRequested == FALSE0){ | |||
| 1607 | throw wxString(wxT("Received unrequested AICH Packet")L"Received unrequested AICH Packet"); | |||
| 1608 | } | |||
| 1609 | m_fAICHRequested = FALSE0; | |||
| 1610 | ||||
| 1611 | CMemFile data(packet, size); | |||
| 1612 | if (size <= 16){ | |||
| 1613 | CAICHHashSet::ClientAICHRequestFailed(this); | |||
| 1614 | return; | |||
| 1615 | } | |||
| 1616 | ||||
| 1617 | CMD4Hash hash = data.ReadHash(); | |||
| 1618 | CPartFile* pPartFile = theApp->downloadqueue->GetFileByID(hash); | |||
| 1619 | CAICHRequestedData request = CAICHHashSet::GetAICHReqDetails(this); | |||
| 1620 | uint16 nPart = data.ReadUInt16(); | |||
| 1621 | if (pPartFile != NULL__null && request.m_pPartFile == pPartFile && request.m_pClient.GetClient() == this && nPart == request.m_nPart){ | |||
| 1622 | CAICHHash ahMasterHash(&data); | |||
| 1623 | if ( (pPartFile->GetAICHHashset()->GetStatus() == AICH_TRUSTED || pPartFile->GetAICHHashset()->GetStatus() == AICH_VERIFIED) | |||
| 1624 | && ahMasterHash == pPartFile->GetAICHHashset()->GetMasterHash()) | |||
| 1625 | { | |||
| 1626 | if(pPartFile->GetAICHHashset()->ReadRecoveryData(request.m_nPart*PARTSIZE, &data)){ | |||
| 1627 | // finally all checks passed, everything seems to be fine | |||
| 1628 | AddDebugLogLineN(logAICHTransfer, wxT("AICH Packet Answer: Succeeded to read and validate received recoverydata"))do {} while (false); | |||
| 1629 | CAICHHashSet::RemoveClientAICHRequest(this); | |||
| 1630 | pPartFile->AICHRecoveryDataAvailable(request.m_nPart); | |||
| 1631 | return; | |||
| 1632 | } else { | |||
| 1633 | AddDebugLogLineN(logAICHTransfer, wxT("AICH Packet Answer: Succeeded to read and validate received recoverydata"))do {} while (false); | |||
| 1634 | } | |||
| 1635 | } else { | |||
| 1636 | AddDebugLogLineN( logAICHTransfer, wxT("AICH Packet Answer: Masterhash differs from packethash or hashset has no trusted Masterhash") )do {} while (false); | |||
| 1637 | } | |||
| 1638 | } else { | |||
| 1639 | AddDebugLogLineN( logAICHTransfer, wxT("AICH Packet Answer: requested values differ from values in packet") )do {} while (false); | |||
| 1640 | } | |||
| 1641 | ||||
| 1642 | CAICHHashSet::ClientAICHRequestFailed(this); | |||
| 1643 | } | |||
| 1644 | ||||
| 1645 | ||||
| 1646 | void CUpDownClient::ProcessAICHRequest(const uint8_t* packet, uint32 size) | |||
| 1647 | { | |||
| 1648 | if (size != 16 + 2 + CAICHHash::GetHashSize()) { | |||
| 1649 | throw wxString(wxT("Received AICH Request Packet with wrong size")L"Received AICH Request Packet with wrong size"); | |||
| 1650 | } | |||
| 1651 | ||||
| 1652 | CMemFile data(packet, size); | |||
| 1653 | ||||
| 1654 | CMD4Hash hash = data.ReadHash(); | |||
| 1655 | uint16 nPart = data.ReadUInt16(); | |||
| 1656 | CAICHHash ahMasterHash(&data); | |||
| 1657 | CKnownFile* pKnownFile = theApp->sharedfiles->GetFileByID(hash); | |||
| 1658 | if (pKnownFile != NULL__null){ | |||
| 1659 | if (pKnownFile->GetAICHHashset()->GetStatus() == AICH_HASHSETCOMPLETE && pKnownFile->GetAICHHashset()->HasValidMasterHash() | |||
| 1660 | && pKnownFile->GetAICHHashset()->GetMasterHash() == ahMasterHash && pKnownFile->GetPartCount() > nPart | |||
| 1661 | && pKnownFile->GetFileSize() > EMBLOCKSIZE && pKnownFile->GetFileSize() - PARTSIZE*nPart > EMBLOCKSIZE) | |||
| 1662 | { | |||
| 1663 | CMemFile fileResponse; | |||
| 1664 | fileResponse.WriteHash(pKnownFile->GetFileHash()); | |||
| 1665 | fileResponse.WriteUInt16(nPart); | |||
| 1666 | pKnownFile->GetAICHHashset()->GetMasterHash().Write(&fileResponse); | |||
| 1667 | if (pKnownFile->GetAICHHashset()->CreatePartRecoveryData(nPart*PARTSIZE, &fileResponse)){ | |||
| 1668 | AddDebugLogLineN(logAICHTransfer,do {} while (false) | |||
| 1669 | CFormat(wxT("AICH Packet Request: Successfully created and send recoverydata for '%s' to %s"))do {} while (false) | |||
| 1670 | % pKnownFile->GetFileName() % GetClientFullInfo())do {} while (false); | |||
| 1671 | ||||
| 1672 | CPacket* packAnswer = new CPacket(fileResponse, OP_EMULEPROT, OP_AICHANSWER); | |||
| 1673 | theStats::AddUpOverheadOther(packAnswer->GetPacketSize()); | |||
| 1674 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHANSWER to") + GetFullIP())do {} while (false); | |||
| 1675 | SafeSendPacket(packAnswer); | |||
| 1676 | return; | |||
| 1677 | } else { | |||
| 1678 | AddDebugLogLineN(logAICHTransfer,do {} while (false) | |||
| 1679 | CFormat(wxT("AICH Packet Request: Failed to create recoverydata for '%s' to %s"))do {} while (false) | |||
| 1680 | % pKnownFile->GetFileName() % GetClientFullInfo())do {} while (false); | |||
| 1681 | } | |||
| 1682 | } else { | |||
| 1683 | AddDebugLogLineN(logAICHTransfer,do {} while (false) | |||
| 1684 | CFormat(wxT("AICH Packet Request: Failed to create recoverydata - Hashset not ready or requested Hash differs from Masterhash for '%s' to %s"))do {} while (false) | |||
| 1685 | % pKnownFile->GetFileName() % GetClientFullInfo())do {} while (false); | |||
| 1686 | } | |||
| 1687 | } else { | |||
| 1688 | AddDebugLogLineN( logAICHTransfer, wxT("AICH Packet Request: Failed to find requested shared file - ") + GetClientFullInfo() )do {} while (false); | |||
| 1689 | } | |||
| 1690 | ||||
| 1691 | CPacket* packAnswer = new CPacket(OP_AICHANSWER, 16, OP_EMULEPROT); | |||
| 1692 | packAnswer->Copy16ToDataBuffer(hash.GetHash()); | |||
| 1693 | theStats::AddUpOverheadOther(packAnswer->GetPacketSize()); | |||
| 1694 | AddDebugLogLineN(logLocalClient, wxT("Local Client: OP_AICHANSWER to") + GetFullIP())do {} while (false); | |||
| 1695 | SafeSendPacket(packAnswer); | |||
| 1696 | } | |||
| 1697 | ||||
| 1698 | void CUpDownClient::ProcessAICHFileHash(CMemFile* data, const CPartFile* file){ | |||
| 1699 | CPartFile* pPartFile; | |||
| 1700 | if (file == NULL__null){ | |||
| 1701 | pPartFile = theApp->downloadqueue->GetFileByID(data->ReadHash()); | |||
| 1702 | } else { | |||
| 1703 | pPartFile = const_cast<CPartFile*>(file); | |||
| 1704 | } | |||
| 1705 | CAICHHash ahMasterHash(data); | |||
| 1706 | ||||
| 1707 | if(pPartFile != NULL__null && pPartFile == GetRequestFile()){ | |||
| 1708 | SetReqFileAICHHash(new CAICHHash(ahMasterHash)); | |||
| 1709 | pPartFile->GetAICHHashset()->UntrustedHashReceived(ahMasterHash, GetConnectIP()); | |||
| 1710 | } else { | |||
| 1711 | AddDebugLogLineN( logAICHTransfer, wxT("ProcessAICHFileHash(): PartFile not found or Partfile differs from requested file, ") + GetClientFullInfo() )do {} while (false); | |||
| 1712 | } | |||
| 1713 | } | |||
| 1714 | // File_checked_for_headers |