version 1.1, 2001/04/18 13:54:25 |
version 1.2, 2001/05/02 12:36:39 |
| |
* Admin Executor Service (AES) | * Admin Executor Service (AES) |
* | * |
* $Id$ | * $Id$ |
| * |
*/ | */ |
| |
/* Copyright, 2000 Nevrax Ltd. | /* Copyright, 2000 Nevrax Ltd. |
* | * |
* This file is part of NEVRAX NeL Network Services | * This file is part of NEVRAX D.T.C. SYSTEM. |
* NEVRAX NeL Network Services is free software; you can redistribute it and/or modify | * NEVRAX D.T.C. SYSTEM is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by | * it under the terms of the GNU General Public License as published by |
* the Free Software Foundation; either version 2, or (at your option) | * the Free Software Foundation; either version 2, or (at your option) |
* any later version. | * any later version. |
* | * |
* NEVRAX NeL Network Services is distributed in the hope that it will be useful, but | * NEVRAX D.T.C. SYSTEM is distributed in the hope that it will be useful, but |
* WITHOUT ANY WARRANTY; without even the implied warranty of | * WITHOUT ANY WARRANTY; without even the implied warranty of |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
* General Public License for more details. | * General Public License for more details. |
* | * |
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License |
* along with NEVRAX NeL Network Services; see the file COPYING. If not, write to the | * along with NEVRAX D.T.C. SYSTEM; see the file COPYING. If not, write to the |
* Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
* MA 02111-1307, USA. | * MA 02111-1307, USA. |
*/ | */ |
| |
#include <nel/misc/debug.h> | #include <io.h> |
#include <nel/misc/log.h> | #include <process.h> |
#include <nel/misc/common.h> | #include <fcntl.h> |
#include <nel/net/service.h> | #include <sys/stat.h> |
#include <nel/net/net_displayer.h> | |
| #include <string> |
#include "sysload.h" | #include <list> |
#include "sysmem.h" | |
#include "sysswap.h" | #include "nel/misc/debug.h" |
| #include "nel/misc/config_file.h" |
| #include "nel/misc/thread.h" |
| |
| #include "nel/net/service.h" |
| #include "nel/net/net_manager.h" |
| |
| |
using namespace std; | using namespace std; |
using namespace NLMISC; | using namespace NLMISC; |
using namespace NLNET; | using namespace NLNET; |
| |
| |
static const char UNKNOW_VALUE[] = "<Unknown>"; | |
| |
| struct CService |
| { |
| CService(TSockId s) : ServiceSockId(s), ServiceId(NextServiceId++) { } |
| |
CLog StatLog(CLog::LOG_STAT); | TSockId ServiceSockId; // socket number to communicate with |
| uint32 ServiceId; // id to identify it |
| string ShortName; |
| string LongName; |
| |
| private: |
| |
/// Log Stat data (STT) | static uint32 NextServiceId; |
void sendData (const char *str, TSenderId from) | }; |
{ | |
StatLog.displayNL( str ); | |
} | |
| |
| uint32 CService::NextServiceId = 0; |
| |
/// Log the last minute average load | list<CService> Services; |
void cbLoad ( CMessage& message, TSenderId from ) | typedef list<CService>::iterator sit; |
{ | |
CSysLoad sysload = CSysLoad(); | |
double load = sysload.getLoadInfo(); | |
string answer( "LOAD " ); | |
| |
if ( load < 0 ) | sit find (TSockId sid) |
{ | { |
answer.append( UNKNOW_VALUE ); | sit it; |
| for (it = Services.begin(); it != Services.end(); it++) |
| { |
| if ((*it).ServiceSockId == sid) break; |
} | } |
else | return it; |
| } |
| |
| sit find (uint32 sid) |
| { |
| sit it; |
| for (it = Services.begin(); it != Services.end(); it++) |
{ | { |
char str[6]; | if ((*it).ServiceId == sid) break; |
smprintf( str, 6, "%.2f", load ); | |
answer.append( string(str) ); | |
} | } |
| return it; |
| } |
| |
| |
sendData( answer.c_str(), from ); | class CExecuteCommandThread : public IRunnable |
| { |
| public: |
| string Command; |
| |
| CExecuteCommandThread (string command) : Command(command) { } |
| |
| void run () |
| { |
| nlinfo ("start executing: %s", Command.c_str()); |
| system (Command.c_str()); |
| nlinfo ("end executing: %s", Command.c_str()); |
} | } |
| }; |
| |
| |
| void executeCommand (string command, bool background) |
| { |
| if (command.empty()) return; |
| |
/// Log the total memory size and the used memory size (in B) | /* |
void cbMemory ( CMessage& message, TSenderId from ) | nlinfo ("start executing: %s", command.c_str()); |
| if (command[command.size()-1] == '&') |
{ | { |
CSysMemory sysmem = CSysMemory(); | command.resize(command.size()-2); |
sint memUsage = sysmem.getMemoryUsage(); | |
string answer( "MEM " ); | |
| |
if ( memUsage < 0 ) | if (spawnlp (_P_NOWAIT, cmd.c_str(), command.c_str(), NULL) == -1) |
{ | { |
answer.append( UNKNOW_VALUE ); | perror ("ca chie grave!!!!: "); |
| } |
} | } |
else | else |
{ | { |
char str[3]; | if (spawnlp (_P_WAIT, cmd.c_str(), command.c_str(), NULL) == -1) |
smprintf( str, 3, "%d", memUsage ); | { |
answer.append( string(str) ); | perror ("ca chie grave!!!!: "); |
} | } |
| } |
| nlinfo ("end executing: %s", command.c_str()); |
| */ |
| |
sendData( answer.c_str(), from ); | command += " >NUL:"; |
| if (background) |
| { |
| IThread *thread = IThread::create (new CExecuteCommandThread (command)); |
| thread->start (); |
| } |
| else |
| { |
| CExecuteCommandThread cmdt (command); |
| cmdt.run (); |
| } |
} | } |
| |
| |
/// Log the swap size and the used swap space (in kB) | /* |
void cbSwap ( CMessage& message, TSenderId from ) | // execute without |
| void executeCommand (string command, TSockId from, CCallbackNetBase &netbase) |
{ | { |
CSysSwap sysswap = CSysSwap(); | if (command.empty()) return; |
sint swapUsage = sysswap.getSwapUsage(); | |
string answer( "SWAP " ); | #define STDOUT 1 |
| #define STDERR 2 |
| int nul, oldstdout, oldstderr; |
| char *tmpfilename = tmpnam (NULL); |
| nul = _open(tmpfilename, _O_RDWR | _O_CREAT | _O_TRUNC | _O_TEMPORARY | _O_SHORT_LIVED | _O_EXCL, _S_IREAD | _S_IWRITE); |
| oldstdout = _dup(STDOUT); |
| oldstderr = _dup(STDERR); |
| _dup2(nul, STDOUT); |
| _dup2(nul, STDERR); |
| system(command.c_str()); |
| _dup2(oldstdout, STDOUT); |
| _dup2(oldstderr, STDERR); |
| _close(oldstdout); |
| _close(oldstderr); |
| |
if ( swapUsage < 0 ) | _lseek (nul, 0L, SEEK_SET); |
| |
| while (!_eof(nul)) |
{ | { |
answer.append( UNKNOW_VALUE ); | uint8 buffer[10000]; |
| uint32 nbread = _read (nul, buffer, 10000); |
| |
| CMessage msgout (netbase.getSIDA(), "ESCR"); |
| msgout.serial (nbread); |
| msgout.serialBuffer (buffer, nbread); |
| netbase.send (msgout, from); |
} | } |
else | |
| _close(nul); |
| */ |
| /* |
| FILE *fp = fopen ("test.txt", "r"); |
| do |
{ | { |
char str[3]; | char str[1024]; |
smprintf( str, 3, "%d", swapUsage ); | fgets (str, 1024, fp); |
answer.append( string(str) ); | if (feof(fp)) break; |
| result.push_back (str); |
} | } |
| while (true); |
| fclose (fp); |
| // remove ("test.txt"); |
| *///} |
| |
sendData( answer.c_str(), from ); | //////////////////////////////////////////////////////////////////////////////////////////////////////// |
} | //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| ////////////////// CONNECTION TO THE SERVICES ////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| static void cbServiceIdentification (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) |
| { |
| CService *c = (CService*) from->appId(); |
| |
| msgin.serial (c->ShortName); |
| msgin.serial (c->LongName); |
| |
| nlinfo ("%s %s %s is identified", from->asString().c_str(), c->ShortName.c_str(), c->LongName.c_str()); |
| |
| CMessage msgout (CNetManager::getSIDA ("AESAS"), "SID"); |
| msgout.serial (c->ShortName); |
| msgout.serial (c->LongName); |
| CNetManager::send ("AESAS", msgout); |
| } |
| |
// Log all the server informations. | static void cbServiceReady (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) |
void cbSystem ( CMessage& message, TSenderId from ) | |
{ | { |
cbLoad ( message, from ); | CService *c = (CService*) from->appId(); |
cbMemory ( message, from ); | |
cbSwap ( message, from ); | nlinfo ("%s %s %s is ready", from->asString().c_str(), c->ShortName.c_str(), c->LongName.c_str()); |
| |
| CMessage msgout (CNetManager::getSIDA ("AESAS"), "SR"); |
| msgout.serial (c->ShortName); |
| msgout.serial (c->LongName); |
| CNetManager::send ("AESAS", msgout); |
} | } |
| |
| void serviceConnection (const string &serviceName, TSockId from, void *arg) |
| { |
| Services.push_back (CService(from)); |
| CService *c = &(Services.back()); |
| from->setAppId ((uint64)c); |
| |
/** | nlinfo ("%s is connected", from->asString().c_str()); |
* Callback Array | |
* Message types: | CMessage msgout (CNetManager::getSIDA ("AESAS"), "SC"); |
* LOAD: log Load information | CNetManager::send ("AESAS", msgout); |
* MEMORY: log Memory information | } |
* SWAP: log Swap information | |
* SYSTEM: log the Load, Memory, and Swap informations | void serviceDisconnection (const string &serviceName, TSockId from, void *arg) |
*/ | |
TCallbackItem CallbackArray[] = | |
{ | { |
{ "LOAD", cbLoad }, | CService *c = (CService*) from->appId(); |
{ "MEMORY", cbMemory }, | |
{ "SWAP", cbSwap }, | |
| |
{ "SYSTEM", cbSystem } | nlinfo ("%s %s %s is disconnected", from->asString().c_str(), c->ShortName.c_str(), c->LongName.c_str()); |
}; | |
| |
| CMessage msgout (CNetManager::getSIDA ("AESAS"), "SD"); |
| msgout.serial (c->ShortName); |
| msgout.serial (c->LongName); |
| CNetManager::send ("AESAS", msgout); |
| } |
| |
| |
/** Admin Executor Service (AES). | /** Callback Array |
* Log informations (load, memory usage, etc ...) about the server it's | |
* running on. | |
* These informations are used by the Admin Service (AS) and the Naming | |
* Service (NS) to watch the differents servers of the shard. | |
*/ | */ |
class CAdminExecutorService : public NLNET::IService | TCallbackItem ServicesCallbackArray[] = |
{ | { |
public: | { "SID", cbServiceIdentification }, |
| { "SR", cbServiceReady }, |
| }; |
| |
/// Initializes the service | //////////////////////////////////////////////////////////////////////////////////////////////////////// |
void init () | //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| ////////////////// CONNECTION TO THE AS //////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| static void cbExecuteSystemCommand (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) |
{ | { |
// Connect to the Log Service | string systemCommand; |
StatLog.addDisplayer( new NLMISC::CStdDisplayer() ); | uint8 background; |
| msgin.serial (systemCommand); |
| msgin.serial (background); |
| |
NLNET::CNetDisplayer *nd = new NLNET::CNetDisplayer; | nlinfo ("I have to execute '%s'", systemCommand.c_str()); |
| |
if ( nd->connected() ) | executeCommand (systemCommand, background==1); |
{ | |
StatLog.addDisplayer( nd ); | |
} | } |
else | |
| static void cbStopService (CMessage& msgin, TSockId from, CCallbackNetBase &netbase) |
{ | { |
nlerror( "Coudn't connect to the Log Service." ); | string service; |
} | |
| nlinfo ("I have to stop service"); |
| |
} | } |
| |
| |
| TCallbackItem AESASCallbackArray[] = |
| { |
| { "ESC", cbExecuteSystemCommand }, |
| { "SS", cbStopService }, |
}; | }; |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| ////////////////// SERVICE IMPLEMENTATION ////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| //////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| class CAdminExecutorService : public IService |
| { |
| public: |
| |
| /// Init the service, load the universal time. |
| void init () |
| { |
| CNetManager::setConnectionCallback ("AES", serviceConnection, NULL); |
| CNetManager::setDisconnectionCallback ("AES", serviceDisconnection, NULL); |
| |
| // install the server for AS |
| CNetManager::addServer ("AESAS", 49996); |
| CNetManager::addCallbackArray ("AESAS", AESASCallbackArray, sizeof(AESASCallbackArray)/sizeof(AESASCallbackArray[0])); |
| } |
| |
| bool update () |
| { |
| return true; |
| } |
| }; |
| |
NLNET_SERVICE_MAIN( CAdminExecutorService, "AES", 50009 ); | |
| |
// End of admin_executor_service.cpp | /// Naming Service |
| NLNET_SERVICE_MAIN (CAdminExecutorService, "AES", "admin_executor_service", 49997, ServicesCallbackArray); |