1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2016-2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
27 // these defines is for IsDebuggerPresent(). it'll not compile on windows 95
28 // just comment this and the IsDebuggerPresent to compile on windows 95
30 #elif defined NL_OS_UNIX
34 #include "nel/misc/config_file.h"
35 #include "nel/misc/displayer.h"
36 #include "nel/misc/mutex.h"
37 #include "nel/misc/window_displayer.h"
38 #include "nel/misc/gtk_displayer.h"
39 #include "nel/misc/win_displayer.h"
40 #include "nel/misc/path.h"
41 #include "nel/misc/hierarchical_timer.h"
42 #include "nel/misc/report.h"
43 #include "nel/misc/system_info.h"
44 #include "nel/misc/timeout_assertion_thread.h"
46 #include "nel/net/naming_client.h"
47 #include "nel/net/service.h"
48 #include "nel/net/unified_network.h"
49 #include "nel/net/net_displayer.h"
50 #include "nel/net/email.h"
51 #include "nel/net/varpath.h"
52 #include "nel/net/admin.h"
53 #include "nel/net/module_manager.h"
54 #include "nel/net/transport_class.h"
56 #include "stdin_monitor_thread.h"
64 using namespace NLMISC
;
74 static const sint Signal
[] = {
75 SIGABRT
, SIGFPE
, SIGILL
, SIGINT
, SIGSEGV
, SIGTERM
78 static const char *SignalName
[]=
80 "SIGABRT", "SIGFPE", "SIGILL", "SIGINT", "SIGSEGV", "SIGTERM"
83 static const char* NegFiltersNames
[] =
98 TUnifiedCallbackItem EmptyCallbackArray
[1] = { { "", NULL
} };
100 // class static member
101 IService
*IService::_Instance
= NULL
;
103 static sint ExitSignalAsked
= 0;
106 CVariable
<sint32
> UserSpeedLoop ("nel", "UserSpeedLoop", "duration of the last user loop (in ms)", 10, false);
107 CVariable
<sint32
> NetSpeedLoop ("nel", "NetSpeedLoop", "duration of the last network loop (in ms)", 10, false);
108 /// The time passed in callback during the loop
109 CVariable
<uint32
> L5CallbackTime("nel", "L5CallbackTime", "Time passed in the L5 callback function in the last loop (in ms)", 0, 100 );
110 /// The number of L5 callback treated
111 CVariable
<uint32
> L5CallbackCount("nel", "L5CallbackCount", "The number of layer 5 callback received in the last loop", 0, 100 );
113 extern uint32 TotalCallbackCalled
;
114 extern uint32 TimeInCallback
;
115 uint32 LastTotalCallbackCalled
= 0;
116 uint32 LastTimeInCallback
= 0;
120 // this is the thread that initialized the signal redirection
121 // we'll ignore other thread signals
122 static size_t SignalisedThread
;
124 static CFileDisplayer fd
;
125 static CNetDisplayer
commandDisplayer(false);
126 //static CLog commandLog;
128 static string CompilationDate
;
129 static uint32 LaunchingDate
;
131 static uint32 NbUserUpdate
= 0;
133 string CompilationMode
= nlMode
;
135 //static bool Bench = false;
137 CVariable
<bool> Bench ("nel", "Bench", "1 if benching 0 if not", 0, true);
139 // This produce an assertion in the thread if the update loop is too slow
140 static CTimeoutAssertionThread MyTAT
;
141 static void UpdateAssertionThreadTimeoutCB(IVariable
&var
) { uint32 timeOut
; fromString(var
.toString(), timeOut
); MyTAT
.timeout(timeOut
); }
142 static CVariable
<uint32
> UpdateAssertionThreadTimeout("nel", "UpdateAssertionThreadTimeout", "in millisecond, timeout before thread assertion", 0, 0, true, UpdateAssertionThreadTimeoutCB
);
144 // Flag to enable/disable the flushing of the sending queues when the service is shut down
145 // Default: false (matches the former behavior)
146 // Set it to true in services that need to send data on exit (for instance in their release() method)
147 CVariable
<bool> FlushSendingQueuesOnExit("nel", "FlushSendingQueuesOnExit",
148 "Flag to enable/disable the flushing of the sending queues when the service is shut down", false, 0, true );
150 // If FlushSendingQueuesOnExit is on, only the sending queues to these specified services will be flushed
151 // Format: service short names separated by ':'
152 // Default: "" (all will be flushed if FlushSendingQueuesOnExit is on, none if it is off)
153 CVariable
<string
> NamesOfOnlyServiceToFlushSending("nel", "NamesOfOnlyServiceToFlushSending",
154 "If FlushSendingQueuesOnExit is on, only the sending queues to these specified services will be flushed (ex: \"WS:LS\"; all will be flushed if empty string)", "", 0, true );
161 // This function is called when a signal comes
162 static void sigHandler(int Sig
)
164 // redirect the signal for the next time
165 signal(Sig
, sigHandler
);
168 for (int i
= 0; i
< (int)(sizeof(Signal
)/sizeof(Signal
[0])); i
++)
170 if (Sig
== Signal
[i
])
172 if (getThreadId () != SignalisedThread
)
174 nldebug ("SERVICE: Not the main thread (%u, %u) received the signal (%s, %d), ignore it", getThreadId (), SignalisedThread
, SignalName
[i
],Sig
);
179 nlinfo ("SERVICE: Signal %s (%d) received", SignalName
[i
], Sig
);
182 // Note: SIGKILL (9) and SIGSTOP (19) can't be trapped
184 if (IService::getInstance()->haveLongArg("nobreak"))
187 nlinfo("SERVICE: Ignoring ctrl-c");
194 // you should not call a function and system function like printf in a SigHandle because
195 // signal-handler routines are usually called asynchronously when an interrupt occurs.
196 if (ExitSignalAsked
== 0)
198 nlinfo ("SERVICE: Receive a signal that said that i must exit");
199 ExitSignalAsked
= Sig
;
204 nlinfo ("SERVICE: Signal already received, launch the brutal exit");
212 nlwarning ("SERVICE: Unknown signal received (%d)", Sig
);
215 // Initialise the signal redirection
216 static void initSignal()
218 SignalisedThread
= getThreadId ();
220 // in debug mode, we only trap the SIGINT signal (for ctrl-c handling)
221 //signal(Signal[3], sigHandler);
222 //nldebug("Signal : %s (%d) trapped", SignalName[3], Signal[3]);
224 // in release, redirect all signals
225 // don't redirect now because too hard to debug...
226 // for (int i = 0; i < (int)(sizeof(Signal)/sizeof(Signal[0])); i++)
228 // signal(Signal[i], sigHandler);
229 // nldebug("Signal %s (%d) trapped", SignalName[i], Signal[i]);
232 if (IService::getInstance()->haveLongArg("nobreak"))
234 signal(Signal
[3], sigHandler
);
239 void cbDirectoryChanged (IVariable
&var
)
241 IService
*instance
= IService::getInstance();
243 // Convert to full path if required
244 // (warning: ConvertSavesFilesDirectoryToFullPath, read from the config file, won't be ready for the initial variable assigments done before the config file has been loaded)
245 string vp
= var
.toString();
246 if ((var
.getName() != "SaveFilesDirectory") || instance
->ConvertSavesFilesDirectoryToFullPath
.get())
248 vp
= CPath::getFullPath(vp
);
251 nlinfo ("SERVICE: '%s' changed to '%s'", var
.getName().c_str(), vp
.c_str());
253 // Update the running directory if needed
254 if (var
.getName() == "RunningDirectory")
256 CPath::setCurrentPath(vp
);
259 // Call the callback if provided
260 if (instance
->_DirectoryChangedCBI
)
261 instance
->_DirectoryChangedCBI
->onVariableChanged(var
);
266 // Service built-in callbacks
269 void cbReceiveShardId (CMessage
& msgin
, const string
&serviceName
, TServiceId serviceId
)
272 msgin
.serial(shardId
);
274 if (IService::getInstance()->getDontUseNS())
276 // we don't use NS, so shard ID message don't concern us
280 if (serviceName
!= "WS")
282 nlwarning("SERVICE: received unauthorized R_SH_ID callback from service %s-%uh asking to set ShardId to %d", serviceName
.c_str(), serviceId
.get(), shardId
);
286 nlinfo("SERVICE: ShardId is %u", shardId
);
287 IService::getInstance()->setShardId( shardId
);
290 std::string
IService::getServiceStatusString() const
292 static string emptyString
;
299 void IService::anticipateShardId( uint32 shardId
)
301 if ( ! ((_ShardId
== DEFAULT_SHARD_ID
) || (shardId
== _ShardId
)) )
302 nlerror( "IService::anticipateShardId() overwrites %u with %u", _ShardId
, shardId
);
307 void IService::setShardId( uint32 shardId
)
309 if ( ! ((_ShardId
== DEFAULT_SHARD_ID
) || (shardId
== _ShardId
)) )
310 nlwarning( "SERVICE: The shardId from the WS (%u) is different from the anticipated shardId (%u)", shardId
, _ShardId
);
314 TUnifiedCallbackItem builtinServiceCallbacks
[] =
316 { "R_SH_ID", cbReceiveShardId
},
322 // Class implementation
326 IService::IService() :
328 WriteFilesDirectory("nel", "WriteFilesDirectory", "directory where to save generic shard information (packed_sheets for example)", ".", 0, true, cbDirectoryChanged
),
329 SaveFilesDirectory("nel", "SaveFilesDirectory", "directory where to save specific shard information (shard time for example)", ".", 0, true, cbDirectoryChanged
),
330 ConvertSavesFilesDirectoryToFullPath("nel", "ConvertSaveFilesDirectoryToFullPath", "If true (default), the provided SaveFilesDirectory will be converted to a full path (ex: saves -> /home/dir/saves)", true, 0, true ),
331 ListeningPort("nel", "ListeningPort", "listening port for this service", 0, 0, true),
332 _RecordingState(CCallbackNetBase::Off
),
337 ConfigDirectory("nel", "ConfigDirectory", "directory where config files are", ".", 0, true, cbDirectoryChanged
),
338 LogDirectory("nel", "LogDirectory", "directory where the service is logging", ".", 0, true, cbDirectoryChanged
),
339 RunningDirectory("nel", "RunningDirectory", "directory where the service is running on", ".", 0, true, cbDirectoryChanged
),
340 Version("nel", "Version", "Version of the shard", ""),
342 _CallbackArraySize (0),
345 _ResetMeasures(false),
347 _ClosureClearanceStatus(CCMustRequestClearance
),
348 _RequestClosureClearanceCallback(NULL
),
349 _DirectoryChangedCBI(NULL
)
354 // register in the safe singleton registry
355 INelContext::getInstance().setSingletonPointer("IService", this);
358 IService::~IService()
360 // unregister the singleton
361 INelContext::getInstance().releaseSingletonPointer("IService", this);
365 bool IService::haveArg (char argName
) const
367 for (uint32 i
= 0; i
< _Args
.size(); i
++)
369 if (_Args
[i
].size() >= 2 && _Args
[i
][0] == '-')
371 if (_Args
[i
][1] == argName
)
381 string
IService::getArg (char argName
) const
383 for (uint32 i
= 0; i
< _Args
.size(); i
++)
385 if (_Args
[i
].size() >= 2 && _Args
[i
][0] == '-')
387 if (_Args
[i
][1] == argName
)
389 /* Remove the first and last '"' :
390 -c"C:\Documents and Settings\toto.tmp"
392 C:\Documents and Settings\toto.tmp
395 if (_Args
[i
].size() < 3)
397 //throw Exception ("Parameter '-%c' is malformed, missing content", argName);
399 if (_Args
[i
][begin
] == '"')
403 uint size
= (uint
)_Args
[i
].size();
404 if (size
&& _Args
[i
][size
-1] == '"')
406 size
= (uint
)(std::max((int)0, (int)size
-(int)begin
));
407 return _Args
[i
].substr(begin
, size
);
411 throw Exception ("Parameter '-%c' is not found in command line", argName
);
415 bool IService::haveLongArg (const char* argName
) const
417 for (uint32 i
= 0; i
< _Args
.size(); i
++)
419 if (_Args
[i
].left(2)=="--" && _Args
[i
].leftCrop(2).splitTo('=')==argName
)
428 string
IService::getLongArg (const char* argName
) const
430 for (uint32 i
= 0; i
< _Args
.size(); i
++)
432 if (_Args
[i
].left(2)=="--" && _Args
[i
].leftCrop(2).splitTo('=')==argName
)
434 NLMISC::CSString val
= _Args
[i
].splitFrom('=');
437 return val
.unquoteIfQuoted();
439 if (i
+1<_Args
.size() && _Args
[i
+1].c_str()[0]!='-')
441 return _Args
[i
+1].unquoteIfQuoted();
444 return std::string();
447 return std::string();
451 void IService::setArgs (const char *args
)
453 _Args
.push_back ("<ProgramName>");
456 string::size_type pos1
= 0, pos2
= 0;
460 // Look for the first non space character
461 pos1
= sargs
.find_first_not_of (" ", pos2
);
462 if (pos1
== string::npos
) break;
464 // Look for the first space or "
465 pos2
= sargs
.find_first_of (" \"", pos1
);
466 if (pos2
!= string::npos
)
469 if (sargs
[pos2
] == '"')
471 // Look for the final \"
472 pos2
= sargs
.find_first_of ("\"", pos2
+1);
473 if (pos2
!= string::npos
)
475 // Look for the first space
476 pos2
= sargs
.find_first_of (" ", pos2
+1);
481 // Compute the size of the string to extract
482 string::difference_type length
= (pos2
!= string::npos
) ? pos2
-pos1
: string::npos
;
484 string tmp
= sargs
.substr (pos1
, length
);
485 _Args
.push_back (tmp
);
487 while (pos2
!= string::npos
);
490 void IService::setArgs (int argc
, const char **argv
)
492 for (sint i
= 0; i
< argc
; i
++)
494 _Args
.push_back (argv
[i
]);
498 void IService::setArgs(int argc
, const wchar_t **argv
)
500 for (sint i
= 0; i
< argc
; i
++)
502 _Args
.push_back(nlWideToUtf8(argv
[i
]));
506 void cbLogFilter (CConfigFile::CVar
&var
)
509 if (var
.Name
== "NegFiltersDebug")
513 else if (var
.Name
== "NegFiltersInfo")
517 else if (var
.Name
== "NegFiltersWarning")
521 else if (var
.Name
== "NegFiltersAssert")
525 else if (var
.Name
== "NegFiltersError")
534 nlinfo ("SERVICE: Updating %s from config file", var
.Name
.c_str());
536 // remove all old filters from config file
537 CConfigFile::CVar
&oldvar
= IService::getInstance()->ConfigFile
.getVar (var
.Name
);
538 for (uint j
= 0; j
< oldvar
.size(); j
++)
540 log
->removeFilter (oldvar
.asString(j
).c_str());
543 // add all new filters from config file
544 for (uint i
= 0; i
< var
.size(); i
++)
546 log
->addNegativeFilter (var
.asString(i
).c_str());
550 void cbExecuteCommands (CConfigFile::CVar
&var
)
552 for (uint i
= 0; i
< var
.size(); i
++)
554 ICommand::execute (var
.asString(i
), IService::getInstance()->CommandLog
);
561 // The main function of the service
564 sint
IService::main (const char *serviceShortName
, const char *serviceLongName
, uint16 servicePort
, const char *configDir
, const char *logDir
, const char *compilationDate
)
566 bool userInitCalled
= false;
567 CConfigFile::CVar
*var
= NULL
;
569 IThread
*timeoutThread
= NULL
;
571 // a short name service can't be a number
573 nlassert (!fromString(serviceShortName
, tmp
));
578 // init the module manager
579 IModuleManager::getInstance();
584 // at the very beginning, eventually wrote a file with the pid
585 if (haveLongArg("writepid"))
587 // use legacy C primitives
588 FILE *fp
= nlfopen("pid.state", "wt");
591 fprintf(fp
, "%u", getpid());
596 _ShortName
= serviceShortName
;
597 CLog::setProcessName (_ShortName
);
599 // get the path where to run the service if any in the command line
601 RunningDirectory
= CPath::standardizePath(getArg('A'));
603 ConfigDirectory
= CPath::standardizePath(configDir
);
604 LogDirectory
= CPath::standardizePath(logDir
);
605 _LongName
= serviceLongName
;
607 CompilationDate
= compilationDate
;
609 LaunchingDate
= CTime::getSecondsSince1970();
611 ListeningPort
= servicePort
;
613 // setDefaultEmailParams ("gw.nevrax.com", "", "cado@nevrax.com");
617 // Load the config file
620 // get the config file dir if any in the command line
622 ConfigDirectory
= CPath::standardizePath(getArg('C'));
624 string cfn
= ConfigDirectory
.c_str() + _LongName
+ ".cfg";
625 if (!CFile::fileExists(ConfigDirectory
.c_str() + _LongName
+ ".cfg"))
627 // check if the default exists
628 if (!CFile::fileExists(ConfigDirectory
.c_str() + _LongName
+ "_default.cfg"))
630 nlerror ("SERVICE: Neither the config file '%s' nor the default one can be found, can't launch the service", cfn
.c_str());
634 // create the basic .cfg that link the default one
635 FILE *fp
= nlfopen (cfn
, "w");
638 nlerror ("SERVICE: Can't create config file '%s'", cfn
.c_str());
640 fprintf(fp
, "// link the default config file for %s\n", _LongName
.c_str());
641 fprintf(fp
, "RootConfigFilename = \"%s_default.cfg\";\n", _LongName
.c_str());
646 ConfigFile
.load (cfn
);
648 // setup variable with config file variable
649 IVariable::init (ConfigFile
);
651 if (ConfigFile
.exists("DefaultEmailSMTP") && ConfigFile
.exists("DefaultEmailTo"))
652 NLNET::setDefaultEmailParams(
653 ConfigFile
.getVar("DefaultEmailSMTP").asString(),
654 ConfigFile
.exists("DefaultEmailFrom")
655 ? ConfigFile
.getVar("DefaultEmailFrom").asString()
656 : "service@opennel.org",
657 ConfigFile
.getVar("DefaultEmailTo").asString());
663 if ((var
= ConfigFile
.getVarPtr("NoWSShardId")) != NULL
)
665 _ShardId
= var
->asInt();
669 // something high enough as default
670 _ShardId
= DEFAULT_SHARD_ID
;
675 string s
= IService::getInstance()->getArg('Z');
678 // do not release the module manager
682 // release the module manager
683 IModuleManager::getInstance().releaseInstance();
689 // we have to call this again because the config file can changed this variable but the cmd line is more prioritary
691 RunningDirectory
= CPath::standardizePath(getArg('A'));
695 // Init debug/log stuffs (must be first things otherwise we can't log if errors)
698 // get the log dir if any in the command line
700 LogDirectory
= CPath::standardizePath(getArg('L'));
702 changeLogDirectory (LogDirectory
);
704 bool noLog
= (ConfigFile
.exists ("DontLog")) && (ConfigFile
.getVar("DontLog").asInt() == 1);
705 noLog
|=haveLongArg("nolog");
708 // we create the log with service name filename ("test_service_ALIAS.log" for example)
709 string logname
= LogDirectory
.toString() + _LongName
;
711 logname
+= "_" + toLowerAscii(getArg('N'));
713 fd
.setParam (logname
, false);
715 DebugLog
->addDisplayer (&fd
);
716 InfoLog
->addDisplayer (&fd
);
717 WarningLog
->addDisplayer (&fd
);
718 AssertLog
->addDisplayer (&fd
);
719 ErrorLog
->addDisplayer (&fd
);
720 CommandLog
.addDisplayer (&fd
, true);
723 bool dontUseStdIn
= (ConfigFile
.exists ("DontUseStdIn")) && (ConfigFile
.getVar("DontUseStdIn").asInt() == 1);
726 IStdinMonitorSingleton::getInstance()->init();
730 // Init the hierarchical timer
733 CHTimer::startBench(false, true);
737 // Set the assert mode
740 if (ConfigFile
.exists ("Assert"))
741 setAssert (ConfigFile
.getVar("Assert").asInt() == 1);
744 // Set the update timeout if found in the cfg
746 if ((var
= ConfigFile
.getVarPtr("UpdateTimeout")) != NULL
)
748 _UpdateTimeout
= var
->asInt();
752 // Set the negative filter from the config file
755 for(const char **name
= NegFiltersNames
; *name
; name
++)
757 if ((var
= ConfigFile
.getVarPtr (*name
)) != NULL
)
759 ConfigFile
.setCallback (*name
, cbLogFilter
);
764 ConfigFile
.setCallback ("Commands", cbExecuteCommands
);
765 if ((var
= ConfigFile
.getVarPtr ("Commands")) != NULL
)
767 cbExecuteCommands(*var
);
771 // Command line start
776 // Create the window if needed
779 if ((var
= ConfigFile
.getVarPtr ("WindowStyle")) != NULL
)
781 string disp
= var
->asString ();
785 WindowDisplayer
= new CGtkDisplayer ("DEFAULT_WD");
792 WindowDisplayer
= new CWinDisplayer ("DEFAULT_WD");
794 #endif // NL_OS_WINDOWS
796 if (WindowDisplayer
== NULL
&& disp
!= "NONE")
798 nlinfo ("SERVICE: Unknown value for the WindowStyle (should be GTK, WIN or NONE), use no window displayer");
802 vector
<pair
<string
,uint
> > displayedVariables
;
803 //uint speedNetLabel, speedUsrLabel, rcvLabel, sndLabel, rcvQLabel, sndQLabel, scrollLabel;
804 if (WindowDisplayer
!= NULL
)
807 // Init window param if necessary
810 sint x
=-1, y
=-1, w
=-1, h
=-1, fs
=10, history
=-1;
811 bool iconified
= false, ww
= false;
814 if ((var
= ConfigFile
.getVarPtr("XWinParam")) != NULL
) x
= var
->asInt();
815 if ((var
= ConfigFile
.getVarPtr("YWinParam")) != NULL
) y
= var
->asInt();
816 if ((var
= ConfigFile
.getVarPtr("WWinParam")) != NULL
) w
= var
->asInt();
817 if ((var
= ConfigFile
.getVarPtr("HWinParam")) != NULL
) h
= var
->asInt();
818 if ((var
= ConfigFile
.getVarPtr("HistoryWinParam")) != NULL
) history
= var
->asInt();
819 if ((var
= ConfigFile
.getVarPtr("IWinParam")) != NULL
) iconified
= var
->asInt() == 1;
820 if ((var
= ConfigFile
.getVarPtr("FontSize")) != NULL
) fs
= var
->asInt();
821 if ((var
= ConfigFile
.getVarPtr("FontName")) != NULL
) fn
= var
->asString();
822 if ((var
= ConfigFile
.getVarPtr("WordWrap")) != NULL
) ww
= var
->asInt() == 1;
824 if (haveArg('I')) iconified
= true;
826 WindowDisplayer
->create (string("*INIT* ") + _ShortName
+ " " + _LongName
, iconified
, x
, y
, w
, h
, history
, fs
, fn
, ww
, &CommandLog
);
828 DebugLog
->addDisplayer (WindowDisplayer
);
829 InfoLog
->addDisplayer (WindowDisplayer
);
830 WarningLog
->addDisplayer (WindowDisplayer
);
831 ErrorLog
->addDisplayer (WindowDisplayer
);
832 AssertLog
->addDisplayer (WindowDisplayer
);
833 CommandLog
.addDisplayer(WindowDisplayer
, true);
835 // adding default displayed variables
836 displayedVariables
.push_back(make_pair(string("NetLop|NetSpeedLoop"), WindowDisplayer
->createLabel ("NetLop")));
837 displayedVariables
.push_back(make_pair(string("UsrLop|UserSpeedLoop"), WindowDisplayer
->createLabel ("UsrLop")));
838 displayedVariables
.push_back(make_pair(string("|Scroller"), WindowDisplayer
->createLabel ("NeL Rulez")));
840 CConfigFile::CVar
*v
= ConfigFile
.getVarPtr("DisplayedVariables");
843 for (uint i
= 0; i
< v
->size(); i
++)
845 displayedVariables
.push_back(make_pair(v
->asString(i
), WindowDisplayer
->createLabel (v
->asString(i
).c_str())));
850 nlinfo ("SERVICE: Starting Service '%s' using NeL (" __DATE__
" " __TIME__
") compiled %s", _ShortName
.c_str(), CompilationDate
.c_str());
851 nlinfo ("SERVICE: On OS: %s", CSystemInfo::getOS().c_str());
853 setExitStatus (EXIT_SUCCESS
);
856 // Redirect signal if needed (in release mode only)
863 // don't install signal is the application is started in debug mode
864 if (IsDebuggerPresent ())
866 //nlinfo("Running with the debugger, don't redirect signals");
871 //nlinfo("Running without the debugger, redirect SIGINT signal");
881 // Ignore SIGPIPE (broken pipe) on unix system
885 // Ignore the SIGPIPE signal
887 bool IgnoredPipe
= true;
888 if (sigemptyset (&SigList
) == -1)
890 perror("sigemptyset()");
894 if (sigaddset (&SigList
, SIGPIPE
) == -1)
896 perror("sigaddset()");
900 if (sigprocmask (SIG_BLOCK
, &SigList
, NULL
) == -1)
902 perror("sigprocmask()");
905 nldebug ("SERVICE: SIGPIPE %s", IgnoredPipe
?"Ignored":"Not Ignored");
910 // Initialize the network system
916 // Initialize WSAStartup and network stuffs
917 CSock::initNetwork();
919 // Get the localhost name
920 localhost
= CInetAddress::localHost().hostName();
922 catch (const NLNET::ESocket
&)
924 localhost
= "<UnknownHost>";
927 // Set the localhost name and service name to the logger
928 CLog::setProcessName (localhost
+"/"+_ShortName
);
929 nlinfo ("SERVICE: Host: %s", localhost
.c_str());
932 // Initialize server parameters
935 // set the listen port if there are a port arg in the command line
938 NLMISC::fromString(getArg('P'), ListeningPort
);
941 // set the aes aliasname if present in cfg file
942 CConfigFile::CVar
*varAliasName
= ConfigFile
.getVarPtr("AESAliasName");
943 if (varAliasName
!= NULL
)
945 _AliasName
= varAliasName
->asString();
946 nlinfo("SERVICE: Setting alias name to: '%s'",_AliasName
.c_str());
949 // set the aes aliasname if is present in the command line
952 _AliasName
= getArg('N');
953 nlinfo("SERVICE: Setting alias name to: '%s'",_AliasName
.c_str());
956 // Load the recording state from the config file
957 if ((var
= ConfigFile
.getVarPtr ("Rec")) != NULL
)
959 string srecstate
= toUpperAscii(var
->asString());
960 if ( srecstate
== "RECORD" )
962 _RecordingState
= CCallbackNetBase::Record
;
963 nlinfo( "SERVICE: Service recording messages" );
965 else if ( srecstate
== "REPLAY" )
967 _RecordingState
= CCallbackNetBase::Replay
;
968 nlinfo( "SERVICE: Service replaying messages" );
972 _RecordingState
= CCallbackNetBase::Off
;
978 _RecordingState
= CCallbackNetBase::Off
;
981 // Load the default stream format
982 if ((var
= ConfigFile
.getVarPtr ("StringMsgFormat")) != NULL
)
984 CMessage::setDefaultStringMode( var
->asInt() == 1 );
988 // Not found => binary
989 CMessage::setDefaultStringMode( false );
998 if ((var
= ConfigFile
.getVarPtr ("SId")) != NULL
)
1000 sint32 sid
= var
->asInt();
1001 if (sid
<=0 || sid
>255)
1003 nlwarning("SERVICE: Bad SId value in the config file, %d is not in [0;255] range", sid
);
1008 _SId
.set(static_cast<uint16
>(sid
));
1013 // ok, SId not found, use dynamic sid
1018 // look if we don't want to use NS
1019 if ((var
= ConfigFile
.getVarPtr ("DontUseNS")) != NULL
)
1021 // if we set the value in the config file, get it
1022 _DontUseNS
= (var
->asInt() == 1);
1026 // if not, we use ns only if service is not ns, ls, aes, as
1029 if (haveLongArg("nons"))
1031 // command line override
1036 // Register all network associations (must be before the CUnifiedNetwork::getInstance()->init)
1039 if ((var
= ConfigFile
.getVarPtr ("Networks")) != NULL
)
1041 for (uint8 i
= 0; i
< var
->size (); i
++)
1042 CUnifiedNetwork::getInstance()->addNetworkAssociation (var
->asString(i
), i
);
1045 if ((var
= ConfigFile
.getVarPtr ("DefaultNetworks")) != NULL
)
1047 for (uint8 i
= 0; i
< var
->size (); i
++)
1048 CUnifiedNetwork::getInstance()->addDefaultNetwork(var
->asString(i
));
1051 // normal setup for the common services
1061 // if the naming service address is set on the command line, get it (overwrite the cfg)
1062 LSAddr
= getArg('B');
1066 // else read the naming service address from the config file
1067 LSAddr
= ConfigFile
.getVar ("NSHost").asString();
1070 // if there's no port to the NS, use the default one 50000
1071 if (LSAddr
.find(":") == string::npos
)
1074 CInetAddress
loc(LSAddr
);
1077 // todo: check if app not closed by user, or you get stuck here
1079 if ( CUnifiedNetwork::getInstance()->init (&loc
, _RecordingState
, _ShortName
, ListeningPort
, _SId
) )
1085 nlinfo( "SERVICE: Exiting..." );
1090 // remove the stdin monitor thread
1091 IStdinMonitorSingleton::getInstance()->release(); // does nothing if not initialized
1093 // release the module manager
1094 IModuleManager::getInstance().releaseInstance();
1099 catch (const ESocketConnectionFailed
&)
1101 nlinfo ("SERVICE: Could not connect to the Naming Service (%s). Retrying in a few seconds...", loc
.asString().c_str());
1108 CUnifiedNetwork::getInstance()->init(NULL
, _RecordingState
, _ShortName
, ListeningPort
, _SId
);
1111 // get the hostname for later use
1112 _HostName
= CInetAddress::localHost().hostName();
1114 // At this point, the _SId must be ok if we use the naming service.
1115 // 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
1119 nlassert (_SId
.get() != 0);
1123 // Connect to the local AES and send identification
1126 // look if we don't want to use NS
1127 if ((var
= ConfigFile
.getVarPtr ("DontUseAES")) != NULL
)
1129 // if we set the value in the config file, get it
1130 _DontUseAES
= var
->asInt() == 1;
1134 // if not, we use aes only if service is not aes or as
1135 _DontUseAES
= false;
1138 initAdmin (_DontUseAES
);
1140 while (NLNET::CUnifiedNetwork::getInstance()->tryFlushAllQueues() != 0)
1146 // Add callback array
1149 // add inner service callback array
1150 NLNET::CUnifiedNetwork::getInstance()->addCallbackArray(builtinServiceCallbacks
, sizeof(builtinServiceCallbacks
)/sizeof(builtinServiceCallbacks
[0]));
1152 // add callback set in the NLNET_SERVICE_MAIN macro
1153 NLNET::CUnifiedNetwork::getInstance()->addCallbackArray(_CallbackArray
, _CallbackArraySize
);
1156 // Now we have the service id, we can set the entites id generator
1159 NLMISC::CEntityId::setServiceId(TServiceId8(_SId
).get());
1161 // Set the localhost name and service name and the sid
1162 CLog::setProcessName (localhost
+"/"+_ShortName
+"-"+toString(_SId
.get()));
1166 // Add default pathes
1169 if ((var
= ConfigFile
.getVarPtr ("IgnoredFiles")) != NULL
)
1171 for (uint i
= 0; i
< var
->size(); i
++)
1173 CPath::addIgnoredDoubleFile (var
->asString(i
));
1177 if ((var
= ConfigFile
.getVarPtr ("Paths")) != NULL
)
1179 for (uint i
= 0; i
< var
->size(); i
++)
1181 CPath::addSearchPath (NLMISC::expandEnvironmentVariables(var
->asString(i
)), true, false);
1185 if ((var
= ConfigFile
.getVarPtr ("PathsNoRecurse")) != NULL
)
1187 for (uint i
= 0; i
< var
->size(); i
++)
1189 CPath::addSearchPath (NLMISC::expandEnvironmentVariables(var
->asString(i
)), false, false);
1193 // if we can, try to setup where to save files
1194 if (IService::getInstance()->haveArg('W'))
1196 // use the command line param if set (must be done after the config file has been loaded)
1197 SaveFilesDirectory
= IService::getInstance()->getArg('W');
1200 CTransportClass::init();
1203 // Call the user service init
1206 userInitCalled
= true; // the bool must be put *before* the call to init()
1208 setCurrentStatus("Initializing");
1210 clearCurrentStatus("Initializing");
1214 // Connects to the present services
1215 // WARNING: only after the user init() was called because the
1216 // addService may call up service callbacks.
1219 CUnifiedNetwork::getInstance()->connect();
1222 // Say to the AES that the service is ready
1227 // send the ready message (service init finished)
1228 CMessage
msgout ("SR");
1229 CUnifiedNetwork::getInstance()->send("AES", msgout
);
1233 _Initialized
= true;
1235 nlinfo ("SERVICE: Service initialized, executing StartCommands");
1238 // Call the user command from the config file if any
1240 string
cmdRoot("StartCommands");
1241 vector
<string
> posts
;
1243 // add an empty string (for the common part of start commands)
1244 posts
.push_back(string());
1246 if (IService::getInstance()->haveArg('S'))
1248 string s
= IService::getInstance()->getArg('S');
1252 CConfigFile::CVar
*var
;
1253 for (uint i
=0; i
<posts
.size(); ++i
)
1255 string varName
= cmdRoot
+ posts
[i
];
1256 if ((var
= IService::getInstance()->ConfigFile
.getVarPtr (varName
)) != NULL
)
1258 for (uint i
= 0; i
< var
->size(); i
++)
1260 ICommand::execute (var
->asString(i
), CommandLog
);
1266 CLog logDisplayVars
;
1267 CLightMemDisplayer mdDisplayVars
;
1268 logDisplayVars
.addDisplayer (&mdDisplayVars
);
1271 // Activate the timeout assertion thread
1274 timeoutThread
= IThread::create(&MyTAT
, 1024*4);
1275 timeoutThread
->start();
1278 // Set service ready
1281 nlinfo ("SERVICE: Service ready");
1283 if (WindowDisplayer
!= NULL
)
1284 WindowDisplayer
->setTitleBar (_ShortName
+ " " + _LongName
+ " " + Version
.c_str());
1287 // Call the user service update each loop and check files and network activity
1290 TTime checkCpuProcTime
= 0;
1296 if(Bench
) CHTimer::startBench(false, true, false);
1298 // count the amount of time to manage internal system
1299 TTime bbefore
= CTime::getLocalTime ();
1301 // every second, check for CPU usage
1302 if (bbefore
- checkCpuProcTime
> 1000)
1304 checkCpuProcTime
= bbefore
;
1305 _CPUUsageStats
.peekMeasures();
1308 // call the user update and exit if the user update asks it
1310 H_AUTO(NLNETServiceUpdate
);
1313 CHTimer::endBench();
1318 // deal with any input waiting from stdin
1320 H_AUTO(NLNETStdinMonitorUpdate
);
1321 IStdinMonitorSingleton::getInstance()->update();
1324 // if the launching mode is 'quit after the first update' we set the exit signal
1327 // we use -100 so that the final return code ends as 0 (100+ExitSignalAsked) because
1328 // otherwise we can't launch services with -Q in a makefile
1329 ExitSignalAsked
= -100;
1333 // count the amount of time to manage internal system
1334 TTime before
= CTime::getLocalTime ();
1336 if (WindowDisplayer
!= NULL
)
1338 // update the window displayer and quit if asked
1339 if (!WindowDisplayer
->update ())
1341 nlinfo ("SERVICE: The window displayer was closed by user, need to quit");
1342 ExitSignalAsked
= 1;
1346 // stop the loop if the exit signal asked
1347 if (ExitSignalAsked
!= 0)
1349 if ( _RequestClosureClearanceCallback
)
1351 if ( _ClosureClearanceStatus
== CCClearedForClosure
)
1353 // Clearance has been granted
1354 CHTimer::endBench();
1357 else if ( _ClosureClearanceStatus
== CCMustRequestClearance
)
1359 if ( _RequestClosureClearanceCallback() )
1362 _ClosureClearanceStatus
= CCClearedForClosure
;
1363 CHTimer::endBench();
1368 // Delayed clearance
1369 _ClosureClearanceStatus
= CCWaitingForClearance
;
1372 else if ( _ClosureClearanceStatus
>= CCCallbackThenClose
)
1374 // Always direct closure, because we don't have a connection to the naming service anymore
1375 // But still call the callback
1376 _RequestClosureClearanceCallback();
1377 CHTimer::endBench();
1383 // Immediate closure, no clearance needed
1384 CHTimer::endBench();
1389 CConfigFile::checkConfigFiles ();
1393 CFile::checkFileChange();
1395 // update updatable interface
1396 set
<IServiceUpdatable
*>::iterator
first(_Updatables
.begin()), last(_Updatables
.end());
1397 for (; first
!= last
; ++first
)
1399 IServiceUpdatable
*updatable
= *first
;
1400 updatable
->serviceLoopUpdate();
1403 // get and manage layer 5 messages
1404 CUnifiedNetwork::getInstance()->update (_UpdateTimeout
);
1408 IModuleManager::getInstance().updateModules();
1411 // Allow direct closure if the naming service was lost
1412 if ( _RequestClosureClearanceCallback
)
1414 if ( ! CNamingClient::connected() )
1416 if ( _ClosureClearanceStatus
< CCCallbackThenClose
)
1417 _ClosureClearanceStatus
+= CCCallbackThenClose
; // change status but backup old value
1421 if ( _ClosureClearanceStatus
>= CCCallbackThenClose
)
1422 _ClosureClearanceStatus
-= CCCallbackThenClose
; // set the closure state back if the NS comes back
1426 NetSpeedLoop
= (sint32
) (CTime::getLocalTime () - before
);
1427 UserSpeedLoop
= (sint32
) (before
- bbefore
);
1428 L5CallbackTime
= TimeInCallback
- LastTimeInCallback
;
1429 LastTimeInCallback
= TimeInCallback
;
1430 L5CallbackCount
= TotalCallbackCalled
- LastTotalCallbackCalled
;
1431 LastTotalCallbackCalled
= TotalCallbackCalled
;
1433 if (WindowDisplayer
!= NULL
)
1435 static TTime lt
= 0;
1436 TTime ct
= CTime::getLocalTime();
1440 uint64 rcv
, snd
, rcvq
, sndq
;
1441 rcv
= CUnifiedNetwork::getInstance()->getBytesReceived ();
1442 snd
= CUnifiedNetwork::getInstance()->getBytesSent ();
1443 rcvq
= CUnifiedNetwork::getInstance()->getReceiveQueueSize ();
1444 sndq
= CUnifiedNetwork::getInstance()->getSendQueueSize ();
1446 for (uint i
= 0; i
< displayedVariables
.size(); i
++)
1448 // it s a separator, do nothing
1449 if (displayedVariables
[i
].first
.empty())
1452 // it s a command, do nothing
1453 if (displayedVariables
[i
].first
[0] == '@')
1456 string dispName
= displayedVariables
[i
].first
;
1457 string varName
= dispName
;
1458 string::size_type pos
= dispName
.find("|");
1459 if (pos
!= string::npos
)
1461 varName
= displayedVariables
[i
].first
.substr(pos
+1);
1462 dispName
= displayedVariables
[i
].first
.substr(0, pos
);
1465 if (dispName
.empty())
1468 str
= dispName
+ ": ";
1470 mdDisplayVars
.clear ();
1471 ICommand::execute(varName
, logDisplayVars
, true);
1472 const std::deque
<std::string
> &strs
= mdDisplayVars
.lockStrings();
1475 str
+= strs
[0].substr(0,strs
[0].size()-1);
1481 mdDisplayVars
.unlockStrings();
1482 WindowDisplayer
->setLabel (displayedVariables
[i
].second
, str
);
1489 // nldebug ("SYNC: updatetimeout must be %d and is %d, sleep the rest of the time", _UpdateTimeout, delta);
1491 CHTimer::endBench();
1493 // Resetting the hierarchical timer must be done outside the top-level timer
1494 if ( _ResetMeasures
)
1497 _ResetMeasures
= false;
1503 catch (const EFatalError
&)
1505 // Somebody call nlerror, so we have to quit now, the message already display
1506 // so we don't have to to anything
1507 setExitStatus (EXIT_FAILURE
);
1509 catch (const ESocket
&e
)
1511 // Catch NeL network exception to release the system cleanly setExitStatus (EXIT_FAILURE);
1512 ErrorLog
->displayNL( "NeL Exception in \"%s\": %s", _ShortName
.c_str(), e
.what() );
1514 catch ( uint
) // SEH exceptions
1516 ErrorLog
->displayNL( "SERVICE: System exception" );
1521 nlinfo ("SERVICE: Service starts releasing");
1524 // Call the user service release() if the init() was called
1529 setCurrentStatus("Releasing");
1533 CTransportClass::release();
1536 // Delete all network connection (naming client also)
1539 std::vector
<std::string
> namesOfOnlyServiceToFlushSendingV
;
1540 explode( NamesOfOnlyServiceToFlushSending
.get(), string(":"), namesOfOnlyServiceToFlushSendingV
, true );
1541 CUnifiedNetwork::getInstance()->release (FlushSendingQueuesOnExit
.get(), namesOfOnlyServiceToFlushSendingV
);
1543 // warn the module layer that the application is about to close
1544 IModuleManager::getInstance().applicationExit();
1546 // // release the network
1547 // CSock::releaseNetwork ();
1550 // Remove the window displayer
1553 if (WindowDisplayer
!= NULL
)
1555 DebugLog
->removeDisplayer (WindowDisplayer
);
1556 InfoLog
->removeDisplayer (WindowDisplayer
);
1557 WarningLog
->removeDisplayer (WindowDisplayer
);
1558 ErrorLog
->removeDisplayer (WindowDisplayer
);
1559 AssertLog
->removeDisplayer (WindowDisplayer
);
1560 CommandLog
.removeDisplayer (WindowDisplayer
);
1562 delete WindowDisplayer
;
1563 WindowDisplayer
= NULL
;
1566 nlinfo ("SERVICE: Service released successfully");
1568 catch (const EFatalError
&)
1570 // Somebody call nlerror, so we have to quit now, the message already display
1571 // so we don't have to to anything
1572 setExitStatus (EXIT_FAILURE
);
1575 // remove the stdin monitor thread
1576 IStdinMonitorSingleton::getInstance()->release(); // does nothing if not initialized
1578 // release the module manager
1579 IModuleManager::getInstance().releaseInstance();
1581 // release the network
1582 CSock::releaseNetwork ();
1584 // stop the timeout thread
1586 if (timeoutThread
!= NULL
)
1588 timeoutThread
->wait();
1589 delete timeoutThread
;
1593 CHTimer::displayByExecutionPath ();
1594 CHTimer::displayHierarchical(&CommandLog
, true, 64);
1595 CHTimer::displayHierarchicalByExecutionPathSorted (&CommandLog
, CHTimer::TotalTime
, true, 64);
1597 nlinfo ("SERVICE: Service ends");
1599 return ExitSignalAsked
?100+ExitSignalAsked
:getExitStatus ();
1602 void IService::exit (sint code
)
1604 nlinfo ("SERVICE: Somebody called IService::exit(), I have to quit");
1605 ExitSignalAsked
= code
;
1608 /// Push a new status on the status stack.
1609 void IService::setCurrentStatus(const std::string
&status
)
1611 // remove the status if it is already in the stack
1612 _ServiceStatusStack
.erase(std::remove(_ServiceStatusStack
.begin(), _ServiceStatusStack
.end(), status
), _ServiceStatusStack
.end());
1614 // insert the status on top of the stack
1615 _ServiceStatusStack
.push_back(status
);
1619 /// Remove a status from the status stack. If this status is at top of stack, the next status become the current status
1620 void IService::clearCurrentStatus(const std::string
&status
)
1622 // remove the status of the stack
1623 _ServiceStatusStack
.erase(std::remove(_ServiceStatusStack
.begin(), _ServiceStatusStack
.end(), status
), _ServiceStatusStack
.end());
1626 /// Add a tag in the status string
1627 void IService::addStatusTag(const std::string
&statusTag
)
1629 _ServiveStatusTags
.insert(statusTag
);
1632 /// Remove a tag from the status string
1633 void IService::removeStatusTag(const std::string
&statusTag
)
1635 _ServiveStatusTags
.erase(statusTag
);
1638 /// Get the current status with attached tags
1639 std::string
IService::getFullStatus() const
1643 // get hold of the status at the top of the status stack
1644 if (!_ServiceStatusStack
.empty())
1646 result
= _ServiceStatusStack
.back();
1649 // add status tags to the result so far
1650 set
<string
>::const_iterator
first(_ServiveStatusTags
.begin()), last(_ServiveStatusTags
.end());
1651 for (; first
!= last
; ++first
)
1653 if (first
!= _ServiveStatusTags
.begin() || !result
.empty())
1658 // return the result
1659 return result
.empty()? "Online": result
;
1664 * Require to reset the hierarchical timer
1666 void IService::requireResetMeasures()
1668 _ResetMeasures
= true;
1675 std::string
IService::getServiceUnifiedName () const
1677 nlassert (!_ShortName
.empty());
1679 if (!_AliasName
.empty())
1681 res
= _AliasName
+"/";
1684 if (_SId
.get() != 0)
1687 res
+= toString (_SId
.get());
1694 * Returns the date of launch of the service. Unit: see CTime::getSecondsSince1970()
1696 uint32
IService::getLaunchingDate () const
1698 return LaunchingDate
;
1702 void IService::registerUpdatable(IServiceUpdatable
*updatable
)
1704 _Updatables
.insert(updatable
);
1707 void IService::unregisterUpdatable(IServiceUpdatable
*updatable
)
1709 _Updatables
.erase(updatable
);
1713 // Commands and Variables for controling all services
1716 NLMISC_CATEGORISED_DYNVARIABLE(nel
, string
, LaunchingDate
, "date of the launching of the program")
1718 nlunreferenced(human
);
1719 if (get
) *pointer
= asctime (localtime ((time_t*)&LaunchingDate
));
1722 NLMISC_CATEGORISED_DYNVARIABLE(nel
, string
, Uptime
, "time from the launching of the program")
1727 *pointer
= secondsToHumanReadable (CTime::getSecondsSince1970() - LaunchingDate
);
1729 *pointer
= NLMISC::toString(CTime::getSecondsSince1970() - LaunchingDate
);
1733 NLMISC::fromString(*pointer
, LaunchingDate
);
1734 LaunchingDate
= CTime::getSecondsSince1970() - LaunchingDate
;
1738 NLMISC_CATEGORISED_VARIABLE(nel
, string
, CompilationDate
, "date of the compilation");
1739 NLMISC_CATEGORISED_VARIABLE(nel
, string
, CompilationMode
, "mode of the compilation");
1741 NLMISC_CATEGORISED_VARIABLE(nel
, uint32
, NbUserUpdate
, "number of time the user IService::update() called");
1743 NLMISC_CATEGORISED_DYNVARIABLE(nel
, string
, Scroller
, "current size in bytes of the sent queue size")
1745 nlunreferenced(human
);
1749 // display the scroll text
1750 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!!! "
1751 "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!!! ";
1753 *pointer
= foo
.substr ((pos
++)%(foo
.size()/2), 10);
1757 NLMISC_CATEGORISED_COMMAND(nel
, quit
, "exit the service", "")
1759 nlunreferenced(rawCommandString
);
1760 nlunreferenced(quiet
);
1761 nlunreferenced(human
);
1763 if(args
.size() != 0) return false;
1765 log
.displayNL("User ask me with a command to quit");
1766 ExitSignalAsked
= 0xFFFF;
1771 NLMISC_CATEGORISED_COMMAND(nel
, brutalQuit
, "exit the service brutally", "")
1773 nlunreferenced(rawCommandString
);
1774 nlunreferenced(log
);
1775 nlunreferenced(quiet
);
1776 nlunreferenced(human
);
1778 if(args
.size() != 0) return false;
1780 ::exit (0xFFFFFFFF);
1787 NLMISC_CATEGORISED_COMMAND(nel
, mutex
, "display mutex values", "")
1789 if(args
.size() != 0) return false;
1791 map
<CFairMutex
*,TMutexLocks
> acquiretimes
= getNewAcquireTimes();
1793 map
<CFairMutex
*,TMutexLocks
>::iterator im
;
1794 for ( im
=acquiretimes
.begin(); im
!=acquiretimes
.end(); ++im
)
1796 log
.displayNL( "%d %p %s: %.0f %.0f, called %u times th(%d, %d wait)%s", (*im
).second
.MutexNum
, (*im
).first
, (*im
).second
.MutexName
.c_str(),
1797 CTime::cpuCycleToSecond((*im
).second
.TimeToEnter
)*1000.0, CTime::cpuCycleToSecond((*im
).second
.TimeInMutex
)*1000.0,
1798 (*im
).second
.Nb
, (*im
).second
.ThreadHavingTheMutex
, (*im
).second
.WaitingMutex
,
1799 (*im
).second
.Dead
?" DEAD":"");
1804 #endif // MUTEX_DEBUG
1806 NLMISC_CATEGORISED_COMMAND(nel
, serviceInfo
, "display information about this service", "")
1808 nlunreferenced(rawCommandString
);
1809 nlunreferenced(quiet
);
1810 nlunreferenced(human
);
1812 if(args
.size() != 0) return false;
1814 log
.displayNL ("Service %s '%s' using NeL (" __DATE__
" " __TIME__
")", IService::getInstance()->getServiceLongName().c_str(), IService::getInstance()->getServiceUnifiedName().c_str());
1815 log
.displayNL ("Service listening port: %d", IService::getInstance()->ListeningPort
.get());
1816 log
.displayNL ("Service running directory: '%s'", IService::getInstance()->RunningDirectory
.c_str());
1817 log
.displayNL ("Service log directory: '%s'", IService::getInstance()->LogDirectory
.c_str());
1818 log
.displayNL ("Service save files directory: '%s'", IService::getInstance()->SaveFilesDirectory
.c_str());
1819 log
.displayNL ("Service write files directory: '%s'", IService::getInstance()->WriteFilesDirectory
.c_str());
1820 log
.displayNL ("Service config directory: '%s' config filename: '%s.cfg'", IService::getInstance()->ConfigDirectory
.c_str(), IService::getInstance()->_LongName
.c_str());
1821 log
.displayNL ("Service id: %hu", IService::getInstance()->_SId
.get());
1822 log
.displayNL ("Service update timeout: %dms", IService::getInstance()->_UpdateTimeout
);
1823 log
.displayNL ("Service %suse naming service", IService::getInstance()->_DontUseNS
?"don't ":"");
1824 log
.displayNL ("Service %suse admin executor service", IService::getInstance()->_DontUseAES
?"don't ":"");
1825 log
.displayNL ("NeL is compiled in %s mode", CompilationMode
.c_str());
1827 log
.displayNL ("Services arguments: %d args", IService::getInstance()->_Args
.size ());
1828 for (uint i
= 0; i
< IService::getInstance()->_Args
.size (); i
++)
1830 log
.displayNL (" argv[%d] = '%s'", i
, IService::getInstance()->_Args
[i
].c_str ());
1833 log
.displayNL ("Naming service info: %s", CNamingClient::info().c_str());
1835 ICommand::execute ("services", log
);
1840 NLMISC_CATEGORISED_COMMAND(nel
, resetMeasures
, "reset hierarchical timer", "")
1842 nlunreferenced(rawCommandString
);
1843 nlunreferenced(args
);
1844 nlunreferenced(log
);
1845 nlunreferenced(quiet
);
1846 nlunreferenced(human
);
1848 IService::getInstance()->requireResetMeasures();
1852 NLMISC_CATEGORISED_COMMAND(nel
, getWinDisplayerInfo
, "display the info about the pos and size of the window displayer", "")
1854 nlunreferenced(rawCommandString
);
1855 nlunreferenced(args
);
1856 nlunreferenced(quiet
);
1857 nlunreferenced(human
);
1860 IService::getInstance()->WindowDisplayer
->getWindowPos (x
,y
,w
,h
);
1861 log
.displayNL ("Window Displayer : XWinParam = %d; YWinParam = %d; WWinParam = %d; HWinParam = %d;", x
, y
, w
, h
);
1865 NLMISC_CATEGORISED_COMMAND(nel
, displayConfigFile
, "display the variables of the default configfile", "")
1867 nlunreferenced(rawCommandString
);
1868 nlunreferenced(args
);
1869 nlunreferenced(quiet
);
1870 nlunreferenced(human
);
1872 IService::getInstance()->ConfigFile
.display (&log
);
1876 NLMISC_CATEGORISED_COMMAND(nel
, getUnknownConfigFileVariables
, "display the variables from config file that are called but not present", "")
1878 nlunreferenced(rawCommandString
);
1879 nlunreferenced(args
);
1880 nlunreferenced(quiet
);
1881 nlunreferenced(human
);
1883 log
.displayNL ("%d Variables not found in the configfile '%s'", IService::getInstance()->ConfigFile
.UnknownVariables
.size(), IService::getInstance()->ConfigFile
.getFilename().c_str() );
1884 for (uint i
= 0; i
< IService::getInstance()->ConfigFile
.UnknownVariables
.size(); i
++)
1886 log
.displayNL (" %s", IService::getInstance()->ConfigFile
.UnknownVariables
[i
].c_str());
1891 // -1 = service is quitting
1892 // 0 = service is not connected
1893 // 1 = service is running
1894 // 2 = service is launching
1895 // 3 = service failed launching
1897 NLMISC_CATEGORISED_DYNVARIABLE(nel
, string
, State
, "Set this value to 0 to shutdown the service and 1 to start the service")
1899 nlunreferenced(human
);
1900 // read or write the variable
1906 if (IService::getInstance()->getServiceShortName() == "AES" || IService::getInstance()->getServiceShortName() == "AS")
1908 nlinfo ("SERVICE: I can't set State=0 because I'm the admin and I should never quit");
1910 else if (*pointer
== "0" || *pointer
== "2")
1912 // ok, we want to set the value to false, just quit
1913 nlinfo ("SERVICE: User ask me with a command to quit using the State variable");
1914 ExitSignalAsked
= 0xFFFE;
1915 IService
*srv
= IService::getInstance();
1920 srv
->setCurrentStatus("Quitting");
1924 nlwarning ("SERVICE: Unknown value for State '%s'", (*pointer
).c_str());
1928 // whether reading or writing, the internal value of the state variable should end up as the result of getFullStatus()
1929 IService
*srv
= IService::getInstance();
1934 *pointer
= srv
->getFullStatus();
1938 NLMISC_CATEGORISED_DYNVARIABLE(nel
, uint32
, ShardId
, "Get value of shardId set for this particular service")
1940 nlunreferenced(human
);
1941 // read or write the variable
1944 *pointer
= IService::getInstance()->getShardId();
1949 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, CPULoad
, "Get instant CPU load of the server")
1951 nlunreferenced(human
);
1952 // read or write the variable
1953 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPULoad(); }
1956 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, ProcessLoad
, "Get instant CPU load of the process/service")
1958 nlunreferenced(human
);
1959 // read or write the variable
1960 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessLoad(); }
1963 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, CPUUserLoad
, "Get instant CPU user load of the server")
1965 nlunreferenced(human
);
1966 // read or write the variable
1967 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUUserLoad(); }
1970 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, CPUSytemLoad
, "Get instant CPU system load of the server")
1972 nlunreferenced(human
);
1973 // read or write the variable
1974 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUSystemLoad(); }
1977 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, CPUNiceLoad
, "Get instant CPU nice processes load of the server")
1979 nlunreferenced(human
);
1980 // read or write the variable
1981 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUNiceLoad(); }
1984 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, CPUIOWaitLoad
, "Get instant CPU IO wait load of the server")
1986 nlunreferenced(human
);
1987 // read or write the variable
1988 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUIOWaitLoad(); }
1991 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, ProcessUserLoad
, "Get instant CPU user load of the process/service")
1993 nlunreferenced(human
);
1994 // read or write the variable
1995 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessUserLoad(); }
1998 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, ProcessSystemLoad
, "Get instant CPU system load of the process/service")
2000 nlunreferenced(human
);
2001 // read or write the variable
2002 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessSystemLoad(); }
2006 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanCPULoad
, "Get instant CPU load of the server")
2008 nlunreferenced(human
);
2009 // read or write the variable
2010 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPULoad(CCPUTimeStat::Mean
); }
2013 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanProcessLoad
, "Get instant CPU load of the process/service")
2015 nlunreferenced(human
);
2016 // read or write the variable
2017 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessLoad(CCPUTimeStat::Mean
); }
2020 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanCPUUserLoad
, "Get instant CPU user load of the server")
2022 nlunreferenced(human
);
2023 // read or write the variable
2024 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUUserLoad(CCPUTimeStat::Mean
); }
2027 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanCPUSytemLoad
, "Get instant CPU system load of the server")
2029 nlunreferenced(human
);
2030 // read or write the variable
2031 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUSystemLoad(CCPUTimeStat::Mean
); }
2034 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanCPUNiceLoad
, "Get instant CPU nice processes load of the server")
2036 nlunreferenced(human
);
2037 // read or write the variable
2038 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUNiceLoad(CCPUTimeStat::Mean
); }
2041 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanCPUIOWaitLoad
, "Get instant CPU IO wait load of the server")
2043 nlunreferenced(human
);
2044 // read or write the variable
2045 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUIOWaitLoad(CCPUTimeStat::Mean
); }
2048 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanProcessUserLoad
, "Get instant CPU user load of the process/service")
2050 nlunreferenced(human
);
2051 // read or write the variable
2052 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessUserLoad(CCPUTimeStat::Mean
); }
2055 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, MeanProcessSystemLoad
, "Get instant CPU system load of the process/service")
2057 nlunreferenced(human
);
2058 // read or write the variable
2059 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessSystemLoad(CCPUTimeStat::Mean
); }
2064 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakCPULoad
, "Get instant CPU load of the server")
2066 nlunreferenced(human
);
2067 // read or write the variable
2068 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPULoad(CCPUTimeStat::Peak
); }
2071 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakProcessLoad
, "Get instant CPU load of the process/service")
2073 nlunreferenced(human
);
2074 // read or write the variable
2075 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessLoad(CCPUTimeStat::Peak
); }
2078 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakCPUUserLoad
, "Get instant CPU user load of the server")
2080 nlunreferenced(human
);
2081 // read or write the variable
2082 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUUserLoad(CCPUTimeStat::Peak
); }
2085 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakCPUSytemLoad
, "Get instant CPU system load of the server")
2087 nlunreferenced(human
);
2088 // read or write the variable
2089 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUSystemLoad(CCPUTimeStat::Peak
); }
2092 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakCPUNiceLoad
, "Get instant CPU nice processes load of the server")
2094 nlunreferenced(human
);
2095 // read or write the variable
2096 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUNiceLoad(CCPUTimeStat::Peak
); }
2099 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakCPUIOWaitLoad
, "Get instant CPU IO wait load of the server")
2101 nlunreferenced(human
);
2102 // read or write the variable
2103 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getCPUIOWaitLoad(CCPUTimeStat::Peak
); }
2106 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakProcessUserLoad
, "Get instant CPU user load of the process/service")
2108 nlunreferenced(human
);
2109 // read or write the variable
2110 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessUserLoad(CCPUTimeStat::Peak
); }
2113 NLMISC_CATEGORISED_DYNVARIABLE(cpu
, float, PeakProcessSystemLoad
, "Get instant CPU system load of the process/service")
2115 nlunreferenced(human
);
2116 // read or write the variable
2117 if (get
) { *pointer
= IService::getInstance()->getCPUUsageStats().getProcessSystemLoad(CCPUTimeStat::Peak
); }