void ConnectionManager::on(UserConnectionListener::Direction, UserConnection* aSource, const string& dir, const string& num) throw() { if(aSource->getState() != UserConnection::STATE_DIRECTION) { dcdebug("CM::onDirection %p received direction twice, ignoring\n", (void*)aSource); return; } dcassert(aSource->isSet(UserConnection::FLAG_DOWNLOAD) ^ aSource->isSet(UserConnection::FLAG_UPLOAD)); if(dir == "Upload") { // Fine, the other fellow want's to send us data...make sure we really want that... if(aSource->isSet(UserConnection::FLAG_UPLOAD)) { // Huh? Strange...disconnect... putConnection(aSource); return; } } else { if(aSource->isSet(UserConnection::FLAG_DOWNLOAD)) { int number = Util::toInt(num); // Damn, both want to download...the one with the highest number wins... if(aSource->getNumber() < number) { // Damn! We lost! aSource->unsetFlag(UserConnection::FLAG_DOWNLOAD); aSource->setFlag(UserConnection::FLAG_UPLOAD); } else if(aSource->getNumber() == number) { putConnection(aSource); return; } } } dcassert(aSource->isSet(UserConnection::FLAG_DOWNLOAD) ^ aSource->isSet(UserConnection::FLAG_UPLOAD)); aSource->setState(UserConnection::STATE_KEY); }
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); } } }
/** * Someone's connecting, accept the connection and wait for identification... * It's always the other fellow that starts sending if he made the connection. */ void ConnectionManager::on(ServerSocketListener::IncomingConnection) throw() { UserConnection* uc = NULL; u_int32_t now = GET_TICK(); if(now > floodCounter) { floodCounter = now + FLOOD_ADD; } else { if(now + FLOOD_TRIGGER < floodCounter) { Socket s; try { s.accept(socket); } catch(const SocketException&) { // ... } dcdebug("Connection flood detected!\n"); return; } else { floodCounter += 2000; } } try { uc = getConnection(); uc->setFlag(UserConnection::FLAG_INCOMING); uc->setState(UserConnection::STATE_NICK); uc->setLastActivity(GET_TICK()); uc->accept(socket); } catch(const SocketException& e) { dcdebug("ConnectionManager::OnIncomingConnection caught: %s\n", e.getError().c_str()); if(uc) putConnection(uc); } }
/** * Someone's connecting, accept the connection and wait for identification... * It's always the other fellow that starts sending if he made the connection. */ void ConnectionManager::accept(const Socket& sock, bool secure) throw() { uint32_t now = GET_TICK(); if(now > floodCounter) { floodCounter = now + FLOOD_ADD; } else { if(false && now + FLOOD_TRIGGER < floodCounter) { Socket s; try { s.accept(sock); } catch(const SocketException&) { // ... } dcdebug("Connection flood detected!\n"); return; } else { floodCounter += FLOOD_ADD; } } UserConnection* uc = getConnection(false, secure); uc->setFlag(UserConnection::FLAG_INCOMING); uc->setState(UserConnection::STATE_SUPNICK); uc->setLastActivity(GET_TICK()); try { uc->accept(sock); } catch(const Exception&) { putConnection(uc); delete 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); } }
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::on(AdcCommand::INF, UserConnection* aSource, const AdcCommand& cmd) throw() { if(aSource->getState() != UserConnection::STATE_INF) { // Already got this once, ignore... aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_PROTOCOL_GENERIC, "Expecting INF")); dcdebug("CM::onINF %p sent INF twice\n", (void*)aSource); aSource->disconnect(); return; } string cid; if(!cmd.getParam("ID", 0, cid)) { aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_INF_MISSING, "ID missing").addParam("FL", "ID")); dcdebug("CM::onINF missing ID\n"); aSource->disconnect(); return; } aSource->setUser(ClientManager::getInstance()->findUser(CID(cid))); if(!aSource->getUser()) { dcdebug("CM::onINF: User not found"); aSource->send(AdcCommand(AdcCommand::SEV_FATAL, AdcCommand::ERROR_GENERIC, "User not found")); putConnection(aSource); return; } if(aSource->isSet(UserConnection::FLAG_INCOMING)) { aSource->setFlag(UserConnection::FLAG_DOWNLOAD); addDownloadConnection(aSource); } else { aSource->setFlag(UserConnection::FLAG_UPLOAD); addUploadConnection(aSource); } }
void ConnectionManager::putUploadConnection(UserConnection* aSource) { { 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::connect(const string& aServer, short aPort, const string& aNick) { if(shuttingDown) return; UserConnection* uc = NULL; try { uc = getConnection(); uc->setNick(aNick); uc->setState(UserConnection::STATE_CONNECT); uc->connect(aServer, aPort); } catch(const SocketException&) { if(uc) putConnection(uc); } }
void ConnBoshMultStat::handleReceivedData( const ConnectionBase* /*connection*/, const std::string& data ) { m_buffer += data; std::string::size_type headerLength = 0; while( ( headerLength = m_buffer.find( "\r\n\r\n" ) ) != std::string::npos ) { m_bufferHeader = m_buffer.substr( 0, headerLength+2 ); const std::string& statusCode = m_bufferHeader.substr( 9, 3 ); if( statusCode != "200" ) { m_logInstance.warn( LogAreaClassConnectionBOSH, "Received error via legacy HTTP status code: " + statusCode + ". Disconnecting." ); m_state = StateDisconnected; // As per XEP, consider connection broken disconnect(); } m_bufferContentLength = atol( getHTTPField( "Content-Length" ).c_str() ); if( !m_bufferContentLength ) return; if( m_connMode != ModeLegacyHTTP && ( getHTTPField( "Connection" ) == "close" || m_bufferHeader.substr( 0, 8 ) == "HTTP/1.0" ) ) { m_logInstance.dbg( LogAreaClassConnectionBOSH, "Server indicated lack of support for HTTP/1.1 - falling back to HTTP/1.0" ); m_connMode = ModeLegacyHTTP; } if( m_buffer.length() >= ( headerLength + 4 + m_bufferContentLength ) ) { putConnection(); --m_openRequests; std::string xml = m_buffer.substr( headerLength + 4, m_bufferContentLength ); m_parser.feed( xml ); m_buffer.erase( 0, headerLength + 4 + m_bufferContentLength ); m_bufferContentLength = 0; m_bufferHeader = EmptyString; } else { m_logInstance.warn( LogAreaClassConnectionBOSH, "buffer length mismatch" ); break; } } }
void ConnectionManager::nmdcConnect(const string& aServer, uint16_t aPort, const string& aNick, const string& hubUrl) { if(shuttingDown) return; UserConnection* uc = getConnection(true, false); uc->setToken(aNick); uc->setHubUrl(hubUrl); uc->setState(UserConnection::STATE_CONNECT); uc->setFlag(UserConnection::FLAG_NMDC); try { uc->connect(aServer, aPort); } catch(const Exception&) { putConnection(uc); delete uc; } }
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() { if(aSource->isSet(UserConnection::FLAG_DOWNLOAD) && aSource->getCQI()) { { Lock l(cs); for(ConnectionQueueItem::Iter i = downPool.begin(); i != downPool.end(); ++i) { dcassert((*i)->getConnection()); if((*i)->getConnection() == aSource) { dcdebug("ConnectionManager::onError Removing connection %p to %s from active pool\n", aSource, aSource->getUser()->getNick().c_str()); downPool.erase(i); break; } } } } putConnection(aSource); }
void ConnectionManager::adcConnect(const OnlineUser& aUser, uint16_t aPort, const string& aToken, bool secure) { if(shuttingDown) return; UserConnection* uc = getConnection(false, secure); uc->setToken(aToken); uc->setState(UserConnection::STATE_CONNECT); if(aUser.getIdentity().isOp()) { uc->setFlag(UserConnection::FLAG_OP); } try { uc->connect(aUser.getIdentity().getIp(), aPort); } catch(const Exception&) { putConnection(uc); delete uc; } }
/** * 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); }
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(UserConnectionListener::Connected, UserConnection* aSource) throw() { if(aSource->isSecure() && !aSource->isTrusted() && !BOOLSETTING(ALLOW_UNTRUSTED_CLIENTS)) { putConnection(aSource); LogManager::getInstance()->message(STRING(CERTIFICATE_NOT_TRUSTED)); return; } dcassert(aSource->getState() == UserConnection::STATE_CONNECT); if(aSource->isSet(UserConnection::FLAG_NMDC)) { aSource->myNick(aSource->getToken()); aSource->lock(CryptoManager::getInstance()->getLock(), CryptoManager::getInstance()->getPk()); } else { StringList defFeatures = adcFeatures; if(BOOLSETTING(COMPRESS_TRANSFERS)) { defFeatures.push_back("AD" + UserConnection::FEATURE_ZLIB_GET); } aSource->sup(defFeatures); } aSource->setState(UserConnection::STATE_SUPNICK); }
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); }