Fix Systemd unitdir path on x86_64
[profile/ivi/node-state-manager.git] / NodeStateManager / NodeStateManager.c
1 /**********************************************************************************************************************
2 *
3 * Copyright (C) 2013 Continental Automotive Systems, Inc.
4 *
5 * Author: Jean-Pierre.Bogler@continental-corporation.com
6 *
7 * Implementation of the NodeStateManager
8 *
9 * The NodeStateManager (NSM) is a central state manager for the system node. It manages the "NodeState",
10 * the "ApplicationMode" and many other states of the complete system. In addition, the NSM offers a
11 * session handling and a shutdown management.
12 * The NSM communicates with the NodeStateMachine (NSMC) to request and inform it about state changes
13 * and the NodeStateAccess (NSMA) to connect to the D-Bus.
14 *
15 * This Source Code Form is subject to the terms of the Mozilla Public
16 * License, v. 2.0. If a copy of the MPL was not distributed with this
17 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
18 *
19 **********************************************************************************************************************/
20
21
22 /**********************************************************************************************************************
23 *
24 * Header includes
25 *
26 **********************************************************************************************************************/
27 #include "NodeStateManager.h"               /* Own Header file                */
28 #include "NodeStateTypes.h"                 /* Typedefinitions to use the NSM */
29 #include "string.h"                         /* Memcpy etc.                    */
30 #include "gio/gio.h"                        /* GLib lists                     */
31 #include "dlt/dlt.h"                        /* DLT Log'n'Trace                */
32 #include "NodeStateMachine.h"               /* Talk to NodeStateMachine       */
33 #include "NodeStateAccess.h"                /* Access the IPC (D-Bus)         */
34 #include "syslog.h"                         /* Syslog messages                */
35 #include <systemd/sd-daemon.h>              /* Systemd wdog                   */
36 #include <persistence_client_library.h>     /* Init/DeInit PCL                */
37 #include <persistence_client_library_key.h> /* Access persistent data         */
38
39
40 /**********************************************************************************************************************
41 *
42 * Local defines, macros and type definitions.
43 *
44 **********************************************************************************************************************/
45
46 /* Defines to access persistence keys */
47 #define NSM_PERS_APPLICATION_MODE_DB  0xFF
48 #define NSM_PERS_APPLICATION_MODE_KEY "ERG_OIP_NSM_NODE_APPMODE"
49
50 /* The type defines the structure for a lifecycle consumer client                             */
51 typedef struct
52 {
53   gchar                  *sBusName;          /* Bus name of the lifecycle client              */
54   gchar                  *sObjName;          /* Object path of the client                     */
55   guint32                 u32RegisteredMode; /* Bit array of shutdown modes                   */
56   NSMA_tLcConsumerHandle  hClient;           /* Handle for proxy object for lifecycle client  */
57   gboolean                boShutdown;        /* Only "run up" clients which are shut down     */
58 } NSM__tstLifecycleClient;
59
60
61 /* The type is used to store failed applications. A struct is used to allow extsions in future */
62 typedef struct
63 {
64   gchar sName[NSM_MAX_SESSION_OWNER_LENGTH];
65 } NSM__tstFailedApplication;
66
67
68 /* List of names for the available default sessions, will are automatically provided by NSM    */
69 static const gchar* NSM__asDefaultSessions[] = { "DiagnosisSession",
70                                                  "HevacSession",
71                                                  "HmiActiveSession",
72                                                  "NetworkActiveSession",
73                                                  "NetworkPassiveSession",
74                                                  "PdcSession",
75                                                  "PermanentModeSession",
76                                                  "PhoneSession",
77                                                  "RvcSession",
78                                                  "SwlSession",
79                                                  "ProductLcSession",
80                                                  "PlatformThermalSession",
81                                                  "PlatformSupplySession",
82                                                  "PersistencySession"
83                                                };
84
85 /**********************************************************************************************************************
86 *
87 * Prototypes for file local functions (see implementation for description)
88 *
89 **********************************************************************************************************************/
90
91 /* Helper functions to destruct objects */
92 static void NSM__vFreeFailedApplicationObject(gpointer pFailedApplication);
93 static void NSM__vFreeSessionObject          (gpointer pSession          );
94 static void NSM__vFreeLifecycleClientObject  (gpointer pLifecycleClient  );
95
96
97 /* Helper functions to compare objects in lists */
98 static gboolean NSM__boIsPlatformSession           (NsmSession_s *pstSession);
99 static gint     NSM__i32LifecycleClientCompare     (gconstpointer pL1, gconstpointer pL2);
100 static gint     NSM__i32SessionOwnerNameSeatCompare(gconstpointer pS1, gconstpointer pS2);
101 static gint     NSM__i32SessionNameSeatCompare     (gconstpointer pS1, gconstpointer pS2);
102 static gint     NSM__i32SessionOwnerCompare        (gconstpointer pS1, gconstpointer pS2);
103 static gint     NSM__i32ApplicationCompare         (gconstpointer pA1, gconstpointer pA2);
104
105
106 /* Helper functions to recognize failed applications and disable their sessions */
107 static void             NSM__vDisableSessionsForApp(NSM__tstFailedApplication* pstFailedApp);
108 static NsmErrorStatus_e NSM__enSetAppStateFailed   (NSM__tstFailedApplication* pstFailedApp);
109 static NsmErrorStatus_e NSM__enSetAppStateValid    (NSM__tstFailedApplication* pstFailedApp);
110
111
112 /* Helper functions to control and start the "lifecycle request" sequence */
113 static void NSM__vCallNextLifecycleClient(void);
114 static void NSM__vOnLifecycleRequestFinish(const NsmErrorStatus_e enErrorStatus);
115
116
117 /* Internal functions, to set and get values. Indirectly used by D-Bus and StateMachine */
118 static NsmErrorStatus_e     NSM__enRegisterSession       (NsmSession_s *session,
119                                                                   gboolean      boInformBus,
120                                                                   gboolean      boInformMachine);
121 static NsmErrorStatus_e     NSM__enUnRegisterSession     (NsmSession_s *session,
122                                                                   gboolean      boInformBus,
123                                                                   gboolean      boInformMachine);
124 static NsmErrorStatus_e     NSM__enSetNodeState          (NsmNodeState_e       enNodeState,
125                                                           gboolean             boInformBus,
126                                                           gboolean             boInformMachine);
127 static NsmErrorStatus_e     NSM__enSetBootMode           (const gint           i32BootMode,
128                                                           gboolean             boInformMachine);
129 static NsmErrorStatus_e     NSM__enSetApplicationMode    (NsmApplicationMode_e enApplicationMode,
130                                                           gboolean             boInformBus,
131                                                           gboolean             boInformMachine);
132 static NsmErrorStatus_e     NSM__enSetShutdownReason     (NsmShutdownReason_e  enNewShutdownReason,
133                                                           gboolean             boInformMachine);
134
135 static void                 NSM__vPublishSessionChange   (NsmSession_s        *pstChangedSession,
136                                                           gboolean             boInformBus,
137                                                           gboolean             boInformMachine);
138 static NsmErrorStatus_e     NSM__enSetDefaultSessionState(NsmSession_s        *pstSession,
139                                                           gboolean             boInformBus,
140                                                           gboolean             boInformMachine);
141 static NsmErrorStatus_e     NSM__enSetProductSessionState(NsmSession_s        *pstSession,
142                                                           gboolean             boInformBus,
143                                                           gboolean             boInformMachine);
144 static NsmErrorStatus_e     NSM__enSetSessionState       (NsmSession_s        *pstSession,
145                                                           gboolean             boInformBus,
146                                                           gboolean             boInformMachine);
147 static NsmErrorStatus_e     NSM__enGetSessionState       (NsmSession_s        *pstSession);
148
149
150 /* Internal functions that are directly used from D-Bus and StateMachine */
151 static NsmErrorStatus_e     NSM__enGetNodeState      (NsmNodeState_e *penNodeState);
152 static NsmErrorStatus_e     NSM__enGetApplicationMode(NsmApplicationMode_e *penApplicationMode);
153
154
155 /* Callbacks for D-Bus interfaces of the NodeStateManager */
156 static NsmErrorStatus_e NSM__enOnHandleSetBootMode              (const gint                  i32BootMode);
157 static NsmErrorStatus_e NSM__enOnHandleSetNodeState             (const NsmNodeState_e        enNodeState);
158 static NsmErrorStatus_e NSM__enOnHandleSetApplicationMode       (const NsmApplicationMode_e  enApplMode);
159 static NsmErrorStatus_e NSM__enOnHandleRequestNodeRestart       (const NsmRestartReason_e    enRestartReason,
160                                                                  const guint                 u32RestartType);
161 static NsmErrorStatus_e NSM__enOnHandleSetAppHealthStatus       (const gchar                *sAppName,
162                                                                  const gboolean              boAppState);
163 static gboolean         NSM__boOnHandleCheckLucRequired         (void);
164 static NsmErrorStatus_e NSM__enOnHandleRegisterSession          (const gchar                *sSessionName,
165                                                                  const gchar                *sSessionOwner,
166                                                                  const NsmSeat_e             enSeatId,
167                                                                  const NsmSessionState_e     enSessionState);
168 static NsmErrorStatus_e NSM__enOnHandleUnRegisterSession        (const gchar                *sSessionName,
169                                                                  const gchar                *sSessionOwner,
170                                                                  const NsmSeat_e             enSeatId);
171 static NsmErrorStatus_e NSM__enOnHandleRegisterLifecycleClient  (const gchar                *sBusName,
172                                                                  const gchar                *sObjName,
173                                                                  const guint                 u32ShutdownMode,
174                                                                  const guint                 u32TimeoutMs);
175 static NsmErrorStatus_e NSM__enOnHandleUnRegisterLifecycleClient(const gchar                *sBusName,
176                                                                  const gchar                *sObjName,
177                                                                  const guint                 u32ShutdownMode);
178 static NsmErrorStatus_e NSM__enOnHandleGetSessionState          (const gchar                *sSessionName,
179                                                                  const NsmSeat_e             enSeatId,
180                                                                  NsmSessionState_e          *penSessionState);
181 static NsmErrorStatus_e NSM__enOnHandleSetSessionState          (const gchar                *sSessionName,
182                                                                  const gchar                *sSessionOwner,
183                                                                  const NsmSeat_e             enSeatId,
184                                                                  const NsmSessionState_e     enSessionState);
185 static guint NSM__u32OnHandleGetAppHealthCount                  (void);
186 static guint NSM__u32OnHandleGetInterfaceVersion                (void);
187
188 /* Functions to simplify internal work flow */
189 static void  NSM__vInitializeVariables   (void);
190 static void  NSM__vCreatePlatformSessions(void);
191 static void  NSM__vCreateMutexes         (void);
192 static void  NSM__vDeleteMutexes         (void);
193
194 /* LTPROF helper function */
195 static void NSM__vLtProf(gchar *pszBus, gchar *pszObj, guint32 dwReason, gchar *pszInOut, guint32 dwValue);
196 static void NSM__vSyslogOpen(void);
197 static void NSM__vSyslogClose(void);
198
199 /* Systemd watchdog functions */
200 static gboolean NSM__boOnHandleTimerWdog(gpointer pUserData);
201 static void     NSM__vConfigureWdogTimer(void);
202
203 /**********************************************************************************************************************
204 *
205 * Local variables and constants
206 *
207 **********************************************************************************************************************/
208
209 /* Context for Log'n'Trace */
210 DLT_DECLARE_CONTEXT(NsmContext);
211
212 /* Variables for "Properties" hosted by the NSM */
213 static GMutex                    *NSM__pSessionMutex           = NULL;
214 static GSList                    *NSM__pSessions               = NULL;
215
216 static GList                     *NSM__pLifecycleClients       = NULL;
217
218 static GMutex                    *NSM__pNodeStateMutex         = NULL;
219 static NsmNodeState_e             NSM__enNodeState             = NsmNodeState_NotSet;
220
221 static GMutex                    *NSM__pNextApplicationModeMutex = NULL;
222 static GMutex                    *NSM__pThisApplicationModeMutex = NULL;
223 static NsmApplicationMode_e       NSM__enNextApplicationMode     = NsmApplicationMode_NotSet;
224 static NsmApplicationMode_e       NSM__enThisApplicationMode     = NsmApplicationMode_NotSet;
225 static gboolean                   NSM__boThisApplicationModeRead = FALSE;
226
227 static GSList                    *NSM__pFailedApplications     = NULL;
228
229 /* Variables for internal state management (of lifecycle requests) */
230 static NSM__tstLifecycleClient   *NSM__pCurrentLifecycleClient = NULL;
231
232 /* Constant array of callbacks which are registered at the NodeStateAccess library */
233 static const NSMA_tstObjectCallbacks NSM__stObjectCallBacks = { &NSM__enOnHandleSetBootMode,
234                                                                 &NSM__enOnHandleSetNodeState,
235                                                                 &NSM__enOnHandleSetApplicationMode,
236                                                                 &NSM__enOnHandleRequestNodeRestart,
237                                                                 &NSM__enOnHandleSetAppHealthStatus,
238                                                                 &NSM__boOnHandleCheckLucRequired,
239                                                                 &NSM__enOnHandleRegisterSession,
240                                                                 &NSM__enOnHandleUnRegisterSession,
241                                                                 &NSM__enOnHandleRegisterLifecycleClient,
242                                                                 &NSM__enOnHandleUnRegisterLifecycleClient,
243                                                                 &NSM__enGetApplicationMode,
244                                                                 &NSM__enOnHandleGetSessionState,
245                                                                 &NSM__enGetNodeState,
246                                                                 &NSM__enOnHandleSetSessionState,
247                                                                 &NSM__u32OnHandleGetAppHealthCount,
248                                                                 &NSM__u32OnHandleGetInterfaceVersion,
249                                                                 &NSM__vOnLifecycleRequestFinish
250                                                               };
251
252 /**********************************************************************************************************************
253 *
254 * Local (static) functions
255 *
256 **********************************************************************************************************************/
257
258
259 /**********************************************************************************************************************
260 *
261 * This helper function is called from various places to check if a session is a "platform" session.
262 *
263 * @param  pstSession: Pointer to the session for which a check should be done, if it is a platform session
264 *
265 * @return TRUE:  The session is a "platform" session
266 *         FALSE: The session is not a "platform" session
267 *
268 **********************************************************************************************************************/
269 static gboolean NSM__boIsPlatformSession(NsmSession_s *pstSession)
270 {
271   /* Function local variables */
272   gboolean boIsPlatformSession = FALSE;
273   guint16  u16SessionIdx       = 0;
274
275   for(u16SessionIdx = 0;
276          (u16SessionIdx       <  sizeof(NSM__asDefaultSessions)/sizeof(gchar*))
277       && (boIsPlatformSession == FALSE);
278       u16SessionIdx++)
279   {
280     boIsPlatformSession = (g_strcmp0(pstSession->sName, NSM__asDefaultSessions[u16SessionIdx]) == 0);
281   }
282
283   return boIsPlatformSession;
284 }
285
286
287 /**
288 * NSM__enRegisterSession:
289 * @session:         Ptr to NsmSession_s structure containing data to register a session
290 * @boInformBus:     Flag whether the a dbus signal should be send to inform about the new session
291 * @boInformMachine: Flag whether the NSMC should be informed about the new session
292 *
293 * The internal function is used to register a session. It is either called from the dbus callback
294 * or it is called via the internal context of the NSMC.
295 */
296 static NsmErrorStatus_e NSM__enRegisterSession(NsmSession_s *session, gboolean boInformBus, gboolean boInformMachine)
297 {
298   /* Function local variables                                              */
299   NsmErrorStatus_e enRetVal     = NsmErrorStatus_NotSet; /* Return value   */
300   NsmSession_s     *pNewSession = NULL;  /* Pointer to new created session */
301   GSList           *pListEntry  = NULL;  /* Pointer to list entry          */
302
303   if(    (g_strcmp0(session->sOwner, NSM_DEFAULT_SESSION_OWNER) != 0)
304       && (session->enState                                      > NsmSessionState_Unregistered))
305   {
306           if(NSM__boIsPlatformSession(session) == FALSE)
307           {
308             g_mutex_lock(NSM__pSessionMutex);
309
310             pListEntry = g_slist_find_custom(NSM__pSessions, session, &NSM__i32SessionNameSeatCompare);
311
312             if(pListEntry == NULL)
313             {
314               enRetVal = NsmErrorStatus_Ok;
315
316               pNewSession  = g_new0(NsmSession_s, 1);
317               memcpy(pNewSession, session, sizeof(NsmSession_s));
318
319               DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Registered session."                          ),
320                                                 DLT_STRING(" Name: "         ), DLT_STRING(session->sName      ),
321                                                 DLT_STRING(" Owner: "        ), DLT_STRING(session->sOwner     ),
322                                                 DLT_STRING(" Seat: "         ), DLT_INT((gint) session->enSeat ),
323                                                 DLT_STRING(" Initial state: "), DLT_INT((gint) session->enState));
324
325               /* Return OK and append new object */
326               NSM__pSessions = g_slist_append(NSM__pSessions, pNewSession);
327
328               /* Inform D-Bus and StateMachine about the new session. */
329               NSM__vPublishSessionChange(pNewSession, boInformBus, boInformMachine);
330             }
331             else
332             {
333               /* Error: The session already exists. Don't store passed state. */
334               enRetVal = NsmErrorStatus_WrongSession;
335               DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: Failed to register session. Session already exists."),
336                                                 DLT_STRING(" Name: "         ), DLT_STRING(session->sName            ),
337                                                 DLT_STRING(" Owner: "        ), DLT_STRING(session->sOwner           ),
338                                                 DLT_STRING(" Seat: "         ), DLT_INT((gint) session->enSeat       ),
339                                                 DLT_STRING(" Initial state: "), DLT_INT((gint) session->enState      ));
340             }
341
342             g_mutex_unlock(NSM__pSessionMutex);
343           }
344           else
345           {
346             /* Error: It is not allowed to re-register a default session! */
347             enRetVal = NsmErrorStatus_Parameter;
348             DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to register session. Re-Registration of default session not allowed."),
349                                                DLT_STRING(" Name: "         ), DLT_STRING(session->sName                                    ),
350                                                DLT_STRING(" Owner: "        ), DLT_STRING(session->sOwner                                   ),
351                                                DLT_STRING(" Seat: "         ), DLT_INT((gint) session->enSeat                               ),
352                                                DLT_STRING(" Initial state: "), DLT_INT((gint) session->enState                              ));
353           }
354   }
355   else
356   {
357     /* Error: A parameter with an invalid value has been passed */
358     enRetVal = NsmErrorStatus_Parameter;
359     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to register session. Invalid owner or state."),
360                                        DLT_STRING(" Name: "         ), DLT_STRING(session->sName            ),
361                                        DLT_STRING(" Owner: "        ), DLT_STRING(session->sOwner           ),
362                                        DLT_STRING(" Seat: "         ), DLT_INT((gint) session->enSeat       ),
363                                        DLT_STRING(" Initial state: "), DLT_INT((gint) session->enState      ));
364   }
365
366   return enRetVal;
367 }
368
369
370 /**
371 * NSM__enUnRegisterSession:
372 * @session:         Ptr to NsmSession_s structure containing data to unregister a session
373 * @boInformBus:     Flag whether the a dbus signal should be send to inform about the lost session
374 * @boInformMachine: Flag whether the NSMC should be informed about the lost session
375 *
376 * The internal function is used to unregister a session. It is either called from the dbus callback
377 * or it is called via the internal context of the NSMC.
378 */
379 static NsmErrorStatus_e NSM__enUnRegisterSession(NsmSession_s *session, gboolean boInformBus, gboolean boInformMachine)
380 {
381   /* Function local variables                                                                */
382   NsmErrorStatus_e  enRetVal         = NsmErrorStatus_NotSet; /* Return value                */
383   NsmSession_s     *pExistingSession = NULL;                  /* Pointer to existing session */
384   GSList           *pListEntry       = NULL;                  /* Pointer to list entry       */
385
386   if(NSM__boIsPlatformSession(session) == FALSE)
387   {
388     g_mutex_lock(NSM__pSessionMutex);
389
390     pListEntry = g_slist_find_custom(NSM__pSessions, session, &NSM__i32SessionOwnerNameSeatCompare);
391
392     /* Check if the session exists */
393     if(pListEntry != NULL)
394     {
395       /* Found the session in the list. Now remove it. */
396       enRetVal = NsmErrorStatus_Ok;
397       pExistingSession = (NsmSession_s*) pListEntry->data;
398
399       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Unregistered session."                          ),
400                                         DLT_STRING(" Name: "      ), DLT_STRING(pExistingSession->sName  ),
401                                         DLT_STRING(" Owner: "     ), DLT_STRING(pExistingSession->sOwner ),
402                                         DLT_STRING(" Seat: "      ), DLT_INT(   pExistingSession->enSeat ),
403                                         DLT_STRING(" Last state: "), DLT_INT(   pExistingSession->enState));
404
405       pExistingSession->enState = NsmSessionState_Unregistered;
406
407       /* Inform D-Bus and StateMachine about the unregistered session */
408       NSM__vPublishSessionChange(pExistingSession, boInformBus, boInformMachine);
409
410       NSM__vFreeSessionObject(pExistingSession);
411       NSM__pSessions = g_slist_remove(NSM__pSessions, pExistingSession);
412     }
413     else
414     {
415       /* Error: The session is unknown. */
416       enRetVal = NsmErrorStatus_WrongSession;
417       DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: Failed to unregister session. Session unknown."),
418                                         DLT_STRING(" Name: "      ), DLT_STRING(session->sName          ),
419                                         DLT_STRING(" Owner: "     ), DLT_STRING(session->sOwner         ),
420                                         DLT_STRING(" Seat: "      ), DLT_INT((gint) session->enSeat     ));
421     }
422
423     g_mutex_unlock(NSM__pSessionMutex);
424   }
425   else
426   {
427     /* Error: Failed to unregister session. The passed session is a "platform" session. */
428     enRetVal = NsmErrorStatus_WrongSession;
429     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to unregister session. The session is a platform session."),
430                                        DLT_STRING(" Name: "      ), DLT_STRING(session->sName                            ),
431                                        DLT_STRING(" Owner: "     ), DLT_STRING(session->sOwner                           ),
432                                        DLT_STRING(" Seat: "      ), DLT_INT((gint) session->enSeat                       ));
433   }
434
435   return enRetVal;
436 }
437
438
439 /**********************************************************************************************************************
440 *
441 * The function is called from IPC and StateMachine to set the NodeState.
442 *
443 * @param enNodeState:     New NodeState that should be stored.
444 * @param boInformBus:     Defines whether a D-Bus signal should be send when the NodeState could be changed.
445 * @param boInformMachine: Defines whether the StateMachine should be informed about the new NodeState.
446 *
447 * @return see NsmErrorStatus_e
448 *
449 **********************************************************************************************************************/
450 static NsmErrorStatus_e NSM__enSetNodeState(NsmNodeState_e enNodeState, gboolean boInformBus, gboolean boInformMachine)
451 {
452   /* Function local variables                                        */
453   NsmErrorStatus_e enRetVal = NsmErrorStatus_NotSet; /* Return value */
454
455   /* Check if the passed parameter is valid */
456   if((enNodeState > NsmNodeState_NotSet) && (enNodeState < NsmNodeState_Last))
457   {
458     /* Assert that the Node not already is shut down. Otherwise it will switch of immediately */
459     enRetVal = NsmErrorStatus_Ok;
460
461     g_mutex_lock(NSM__pNodeStateMutex);
462
463     /* Only store the new value and emit a signal, if the new value is different */
464     if(NSM__enNodeState != enNodeState)
465     {
466       /* Store the last NodeState, before switching to the new one */
467       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Changed NodeState."                           ),
468                                         DLT_STRING(" Old NodeState: "), DLT_INT((gint) NSM__enNodeState),
469                                         DLT_STRING(" New NodeState: "), DLT_INT((gint) enNodeState     ));
470
471
472       /* Store the passed NodeState and emit a signal to inform system that the NodeState changed */
473       NSM__enNodeState = enNodeState;
474
475       /* If required, inform the D-Bus about the change (send signal) */
476       if(boInformBus == TRUE)
477       {
478         (void) NSMA_boSendNodeStateSignal(NSM__enNodeState);
479       }
480
481       /* If required, inform the StateMachine about the change */
482       if(boInformMachine == TRUE)
483       {
484         NsmcSetData(NsmDataType_NodeState, (unsigned char*) &NSM__enNodeState,  sizeof(NsmDataType_NodeState));
485       }
486
487       /* Leave the lock now, because its not recursive. 'NSM__vCallNextLifecycleClient' may need it. */
488       g_mutex_unlock(NSM__pNodeStateMutex);
489
490       /* Check if a new life cycle request needs to be started based on the new ShutdownType */
491       if(NSM__pCurrentLifecycleClient == NULL)
492       {
493         NSM__vCallNextLifecycleClient();
494       }
495     }
496     else
497     {
498       /* NodeState stays the same. Just leave the lock. */
499       g_mutex_unlock(NSM__pNodeStateMutex);
500     }
501   }
502   else
503   {
504     /* Error: The passed boot mode is invalid. Return an error. */
505     enRetVal = NsmErrorStatus_Parameter;
506     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to change NodeState. Invalid parameter."),
507                                        DLT_STRING(" Old NodeState: "),     DLT_INT(NSM__enNodeState    ),
508                                        DLT_STRING(" Desired NodeState: "), DLT_INT((gint) enNodeState) );
509   }
510
511   return enRetVal;
512 }
513
514
515 /**********************************************************************************************************************
516 *
517 * The function is called from IPC and StateMachine to get the NodeState.
518 *
519 * @return see NsmNodeState_e
520 *
521 **********************************************************************************************************************/
522 static NsmErrorStatus_e NSM__enGetNodeState(NsmNodeState_e *penNodeState)
523 {
524   NsmErrorStatus_e enRetVal = NsmErrorStatus_NotSet;
525
526   if(penNodeState != NULL)
527   {
528     enRetVal = NsmErrorStatus_Ok;
529
530     g_mutex_lock(NSM__pNodeStateMutex);
531     *penNodeState = NSM__enNodeState;
532     g_mutex_unlock(NSM__pNodeStateMutex);
533   }
534   else
535   {
536     enRetVal = NsmErrorStatus_Parameter;
537   }
538
539   return enRetVal;
540 }
541
542
543 /**********************************************************************************************************************
544 *
545 * The function is called from IPC and StateMachine to set the BootMode.
546 *
547 * @param i32BootMode:     New BootMode that should be stored.
548 * @param boInformBus:     Defines whether a D-Bus signal should be send when the BootMode could be changed.
549 * @param boInformMachine: Defines whether the StateMachine should be informed about the new BootMode.
550 *
551 * @return see NsmErrorStatus_e
552 *
553 **********************************************************************************************************************/
554 static NsmErrorStatus_e NSM__enSetBootMode(const gint i32BootMode, gboolean boInformMachine)
555 {
556   /* Function local variables */
557   gint             i32CurrentBootMode = 0;
558   NsmErrorStatus_e enRetVal           = NsmErrorStatus_NotSet;
559
560   /* The BootMode property should be thread safe by D-Bus. No critical section need.  */
561   (void) NSMA_boGetBootMode(&i32CurrentBootMode);
562   enRetVal           = NsmErrorStatus_Ok;
563
564   if(i32CurrentBootMode != i32BootMode)
565   {
566     (void) NSMA_boSetBootMode(i32BootMode);
567
568     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Changed BootMode."                      ),
569                                       DLT_STRING(" Old BootMode: "), DLT_INT(i32CurrentBootMode),
570                                       DLT_STRING(" New BootMode: "), DLT_INT(i32BootMode       ));
571
572     /* Inform the machine if desired. The D-Bus will auto. update, because this is property */
573     if(boInformMachine == TRUE)
574     {
575        NsmcSetData(NsmDataType_BootMode, (unsigned char*) &i32BootMode,  sizeof(gint));
576     }
577   }
578
579   /* Return ok. There is no limitation for this value. */
580   return enRetVal;
581 }
582
583 /**********************************************************************************************************************
584 *
585 * The function is called from IPC and StateMachine to set the ApplicationMode.
586 *
587 * @param enApplicationMode: New application mode that should be stored.
588 * @param boInformBus:       Defines whether a D-Bus signal should be send when the ApplicationMode could be changed.
589 * @param boInformMachine:   Defines whether the StateMachine should be informed about the new ApplicationMode.
590 *
591 * @return see NsmErrorStatus_e
592 *
593 **********************************************************************************************************************/
594 static NsmErrorStatus_e
595 NSM__enSetApplicationMode(NsmApplicationMode_e enApplicationMode,
596                           gboolean             boInformBus,
597                           gboolean             boInformMachine)
598 {
599   /* Function local variables                                          */
600   NsmErrorStatus_e enRetVal   = NsmErrorStatus_NotSet; /* Return value */
601   int              pcl_return = 0;
602
603   /* Check if the passed parameter is valid */
604   if(    (enApplicationMode > NsmApplicationMode_NotSet)
605       && (enApplicationMode < NsmApplicationMode_Last  ))
606   {
607     /* The passed parameter is valid. Return OK */
608     enRetVal = NsmErrorStatus_Ok;
609
610     g_mutex_lock(NSM__pNextApplicationModeMutex);
611
612     /* Only store new value and emit signal, if new value is different */
613     if(NSM__enNextApplicationMode != enApplicationMode)
614     {
615       /* Store new value and emit signal with new application mode */
616       DLT_LOG(NsmContext,
617               DLT_LOG_INFO,
618               DLT_STRING("NSM: Changed ApplicationMode.");
619               DLT_STRING("Old AppMode:"); DLT_INT((int) NSM__enNextApplicationMode);
620               DLT_STRING("New AppMode:"); DLT_INT((int) enApplicationMode));
621
622       NSM__enNextApplicationMode = enApplicationMode;
623
624       /* If original persistent value has not been read before, get it now! */
625       g_mutex_lock(NSM__pThisApplicationModeMutex);
626
627       if(NSM__boThisApplicationModeRead == FALSE)
628       {
629         /* Get data from persistence */
630         pcl_return = pclKeyReadData(NSM_PERS_APPLICATION_MODE_DB,
631                                     NSM_PERS_APPLICATION_MODE_KEY,
632                                     0,
633                                     0,
634                                     (unsigned char*) &NSM__enThisApplicationMode,
635                                     sizeof(NSM__enThisApplicationMode));
636
637         if(pcl_return != sizeof(NSM__enThisApplicationMode))
638         {
639           NSM__enThisApplicationMode = NsmApplicationMode_NotSet;
640           DLT_LOG(NsmContext,
641                   DLT_LOG_WARN,
642                   DLT_STRING("NSM: Failed to read ApplicationMode.");
643                   DLT_STRING("Error: Unexpected PCL return.");
644                   DLT_STRING("Return:"); DLT_INT(pcl_return));
645         }
646
647         NSM__boThisApplicationModeRead = TRUE;
648       }
649
650       g_mutex_unlock(NSM__pThisApplicationModeMutex);
651
652       /* Write the new application mode to persistence */
653       pcl_return = pclKeyWriteData(NSM_PERS_APPLICATION_MODE_DB,
654                                    NSM_PERS_APPLICATION_MODE_KEY,
655                                    0,
656                                    0,
657                                    (unsigned char*) &NSM__enNextApplicationMode,
658                                    sizeof(NSM__enNextApplicationMode));
659
660       if(pcl_return != sizeof(NSM__enNextApplicationMode))
661       {
662         DLT_LOG(NsmContext,
663                 DLT_LOG_ERROR,
664                 DLT_STRING("NSM: Failed to persist ApplicationMode.");
665                 DLT_STRING("Error: Unexpected PCL return.");
666                 DLT_STRING("Return:"); DLT_INT(pcl_return));
667       }
668
669       if(boInformBus == TRUE)
670       {
671         NSMA_boSendApplicationModeSignal(NSM__enNextApplicationMode);
672       }
673
674       if(boInformMachine == TRUE)
675       {
676          NsmcSetData(NsmDataType_AppMode,
677                      (unsigned char*) &NSM__enNextApplicationMode,
678                      sizeof(NsmApplicationMode_e));
679       }
680     }
681
682     g_mutex_unlock(NSM__pNextApplicationModeMutex);
683   }
684   else
685   {
686     /* Error: The passed application mode is invalid. Return an error. */
687     enRetVal = NsmErrorStatus_Parameter;
688     DLT_LOG(NsmContext,
689             DLT_LOG_ERROR,
690             DLT_STRING("NSM: Failed to change ApplicationMode.");
691             DLT_STRING("Error:"); DLT_STRING("Invalid parameter.");
692             DLT_STRING("Old AppMode:"); DLT_INT((int) NSM__enNextApplicationMode);
693             DLT_STRING("New AppMode:"); DLT_INT((int) enApplicationMode));
694   }
695
696   return enRetVal;
697 }
698
699
700 /**********************************************************************************************************************
701 *
702 * The function is called from IPC and StateMachine to get the ApplicationMode.
703 *
704 * @return see NsmApplicationMode_e
705 *
706 **********************************************************************************************************************/
707 static NsmErrorStatus_e
708 NSM__enGetApplicationMode(NsmApplicationMode_e *penApplicationMode)
709 {
710   NsmErrorStatus_e enRetVal   = NsmErrorStatus_NotSet;
711   int              pcl_return = 0;
712
713   if(penApplicationMode != NULL)
714   {
715     g_mutex_lock(NSM__pThisApplicationModeMutex);
716
717     /* Check if value already was obtained from persistence */
718     if(NSM__boThisApplicationModeRead == FALSE)
719     {
720       /* There was no read attempt before. Read from persistence */
721       pcl_return = pclKeyReadData(NSM_PERS_APPLICATION_MODE_DB,
722                                   NSM_PERS_APPLICATION_MODE_KEY,
723                                   0,
724                                   0,
725                                   (unsigned char*) &NSM__enThisApplicationMode,
726                                   sizeof(NSM__enThisApplicationMode));
727
728       /* Check the PCL return */
729       if(pcl_return != sizeof(NSM__enThisApplicationMode))
730       {
731         /* Read failed. From now on always return 'NsmApplicationMode_NotSet' */
732         NSM__enThisApplicationMode = NsmApplicationMode_NotSet;
733         DLT_LOG(NsmContext,
734                 DLT_LOG_WARN,
735                 DLT_STRING("NSM: Failed to read ApplicationMode.");
736                 DLT_STRING("Error: Unexpected PCL return.");
737                 DLT_STRING("Return:"); DLT_INT(pcl_return));
738       }
739
740       /* There was a first read attempt from persistence */
741       NSM__boThisApplicationModeRead = TRUE;
742     }
743
744     enRetVal = NsmErrorStatus_Ok;
745     *penApplicationMode = NSM__enThisApplicationMode;
746
747     g_mutex_unlock(NSM__pThisApplicationModeMutex);
748   }
749   else
750   {
751     enRetVal = NsmErrorStatus_Parameter;
752   }
753
754   return enRetVal;
755 }
756
757
758 /**********************************************************************************************************************
759 *
760 * The function is called from the StateMachine. There is no D-Bus interface to set the ShutdownReason,
761 * because it is a property.
762 *
763 * @param enNewShutdownReason: New ShutdownReason that should be stored.
764 * @param boInformMachine:     Determines if StateMachine needs to be called on a successful change.
765 *                             Most of the time this should be false, because the machine sets the
766 *                             value and can check the return value for errors.
767 *
768 * @return see NsmErrorStatus_e
769 *
770 **********************************************************************************************************************/
771 static NsmErrorStatus_e NSM__enSetShutdownReason(NsmShutdownReason_e enNewShutdownReason, gboolean boInformMachine)
772 {
773   /* Function local variables                                                          */
774   NsmErrorStatus_e    enRetVal                = NsmErrorStatus_NotSet; /* Return value */
775   NsmShutdownReason_e enCurrentShutdownReason = NsmShutdownReason_NotSet;
776
777   /* Check if the passed parameter is valid */
778   if((enNewShutdownReason > NsmShutdownReason_NotSet) && (enNewShutdownReason < NsmShutdownReason_Last))
779   {
780     /* The passed parameter is valid. Return OK */
781     enRetVal = NsmErrorStatus_Ok;
782     (void) NSMA_boGetShutdownReason(&enCurrentShutdownReason);
783
784     /* Only store the new value and emit a signal, if the new value is different */
785     if(enNewShutdownReason != enCurrentShutdownReason)
786     {
787       /* Store new value and emit signal with new application mode */
788       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Changed ShutdownReason."),
789                                         DLT_STRING(" Old ShutdownReason: "), DLT_INT((gint) enCurrentShutdownReason),
790                                         DLT_STRING(" New ShutdownReason: "), DLT_INT((gint) enNewShutdownReason    ));
791
792       (void) NSMA_boSetShutdownReason(enNewShutdownReason);
793
794       if(boInformMachine == TRUE)
795       {
796          NsmcSetData(NsmDataType_ShutdownReason, (unsigned char*) &enNewShutdownReason, sizeof(NsmShutdownReason_e));
797       }
798     }
799   }
800   else
801   {
802     /* Error: The passed application mode is invalid. Return an error. */
803     enRetVal = NsmErrorStatus_Parameter;
804     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to change ShutdownReason. Invalid parameter."          ),
805                                        DLT_STRING(" Old ShutdownReason: "),     DLT_INT((gint) enCurrentShutdownReason),
806                                        DLT_STRING(" Desired ShutdownReason: "), DLT_INT((gint) enNewShutdownReason    ));
807   }
808
809   return enRetVal;
810 }
811
812 /**********************************************************************************************************************
813 *
814 * The function is called when a session state changed. It informs the system (IPC and StateMachine) about
815 * the changed session state.
816 *
817 * @param pstSession:      Pointer to structure with updated session information.
818 * @param boInformBus:     Defines whether a D-Bus signal should be send on session change.
819 * @param boInformMachine: Defines whether the StateMachine should be informed about session change.
820 *
821 **********************************************************************************************************************/
822 static void NSM__vPublishSessionChange(NsmSession_s *pstChangedSession, gboolean boInformBus, gboolean boInformMachine)
823 {
824   NsmErrorStatus_e enStateMachineReturn = NsmErrorStatus_NotSet;
825
826   if(boInformBus == TRUE)
827   {
828     NSMA_boSendSessionSignal(pstChangedSession);
829   }
830
831   if(boInformMachine == TRUE)
832   {
833     enStateMachineReturn = NsmcSetData(NsmDataType_SessionState, (unsigned char*) pstChangedSession, sizeof(NsmSession_s));
834
835     if(enStateMachineReturn != NsmErrorStatus_Ok)
836     {
837       DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to inform state machine about changed session state."       ),
838                                          DLT_STRING(" State machine returned: "),      DLT_INT(   enStateMachineReturn       ),
839                                          DLT_STRING(" Application: "),                 DLT_STRING(pstChangedSession->sOwner  ),
840                                          DLT_STRING(" Session: "),                     DLT_STRING(pstChangedSession->sName   ),
841                                          DLT_STRING(" Seat: "),                        DLT_INT(   pstChangedSession->enSeat  ),
842                                          DLT_STRING(" Desired state: "),               DLT_INT(   pstChangedSession->enState));
843     }
844   }
845 }
846
847
848 /**********************************************************************************************************************
849 *
850 * The function is called when the state of a product session should be changed.
851 *
852 * @param pstSession:      Pointer to structure where session name, owner, seat and desired SessionState are defined.
853 * @param boInformBus:     Defines whether a D-Bus signal should be send on session change.
854 * @param boInformMachine: Defines whether the StateMachine should be informed about session change.
855 *
856 * @return see NsmErrorStatus_e
857 *
858 **********************************************************************************************************************/
859 static NsmErrorStatus_e NSM__enSetProductSessionState(NsmSession_s *pstSession, gboolean boInformBus, gboolean boInformMachine)
860 {
861   /* Function local variables                                         */
862   NsmErrorStatus_e  enRetVal = NsmErrorStatus_NotSet; /* Return value */
863   GSList           *pListEntry                   = NULL;
864   NsmSession_s     *pExistingSession             = NULL;
865
866   g_mutex_lock(NSM__pSessionMutex);
867
868   pListEntry = g_slist_find_custom(NSM__pSessions, pstSession, &NSM__i32SessionOwnerNameSeatCompare);
869
870   if(pListEntry != NULL)
871   {
872     enRetVal = NsmErrorStatus_Ok;
873     pExistingSession = (NsmSession_s*) pListEntry->data;
874
875     if(pExistingSession->enState != pstSession->enState)
876     {
877       pExistingSession->enState = pstSession->enState;
878       NSM__vPublishSessionChange(pExistingSession, boInformBus, boInformMachine);
879     }
880   }
881   else
882   {
883     enRetVal = NsmErrorStatus_WrongSession;
884     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to set session state. Session unknown."),
885                                        DLT_STRING(" Application: "),   DLT_STRING(pstSession->sOwner  ),
886                                        DLT_STRING(" Session: "),       DLT_STRING(pstSession->sName   ),
887                                        DLT_STRING(" Seat: "),          DLT_INT(   pstSession->enSeat  ),
888                                        DLT_STRING(" Desired state: "), DLT_INT(   pstSession->enState));
889   }
890
891   g_mutex_unlock(NSM__pSessionMutex);
892
893   return enRetVal;
894 }
895
896
897 /**********************************************************************************************************************
898 *
899 * The function is called when the state of a default session should be changed.
900 *
901 * @param pstSession:      Pointer to structure where session name, owner, seat and desired SessionState are defined.
902 * @param boInformBus:     Defines whether a D-Bus signal should be send on session change.
903 * @param boInformMachine: Defines whether the StateMachine should be informed about session change.
904 *
905 * @return see NsmErrorStatus_e
906 *
907 **********************************************************************************************************************/
908 static NsmErrorStatus_e NSM__enSetDefaultSessionState(NsmSession_s *pstSession, gboolean boInformBus, gboolean boInformMachine)
909 {
910   /* Function local variables                                                  */
911   NsmErrorStatus_e  enRetVal          = NsmErrorStatus_NotSet; /* Return value */
912   GSList           *pListEntry        = NULL;
913   NsmSession_s     *pExistingSession  = NULL;
914
915   /* Lock the sessions to be able to change them! */
916   g_mutex_lock(NSM__pSessionMutex);
917
918   pListEntry = g_slist_find_custom(NSM__pSessions, pstSession, &NSM__i32SessionNameSeatCompare);
919
920   if(pListEntry != NULL)
921   {
922     pExistingSession = (NsmSession_s*) pListEntry->data;
923
924     /* Check that the caller owns the session */
925     if(g_strcmp0(pExistingSession->sOwner, pstSession->sOwner) == 0)
926     {
927       enRetVal = NsmErrorStatus_Ok;
928
929       if(pExistingSession->enState != pstSession->enState)
930       {
931         DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Changed default session's state."),
932                                           DLT_STRING(" Application: "), DLT_STRING(pExistingSession->sOwner ),
933                                           DLT_STRING(" Session: "),     DLT_STRING(pExistingSession->sName  ),
934                                           DLT_STRING(" Seat: "),        DLT_INT(   pExistingSession->enSeat ),
935                                           DLT_STRING(" Old state: "),   DLT_INT(   pExistingSession->enState),
936                                           DLT_STRING(" New state: "),   DLT_INT(   pstSession->enState      ));
937
938         pExistingSession->enState = pstSession->enState;
939
940         NSM__vPublishSessionChange(pExistingSession, boInformBus, boInformMachine);
941
942         if(pstSession->enState == NsmSessionState_Inactive)
943         {
944           g_strlcpy(pExistingSession->sOwner, NSM_DEFAULT_SESSION_OWNER, sizeof(pExistingSession->sOwner));
945         }
946       }
947     }
948     else
949     {
950       /* The caller does not own the session. Check if he can become the owner. */
951       if(g_strcmp0(pExistingSession->sOwner, NSM_DEFAULT_SESSION_OWNER) == 0)
952       {
953         /* The session has no owner. The new owner can obtain the session by setting it to an "active" state */
954         if(pstSession->enState != NsmSessionState_Inactive)
955         {
956           /* The session has been activated. Overtake the owner. Broadcast new state. */
957           enRetVal = NsmErrorStatus_Ok;
958           g_strlcpy(pExistingSession->sOwner, pstSession->sOwner, sizeof(pExistingSession->sOwner));
959
960           DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Changed default session's state."),
961                                             DLT_STRING(" Application: "), DLT_STRING(pExistingSession->sOwner ),
962                                             DLT_STRING(" Session: "),     DLT_STRING(pExistingSession->sName  ),
963                                             DLT_STRING(" Seat: "),        DLT_INT(   pExistingSession->enSeat ),
964                                             DLT_STRING(" Old state: "),   DLT_INT(   pExistingSession->enState),
965                                             DLT_STRING(" New state: "),   DLT_INT(   pstSession->enState      ));
966
967           pExistingSession->enState = pstSession->enState;
968
969           NSM__vPublishSessionChange(pExistingSession, boInformBus, boInformMachine);
970         }
971         else
972         {
973           /* The session has no owner, but could not be activated because the passed state is "inactive". */
974           enRetVal = NsmErrorStatus_Parameter;
975
976           DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to enable default session. Passed state is 'inactive'. "),
977                                              DLT_STRING(" Session: "),                DLT_STRING(pstSession->sName           ),
978                                              DLT_STRING(" Seat: "),                   DLT_INT(   pstSession->enSeat          ),
979                                              DLT_STRING(" Owning     application: "), DLT_STRING(pExistingSession->sOwner    ),
980                                              DLT_STRING(" Requesting application: "), DLT_STRING(pstSession->sOwner          ));
981         }
982       }
983       else
984       {
985         /* The session owners do not match and the existing session has an owner */
986         enRetVal = NsmErrorStatus_Error;
987
988         DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to set default session state. Session has another owner."),
989                                            DLT_STRING(" Session: "),                DLT_STRING(pstSession->sName            ),
990                                            DLT_STRING(" Seat: "),                   DLT_INT(   pstSession->enSeat           ),
991                                            DLT_STRING(" Owning     application: "), DLT_STRING(pExistingSession->sOwner     ),
992                                            DLT_STRING(" Requesting application: "), DLT_STRING(pstSession->sOwner           ));
993       }
994     }
995   }
996   else
997   {
998     /* This should never happen, because the function is only called for default sessions! */
999     enRetVal = NsmErrorStatus_Internal;
1000     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Critical error. Default session not found in session list!"),
1001                                        DLT_STRING(" Application: "),   DLT_STRING(pstSession->sOwner               ),
1002                                        DLT_STRING(" Session: "),       DLT_STRING(pstSession->sName                ),
1003                                        DLT_STRING(" Seat: "),          DLT_INT(   pstSession->enSeat               ),
1004                                        DLT_STRING(" Desired state: "), DLT_INT(   pstSession->enState              ));
1005   }
1006
1007   /* Unlock the sessions again. */
1008   g_mutex_unlock(NSM__pSessionMutex);
1009
1010   return enRetVal;
1011 }
1012
1013
1014 /**********************************************************************************************************************
1015 *
1016 * The function is called from IPC and StateMachine to set a session state.
1017 *
1018 * @param pstSession:      Pointer to structure where session name, owner, seat and desired SessionState are defined.
1019 * @param boInformBus:     Defines whether a D-Bus signal should be send on session change.
1020 * @param boInformMachine: Defines whether the StateMachine should be informed about session change.
1021 *
1022 * @return see NsmErrorStatus_e
1023 *
1024 **********************************************************************************************************************/
1025 static NsmErrorStatus_e NSM__enSetSessionState(NsmSession_s *pstSession, gboolean boInformBus, gboolean boInformMachine)
1026 {
1027   /* Function local variables                                           */
1028   NsmErrorStatus_e    enRetVal = NsmErrorStatus_NotSet; /* Return value */
1029
1030   /* Check if the passed parameters are valid. */
1031   if(   (g_strcmp0(pstSession->sOwner, NSM_DEFAULT_SESSION_OWNER) != 0)
1032      && (pstSession->enState > NsmSessionState_Unregistered           )
1033      && (pstSession->enSeat  >  NsmSeat_NotSet                        )
1034      && (pstSession->enSeat  <  NsmSeat_Last                          ))
1035   {
1036     /* Parameters are valid. Check if a platform session state is set */
1037     if(NSM__boIsPlatformSession(pstSession) == TRUE)
1038     {
1039       enRetVal = NSM__enSetDefaultSessionState(pstSession, boInformBus, boInformMachine);
1040     }
1041     else
1042     {
1043       enRetVal = NSM__enSetProductSessionState(pstSession, boInformBus, boInformMachine);
1044     }
1045   }
1046   else
1047   {
1048     /* Error: An invalid parameter has been passed. */
1049     enRetVal = NsmErrorStatus_Parameter;
1050     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to change session state. Invalid paramter."),
1051                                        DLT_STRING(" Application: "),   DLT_STRING(pstSession->sOwner      ),
1052                                        DLT_STRING(" Session: "),       DLT_STRING(pstSession->sName       ),
1053                                        DLT_STRING(" Seat: "),          DLT_INT(   pstSession->enSeat      ),
1054                                        DLT_STRING(" Desired state: "), DLT_INT(   pstSession->enState     ));
1055   }
1056
1057   return enRetVal;
1058 }
1059
1060
1061 /**********************************************************************************************************************
1062 *
1063 * The function is called from IPC and StateMachine to get the session state.
1064 *
1065 * @param pstSession: Pointer to structure where session name, owner and seat are defined and SessionState will be set.
1066 *
1067 * @return see NsmErrorStatus_e
1068 *
1069 **********************************************************************************************************************/
1070 static NsmErrorStatus_e NSM__enGetSessionState(NsmSession_s *pstSession)
1071 {
1072   /* Function local variables                                                                  */
1073   NsmErrorStatus_e    enRetVal         = NsmErrorStatus_NotSet; /* Return value                */
1074   NsmSession_s       *pExistingSession = NULL;                  /* Pointer to existing session */
1075   GSList             *pListEntry       = NULL;
1076
1077   g_mutex_lock(NSM__pSessionMutex);
1078
1079   /* Search for session with name, seat and owner. */
1080   pListEntry = g_slist_find_custom(NSM__pSessions, pstSession, &NSM__i32SessionNameSeatCompare);
1081
1082   if(pListEntry != NULL)
1083   {
1084     /* Found the session in the list. Return its state. */
1085     enRetVal            = NsmErrorStatus_Ok;
1086     pExistingSession    = (NsmSession_s*) pListEntry->data;
1087     pstSession->enState = pExistingSession->enState;
1088   }
1089   else
1090   {
1091     /* Error: The session is unknown. */
1092     enRetVal = NsmErrorStatus_WrongSession;
1093     DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: Failed to retrieve session state. Unknown session."),
1094                                       DLT_STRING(" Session: "),       DLT_STRING(pstSession->sName        ),
1095                                       DLT_STRING(" Seat: "),          DLT_INT(   pstSession->enSeat       ));
1096   }
1097
1098   g_mutex_unlock(NSM__pSessionMutex);
1099
1100   return enRetVal;
1101 }
1102
1103
1104 static void NSM__vFreeFailedApplicationObject(gpointer pFailedApplication)
1105 {
1106   /* Function local variables. Cast the passed object */
1107   NSM__tstFailedApplication *pstFailedApplication = (NSM__tstFailedApplication*) pFailedApplication;
1108
1109   g_free(pstFailedApplication);
1110 }
1111
1112
1113 /**********************************************************************************************************************
1114 *
1115 * The function is called either manually for one object or for every "session object", when the list of registered
1116 * sessions is destroyed with "g_slist_free_full". All memory occupied by the "session object" is released.
1117 *
1118 * @param pSession: Pointer to the session object
1119 *
1120 * @return void
1121 *
1122 **********************************************************************************************************************/
1123 static void NSM__vFreeSessionObject(gpointer pSession)
1124 {
1125   /* Function local variables. Cast the passed object */
1126   NsmSession_s *pstSession = (NsmSession_s*) pSession;
1127
1128   /* Free the session object */
1129   g_free(pstSession);
1130 }
1131
1132
1133 /**********************************************************************************************************************
1134 *
1135 * The function is called either manually for one object or for every "lifecycle client object", when the list of
1136 * registered lifecycle clients is destroyed with "g_slist_free_full".
1137 * All memory occupied by the "lifecycle client object" is released.
1138 *
1139 * @param pLifecycleClient: Pointer to the lifecycle client object
1140 *
1141 * @return void
1142 *
1143 **********************************************************************************************************************/
1144 static void NSM__vFreeLifecycleClientObject(gpointer pLifecycleClient)
1145 {
1146   /* Function local variables. Cast the passed object */
1147   NSM__tstLifecycleClient *pstLifecycleClient = (NSM__tstLifecycleClient*) pLifecycleClient;
1148
1149   /* Free internal strings and objects */
1150   g_free(pstLifecycleClient->sBusName);
1151   g_free(pstLifecycleClient->sObjName);
1152
1153   /* No need to check for NULL. Only valid clients come here */
1154   NSMA_boFreeLcConsumerProxy(pstLifecycleClient->hClient);
1155
1156   /* Free the shutdown client object */
1157   g_free(pstLifecycleClient);
1158 }
1159
1160
1161 /**********************************************************************************************************************
1162 *
1163 * The function is used to "custom compare" and identify a lifecycle client in the list of clients.
1164 * Because the function is not used for sorting, the return value 1 is not used.
1165 *
1166 * @param pS1: Lifecycle client from list
1167 * @param pS2: Lifecycle client to compare
1168 *
1169 * @return -1: pL1 < pL2
1170 *          0: pL1 = pL2
1171 *          1: pL1 > pL2 (unused, because function not used for sorting)
1172 *
1173 **********************************************************************************************************************/
1174 static gint NSM__i32LifecycleClientCompare(gconstpointer pL1, gconstpointer pL2)
1175 {
1176   /* Function local variables. Cast the passed objects */
1177   NSM__tstLifecycleClient *pListClient    = NULL;
1178   NSM__tstLifecycleClient *pCompareClient = NULL;
1179   gint                     i32RetVal      = 1;
1180
1181   pListClient    = (NSM__tstLifecycleClient*) pL1;
1182   pCompareClient = (NSM__tstLifecycleClient*) pL2;
1183
1184   /* Compare the bus name of the client */
1185   if(g_strcmp0(pListClient->sBusName, pCompareClient->sBusName) == 0)
1186   {
1187     /* Bus names are equal. Now compare object name */
1188     if(g_strcmp0(pListClient->sObjName, pCompareClient->sObjName) == 0)
1189     {
1190       i32RetVal = 0;  /* Clients are identical. Return 0.       */
1191     }
1192     else
1193     {
1194       i32RetVal = -1; /* Object names are different. Return -1. */
1195     }
1196   }
1197   else
1198   {
1199     i32RetVal = -1;   /* Bus names are different. Return -1.    */
1200   }
1201
1202   return i32RetVal;   /* Return result of comparison.           */
1203 }
1204
1205
1206 /**********************************************************************************************************************
1207 *
1208 * The function is used to "custom compare" and identify a session in the list of sessions.
1209 * It compares the "session name", the "session owner" and "seat".
1210 * Because the function is not used for sorting, the return value 1 is not used.
1211 *
1212 * @param pS1: Session from list
1213 * @param pS2: Session to compare
1214 *
1215 * @return -1: pS1 < pS2
1216 *          0: pS1 = pS2
1217 *          1: pS1 > pS2 (unused, because function not used for sorting)
1218 *
1219 **********************************************************************************************************************/
1220 static gint NSM__i32SessionOwnerNameSeatCompare(gconstpointer pS1, gconstpointer pS2)
1221 {
1222   /* Function local variables. Cast the passed objects */
1223   NsmSession_s *pListSession   = NULL;
1224   NsmSession_s *pSearchSession = NULL;
1225   gint          i32RetVal      = 1;
1226
1227   pListSession   = (NsmSession_s*) pS1;
1228   pSearchSession = (NsmSession_s*) pS2;
1229
1230   if(g_strcmp0(pListSession->sOwner,  pSearchSession->sOwner) == 0)
1231   {
1232     i32RetVal = NSM__i32SessionNameSeatCompare(pS1, pS2);
1233   }
1234   else
1235   {
1236     i32RetVal = -1;    /* Session owners differ. Return -1.  */
1237   }
1238
1239   return i32RetVal;    /* Return result of comparison        */
1240 }
1241
1242
1243 /**********************************************************************************************************************
1244 *
1245 * The function is used to "custom compare" and identify a session in the list of sessions.
1246 * It compares the "session name" and "seat".
1247 * Because the function is not used for sorting, the return value 1 is not used.
1248 *
1249 * @param pS1: Session from list
1250 * @param pS2: Session to compare
1251 *
1252 * @return -1: pS1 < pS2
1253 *          0: pS1 = pS2
1254 *          1: pS1 > pS2 (unused, because function not used for sorting)
1255 *
1256 **********************************************************************************************************************/
1257 static gint NSM__i32SessionNameSeatCompare(gconstpointer pS1, gconstpointer pS2)
1258 {
1259   /* Function local variables. Cast the passed objects */
1260   NsmSession_s *pListSession   = NULL;
1261   NsmSession_s *pSearchSession = NULL;
1262   gint          i32RetVal      = 1;
1263
1264   pListSession   = (NsmSession_s*) pS1;
1265   pSearchSession = (NsmSession_s*) pS2;
1266
1267   /* Compare seats of the sessions. */
1268   if(pListSession->enSeat == pSearchSession->enSeat)
1269   {
1270     /* Seats are equal. Compare session names. */
1271     if(g_strcmp0(pListSession->sName,  pSearchSession->sName)  == 0)
1272     {
1273       i32RetVal = 0;  /* Session are equal. Return 0.      */
1274     }
1275     else
1276     {
1277       i32RetVal = -1; /* Session names differ. Return -1.  */
1278     }
1279   }
1280   else
1281   {
1282     i32RetVal = -1;   /* Session seats differ. Return -1.  */
1283   }
1284
1285   return i32RetVal;
1286 }
1287
1288
1289 /**********************************************************************************************************************
1290 *
1291 * The function is used to "custom compare" and identify an application name.
1292 * Because the function is not used for sorting, the return value 1 is not used.
1293 *
1294 * @param pA1: Application object from list
1295 * @param pA2: Application object to compare
1296 *
1297 * @return -1: pA1 < pA2
1298 *          0: pA1 = pA2
1299 *          1: pA1 > pA2 (unused, because function not used for sorting)
1300 *
1301 **********************************************************************************************************************/
1302 static gint NSM__i32ApplicationCompare(gconstpointer pA1, gconstpointer pA2)
1303 {
1304   /* Function local variables. Cast the passed objects */
1305   NSM__tstFailedApplication *pListApp   = NULL;
1306   NSM__tstFailedApplication *pSearchApp = NULL;
1307   gint          i32RetVal      = 1;
1308
1309   pListApp   = (NSM__tstFailedApplication*) pA1;
1310   pSearchApp = (NSM__tstFailedApplication*) pA2;
1311
1312   /* Compare names of the applications */
1313   if(g_strcmp0(pListApp->sName, pSearchApp->sName) == 0)
1314   {
1315     i32RetVal = 0;  /* Names are equal. Return 0.      */
1316   }
1317   else
1318   {
1319     i32RetVal = -1; /* Names are different. Return -1. */
1320   }
1321
1322   return i32RetVal; /* Return result of comparison     */
1323 }
1324
1325
1326 /**********************************************************************************************************************
1327 *
1328 * The function is used to "custom compare" and identify a session with a special owner.
1329 * Because the function is not used for sorting, the return value 1 is not used.
1330 *
1331 * @param pS1: Session from list
1332 * @param pS2: Session to compare
1333 *
1334 * @return -1: pS1 < pS2
1335 *          0: pS1 = pS2
1336 *          1: pS1 > pS2 (unused, because function not used for sorting)
1337 *
1338 **********************************************************************************************************************/
1339 static gint NSM__i32SessionOwnerCompare(gconstpointer pS1, gconstpointer pS2)
1340 {
1341   /* Function local variables. Cast the passed objects */
1342   NsmSession_s *pListSession   = NULL;
1343   NsmSession_s *pSearchSession = NULL;
1344   gint          i32RetVal      = 1;
1345
1346   pListSession   = (NsmSession_s*) pS1;
1347   pSearchSession = (NsmSession_s*) pS2;
1348
1349   /* Compare owners of the sessions */
1350   if(g_strcmp0(pListSession->sOwner, pSearchSession->sOwner) == 0)
1351   {
1352     i32RetVal = 0;  /* Owners are equal. Return 0.      */
1353   }
1354   else
1355   {
1356     i32RetVal = -1; /* Owners are different. Return -1. */
1357   }
1358
1359   return i32RetVal; /* Return result of comparison      */
1360 }
1361
1362
1363 /**********************************************************************************************************************
1364 *
1365 * The function is called after a lifecycle client was informed about the changed life cycle.
1366 * The return value of the last informed client will be evaluated and the next lifecycle client
1367 * to inform will be determined and called.
1368 * If there is no client left, the lifecycle sequence will be finished.
1369 *
1370 * @param pSrcObject: Source object (lifecycle client proxy)
1371 * @param pRes:       Result of asynchronous call
1372 * @param pUserData:  Pointer to the current lifecycle client object
1373 *
1374 * @return void
1375 *
1376 **********************************************************************************************************************/
1377 static void NSM__vOnLifecycleRequestFinish(const NsmErrorStatus_e enErrorStatus)
1378 {
1379   if(enErrorStatus == NsmErrorStatus_Ok)
1380   {
1381     /* The clients "LifecycleRequest" has been successfully processed. */
1382         NSM__vLtProf(NSM__pCurrentLifecycleClient->sBusName, NSM__pCurrentLifecycleClient->sObjName, 0, "leave: ", 0);
1383     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Successfully called lifecycle client."));
1384   }
1385   else
1386   {
1387     /* Error: The method of the lifecycle client returned an error */
1388     NSM__vLtProf(NSM__pCurrentLifecycleClient->sBusName, NSM__pCurrentLifecycleClient->sObjName, 0, "leave: error: ", enErrorStatus);
1389     DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: Failed to call life cycle client."       ),
1390                                       DLT_STRING(" Return Value: "), DLT_INT((gint) enErrorStatus));
1391   }
1392
1393   NSM__vCallNextLifecycleClient();
1394 }
1395
1396
1397 /**********************************************************************************************************************
1398 *
1399 * The function is called when:
1400 *    - The NodeState changes (NSM__boHandleSetNodeState), to initiate a lifecycle sequence
1401 *    - A client returned and the next client has to be called (NSM__vOnLifecycleRequestFinish)
1402 *
1403 * If the clients need to "run up" or shut down for the current NodeState, the function
1404 * searches the list forward or backward until a client is found, which needs to be informed.
1405 *
1406 * PLEASE NOTE: If all clients have been informed about a "shut down", this function will quit the
1407 *              "g_main_loop", which leads to the the termination of the NSM!
1408 *
1409 * @return void
1410 *
1411 **********************************************************************************************************************/
1412 static void NSM__vCallNextLifecycleClient(void)
1413 {
1414   /* Function local variables                                                                      */
1415   GList                   *pListEntry      = NULL;                 /* Iterate through list entries */
1416   NSM__tstLifecycleClient *pClient         = NULL;                 /* Client object from list      */
1417   guint32                  u32ShutdownType = NSM_SHUTDOWNTYPE_NOT; /* Return value                 */
1418   gboolean                 boShutdown      = FALSE;
1419
1420   NSM__pCurrentLifecycleClient = NULL;
1421
1422   g_mutex_lock(NSM__pNodeStateMutex);
1423
1424   /* Based on NodeState determine if clients have to shutdown or run up. Find a client that has not been informed */
1425   switch(NSM__enNodeState)
1426   {
1427     /* For "shutdown" search backward in the list, until there is a client that has not been shut down */
1428     case NsmNodeState_ShuttingDown:
1429       u32ShutdownType = NSM_SHUTDOWNTYPE_NORMAL;
1430       for( pListEntry = g_list_last(NSM__pLifecycleClients);
1431           (pListEntry != NULL) && (NSM__pCurrentLifecycleClient == NULL);
1432           pListEntry = g_list_previous(pListEntry))
1433       {
1434         /* Check if client has not been shut down and is registered for "normal shutdown" */
1435         pClient = (NSM__tstLifecycleClient*) pListEntry->data;
1436         if(   (  pClient->boShutdown                           == FALSE)
1437            && ( (pClient->u32RegisteredMode & u32ShutdownType) != 0    ))
1438         {
1439           /* Found a "running" previous client, registered for the shutdown mode */
1440           NSM__pCurrentLifecycleClient = (NSM__tstLifecycleClient*) pListEntry->data;
1441         }
1442       }
1443     break;
1444
1445     /* For "fast shutdown" search backward in the list, until there is a client that has not been shut down */
1446     case NsmNodeState_FastShutdown:
1447       u32ShutdownType = NSM_SHUTDOWNTYPE_FAST;
1448       for( pListEntry = g_list_last(NSM__pLifecycleClients);
1449           (pListEntry != NULL) && (NSM__pCurrentLifecycleClient == NULL);
1450           pListEntry = g_list_previous(pListEntry))
1451       {
1452         /* Check if client has not been shut down and is registered for "fast shutdown" */
1453         pClient = (NSM__tstLifecycleClient*) pListEntry->data;
1454         if(   (  pClient->boShutdown                           == FALSE)
1455            && ( (pClient->u32RegisteredMode & u32ShutdownType) != 0    ))
1456         {
1457           /* Found a "running" previous client, registered for the shutdown mode */
1458           NSM__pCurrentLifecycleClient = (NSM__tstLifecycleClient*) pListEntry->data;
1459         }
1460       }
1461     break;
1462
1463     /* For a "running" mode search forward in the list (get next), until there is a client that is shut down */
1464     default:
1465       u32ShutdownType = NSM_SHUTDOWNTYPE_RUNUP;
1466       for(pListEntry = g_list_first(NSM__pLifecycleClients);
1467           (pListEntry != NULL) && (NSM__pCurrentLifecycleClient == NULL);
1468           pListEntry = g_list_next(pListEntry))
1469       {
1470         /* Check if client is shut down */
1471         pClient = (NSM__tstLifecycleClient*) pListEntry->data;
1472         if(pClient->boShutdown == TRUE)
1473         {
1474           /* The client was shutdown. It should run up, because we are in a running mode */
1475           NSM__pCurrentLifecycleClient = (NSM__tstLifecycleClient*) pListEntry->data;
1476         }
1477       }
1478     break;
1479   }
1480
1481   /* Check if a client could be found that needs to be informed */
1482   if(NSM__pCurrentLifecycleClient != NULL)
1483   {
1484     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Call lifecycle client."                                                  ),
1485                                       DLT_STRING(" Bus name: "),         DLT_STRING(NSM__pCurrentLifecycleClient->sBusName      ),
1486                                       DLT_STRING(" Obj name: "),         DLT_STRING(NSM__pCurrentLifecycleClient->sObjName      ),
1487                                       DLT_STRING(" Registered types: "), DLT_INT(NSM__pCurrentLifecycleClient->u32RegisteredMode),
1488                                       DLT_STRING(" Client: "),           DLT_INT( (guint) NSM__pCurrentLifecycleClient->hClient ),
1489                                       DLT_STRING(" ShutdownType: "),     DLT_UINT(u32ShutdownType                               ));
1490
1491     /* Remember that client received a run-up or shutdown call */
1492     pClient->boShutdown = (u32ShutdownType != NSM_SHUTDOWNTYPE_RUNUP);
1493
1494     NSM__vLtProf(NSM__pCurrentLifecycleClient->sBusName, NSM__pCurrentLifecycleClient->sObjName, u32ShutdownType, "enter: ", 0);
1495
1496     NSMA_boCallLcClientRequest(NSM__pCurrentLifecycleClient->hClient, u32ShutdownType);
1497     boShutdown = FALSE;
1498   }
1499   else
1500   {
1501     /* The last client was called. Depending on the NodeState check if we can end. */
1502     switch(NSM__enNodeState)
1503     {
1504       /* All registered clients have been 'fast shutdown'. Set NodeState to "shutdown" */
1505       case NsmNodeState_FastShutdown:
1506         DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Informed all registered clients about 'fast shutdown'. Set NodeState to 'shutdown'"));
1507
1508         NSM__enNodeState = NsmNodeState_Shutdown;
1509         NsmcSetData(NsmDataType_NodeState, (unsigned char*) &NSM__enNodeState, sizeof(NsmNodeState_e));
1510         NSMA_boSendNodeStateSignal(NSM__enNodeState);
1511         boShutdown = TRUE;
1512       break;
1513
1514       /* All registered clients have been 'shutdown'. Set NodeState to "shutdown" */
1515       case NsmNodeState_ShuttingDown:
1516         DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Informed all registered clients about 'shutdown'. Set NodeState to 'shutdown'."));
1517
1518         NSM__enNodeState = NsmNodeState_Shutdown;
1519         NsmcSetData(NsmDataType_NodeState, (unsigned char*) &NSM__enNodeState, sizeof(NsmNodeState_e));
1520         NSMA_boSendNodeStateSignal(NSM__enNodeState);
1521         boShutdown = TRUE;
1522       break;
1523
1524       /* We are in a running state. Nothing to do */
1525       default:
1526         boShutdown = FALSE;
1527       break;
1528     }
1529   }
1530
1531   g_mutex_unlock(NSM__pNodeStateMutex);
1532
1533   if(boShutdown == TRUE)
1534   {
1535     NSMA_boQuitEventLoop();
1536   }
1537 }
1538
1539
1540 /**********************************************************************************************************************
1541 *
1542 * The callback is called when a check for LUC is required.
1543 * It uses the NodeStateMachine to determine whether LUC is required.
1544 *
1545 * @param pboRetVal: Pointer, where to store the StateMAchine's return value
1546 *
1547 **********************************************************************************************************************/
1548 static gboolean NSM__boOnHandleCheckLucRequired(void)
1549 {
1550   /* Determine if LUC is required by asking the NodeStateMachine */
1551   return (NsmcLucRequired() == 0x01) ? TRUE : FALSE;
1552 }
1553
1554
1555 /**********************************************************************************************************************
1556 *
1557 * The callback is called when the "boot mode" should be set.
1558 * It sets the BootMode using an internal function.
1559 *
1560 * @param i32BootMode: New boot mode
1561 * @param penRetVal:   Pointer, where to store the return value
1562 *
1563 **********************************************************************************************************************/
1564 static NsmErrorStatus_e NSM__enOnHandleSetBootMode(const gint i32BootMode)
1565 {
1566   /* Use internal setter to set the BootMode and inform the StateMachine */
1567   return NSM__enSetBootMode(i32BootMode, TRUE);
1568 }
1569
1570
1571 /**********************************************************************************************************************
1572 *
1573 * The callback is called when the "node state" should be set.
1574 * It sets the NodeState using an internal function.
1575 *
1576 * @param enNodeStateId: New node state
1577 * @param penRetVal:     Pointer, where to store the return value
1578 *
1579 **********************************************************************************************************************/
1580 static NsmErrorStatus_e NSM__enOnHandleSetNodeState(const NsmNodeState_e  enNodeState)
1581 {
1582   return NSM__enSetNodeState(enNodeState, TRUE, TRUE);
1583 }
1584
1585
1586 /**********************************************************************************************************************
1587 *
1588 * The callback is called when the "application mode" should be set.
1589 * It sets the ApplicationMode using an internal function.
1590 *
1591 * @param enApplicationModeId: New application mode
1592 * @param penRetVal:           Pointer, where to store the return value
1593 *
1594 **********************************************************************************************************************/
1595 static NsmErrorStatus_e NSM__enOnHandleSetApplicationMode(const NsmApplicationMode_e enApplMode)
1596 {
1597   return NSM__enSetApplicationMode(enApplMode, TRUE, TRUE);
1598 }
1599
1600
1601 /**********************************************************************************************************************
1602 *
1603 * The callback is called when the node reset is requested.
1604 * It passes the request to the NodestateMachine.
1605 *
1606 * @param i32RestartReason:     Restart reason
1607 * @param i32RestartType:       Restart type
1608 * @param penRetVal:            Pointer, where to store the return value
1609 *
1610 **********************************************************************************************************************/
1611 static NsmErrorStatus_e NSM__enOnHandleRequestNodeRestart(const NsmRestartReason_e enRestartReason,
1612                                                           const guint              u32RestartType)
1613 {
1614   NsmErrorStatus_e enRetVal = NsmErrorStatus_NotSet;
1615
1616   DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Node restart has been requested."));
1617
1618   if(NsmcRequestNodeRestart(enRestartReason, u32RestartType) == 0x01)
1619   {
1620     enRetVal = NsmErrorStatus_Ok;
1621     (void) NSMA_boSetRestartReason(enRestartReason);
1622   }
1623   else
1624   {
1625     enRetVal = NsmErrorStatus_Error;
1626   }
1627
1628   return enRetVal;
1629 }
1630
1631
1632 /**********************************************************************************************************************
1633 *
1634 * The called is called when a new session should be registered.
1635 * It checks the passed parameters and creates a NsmSession_s structure of them.
1636 * If everything is ok, the new session will be created and the system and StateMachine will be informed.
1637 *
1638 * @param sSessionName:   Name of the new session
1639 * @param sSessionOwner:  Owner of the new session
1640 * @param enSeatId:       Seat which belongs to the new session
1641 * @param enSessionState: Initial state of the new session
1642 * @param penRetVal:      Pointer, where to store the return value
1643 *
1644 **********************************************************************************************************************/
1645 static NsmErrorStatus_e NSM__enOnHandleRegisterSession(const gchar             *sSessionName,
1646                                                        const gchar             *sSessionOwner,
1647                                                        const NsmSeat_e          enSeatId,
1648                                                        const NsmSessionState_e  enSessionState)
1649 {
1650   /* Function local variables                                                     */
1651   glong             u32SessionNameLen  = 0;     /* Length of passed session owner */
1652   glong             u32SessionOwnerLen = 0;     /* Length of passed session name  */
1653   NsmSession_s      stSession;                  /* To search for existing session */
1654   NsmErrorStatus_e  enRetVal           = NsmErrorStatus_NotSet;
1655
1656   /* Check if the passed parameters are valid */
1657   u32SessionNameLen  = g_utf8_strlen(sSessionName,  -1);
1658   u32SessionOwnerLen = g_utf8_strlen(sSessionOwner, -1);
1659
1660   if(   (u32SessionNameLen  <  NSM_MAX_SESSION_NAME_LENGTH )
1661      && (u32SessionOwnerLen <  NSM_MAX_SESSION_OWNER_LENGTH)
1662      && (enSeatId           >  NsmSeat_NotSet              )
1663      && (enSeatId           <  NsmSeat_Last                ))
1664   {
1665     /* Initialize temporary session object to check if session already exists */
1666     g_strlcpy((gchar*) stSession.sName,  sSessionName,  sizeof(stSession.sName) );
1667     g_strlcpy((gchar*) stSession.sOwner, sSessionOwner, sizeof(stSession.sOwner));
1668     stSession.enSeat  = enSeatId;
1669     stSession.enState = enSessionState;
1670
1671     enRetVal = NSM__enRegisterSession(&stSession, TRUE, TRUE);
1672   }
1673   else
1674   {
1675     /* Error: A parameter with an invalid value has been passed */
1676     enRetVal = NsmErrorStatus_Parameter;
1677     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to register session. Invalid parameter."),
1678                                        DLT_STRING("Name:"         ), DLT_STRING(sSessionName           ),
1679                                        DLT_STRING("Owner:"        ), DLT_STRING(sSessionOwner          ),
1680                                        DLT_STRING("Seat:"         ), DLT_INT((gint) enSeatId           ),
1681                                        DLT_STRING("Initial state:"), DLT_INT((gint) enSessionState     ));
1682   }
1683
1684   return enRetVal;
1685 }
1686
1687
1688 /**********************************************************************************************************************
1689 *
1690 * The callback is called when a session should be unregistered.
1691 * It checks the passed parameters and creates a NsmSession_s structure of them.
1692 * If everything is ok, the new session will be removed and the system and StateMachine will be informed.
1693 *
1694 * @param sSessionName:  Name of the new session that should be unregistered.
1695 * @param sSessionOwner: Current owner of the session that should be unregistered.
1696 * @param enSeat:        Seat for which the session should be unregistered.
1697 * @param penRetVal:     Pointer, where to store the return value
1698 *
1699 **********************************************************************************************************************/
1700 static NsmErrorStatus_e NSM__enOnHandleUnRegisterSession(const gchar     *sSessionName,
1701                                                          const gchar     *sSessionOwner,
1702                                                          const NsmSeat_e  enSeatId)
1703 {
1704   /* Function local variables                                                                   */
1705   glong             u32SessionNameLen  = 0;                   /* Length of passed session owner */
1706   glong             u32SessionOwnerLen = 0;                   /* Length of passed session name  */
1707   NsmSession_s      stSearchSession    = {0};                 /* To search for existing session */
1708   NsmErrorStatus_e  enRetVal           = NsmErrorStatus_NotSet;
1709
1710   /* Check if the passed parameters are valid */
1711   u32SessionNameLen  = g_utf8_strlen(sSessionName,  -1);
1712   u32SessionOwnerLen = g_utf8_strlen(sSessionOwner, -1);
1713
1714   if(   (u32SessionNameLen   < NSM_MAX_SESSION_NAME_LENGTH )
1715      && (u32SessionOwnerLen  < NSM_MAX_SESSION_OWNER_LENGTH))
1716   {
1717     /* Assign seat, session name and owner to search for session */
1718     stSearchSession.enSeat = enSeatId;
1719     g_strlcpy((gchar*) stSearchSession.sName,  sSessionName,  sizeof(stSearchSession.sName) );
1720     g_strlcpy((gchar*) stSearchSession.sOwner, sSessionOwner, sizeof(stSearchSession.sOwner));
1721
1722     enRetVal = NSM__enUnRegisterSession(&stSearchSession, TRUE, TRUE);
1723   }
1724   else
1725   {
1726     /* Error: Invalid parameter. The session or owner name is to long. */
1727     enRetVal = NsmErrorStatus_Parameter;
1728     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to unregister session. The session or owner name is to long."),
1729                                        DLT_STRING(" Name: "      ), DLT_STRING(sSessionName                                 ),
1730                                        DLT_STRING(" Owner: "     ), DLT_STRING(sSessionOwner                                ),
1731                                        DLT_STRING(" Seat: "      ), DLT_INT((gint) enSeatId                                 ));
1732   }
1733
1734   return enRetVal;
1735 }
1736
1737
1738 /**********************************************************************************************************************
1739 *
1740 * The callback is called when a lifecycle client should be registered.
1741 * In the list of lifecycle clients it will be checked if the client already exists.
1742 * If it exists, it's settings will be updated. Otherwise a new client will be created.
1743 *
1744 * @param sBusName:        Bus name of the remote application that hosts the lifecycle client interface
1745 * @param sObjName:        Object name of the lifecycle client
1746 * @param u32ShutdownMode: Shutdown mode for which the client wants to be informed
1747 * @param u32TimeoutMs:    Timeout in ms. If the client does not return after the specified time, the NSM
1748 *                         aborts its shutdown and calls the next client.
1749 * @param penRetVal:       Pointer, where to store the return value
1750 *
1751 **********************************************************************************************************************/
1752 static NsmErrorStatus_e NSM__enOnHandleRegisterLifecycleClient(const gchar *sBusName,
1753                                                                const gchar *sObjName,
1754                                                                const guint  u32ShutdownMode,
1755                                                                const guint  u32TimeoutMs)
1756 {
1757   NSM__tstLifecycleClient     stTestLifecycleClient = {0};
1758   NSM__tstLifecycleClient    *pstNewClient          = NULL;
1759   NSM__tstLifecycleClient    *pstExistingClient     = NULL;
1760   GList                      *pListEntry            = NULL;
1761   NSMA_tLcConsumerHandle     *hConsumer             = NULL;
1762   GError                     *pError                = NULL;
1763   NsmErrorStatus_e            enRetVal              = NsmErrorStatus_NotSet;
1764
1765   /* The parameters are valid. Create a temporary client to search the list */
1766   stTestLifecycleClient.sBusName = (gchar*) sBusName;
1767   stTestLifecycleClient.sObjName = (gchar*) sObjName;
1768
1769   /* Check if the lifecycle client already is registered */
1770   pListEntry = g_list_find_custom(NSM__pLifecycleClients, &stTestLifecycleClient, &NSM__i32LifecycleClientCompare);
1771
1772   if(pListEntry == NULL)
1773   {
1774     /* The client does not exist. Try to create a new proxy */
1775     hConsumer = NSMA_hCreateLcConsumer(sBusName, sObjName, u32TimeoutMs);
1776
1777     /* The new proxy could be created. Create and store new client */
1778     if(hConsumer != NULL)
1779     {
1780       enRetVal = NsmErrorStatus_Ok;
1781
1782       /* Create client object and copies of the strings. */
1783       pstNewClient = g_new0(NSM__tstLifecycleClient, 1);
1784       pstNewClient->u32RegisteredMode = u32ShutdownMode;
1785       pstNewClient->sBusName          = g_strdup(sBusName);
1786       pstNewClient->sObjName          = g_strdup(sObjName);
1787       pstNewClient->boShutdown        = FALSE;
1788       pstNewClient->hClient           = hConsumer;
1789
1790
1791       /* Append the new client to the list */
1792       NSM__pLifecycleClients = g_list_append(NSM__pLifecycleClients, pstNewClient);
1793
1794       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Registered new lifecycle consumer."                 ),
1795                                         DLT_STRING(" Bus name: "), DLT_STRING(pstNewClient->sBusName         ),
1796                                         DLT_STRING(" Obj name: "), DLT_STRING(pstNewClient->sObjName         ),
1797                                         DLT_STRING(" Timeout: " ), DLT_UINT(  u32TimeoutMs                   ),
1798                                         DLT_STRING(" Mode(s): "),  DLT_INT(   pstNewClient->u32RegisteredMode),
1799                                         DLT_STRING(" Client: "),   DLT_UINT((guint) pstNewClient->hClient    ));
1800     }
1801     else
1802     {
1803       enRetVal = NsmErrorStatus_Dbus;
1804       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Failed to register new lifecycle consumer. D-Bus error."),
1805                                         DLT_STRING(" Bus name: "),           DLT_STRING(sBusName                 ),
1806                                         DLT_STRING(" Obj name: "),           DLT_STRING(sObjName                 ),
1807                                         DLT_STRING(" Timeout: " ),           DLT_UINT(  u32TimeoutMs             ),
1808                                         DLT_STRING(" Registered mode(s): "), DLT_INT(   u32ShutdownMode          ),
1809                                         DLT_STRING(" Error: "),              DLT_STRING(pError->message          ));
1810
1811       g_error_free(pError);
1812     }
1813   }
1814   else
1815   {
1816     /* The client already exists. Assert to update the values for timeout and mode */
1817     enRetVal = NsmErrorStatus_Ok;
1818     pstExistingClient = (NSM__tstLifecycleClient*) pListEntry->data;
1819     pstExistingClient->u32RegisteredMode |= u32ShutdownMode;
1820     NSMA_boSetLcClientTimeout(pstExistingClient->hClient, u32TimeoutMs);
1821
1822     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Changed lifecycle consumer registration."                          ),
1823                                       DLT_STRING(" Bus name: "),           DLT_STRING(pstExistingClient->sBusName         ),
1824                                       DLT_STRING(" Obj name: "),           DLT_STRING(pstExistingClient->sObjName         ),
1825                                       DLT_STRING(" Timeout: " ),           DLT_UINT(  u32TimeoutMs                        ),
1826                                       DLT_STRING(" Registered mode(s): "), DLT_INT(   pstExistingClient->u32RegisteredMode));
1827   }
1828
1829   return enRetVal;
1830 }
1831
1832
1833 /**********************************************************************************************************************
1834 *
1835 * The callback is called when a lifecycle client should be unregistered or a shutdown
1836 * mode should be removed. In the list of lifecycle clients will be checked if the client exists. If the
1837 * client is found, the registration for the passed shutdown modes will be removed. If the client finally
1838 * is not registered for any shutdown mode, its entry will be removed from the list.
1839 *
1840 * @param sBusName:        Bus name of the remote application that hosts the lifecycle client interface
1841 * @param sObjName:        Object name of the lifecycle client
1842 * @param u32ShutdownMode: Shutdown mode for which the client wants to unregister
1843 * @param penRetVal:       Pointer, where to store the return value
1844 *
1845 **********************************************************************************************************************/
1846 static NsmErrorStatus_e NSM__enOnHandleUnRegisterLifecycleClient(const gchar *sBusName,
1847                                                                  const gchar *sObjName,
1848                                                                  const guint  u32ShutdownMode)
1849 {
1850   NSM__tstLifecycleClient *pstExistingClient = NULL;
1851   NSM__tstLifecycleClient  stSearchClient    = {0};
1852   GList                   *pListEntry        = NULL;
1853   NsmErrorStatus_e         enRetVal          = NsmErrorStatus_NotSet;
1854
1855   stSearchClient.sBusName = (gchar*) sBusName;
1856   stSearchClient.sObjName = (gchar*) sObjName;
1857
1858   /* Check if the lifecycle client already is registered */
1859   pListEntry = g_list_find_custom(NSM__pLifecycleClients, &stSearchClient, &NSM__i32LifecycleClientCompare);
1860
1861   /* Check if an existing client could be found */
1862   if(pListEntry != NULL)
1863   {
1864     /* The client could be found in the list. Change the registered shutdown mode */
1865     enRetVal = NsmErrorStatus_Ok;
1866     pstExistingClient = (NSM__tstLifecycleClient*) pListEntry->data;
1867     pstExistingClient->u32RegisteredMode &= ~(u32ShutdownMode);
1868
1869     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Unregistered lifecycle consumer for mode(s)."                ),
1870                                       DLT_STRING(" Bus name: "),     DLT_STRING(pstExistingClient->sBusName         ),
1871                                       DLT_STRING(" Obj name: "),     DLT_STRING(pstExistingClient->sObjName         ),
1872                                       DLT_STRING(" New mode: "),     DLT_INT(   pstExistingClient->u32RegisteredMode),
1873                                       DLT_STRING(" Client: "  ),     DLT_UINT((guint) pstExistingClient->hClient)   );
1874
1875     if(pstExistingClient->u32RegisteredMode == NSM_SHUTDOWNTYPE_NOT)
1876     {
1877       /* The client is not registered for at least one mode. Remove it from the list */
1878       NSM__vFreeLifecycleClientObject(pstExistingClient);
1879       NSM__pLifecycleClients = g_list_remove(NSM__pLifecycleClients, pstExistingClient);
1880     }
1881   }
1882   else
1883   {
1884     /* Warning: The client could not be found in the list of clients. */
1885     enRetVal = NsmErrorStatus_Parameter;
1886     DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: Failed to unregister lifecycle consumer."),
1887                                       DLT_STRING(" Bus name: "),             DLT_STRING(sBusName),
1888                                       DLT_STRING(" Obj name: "),             DLT_STRING(sObjName),
1889                                       DLT_STRING(" Unregistered mode(s): "), DLT_INT(   u32ShutdownMode));
1890   }
1891
1892   return enRetVal;
1893 }
1894
1895
1896 /**********************************************************************************************************************
1897 *
1898 * The function is used to get the state of the passed session.
1899 * It checks the passed parameters and creates a NsmSession_s structure of them.
1900 * If everything is ok, the state of the session will be determined and written to penSessionState.
1901 *
1902 * @param sSessionName:    Name  of the session whose state just be returned
1903 * @param sSessionName:    Owner of the session whose state just be returned
1904 * @param enSeatId:        Seat of the session
1905 * @param penSessionState: Pointer where to store the session state
1906 * @param penRetVal:       Pointer where to store the return value
1907 *
1908 **********************************************************************************************************************/
1909 static NsmErrorStatus_e NSM__enOnHandleGetSessionState(const gchar       *sSessionName,
1910                                                        const NsmSeat_e    enSeatId,
1911                                                        NsmSessionState_e *penSessionState)
1912 {
1913   /* Function local variables                                                                     */
1914   NsmErrorStatus_e  enRetVal           = NsmErrorStatus_NotSet;
1915   glong             u32SessionNameLen  = 0;                     /* Length of passed session owner */
1916   NsmSession_s      stSearchSession    = {0};                   /* To search for existing session */
1917
1918   /* Check if the passed parameters are valid */
1919   u32SessionNameLen = g_utf8_strlen(sSessionName, -1);
1920
1921   if(u32SessionNameLen < NSM_MAX_SESSION_OWNER_LENGTH)
1922   {
1923     /* Search for session with name, seat and owner. */
1924     stSearchSession.enSeat = enSeatId;
1925     g_strlcpy((gchar*) stSearchSession.sName,  sSessionName,  sizeof(stSearchSession.sName) );
1926
1927     enRetVal = NSM__enGetSessionState(&stSearchSession);
1928     *penSessionState = stSearchSession.enState;
1929   }
1930   else
1931   {
1932     /* Error: Invalid parameter. The session or owner name is to long. */
1933     enRetVal = NsmErrorStatus_Parameter;
1934     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to get session state. The session name is to long."),
1935                                        DLT_STRING(" Name: "      ), DLT_STRING(sSessionName                       ),
1936                                        DLT_STRING(" Seat: "      ), DLT_INT((gint) enSeatId                       ));
1937   }
1938
1939   return enRetVal;
1940 }
1941
1942
1943 /**********************************************************************************************************************
1944 *
1945 * The function sets the state of a session to a passed value.
1946 * It checks the passed parameters and creates a NsmSession_s structure of them.
1947 * If everything is ok, the state of the session will be set accordingly.
1948 *
1949 * @param sSessionName:   Name of the session whose state just be set
1950 * @param sSessionOwner:  Owner of the session
1951 * @param enSeatId:       Seat of the session
1952 * @param enSessionState: New state of the session
1953 * @param penRetVal:      Pointer where to store the return value
1954 *
1955 **********************************************************************************************************************/
1956 static NsmErrorStatus_e NSM__enOnHandleSetSessionState(const gchar             *sSessionName,
1957                                                        const gchar             *sSessionOwner,
1958                                                        const NsmSeat_e          enSeatId,
1959                                                        const NsmSessionState_e  enSessionState)
1960 {
1961   /* Function local variables                                                                       */
1962   NsmErrorStatus_e enRetVal           = NsmErrorStatus_NotSet;
1963   glong            u32SessionNameLen  = 0;            /* Length of passed session owner             */
1964   glong            u32SessionOwnerLen = 0;            /* Length of passed session name              */
1965   NsmSession_s     stSession          = {0};          /* Session object passed to internal function */
1966
1967   /* Check if the passed parameters are valid */
1968   u32SessionNameLen  = g_utf8_strlen(sSessionName,  -1);
1969   u32SessionOwnerLen = g_utf8_strlen(sSessionOwner, -1);
1970
1971   if(   (u32SessionNameLen  < NSM_MAX_SESSION_NAME_LENGTH )
1972      && (u32SessionOwnerLen < NSM_MAX_SESSION_OWNER_LENGTH))
1973   {
1974     /* Build session object to pass it internally */
1975     g_strlcpy((gchar*) stSession.sName,  sSessionName,  sizeof(stSession.sName) );
1976     g_strlcpy((gchar*) stSession.sOwner, sSessionOwner, sizeof(stSession.sOwner));
1977
1978     stSession.enSeat  = enSeatId;
1979     stSession.enState = enSessionState;
1980
1981     enRetVal = NSM__enSetSessionState(&stSession, TRUE, TRUE);
1982   }
1983   else
1984   {
1985     /* Error: Invalid parameter. The session or owner name is to long. */
1986     enRetVal = NsmErrorStatus_Parameter;
1987     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to set session state. Invalid parameter."),
1988                                        DLT_STRING(" Name: "      ), DLT_STRING(sSessionName             ),
1989                                        DLT_STRING(" Owner: "     ), DLT_STRING(sSessionOwner            ),
1990                                        DLT_STRING(" Seat: "      ), DLT_INT((gint) enSeatId             ));
1991   }
1992
1993   return enRetVal;
1994 }
1995
1996
1997 /**********************************************************************************************************************
1998 *
1999 * The helper function is called by 'NSM__boOnHandleSetAppHealthStatus', when an application became valid again.
2000 * It removes the application from the list of invalid apps.
2001 *
2002 * @param pstFailedApp: Pointer to structure with information about the failed application.
2003 *
2004 * @return NsmErrorStatus_Ok:           The application has been removed from the list of failed apps.
2005 *         NsmErrorStatus_WrongSession: The application has never been on the list of failed apps.
2006 *
2007 **********************************************************************************************************************/
2008 static NsmErrorStatus_e NSM__enSetAppStateValid(NSM__tstFailedApplication* pstFailedApp)
2009 {
2010   /* Function local variables                                                                             */
2011   GSList                    *pAppListEntry          = NULL;                  /* List entry of application */
2012   NsmErrorStatus_e           enRetVal               = NsmErrorStatus_NotSet; /* Return value              */
2013   NSM__tstFailedApplication *pstExistingApplication = NULL;
2014
2015   /* An application has become valid again. Check if it really was invalid before. */
2016   pAppListEntry = g_slist_find_custom(NSM__pFailedApplications, pstFailedApp, &NSM__i32ApplicationCompare);
2017
2018   if(pAppListEntry != NULL)
2019   {
2020     /* We found at least one entry for the application. Remove it from the list */
2021     enRetVal = NsmErrorStatus_Ok;
2022     pstExistingApplication = (NSM__tstFailedApplication*) pAppListEntry->data;
2023     NSM__pFailedApplications = g_slist_remove(NSM__pFailedApplications, pstExistingApplication);
2024     NSM__vFreeFailedApplicationObject(pstExistingApplication);
2025
2026     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: An application has become valid again."    ),
2027                                       DLT_STRING(" Application: "), DLT_STRING(pstFailedApp->sName));
2028   }
2029   else
2030   {
2031     /* Error: There was no session registered for the application that failed. */
2032     enRetVal = NsmErrorStatus_Error;
2033     DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: Failed to set application valid. Application was never invalid."),
2034                                       DLT_STRING(" Application: "), DLT_STRING(pstFailedApp->sName                     ));
2035   }
2036
2037   return enRetVal;
2038 }
2039
2040
2041 /**********************************************************************************************************************
2042 *
2043 * The helper function is called by 'NSM__enSetAppStateFailed', when an application failed.
2044 * It looks for sessions that have been registered by the app.
2045 *
2046 * @param pstFailedApp: Pointer to structure with information about the failed application.
2047 *
2048 **********************************************************************************************************************/
2049 static void NSM__vDisableSessionsForApp(NSM__tstFailedApplication* pstFailedApp)
2050 {
2051   /* Function local variables */
2052   GSList       *pSessionListEntry  = NULL;
2053   NsmSession_s *pstExistingSession = NULL;
2054   NsmSession_s  stSearchSession    = {0};
2055
2056   /* Only set the "owner" of the session (to the AppName) to search for all sessions of the app. */
2057   g_strlcpy(stSearchSession.sOwner, pstFailedApp->sName, sizeof(stSearchSession.sOwner));
2058
2059   g_mutex_lock(NSM__pSessionMutex);
2060   pSessionListEntry = g_slist_find_custom(NSM__pSessions, &stSearchSession, &NSM__i32SessionOwnerCompare);
2061
2062   if(pSessionListEntry != NULL)
2063   {
2064     /* Found at least one session. */
2065     do
2066     {
2067       /* Get the session object for the list entry */
2068       pstExistingSession = (NsmSession_s*) pSessionListEntry->data;
2069       pstExistingSession->enState = NsmSessionState_Unregistered;
2070
2071       /* Inform D-Bus and StateMachine that a session became invalid */
2072       NSM__vPublishSessionChange(pstExistingSession, TRUE, TRUE);
2073
2074       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: A session has become invalid, because an application failed."),
2075                                         DLT_STRING(" Application: "), DLT_STRING(pstExistingSession->sOwner           ),
2076                                         DLT_STRING(" Session: "),     DLT_STRING(pstExistingSession->sName            ),
2077                                         DLT_STRING(" Seat: "),        DLT_INT(   pstExistingSession->enSeat           ),
2078                                         DLT_STRING(" State: "),       DLT_INT(   pstExistingSession->enState          ));
2079
2080       /* Remove or "reset" session */
2081       if(NSM__boIsPlatformSession(pstExistingSession) == TRUE)
2082       {
2083         /* It is a default session. Don't remove it. Set owner to NSM again. */
2084         g_strlcpy(pstExistingSession->sOwner, NSM_DEFAULT_SESSION_OWNER, sizeof(pstExistingSession->sOwner));
2085       }
2086       else
2087       {
2088         /* The session has been registered by a failed app. Remove it. */
2089         NSM__pSessions = g_slist_remove(NSM__pSessions, pstExistingSession);
2090         NSM__vFreeSessionObject(pstExistingSession);
2091       }
2092
2093       /* Try to find the next session that had been registered for the app. */
2094       pSessionListEntry = g_slist_find_custom(NSM__pSessions, &stSearchSession, &NSM__i32SessionOwnerCompare);
2095
2096     } while(pSessionListEntry != NULL);
2097   }
2098   else
2099   {
2100     /* There have been no session registered for this application. */
2101     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: There had been no registered sessions."    ),
2102                                       DLT_STRING(" Application: "), DLT_STRING(pstFailedApp->sName));
2103   }
2104
2105   g_mutex_unlock(NSM__pSessionMutex);
2106 }
2107
2108
2109 /**********************************************************************************************************************
2110 *
2111 * The helper function is called by 'NSM__boOnHandleSetAppHealthStatus', when an application failed.
2112 *
2113 * @param pstFailedApp: Pointer to structure with information about the failed application.
2114 *
2115 * @return always "NsmErrorStatus_Ok"
2116 *
2117 **********************************************************************************************************************/
2118 static NsmErrorStatus_e NSM__enSetAppStateFailed(NSM__tstFailedApplication* pstFailedApp)
2119 {
2120   /* Function local variables                                                                            */
2121   GSList                    *pFailedAppListEntry   = NULL;                  /* List entry of application */
2122   NsmErrorStatus_e           enRetVal              = NsmErrorStatus_NotSet; /* Return value              */
2123   NSM__tstFailedApplication *pstFailedApplication  = NULL;
2124
2125   /* An application failed. Check if the application already is known as 'failed'. */
2126   pFailedAppListEntry = g_slist_find_custom(NSM__pFailedApplications, pstFailedApp, &NSM__i32ApplicationCompare);
2127
2128   if(pFailedAppListEntry == NULL)
2129   {
2130     /* The application is not on the list yet. Create it. */
2131     enRetVal = NsmErrorStatus_Ok;
2132
2133     pstFailedApplication  = g_new(NSM__tstFailedApplication, 1);
2134     g_strlcpy(pstFailedApplication->sName, pstFailedApp->sName, sizeof(pstFailedApplication->sName));
2135     NSM__pFailedApplications = g_slist_append(NSM__pFailedApplications, pstFailedApplication);
2136
2137     /* Disable all session that have been registered by the application */
2138     NSM__vDisableSessionsForApp(pstFailedApplication);
2139   }
2140   else
2141   {
2142     /* Warning: The application is already in the list of failed session. */
2143     enRetVal = NsmErrorStatus_Ok;
2144     DLT_LOG(NsmContext, DLT_LOG_WARN, DLT_STRING("NSM: The application has already been marked as 'failed'."),
2145                                       DLT_STRING(" Application: "), DLT_STRING(pstFailedApp->sName          ));
2146   }
2147
2148   return enRetVal;
2149 }
2150
2151
2152 /**********************************************************************************************************************
2153 *
2154 * The function is called when an application has become invalid or valid again.
2155 * If an application became inactive, it will be added to the list of failed applications
2156 * and signals for the session registered by the application will be emitted.
2157 * If an application became valid again, it will only be removed from the list of failed sessions.
2158 *
2159 * @param sAppName:   Application which changed its state.
2160 * @param boAppState: Indicates if the application became invalid or valid again.
2161 * @param penRetVal:  Pointer where to store the return value
2162 *
2163 **********************************************************************************************************************/
2164 static NsmErrorStatus_e NSM__enOnHandleSetAppHealthStatus(const gchar    *sAppName,
2165                                                           const gboolean  boAppState)
2166 {
2167   /* Function local variables                                                                     */
2168   NSM__tstFailedApplication stSearchApplication = {0}; /* Temporary application object for search */
2169   NsmErrorStatus_e          enRetVal            = NsmErrorStatus_NotSet;
2170
2171   /* Check if passed parameters are valid */
2172   if(strlen(sAppName) < NSM_MAX_SESSION_OWNER_LENGTH)
2173   {
2174     /* The application name is valid. Copy it for further checks. */
2175     g_strlcpy((gchar*) stSearchApplication.sName, sAppName, sizeof(stSearchApplication.sName));
2176
2177     if(boAppState == TRUE)
2178     {
2179       enRetVal = NSM__enSetAppStateValid(&stSearchApplication);
2180     }
2181     else
2182     {
2183       enRetVal = NSM__enSetAppStateFailed(&stSearchApplication);
2184     }
2185   }
2186   else
2187   {
2188     /* Error: The passed application name is too long. */
2189     enRetVal = NsmErrorStatus_Parameter;
2190     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Failed to set application health status. The application name is too long."),
2191                                        DLT_STRING(" Owner: "     ), DLT_STRING(sAppName                                            ),
2192                                        DLT_STRING(" State: "     ), DLT_INT(boAppState                                             ));
2193
2194   }
2195
2196   return enRetVal;
2197 }
2198
2199
2200 /**********************************************************************************************************************
2201 *
2202 * The function returns the current AppHealthCount, which is stored in local variable.
2203 *
2204 * @param pu32AppHealthCount: Pointer where to store the AppHealthCount (number of failed applications).
2205 *
2206 **********************************************************************************************************************/
2207 static guint NSM__u32OnHandleGetAppHealthCount(void)
2208 {
2209   return g_slist_length(NSM__pFailedApplications);
2210 }
2211
2212
2213 /**********************************************************************************************************************
2214 *
2215 * The function returns the current interface version of the NodeStateManager.
2216 *
2217 * @param pu32InterfaceVersion: Pointer where to store the interface version.
2218 *
2219 **********************************************************************************************************************/
2220 static guint NSM__u32OnHandleGetInterfaceVersion(void)
2221 {
2222   /* Return interface version to caller. */
2223   return NSM_INTERFACE_VERSION;
2224 }
2225
2226
2227 /**********************************************************************************************************************
2228 *
2229 * The function is called cyclically and triggers the systemd wdog.
2230 *
2231 * @param pUserData: Pointer to optional user data
2232 *
2233 * @return Always TRUE to keep timer callback alive.
2234 *
2235 **********************************************************************************************************************/
2236 static gboolean NSM__boOnHandleTimerWdog(gpointer pUserData)
2237 {
2238   (void) sd_notify(0, "WATCHDOG=1");
2239   DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Triggered systemd WDOG."));
2240
2241   return TRUE;
2242 }
2243
2244
2245 /**********************************************************************************************************************
2246 *
2247 * The function checks if the NSM is observed by a systemd wdog and installs a timer if necessary.
2248 *
2249 **********************************************************************************************************************/
2250 static void NSM__vConfigureWdogTimer(void)
2251 {
2252   const gchar *sWdogSec   = NULL;
2253   guint        u32WdogSec = 0;
2254
2255   sWdogSec = g_getenv("WATCHDOG_USEC");
2256
2257   if(sWdogSec != NULL)
2258   {
2259     u32WdogSec = strtoul(sWdogSec, NULL, 10);
2260
2261     /* The min. valid value for systemd is 1 s => WATCHDOG_USEC at least needs to contain 1.000.000 us */
2262     if(u32WdogSec >= 1000000)
2263     {
2264       /* Convert us timeout in ms and divide by two to trigger wdog every half timeout interval */
2265       u32WdogSec /= 2000;
2266       (void) g_timeout_add_full(G_PRIORITY_DEFAULT,
2267                                 u32WdogSec,
2268                                 &NSM__boOnHandleTimerWdog,
2269                                 NULL,
2270                                 NULL);
2271       DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Started wdog timer."            ),
2272                                         DLT_STRING("Interval [ms]:"), DLT_UINT(u32WdogSec));
2273     }
2274     else
2275     {
2276       DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Error. Invalid wdog config."    ),
2277                                          DLT_STRING("WATCHDOG_USEC:"), DLT_STRING(sWdogSec));
2278     }
2279   }
2280   else
2281   {
2282     DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Daemon not observed by wdog"));
2283   }
2284 }
2285
2286
2287 /**********************************************************************************************************************
2288 *
2289 * The function initializes all file local variables
2290 *
2291 **********************************************************************************************************************/
2292 static void  NSM__vInitializeVariables(void)
2293 {
2294   /* Initialize file local variables */
2295   NSM__pSessionMutex           = NULL;
2296   NSM__pSessions               = NULL;
2297   NSM__pLifecycleClients       = NULL;
2298   NSM__pNodeStateMutex         = NULL;
2299   NSM__enNodeState             = NsmNodeState_NotSet;
2300   NSM__pNextApplicationModeMutex = NULL;
2301   NSM__pThisApplicationModeMutex = NULL;
2302   NSM__pFailedApplications     = NULL;
2303   NSM__pCurrentLifecycleClient = NULL;
2304   NSM__enNextApplicationMode   = NsmApplicationMode_NotSet;
2305   NSM__enThisApplicationMode   = NsmApplicationMode_NotSet;
2306   NSM__boThisApplicationModeRead = FALSE;
2307 }
2308
2309
2310 /**********************************************************************************************************************
2311 *
2312 * The function creates the platform sessions, configured in "NSM__asDefaultSessions".
2313 *
2314 **********************************************************************************************************************/
2315 static void  NSM__vCreatePlatformSessions(void)
2316 {
2317   NsmSession_s *pNewDefaultSession   = NULL;
2318   guint         u32DefaultSessionIdx = 0;
2319   NsmSeat_e     enSeatIdx            = NsmSeat_NotSet;
2320
2321   /* Configure the default sessions, which are always available */
2322   for(u32DefaultSessionIdx = 0;
2323       u32DefaultSessionIdx < sizeof(NSM__asDefaultSessions)/sizeof(gchar*);
2324       u32DefaultSessionIdx++)
2325   {
2326     /* Create a session for every session name and seat */
2327     for(enSeatIdx = NsmSeat_NotSet + 1; enSeatIdx < NsmSeat_Last; enSeatIdx++)
2328     {
2329       pNewDefaultSession          = g_new0(NsmSession_s, 1);
2330       g_strlcpy((gchar*) pNewDefaultSession->sName,  NSM__asDefaultSessions[u32DefaultSessionIdx], sizeof(pNewDefaultSession->sName));
2331       g_strlcpy((gchar*) pNewDefaultSession->sOwner, NSM_DEFAULT_SESSION_OWNER, sizeof(pNewDefaultSession->sOwner));
2332       pNewDefaultSession->enSeat  = enSeatIdx;
2333       pNewDefaultSession->enState = NsmSessionState_Inactive;
2334
2335       NSM__pSessions = g_slist_append(NSM__pSessions, pNewDefaultSession);
2336     }
2337   }
2338 }
2339
2340
2341 /**********************************************************************************************************************
2342 *
2343 * The function creates the mutexes used in the NSM.
2344 *
2345 **********************************************************************************************************************/
2346 static void NSM__vCreateMutexes(void)
2347 {
2348   /* Initialize the local mutexes */
2349   NSM__pNodeStateMutex       = g_mutex_new();
2350   NSM__pThisApplicationModeMutex = g_mutex_new();
2351   NSM__pNextApplicationModeMutex = g_mutex_new();
2352   NSM__pSessionMutex         = g_mutex_new();
2353 }
2354
2355
2356 /**********************************************************************************************************************
2357 *
2358 * The function deletes the mutexes used in the NSM.
2359 *
2360 **********************************************************************************************************************/
2361 static void NSM__vDeleteMutexes(void)
2362 {
2363   /* Delete the local mutexes */
2364   g_mutex_free(NSM__pNodeStateMutex);
2365   g_mutex_free(NSM__pNextApplicationModeMutex);
2366   g_mutex_free(NSM__pThisApplicationModeMutex);
2367   g_mutex_free(NSM__pSessionMutex);
2368 }
2369
2370
2371 /**********************************************************************************************************************
2372 *
2373 * The function is called to trace a syslog message for a shutdown client.
2374 *
2375 * @param sBus:          Bus name of the shutdown client.
2376 * @param sObj:          Object name of the lifecycle client.
2377 * @param u32Reason:     Shutdown reason send to the client.
2378 * @param sInOut:        "enter" or "leave" (including failure reason)
2379 * @param enErrorStatus: Error value
2380 *
2381 **********************************************************************************************************************/
2382 static void NSM__vLtProf(gchar *sBus, gchar *sObj, guint32 u32Reason, gchar *sInOut, NsmErrorStatus_e enErrorStatus)
2383 {
2384     gchar pszLtprof[128] = "LTPROF: bus:%s obj:%s (0x%08X:%d) ";
2385     guint32 dwLength = 128;
2386
2387     g_strlcat(pszLtprof, sInOut, dwLength);
2388
2389     if(u32Reason != 0)
2390     {
2391         if(u32Reason == NSM_SHUTDOWNTYPE_RUNUP)
2392         {
2393           g_strlcat(pszLtprof, "runup", dwLength);
2394         }
2395         else
2396         {
2397           g_strlcat(pszLtprof, "shutdown", dwLength);
2398         }
2399     }
2400
2401     syslog(LOG_NOTICE, (char *)pszLtprof, sBus, sObj, u32Reason, enErrorStatus);
2402 }
2403
2404
2405 /**********************************************************************************************************************
2406 *
2407 * The function is used to initialize syslog
2408 *
2409 **********************************************************************************************************************/
2410 static void NSM__vSyslogOpen(void)
2411 {
2412   openlog("NSM", LOG_PID, LOG_USER);
2413 }
2414
2415
2416 /**********************************************************************************************************************
2417 *
2418 * The function is used to deinitialize syslog
2419 *
2420 **********************************************************************************************************************/
2421 static void NSM__vSyslogClose(void)
2422 {
2423   closelog();
2424 }
2425
2426
2427 /**********************************************************************************************************************
2428 *
2429 * Interfaces. Exported functions. See Header for detailed description.
2430 *
2431 **********************************************************************************************************************/
2432
2433
2434 /* The function is called by the NodeStateMachine to set a "property" of the NSM. */
2435 NsmErrorStatus_e NsmSetData(NsmDataType_e enData, unsigned char *pData, unsigned int u32DataLen)
2436 {
2437   /* Function local variables                                        */
2438   NsmErrorStatus_e enRetVal = NsmErrorStatus_NotSet; /* Return value */
2439
2440   /* Check which data the NSMC wants to set */
2441   switch(enData)
2442   {
2443     /* NSMC wants to set the NodeState */
2444     case NsmDataType_NodeState:
2445       enRetVal =   (u32DataLen == sizeof(NsmNodeState_e))
2446                  ? NSM__enSetNodeState((NsmNodeState_e) *pData, TRUE, FALSE)
2447                  : NsmErrorStatus_Parameter;
2448     break;
2449
2450     /* NSMC wants to set the AppMode */
2451     case NsmDataType_AppMode:
2452       enRetVal =   (u32DataLen == sizeof(NsmApplicationMode_e))
2453                  ? NSM__enSetApplicationMode((NsmApplicationMode_e) *pData, TRUE, FALSE)
2454                  : NsmErrorStatus_Parameter;
2455     break;
2456
2457     /* NSMC wants to set the BootMode */
2458     case NsmDataType_BootMode:
2459       enRetVal =   (u32DataLen == sizeof(gint))
2460                  ? NSM__enSetBootMode((gint) *pData, FALSE)
2461                  : NsmErrorStatus_Parameter;
2462     break;
2463
2464     /* NSMC wants to set the ShutdownReason */
2465     case NsmDataType_ShutdownReason:
2466       enRetVal =   (u32DataLen == sizeof(NsmShutdownReason_e))
2467                  ? NSM__enSetShutdownReason((NsmShutdownReason_e) *pData, FALSE)
2468                  : NsmErrorStatus_Parameter;
2469     break;
2470
2471     /* NSMC wants to set a SessionState */
2472     case NsmDataType_SessionState:
2473       enRetVal =   (u32DataLen == sizeof(NsmSession_s))
2474                  ? NSM__enSetSessionState((NsmSession_s*) pData, TRUE, FALSE)
2475                  : NsmErrorStatus_Parameter;
2476     break;
2477
2478     /* NSMC wants to register a session */
2479     case NsmDataType_RegisterSession:
2480       enRetVal =   (u32DataLen == sizeof(NsmSession_s))
2481                  ? NSM__enRegisterSession((NsmSession_s*) pData, TRUE, FALSE)
2482                  : NsmErrorStatus_Parameter;
2483     break;
2484
2485     /* NSMC wants to unregister a session */
2486     case NsmDataType_UnRegisterSession:
2487       enRetVal =   (u32DataLen == sizeof(NsmSession_s))
2488                  ? NSM__enUnRegisterSession((NsmSession_s*) pData, TRUE, FALSE)
2489                  : NsmErrorStatus_Parameter;
2490     break;
2491
2492     /* Error: The type of the data NSMC is trying to set is unknown or the data is read only! */
2493     case NsmDataType_RestartReason:
2494     case NsmDataType_RunningReason:
2495     default:
2496       enRetVal = NsmErrorStatus_Parameter;
2497     break;
2498   }
2499
2500   return enRetVal;
2501 }
2502
2503
2504 /* The function is called by the NodeStateMachine to get a "property" of the NSM. */
2505 int NsmGetData(NsmDataType_e enData, unsigned char *pData, unsigned int u32DataLen)
2506 {
2507   /* Function local variables                                             */
2508   int i32RetVal = -1; /* Return value. Positive: Amount of written bytes.
2509                                        Negative: An error occurred.       */
2510
2511   /* Check which data the NSMC wants to get */
2512   switch(enData)
2513   {
2514     /* NSMC wants to get the NodeState */
2515     case NsmDataType_NodeState:
2516       if(u32DataLen == sizeof(NsmNodeState_e))
2517       {
2518         if(NSM__enGetNodeState((NsmNodeState_e*) pData) == NsmErrorStatus_Ok)
2519         {
2520           i32RetVal = sizeof(NsmNodeState_e);
2521         }
2522       }
2523     break;
2524
2525     /* NSMC wants to get the ApplicationMode */
2526     case NsmDataType_AppMode:
2527       if(u32DataLen == sizeof(NsmApplicationMode_e))
2528       {
2529         if(NSM__enGetApplicationMode((NsmApplicationMode_e*) pData) == NsmErrorStatus_Ok)
2530         {
2531           i32RetVal = sizeof(NsmApplicationMode_e);
2532         }
2533       }
2534     break;
2535
2536     /* NSMC wants to get the BootMode */
2537     case NsmDataType_BootMode:
2538       if(u32DataLen == sizeof(gint))
2539       {
2540         if(NSMA_boGetBootMode((gint*) pData) == TRUE)
2541         {
2542           i32RetVal = sizeof(gint);
2543         }
2544       }
2545     break;
2546
2547     /* NSMC wants to get the RunningReason */
2548     case NsmDataType_RunningReason:
2549       if(u32DataLen == sizeof(NsmRunningReason_e))
2550       {
2551         if(NSMA_boGetRunningReason((NsmRunningReason_e*) pData) == TRUE)
2552         {
2553           i32RetVal = sizeof(NsmRunningReason_e);
2554         }
2555       }
2556     break;
2557
2558     /* NSMC wants to get the ShutdownReason */
2559     case NsmDataType_ShutdownReason:
2560       if(u32DataLen == sizeof(NsmShutdownReason_e))
2561       {
2562         if(NSMA_boGetShutdownReason((NsmShutdownReason_e*) pData) == TRUE)
2563         {
2564           i32RetVal = sizeof(NsmShutdownReason_e);
2565         }
2566       }
2567     break;
2568
2569     /* NSMC wants to get the RestartReason */
2570     case NsmDataType_RestartReason:
2571       if(u32DataLen == sizeof(NsmRestartReason_e))
2572       {
2573         if(NSMA_boGetRestartReason((NsmRestartReason_e*) pData) == TRUE)
2574         {
2575           i32RetVal = sizeof(NsmRestartReason_e);
2576         }
2577       }
2578     break;
2579
2580     /* NSMC wants to get the SessionState */
2581     case NsmDataType_SessionState:
2582       if(u32DataLen == sizeof(NsmSession_s))
2583       {
2584         if(NSM__enGetSessionState((NsmSession_s*) pData) == NsmErrorStatus_Ok)
2585         {
2586           i32RetVal = sizeof(NsmSession_s);
2587         }
2588       }
2589     break;
2590
2591     /* Error: The type of the data NSMC is trying to set is unknown. */
2592     default:
2593       i32RetVal = -1;
2594     break;
2595   }
2596
2597   return i32RetVal;
2598 }
2599
2600
2601 unsigned int NsmGetInterfaceVersion(void)
2602 {
2603         return NSM_INTERFACE_VERSION;
2604 }
2605
2606
2607 /* The main function of the NodeStateManager */
2608 int main(void)
2609 {
2610   gboolean  boEndByUser = FALSE;
2611   int       pcl_return  = 0;
2612
2613   /* Initialize glib for using "g" types */
2614   g_type_init();
2615
2616   /* Register NSM for DLT */
2617   DLT_REGISTER_APP("NSM", "Node State Manager");
2618   DLT_REGISTER_CONTEXT(NsmContext, "005", "Context for the NSM");
2619   DLT_ENABLE_LOCAL_PRINT();
2620
2621   /* Initialize syslog */
2622   NSM__vSyslogOpen();
2623
2624   /* Print first msg. to show that NSM is going to start */
2625   DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: NodeStateManager started."), DLT_STRING("Version:"), DLT_STRING(VERSION));
2626
2627   /* Initialize PCL before initializing variables */
2628   pcl_return = pclInitLibrary("NodeStateManager",   PCL_SHUTDOWN_TYPE_NORMAL
2629                                                   | PCL_SHUTDOWN_TYPE_FAST);
2630   if(pcl_return < 0)
2631   {
2632     DLT_LOG(NsmContext,
2633             DLT_LOG_WARN,
2634             DLT_STRING("NSM: Failed to initialize PCL.");
2635             DLT_STRING("Error: Unexpected PCL return.");
2636             DLT_STRING("Return:"); DLT_INT(pcl_return));
2637   }
2638
2639   /* Currently no other resources accessing the NSM. Prepare it now! */
2640   NSM__vInitializeVariables();     /* Initialize file local variables*/
2641   NSM__vCreatePlatformSessions();  /* Create platform sessions       */
2642   NSM__vCreateMutexes();           /* Create mutexes                 */
2643
2644   /* Initialize the NSMA before the NSMC, because the NSMC can access properties */
2645   if(NSMA_boInit(&NSM__stObjectCallBacks) == TRUE)
2646   {
2647     /* Set the properties to initial values */
2648     (void) NSMA_boSetBootMode(0);
2649     (void) NSMA_boSetRestartReason(NsmRestartReason_NotSet);
2650     (void) NSMA_boSetShutdownReason(NsmShutdownReason_NotSet);
2651     (void) NSMA_boSetRunningReason(NsmRunningReason_WakeupCan);
2652
2653     /* Initialize/start the NSMC */
2654     if(NsmcInit() == 0x01)
2655     {
2656       /* Start timer to satisfy wdog */
2657       NSM__vConfigureWdogTimer();
2658       
2659       /* The event loop is only canceled if the Node is completely shut down or there is an internal error. */
2660       boEndByUser = NSMA_boWaitForEvents();
2661
2662       if(boEndByUser == TRUE)
2663       {
2664         DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Successfully canceled event loop. "),
2665                                           DLT_STRING("Shutting down NodeStateManager."        ));
2666       }
2667       else
2668       {
2669         DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: Error in event loop. "     ),
2670                                           DLT_STRING("Shutting down NodeStateManager."));
2671       }
2672
2673       /* The event loop returned. Clean up the NSMA. */
2674       (void) NSMA_boDeInit();
2675     }
2676     else
2677     {
2678       /* Error: Failed to initialize the NSMC. Clean up NSMA, because it is not needed anymore. */
2679       (void) NSMA_boDeInit();
2680       DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Error. Failed to initialize the NSMC."));
2681     }
2682   }
2683   else
2684   {
2685     /* Error: Failed to initialize the NSMA. */
2686     DLT_LOG(NsmContext, DLT_LOG_ERROR, DLT_STRING("NSM: Error. Failed to initialize the NSMA."));
2687   }
2688
2689   /* Free the mutexes */
2690   NSM__vDeleteMutexes();
2691
2692   /* Remove data from all lists */
2693   g_slist_free_full(NSM__pSessions,           &NSM__vFreeSessionObject);
2694   g_slist_free_full(NSM__pFailedApplications, &NSM__vFreeFailedApplicationObject);
2695   g_list_free_full (NSM__pLifecycleClients,   &NSM__vFreeLifecycleClientObject);
2696
2697   /* Deinitialize the PCL */
2698   pcl_return = pclDeinitLibrary();
2699
2700   if(pcl_return < 0)
2701   {
2702     DLT_LOG(NsmContext,
2703             DLT_LOG_WARN,
2704             DLT_STRING("NSM: Failed to deinitialize PCL.");
2705             DLT_STRING("Error: Unexpected PCL return.");
2706             DLT_STRING("Return:"); DLT_INT(pcl_return));
2707   }
2708
2709   DLT_LOG(NsmContext, DLT_LOG_INFO, DLT_STRING("NSM: NodeStateManager stopped."));
2710
2711   /* Deinit syslog */
2712   NSM__vSyslogClose();
2713
2714   /* Unregister NSM from DLT */
2715   DLT_UNREGISTER_CONTEXT(NsmContext);
2716   DLT_UNREGISTER_APP();
2717
2718   return 0;
2719 }