void DownloadManager::on(UserConnectionListener::FileNotAvailable, UserConnection* aSource) throw() { Download* d = aSource->getDownload(); dcassert(d != NULL); if(d->isSet(Download::FLAG_TREE_DOWNLOAD)) { // No tree, too bad... aSource->setDownload(d->getOldDownload()); delete d->getFile(); d->setFile(NULL); delete d; checkDownloads(aSource); return; } dcdebug("File Not Available: %s\n", d->getTarget().c_str()); if(d->getFile()) { delete d->getFile(); d->setFile(NULL); d->setCrcCalc(NULL); } fire(DownloadManagerListener::Failed(), d, d->getTargetFileName() + ": " + STRING(FILE_NOT_AVAILABLE)); aSource->setDownload(NULL); QueueManager::getInstance()->removeSource(d->getTarget(), aSource->getUser(), QueueItem::Source::FLAG_FILE_NOT_AVAILABLE, false); removeDownload(d, false, false); checkDownloads(aSource); }
/** Download finished! */ void DownloadManager::endData(UserConnection* aSource) { dcassert(aSource->getState() == UserConnection::STATE_RUNNING); Download* d = aSource->getDownload(); dcassert(d != NULL); if(d->getType() == Transfer::TYPE_TREE) { d->getFile()->flush(); int64_t bl = 1024; while(bl * (int64_t)d->getTigerTree().getLeaves().size() < d->getTigerTree().getFileSize()) bl *= 2; d->getTigerTree().setBlockSize(bl); d->getTigerTree().calcRoot(); if(!(d->getTTH() == d->getTigerTree().getRoot())) { // This tree is for a different file, remove from queue... removeDownload(d); fire(DownloadManagerListener::Failed(), d, _("Full tree does not match TTH root")); QueueManager::getInstance()->removeSource(d->getPath(), aSource->getUser(), QueueItem::Source::FLAG_BAD_TREE, false); QueueManager::getInstance()->putDownload(d, false); checkDownloads(aSource); return; } d->setTreeValid(true); } else { // First, finish writing the file (flushing the buffers and closing the file...) try { d->getFile()->flush(); } catch(const Exception& e) { d->resetPos(); failDownload(aSource, e.getError()); return; } aSource->setSpeed(d->getAverageSpeed()); aSource->updateChunkSize(d->getTigerTree().getBlockSize(), d->getSize(), GET_TICK() - d->getStart()); dcdebug("Download finished: %s, size " I64_FMT ", downloaded " I64_FMT "\n", d->getPath().c_str(), static_cast<long long int>(d->getSize()), static_cast<long long int>(d->getPos())); if(BOOLSETTING(LOG_DOWNLOADS) && (BOOLSETTING(LOG_FILELIST_TRANSFERS) || d->getType() == Transfer::TYPE_FILE)) { logDownload(aSource, d); } } removeDownload(d); fire(DownloadManagerListener::Complete(), d); QueueManager::getInstance()->putDownload(d, true); checkDownloads(aSource); }
void DownloadManager::on(UserConnectionListener::Updated, UserConnection* aSource) noexcept { { Lock l(cs); UserConnectionList::iterator i = find(idlers.begin(), idlers.end(), aSource); if(i == idlers.end()) return; idlers.erase(i); } checkDownloads(aSource); }
void DownloadManager::addConnection(UserConnectionPtr conn) { if(!conn->isSet(UserConnection::FLAG_SUPPORTS_TTHF) || !conn->isSet(UserConnection::FLAG_SUPPORTS_ADCGET)) { // Can't download from these... conn->getUser()->setFlag(User::OLD_CLIENT); QueueManager::getInstance()->removeSource(conn->getUser(), QueueItem::Source::FLAG_NO_TTHF); conn->disconnect(); return; } if (BOOLSETTING(IPFILTER) && !ipfilter::getInstance()->OK(conn->getRemoteIp(),eDIRECTION_IN)) { conn->error("Your IP is Blocked!"); LogManager::getInstance()->message(_("IPFilter: Blocked outgoing connection to ") + conn->getRemoteIp()); QueueManager::getInstance()->removeSource(conn->getUser(), QueueItem::Source::FLAG_REMOVED); removeConnection(conn); return; } conn->addListener(this); checkDownloads(conn); }
void DownloadManager::fileNotAvailable(UserConnection* aSource) { if(aSource->getState() != UserConnection::STATE_SND) { dcdebug("DM::fileNotAvailable Invalid state, disconnecting"); aSource->disconnect(); return; } Download* d = aSource->getDownload(); dcassert(d != NULL); dcdebug("File Not Available: %s\n", d->getPath().c_str()); removeDownload(d); fire(DownloadManagerListener::Failed(), d, str(F_("%1%: File not available") % d->getTargetFileName())); QueueManager::getInstance()->removeSource(d->getPath(), aSource->getUser(), d->getType() == Transfer::TYPE_TREE ? QueueItem::Source::FLAG_NO_TREE : QueueItem::Source::FLAG_FILE_NOT_AVAILABLE, false); QueueManager::getInstance()->putDownload(d, false); checkDownloads(aSource); }
/** Download finished! */ void DownloadManager::handleEndData(UserConnection* aSource) { dcassert(aSource->getState() == UserConnection::STATE_DONE); Download* d = aSource->getDownload(); dcassert(d != NULL); if(d->isSet(Download::FLAG_TREE_DOWNLOAD)) { d->getFile()->flush(); delete d->getFile(); d->setFile(NULL); Download* old = d->getOldDownload(); size_t bl = 1024; while(bl * old->getTigerTree().getLeaves().size() < old->getSize()) bl *= 2; old->getTigerTree().setBlockSize(bl); dcassert(old->getSize() != -1); old->getTigerTree().setFileSize(old->getSize()); old->getTigerTree().calcRoot(); if(!(*old->getTTH() == old->getTigerTree().getRoot())) { // This tree is for a different file, remove from queue... fire(DownloadManagerListener::Failed(), old, STRING(INVALID_TREE)); string target = old->getTarget(); aSource->setDownload(NULL); removeDownload(old, true); QueueManager::getInstance()->removeSource(target, aSource->getUser(), QueueItem::Source::FLAG_BAD_TREE, false); checkDownloads(aSource); return; } d->getOldDownload()->setTreeValid(true); HashManager::getInstance()->addTree(old->getTarget(), old->getTigerTree()); aSource->setDownload(d->getOldDownload()); delete d; // Ok, now we can continue to the actual file... checkDownloads(aSource); return; } u_int32_t crc = 0; bool hasCrc = (d->getCrcCalc() != NULL); // First, finish writing the file (flushing the buffers and closing the file...) try { d->getFile()->flush(); if(hasCrc) crc = d->getCrcCalc()->getFilter().getValue(); delete d->getFile(); d->setFile(NULL); d->setCrcCalc(NULL); // Check if we're anti-fragging... if(d->isSet(Download::FLAG_ANTI_FRAG)) { // Ok, rename the file to what we expect it to be... try { const string& tgt = d->getTempTarget().empty() ? d->getTarget() : d->getTempTarget(); File::renameFile(d->getDownloadTarget(), tgt); d->unsetFlag(Download::FLAG_ANTI_FRAG); } catch(const FileException& e) { dcdebug("AntiFrag: %s\n", e.getError().c_str()); // Now what? } } } catch(const FileException& e) { fire(DownloadManagerListener::Failed(), d, e.getError()); aSource->setDownload(NULL); removeDownload(d, true); removeConnection(aSource); return; } dcassert(d->getPos() == d->getSize()); dcdebug("Download finished: %s, size " I64_FMT ", downloaded " I64_FMT "\n", d->getTarget().c_str(), d->getSize(), d->getTotal()); // Check if we have some crc:s... if(BOOLSETTING(SFV_CHECK)) { SFVReader sfv(d->getTarget()); if(sfv.hasCRC()) { bool crcMatch; string tgt = d->getDownloadTarget(); if(hasCrc) { crcMatch = (crc == sfv.getCRC()); } else { // More complicated, we have to reread the file try { File ff(tgt, File::READ, File::OPEN); CalcInputStream<CRC32Filter, false> f(&ff); const size_t BUF_SIZE = 16 * 65536; AutoArray<u_int8_t> b(BUF_SIZE); size_t n = BUF_SIZE; while(f.read((u_int8_t*)b, n) > 0) ; // Keep on looping... crcMatch = (f.getFilter().getValue() == sfv.getCRC()); } catch (FileException&) { // Nope; read failed... goto noCRC; } } if(!crcMatch) { File::deleteFile(tgt); dcdebug("DownloadManager: CRC32 mismatch for %s\n", d->getTarget().c_str()); LogManager::getInstance()->message(STRING(SFV_INCONSISTENCY) + " (" + STRING(FILE) + ": " + d->getTarget() + ")"); fire(DownloadManagerListener::Failed(), d, STRING(SFV_INCONSISTENCY)); string target = d->getTarget(); aSource->setDownload(NULL); removeDownload(d, true); QueueManager::getInstance()->removeSource(target, aSource->getUser(), QueueItem::Source::FLAG_CRC_WARN, false); checkDownloads(aSource); return; } d->setFlag(Download::FLAG_CRC32_OK); dcdebug("DownloadManager: CRC32 match for %s\n", d->getTarget().c_str()); } } noCRC: if(BOOLSETTING(LOG_DOWNLOADS) && (BOOLSETTING(LOG_FILELIST_TRANSFERS) || !d->isSet(Download::FLAG_USER_LIST))) { StringMap params; params["target"] = d->getTarget(); params["user"] = aSource->getUser()->getNick(); params["hub"] = aSource->getUser()->getLastHubName(); params["hubip"] = aSource->getUser()->getLastHubAddress(); params["size"] = Util::toString(d->getSize()); params["sizeshort"] = Util::formatBytes(d->getSize()); params["chunksize"] = Util::toString(d->getTotal()); params["chunksizeshort"] = Util::formatBytes(d->getTotal()); params["actualsize"] = Util::toString(d->getActual()); params["actualsizeshort"] = Util::formatBytes(d->getActual()); params["speed"] = Util::formatBytes(d->getAverageSpeed()) + "/s"; params["time"] = Util::formatSeconds((GET_TICK() - d->getStart()) / 1000); params["sfv"] = Util::toString(d->isSet(Download::FLAG_CRC32_OK) ? 1 : 0); LOG(DOWNLOAD_AREA, Util::formatParams(SETTING(LOG_FORMAT_POST_DOWNLOAD), params)); } // Check if we need to move the file if( !d->getTempTarget().empty() && (Util::stricmp(d->getTarget().c_str(), d->getTempTarget().c_str()) != 0) ) { try { File::ensureDirectory(d->getTarget()); if(File::getSize(d->getTempTarget()) > MOVER_LIMIT) { mover.moveFile(d->getTempTarget(), d->getTarget()); } else { File::renameFile(d->getTempTarget(), d->getTarget()); } d->setTempTarget(Util::emptyString); } catch(const FileException&) { try { if(!SETTING(DOWNLOAD_DIRECTORY).empty()) { File::renameFile(d->getTempTarget(), SETTING(DOWNLOAD_DIRECTORY) + d->getTargetFileName()); } else { File::renameFile(d->getTempTarget(), Util::getFilePath(d->getTempTarget()) + d->getTargetFileName()); } } catch(const FileException&) { try { File::renameFile(d->getTempTarget(), Util::getFilePath(d->getTempTarget()) + d->getTargetFileName()); } catch(const FileException&) { // Ignore... } } } } fire(DownloadManagerListener::Complete(), d); aSource->setDownload(NULL); removeDownload(d, true, true); checkDownloads(aSource); }