Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, QObject *parent)
	: QObject(parent),
	  Server_AbstractUserInterface(_server),
	  deleted(false),
	  databaseInterface(_databaseInterface),
	  authState(NotLoggedIn),
	  acceptsUserListChanges(false),
	  acceptsRoomListChanges(false),
	  timeRunning(0),
	  lastDataReceived(0)
{
	connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
}
Example #2
0
Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, int _gameId, const QString &_description, const QString &_password, int _maxPlayers, const QList<int> &_gameTypes, bool _onlyBuddies, bool _onlyRegistered, bool _spectatorsAllowed, bool _spectatorsNeedPassword, bool _spectatorsCanTalk, bool _spectatorsSeeEverything, Server_Room *_room)
	: QObject(),
          room(_room),
          nextPlayerId(0),
          hostId(0),
          creatorInfo(new ServerInfo_User(_creatorInfo)),
          gameStarted(false),
          gameClosed(false),
          gameId(_gameId),
          description(_description),
          password(_password),
          maxPlayers(_maxPlayers),
          gameTypes(_gameTypes),
          activePlayer(-1),
          activePhase(-1),
          onlyBuddies(_onlyBuddies),
          onlyRegistered(_onlyRegistered),
          spectatorsAllowed(_spectatorsAllowed),
          spectatorsNeedPassword(_spectatorsNeedPassword),
          spectatorsCanTalk(_spectatorsCanTalk),
          spectatorsSeeEverything(_spectatorsSeeEverything),
          inactivityCounter(0),
          startTimeOfThisGame(0),
          secondsElapsed(0),
          firstGameStarted(false),
          startTime(QDateTime::currentDateTime()),
          gameMutex(QMutex::Recursive)
{
	currentReplay = new GameReplay;
	currentReplay->set_replay_id(room->getServer()->getDatabaseInterface()->getNextReplayId());
	
	connect(this, SIGNAL(sigStartGameIfReady()), this, SLOT(doStartGameIfReady()), Qt::QueuedConnection);
	
	getInfo(*currentReplay->mutable_game_info());

	if (room->getServer()->getGameShouldPing()) {
		pingClock = new QTimer(this);
		connect(pingClock, SIGNAL(timeout()), this, SLOT(pingClockTimeout()));
		pingClock->start(1000);
	}
}
Example #3
0
bool Servatrice::initServer()
{
    serverName = settings->value("server/name").toString();
    serverId = settings->value("server/id", 0).toInt();
    bool regServerOnly = settings->value("server/regonly", 0).toBool();
        
    const QString authenticationMethodStr = settings->value("authentication/method").toString();
    if (authenticationMethodStr == "sql") {
        authenticationMethod = AuthenticationSql;
    } else {
        if (regServerOnly) {
            qDebug() << "Registration only server enabled but no DB Connection : Error.";
            return false;   
        }
        authenticationMethod = AuthenticationNone;
    }
    
    QString dbTypeStr = settings->value("database/type").toString();
    if (dbTypeStr == "mysql")
        databaseType = DatabaseMySql;
    else
        databaseType = DatabaseNone;
    
    servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this);
    setDatabaseInterface(servatriceDatabaseInterface);
    
    if (databaseType != DatabaseNone) {
        settings->beginGroup("database");
        dbPrefix = settings->value("prefix").toString();
        servatriceDatabaseInterface->initDatabase("QMYSQL",
                              settings->value("hostname").toString(),
                              settings->value("database").toString(),
                              settings->value("user").toString(),
                              settings->value("password").toString());
        settings->endGroup();
        
        updateServerList();
        
        qDebug() << "Clearing previous sessions...";
        servatriceDatabaseInterface->clearSessionTables();
    }
    
    const QString roomMethod = settings->value("rooms/method").toString();
    if (roomMethod == "sql") {
        QSqlQuery query(servatriceDatabaseInterface->getDatabase());
        query.prepare("select id, name, descr, auto_join, join_message from " + dbPrefix + "_rooms order by id asc");
        servatriceDatabaseInterface->execSqlQuery(query);
        while (query.next()) {
            QSqlQuery query2(servatriceDatabaseInterface->getDatabase());
            query2.prepare("select name from " + dbPrefix + "_rooms_gametypes where id_room = :id_room");
            query2.bindValue(":id_room", query.value(0).toInt());
            servatriceDatabaseInterface->execSqlQuery(query2);
            QStringList gameTypes;
            while (query2.next())
                gameTypes.append(query2.value(0).toString());
            
            addRoom(new Server_Room(query.value(0).toInt(),
                                    query.value(1).toString(),
                                    query.value(2).toString(),
                                    query.value(3).toInt(),
                                    query.value(4).toString(),
                                    gameTypes,
                                    this
            ));
        }
    } else {
        int size = settings->beginReadArray("rooms/roomlist");
        for (int i = 0; i < size; ++i) {
            settings->setArrayIndex(i);
            
            QStringList gameTypes;
            int size2 = settings->beginReadArray("game_types");
                for (int j = 0; j < size2; ++j) {
                settings->setArrayIndex(j);
                gameTypes.append(settings->value("name").toString());
            }
            settings->endArray();
                
            Server_Room *newRoom = new Server_Room(
                i,
                settings->value("name").toString(),
                settings->value("description").toString(),
                settings->value("autojoin").toBool(),
                settings->value("joinmessage").toString(),
                gameTypes,
                this
            );
            addRoom(newRoom);
        }
        settings->endArray();
    }
    
    updateLoginMessage();
    
    maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt();
    maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt();
    
    maxUsersPerAddress = settings->value("security/max_users_per_address").toInt();
    messageCountingInterval = settings->value("security/message_counting_interval").toInt();
    maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt();
    maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt();
    maxGamesPerUser = settings->value("security/max_games_per_user").toInt();

	try { if (settings->value("servernetwork/active", 0).toInt()) {
		qDebug() << "Connecting to ISL network.";
		const QString certFileName = settings->value("servernetwork/ssl_cert").toString();
		const QString keyFileName = settings->value("servernetwork/ssl_key").toString();
		qDebug() << "Loading certificate...";
		QFile certFile(certFileName);
		if (!certFile.open(QIODevice::ReadOnly))
			throw QString("Error opening certificate file: %1").arg(certFileName);
		QSslCertificate cert(&certFile);
#if QT_VERSION < 0x050000
		if (!cert.isValid())
			throw(QString("Invalid certificate."));
#else
		const QDateTime currentTime = QDateTime::currentDateTime();
		if(currentTime < cert.effectiveDate() ||
			currentTime > cert.expiryDate() ||
			cert.isBlacklisted())
			throw(QString("Invalid certificate."));
#endif
		qDebug() << "Loading private key...";
		QFile keyFile(keyFileName);
		if (!keyFile.open(QIODevice::ReadOnly))
			throw QString("Error opening private key file: %1").arg(keyFileName);
		QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
		if (key.isNull())
			throw QString("Invalid private key.");
		
		QMutableListIterator<ServerProperties> serverIterator(serverList);
		while (serverIterator.hasNext()) {
			const ServerProperties &prop = serverIterator.next();
			if (prop.cert == cert) {
				serverIterator.remove();
				continue;
			}
			
			QThread *thread = new QThread;
			thread->setObjectName("isl_" + QString::number(prop.id));
			connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
			
			IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this);
			interface->moveToThread(thread);
			connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));
			
			thread->start();
			QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
		}
			
		const int networkPort = settings->value("servernetwork/port", 14747).toInt();
		qDebug() << "Starting ISL server on port" << networkPort;
		
		islServer = new Servatrice_IslServer(this, cert, key, this);
		if (islServer->listen(QHostAddress::Any, networkPort))
			qDebug() << "ISL server listening.";
		else
			throw QString("islServer->listen()");
	} } catch (QString error) {
		qDebug() << "ERROR --" << error;
		return false;
	}
	
	pingClock = new QTimer(this);
	connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
	pingClock->start(1000);
	
	int statusUpdateTime = settings->value("server/statusupdate").toInt();
	statusUpdateClock = new QTimer(this);
	connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
	if (statusUpdateTime != 0) {
		qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
		statusUpdateClock->start(statusUpdateTime);
	}
	
	const int numberPools = settings->value("server/number_pools", 1).toInt();
	gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
	gameServer->setMaxPendingConnections(1000);
	const int gamePort = settings->value("server/port", 4747).toInt();
	qDebug() << "Starting server on port" << gamePort;
	if (gameServer->listen(QHostAddress::Any, gamePort))
		qDebug() << "Server listening.";
	else {
		qDebug() << "gameServer->listen(): Error.";
		return false;
	}
	return true;
}
Example #4
0
bool Servatrice::initServer()
{
    serverName = settingsCache->value("server/name", "My Cockatrice server").toString();
    serverId = settingsCache->value("server/id", 0).toInt();
    clientIdRequired = settingsCache->value("server/requireclientid",0).toBool();
    regServerOnly = settingsCache->value("authentication/regonly", 0).toBool();

    const QString authenticationMethodStr = settingsCache->value("authentication/method").toString();
    if (authenticationMethodStr == "sql") {
        qDebug() << "Authenticating method: sql";
        authenticationMethod = AuthenticationSql;
    } else if(authenticationMethodStr == "password") {
        qDebug() << "Authenticating method: password";
        authenticationMethod = AuthenticationPassword;
    } else {
        if (regServerOnly) {
            qDebug() << "Registration only server enabled but no authentication method defined: Error.";
            return false;
        }

        qDebug() << "Authenticating method: none";
        authenticationMethod = AuthenticationNone;
    }

    qDebug() << "Store Replays: " << settingsCache->value("game/store_replays", true).toBool();
    qDebug() << "Client ID Required: " << clientIdRequired;
    bool maxUserLimitEnabled = settingsCache->value("security/enable_max_user_limit", false).toBool();
    qDebug() << "Maximum user limit enabled: " << maxUserLimitEnabled;

    if (maxUserLimitEnabled){
        int maxUserLimit = settingsCache->value("security/max_users_total", 500).toInt();
        qDebug() << "Maximum total user limit: " << maxUserLimit;
        int maxTcpUserLimit = settingsCache->value("security/max_users_tcp", 500).toInt();
        qDebug() << "Maximum tcp user limit: " << maxTcpUserLimit;
        int maxWebsocketUserLimit = settingsCache->value("security/max_users_websocket", 500).toInt();
        qDebug() << "Maximum websocket user limit: " << maxWebsocketUserLimit;
    }

    bool registrationEnabled = settingsCache->value("registration/enabled", false).toBool();
    bool requireEmailForRegistration = settingsCache->value("registration/requireemail", true).toBool();
    bool requireEmailActivation = settingsCache->value("registration/requireemailactivation", true).toBool();

    qDebug() << "Accept registered users only: " << regServerOnly;
    qDebug() << "Registration enabled: " << registrationEnabled;
    if (registrationEnabled)
    {
        qDebug() << "Require email address to register: " << requireEmailForRegistration;
        qDebug() << "Require email activation via token: " << requireEmailActivation;
    }

    FeatureSet features;
    features.initalizeFeatureList(serverRequiredFeatureList);
    requiredFeatures = settingsCache->value("server/requiredfeatures","").toString();
    QStringList listReqFeatures = requiredFeatures.split(",", QString::SkipEmptyParts);
    if (!listReqFeatures.isEmpty())
        foreach(QString reqFeature, listReqFeatures)
            features.enableRequiredFeature(serverRequiredFeatureList,reqFeature);

    qDebug() << "Required client features: " << serverRequiredFeatureList;

    QString dbTypeStr = settingsCache->value("database/type").toString();
    if (dbTypeStr == "mysql")
        databaseType = DatabaseMySql;
    else
        databaseType = DatabaseNone;

    servatriceDatabaseInterface = new Servatrice_DatabaseInterface(-1, this);
    setDatabaseInterface(servatriceDatabaseInterface);

    if (databaseType != DatabaseNone) {
        settingsCache->beginGroup("database");
        dbPrefix = settingsCache->value("prefix").toString();
        bool dbOpened =
            servatriceDatabaseInterface->initDatabase("QMYSQL",
                 settingsCache->value("hostname").toString(),
                 settingsCache->value("database").toString(),
                 settingsCache->value("user").toString(),
                 settingsCache->value("password").toString());
        settingsCache->endGroup();
        if (!dbOpened) {
            qDebug() << "Failed to open database";
            return false;
        }

        updateServerList();

        qDebug() << "Clearing previous sessions...";
        servatriceDatabaseInterface->clearSessionTables();
    }

    const QString roomMethod = settingsCache->value("rooms/method").toString();
    if (roomMethod == "sql") {
        QSqlQuery *query = servatriceDatabaseInterface->prepareQuery("select id, name, descr, permissionlevel, auto_join, join_message, chat_history_size from {prefix}_rooms where id_server = :id_server order by id asc");
        query->bindValue(":id_server", serverId);
        servatriceDatabaseInterface->execSqlQuery(query);
        while (query->next()) {
            QSqlQuery *query2 = servatriceDatabaseInterface->prepareQuery("select name from {prefix}_rooms_gametypes where id_room = :id_room AND id_server = :id_server");
            query2->bindValue(":id_server", serverId);
            query2->bindValue(":id_room", query->value(0).toInt());
            servatriceDatabaseInterface->execSqlQuery(query2);
            QStringList gameTypes;
            while (query2->next())
                gameTypes.append(query2->value(0).toString());

            addRoom(new Server_Room(query->value(0).toInt(),
                                    query->value(6).toInt(),
                                    query->value(1).toString(),
                                    query->value(2).toString(),
                                    query->value(3).toString().toLower(),
                                    query->value(4).toInt(),
                                    query->value(5).toString(),
                                    gameTypes,
                                    this
            ));
        }
    } else {
        int size = settingsCache->beginReadArray("rooms/roomlist");
        for (int i = 0; i < size; ++i) {
            settingsCache->setArrayIndex(i);

            QStringList gameTypes;
            int size2 = settingsCache->beginReadArray("game_types");
                for (int j = 0; j < size2; ++j) {
                settingsCache->setArrayIndex(j);
                gameTypes.append(settingsCache->value("name").toString());
            }
            settingsCache->endArray();

            Server_Room *newRoom = new Server_Room(
                i,
                settingsCache->value("chathistorysize").toInt(),
                settingsCache->value("name").toString(),
                settingsCache->value("description").toString(),
                settingsCache->value("permissionlevel").toString().toLower(),
                settingsCache->value("autojoin").toBool(),
                settingsCache->value("joinmessage").toString(),
                gameTypes,
                this
            );
            addRoom(newRoom);
        }

        if(size==0)
        {
            // no room defined in config, add a dummy one
            Server_Room *newRoom = new Server_Room(
                0,
                100,
                "General room",
                "Play anything here.",
                "none",
                true,
                "",
                QStringList("Standard"),
                this
            );
            addRoom(newRoom);
        }

        settingsCache->endArray();
    }

    updateLoginMessage();

    maxGameInactivityTime = settingsCache->value("game/max_game_inactivity_time", 120).toInt();
    maxPlayerInactivityTime = settingsCache->value("server/max_player_inactivity_time", 15).toInt();
    pingClockInterval = settingsCache->value("server/clientkeepalive", 1).toInt();
    maxUsersPerAddress = settingsCache->value("security/max_users_per_address", 4).toInt();
    messageCountingInterval = settingsCache->value("security/message_counting_interval", 10).toInt();
    maxMessageCountPerInterval = settingsCache->value("security/max_message_count_per_interval", 15).toInt();
    maxMessageSizePerInterval = settingsCache->value("security/max_message_size_per_interval", 1000).toInt();
    maxGamesPerUser = settingsCache->value("security/max_games_per_user", 5).toInt();
    commandCountingInterval = settingsCache->value("game/command_counting_interval", 10).toInt();
    maxCommandCountPerInterval = settingsCache->value("game/max_command_count_per_interval", 20).toInt();

    try { if (settingsCache->value("servernetwork/active", 0).toInt()) {
        qDebug() << "Connecting to ISL network.";
        const QString certFileName = settingsCache->value("servernetwork/ssl_cert").toString();
        const QString keyFileName = settingsCache->value("servernetwork/ssl_key").toString();
        qDebug() << "Loading certificate...";
        QFile certFile(certFileName);
        if (!certFile.open(QIODevice::ReadOnly))
            throw QString("Error opening certificate file: %1").arg(certFileName);
        QSslCertificate cert(&certFile);

        const QDateTime currentTime = QDateTime::currentDateTime();
        if(currentTime < cert.effectiveDate() ||
            currentTime > cert.expiryDate() ||
            cert.isBlacklisted())
            throw(QString("Invalid certificate."));

        qDebug() << "Loading private key...";
        QFile keyFile(keyFileName);
        if (!keyFile.open(QIODevice::ReadOnly))
            throw QString("Error opening private key file: %1").arg(keyFileName);
        QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
        if (key.isNull())
            throw QString("Invalid private key.");

        QMutableListIterator<ServerProperties> serverIterator(serverList);
        while (serverIterator.hasNext()) {
            const ServerProperties &prop = serverIterator.next();
            if (prop.cert == cert) {
                serverIterator.remove();
                continue;
            }

            QThread *thread = new QThread;
            thread->setObjectName("isl_" + QString::number(prop.id));
            connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

            IslInterface *interface = new IslInterface(prop.id, prop.hostname, prop.address.toString(), prop.controlPort, prop.cert, cert, key, this);
            interface->moveToThread(thread);
            connect(interface, SIGNAL(destroyed()), thread, SLOT(quit()));

            thread->start();
            QMetaObject::invokeMethod(interface, "initClient", Qt::BlockingQueuedConnection);
        }

        const int networkPort = settingsCache->value("servernetwork/port", 14747).toInt();
        qDebug() << "Starting ISL server on port" << networkPort;

        islServer = new Servatrice_IslServer(this, cert, key, this);
        if (islServer->listen(QHostAddress::Any, networkPort))
            qDebug() << "ISL server listening.";
        else
            throw QString("islServer->listen()");
    } } catch (QString error) {
        qDebug() << "ERROR --" << error;
        return false;
    }

    pingClock = new QTimer(this);
    connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
    pingClock->start(pingClockInterval * 1000);

    int statusUpdateTime = settingsCache->value("server/statusupdate", 15000).toInt();
    statusUpdateClock = new QTimer(this);
    connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
    if (statusUpdateTime != 0) {
        qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
        statusUpdateClock->start(statusUpdateTime);
    }

    // SOCKET SERVER
    const int numberPools = settingsCache->value("server/number_pools", 1).toInt();
    if(numberPools > 0)
    {
        gameServer = new Servatrice_GameServer(this, numberPools, servatriceDatabaseInterface->getDatabase(), this);
        gameServer->setMaxPendingConnections(1000);
        const int gamePort = settingsCache->value("server/port", 4747).toInt();
        qDebug() << "Starting server on port" << gamePort;
        if (gameServer->listen(QHostAddress::Any, gamePort))
            qDebug() << "Server listening.";
        else {
            qDebug() << "gameServer->listen(): Error:" << gameServer->errorString();
            return false;
        }
    }

#if QT_VERSION > 0x050300
    // WEBSOCKET SERVER
    const int wesocketNumberPools = settingsCache->value("server/websocket_number_pools", 1).toInt();
    if(wesocketNumberPools > 0)
    {
        websocketGameServer = new Servatrice_WebsocketGameServer(this, wesocketNumberPools, servatriceDatabaseInterface->getDatabase(), this);
        websocketGameServer->setMaxPendingConnections(1000);
        const int websocketGamePort = settingsCache->value("server/websocket_port", 4748).toInt();
        qDebug() << "Starting websocket server on port" << websocketGamePort;
        if (websocketGameServer->listen(QHostAddress::Any, websocketGamePort))
            qDebug() << "Websocket server listening.";
        else {
            qDebug() << "websocketGameServer->listen(): Error:" << websocketGameServer->errorString();
            return false;
        }
    }
#endif
    return true;
}
Example #5
0
Servatrice::Servatrice(QSettings *_settings, QObject *parent)
	: Server(parent), dbMutex(QMutex::Recursive), settings(_settings), uptime(0), shutdownTimer(0)
{
	pingClock = new QTimer(this);
	connect(pingClock, SIGNAL(timeout()), this, SIGNAL(pingClockTimeout()));
	pingClock->start(1000);
	
	ProtocolItem::initializeHash();
	
	serverId = settings->value("server/id", 0).toInt();
	int statusUpdateTime = settings->value("server/statusupdate").toInt();
	statusUpdateClock = new QTimer(this);
	connect(statusUpdateClock, SIGNAL(timeout()), this, SLOT(statusUpdate()));
	if (statusUpdateTime != 0) {
		qDebug() << "Starting status update clock, interval " << statusUpdateTime << " ms";
		statusUpdateClock->start(statusUpdateTime);
	}
	
	threaded = settings->value("server/threaded", false).toInt();
	tcpServer = new Servatrice_TcpServer(this, threaded, this);
	int port = settings->value("server/port", 4747).toInt();
	qDebug() << "Starting server on port" << port;
	if (tcpServer->listen(QHostAddress::Any, port))
		qDebug() << "Server listening.";
	else
		qDebug() << "tcpServer->listen(): Error.";
	
	QString dbType = settings->value("database/type").toString();
	dbPrefix = settings->value("database/prefix").toString();
	if (dbType == "mysql")
		openDatabase();
	
	int size = settings->beginReadArray("rooms");
	for (int i = 0; i < size; ++i) {
	  	settings->setArrayIndex(i);
		
		QStringList gameTypes;
		int size2 = settings->beginReadArray("game_types");
		for (int j = 0; j < size2; ++j) {
			settings->setArrayIndex(j);
			gameTypes.append(settings->value("name").toString());
		}
		settings->endArray();
			
		Server_Room *newRoom = new Server_Room(
			i,
			settings->value("name").toString(),
			settings->value("description").toString(),
			settings->value("autojoin").toBool(),
			settings->value("joinmessage").toString(),
			gameTypes,
			this
		);
		addRoom(newRoom);
	}
	settings->endArray();
	
	updateLoginMessage();
	
	maxGameInactivityTime = settings->value("game/max_game_inactivity_time").toInt();
	maxPlayerInactivityTime = settings->value("game/max_player_inactivity_time").toInt();
	
	maxUsersPerAddress = settings->value("security/max_users_per_address").toInt();
	messageCountingInterval = settings->value("security/message_counting_interval").toInt();
	maxMessageCountPerInterval = settings->value("security/max_message_count_per_interval").toInt();
	maxMessageSizePerInterval = settings->value("security/max_message_size_per_interval").toInt();
	maxGamesPerUser = settings->value("security/max_games_per_user").toInt();
}
Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, QObject *parent)
	: QObject(parent), server(_server), authState(PasswordWrong), acceptsUserListChanges(false), acceptsRoomListChanges(false), userInfo(0), lastCommandTime(QDateTime::currentDateTime())
{
	connect(server, SIGNAL(pingClockTimeout()), this, SLOT(pingClockTimeout()));
}