#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; }