# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

service.cpp

Go to the documentation of this file.
00001 
00009 /* Copyright, 2001 Nevrax Ltd.
00010  *
00011  * This file is part of NEVRAX NEL.
00012  * NEVRAX NEL is free software; you can redistribute it and/or modify
00013  * it under the terms of the GNU General Public License as published by
00014  * the Free Software Foundation; either version 2, or (at your option)
00015  * any later version.
00016  *
00017  * NEVRAX NEL is distributed in the hope that it will be useful, but
00018  * WITHOUT ANY WARRANTY; without even the implied warranty of
00019  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00020  * General Public License for more details.
00021  *
00022  * You should have received a copy of the GNU General Public License
00023  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00024  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00025  * MA 02111-1307, USA.
00026  */
00027 
00028 #include "stdnet.h"
00029 
00030 #ifdef NL_OS_WINDOWS
00031 
00032 //
00033 // Includes
00034 //
00035 
00036 // these defines is for IsDebuggerPresent(). it'll not compile on windows 95
00037 // just comment this and the IsDebuggerPresent to compile on windows 95
00038 #       define _WIN32_WINDOWS   0x0410
00039 #       define WINVER                   0x0400
00040 #       include <windows.h>
00041 #       include <direct.h>
00042 
00043 #elif defined NL_OS_UNIX
00044 
00045 #       include <unistd.h>
00046 
00047 #endif
00048 
00049 #include <stdlib.h>
00050 #include <signal.h>
00051 
00052 #include "nel/misc/config_file.h"
00053 #include "nel/misc/displayer.h"
00054 #include "nel/misc/mutex.h"
00055 #include "nel/misc/window_displayer.h"
00056 #include "nel/misc/gtk_displayer.h"
00057 #include "nel/misc/win_displayer.h"
00058 #include "nel/misc/path.h"
00059 #include "nel/misc/hierarchical_timer.h"
00060 #include "nel/misc/report.h"
00061 
00062 #include "nel/net/naming_client.h"
00063 #include "nel/net/service.h"
00064 #include "nel/net/unified_network.h"
00065 #include "nel/net/net_manager.h"
00066 #include "nel/net/net_displayer.h"
00067 #include "nel/net/email.h"
00068 #include "nel/net/varpath.h"
00069 
00070 #include "nel/misc/hierarchical_timer.h"
00071 
00072 
00073 //
00074 // Namespace
00075 //
00076 
00077 using namespace std;
00078 using namespace NLMISC;
00079 
00080 
00081 namespace NLNET
00082 {
00083 
00084 
00085 //
00086 // Constants
00087 //
00088 
00089 static const sint Signal[] = {
00090   SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
00091 };
00092 
00093 static const char *SignalName[]=
00094 {
00095   "SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV", "SIGTERM"
00096 };
00097 
00098 
00099 //
00100 // Variables
00101 //
00102 
00103 
00104 // class static member
00105 IService        *IService::_Instance = NULL;
00106 
00107 static sint ExitSignalAsked = 0;
00108 
00109 // services stat
00110 static sint32 NetSpeedLoop, UserSpeedLoop;
00111 
00112 // this is the thread that initialized the signal redirection
00113 // we ll ignore other thread signals
00114 static uint SignalisedThread;
00115 
00116 static CFileDisplayer fd;
00117 static CNetDisplayer commandDisplayer(false);
00118 static CLog commandLog;
00119 
00120 
00121 //
00122 // Callback managing
00123 //
00124 
00125 void serviceGetView (uint32 rid, const string &rawvarpath, vector<string> &vara, vector<string> &vala)
00126 {
00127         string str;
00128         CLog logDisplayVars;
00129         CMemDisplayer mdDisplayVars;
00130         logDisplayVars.addDisplayer (&mdDisplayVars);
00131         
00132         CVarPath varpath(rawvarpath);
00133         
00134         // add default row
00135         vara.push_back ("service");
00136 
00137         vala.push_back (IService::getInstance ()->getServiceUnifiedName());
00138         
00139         for (uint j = 0; j < varpath.Destination.size (); j++)
00140         {
00141                 string cmd = varpath.Destination[j].first;
00142 
00143                 // replace = with space to execute the command
00144                 uint pos = cmd.find("=");
00145                 if (pos != string::npos)
00146                         cmd[pos] = ' ';
00147 
00148                 mdDisplayVars.clear ();
00149                 ICommand::execute(cmd, logDisplayVars, true);
00150                 const std::deque<std::string>   &strs = mdDisplayVars.lockStrings();
00151                 if (strs.size()>0)
00152                 {
00153                         string s_ = strs[0];
00154                         
00155                         uint32 pos = strs[0].find("=");
00156                         if(pos != string::npos && pos + 2 < strs[0].size())
00157                         {
00158                                 uint32 pos2 = string::npos;
00159                                 if(strs[0][strs[0].size()-1] == '\n')
00160                                         pos2 = strs[0].size() - pos - 2 - 1;
00161                                 
00162                                 str = strs[0].substr (pos+2, pos2);
00163                         }
00164                         else
00165                         {
00166                                 str = "???";
00167                         }
00168                 }
00169                 else
00170                 {
00171                         str = "???";
00172                 }
00173                 mdDisplayVars.unlockStrings();
00174                 
00175                 if (pos != string::npos)
00176                         vara.push_back(cmd.substr(0, pos));
00177                 else
00178                         vara.push_back(cmd);
00179 
00180                 vala.push_back (str);
00181                 nlinfo ("Add to result view '%s' = '%s'", varpath.Destination[j].first.c_str(), str.c_str());
00182         }
00183         
00184 }
00185 
00186 void servcbGetView (CMessage &msgin, const std::string &serviceName, uint16 sid)
00187 {
00188         uint32 rid;
00189         string rawvarpath;
00190 
00191         msgin.serial (rid);
00192         msgin.serial (rawvarpath);
00193 
00194         vector<string> vara;
00195         vector<string> vala;
00196 
00197         serviceGetView (rid, rawvarpath, vara, vala);
00198 
00199         CMessage msgout("VIEW");
00200         msgout.serial(rid);
00201         
00202         msgout.serialCont (vara);
00203         msgout.serialCont (vala);
00204 
00205         CUnifiedNetwork::getInstance ()->send (sid, msgout);
00206         nlinfo ("Sent result view to service '%s-%hu'", serviceName.c_str(), sid);
00207 }
00208 
00209 void AESConnection (const string &serviceName, uint16 sid, void *arg)
00210 {
00211         // established a connection to the AES, identify myself
00212 
00213         //
00214         // Sends the identification message with the name of the service and all commands available on this service
00215         //
00216 
00217         CMessage msgout ("SID");
00218         uint32 pid = getpid ();
00219         msgout.serial (IService::getInstance()->_AliasName, IService::getInstance()->_LongName, pid);
00220         ICommand::serialCommands (msgout);
00221         CUnifiedNetwork::getInstance()->send("AES", msgout);
00222 
00223         if (IService::getInstance()->_Initialized)
00224         {
00225                 CMessage msgout2 ("SR");
00226                 CUnifiedNetwork::getInstance()->send("AES", msgout2);
00227         }
00228 
00229         // add the displayer to the standard logger
00230 //      TSockId                 hid;
00231 //      CCallbackClient *client = dynamic_cast<CCallbackClient *>(CUnifiedNetwork::getInstance()->getNetBase("AES", hid));
00232 //      commandDisplayer.setLogServer (client);
00233 //      commandLog.addDisplayer (&commandDisplayer);
00234 }
00235 
00236 
00237 static void AESDisconnection (const std::string &serviceName, uint16 sid, void *arg)
00238 {
00239 //      commandLog.removeDisplayer (&commandDisplayer);
00240 }
00241 
00242 
00243 static void cbExecCommand (CMessage &msgin, const std::string &serviceName, uint16 sid)
00244 {
00245         nlwarning ("AES: Deprecated function call cbExecCommand");
00246 
00247 /*      string command;
00248         msgin.serial (command);
00249 
00250         ICommand::execute (command, commandLog);
00251 */}
00252 
00253 
00254 static void cbStopService (CMessage &msgin, const std::string &serviceName, uint16 sid)
00255 {
00256         nlinfo ("Receive a stop from service %s-%d, need to quit", serviceName.c_str(), sid);
00257         ExitSignalAsked = 0xFFFF;
00258 }
00259 
00260 
00261 
00262 // layer 5
00263 static TUnifiedCallbackItem AESCallbackArray[] =
00264 {
00265         { "STOPS", cbStopService },
00266         { "EXEC_COMMAND", cbExecCommand },
00267         { "GET_VIEW", servcbGetView },
00268 };
00269 
00270 //
00271 // Signals managing
00272 //
00273 
00274 // This function is called when a signal comes
00275 static void sigHandler(int Sig)
00276 {
00277         // redirect the signal for the next time
00278         signal(Sig, sigHandler);
00279 
00280         // find the signal
00281         for (int i = 0; i < (int)(sizeof(Signal)/sizeof(Signal[0])); i++)
00282         {
00283                 if (Sig == Signal[i])
00284                 {
00285                         if (getThreadId () != SignalisedThread)
00286                         {
00287                                 nldebug ("Not the main thread received the signal (%s, %d), ignore it", SignalName[i],Sig);
00288                                 return;
00289                         }
00290                         else
00291                         {
00292                                 nlinfo ("Signal %s (%d) received", SignalName[i], Sig);
00293                                 switch (Sig)
00294                                 {
00295                                 case SIGABRT :
00296                                 case SIGILL  :
00297                                 case SIGINT  :
00298                                 case SIGSEGV :
00299                                 case SIGTERM :
00300                                 // you should not call a function and system function like printf in a SigHandle because
00301                                 // signal-handler routines are usually called asynchronously when an interrupt occurs.
00302                                 if (ExitSignalAsked == 0)
00303                                 {
00304                                         nlinfo ("Receive a signal that said that i must exit");
00305                                         ExitSignalAsked = Sig;
00306                                         return;
00307                                 }
00308                                 else
00309                                 {
00310                                         nlinfo ("Signal already received, launch the brutal exit");
00311                                         exit (EXIT_FAILURE);
00312                                 }
00313                                 break;
00314                                 }
00315                         }
00316                 }
00317         }
00318         nlinfo ("Unknown signal received (%d)", Sig);
00319 }
00320 
00321 // Initialise the signal redirection
00322 static void initSignal()
00323 {
00324         SignalisedThread = getThreadId ();
00325 #ifdef NL_DEBUG
00326         // in debug mode, we only trap the SIGINT signal
00327         signal(Signal[3], sigHandler);
00328         //nldebug("Signal : %s (%d) trapped", SignalName[3], Signal[3]);
00329 #else
00330         // in release, redirect all signals
00331 /* don't redirect now because to hard to debug...
00332         for (int i = 0; i < (int)(sizeof(Signal)/sizeof(Signal[0])); i++)
00333         {
00334                 signal(Signal[i], sigHandler);
00335                 nldebug("Signal %s (%d) trapped", SignalName[i], Signal[i]);
00336         }
00337 */
00338 #endif
00339 }
00340 
00341 //
00342 // Class implementation
00343 //
00344 
00345 // Ctor
00346 IService::IService() :
00347         WindowDisplayer(NULL),
00348         _Port(0),
00349         _RecordingState(CCallbackNetBase::Off),
00350         _UpdateTimeout(100),
00351         _SId(0),
00352         _Status(0),
00353         _Initialized(false),
00354         _ResetMeasures(false)
00355 {
00356         // Singleton
00357         nlassert( _Instance == NULL );
00358 
00359         _Instance = this;
00360 }
00361 
00362 
00363 
00364 bool IService::haveArg (char argName)
00365 {
00366         for (uint32 i = 0; i < _Args.size(); i++)
00367         {
00368                 if (_Args[i].size() >= 2 && _Args[i][0] == '-')
00369                 {
00370                         if (_Args[i][1] == argName)
00371                         {
00372                                 return true;
00373                         }
00374                 }
00375         }
00376         return false;
00377 }
00378 
00379 string IService::getArg (char argName)
00380 {
00381         for (uint32 i = 0; i < _Args.size(); i++)
00382         {
00383                 if (_Args[i].size() >= 2 && _Args[i][0] == '-')
00384                 {
00385                         if (_Args[i][1] == argName)
00386                         {
00387                                 return _Args[i].substr(2);
00388                         }
00389                 }
00390         }
00391         throw Exception ("Parameter '-%c' is not found in command line", argName);
00392 }
00393 
00394 
00395 void IService::setArgs (const char *args)
00396 {
00397         _Args.push_back ("<ProgramName>");
00398 
00399         string sargs (args);
00400         uint32 pos1 = 0, pos2 = 0;
00401 
00402         do
00403         {
00404                 pos1 = sargs.find_first_not_of (" ", pos2);
00405                 if (pos1 == string::npos) break;
00406                 pos2 = sargs.find_first_of (" ", pos1);
00407                 _Args.push_back (sargs.substr (pos1, pos2-pos1));
00408         }
00409         while (pos2 != string::npos);
00410 }
00411 
00412 void IService::setArgs (int argc, const char **argv)
00413 {
00414         for (sint i = 0; i < argc; i++)
00415         {
00416                 _Args.push_back (argv[i]);
00417         }
00418 }
00419 
00420 /*
00421  * Returns a pointer to the CCallbackServer object
00422  */
00423 CCallbackServer *IService::getServer()
00424 {
00425         return NULL;
00426 }
00427 
00428 
00429 
00430 void cbLogFilter (CConfigFile::CVar &var)
00431 {
00432         CLog *log = NULL;
00433         if (var.Name == "NegFiltersDebug")
00434         {
00435                 log = DebugLog;
00436                 nlinfo ("Updating negative filter on debug from config file");
00437         }
00438         else if (var.Name == "NegFiltersInfo")
00439         {
00440                 log = InfoLog;
00441                 nlinfo ("Updating negative filter on info from config file");
00442         }
00443         else
00444         {
00445                 nlstop;
00446         }
00447 
00448         // remove all old filter from configfile
00449         CConfigFile::CVar &oldvar = IService::getInstance()->ConfigFile.getVar (var.Name);
00450         for (sint j = 0; j < oldvar.size(); j++)
00451         {
00452                 log->removeFilter (oldvar.asString(j).c_str());
00453         }
00454 
00455         // add all new filter from configfile
00456         for (sint i = 0; i < var.size(); i++)
00457         {
00458                 log->addNegativeFilter (var.asString(i).c_str());
00459         }
00460 }
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468 
00469 //
00470 // The main function of the service
00471 //
00472 
00473 sint IService::main (const char *serviceShortName, const char *serviceLongName, uint16 servicePort, const char *configDir, const char *logDir)
00474 {
00475         bool userInitCalled = false;
00476         bool resyncEvenly = false;
00477         CConfigFile::CVar *var = NULL;
00478         
00479         // a short name service can't be a number
00480         nlassert (atoi(serviceShortName) == 0);
00481 
00482         try
00483         {
00484                 //
00485                 // Init parameters
00486                 //
00487                 
00488                 _ConfigDir = CPath::standardizePath(configDir);
00489                 _LogDir = CPath::standardizePath(logDir);
00490                 _ShortName = serviceShortName;
00491                 _LongName = serviceLongName;
00492 
00493                 // Set the process name
00494                 CLog::setProcessName (_ShortName);
00495 
00496                 setReportEmailFunction ((void*)sendEmail);
00497                 setDefaultEmailParams ("gw.nevrax.com", "", "lecroart@nevrax.com");
00498 
00499                 // get the path where to run the service if any in the command line
00500                 if (haveArg('A'))
00501                 {
00502                         _RunningPath = CPath::standardizePath(getArg('A'));
00503 #ifdef NL_OS_WINDOWS
00504                         _chdir (_RunningPath.c_str());
00505 #else
00506                         chdir (_RunningPath.c_str());
00507 #endif
00508                 }
00509 
00510                 //
00511                 // Init debug/log stuffs (must be first things otherwise we can't log if errors)
00512                 //
00513 
00514                 // get the log dir if any in the command line
00515                 if (haveArg('L'))
00516                         _LogDir = CPath::standardizePath(getArg('L'));
00517 
00518                 // get the config file dir if any in the command line
00519                 if (haveArg('C'))
00520                         _ConfigDir = CPath::standardizePath(getArg('C'));
00521 
00522                 createDebug (_LogDir.c_str(), false);
00523 
00524                 //DebugLog->addNegativeFilter ("NETL");
00525 
00526                 // we create the log with service name filename ("test_service.log" for example)
00527                 fd.setParam (_LogDir + _LongName + ".log", false);
00528 
00529                 DebugLog->addDisplayer (&fd);
00530                 InfoLog->addDisplayer (&fd);
00531                 WarningLog->addDisplayer (&fd);
00532                 AssertLog->addDisplayer (&fd);
00533                 ErrorLog->addDisplayer (&fd);
00534 
00535 
00536                 //
00537                 // Init the hierarchical timer
00538                 //
00539 
00540                 CHTimer::startBench(false, true);
00541 
00542 
00543                 //
00544                 // Load the config file
00545                 //
00546 
00547                 ConfigFile.load (_ConfigDir + _LongName + ".cfg");
00548 
00549 
00550                 //
00551                 // Set the negatif filter from the config file
00552                 //
00553 
00554                 if ((var = ConfigFile.getVarPtr ("NegFiltersDebug")) != NULL)
00555                 {
00556                         ConfigFile.setCallback ("NegFiltersDebug", cbLogFilter);
00557                         for (sint i = 0; i < var->size(); i++)
00558                         {
00559                                 DebugLog->addNegativeFilter (var->asString(i).c_str());
00560                         }
00561                 }
00562 
00563                 if ((var = ConfigFile.getVarPtr ("NegFiltersInfo")) != NULL)
00564                 {
00565                         ConfigFile.setCallback ("NegFiltersInfo", cbLogFilter);
00566                         for (sint i = 0; i < var->size(); i++)
00567                         {
00568                                 InfoLog->addNegativeFilter (var->asString(i).c_str());
00569                         }
00570                 }
00571 
00572 
00573                 //
00574                 // Create the window if neeeded
00575                 //
00576 
00577                 if ((var = ConfigFile.getVarPtr ("WindowStyle")) != NULL)
00578                 {
00579                         string disp = var->asString ();
00580 #ifdef NL_USE_GTK
00581                         if (disp == "GTK")
00582                         {
00583                                 WindowDisplayer = new CGtkDisplayer ("DEFAULT_WD");
00584                         }
00585 #endif // NL_USE_GTK
00586 
00587 #ifdef NL_OS_WINDOWS
00588                         if (disp == "WIN")
00589                         {
00590                                 WindowDisplayer = new CWinDisplayer ("DEFAULT_WD");
00591                         }
00592 #endif // NL_OS_WINDOWS
00593 
00594                         if (WindowDisplayer == NULL && disp != "NONE")
00595                         {
00596                                 nlwarning ("Unknown value for the WindowStyle (should be GTK, WIN or NONE), use no window displayer");
00597                         }
00598                 }
00599 
00600                 vector <pair<string,uint> > displayedVariables;
00601                 //uint speedNetLabel, speedUsrLabel, rcvLabel, sndLabel, rcvQLabel, sndQLabel, scrollLabel;
00602                 if (WindowDisplayer != NULL)
00603                 {
00604                         //
00605                         // Init window param if necessary
00606                         //
00607 
00608                         sint x=-1, y=-1, w=-1, h=-1, fs=10;
00609                         bool iconified = false, ww = false;
00610                         string fn;
00611 
00612                         if ((var = ConfigFile.getVarPtr("XWinParam")) != NULL) x = var->asInt();
00613                         if ((var = ConfigFile.getVarPtr("YWinParam")) != NULL) y = var->asInt();
00614                         if ((var = ConfigFile.getVarPtr("WWinParam")) != NULL) w = var->asInt();
00615                         if ((var = ConfigFile.getVarPtr("HWinParam")) != NULL) h = var->asInt();
00616                         if ((var = ConfigFile.getVarPtr("HWinParam")) != NULL) iconified = var->asInt() == 1;
00617                         if ((var = ConfigFile.getVarPtr("FontSize")) != NULL) fs = var->asInt();
00618                         if ((var = ConfigFile.getVarPtr("FontName")) != NULL) fn = var->asString();
00619                         if ((var = ConfigFile.getVarPtr("WordWrap")) != NULL) ww = var->asInt() == 1;
00620                         
00621                         if (haveArg('I')) iconified = true;
00622 
00623                         WindowDisplayer->create (string("*INIT* ") + _ShortName + " " + _LongName, iconified, x, y, w, h, -1, fs, fn, ww);
00624 
00625                         DebugLog->addDisplayer (WindowDisplayer);
00626                         InfoLog->addDisplayer (WindowDisplayer);
00627                         WarningLog->addDisplayer (WindowDisplayer);
00628                         ErrorLog->addDisplayer (WindowDisplayer);
00629                         AssertLog->addDisplayer (WindowDisplayer);
00630 
00631                         // adding default displayed variables
00632                         displayedVariables.push_back(make_pair(string("NetLop|NetSpeedLoop"), WindowDisplayer->createLabel ("NetLop")));
00633                         displayedVariables.push_back(make_pair(string("UsrLop|UserSpeedLoop"), WindowDisplayer->createLabel ("UsrLop")));
00634 //                      displayedVariables.push_back(make_pair(string("Rcv|ReceivedBytes"), WindowDisplayer->createLabel ("Rcv")));
00635 //                      displayedVariables.push_back(make_pair(string("Snd|SentBytes"), WindowDisplayer->createLabel ("Snd")));
00636 //                      displayedVariables.push_back(make_pair(string("RcvQ|ReceivedQueueSize"), WindowDisplayer->createLabel ("RcvQ")));
00637 //                      displayedVariables.push_back(make_pair(string("SndQ|SentQueueSize"), WindowDisplayer->createLabel ("SndQ")));
00638                         displayedVariables.push_back(make_pair(string("|Scroller"), WindowDisplayer->createLabel ("NeL Rulez")));
00639                         
00640                         CConfigFile::CVar *v = ConfigFile.getVarPtr("DisplayedVariables");
00641                         if (v != NULL)
00642                         {
00643                                 for (sint i = 0; i < v->size(); i++)
00644                                 {
00645                                         displayedVariables.push_back(make_pair(v->asString(i), WindowDisplayer->createLabel (v->asString(i).c_str())));
00646                                 }
00647                         }
00648                 }
00649 
00650                 nlinfo ("Starting Service '%s' using NeL ("__DATE__" "__TIME__")", _ShortName.c_str());
00651 
00652                 setStatus (EXIT_SUCCESS);
00653 
00654                 //
00655                 // Redirect signal if needed (in release mode only)
00656                 //
00657 
00658 #ifdef NL_OS_WINDOWS
00659 #ifdef NL_RELEASE
00660                 initSignal();
00661 #else
00662                 // don't install signal is the application is started in debug mode
00663                 if (IsDebuggerPresent ())
00664                 {
00665                         //nlinfo("Running with the debugger, don't redirect signals");
00666                         initSignal();
00667                 }
00668                 else
00669                 {
00670                         //nlinfo("Running without the debugger, redirect SIGINT signal");
00671                         initSignal();
00672                 }
00673 #endif
00674 #else // NL_OS_UNIX
00675                 initSignal();
00676 #endif
00677 
00678 
00679                 //
00680                 // Ignore SIGPIPE (broken pipe) on unix system
00681                 //
00682 
00683 #ifdef NL_OS_UNIX
00684                 // Ignore the SIGPIPE signal
00685                 sigset_t SigList;
00686                 bool IgnoredPipe = true;
00687                 if (sigemptyset (&SigList) == -1)
00688                 {
00689                         perror("sigemptyset()");
00690                         IgnoredPipe = false;
00691                 }
00692 
00693                 if (sigaddset (&SigList, SIGPIPE) == -1)
00694                 {
00695                         perror("sigaddset()");
00696                         IgnoredPipe = false;
00697                 }
00698 
00699                 if (sigprocmask (SIG_BLOCK, &SigList, NULL) == -1)
00700                 {
00701                         perror("sigprocmask()");
00702                         IgnoredPipe = false;
00703                 }
00704                 nldebug ("SIGPIPE %s", IgnoredPipe?"Ignored":"Not Ignored");
00705 #endif // NL_OS_UNIX
00706 
00707 
00708                 //
00709                 // Initialize the network system
00710                 //
00711                 
00712                 string localhost;
00713                 try
00714                 {
00715                         // Initialize WSAStartup and network stuffs
00716                         CSock::initNetwork();
00717 
00718                         // Get the localhost name
00719                         localhost = CInetAddress::localHost().hostName();
00720                 }
00721                 catch (NLNET::ESocket &)
00722                 {
00723                         localhost = "<UnknownHost>";
00724                 }
00725 
00726                 // Set the localhost name and service name to the logger
00727                 CLog::setProcessName (localhost+"/"+_ShortName);
00728 
00729                 //
00730                 // Initialize server parameters
00731                 //
00732 
00733                 // Get the port from config file or in the macro (overload the port set by the user init())
00734                 if ((var = ConfigFile.getVarPtr("Port")) != NULL)
00735                 {
00736                         // set the listen port with the value in the config file if any
00737                         _Port = var->asInt();
00738                 }
00739                 else
00740                 {
00741                         // set the listen port with the value in the NLNET_SERVICE_MAIN macro
00742                         _Port = servicePort;
00743                 }
00744 
00745                 // set the listen port if there are a port arg in the command line
00746                 if (haveArg('P'))
00747                 {
00748                         _Port = atoi(getArg('P').c_str());
00749                 }
00750 
00751                 // set the aliasname if is present in the command line
00752                 if (haveArg('N'))
00753                 {
00754                         _AliasName = getArg('N');
00755                 }
00756 
00757                 // Load the recording state from the config file
00758                 if ((var = ConfigFile.getVarPtr ("Rec")) != NULL)
00759                 {
00760                         string srecstate = var->asString();
00761                         strupr( srecstate );
00762                         if ( srecstate == "RECORD" )
00763                         {
00764                                 _RecordingState = CCallbackNetBase::Record;
00765                                 nlinfo( "Service recording messages" );
00766                         }
00767                         else if ( srecstate == "REPLAY" )
00768                         {
00769                                 _RecordingState = CCallbackNetBase::Replay;
00770                                 nlinfo( "Service replaying messages" );
00771                         }
00772                         else
00773                         {
00774                                 _RecordingState = CCallbackNetBase::Off;
00775                         }
00776                 }
00777                 else
00778                 {
00779                         // Not found
00780                         _RecordingState = CCallbackNetBase::Off;
00781                 }
00782 
00783                 // Load the default stream format
00784                 if ((var = ConfigFile.getVarPtr ("StringMsgFormat")) != NULL)
00785                 {
00786                         CMessage::setDefaultStringMode( var->asInt() == 1 );
00787                 }
00788                 else
00789                 {
00790                         // Not found => binary
00791                         CMessage::setDefaultStringMode( false );
00792                 }
00793 
00794 /*
00795                 //
00796                 // Layer4 Startup (Connect to the Naming Service (except for the NS itself and Login Service))
00797                 //
00798 
00799                 if (IService::_ShortName != "NS" && IService::_ShortName != "LS" && IService::_ShortName != "AES" && IService::_ShortName != "AS")
00800                 {
00801                         bool ok = false;
00802                         while (!ok)
00803                         {
00804                                 // read the naming service address from the config file
00805                                 CInetAddress loc(ConfigFile.getVar("NSHost").asString(), ConfigFile.getVar("NSPort").asInt());
00806                                 try
00807                                 {
00808                                         CNetManager::init( &loc, _RecordingState );
00809                                         ok = true;
00810                                 }
00811                                 catch (ESocketConnectionFailed &)
00812                                 {
00813                                         nlwarning ("Could not connect to the Naming Service (%s). Retrying in a few seconds...", loc.asString().c_str());
00814                                         nlSleep (5000);
00815                                 }
00816                         }
00817                 }
00818                 else
00819                 {
00820                         CNetManager::init( NULL, _RecordingState );
00821                 }
00822 */
00823 
00827 
00828                 // get the sid
00829                 if ((var = ConfigFile.getVarPtr ("SId")) != NULL)
00830                 {
00831                         sint32 sid = var->asInt();
00832                         if (sid<=0 || sid>255)
00833                         {
00834                                 nlwarning("Bad SId value in the config file, %d is not in [0;255] range", sid);
00835                                 _SId = 0;
00836                         }
00837                         else
00838                         {
00839                                 _SId = (uint8) sid;
00840                         }
00841                 }
00842                 else
00843                 {
00844                         // ok, SId not found, use dynamic sid
00845                         _SId = 0;
00846                 }
00847 
00848 
00849                 // look if we don't want to use NS
00850                 if ((var = ConfigFile.getVarPtr ("DontUseNS")) != NULL)
00851                 {
00852                         // if we set the value in the config file, get it
00853                         _DontUseNS = (var->asInt() == 1);
00854                 }
00855                 else
00856                 {
00857                         // if not, we use ns only if service is not ns, ls, aes, as
00858                         _DontUseNS = false;
00859                 }
00860 
00861                 //
00862                 // Register all network associations (must be before the CUnifiedNetwork::getInstance()->init)
00863                 //
00864 
00865                 if ((var = ConfigFile.getVarPtr ("Networks")) != NULL)
00866                 {
00867                         for (uint8 i = 0; i < var->size (); i++)
00868                                 CUnifiedNetwork::getInstance()->addNetworkAssociation (var->asString(i), i);
00869                 }
00870 
00871                 if ((var = ConfigFile.getVarPtr ("DefaultNetworks")) != NULL)
00872                 {
00873                         for (uint8 i = 0; i < var->size (); i++)
00874                                 CUnifiedNetwork::getInstance()->addDefaultNetwork(var->asString(i));
00875                 }
00876 
00877                 // normal setup for the common services
00878                 if (!_DontUseNS)
00879                 {
00880                         bool ok = false;
00881                         while (!ok)
00882                         {
00883                                 // read the naming service address from the config file
00884                                 string LSAddr = ConfigFile.getVar ("NSHost").asString();
00885                                 
00886                                 // if there's no port to the NS, use the default one 50000
00887                                 if (LSAddr.find(":") == string::npos)
00888                                         LSAddr += ":50000";
00889 
00890                                 CInetAddress loc(LSAddr);
00891                                 try
00892                                 {
00893                                         CUnifiedNetwork::getInstance()->init (&loc, _RecordingState, _ShortName, _Port, _SId);
00894 
00895                                         ok = true;
00896                                 }
00897                                 catch (ESocketConnectionFailed &)
00898                                 {
00899                                         nlwarning ("Could not connect to the Naming Service (%s). Retrying in a few seconds...", loc.asString().c_str());
00900                                         nlSleep (5000);
00901                                 }
00902                         }
00903                 }
00904                 else
00905                 {
00906                         CUnifiedNetwork::getInstance()->init(NULL, _RecordingState, _ShortName, _Port, _SId);
00907                 }
00908 
00909                 // At this point, the _SId must be ok if we use the naming service.
00910                 // If it's 0, it means that we don't use NS and we left the other side server to find a sid for your connection
00911 
00912                 if(!_DontUseNS)
00913                 {
00914                         nlassert (_SId != 0);
00915                 }
00916 
00917                 //
00918                 // Connect to the local AES and send identification
00919                 //
00920 
00921                 // look if we don't want to use NS
00922                 if ((var = ConfigFile.getVarPtr ("DontUseAES")) != NULL)
00923                 {
00924                         // if we set the value in the config file, get it
00925                         _DontUseAES = var->asInt() == 1;
00926                 }
00927                 else
00928                 {
00929                         // if not, we use aes only if service is not aes or as
00930                         _DontUseAES = false;
00931                 }
00932 
00933                 if (!_DontUseAES)
00934                 {
00935                         CUnifiedNetwork::getInstance()->setServiceUpCallback ("AES", AESConnection, NULL);
00936                         CUnifiedNetwork::getInstance()->setServiceDownCallback ("AES", AESDisconnection, NULL);
00937                         CUnifiedNetwork::getInstance()->addCallbackArray (AESCallbackArray, sizeof(AESCallbackArray)/sizeof(AESCallbackArray[0]));
00938                         CUnifiedNetwork::getInstance()->addService ("AES", CInetAddress("localhost:49997"));
00939                 }
00940 
00941 
00942                 //
00943                 // Add callback array
00944                 //
00945 
00946                 // add callback set in the NLNET_SERVICE_MAIN macro
00947                 NLNET::CUnifiedNetwork::getInstance()->addCallbackArray(_CallbackArray, _CallbackArraySize);
00948 
00949                 //
00950                 // Now we have the service id, we can set the entites id generator
00951                 //
00952 
00953                 _NextEntityId.setServiceId(_SId);
00954 
00955                 // Set the localhost name and service name and the sid
00956                 CLog::setProcessName (localhost+"/"+_ShortName+"-"+toString((uint16)_SId));
00957 
00958 
00959                 //
00960                 // Add default pathes
00961                 //
00962 
00963                 if ((var = ConfigFile.getVarPtr ("Paths")) != NULL)
00964                 {
00965                         for (sint i = 0; i < var->size(); i++)
00966                         {
00967                                 CPath::addSearchPath (var->asString(i), true, false);
00968                         }
00969                 }
00970 
00971                 if ((var = ConfigFile.getVarPtr ("PathsNoRecurse")) != NULL)
00972                 {
00973                         for (sint i = 0; i < var->size(); i++)
00974                         {
00975                                 CPath::addSearchPath (var->asString(i), false, false);
00976                         }
00977                 }
00978 
00979 
00980                 // if we can, try to setup where to write files
00981                 if ((var = ConfigFile.getVarPtr ("WriteFilesDirectory")) != NULL)
00982                 {
00983                         WriteFilesDirectory = CPath::standardizePath(var->asString());
00984                 }
00985 
00986 
00987                 //
00988                 // Call the user service init
00989                 //
00990 
00991                 userInitCalled = true; // the bool must be put *before* the call to init()
00992                 init ();
00993 
00994 
00995                 //
00996                 // Connects to the present services
00997                 // WARNING: only after the user init() was called because the
00998                 // addService may call up service callbacks.
00999                 //
01000 
01001                 CUnifiedNetwork::getInstance()->connect();
01002 
01003 
01004                 //
01005                 // Say to the AES that the service is ready
01006                 //
01007 
01008                 if (!_DontUseAES)
01009                 {
01010                         // send the ready message (service init finished)
01011                         CMessage msgout ("SR");
01012                         CUnifiedNetwork::getInstance()->send("AES", msgout);
01013                 }
01014 
01015 
01016                 _Initialized = true;
01017 
01018                 nlinfo ("Service initialised, executing StartCommands");
01019 
01020                 //
01021                 // Call the user command from the config file if any
01022                 //
01023 
01024                 if ((var = ConfigFile.getVarPtr ("StartCommands")) != NULL)
01025                 {
01026                         for (sint i = 0; i < var->size(); i++)
01027                         {
01028                                 ICommand::execute (var->asString(i), *InfoLog);
01029                         }
01030                 }
01031 
01032                 string str;
01033                 CLog logDisplayVars;
01034                 CMemDisplayer mdDisplayVars;
01035                 logDisplayVars.addDisplayer (&mdDisplayVars);
01036 
01037                 nlinfo ("Service ready");
01038 
01039                 if (WindowDisplayer != NULL)
01040                         WindowDisplayer->setTitleBar (_ShortName + " " + _LongName + " " + _Version);
01041 
01042                 //
01043                 // Call the user service update each loop and check files and network activity
01044                 //
01045 
01046                 do
01047                 {
01048                         //H_BEFORE(NLNETServiceLoop); // Not tick-wise
01049                         // count the amount of time to manage internal system
01050                         TTime bbefore = CTime::getLocalTime ();
01051 
01052                         // call the user update and exit if the user update asks it
01053                         //H_BEFORE(NLNETServiceUpdate);
01054                         if (!update ())
01055                         {
01056                                 //H_AFTER(NLNETServiceLoop); // Not tick-wise
01057                                 //H_AFTER(NLNETServiceUpdate);
01058                                 break;
01059                         }
01060                         //H_AFTER(NLNETServiceUpdate);
01061                         
01062                         // count the amount of time to manage internal system
01063                         TTime before = CTime::getLocalTime ();
01064 
01065                         if (WindowDisplayer != NULL)
01066                         {
01067                                 // update the window displayer and quit if asked
01068                                 if (!WindowDisplayer->update ())
01069                                 {
01070                                         nlinfo ("The window displayer was closed by user, need to quit");
01071                                         ExitSignalAsked = 1;
01072                                 }
01073                         }
01074 
01075                         // stop the loop if the exit signal asked
01076                         if (ExitSignalAsked > 0)
01077                         {
01078                                 //H_AFTER(NLNETServiceLoop) // Not tick-wise
01079                                 break;
01080                         }
01081         
01082                         CConfigFile::checkConfigFiles ();
01083 
01084                         CFile::checkFileChange();
01085 
01086                         //H_BEFORE(NLNETManageMessages); // Not tick-wise
01087                         // get and manage layer 5 messages
01088                         CUnifiedNetwork::getInstance()->update (_UpdateTimeout);
01089                         //H_AFTER(NLNETManageMessages); // Not tick-wise
01090                         
01091                         // resync the clock every hours
01092                         if (resyncEvenly)
01093                         {
01094                                 static TTime LastSyncTime = CTime::getLocalTime ();
01095 
01096                                 //---------------------------------------
01097                                 // To simulate Ctrl-C in the debugger... Exit after 1 min !
01098                                 /*if (CTime::getLocalTime () - LastSyncTime > 60 * 1000 )
01099                                 {
01100                                         ExitSignalAsked = 1;
01101                                 }*/
01102                                 //---------------------------------------
01103 /*
01104                                 if (CTime::getLocalTime () - LastSyncTime > 60*60*1000)
01105                                 {
01106                                         CUniTime::syncUniTimeFromService ( _RecordingState );
01107                                         LastSyncTime = CTime::getLocalTime ();
01108                                 }
01109 */
01110                         }
01111 
01112                         NetSpeedLoop = (sint32) (CTime::getLocalTime () - before);
01113                         UserSpeedLoop = (sint32) (before - bbefore);
01114 
01115                         if (WindowDisplayer != NULL)
01116                         {
01117                                 uint64 rcv, snd, rcvq, sndq;
01118                                 rcv = CUnifiedNetwork::getInstance()->getBytesReceived ();
01119                                 snd = CUnifiedNetwork::getInstance()->getBytesSent ();
01120                                 rcvq = CUnifiedNetwork::getInstance()->getReceiveQueueSize ();
01121                                 sndq = CUnifiedNetwork::getInstance()->getSendQueueSize ();
01122 
01123                                 for (uint i = 0; i < displayedVariables.size(); i++)
01124                                 {
01125                                         // it s a separator, do nothing
01126                                         if (displayedVariables[i].first.empty())
01127                                                 continue;
01128 
01129                                         // it s a command, do nothing
01130                                         if (displayedVariables[i].first[0] == '@')
01131                                                 continue;
01132 
01133                                         string dispName = displayedVariables[i].first;
01134                                         string varName = dispName;
01135                                         uint32 pos = dispName.find("|");
01136                                         if (pos != string::npos)
01137                                         {
01138                                                 varName = displayedVariables[i].first.substr(pos+1);
01139                                                 dispName = displayedVariables[i].first.substr(0, pos);
01140                                         }
01141 
01142                                         if (dispName.empty())
01143                                                 str = "";
01144                                         else
01145                                                 str = dispName + ": ";
01146                                         
01147                                         mdDisplayVars.clear ();
01148                                         ICommand::execute(varName, logDisplayVars, true);
01149                                         const std::deque<std::string>   &strs = mdDisplayVars.lockStrings();
01150                                         if (strs.size()>0)
01151                                         {
01152                                                 
01153                                                 string s_ = strs[0];
01154 
01155                                                 uint32 pos = strs[0].find("=");
01156                                                 if(pos != string::npos && pos + 2 < strs[0].size())
01157                                                 {
01158                                                         uint32 pos2 = string::npos;
01159                                                         if(strs[0][strs[0].size()-1] == '\n')
01160                                                                 pos2 = strs[0].size() - pos - 2 - 1;
01161 
01162                                                         str += strs[0].substr (pos+2, pos2);
01163                                                 }
01164                                                 else
01165                                                 {
01166                                                         str += "???";
01167                                                 }
01168                                         }
01169                                         else
01170                                         {
01171                                                 str += "???";
01172                                         }
01173                                         mdDisplayVars.unlockStrings();
01174                                         WindowDisplayer->setLabel (displayedVariables[i].second, str);
01175                                 }
01176 
01177                         }
01178 
01179 //                      nldebug ("SYNC: updatetimeout must be %d and is %d, sleep the rest of the time", _UpdateTimeout, delta);
01180                         //H_AFTER(NLNETServiceLoop); // Not tick-wise
01181 
01182                         // Resetting the hierarchical timer must be done outside the top-level timer
01183                         if ( _ResetMeasures )
01184                         {
01185                                 CHTimer::clear();
01186                                 _ResetMeasures = false;
01187                         }
01188                         //H_AFTER(NLNETServiceLoop);
01189                 }
01190                 while (true);
01191         }
01192 /*      catch (ETrapDebug &)
01193         {
01194                 // we have to do that if we want to trap unhandled exception with the report message box
01195                 setStatus (EXIT_FAILURE);
01196         }
01197 */      catch (EFatalError &)
01198         {
01199                 // Somebody call nlerror, so we have to quit now, the message already display
01200                 // so we don't have to to anything
01201                 setStatus (EXIT_FAILURE);
01202         }
01203         catch ( uint ) // SEH exceptions
01204         {
01205                 ErrorLog->displayNL( "System exception" );
01206         }
01207 
01208 #ifdef NL_RELEASE
01209 /*      // in release mode, we catch everything to handle clean release.
01210         catch (Exception &e)
01211         {
01212                 // Catch NeL exception to release the system cleanly
01213                 setStatus (EXIT_FAILURE);
01214                 nlinfo ("ERROR: NeL Exception: Error running the service \"%s\": %s", _ShortName.c_str(), e.what());
01215         }
01216         catch (...)
01217         {
01218                 // Catch anything we can to release the system cleanly
01219                 setStatus (EXIT_FAILURE);
01220                 nlinfo ("ERROR: Unknown external exception");
01221         }
01222 */
01223 #endif
01224 
01225         try
01226         {
01227                 nlinfo ("Service starts releasing");
01228 
01229                 //
01230                 // Call the user service release() if the init() was called
01231                 //
01232 
01233                 if (userInitCalled)
01234                         release ();
01235 
01236                 //
01237                 // Delete all network connection (naming client also)
01238                 //
01239 
01240                 CUnifiedNetwork::getInstance()->release ();
01241 
01242                 CSock::releaseNetwork ();
01243 
01244                 //
01245                 // Remove the window displayer
01246                 //
01247 
01248                 if (WindowDisplayer != NULL)
01249                 {
01250                         DebugLog->removeDisplayer (WindowDisplayer);
01251                         InfoLog->removeDisplayer (WindowDisplayer);
01252                         WarningLog->removeDisplayer (WindowDisplayer);
01253                         ErrorLog->removeDisplayer (WindowDisplayer);
01254                         AssertLog->removeDisplayer (WindowDisplayer);
01255 
01256                         delete WindowDisplayer;
01257                         WindowDisplayer = NULL;
01258                 }
01259 
01260                 nlinfo ("Service released succesfuly");
01261         }
01262 /*      catch (ETrapDebug &)
01263         {
01264                 // we have to do that if we want to trap unhandled exception with the report message box
01265                 setStatus (EXIT_FAILURE);
01266         }
01267 */      catch (EFatalError &)
01268         {
01269                 // Somebody call nlerror, so we have to quit now, the message already display
01270                 // so we don't have to to anything
01271                 setStatus (EXIT_FAILURE);
01272         }
01273 
01274 #ifdef NL_RELEASE
01275 /*      // in release mode, we catch everything to handle clean release.
01276         catch (Exception &e)
01277         {
01278                 setStatus (EXIT_FAILURE);
01279                 nlinfo ("ERROR: NeL Exception: Error releasing the service \"%s\": %s", _ShortName.c_str(), e.what());
01280         }
01281         catch (...)
01282         {
01283                 // Catch anything we can to release the system cleanly
01284                 setStatus (EXIT_FAILURE);
01285                 nlinfo ("ERROR: Unknown external exception");
01286         }
01287 */
01288 #endif
01289 
01290         CHTimer::endBench();
01291         CHTimer::display();
01292         CHTimer::displayByExecutionPath ();
01293         CHTimer::displayHierarchical(InfoLog, true, 64);
01294         CHTimer::displayHierarchicalByExecutionPathSorted (InfoLog, CHTimer::TotalTime, true, 64);
01295 
01296         nlinfo ("Service ends");
01297 
01298         return ExitSignalAsked?100+ExitSignalAsked:getStatus ();
01299 }
01300 
01301 void IService::exit (sint code)
01302 {
01303         nlinfo ("somebody called IService::exit(), I have to quit");
01304         ExitSignalAsked = code;
01305 }
01306 
01307 /*
01308  * Require to reset the hierarchical timer
01309  */
01310 void IService::requireResetMeasures()
01311 {
01312         _ResetMeasures = true;
01313 }
01314 
01315 
01316 std::string IService::getServiceUnifiedName () const
01317 {
01318         nlassert (!_ShortName.empty())
01319                 string res;
01320         if (!_AliasName.empty())
01321         {
01322                 res = _AliasName+"/";
01323         }
01324         res += _ShortName;
01325         if (_SId != 0)
01326         {
01327                 res += "-";
01328                 res += toString (_SId);
01329         }
01330         return res;
01331 }
01332 
01333 
01334 
01335 //
01336 // Commands and Variables for controling all services
01337 //
01338 
01339 NLMISC_VARIABLE(sint32, NetSpeedLoop, "duration of the last network loop (in ms)");
01340 NLMISC_VARIABLE(sint32, UserSpeedLoop, "duration of the last user loop (in ms)");
01341 
01342 NLMISC_DYNVARIABLE(uint64, ReceivedBytes, "total of bytes received by this service")
01343 {
01344         // we can only read the value
01345         if (get)
01346                 *pointer = CUnifiedNetwork::getInstance()->getBytesReceived ();
01347 }
01348 
01349 NLMISC_DYNVARIABLE(uint64, SentBytes, "total of bytes sent by this service")
01350 {
01351         // we can only read the value
01352         if (get)
01353                 *pointer = CUnifiedNetwork::getInstance()->getBytesSent ();
01354 }
01355 
01356 NLMISC_DYNVARIABLE(uint64, ReceivedQueueSize, "current size in bytes of the received queue size")
01357 {
01358         // we can only read the value
01359         if (get)
01360                 *pointer = CUnifiedNetwork::getInstance()->getReceiveQueueSize ();
01361 }
01362 
01363 NLMISC_DYNVARIABLE(uint64, SentQueueSize, "current size in bytes of the sent queue size")
01364 {
01365         // we can only read the value
01366         if (get)
01367                 *pointer = CUnifiedNetwork::getInstance()->getSendQueueSize ();
01368 }
01369 
01370 NLMISC_DYNVARIABLE(string, Scroller, "current size in bytes of the sent queue size")
01371 {
01372         if (get)
01373         {
01374                 // display the scroll text
01375                 static string foo =     "Welcome to NeL Service! This scroll is used to see the update frequency of the main function and to see if the service is frozen or not. Have a nice day and hope you'll like NeL!!! "
01376                                                         "Welcome to NeL Service! This scroll is used to see the update frequency of the main function and to see if the service is frozen or not. Have a nice day and hope you'll like NeL!!! ";
01377                 static int pos = 0;
01378                 *pointer = foo.substr ((pos++)%(foo.size()/2), 10);
01379         }
01380 }
01381 
01382 NLMISC_COMMAND (quit, "exit the service", "")
01383 {
01384         if(args.size() != 0) return false;
01385 
01386         nlinfo ("User ask me with a command to quit");
01387         ExitSignalAsked = 0xFFFF;
01388 
01389         return true;
01390 }
01391 
01392 NLMISC_COMMAND (brutalQuit, "exit the service brutally", "")
01393 {
01394         if(args.size() != 0) return false;
01395 
01396         ::exit (0xFFFFFFFF);
01397 
01398         return true;
01399 }
01400 
01401 
01402 #ifdef MUTEX_DEBUG
01403 NLMISC_COMMAND (mutex, "display mutex values", "")
01404 {
01405         if(args.size() != 0) return false;
01406 
01407         map<CFairMutex*,TMutexLocks>    acquiretimes = getNewAcquireTimes();
01408 
01409         map<CFairMutex*,TMutexLocks>::iterator im;
01410         for ( im=acquiretimes.begin(); im!=acquiretimes.end(); ++im )
01411         {
01412                 nlinfo( "%d %p %s: %.0f %.0f, called %u times th(%d, %d wait)%s", (*im).second.MutexNum, (*im).first, (*im).second.MutexName.c_str(),
01413                         CTime::cpuCycleToSecond((*im).second.TimeToEnter)*1000.0, CTime::cpuCycleToSecond((*im).second.TimeInMutex)*1000.0,
01414                         (*im).second.Nb, (*im).second.ThreadHavingTheMutex, (*im).second.WaitingMutex,
01415                         (*im).second.Dead?" DEAD":"");
01416         }
01417 
01418         return true;
01419 }
01420 #endif // MUTEX_DEBUG
01421 
01422 NLMISC_COMMAND (serviceInfo, "display information about this service", "")
01423 {
01424         if(args.size() != 0) return false;
01425 
01426         log.displayNL ("Service %s '%s' using NeL ("__DATE__" "__TIME__")", IService::getInstance()->getServiceLongName().c_str(), IService::getInstance()->getServiceUnifiedName().c_str());
01427         log.displayNL ("Service listening port: %d", IService::getInstance()->_Port);
01428         log.displayNL ("Service running directory: '%s'", IService::getInstance()->_RunningPath.c_str());
01429         log.displayNL ("Service log directory: '%s'", IService::getInstance()->_LogDir.c_str());
01430         log.displayNL ("Service config directory: '%s' config filename: '%s.cfg'", IService::getInstance()->_ConfigDir.c_str(), IService::getInstance()->_LongName.c_str());
01431         log.displayNL ("Service id: %d", IService::getInstance()->_SId);
01432         log.displayNL ("Service update timeout: %dms", IService::getInstance()->_UpdateTimeout);
01433         log.displayNL ("Service %suse naming service", IService::getInstance()->_DontUseNS?"don't ":"");
01434         log.displayNL ("Service %suse admin executor service", IService::getInstance()->_DontUseAES?"don't ":"");
01435 #ifdef NL_RELEASE_DEBUG
01436         string mode = "NL_RELEASE_DEBUG";
01437 #elif defined(NL_DEBUG_FAST)
01438         string mode = "NL_DEBUG_FAST";
01439 #elif defined(NL_DEBUG)
01440         string mode = "NL_DEBUG";
01441 #elif defined(NL_RELEASE)
01442         string mode = "NL_RELEASE";
01443 #else
01444         string mode = "???";
01445 #endif
01446         log.displayNL ("NeL is compiled in %s mode", mode.c_str());
01447 
01448         nlinfo ("Services arguments: %d args", IService::getInstance()->_Args.size ());
01449         for (uint i = 0; i < IService::getInstance()->_Args.size (); i++)
01450         {
01451                 nlinfo ("  argv[%d] = '%s'", i, IService::getInstance()->_Args[i].c_str ());
01452         }
01453 
01454         log.displayNL ("Naming service info: %s", CNamingClient::info().c_str());
01455 
01456         ICommand::execute ("services", log);
01457 
01458         return true;
01459 }
01460 
01461 NLMISC_COMMAND(resetMeasures, "reset hierarchical timer", "")
01462 {
01463         IService::getInstance()->requireResetMeasures();
01464         return true;
01465 }
01466 
01467 NLMISC_COMMAND(displayMeasures, "display hierarchical timer", "")
01468 {
01469         CHTimer::display();
01470         CHTimer::displayHierarchicalByExecutionPathSorted (InfoLog, CHTimer::TotalTime, true, 64);
01471         return true;
01472 }
01473 
01474 NLMISC_COMMAND(getWinDisplayerInfo, "display the info about the pos and size of the window displayer", "")
01475 {
01476         uint32 x,y,w,h;
01477         IService::getInstance()->WindowDisplayer->getWindowPos (x,y,w,h);
01478         log.displayNL ("Window Displayer : XWinParam = %d; YWinParam = %d; WWinParam = %d; HWinParam = %d;", x, y, w, h);
01479         return true;
01480 }
01481 
01482 NLMISC_COMMAND(printConfigFile, "display the variables of the default configfile", "")
01483 {
01484         IService::getInstance()->ConfigFile.print(&log);
01485         return true;
01486 }
01487 
01488 NLMISC_COMMAND(getUnknownConfigFileVariables, "display the variables from config file that are called but not present", "")
01489 {
01490         log.displayNL ("%d Variables not found in the configfile '%s'", IService::getInstance()->ConfigFile.UnknownVariables.size(), IService::getInstance()->ConfigFile.getFilename().c_str() );
01491         for (uint i = 0; i < IService::getInstance()->ConfigFile.UnknownVariables.size(); i++)
01492         {
01493                 log.displayNL ("  %s", IService::getInstance()->ConfigFile.UnknownVariables[i].c_str());
01494         }
01495         return true;
01496 }
01497 
01498 NLMISC_COMMAND (freeze, "Freeze the service for N seconds (for debug purpose)", "<N>")
01499 {
01500         if(args.size() != 1) return false;
01501 
01502         sint32 n = atoi (args[0].c_str());
01503 
01504         log.displayNL ("Freezing %d seconds", n);
01505 
01506         nlSleep(n * 1000);      
01507         return true;
01508 }
01509 
01510 uint32 foo = 7777, bar = 6666;
01511 
01512 NLMISC_VARIABLE(uint32, foo, "test the get view system");
01513 NLMISC_VARIABLE(uint32, bar, "test the get view system");
01514 
01515 
01516 // -1 = service is quitting
01517 // 0 = service is not connected
01518 // 1 = service is running
01519 // 2 = service is launching
01520 // 3 = service failed launching
01521 
01522 NLMISC_DYNVARIABLE(string, State, "Set this value to 0 to shutdown the service and 1 to start the service")
01523 {
01524         static string running = "Online";
01525 
01526         // read or write the variable
01527         if (get)
01528         {
01529                 *pointer = running;
01530         }
01531         else
01532         {
01533                 if (IService::getInstance()->getServiceShortName() == "AES" || IService::getInstance()->getServiceShortName() == "AS")
01534                 {
01535                         nlinfo ("I can't set State=0 because I'm the admin and I should never quit");
01536                 }
01537                 else if (*pointer == "0")
01538                 {
01539                         // ok, we want to set the value to false, just quit
01540                         nlinfo ("User ask me with a command to quit using the State variable");
01541                         ExitSignalAsked = 0xFFFE;
01542                         running = "Quitting";
01543                 }
01544                 else
01545                 {
01546                         nlwarning ("Unknown value for State '%s'", (*pointer).c_str());
01547                 }
01548         }
01549 }
01550 
01551 
01552 } //NLNET