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())); }
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); } }
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; }
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; }
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())); }