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;
}
Example #2
0
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();
}
Example #3
0
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;
}
Example #6
0
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));
}
Example #7
0
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;
}