#include "MinigameServer.h" #include #include #include // Inhalt der LoginServer Klasse aus LoginServer.h // Konstruktor MinigameServer::MinigameServer( InitDatei *zIni ) : Thread() { Network::Start( 100 ); std::cout << "MS: Verbindung mit Datenbank wird hergestellt...\n"; db = new MSDatenbank( zIni ); klientAnzahl = 0; klients = new RCArray< MSKlient >(); empfangen = 0; gesendet = 0; fehler = new Text(); ini = zIni->getThis(); id = *zIni->zWert( "ServerId" ); server = new Server(); aServer = new Server(); std::cout << "MS: Starten des Admin Servers...\n"; if( !aServer->verbinde( (unsigned short)TextZuInt( ini->zWert( "AdminServerPort" )->getText(), 10 ), 10 ) ) { std::cout << "MS: Der Admin Server konnte nicht gestartet werden. Das Programm wird beendet.\n"; exit( 1 ); } db->setServerStatus( id, 2 ); end = 0; nichtPausiert = 0; InitializeCriticalSection( &cs ); ref = 1; if( zIni->zWert( "Aktiv" )->istGleich( "TRUE" ) ) { serverStarten(); serverFortsetzen(); } } // Destruktor MinigameServer::~MinigameServer() { fehler->release(); server->trenne(); server->release(); aServer->trenne(); aServer->release(); if( klients ) klients->release(); ini->release(); db->release(); DeleteCriticalSection( &cs ); } // nicht constant void MinigameServer::runn() { while( !end ) { SKlient *klient; klient = aServer->getKlient(); if( end && klient ) { klient->trenne(); klient = klient->release(); Sleep( 1000 ); return; } if( !klient ) return; MSAKlient *clHandle = new MSAKlient( klient, getThis() ); clHandle->start(); } } void MinigameServer::thread() { while( 1 ) { SKlient *klient; klient = server->getKlient(); if( !klient ) break; Framework::getThreadRegister()->cleanUpClosedThreads(); MSKlient *clHandle = new MSKlient( klient, getThis() ); EnterCriticalSection( &cs ); klients->set( clHandle, klientAnzahl ); klientAnzahl++; LeaveCriticalSection( &cs ); clHandle->start(); } } void MinigameServer::close() { db->setServerStatus( id, 1 ); server->trenne(); #ifdef WIN32 warteAufThread( 1000 ); #endif EnterCriticalSection( &cs ); for( int i = 0; i < klientAnzahl; i++ ) klients->z( i )->absturz(); klients = klients->release(); klientAnzahl = 0; LeaveCriticalSection( &cs ); ende(); run = 0; end = 1; Klient *klient = new Klient(); klient->verbinde( aServer->getPort(), "127.0.0.1" ); Sleep( 500 ); aServer->trenne(); klient->release(); } bool MinigameServer::serverStarten() { if( nichtPausiert ) { fehler->setText( "Der Server konnte nicht gestartet werden: Der Server läuft bereits." ); return 0; } if( server ) server->release(); server = new Server(); if( server->verbinde( (unsigned short)TextZuInt( ini->zWert( "ServerPort" )->getText(), 10 ), 10 ) ) { nichtPausiert = 1; start(); return 1; } else { serverBeenden(); fehler->setText( "Der Server konnte nicht gestartet werden: Eventuell ist der Port in benutzung." ); return 0; } } bool MinigameServer::serverPause() { if( !nichtPausiert ) { fehler->setText( "Der Server konnte nicht pausiert werden: Der Server läuft nicht." ); return 0; } if( !db->setServerStatus( id, 2 ) ) { fehler->setText( "Der Server konnte nicht pausiert werden: " ); fehler->append( db->getLetzterFehler() ); return 0; } return 1; } bool MinigameServer::serverFortsetzen() { if( !nichtPausiert ) { fehler->setText( "Der Server konnte nicht fortgesetzt werden: Der Server läuft nicht." ); return 0; } if( !db->setServerStatus( id, 3 ) ) { fehler->setText( "Der Server konnte nicht fortgesetzt werden: " ); fehler->append( db->getLetzterFehler() ); return 0; } return 1; } bool MinigameServer::serverBeenden() { if( !nichtPausiert ) { fehler->setText( "Der Server konnte nicht beendet werden: Der Server läuft nicht." ); return 0; } if( db->serverIstNichtPausiert( id ) ) { fehler->setText( "Der Server konnte nicht beendet werden: Der Server muss erst pausiert werden." ); return 0; } nichtPausiert = 0; ende(); if( server ) server->trenne(); return 1; } bool MinigameServer::setMaxKlients( int mc ) { if( !db->setMaxClients( id, mc ) ) { fehler->setText( "Die maximale Anzahl der Clients konnte nicht gesetzt werden:\n" ); fehler->append( db->getLetzterFehler() ); return 0; } ini->setWert( "MaxClients", Text() += mc ); return 1; } bool MinigameServer::absturzKlient( int klientId ) { bool gefunden = 0; EnterCriticalSection( &cs ); for( int i = 0; i < klientAnzahl; i++ ) { if( klients->z( i ) && klients->z( i )->getKlientNummer() == klientId ) { klients->z( i )->absturz(); klients->remove( i ); klientAnzahl--; gefunden = 1; break; } } LeaveCriticalSection( &cs ); return gefunden; } bool MinigameServer::removeKlient( MSKlient *zKlient ) { bool gefunden = 0; EnterCriticalSection( &cs ); for( int i = 0; i < klientAnzahl; i++ ) { if( klients->z( i ) == zKlient ) { klients->remove( i ); klientAnzahl--; gefunden = 1; break; } } LeaveCriticalSection( &cs ); return gefunden; } void MinigameServer::addGesendet( int bytes ) { gesendet += bytes; } void MinigameServer::addEmpfangen( int bytes ) { empfangen += bytes; } // constant bool MinigameServer::istAn() const { return db->serverIstNichtPausiert( id ); } Server *MinigameServer::zServer() const { return server; } MSDatenbank *MinigameServer::zDB() const { return db; } bool MinigameServer::hatClients() const { return klientAnzahl > 0; } int MinigameServer::getId() const { return id; } char *MinigameServer::getLetzterFehler() const { return fehler->getText(); } InitDatei *MinigameServer::zInit() const { return ini; } // Reference Counting MinigameServer *MinigameServer::getThis() { ref++; return this; } MinigameServer *MinigameServer::release() { ref--; if( !ref ) delete this; return 0; } // Inhalt der LSAKlient Klasse aus LoginServer.h // Konstruktor MSAKlient::MSAKlient( SKlient *klient, MinigameServer *ls ) : Thread() { this->klient = klient; unsigned char key[ 20 ] = { 168, 13, 57, 219, 1, 54, 176, 97, 163, 80, 63, 101, 137, 132, 45, 103, 204, 225, 53, 197 }; klient->setSendeKey( (char*)key, 20 ); klient->setEmpfangKey( (char*)key, 20 ); name = new Text( "" ); passwort = new Text( "" ); adminId = 0; version = 0; this->ms = ls; } // Destruktor MSAKlient::~MSAKlient() { klient->trenne(); klient->release(); ms->release(); name->release(); passwort->release(); } // nicht constant void MSAKlient::thread() { while( 1 ) { char c = 0; if( !klient->getNachrichtEncrypted( &c, 1 ) ) break; else { bool br = 0; switch( c ) { case 1: // Login if( 1 ) { klient->sendeEncrypted( "\1", 1 ); unsigned char nLen = 0; klient->getNachrichtEncrypted( (char*)&nLen, 1 ); char *n = new char[ nLen + 1 ]; n[ (int)nLen ] = 0; if( nLen ) klient->getNachrichtEncrypted( n, nLen ); unsigned char pLen = 0; klient->getNachrichtEncrypted( (char*)&pLen, 1 ); char *p = new char[ pLen + 1 ]; p[ (int)pLen ] = 0; if( pLen ) klient->getNachrichtEncrypted( p, pLen ); int adminId = ms->zDB()->istAdministrator( n, p ); if( adminId ) { klient->sendeEncrypted( "\1", 1 ); name->setText( n ); passwort->setText( p ); this->adminId = adminId; } else errorZuKlient( "Falsche Kombination aus Name und Passwort." ); delete[] n; delete[] p; } break; case 2: // Logout adminId = 0; name->setText( "" ); passwort->setText( "" ); klient->sendeEncrypted( "\1", 1 ); break; case 3: // Trennen br = 1; klient->sendeEncrypted( "\1", 1 ); break; case 4: // Server starten if( !adminId ) errorZuKlient( "Du musst dich einloggen." ); else { if( ms->zDB()->adminHatRecht( adminId, Admin_Recht::MSStarten ) ) { if( !ms->serverStarten() ) { Text *err = new Text(); err->append( ms->getLetzterFehler() ); errorZuKlient( err->getText() ); err->release(); } else klient->sendeEncrypted( "\1", 1 ); } else errorZuKlient( "Du bist nicht berechtigt den Server zu starten." ); } break; case 5: // Server beenden if( !adminId ) errorZuKlient( "Du musst dich einloggen." ); else { if( ms->zDB()->adminHatRecht( adminId, Admin_Recht::MSBeenden ) ) { if( ms->serverBeenden() ) klient->sendeEncrypted( "\1", 1 ); else { Text *err = new Text(); err->append( ms->getLetzterFehler() ); errorZuKlient( err->getText() ); err->release(); } } else errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." ); } break; case 6: // Programm Schließen if( !adminId ) errorZuKlient( "Du musst dich einloggen." ); else { bool ok = 0; if( ms->isRunning() ) { if( ms->zDB()->adminHatRecht( adminId, Admin_Recht::MSBeenden ) ) { if( ms->serverBeenden() ) ok = 1; else { Text *err = new Text(); err->append( ms->getLetzterFehler() ); errorZuKlient( err->getText() ); err->release(); } } else errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." ); } else ok = 1; if( ok && ms->hatClients() ) { errorZuKlient( "Es sind noch Klients Online. Bitte versuche es später erneut." ); break; } if( ok ) { klient->sendeEncrypted( "\1", 1 ); std::cout << "MS: Der Server wird von Benutzer " << adminId << " heruntergefahren.\n"; ms->close(); br = 1; } } break; case 7: // Progtamm abstürzen if( !adminId ) errorZuKlient( "Du musst dich einloggen." ); else { bool ok = 0; if( ms->isRunning() ) { if( ms->zDB()->adminHatRecht( adminId, Admin_Recht::MSBeenden ) ) { ms->serverBeenden(); ok = 1; } else errorZuKlient( "Du bist nicht berechtigt den Server zu beenden." ); } else ok = 1; if( ok ) { klient->sendeEncrypted( "\1", 1 ); std::cout << "MS: Der Server wurde von Benutzer " << adminId << " terminiert.\n"; ms->close(); br = 1; } } break; case 8: // Status Frage if( 1 ) { char status = 0; if( ms->isRunning() ) { status = 1; if( ms->istAn() ) status = 2; } klient->sendeEncrypted( "\1", 1 ); klient->sendeEncrypted( &status, 1 ); } break; case 9: // Server pausieren if( !adminId ) errorZuKlient( "Du musst dich einloggen." ); else { klient->sendeEncrypted( "\1", 1 ); char pause = 0; klient->getNachrichtEncrypted( &pause, 1 ); if( ms->zDB()->adminHatRecht( adminId, Admin_Recht::MSPausieren ) ) { bool ok = 0; if( pause ) ok = ms->serverPause(); else ok = ms->serverFortsetzen(); if( ok ) klient->sendeEncrypted( "\1", 1 ); else { Text *err = new Text(); err->append( ms->getLetzterFehler() ); errorZuKlient( err->getText() ); err->release(); } } else { if( pause ) errorZuKlient( "Du bist nicht berechtigt den Server zu pausieren." ); else errorZuKlient( "Du bist nicht berechtigt den Server fortzusetzen." ); } } break; case 0xA: // maximale Anzahl der Clients setzen if( !adminId ) errorZuKlient( "Du musst dich einloggen." ); else { klient->sendeEncrypted( "\1", 1 ); int maxC = 0; klient->getNachrichtEncrypted( (char*)&maxC, 4 ); if( ms->zDB()->adminHatRecht( adminId, Admin_Recht::MSMCChange ) ) { if( ms->setMaxKlients( maxC ) ) klient->sendeEncrypted( "\1", 1 ); else { Text *err = new Text(); err->append( ms->getLetzterFehler() ); errorZuKlient( err->getText() ); err->release(); } } else errorZuKlient( "Du bist nicht berechtigt die maximale Anzahl der Clients zu verändern." ); } break; case 0xC: // klient absturtz if( 1 ) { klient->sendeEncrypted( "\1", 1 ); int klientId = 0; klient->getNachrichtEncrypted( (char*)&klientId, 4 ); if( klientId && ms->absturzKlient( klientId ) ) klient->sendeEncrypted( "\1", 1 ); else klient->sendeEncrypted( "\0", 1 ); } break; default: errorZuKlient( "Unbekannte Nachricht!" ); break; } if( br ) break; ms->addEmpfangen( klient->getDownloadBytes( 1 ) ); ms->addGesendet( klient->getUploadBytes( 1 ) ); } } ms->addEmpfangen( klient->getDownloadBytes( 1 ) ); ms->addGesendet( klient->getUploadBytes( 1 ) ); delete this; } void MSAKlient::errorZuKlient( const char *nachricht ) const // sendet eine Fehlernachricht zum Klient { klient->sendeEncrypted( "\3", 1 ); char len = (char)textLength( nachricht ); klient->sendeEncrypted( &len, 1 ); klient->sendeEncrypted( nachricht, len ); } // Inhalt der LSKlient aus LoginServer.h // Konstruktor MSKlient::MSKlient( SKlient *klient, MinigameServer *ls ) : Thread() { this->klient = klient; unsigned char key[ 20 ] = { 88, 103, 192, 232, 69, 54, 57, 3, 239, 138, 234, 172, 126, 72, 81, 55, 205, 97, 59, 255 }; klient->setSendeKey( (char*)key, 20 ); klient->setEmpfangKey( (char*)key, 20 ); klientNummer = 0; this->ms = ls; ref = 1; } // Destruktor MSKlient::~MSKlient() { klient->release(); ms->release(); } // nicht constant void MSKlient::absturz() { ende(); klient->trenne(); ms->zDB()->unregisterKlient( klientNummer, ms->getId() ); } void MSKlient::thread() { while( 1 ) { char c = 0; if( !klient->getNachrichtEncrypted( &c, 1 ) ) break; else { bool br = 0; switch( c ) { case 1: // Klient identifikation klient->getNachrichtEncrypted( (char*)&klientNummer, 4 ); if( !ms->zDB()->proveKlient( klientNummer, ms->getId() ) ) { klientNummer = 0; errorZuKlient( "Du bist nicht für diesen Server eingetragen" ); } else { Text *key = ms->zDB()->getKlientKey( klientNummer ); if( !key ) errorZuKlient( "Es konnte kein Schlüssel ermittelt werden." ); else { klient->sendeEncrypted( "\1", 1 ); klient->setEmpfangKey( *key, key->getLength() ); klient->setSendeKey( *key, key->getLength() ); key->release(); } } break; case 2: // Main / Erhaltung Server message if( 1 ) { char befehl = 0; klient->getNachrichtEncrypted( &befehl, 1 ); switch( befehl ) { case 2: // klient absturtz if( 1 ) { int klientId = 0; klient->getNachrichtEncrypted( (char*)&klientId, 4 ); if( klientId && ms->absturzKlient( klientId ) ) klient->sendeEncrypted( "\1", 1 ); else klient->sendeEncrypted( "\0", 1 ); } break; default: errorZuKlient( "Befehl nicht bekannt!" ); break; } } break; case 3: // Verbindungsende br = 1; klient->sendeEncrypted( "\1", 1 ); break; case 4: // unregister Klient if( !klientNummer ) { errorZuKlient( "Du bist nicht Identifiziert." ); break; } ms->zDB()->unregisterKlient( klientNummer, ms->getId() ); klient->sendeEncrypted( "\1", 1 ); break; case 0x5: // ping if( !klientNummer ) { errorZuKlient( "Du bist nicht Identifiziert." ); break; } klient->sendeEncrypted( "\1", 1 ); break; case 0x6: // Get Minigame Option List { klient->sendeEncrypted( "\1", 1 ); unsigned char l = 0; klient->getNachrichtEncrypted( (char*)&l, 1 ); char *mName = new char[ l ]; mName[ (int)l ] = 0; klient->getNachrichtEncrypted( mName, l ); RCArray< Text > oList; int anz = ms->zDB()->getMinigameOptionList( mName, &oList ); delete[] mName; klient->sendeEncrypted( (char*)&anz, 4 ); for( auto t = oList.getArray(); t.set && t.var; t++ ) { l = (char)t.var->getLength(); klient->sendeEncrypted( &l, 1 ); klient->sendeEncrypted( t.var->getText(), l ); } break; } case 0x7: // Get Minigame Bestscore List { klient->sendeEncrypted( "\1", 1 ); unsigned char l = 0; klient->getNachrichtEncrypted( (char*)&l, 1 ); char *mName = new char[ l ]; mName[ (int)l ] = 0; klient->getNachrichtEncrypted( mName, l ); Array< int > sList; RCArray< Text > pList; RCArray< Text > oList; int anz = ms->zDB()->getMinigameBestscore( mName, &sList, &pList, &oList ); delete[] mName; klient->sendeEncrypted( (char*)&anz, 4 ); for( int i = 0; i < anz; i++ ) { int s = sList.get( i ); klient->sendeEncrypted( (char*)&s, 4 ); l = (char)pList.z( i )->getLength(); klient->sendeEncrypted( &l, 1 ); klient->sendeEncrypted( pList.z( i )->getText(), l ); l = (char)oList.z( i )->getLength(); klient->sendeEncrypted( &l, 1 ); klient->sendeEncrypted( oList.z( i )->getText(), l ); } break; } case 0x8: // Get Minigame Option Bestscore { klient->sendeEncrypted( "\1", 1 ); unsigned char l = 0; klient->getNachrichtEncrypted( (char*)&l, 1 ); char *mName = new char[ l ]; mName[ (int)l ] = 0; klient->getNachrichtEncrypted( mName, l ); klient->getNachrichtEncrypted( (char*)&l, 1 ); char *oName = new char[ l ]; oName[ (int)l ] = 0; klient->getNachrichtEncrypted( oName, l ); Text player; int score = ms->zDB()->getMinigameBestscore( oName, mName, &player ); delete[] mName; delete[] oName; klient->sendeEncrypted( (char*)&score, 4 ); if( score ) { l = (char)player.getLength(); klient->sendeEncrypted( &l, 1 ); klient->sendeEncrypted( player.getText(), l ); } break; } case 0x9: // Report End of Game { if( !klientNummer ) { errorZuKlient( "Du bist nicht Identifiziert." ); break; } klient->sendeEncrypted( "\1", 1 ); unsigned char l = 0; klient->getNachrichtEncrypted( (char*)&l, 1 ); char *mName = new char[ l ]; mName[ (int)l ] = 0; klient->getNachrichtEncrypted( mName, l ); klient->getNachrichtEncrypted( (char*)&l, 1 ); char *oName = new char[ l ]; oName[ (int)l ] = 0; klient->getNachrichtEncrypted( oName, l ); int score; klient->getNachrichtEncrypted( (char*)&score, 4 ); Text fName; if( ms->zDB()->updateMinigameScore( score, oName, klientNummer, mName, ms->getId(), &fName ) ) { ms->zDB()->lock(); Text path = ms->zInit()->zWert( "MGC_Pfad" )->getText(); if( path.getText()[ path.getLength() - 1 ] != '/' ) path += "/"; path += (char*)fName; Datei d; d.setDatei( path ); d.erstellen(); if( d.open( Datei::Style::schreiben ) ) { klient->sendeEncrypted( "\1", 1 ); int size; klient->getNachrichtEncrypted( (char*)&size, 4 ); char *buffer = new char[ 2048 ]; while( size > 0 ) { int l = size > 2048 ? 2048 : size; klient->getNachrichtEncrypted( buffer, l ); d.schreibe( buffer, l ); size -= l; } delete[] buffer; d.close(); } else errorZuKlient( "Fehler beim speichern des Spielverlaufs" ); ms->zDB()->unlock(); } else klient->sendeEncrypted( "\0", 1 ); delete[] mName; delete[] oName; break; } case 0xA: // Get Minigame Capture { klient->sendeEncrypted( "\1", 1 ); unsigned char l = 0; klient->getNachrichtEncrypted( (char*)&l, 1 ); char *mName = new char[ l ]; mName[ (int)l ] = 0; klient->getNachrichtEncrypted( mName, l ); klient->getNachrichtEncrypted( (char*)&l, 1 ); char *oName = new char[ l ]; oName[ (int)l ] = 0; klient->getNachrichtEncrypted( oName, l ); int serverId = ms->zDB()->getMinigameServer( mName, oName ); if( serverId && serverId == ms->getId() ) { ms->zDB()->lock(); Text *fileName = ms->zDB()->getMinigameCaptureFileName( oName, mName ); Text path = ms->zInit()->zWert( "MGC_Pfad" )->getText(); if( path.getText()[ path.getLength() - 1 ] != '/' ) path += "/"; path += fileName->getText(); fileName->release(); Datei d; d.setDatei( path ); if( d.open( Datei::Style::lesen ) ) { klient->sendeEncrypted( "\1", 1 ); int size = (int)d.getSize(); klient->sendeEncrypted( (char*)&size, 4 ); char *buffer = new char[ 2048 ]; while( size > 0 ) { int l = size > 2048 ? 2048 : size; d.lese( buffer, l ); klient->sendeEncrypted( buffer, l ); size -= l; } delete[] buffer; d.close(); } errorZuKlient( "Aufzeichnung konnte nicht gelesen werden." ); ms->zDB()->unlock(); } else if( serverId ) { Text ip; Text port; if( ms->zDB()->getMinigameServer( mName, oName, &ip, &port ) ) { Klient *k = new Klient(); unsigned char key[ 20 ] = { 88, 103, 192, 232, 69, 54, 57, 3, 239, 138, 234, 172, 126, 72, 81, 55, 205, 97, 59, 255 }; k->setSendeKey( (char*)key, 20 ); k->setEmpfangKey( (char*)key, 20 ); if( k->verbinde( (unsigned short)(int)port, (char*)ip ) ) { k->sendeEncrypted( "\xA", 1 ); char ret; k->getNachrichtEncrypted( &ret, 1 ); if( ret == 1 ) { l = (char)textLength( mName ); k->sendeEncrypted( &l, 1 ); k->sendeEncrypted( mName, l ); l = (char)textLength( oName ); k->sendeEncrypted( &l, 1 ); k->sendeEncrypted( oName, l ); k->getNachrichtEncrypted( &ret, 1 ); if( ret == 1 ) { klient->sendeEncrypted( "\1", 1 ); int size; k->getNachrichtEncrypted( (char*)&size, 4 ); klient->sendeEncrypted( (char*)&size, 4 ); char *buffer = new char[ 2048 ]; while( size > 0 ) { int l = size > 2048 ? 2048 : size; k->getNachrichtEncrypted( buffer, l ); klient->sendeEncrypted( buffer, l ); size -= l; } delete[] buffer; } } if( ret == 3 ) { k->getNachrichtEncrypted( (char*)&l, 1 ); char *error = new char[ l + 1 ]; error[ (int)l ] = 0; k->getNachrichtEncrypted( error, l ); errorZuKlient( error ); delete[] error; } else if( ret != 1 ) errorZuKlient( "Umbekannter Fehler während der Kommunikation mit dem Aufzeichnungs Server." ); k->sendeEncrypted( "\3", 1 ); k->getNachrichtEncrypted( &ret, 1 ); k->trenne(); k->release(); } else errorZuKlient( "Aufzeichnungs Server konnte nicht kontaktiert werden." ); } else errorZuKlient( "Aufzeichnungs Server wurde nicht gefunden." ); } else errorZuKlient( "Aufzeichnung wurde nicht gefunden." ); delete[] mName; delete[] oName; break; } default: errorZuKlient( "Unbekannte Nachricht!" ); break; } if( br ) break; ms->addEmpfangen( klient->getDownloadBytes( 1 ) ); ms->addGesendet( klient->getUploadBytes( 1 ) ); } } ms->addEmpfangen( klient->getDownloadBytes( 1 ) ); ms->addGesendet( klient->getUploadBytes( 1 ) ); ms->removeKlient( this ); // delete this } // constant void MSKlient::errorZuKlient( const char *nachricht ) const // sendet eine Fehlernachricht zum Klient { klient->sendeEncrypted( "\3", 1 ); char len = (char)textLength( nachricht ); klient->sendeEncrypted( &len, 1 ); klient->sendeEncrypted( nachricht, len ); } int MSKlient::getKlientNummer() const // gibt die KlientId zurück { return klientNummer; } // Reference Counting MSKlient *MSKlient::getThis() { ref++; return this; } MSKlient *MSKlient::release() { ref--; if( !ref ) delete this; return 0; }