void Transfer::getParams(const UserConnection& aSource, StringMap& params) { params["userNI"] = aSource.getUser()->getNick(); params["userI4"] = aSource.getRemoteIp(); params["hub"] = aSource.getUser()->getClientName(); params["hubURL"] = aSource.getUser()->getClientUrl(); params["fileSI"] = Util::toString(getSize()); params["fileSIshort"] = Util::formatBytes(getSize()); params["fileSIchunk"] = Util::toString(getTotal()); params["fileSIchunkshort"] = Util::formatBytes(getTotal()); params["fileSIactual"] = Util::toString(getActual()); params["fileSIactualshort"] = Util::formatBytes(getActual()); params["speed"] = Util::formatBytes(getAverageSpeed()) + "/s"; params["time"] = Util::formatSeconds((GET_TICK() - getStart()) / 1000); params["fileTR"] = getTTH().toBase32(); }
void Transfer::getParams(const UserConnection& aSource, StringMap& params) { params["userCID"] = aSource.getUser()->getCID().toBase32(); params["userNI"] = Util::toString(ClientManager::getInstance()->getNicks(aSource.getUser()->getCID(), aSource.getHubUrl())); params["userI4"] = aSource.getRemoteIp(); StringList hubNames = ClientManager::getInstance()->getHubNames(aSource.getUser()->getCID(), aSource.getHubUrl()); if(hubNames.empty()) hubNames.push_back(_("Offline")); params["hub"] = Util::toString(hubNames); StringList hubs = ClientManager::getInstance()->getHubs(aSource.getUser()->getCID(), aSource.getHubUrl()); if(hubs.empty()) hubs.push_back(_("Offline")); params["hubURL"] = Util::toString(hubs); params["fileSI"] = Util::toString(getSize()); params["fileSIshort"] = Util::formatBytes(getSize()); params["fileSIactual"] = Util::toString(getActual()); params["fileSIactualshort"] = Util::formatBytes(getActual()); params["speed"] = str(F_("%1%/s") % Util::formatBytes(getAverageSpeed())); params["time"] = Util::formatSeconds((GET_TICK() - getStart()) / 1000); params["fileTR"] = getTTH().toBase32(); }
void displaySpeed(){ int a,b,c,d; double currSpeed = getCurrentSpeed(); double averSpeed = getAverageSpeed(); //current speed in left most if(currSpeed >= 100){ // only allow display two digits, display 99 a = 9; b = 9; }else if(currSpeed > 10 ){ // no decimal pt a = currSpeed / 10; setDecimalAnode0(false); b = (currSpeed - a * 10); }else{ //1 digit + decimal a = currSpeed; setDecimalAnode0(true); b = (currSpeed * 10 ) - (a * 10); } if(averSpeed >= 100){ // only allow display two digits, display 99 c = 9; d = 9; }else if(averSpeed > 10 ){ // no decimal pt c = averSpeed / 10; setDecimalAnode2(false); d = (averSpeed - c * 10); } else{ //1 digit + decimal c = averSpeed; setDecimalAnode2(true); d = (averSpeed * 10 ) - (c * 10); } displayNumbers(a,b,c,d); }
void Transfer::getParams(const UserConnection& aSource, StringMap& params) const { params["userCID"] = aSource.getUser()->getCID().toBase32(); params["userNI"] = Util::toString(ClientManager::getInstance()->getNicks(aSource.getUser()->getCID(), aSource.getHubUrl())); params["userI4"] = aSource.getRemoteIp(); StringList hubNames = ClientManager::getInstance()->getHubNames(aSource.getUser()->getCID(), aSource.getHubUrl()); if(hubNames.empty()) hubNames.push_back(STRING(OFFLINE)); params["hub"] = Util::toString(hubNames); StringList hubs = ClientManager::getInstance()->getHubs(aSource.getUser()->getCID(), aSource.getHubUrl()); if(hubs.empty()) hubs.push_back(STRING(OFFLINE)); params["hubURL"] = Util::toString(hubs); params["fileSI"] = Util::toString(getSize()); params["fileSIshort"] = Util::formatBytes(getSize()); params["fileSIchunk"] = Util::toString(getPos()); params["fileSIchunkshort"] = Util::formatBytes(getPos()); params["fileSIactual"] = Util::toString(getActual()); params["fileSIactualshort"] = Util::formatBytes(getActual()); params["speed"] = Util::formatBytes(static_cast<int64_t>(getAverageSpeed())) + "/s"; params["time"] = Text::fromT(Util::formatSeconds((GET_TICK() - getStart()) / 1000)); params["fileTR"] = getTTH().toBase32(); }
void Transfer::updateRunningAverage() { time_t tick = GET_TICK(); // Update 4 times/sec at most if(tick > (lastTick + 250)) { time_t diff = tick - lastTick; int64_t tot = getTotal(); if( ((tick - getStart()) < AVG_PERIOD) ) { runningAverage = getAverageSpeed(); } else { int64_t bdiff = tot - last; int64_t avg = bdiff * (int64_t)1000 / diff; if(diff > AVG_PERIOD) { runningAverage = avg; } else { // Weighted average... runningAverage = ((avg * diff) + (runningAverage*(AVG_PERIOD-diff)))/AVG_PERIOD; } } last = tot; } lastTick = tick; }
int64_t Transfer::getSecondsLeft(bool wholeFile) const { double avg = getAverageSpeed(); int64_t bytesLeft = (wholeFile ? ((Upload*)this)->getFileSize() : getSize()) - getPos(); return (avg > 0) ? static_cast<int64_t>(bytesLeft / avg) : 0; }
void DownloadManager::checkDownloads(UserConnection* aConn) { Download* d = aConn->getDownload(); bool firstTry = false; if(d == NULL) { firstTry = true; bool slotsFull = (SETTING(DOWNLOAD_SLOTS) != 0) && (getDownloads() >= (size_t)SETTING(DOWNLOAD_SLOTS)); bool speedFull = (SETTING(MAX_DOWNLOAD_SPEED) != 0) && (getAverageSpeed() >= (SETTING(MAX_DOWNLOAD_SPEED)*1024)); if( slotsFull || speedFull ) { bool extraFull = (SETTING(DOWNLOAD_SLOTS) != 0) && (getDownloads() >= (size_t)(SETTING(DOWNLOAD_SLOTS)+3)); if(extraFull || !QueueManager::getInstance()->hasDownload(aConn->getUser(), QueueItem::HIGHEST)) { removeConnection(aConn); return; } } d = QueueManager::getInstance()->getDownload(aConn->getUser()); if(d == NULL) { removeConnection(aConn, true); return; } { Lock l(cs); downloads.push_back(d); } d->setUserConnection(aConn); aConn->setDownload(d); } if(firstTry && !d->getTreeValid() && !d->isSet(Download::FLAG_USER_LIST) && d->getTTH() != NULL) { if(HashManager::getInstance()->getTree(d->getTarget(), d->getTTH(), d->getTigerTree())) { d->setTreeValid(true); } else if(!d->isSet(Download::FLAG_TREE_TRIED) && aConn->isSet(UserConnection::FLAG_SUPPORTS_TTHL)) { // So, we need to download the tree... Download* tthd = new Download(); tthd->setOldDownload(d); tthd->setFlag(Download::FLAG_TREE_DOWNLOAD); tthd->setTarget(d->getTarget()); tthd->setSource(d->getSource()); tthd->setUserConnection(aConn); aConn->setDownload(tthd); aConn->setState(UserConnection::STATE_TREE); // Hack to get by TTH if possible tthd->setTTH(d->getTTH()); aConn->send(tthd->getCommand(false, aConn->isSet(UserConnection::FLAG_SUPPORTS_TTHF))); tthd->setTTH(NULL); return; } } aConn->setState(UserConnection::STATE_FILELENGTH); if(d->isSet(Download::FLAG_RESUME)) { dcassert(d->getSize() != -1); const string& target = (d->getTempTarget().empty() ? d->getTarget() : d->getTempTarget()); int64_t start = File::getSize(target); // Only use antifrag if we don't have a previous non-antifrag part if( BOOLSETTING(ANTI_FRAG) && (start == -1) && (d->getSize() != -1) ) { int64_t aSize = File::getSize(target + Download::ANTI_FRAG_EXT); if(aSize == d->getSize()) start = d->getPos(); else start = 0; d->setFlag(Download::FLAG_ANTI_FRAG); } int rollback = SETTING(ROLLBACK); if(rollback > start) { d->setStartPos(0); } else { d->setStartPos(start - rollback); d->setFlag(Download::FLAG_ROLLBACK); } } else { d->setStartPos(0); } if(d->isSet(Download::FLAG_USER_LIST)) { if(aConn->isSet(UserConnection::FLAG_SUPPORTS_XML_BZLIST)) { d->setSource("files.xml.bz2"); } } if(aConn->isSet(UserConnection::FLAG_SUPPORTS_ADCGET) && d->isSet(Download::FLAG_UTF8)) { aConn->send(d->getCommand( aConn->isSet(UserConnection::FLAG_SUPPORTS_ZLIB_GET), aConn->isSet(UserConnection::FLAG_SUPPORTS_TTHF) )); } else { if(BOOLSETTING(COMPRESS_TRANSFERS) && aConn->isSet(UserConnection::FLAG_SUPPORTS_GETZBLOCK) && d->getSize() != -1 ) { // This one, we'll download with a zblock download instead... d->setFlag(Download::FLAG_ZDOWNLOAD); aConn->getZBlock(d->getSource(), d->getPos(), d->getBytesLeft(), d->isSet(Download::FLAG_UTF8)); } else if(d->isSet(Download::FLAG_UTF8)) { aConn->getBlock(d->getSource(), d->getPos(), d->getBytesLeft(), true); } else { aConn->get(d->getSource(), d->getPos()); } } }
Segment QueueItem::getNextSegment(int64_t blockSize, int64_t wantedSize, int64_t lastSpeed, const PartialSource::Ptr partialSource) const { if(getSize() == -1 || blockSize == 0) { return Segment(0, -1); } if(!BOOLSETTING(MULTI_CHUNK)) { if(!downloads.empty()) { return Segment(-1, 0); } int64_t start = 0; int64_t end = getSize(); if(!done.empty()) { const Segment& first = *done.begin(); if(first.getStart() > 0) { end = Util::roundUp(first.getStart(), blockSize); } else { start = Util::roundDown(first.getEnd(), blockSize); if(done.size() > 1) { const Segment& second = *(++done.begin()); end = Util::roundUp(second.getStart(), blockSize); } } } return Segment(start, std::min(getSize(), end) - start); } if(downloads.size() >= maxSegments || (BOOLSETTING(DONT_BEGIN_SEGMENT) && (size_t)(SETTING(DONT_BEGIN_SEGMENT_SPEED) * 1024) < getAverageSpeed())) { // no other segments if we have reached the speed or segment limit return Segment(-1, 0); } /* added for PFS */ vector<int64_t> posArray; vector<Segment> neededParts; if(partialSource) { posArray.reserve(partialSource->getPartialInfo().size()); // Convert block index to file position for(PartsInfo::const_iterator i = partialSource->getPartialInfo().begin(); i != partialSource->getPartialInfo().end(); i++) posArray.push_back(min(getSize(), (int64_t)(*i) * blockSize)); } /***************************/ double donePart = static_cast<double>(getDownloadedBytes()) / getSize(); // We want smaller blocks at the end of the transfer, squaring gives a nice curve... int64_t targetSize = static_cast<int64_t>(static_cast<double>(wantedSize) * std::max(0.25, (1. - (donePart * donePart)))); if(targetSize > blockSize) { // Round off to nearest block size targetSize = Util::roundDown(targetSize, blockSize); } else { targetSize = blockSize; } int64_t start = 0; int64_t curSize = targetSize; while(start < getSize()) { int64_t end = std::min(getSize(), start + curSize); Segment block(start, end - start); bool overlaps = false; for(SegmentConstIter i = done.begin(); !overlaps && i != done.end(); ++i) { if(curSize <= blockSize) { int64_t dstart = i->getStart(); int64_t dend = i->getEnd(); // We accept partial overlaps, only consider the block done if it is fully consumed by the done block if(dstart <= start && dend >= end) { overlaps = true; } } else { overlaps = block.overlaps(*i); } } for(auto i = downloads.begin(); !overlaps && i != downloads.end(); ++i) { overlaps = block.overlaps((*i)->getSegment()); } if(!overlaps) { if(partialSource) { // store all chunks we could need for(vector<int64_t>::const_iterator j = posArray.begin(); j < posArray.end(); j += 2){ if( (*j <= start && start < *(j+1)) || (start <= *j && *j < end) ) { int64_t b = max(start, *j); int64_t e = min(end, *(j+1)); // segment must be blockSize aligned dcassert(b % blockSize == 0); dcassert(e % blockSize == 0 || e == getSize()); neededParts.push_back(Segment(b, e - b)); } } } else { return block; } } if(overlaps && (curSize > blockSize)) { curSize -= blockSize; } else { start = end; curSize = targetSize; } } if(!neededParts.empty()) { // select random chunk for download dcdebug("Found chunks: %d\n", neededParts.size()); Segment& selected = neededParts[Util::rand(0, neededParts.size())]; selected.setSize(std::min(selected.getSize(), targetSize)); // request only wanted size return selected; } if(partialSource == NULL && BOOLSETTING(OVERLAP_CHUNKS) && lastSpeed > 0) { // overlap slow running chunk for(auto i = downloads.begin(); i != downloads.end(); ++i) { Download* d = *i; // current chunk mustn't be already overlapped if(d->getOverlapped()) continue; // current chunk must be running at least for 4 seconds if(d->getStart() == 0 || GET_TICK() - d->getStart() < 4000) continue; // current chunk mustn't be finished in next 20 seconds if(d->getSecondsLeft() < 20) continue; // overlap current chunk at last block boundary int64_t pos = d->getPos() - (d->getPos() % blockSize); int64_t size = d->getSize() - pos; // new user should finish this chunk more than 2x faster int64_t newChunkLeft = size / lastSpeed; if(2 * newChunkLeft < d->getSecondsLeft()) { dcdebug("Overlapping... old user: %I64d s, new user: %I64d s\n", d->getSecondsLeft(), newChunkLeft); return Segment(d->getStartPos() + pos, size, true); } } } return Segment(0, 0); }