#include "Server.h" #include #include #include #include #include #include // Inhalt der LoginServer Klasse aus LoginServer.h // Konstruktor FactoryCraftServer::FactoryCraftServer(InitDatei* zIni) : ReferenceCounter() { Network::Start(100); runningThreads = 0; klients = new RCArray< FCKlient >(); ini = dynamic_cast(zIni->getThis()); id = *zIni->zWert("ServerId"); sslServer = new SSLServer(); sslServer->setPrivateKeyPassword(zIni->zWert("SSLPasswort")->getText()); sslServer->setCertificateFile(zIni->zWert("SSLCert")->getText()); std::cout << "using cert file " << zIni->zWert("SSLCert")->getText() << "\n"; sslServer->setPrivateKeyFile(zIni->zWert("SSLKey")->getText()); std::cout << "using private key " << zIni->zWert("SSLKey")->getText() << "\n"; server = new Server(); std::cout << "Server Port: " << ini->zWert("Port")->getText() << "\n"; if (!server->verbinde((unsigned short)TextZuInt(ini->zWert("Port")->getText(), 10), 10)) { std::cout << "Der Server konnte nicht gestartet werden.\n"; exit(1); } std::cout << "SSL Server Port: " << ini->zWert("SSLPort")->getText() << "\n"; if (!sslServer->verbinde((unsigned short)TextZuInt(ini->zWert("SSLPort")->getText(), 10), 10)) { std::cout << "Der SSL Server konnte nicht gestartet werden.\n"; exit(2); } Game::initialize(zIni->zWert("World")->getText(), zIni->zWert("SaveDir")->getText()); new Framework::AsynchronCall("Server", [this]() { runningThreads++; while (server->isConnected()) { SKlient* klient = server->getKlient(); if (!klient) continue; unsigned short len; klient->setEmpfangTimeout(5000); klient->getNachricht((char*)&len, 2); char* key = new char[len]; klient->getNachricht((char*)key, len); bool bg; klient->getNachricht((char*)&bg, 1); klient->setEmpfangTimeout(0); bool found = 0; EnterCriticalSection(&cs); for (FCKlient* client : *klients) { if (client->matchAuthKey(key, len)) { if (bg) client->setBackgroundClient(klient); else client->setForegroundClient(klient); found = 1; break; } } LeaveCriticalSection(&cs); if (!found) klient->release(); } runningThreads--; }); InitializeCriticalSection(&cs); } // Destruktor FactoryCraftServer::~FactoryCraftServer() { sslServer->trenne(); server->trenne(); while (runningThreads > 0) Sleep(100); sslServer->release(); server->release(); if (klients) klients->release(); ini->release(); Game::INSTANCE->requestStop(); Game::INSTANCE->release(); DeleteCriticalSection(&cs); } // nicht constant void FactoryCraftServer::run() { runningThreads++; while (sslServer->isConnected()) { SSLSKlient* klient = sslServer->getKlient(); if (!klient) continue; Framework::getThreadRegister()->cleanUpClosedThreads(); FCKlient* clHandle = new FCKlient(klient, dynamic_cast(getThis())); EnterCriticalSection(&cs); klients->add(clHandle); LeaveCriticalSection(&cs); clHandle->start(); } runningThreads--; } void FactoryCraftServer::close() { sslServer->trenne(); EnterCriticalSection(&cs); for (int i = 0; i < klients->getEintragAnzahl(); i++) klients->z(i)->absturz(); klients = (RCArray< FCKlient > *)klients->release(); Game::INSTANCE->save(); LeaveCriticalSection(&cs); } bool FactoryCraftServer::absturzKlient(int accountId) { bool gefunden = 0; EnterCriticalSection(&cs); for (int i = 0; i < klients->getEintragAnzahl(); i++) { if (klients->z(i) && klients->z(i)->getAccountId() == accountId) { klients->z(i)->absturz(); klients->remove(i); gefunden = 1; break; } } LeaveCriticalSection(&cs); return gefunden; } bool FactoryCraftServer::removeKlient(FCKlient* zKlient) { bool gefunden = 0; EnterCriticalSection(&cs); for (int i = 0; i < klients->getEintragAnzahl(); i++) { if (klients->z(i) == zKlient) { klients->remove(i); gefunden = 1; break; } } LeaveCriticalSection(&cs); return gefunden; } bool FactoryCraftServer::hatClients() const { return klients->hat(0); } int FactoryCraftServer::getUnencryptedPort() const { return server->getPort(); } char* randomKey(int& len) { len = 1024 + (int)(((double)rand() / RAND_MAX - 0.5) * 512); char* key = new char[len]; for (int i = 0; i < len; i++) key[i] = (char)(((double)rand() / RAND_MAX) * 256); return key; } // Inhalt der LSKlient aus LoginServer.h // Konstruktor FCKlient::FCKlient(SSLSKlient* klient, FactoryCraftServer* ls) : Thread() { this->klient = klient; background = 0; foreground = 0; accountId = 0; this->ls = ls; zGameClient = 0; backgroundReader = 0; foregroundReader = 0; backgroundWriter = 0; foregroundWriter = 0; authKey = randomKey(authKeyLen); } // Destruktor FCKlient::~FCKlient() { if (zGameClient) { zGameClient->logout(); zGameClient = (GameClient*)zGameClient->release(); } if (background) background->release(); if (foreground) foreground->release(); delete backgroundReader; delete foregroundReader; delete backgroundWriter; delete foregroundWriter; klient->release(); ls->release(); delete[] authKey; } // nicht constant void FCKlient::setForegroundClient(SKlient* foreground) { this->foreground = foreground; foregroundReader = new NetworkReader(foreground); foregroundWriter = new NetworkWriter(foreground); if (foreground && background) zGameClient = Game::INSTANCE->addPlayer(dynamic_cast(getThis()), Framework::Text((int)accountId)); new AsynchronCall([this]() { while (this->foreground->waitForNextMessage()) { if (zGameClient) zGameClient->addMessage(foregroundReader); if (!zGameClient) Sleep(100); } zGameClient->logout(); ls->removeKlient(this); }); } void FCKlient::setBackgroundClient(SKlient* background) { this->background = background; backgroundReader = new NetworkReader(background); backgroundWriter = new NetworkWriter(background); if (foreground && background) zGameClient = Game::INSTANCE->addPlayer(dynamic_cast(getThis()), Framework::Text((int)accountId)); new AsynchronCall([this]() { while (this->background->waitForNextMessage()) { if (zGameClient) zGameClient->addMessage(backgroundReader); if (!zGameClient) Sleep(100); } zGameClient->logout(); ls->removeKlient(this); }); } void FCKlient::absturz() { ende(); klient->trenne(); } void FCKlient::thread() { while (1) { char c = 0; if (!klient->getNachricht(&c, 1)) break; else { bool br = 0; switch (c) { case 1: // Klient identifikation { int accountId = 0; klient->getNachricht((char*)&accountId, 4); unsigned char secretLength = 0; klient->getNachricht((char*)&secretLength, 1); char* secret = new char[secretLength + 1]; klient->getNachricht(secret, (int)secretLength); secret[secretLength] = 0; Text data = "{\"account_id\":"; data += accountId; data += ", \"secret\": \""; data += secret; data += "\"}"; bool ok = false; HTTP::Answer* answer = HTTP::PostRequest("/game_client/api/verify_client.php", "koljastrohm-games.com", data, "application/json", 443, true).execute(); if (answer->getStatusCode() == 200) { JSON::JSONObject obj(answer->getData()); if (obj.hasValue("verified")) { JSON::JSONValue* value = obj.getValue("verified"); if (value->getType() == JSON::JSONType::BOOLEAN) { if (((JSON::JSONBool*)value)->getBool()) { this->accountId = accountId; if (zGameClient) { zGameClient->logout(); zGameClient = (GameClient*)zGameClient->release(); } klient->sende("\1", 1); klient->sende((char*)&authKeyLen, 4); klient->sende(authKey, authKeyLen); int port = ls->getUnencryptedPort(); klient->sende((char*)&port, 4); ok = true; } } value->release(); } } answer->release(); delete[]secret; if (!ok) klient->sende("\0", 1); break; } case 2: // Verbindungsende br = 1; if (zGameClient) { zGameClient->logout(); zGameClient = (GameClient*)zGameClient->release(); } klient->sende("\1", 1); break; default: br = 1; break; } if (br) break; } } } int FCKlient::getAccountId() const // gibt die KlientId zurück { return accountId; } NetworkWriter* FCKlient::zBackgroundWriter() const { return backgroundWriter; } NetworkWriter* FCKlient::zForegroundWriter() const { return foregroundWriter; } bool FCKlient::matchAuthKey(char* key, int len) const { if (foreground && background) return 0; if (len != authKeyLen) return 0; for (int i = 0; i < len; i++) { if (key[i] != authKey[i]) return 0; } return 1; }