bool ServerSocketInterface::initSession() { Event_ServerIdentification identEvent; identEvent.set_server_name(servatrice->getServerName().toStdString()); identEvent.set_server_version(VERSION_STRING); identEvent.set_protocol_version(protocolVersion); SessionEvent *identSe = prepareSessionEvent(identEvent); sendProtocolItem(*identSe); delete identSe; int maxUsers = servatrice->getMaxUsersPerAddress(); //allow unlimited number of connections from the trusted sources QString trustedSources = settingsCache->value("server/trusted_sources","127.0.0.1,::1").toString(); if (trustedSources.contains(socket->peerAddress().toString(),Qt::CaseInsensitive)) return true; if ((maxUsers > 0) && (servatrice->getUsersWithAddress(socket->peerAddress()) >= maxUsers)) { Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::TOO_MANY_CONNECTIONS); SessionEvent *se = prepareSessionEvent(event); sendProtocolItem(*se); delete se; return false; } return true; }
void Servatrice::shutdownTimeout() { --shutdownMinutes; SessionEvent *se; if (shutdownMinutes) { Event_ServerShutdown event; event.set_reason(shutdownReason.toStdString()); event.set_minutes(shutdownMinutes); se = Server_ProtocolHandler::prepareSessionEvent(event); } else { Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::SERVER_SHUTDOWN); se = Server_ProtocolHandler::prepareSessionEvent(event); } clientsLock.lockForRead(); for (int i = 0; i < clients.size(); ++i) clients[i]->sendProtocolItem(*se); clientsLock.unlock(); delete se; if (!shutdownMinutes) deleteLater(); }
void Servatrice::shutdownTimeout() { // Show every time counter cut in half & every minute for last 5 minutes if (shutdownMinutes <= 5 || shutdownMinutes == nextShutdownMessageMinutes) { if (shutdownMinutes == nextShutdownMessageMinutes) nextShutdownMessageMinutes = shutdownMinutes / 2; SessionEvent *se; if (shutdownMinutes) { Event_ServerShutdown event; event.set_reason(shutdownReason.toStdString()); event.set_minutes(shutdownMinutes); se = Server_ProtocolHandler::prepareSessionEvent(event); } else { Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::SERVER_SHUTDOWN); se = Server_ProtocolHandler::prepareSessionEvent(event); } clientsLock.lockForRead(); for (int i = 0; i < clients.size(); ++i) clients[i]->sendProtocolItem(*se); clientsLock.unlock(); delete se; if (!shutdownMinutes) deleteLater(); } shutdownMinutes--; }
bool ServerSocketInterface::initSession() { Event_ServerIdentification identEvent; identEvent.set_server_name(servatrice->getServerName().toStdString()); identEvent.set_server_version(VERSION_STRING); identEvent.set_protocol_version(protocolVersion); SessionEvent *identSe = prepareSessionEvent(identEvent); sendProtocolItem(*identSe); delete identSe; //limit the number of total users based on configuration settings bool enforceUserLimit = settingsCache->value("security/enable_max_user_limit", false).toBool(); if (enforceUserLimit){ int userLimit = settingsCache->value("security/max_users_total", 500).toInt(); int playerCount = (databaseInterface->getActiveUserCount() + 1); if (playerCount > userLimit){ std::cerr << "Max Users Total Limit Reached, please increase the max_users_total setting." << std::endl; logger->logMessage(QString("Max Users Total Limit Reached, please increase the max_users_total setting."), this); Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::USER_LIMIT_REACHED); SessionEvent *se = prepareSessionEvent(event); sendProtocolItem(*se); delete se; return false; } } //allow unlimited number of connections from the trusted sources QString trustedSources = settingsCache->value("security/trusted_sources","127.0.0.1,::1").toString(); if (trustedSources.contains(socket->peerAddress().toString(),Qt::CaseInsensitive)) return true; int maxUsers = servatrice->getMaxUsersPerAddress(); if ((maxUsers > 0) && (servatrice->getUsersWithAddress(socket->peerAddress()) >= maxUsers)) { Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::TOO_MANY_CONNECTIONS); SessionEvent *se = prepareSessionEvent(event); sendProtocolItem(*se); delete se; return false; } return true; }
Response::ResponseCode ServerSocketInterface::cmdBanFromServer(const Command_BanFromServer &cmd, ResponseContainer & /*rc*/) { if (!sqlInterface->checkSql()) return Response::RespInternalError; QString userName = QString::fromStdString(cmd.user_name()); QString address = QString::fromStdString(cmd.address()); QString trustedSources = settingsCache->value("server/trusted_sources","127.0.0.1,::1").toString(); int minutes = cmd.minutes(); if (trustedSources.contains(address,Qt::CaseInsensitive)) address = ""; QSqlQuery query(sqlInterface->getDatabase()); query.prepare("insert into " + servatrice->getDbPrefix() + "_bans (user_name, ip_address, id_admin, time_from, minutes, reason, visible_reason) values(:user_name, :ip_address, :id_admin, NOW(), :minutes, :reason, :visible_reason)"); query.bindValue(":user_name", userName); query.bindValue(":ip_address", address); query.bindValue(":id_admin", userInfo->id()); query.bindValue(":minutes", minutes); query.bindValue(":reason", QString::fromStdString(cmd.reason())); query.bindValue(":visible_reason", QString::fromStdString(cmd.visible_reason())); sqlInterface->execSqlQuery(query); servatrice->clientsLock.lockForRead(); QList<ServerSocketInterface *> userList = servatrice->getUsersWithAddressAsList(QHostAddress(address)); ServerSocketInterface *user = static_cast<ServerSocketInterface *>(server->getUsers().value(userName)); if (user && !userList.contains(user)) userList.append(user); if (!userList.isEmpty()) { Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::BANNED); if (cmd.has_visible_reason()) event.set_reason_str(cmd.visible_reason()); if (minutes) event.set_end_time(QDateTime::currentDateTime().addSecs(60 * minutes).toTime_t()); for (int i = 0; i < userList.size(); ++i) { SessionEvent *se = userList[i]->prepareSessionEvent(event); userList[i]->sendProtocolItem(*se); delete se; QMetaObject::invokeMethod(userList[i], "prepareDestroy", Qt::QueuedConnection); } } servatrice->clientsLock.unlock(); return Response::RespOk; }
void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &event) { client->disconnectFromServer(); QString reasonStr; switch (event.reason()) { case Event_ConnectionClosed::TOO_MANY_CONNECTIONS: reasonStr = tr("There are too many concurrent connections from your address."); break; case Event_ConnectionClosed::BANNED: { reasonStr = tr("Banned by moderator"); if (event.has_end_time()) reasonStr.append("\n" + tr("Expected end time: %1").arg(QDateTime::fromTime_t(event.end_time()).toString())); else reasonStr.append("\n" + tr("This ban lasts indefinitely.")); if (event.has_reason_str()) reasonStr.append("\n\n" + QString::fromStdString(event.reason_str())); break; } case Event_ConnectionClosed::SERVER_SHUTDOWN: reasonStr = tr("Scheduled server shutdown."); break; case Event_ConnectionClosed::USERNAMEINVALID: reasonStr = tr("Invalid username."); break; default: reasonStr = QString::fromStdString(event.reason_str()); } QMessageBox::critical(this, tr("Connection closed"), tr("The server has terminated your connection.\nReason: %1").arg(reasonStr)); }
AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, QString &reasonStr, int &secondsLeft, QString &clientid, QString &clientVersion, QString & /* connectionType */) { if (name.size() > 35) name = name.left(35); Server_DatabaseInterface *databaseInterface = getDatabaseInterface(); AuthenticationResult authState = databaseInterface->checkUserPassword(session, name, password, clientid, reasonStr, secondsLeft); if (authState == NotLoggedIn || authState == UserIsBanned || authState == UsernameInvalid || authState == UserIsInactive) return authState; ServerInfo_User data = databaseInterface->getUserData(name, true); data.set_address(session->getAddress().toStdString()); name = QString::fromStdString(data.name()); // Compensate for case indifference if (authState == PasswordRight) { if (users.contains(name) || databaseInterface->userSessionExists(name)) { if (users.contains(name)) { qDebug("Session already logged in, logging old session out"); Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::LOGGEDINELSEWERE); event.set_reason_str("You have been logged out due to logging in at another location."); event.set_end_time(QDateTime::currentDateTime().toTime_t()); SessionEvent *se = users.value(name)->prepareSessionEvent(event); users.value(name)->sendProtocolItem(*se); delete se; users.value(name)->prepareDestroy(); } else { qDebug() << "Active session and sessions table inconsistent, please validate session table information for user " << name; } } } else if (authState == UnknownUser) { // Change user name so that no two users have the same names, // don't interfere with registered user names though. if (getRegOnlyServerEnabled()) { qDebug("Login denied: registration required"); databaseInterface->unlockSessionTables(); return RegistrationRequired; } QString tempName = name; int i = 0; while (users.contains(tempName) || databaseInterface->activeUserExists(tempName) || databaseInterface->userSessionExists(tempName)) tempName = name + "_" + QString::number(++i); name = tempName; data.set_name(name.toStdString()); } QWriteLocker locker(&clientsLock); databaseInterface->lockSessionTables(); users.insert(name, session); qDebug() << "Server::loginUser:"******"name=" << name; data.set_session_id(databaseInterface->startSession(name, session->getAddress(), clientid, session->getConnectionType())); databaseInterface->unlockSessionTables(); usersBySessionId.insert(data.session_id(), session); qDebug() << "session id:" << data.session_id(); session->setUserInfo(data); Event_UserJoined event; event.mutable_user_info()->CopyFrom(session->copyUserInfo(false)); SessionEvent *se = Server_ProtocolHandler::prepareSessionEvent(event); for (int i = 0; i < clients.size(); ++i) if (clients[i]->getAcceptsUserListChanges()) clients[i]->sendProtocolItem(*se); delete se; event.mutable_user_info()->CopyFrom(session->copyUserInfo(true, true, true)); locker.unlock(); if (clientid.isEmpty()){ // client id is empty, either out dated client or client has been modified if (getClientIDRequiredEnabled()) return ClientIdRequired; } else { // update users database table with client id databaseInterface->updateUsersClientID(name, clientid); } databaseInterface->updateUsersLastLoginData(name, clientVersion); se = Server_ProtocolHandler::prepareSessionEvent(event); sendIsl_SessionEvent(*se); delete se; return authState; }