void ConnectionManager::addUploadConnection(UserConnection* uc) { dcassert(uc->isSet(UserConnection::FLAG_UPLOAD)); bool addConn = false; { Lock l(cs); ConnectionQueueItem::Iter i = find(uploads.begin(), uploads.end(), uc->getUser()); if(i == uploads.end()) { ConnectionQueueItem* cqi = getCQI(uc->getUser(), false); cqi->setState(ConnectionQueueItem::ACTIVE); uc->setFlag(UserConnection::FLAG_ASSOCIATED); fire(ConnectionManagerListener::Connected(), cqi); dcdebug("ConnectionManager::addUploadConnection, leaving to uploadmanager\n"); addConn = true; } } if(addConn) { UploadManager::getInstance()->addConnection(uc); } else { putConnection(uc); } }
void ConnectionManager::addDownloadConnection(UserConnection* uc) { dcassert(uc->isSet(UserConnection::FLAG_DOWNLOAD)); bool addConn = false; { Lock l(cs); ConnectionQueueItem::Iter i = find(downloads.begin(), downloads.end(), uc->getUser()); if(i != downloads.end()) { ConnectionQueueItem* cqi = *i; if(cqi->getState() == ConnectionQueueItem::WAITING || cqi->getState() == ConnectionQueueItem::CONNECTING) { cqi->setState(ConnectionQueueItem::ACTIVE); uc->setFlag(UserConnection::FLAG_ASSOCIATED); fire(ConnectionManagerListener::Connected(), cqi); dcdebug("ConnectionManager::addDownloadConnection, leaving to downloadmanager\n"); addConn = true; } } } if(addConn) { DownloadManager::getInstance()->addConnection(uc); } else { putConnection(uc); } }
/** * Request a connection for downloading. * DownloadManager::addConnection will be called as soon as the connection is ready * for downloading. * @param aUser The user to connect to. */ void ConnectionManager::getDownloadConnection(const User::Ptr& aUser) { dcassert((bool)aUser); ConnectionQueueItem* cqi = NULL; { Lock l(cs); // Check the download pool if(find(downPool.begin(), downPool.end(), aUser) != downPool.end()) { if(find(pendingAdd.begin(), pendingAdd.end(), aUser) == pendingAdd.end()) pendingAdd.push_back(aUser); return; } // See if we're already trying to connect if(find(pendingDown.begin(), pendingDown.end(), aUser) != pendingDown.end()) return; // Check if we have an active download connection already for(ConnectionQueueItem::Iter j = active.begin(); j != active.end(); ++j) { dcassert((*j)->getConnection()); if((*j == aUser) && ((*j)->getConnection()->isSet(UserConnection::FLAG_DOWNLOAD))) return; } // Add it to the pending... cqi = new ConnectionQueueItem(aUser); cqi->setState(ConnectionQueueItem::WAITING); pendingDown.push_back(cqi); fire(ConnectionManagerListener::Added(), cqi); } }
void ConnectionManager::putDownloadConnection(UserConnection* aSource, bool reuse /* = false */) { // Pool it for later usage... if(reuse) { aSource->addListener(this); { Lock l(cs); aSource->getCQI()->setState(ConnectionQueueItem::IDLE); dcassert(find(active.begin(), active.end(), aSource->getCQI()) != active.end()); active.erase(find(active.begin(), active.end(), aSource->getCQI())); downPool.push_back(aSource->getCQI()); } dcdebug("ConnectionManager::putDownloadConnection Pooling reusable connection %p to %s\n", aSource, aSource->getUser()->getNick().c_str()); } else { if(QueueManager::getInstance()->hasDownload(aSource->getCQI()->getUser())) { aSource->removeListeners(); aSource->disconnect(); Lock l(cs); ConnectionQueueItem* cqi = aSource->getCQI(); dcassert(cqi); // Remove the userconnection, don't need it any more dcassert(find(userConnections.begin(), userConnections.end(), aSource) != userConnections.end()); userConnections.erase(find(userConnections.begin(), userConnections.end(), aSource)); pendingDelete.push_back(aSource); cqi->setConnection(NULL); cqi->setState(ConnectionQueueItem::WAITING); dcassert(find(active.begin(), active.end(), aSource->getCQI()) != active.end()); active.erase(find(active.begin(), active.end(), aSource->getCQI())); cqi->setLastAttempt(GET_TICK()); pendingDown.push_back(cqi); } else { { Lock l(cs); dcassert(find(active.begin(), active.end(), aSource->getCQI()) != active.end()); active.erase(find(active.begin(), active.end(), aSource->getCQI())); } putConnection(aSource); } } }
void ConnectionManager::on(UserConnectionListener::Failed, UserConnection* aSource, const string& aError) throw() { Lock l(cs); if(aSource->isSet(UserConnection::FLAG_ASSOCIATED)) { if(aSource->isSet(UserConnection::FLAG_DOWNLOAD)) { ConnectionQueueItem::Iter i = find(downloads.begin(), downloads.end(), aSource->getUser()); dcassert(i != downloads.end()); ConnectionQueueItem* cqi = *i; cqi->setState(ConnectionQueueItem::WAITING); cqi->setLastAttempt(GET_TICK()); fire(ConnectionManagerListener::Failed(), cqi, aError); } else if(aSource->isSet(UserConnection::FLAG_UPLOAD)) { ConnectionQueueItem::Iter i = find(uploads.begin(), uploads.end(), aSource->getUser()); dcassert(i != uploads.end()); ConnectionQueueItem* cqi = *i; putCQI(cqi); } } putConnection(aSource); }
void ConnectionManager::on(TimerManagerListener::Second, uint32_t aTick) throw() { User::List passiveUsers; ConnectionQueueItem::List removed; User::List idlers; { Lock l(cs); bool attemptDone = false; idlers = checkIdle; checkIdle.clear(); for(ConnectionQueueItem::Iter i = downloads.begin(); i != downloads.end(); ++i) { ConnectionQueueItem* cqi = *i; if(cqi->getState() != ConnectionQueueItem::ACTIVE) { if(!cqi->getUser()->isOnline()) { // Not online anymore...remove it from the pending... removed.push_back(cqi); continue; } if(cqi->getUser()->isSet(User::PASSIVE) && !ClientManager::getInstance()->isActive()) { passiveUsers.push_back(cqi->getUser()); removed.push_back(cqi); continue; } if( ((cqi->getLastAttempt() + 60*1000) < aTick) && !attemptDone ) { cqi->setLastAttempt(aTick); QueueItem::Priority prio = QueueManager::getInstance()->hasDownload(cqi->getUser()); if(prio == QueueItem::PAUSED) { removed.push_back(cqi); continue; } bool startDown = DownloadManager::getInstance()->startDownload(prio); if(cqi->getState() == ConnectionQueueItem::WAITING) { if(startDown) { cqi->setState(ConnectionQueueItem::CONNECTING); ClientManager::getInstance()->connect(cqi->getUser()); fire(ConnectionManagerListener::StatusChanged(), cqi); attemptDone = true; } else { cqi->setState(ConnectionQueueItem::NO_DOWNLOAD_SLOTS); fire(ConnectionManagerListener::Failed(), cqi, STRING(ALL_DOWNLOAD_SLOTS_TAKEN)); } } else if(cqi->getState() == ConnectionQueueItem::NO_DOWNLOAD_SLOTS && startDown) { cqi->setState(ConnectionQueueItem::WAITING); } } else if(((cqi->getLastAttempt() + 50*1000) < aTick) && (cqi->getState() == ConnectionQueueItem::CONNECTING)) { fire(ConnectionManagerListener::Failed(), cqi, STRING(CONNECTION_TIMEOUT)); cqi->setState(ConnectionQueueItem::WAITING); } } } for(ConnectionQueueItem::Iter m = removed.begin(); m != removed.end(); ++m) { putCQI(*m); } } for(User::Iter i = idlers.begin(); i != idlers.end(); ++i) { DownloadManager::getInstance()->checkIdle(*i); } for(User::Iter ui = passiveUsers.begin(); ui != passiveUsers.end(); ++ui) { QueueManager::getInstance()->removeSource(*ui, QueueItem::Source::FLAG_PASSIVE); } }
void ConnectionManager::on(TimerManagerListener::Second, u_int32_t aTick) throw() { ConnectionQueueItem::List failPassive; ConnectionQueueItem::List connecting; ConnectionQueueItem::List removed; User::List getDown; { Lock l(cs); { for(User::Iter k = pendingAdd.begin(); k != pendingAdd.end(); ++k) { ConnectionQueueItem::Iter i = find(downPool.begin(), downPool.end(), *k); if(i == downPool.end()) { // Hm, connection must have failed before it could be collected... getDown.push_back(*k); } else { ConnectionQueueItem* cqi = *i; downPool.erase(i); dcassert(find(active.begin(), active.end(), cqi) == active.end()); active.push_back(cqi); dcassert(cqi->getConnection()); dcassert(cqi->getConnection()->getCQI() == cqi); cqi->getConnection()->removeListener(this); DownloadManager::getInstance()->addConnection(cqi->getConnection()); } } pendingAdd.clear(); } bool tooMany = ((SETTING(DOWNLOAD_SLOTS) != 0) && DownloadManager::getInstance()->getDownloads() >= (size_t)SETTING(DOWNLOAD_SLOTS)); bool tooFast = ((SETTING(MAX_DOWNLOAD_SPEED) != 0 && DownloadManager::getInstance()->getAverageSpeed() >= (SETTING(MAX_DOWNLOAD_SPEED)*1024))); bool startDown = !tooMany && !tooFast; int attempts = 0; ConnectionQueueItem::Iter i = pendingDown.begin(); while(i != pendingDown.end()) { ConnectionQueueItem* cqi = *i; dcassert(cqi->getUser()); if(!cqi->getUser()->isOnline()) { // Not online anymore...remove him from the pending... i = pendingDown.erase(i); removed.push_back(cqi); continue; } if( ((cqi->getLastAttempt() + 60*1000) < aTick) && (attempts < 2) ) { cqi->setLastAttempt(aTick); if(!QueueManager::getInstance()->hasDownload(cqi->getUser())) { i = pendingDown.erase(i); removed.push_back(cqi); continue; } if(cqi->getUser()->isSet(User::PASSIVE) && (SETTING(CONNECTION_TYPE) != SettingsManager::CONNECTION_ACTIVE)) { i = pendingDown.erase(i); failPassive.push_back(cqi); continue; } // Always start high-priority downloads unless we have 3 more than maxdownslots already... if(!startDown) { bool extraFull = (SETTING(DOWNLOAD_SLOTS) != 0) && (DownloadManager::getInstance()->getDownloads() >= (size_t)(SETTING(DOWNLOAD_SLOTS)+3)); startDown = !extraFull && QueueManager::getInstance()->hasDownload(cqi->getUser(), QueueItem::HIGHEST); } if(cqi->getState() == ConnectionQueueItem::WAITING) { if(startDown) { cqi->setState(ConnectionQueueItem::CONNECTING); cqi->getUser()->connect(); fire(ConnectionManagerListener::StatusChanged(), cqi); attempts++; } else { cqi->setState(ConnectionQueueItem::NO_DOWNLOAD_SLOTS); fire(ConnectionManagerListener::Failed(), cqi, STRING(ALL_DOWNLOAD_SLOTS_TAKEN)); } } else if(cqi->getState() == ConnectionQueueItem::NO_DOWNLOAD_SLOTS && startDown) { cqi->setState(ConnectionQueueItem::WAITING); } } else if(((cqi->getLastAttempt() + 50*1000) < aTick) && (cqi->getState() == ConnectionQueueItem::CONNECTING)) { fire(ConnectionManagerListener::Failed(), cqi, STRING(CONNECTION_TIMEOUT)); cqi->setState(ConnectionQueueItem::WAITING); } ++i; } } ConnectionQueueItem::Iter m; for(m = removed.begin(); m != removed.end(); ++m) { fire(ConnectionManagerListener::Removed(), *m); delete *m; } for(m = failPassive.begin(); m != failPassive.end(); ++m) { QueueManager::getInstance()->removeSources((*m)->getUser(), QueueItem::Source::FLAG_PASSIVE); fire(ConnectionManagerListener::Removed(), *m); delete *m; } for(User::Iter n = getDown.begin(); n != getDown.end(); ++n) { getDownloadConnection(*n); } }