Пример #1
0
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);
    }
}
Пример #2
0
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);
    }
}
/**
 * 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::on(UserConnectionListener::Key, UserConnection* aSource, const string&/* aKey*/) throw() {
	if(aSource->getState() != UserConnection::STATE_KEY) {
		dcdebug("CM::onKey Bad state, ignoring");
		return;
	}
	// We don't want any messages while the Up/DownloadManagers are working...
	aSource->removeListener(this);
	dcassert(aSource->getUser());
	{
		Lock l(cs);

		// Only one connection / user & direction...
		for(ConnectionQueueItem::Iter k = active.begin(); k != active.end(); ++k) {
			bool sameDirection = (*k)->getConnection()->isSet(UserConnection::FLAG_UPLOAD) == aSource->isSet(UserConnection::FLAG_UPLOAD);
			if( sameDirection && (*k == aSource->getUser()) ) {
				putConnection(aSource);
				return;
			}
		}
		
		ConnectionQueueItem* cqi = NULL;

		if(aSource->isSet(UserConnection::FLAG_DOWNLOAD)) {
			// See if we have a matching user in the pending connections...
			ConnectionQueueItem::Iter i = find(pendingDown.begin(), pendingDown.end(), aSource->getUser());

			if(i == pendingDown.end()) {
				putConnection(aSource);
				return;
			}
			cqi = *i;
			pendingDown.erase(i);
			cqi->setConnection(aSource);
		} else {
			dcassert(aSource->isSet(UserConnection::FLAG_UPLOAD));
			cqi = new ConnectionQueueItem(aSource->getUser());
			cqi->setConnection(aSource);
			fire(ConnectionManagerListener::Added(), cqi);			
		}

		aSource->setCQI(cqi);

		dcassert(find(active.begin(), active.end(), cqi) == active.end());
		active.push_back(cqi);

		fire(ConnectionManagerListener::Connected(), cqi);
		
		if(aSource->isSet(UserConnection::FLAG_DOWNLOAD)) {
			dcdebug("ConnectionManager::onKey, leaving to downloadmanager\n");
			DownloadManager::getInstance()->addConnection(aSource);
		} else {
			dcassert(aSource->isSet(UserConnection::FLAG_UPLOAD));
			dcdebug("ConnectionManager::onKey, leaving to uploadmanager\n");
			UploadManager::getInstance()->addConnection(aSource);
		}
	}
}
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);
		}
	}
}
/**
 * Nick received. If it's a downloader, fine, otherwise it must be an uploader.
 */
void ConnectionManager::on(UserConnectionListener::MyNick, UserConnection* aSource, const string& aNick) throw() {

	if(aSource->getState() != UserConnection::STATE_NICK) {
		// Already got this once, ignore...
		dcdebug("CM::onMyNick %p sent nick twice\n", aSource);
		return;
	}

	dcassert(aNick.size() > 0);
	dcdebug("ConnectionManager::onMyNick %p, %s\n", aSource, aNick.c_str());
	dcassert(!aSource->getUser());

	// First, we try looking in the pending downloads...hopefully it's one of them...
	{
		Lock l(cs);
		for(ConnectionQueueItem::Iter i = pendingDown.begin(); i != pendingDown.end(); ++i) {
			ConnectionQueueItem* cqi = *i;
			if(cqi->getUser()->getNick() == aNick) {
				aSource->setUser(cqi->getUser());
				// Indicate that we're interested in this file...
				aSource->setFlag(UserConnection::FLAG_DOWNLOAD);
			}
		}
	}

	if(!aSource->getUser()) {
		// Make sure we know who it is, i e that he/she is connected...
		if(!ClientManager::getInstance()->isOnline(aNick)) {
			dcdebug("CM::onMyNick Incoming connection from unknown user %s\n", aNick.c_str());
			putConnection(aSource);
			return;
		}

		aSource->setUser(ClientManager::getInstance()->getUser(aNick));
		// We don't need this connection for downloading...make it an upload connection instead...
		aSource->setFlag(UserConnection::FLAG_UPLOAD);
	}

	if( aSource->isSet(UserConnection::FLAG_INCOMING) ) {
		aSource->myNick(aSource->getUser()->getClientNick()); 
		aSource->lock(CryptoManager::getInstance()->getLock(), CryptoManager::getInstance()->getPk());
	}

	aSource->setState(UserConnection::STATE_LOCK);
}
Пример #7
0
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);
}
Пример #8
0
void ConnectionManager::on(UserConnectionListener::MyNick, UserConnection* aSource, const string& aNick) throw() {
    if(aSource->getState() != UserConnection::STATE_SUPNICK) {
        // Already got this once, ignore...
        dcdebug("CM::onMyNick %p sent nick twice\n", (void*)aSource);
        return;
    }

    dcassert(aNick.size() > 0);
    dcdebug("ConnectionManager::onMyNick %p, %s\n", (void*)aSource, aNick.c_str());
    dcassert(!aSource->getUser());

    if(aSource->isSet(UserConnection::FLAG_INCOMING)) {
        // Try to guess where this came from...
        pair<string, string> i = expectedConnections.remove(aNick);
        if(i.second.empty()) {
            dcassert(i.first.empty());
            dcdebug("Unknown incoming connection from %s\n", aNick.c_str());
            putConnection(aSource);
            return;
        }
        aSource->setToken(i.first);
        aSource->setHubUrl(i.second);
    }
    CID cid = ClientManager::getInstance()->makeCid(aNick, aSource->getHubUrl());

    // First, we try looking in the pending downloads...hopefully it's one of them...
    {
        Lock l(cs);
        for(ConnectionQueueItem::Iter i = downloads.begin(); i != downloads.end(); ++i) {
            ConnectionQueueItem* cqi = *i;
            if((cqi->getState() == ConnectionQueueItem::CONNECTING || cqi->getState() == ConnectionQueueItem::WAITING) && cqi->getUser()->getCID() == cid) {
                aSource->setUser(cqi->getUser());
                // Indicate that we're interested in this file...
                aSource->setFlag(UserConnection::FLAG_DOWNLOAD);
                break;
            }
        }
    }

    if(!aSource->getUser()) {
        // Make sure we know who it is, i e that he/she is connected...

        aSource->setUser(ClientManager::getInstance()->findUser(cid));
        if(!aSource->getUser() || !ClientManager::getInstance()->isOnline(aSource->getUser())) {
            dcdebug("CM::onMyNick Incoming connection from unknown user %s\n", aNick.c_str());
            putConnection(aSource);
            return;
        }
        // We don't need this connection for downloading...make it an upload connection instead...
        aSource->setFlag(UserConnection::FLAG_UPLOAD);
    }

    if(ClientManager::getInstance()->isOp(aSource->getUser(), aSource->getHubUrl()))
        aSource->setFlag(UserConnection::FLAG_OP);

    if( aSource->isSet(UserConnection::FLAG_INCOMING) ) {
        aSource->myNick(aSource->getToken());
        aSource->lock(CryptoManager::getInstance()->getLock(), CryptoManager::getInstance()->getPk());
    }

    aSource->setState(UserConnection::STATE_LOCK);
}
Пример #9
0
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);
	}
}