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