diff options
author | Guy Sagnes <guy.sagnes@continental-corporation.com> | 2014-02-25 10:32:29 +0100 |
---|---|---|
committer | Ralf Anton Beier <ralf.anton.beier@continental-corporation.com> | 2014-02-25 11:33:41 +0100 |
commit | 880e7ffe185e5b410ee6183c4ce355a8a204ab28 (patch) | |
tree | 9c18d6aecfaf69a6753b4c2f251583cfe9f3722e /src/pers_ipc_dbus.c | |
parent | 94b07e2221c3333a5a54f689eca4249667892f74 (diff) | |
download | persistence-common-object-880e7ffe185e5b410ee6183c4ce355a8a204ab28.tar.gz |
Added version 1.0.1
12.12.2013 * add missing licenses information / update after review feedback 20131212 - J.Kowalski
03.12.2013 * Persistence Common Object - OIP BL 0.9.130
08.08.2013 * Add instrumentation for debug purposes (low level db access)
18.06.2013 * persistence-common version 1.0.1
- Add makefile to allow creation of auto-generated code
- Default error handler causes the termination of the calling process
- de-central build of the common part
02.05.2013 * initial version of the common persistence libraries
Change-Id: I6ac6b7f1fe453537835ac32f664c04d537d732db
Signed-off-by: Guy Sagnes <guy.sagnes@continental-corporation.com>
Diffstat (limited to 'src/pers_ipc_dbus.c')
-rw-r--r-- | src/pers_ipc_dbus.c | 1590 |
1 files changed, 1590 insertions, 0 deletions
diff --git a/src/pers_ipc_dbus.c b/src/pers_ipc_dbus.c new file mode 100644 index 0000000..cac136d --- /dev/null +++ b/src/pers_ipc_dbus.c @@ -0,0 +1,1590 @@ +/********************************************************************************************************************** +* +* Copyright (C) 2012 Continental Automotive Systems, Inc. +* +* Author: Petrica.Manoila@continental-corporation.com +* +* Implementation of pers_ipc_dbus_if.h +* +* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. +* +* Date Author Reason +* 2013.10.24 uidu0250 CSP_WZ#6327 : Change error handling for missing PCL clients +* 2013.04.03 uidu0250 CSP_WZ#2739 : Initial creation +* +**********************************************************************************************************************/ + +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include <gio/gio.h> +#include <dlt.h> + +#include "persComErrors.h" +#include "persComTypes.h" +#include "persComIpc.h" +#include "PasClientNotificationGen.h" +#include "pers_ipc_dbus_if.h" + +/* ---------- local defines, macros, constants and type definitions ------------ */ + +#define PERS_IPC_INIT_DBUS_INFO_ARRAY_SIZE (uint32_t)24 +#define DBUS_MAIN_LOOP_THREAD_FLAG_SET 1 + +typedef struct persIpcDBusClientInfo_s_ +{ + pstr_t busName; + pstr_t objName; +}persIpcDBusClientInfo_s; + + +/* ----------global variables. initialization of global contexts ------------ */ + +DLT_IMPORT_CONTEXT(persComIpcDLTCtx); + +#define LT_HDR "COMMON_IPC >>" + + +static PersAdminPASInitInfo_s g_pPersIpcPASInfo; /* PAS IPC initialization struct */ +static PersAdminPCLInitInfo_s g_pPersIpcPCLInfo; /* PCL IPC initialization struct */ + +static persIpcDBusClientInfo_s **g_persIpcDBusClientInfoArray = NIL; +static uint32_t g_persIpcDBusClientInfoArraySize = 0; +static uint32_t g_persIpcDBusClientInfoMaxArraySize = 0; +static pthread_mutex_t g_persIpcDBusClientInfoArrayMtx; /* mutex for the access to the DBus client info array */ + +static pthread_t g_hPASDBusThread = 0; /* PAS DBus main loop thread */ +static int g_PASDBusMainLoopThreadFlag; +static pthread_cond_t g_PASDBusMainLoopThreadFlagCV; +static pthread_mutex_t g_PASDBusMainLoopThreadFlagMtx; +static pthread_t g_hPCLDBusThread = 0; /* PCL DBus main loop thread */ +static int g_PCLDBusMainLoopThreadFlag; +static pthread_cond_t g_PCLDBusMainLoopThreadFlagCV; +static pthread_mutex_t g_PCLDBusMainLoopThreadFlagMtx; + + +static GMainLoop *g_pPASMainLoop = NIL; /* PAS DBus main loop */ +static GDBusConnection *g_pPASDBusConnection = NIL; /* PAS DBus connection */ +static GMainLoop *g_pPCLMainLoop = NIL; /* PCL DBus main loop */ +static GDBusConnection *g_pPCLDBusConnection = NIL; /* PCL DBus connection */ +static OipPersistenceAdminSkeleton *g_persIpcDBusPASSkeleton = NIL; +static OipPersistenceAdminProxy *g_persIpcDBusPASProxy = NIL; +static OipPersistenceAdminconsumerSkeleton *g_persIpcDBusPCLSkeleton = NIL; +static volatile bool_t g_bPASDBusConnInit = false; +static volatile bool_t g_bPCLDBusConnInit = false; + + +/* ---------------------- local functions ---------------------------------- */ + +static void OnBusAcquired_cb( GDBusConnection *connection, const gchar *name, gpointer user_data); +static void OnNameAcquired_cb( GDBusConnection *connection, const gchar *name, gpointer user_data); +static void OnNameLost_cb( GDBusConnection *connection, const gchar *name, gpointer user_data); + +/* RegisterPersAdminNotification */ +static gboolean OnHandleRegisterPersAdminNotification ( OipPersistenceAdmin *object, + GDBusMethodInvocation *invocation, + const gchar *arg_BusName, + const gchar *arg_ObjName, + gint arg_NotificationFlag, + guint arg_TimeoutMs); + +/* UnregisterPersAdminNotification */ +static gboolean OnHandleUnregisterPersAdminNotification(OipPersistenceAdmin *object, + GDBusMethodInvocation *invocation, + const gchar *arg_BusName, + const gchar *arg_ObjName, + gint arg_NotificationFlag, + guint arg_TimeoutMs); + +/* PersistenceAdminRequestCompleted */ +static gboolean OnHandlePersAdminRequestCompleted( OipPersistenceAdmin *object, + GDBusMethodInvocation *invocation, + guint arg_RequestId, + gint arg_StatusFlag); + +/* PersAdminRequest */ +static gboolean OnHandlePersAdminRequest( OipPersistenceAdminconsumer *object, + GDBusMethodInvocation *invocation, + guint arg_RequestId, + gint arg_StatusFlag ); + +/* PAS DBus loop thread */ +static void* persIpcPASLoopThread(void *lpParam); + +/* PCL DBus loop thread */ +static void* persIpcPCLLoopThread(void *lpParam); + +/* PCL DBus initialization function */ +static sint_t persIpcInitPCL_DBus_high(); + +/* Get DBus client ID */ +static sint_t persIpcGetIdForDBusInfo(const pstr_t busName, + const pstr_t objName, + uint32_t *clientID); + +/* Export org.genivi.persistence.admin interface */ +static bool_t ExportPersistenceAdminIF(GDBusConnection *connection); + +/* Export org.genivi.persistence.adminconsumer interface */ +static bool_t ExportPersistenceAdminConsumerIF(GDBusConnection *connection); + + + +/** + * \brief Initialize PAS IPC DBus component + * + * \note : The function creates the DBus connection and tries to obtain the DBus name + * and exports the org.genivi.persistence.admin interface. + * It runs the DBus main loop on a second thread. + * + * \param pInitInfo [in] pointer to a \ref PersAdminPASInitInfo_s structure containing + * the supported callbacks + * + * \return 0 for success, negative value for error (\ref PERS_COM_ERROR_CODES_DEFINES) + */ +sint_t persIpcInitPAS_DBus_high(PersAdminPASInitInfo_s *pInitInfo) +{ + sint_t retVal = PERS_COM_SUCCESS; + + if(NIL == pInitInfo) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Invalid parameter in persIpcInitPAS_DBus_high call.")); + return PERS_COM_ERR_INVALID_PARAM; + } + + if((NIL == pInitInfo->pRegCB) || + (NIL == pInitInfo->pUnRegCB) || + (NIL == pInitInfo->pReqCompleteCB)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Invalid parameter in persIpcInitPAS_DBus_high call.")); + return PERS_COM_ERR_INVALID_PARAM; + } + + g_pPersIpcPASInfo.pRegCB = pInitInfo->pRegCB; + g_pPersIpcPASInfo.pUnRegCB = pInitInfo->pUnRegCB; + g_pPersIpcPASInfo.pReqCompleteCB = pInitInfo->pReqCompleteCB; + + /* Init synchronization objects */ + if(0 != pthread_mutex_init (&g_persIpcDBusClientInfoArrayMtx, NIL)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create mutex.")); + return PERS_COM_FAILURE; + } + if(0 != pthread_mutex_init (&g_PASDBusMainLoopThreadFlagMtx, NIL)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create mutex.")); + (void)pthread_mutex_destroy(&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_FAILURE; + } + if(0 != pthread_cond_init (&g_PASDBusMainLoopThreadFlagCV, NIL)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create thread cond.")); + (void)pthread_mutex_destroy(&g_PASDBusMainLoopThreadFlagMtx); + (void)pthread_mutex_destroy(&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_FAILURE; + } + g_PASDBusMainLoopThreadFlag = 0; + + /* Create DBus main loop thread */ + if(0 != pthread_create(&g_hPASDBusThread, NIL, persIpcPASLoopThread, NIL)) + { + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create thread.")); + (void)pthread_cond_destroy(&g_PASDBusMainLoopThreadFlagCV); + (void)pthread_mutex_destroy(&g_PASDBusMainLoopThreadFlagMtx); + (void)pthread_mutex_destroy(&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_FAILURE; + } + + /* Wait for DBus connection initialization */ + if(0 != pthread_mutex_lock (&g_PASDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + return PERS_COM_FAILURE; + } + while (!g_PASDBusMainLoopThreadFlag) + { + (void)pthread_cond_wait (&g_PASDBusMainLoopThreadFlagCV, &g_PASDBusMainLoopThreadFlagMtx); + } + (void)pthread_mutex_unlock (&g_PASDBusMainLoopThreadFlagMtx); + + if(false == g_bPASDBusConnInit) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("PAS DBus connection setup failed.")); + + (void)pthread_cond_destroy(&g_PASDBusMainLoopThreadFlagCV); + (void)pthread_mutex_destroy(&g_PASDBusMainLoopThreadFlagMtx); + (void)pthread_mutex_destroy(&g_persIpcDBusClientInfoArrayMtx); + + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + return retVal; +} + + +/** + * \brief Sends over DBus a request to the PCL client specified by clientId. + * \note : Each requestId should be unique. + * + * \param clientID [in] the client ID returned by the supplied pRegCB callback + * \param requestID [in] a unique identifier generated for every request + * \param request [in] the request to be sent (bitfield using a valid + * combination of any of the following flags : + * ::PERSISTENCE_MODE_LOCK, ::PERSISTENCE_MODE_SYNC and ::PERSISTENCE_MODE_UNLOCK) + * + * \return 0 for success, negative value for error (see \ref PERS_COM_ERROR_CODES_DEFINES) + */ +sint_t persIpcSendRequestToPCL_DBus_high( sint_t clientID, + sint_t requestID, + uint_t request) +{ + sint_t retVal = PERS_COM_SUCCESS; +/* gboolean gbRetVal = false; */ + gint32 outErrorCode = PERS_COM_SUCCESS; + persIpcDBusClientInfo_s dbusClientInfo; +/* OipPersistenceAdminconsumerProxy *pClientNotifProxy = NIL; */ + GError *gError = NIL; + GVariant *gVarReturnVal = NIL; + gint clientTimeout = 500; /* default timeout in ms */ + + if(false == g_bPASDBusConnInit) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus connection not initialized.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_ERR_NO_CONNECTION */ + } + + (void)memset(&dbusClientInfo, 0, sizeof(dbusClientInfo)); + + + /* Get client DBus info */ + + /* Acquire mutex on array of DBus client info */ + if(0 != pthread_mutex_lock (&g_persIpcDBusClientInfoArrayMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + return PERS_COM_FAILURE; + } + + if(clientID >= g_persIpcDBusClientInfoArraySize) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR, DLT_STRING(LT_HDR), + DLT_STRING("Invalid client specified :"), + DLT_INT(clientID)); + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_ERR_INVALID_PARAM; + } + + if(NIL != g_persIpcDBusClientInfoArray[clientID]) + { + dbusClientInfo.busName = (pstr_t)malloc((strlen(g_persIpcDBusClientInfoArray[clientID]->busName) + 1) * sizeof(*(dbusClientInfo.busName))); + if(NIL == dbusClientInfo.busName) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Error allocating memory for client info data.")); + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_ERR_MALLOC; + } + else + { + (void)memset(dbusClientInfo.busName, 0, (strlen(g_persIpcDBusClientInfoArray[clientID]->busName) + 1) * sizeof(*(dbusClientInfo.busName))); + (void)memcpy(dbusClientInfo.busName, g_persIpcDBusClientInfoArray[clientID]->busName, strlen(g_persIpcDBusClientInfoArray[clientID]->busName) * sizeof(*(dbusClientInfo.busName))); + } + + dbusClientInfo.objName = (pstr_t)malloc((strlen(g_persIpcDBusClientInfoArray[clientID]->objName) + 1) * sizeof(*(dbusClientInfo.objName))); + if(NIL == dbusClientInfo.objName) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Error allocating memory for client info data.")); + (void)free(dbusClientInfo.busName); + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_ERR_MALLOC; + } + else + { + (void)memset(dbusClientInfo.objName, 0, (strlen(g_persIpcDBusClientInfoArray[clientID]->objName) + 1) * sizeof(*(dbusClientInfo.objName))); + (void)memcpy(dbusClientInfo.objName, g_persIpcDBusClientInfoArray[clientID]->objName, strlen(g_persIpcDBusClientInfoArray[clientID]->objName) * sizeof(*(dbusClientInfo.objName))); + } + } + + /* Release array mutex */ + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + + + /* Synchronous call to "PersistenceAdminRequest" */ + + /* Does not work using generated code because PCL does not contain an implementation of 'GetAll' : */ + /* + * checkPersAdminMsg 'org.freedesktop.DBus.Properties' -> 'GetAll' + * handleObjectPathMessageFallback Object: ':1.11' -> Interface: 'org.freedesktop.DBus.Properties' -> Message: 'GetAll' + * handleObjectPathMessageFallback -> not a signal 'GetAll' + */ + + /* TO DO : un-comment when PCL implementation is adapted to PersCommonIPC */ + + /* Get the proxy object */ +// pClientNotifProxy = NIL; +// pClientNotifProxy = (OipPersistenceAdminconsumerProxy *)oip_persistence_adminconsumer_proxy_new_sync( g_pPASDBusConnection, +// G_DBUS_PROXY_FLAGS_NONE, +// dbusClientInfo.busName, +// dbusClientInfo.objName, +// NIL, +// NIL); +// if(NIL == pClientNotifProxy) +// { +// DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), +// DLT_STRING("DBus PersAdminConsumer proxy creation failed.")); +// (void)free(dbusClientInfo.busName); +// (void)free(dbusClientInfo.objName); +// return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ +// } +// +// (void)free(dbusClientInfo.busName); +// (void)free(dbusClientInfo.objName); +// +// /* Synchronous call to "PersistenceAdminRequest" */ +// gbRetVal = oip_persistence_adminconsumer_call_persistence_admin_request_sync( (OipPersistenceAdminconsumer *)pClientNotifProxy, +// (gint)request, +// (guint)requestID, +// &outErrorCode, +// NIL, +// &gError); +// +// /* Release the created proxy object */ +// g_object_unref(pClientNotifProxy); +// pClientNotifProxy = NIL; +// +// if(false == gbRetVal) +// { +// DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), +// DLT_STRING("DBus PersistenceAdminRequest call failed with DBus error :"), +// DLT_STRING(gError->message)); +// g_error_free(gError); +// return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ +// } + + gVarReturnVal = g_dbus_connection_call_sync ( g_pPASDBusConnection, + dbusClientInfo.busName, + dbusClientInfo.objName, + PERSISTENCE_ADMIN_CONSUMER_IFACE, + PERSISTENCE_ADMIN_CONSUMER_METHOD_PERS_ADMIN_REQ, + g_variant_new ("(ii)", (sint32_t)request, (sint32_t)requestID), + G_VARIANT_TYPE ("(i)"), + G_DBUS_CALL_FLAGS_NONE, + clientTimeout, + NIL, + &gError); + if(NIL == gVarReturnVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersistenceAdminRequest call failed with DBus error :"), + DLT_STRING(gError->message)); + g_error_free(gError); + (void)free(dbusClientInfo.busName); + (void)free(dbusClientInfo.objName); + + /* consider that PCL client is not available on DBus */ + return PERS_COM_IPC_ERR_PCL_NOT_AVAILABLE; + } + + outErrorCode = g_variant_get_int32(gVarReturnVal); + + g_variant_unref(gVarReturnVal); + + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG, DLT_STRING(LT_HDR), + DLT_STRING("Notified client identified by DBus Name : \""), + DLT_STRING(dbusClientInfo.busName), + DLT_STRING("\" and Object Path : \""), + DLT_STRING(dbusClientInfo.objName), + DLT_STRING("\" Flags="), + DLT_INT(request), + DLT_STRING(" RequestId="), + DLT_INT(requestID), + DLT_STRING("\". Client returned "), + DLT_INT(outErrorCode)); + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersistenceAdminRequest call returned output error code :"), + DLT_INT(outErrorCode)); + + (void)free(dbusClientInfo.busName); + (void)free(dbusClientInfo.objName); + + retVal = outErrorCode; + + return retVal; +} + + +/** + * \brief Register PCL client to PAS over DBus + * + * \note : An additional thread is created for communication purposes. + * Initialize members of the supplied PersAdminPCLInitInfo_s structure before calling this function. + * + * \param pInitInfo [in] pointer to a \ref PersAdminPCLInitInfo_s structure containing + * the supported callbacks + * \param flags [in] supported notification flags + * \param timeout [in] maximum time needed to process any supported request + * + * \return 0 for success, negative value for error (see \ref PERS_COM_ERROR_CODES_DEFINES) + */ +sint_t persIpcRegisterToPAS_DBus_high( PersAdminPCLInitInfo_s * pInitInfo, + uint_t flags, + uint_t timeout) +{ + sint_t retVal = PERS_COM_SUCCESS; + gboolean gbRetVal = false; + const gchar *gUniqueName = NIL; + gint outErrorCode; + GError *gError = NIL; + + + if(NIL == pInitInfo) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Invalid parameter in persIpcRegisterToPAS_DBus_high call.")); + return PERS_COM_ERR_INVALID_PARAM; + } + + if(NIL == pInitInfo->pReqCB) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Invalid parameter in persIpcRegisterToPAS_DBus_high call.")); + return PERS_COM_ERR_INVALID_PARAM; + } + + g_pPersIpcPCLInfo.pReqCB = pInitInfo->pReqCB; + + /* Init DBus connection */ + if(false == g_bPCLDBusConnInit) + { + retVal = persIpcInitPCL_DBus_high(); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("persIpcRegisterToPAS_DBus_high call failed with error code :"), + DLT_INT(retVal)); + return retVal; + } + } + + if(NIL == g_persIpcDBusPASProxy) + { + /* Get the PAS proxy object */ + g_persIpcDBusPASProxy = (OipPersistenceAdminProxy *)oip_persistence_admin_proxy_new_sync( g_pPCLDBusConnection, + G_DBUS_PROXY_FLAGS_NONE, + PERSISTENCE_ADMIN_BUS_NAME, + PERSISTENCE_ADMIN_OBJ_PATH, + NIL, + NIL); + if(NIL == g_persIpcDBusPASProxy) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersAdmin proxy creation failed.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + } + + gUniqueName = g_dbus_connection_get_unique_name(g_pPCLDBusConnection); + if(NIL == gUniqueName) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to obtain the unique DBus name.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_ERR_NO_CONNECTION */ + } + else + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG,DLT_STRING(LT_HDR), + DLT_STRING("Successfully obtained unique BusName :"), + DLT_STRING(gUniqueName)); + } + + /* Synchronous call to "RegisterPersAdminNotification" */ + gbRetVal = oip_persistence_admin_call_register_pers_admin_notification_sync((OipPersistenceAdmin *)g_persIpcDBusPASProxy, + gUniqueName, + PERSISTENCE_ADMIN_CONSUMER_OBJ_PATH, + (gint)flags, + (guint)timeout, + &outErrorCode, + NIL, + &gError); + if(false == gbRetVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus RegisterPersAdminNotification call failed with DBus error :"), + DLT_STRING(gError->message)); + g_error_free(gError); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG,DLT_STRING(LT_HDR), + DLT_STRING("DBus RegisterPersAdminNotification call returned output error code :"), + DLT_INT(outErrorCode)); + + retVal = outErrorCode; + + return retVal; +} + + +/** + * \brief Initialize PCL IPC DBus component + * + * \note : An additional thread is created for communication purposes. + * + * \return 0 for success, negative value for error (\ref PERS_COM_ERROR_CODES_DEFINES) + */ +static sint_t persIpcInitPCL_DBus_high() +{ + + sint_t retVal = PERS_COM_SUCCESS; + bool_t bRetVal; + + if(0 != pthread_mutex_init (&g_PCLDBusMainLoopThreadFlagMtx, NIL)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create mutex.")); + return PERS_COM_FAILURE; + } + + if(0 != pthread_cond_init (&g_PCLDBusMainLoopThreadFlagCV, NIL)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create thread cond.")); + (void)pthread_mutex_destroy(&g_PCLDBusMainLoopThreadFlagMtx); + return PERS_COM_FAILURE; + } + + g_PCLDBusMainLoopThreadFlag = 0; + + if(0 != pthread_create(&g_hPCLDBusThread, NIL, persIpcPCLLoopThread, NIL)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create thread.")); + (void)pthread_cond_destroy(&g_PCLDBusMainLoopThreadFlagCV); + (void)pthread_mutex_destroy(&g_PCLDBusMainLoopThreadFlagMtx); + return PERS_COM_FAILURE; + } + + /* Wait for DBus connection */ + if(0 != pthread_mutex_lock (&g_PCLDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + return PERS_COM_FAILURE; + } + while (!g_PCLDBusMainLoopThreadFlag) + { + pthread_cond_wait (&g_PCLDBusMainLoopThreadFlagCV, &g_PCLDBusMainLoopThreadFlagMtx); + } + (void)pthread_mutex_unlock (&g_PCLDBusMainLoopThreadFlagMtx); + + /* Check DBus connection status */ + if(false == g_bPCLDBusConnInit) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("PCL DBus connection setup failed.")); + (void)pthread_cond_destroy(&g_PCLDBusMainLoopThreadFlagCV); + (void)pthread_mutex_destroy(&g_PCLDBusMainLoopThreadFlagMtx); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + /* Export the org.genivi.persistence.adminconsumer interface over DBus */ + bRetVal = ExportPersistenceAdminConsumerIF(g_pPCLDBusConnection); + if(false == bRetVal) + { + /* Error: the interface could not be exported. */ + g_main_loop_quit(g_pPCLMainLoop); + } + else + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_INFO, DLT_STRING(LT_HDR), + DLT_STRING("Successfully connected to D-Bus and exported object.")); + } + + return retVal; +} + + +/** + * \brief Un-Register PCL client application from PAS over DBus + * \note : The additional thread created for communication purposes is stopped. + * + * \param flags [in] supported notification flags + * + * \return 0 for success, negative value for error (\ref PERS_COM_ERROR_CODES_DEFINES) + */ +sint_t persIpcUnRegisterFromPAS_DBus_high( uint_t flags) +{ + sint_t retVal = PERS_COM_SUCCESS; + gboolean gbRetVal = false; + const gchar *gUniqueName = NIL; + gint outErrorCode; + GError *gError = NIL; + + if(false == g_bPCLDBusConnInit) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus connection not initialized.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_ERR_NO_CONNECTION */ + } + + if(NIL == g_persIpcDBusPASProxy) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersAdmin proxy not available.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + gUniqueName = g_dbus_connection_get_unique_name(g_pPCLDBusConnection); + if(NIL == gUniqueName) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to obtain the unique DBus name.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_ERR_NO_CONNECTION */ + } + + /* Synchronous call to "UnRegisterPersAdminNotification" */ + gbRetVal = oip_persistence_admin_call_un_register_pers_admin_notification_sync( (OipPersistenceAdmin *)g_persIpcDBusPASProxy, + gUniqueName, + PERSISTENCE_ADMIN_CONSUMER_OBJ_PATH, + (gint)flags, + (guint)0, // deprecated + &outErrorCode, + NIL, + &gError); + if(false == gbRetVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus UnRegisterPersAdminNotification call failed with DBus error :"), + DLT_STRING(gError->message)); + g_error_free(gError); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG,DLT_STRING(LT_HDR), + DLT_STRING("DBus UnRegisterPersAdminNotification call returned output error code :"), + DLT_INT(outErrorCode)); + + retVal = outErrorCode; + + /* Quit DBus main loop */ + g_main_loop_quit(g_pPCLMainLoop); + + /* Wait for persIpcPCLLoopThread */ + pthread_join(g_hPCLDBusThread, NIL); + + /* Release any created proxy object */ + if(NIL != g_persIpcDBusPASProxy) + { + g_object_unref(g_persIpcDBusPASProxy); + g_persIpcDBusPASProxy = NIL; + } + + return retVal; +} + + +/** + * \brief Send 'request processed' confirmation to PAS over DBus + * \note : Send confirmation to PAS that the request specified by requestId has been processed. + * The status parameter should reflect this request and could also return an error. + * + * \param requestID [in] the ID of the processed request + * \param status [in] the status of the request processed by PCL + * - In case of success: bitfield using any of the following flags, depending on the request : ::PERSISTENCE_STATUS_LOCKED. + * - In case of error: the sum of ::PERSISTENCE_STATUS_ERROR and an error code \ref PERS_COM_IPC_DEFINES_ERROR is returned. + * + * \return 0 for success, negative value for error (see \ref PERS_COM_ERROR_CODES_DEFINES) + */ +sint_t persIpcSendConfirmationToPAS_DBus_high( sint_t requestID, + uint_t status) +{ + gboolean gbRetVal = false; + gint outErrorCode; + GError *gError = NIL; + + if(false == g_bPCLDBusConnInit) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus connection not initialized.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_ERR_NO_CONNECTION */ + } + + if(NIL == g_persIpcDBusPASProxy) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersAdmin proxy not available.")); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + /* Synchronous call to "PersistenceAdminRequestCompleted" */ + gbRetVal = oip_persistence_admin_call_persistence_admin_request_completed_sync( (OipPersistenceAdmin *)g_persIpcDBusPASProxy, + (guint)requestID, + (gint)status, + &outErrorCode, + NIL, + &gError); + if(false == gbRetVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersistenceAdminRequestCompleted call failed with DBus error :"), + DLT_STRING(gError->message)); + g_error_free(gError); + return PERS_COM_FAILURE; /* PERS_COM_IPC_DBUS_ERROR */ + } + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG,DLT_STRING(LT_HDR), + DLT_STRING("DBus PersistenceAdminRequestCompleted call returned output error code :"), + DLT_INT(outErrorCode)); + + return (sint_t)outErrorCode; +} + + +/** + * \brief Connection to DBus callback + * + * \note The function is called when a connection to the D-Bus could be established. + * According to the documentation the objects should be exported here. + * + * \param connection [in] Connection, which was acquired + * \param name [in] Bus name + * \param user_data [in] Optionally user data + * + * \return void + */ +static void OnBusAcquired_cb( GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + bool_t bRetVal; + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG,DLT_STRING(LT_HDR), + DLT_STRING("Successfully connected to DBus")); + + /* Store the connection. */ + g_pPASDBusConnection = connection; + + /* Export the org.genivi.persistence.admin interface over DBus */ + bRetVal = ExportPersistenceAdminIF(connection); + if(false == bRetVal) + { + /* Error: the interface could not be exported. */ + g_main_loop_quit(g_pPASMainLoop); + } + else + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_INFO, DLT_STRING(LT_HDR), + DLT_STRING("Successfully connected to D-Bus and exported object.")); + } +} + + +/** + * \brief DBus name obtained callback + * + * \note The function is called when the "bus name" could be acquired on the D-Bus. + * + * \param connection [in] Connection over which the bus name was acquired + * \param name [in] Acquired bus name + * \param user_data [in] Optionally user data + * + * \return void + */ +static void OnNameAcquired_cb( GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + DLT_LOG(persComIpcDLTCtx, DLT_LOG_INFO, DLT_STRING(LT_HDR), + DLT_STRING("Successfully obtained D-Bus name:"), DLT_STRING(name)); + + /* DBus connection initialized */ + g_bPASDBusConnInit = true; + + /* Notify that the DBus connection is ready */ + if(0 != pthread_mutex_lock (&g_PASDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + return; + } + g_PASDBusMainLoopThreadFlag = DBUS_MAIN_LOOP_THREAD_FLAG_SET; + (void)pthread_cond_signal (&g_PASDBusMainLoopThreadFlagCV); + (void)pthread_mutex_unlock (&g_PASDBusMainLoopThreadFlagMtx); +} + + +/** + * \brief DBus name lost callback + * + * \note The function is called if either no connection to D-Bus could be established or + * the bus name could not be acquired. + * + * \param connection [in] Connection. If it is NIL, no D-Bus connection could be established. + * Otherwise the bus name was lost. + * \param name [in] Bus name + * \param user_data [in] Optionally user data + * + * \return void + */ +static void OnNameLost_cb( GDBusConnection *connection, + const gchar *name, + gpointer user_data ) +{ + uint32_t clientIdx; + + if(NIL == connection) + { + /* Error: the connection could not be established. */ + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to establish D-Bus connection.")); + } + else + { + /* Error: connection established, but name not obtained. This might be a second instance of the application */ + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to obtain / Lost D-Bus name :"), + DLT_STRING(name)); + } + + /* DBus connection lost */ + g_bPASDBusConnInit = false; + + /* In both cases leave the main loop. */ + g_main_loop_quit(g_pPASMainLoop); + + /* Notify the DBus connection is not ready */ + if(0 != pthread_mutex_lock (&g_PASDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + return; + } + g_PASDBusMainLoopThreadFlag = DBUS_MAIN_LOOP_THREAD_FLAG_SET; + (void)pthread_cond_signal (&g_PASDBusMainLoopThreadFlagCV); + (void)pthread_mutex_unlock (&g_PASDBusMainLoopThreadFlagMtx); + + /* Acquire mutex on array of DBus client info */ + if(0 != pthread_mutex_lock(&g_persIpcDBusClientInfoArrayMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + } + else + { + for(clientIdx = 0; clientIdx < g_persIpcDBusClientInfoArraySize; clientIdx++) + { + if(NIL != g_persIpcDBusClientInfoArray[clientIdx]) + { + if(NIL != g_persIpcDBusClientInfoArray[clientIdx]->busName) + { + (void)free(g_persIpcDBusClientInfoArray[clientIdx]->busName); + } + if(NIL != g_persIpcDBusClientInfoArray[clientIdx]->objName) + { + (void)free(g_persIpcDBusClientInfoArray[clientIdx]->objName); + } + } + } + (void)pthread_mutex_unlock(&g_persIpcDBusClientInfoArrayMtx); + } +} + +/** + * \brief RegisterPersAdminNotification DBus method callback + * + * \note Handler for RegisterPersAdminNotification. + * Signature based on generated code. + */ +static gboolean OnHandleRegisterPersAdminNotification ( OipPersistenceAdmin *object, + GDBusMethodInvocation *invocation, + const gchar *arg_BusName, + const gchar *arg_ObjName, + gint arg_NotificationFlag, + guint arg_TimeoutMs) +{ + sint_t retVal = PERS_COM_SUCCESS; + uint32_t clientId; + + persIpcDBusClientInfo_s **tmpPersIpcDBusClientInfoArray = NIL; + persIpcDBusClientInfo_s *pNewClientInfo = NIL; + + if((NIL == arg_BusName) || (NIL == arg_ObjName)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Invalid parameter in RegisterPersAdminNotification handler.")); + retVal = PERS_COM_ERR_INVALID_PARAM; + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG, DLT_STRING(LT_HDR), + DLT_STRING("RegisterPersAdminNotification called for BusName :"), + DLT_STRING(arg_BusName), + DLT_STRING("and ObjName :"), + DLT_STRING(arg_ObjName), + DLT_STRING("with params : NotificationFlag="), + DLT_INT(arg_NotificationFlag), + DLT_STRING(" TimeoutMs="), + DLT_INT(arg_TimeoutMs)); + + /* Check if the client is already registered */ + retVal = persIpcGetIdForDBusInfo( (pstr_t)arg_BusName, + (pstr_t)arg_ObjName, + &clientId); + if(PERS_COM_SUCCESS == retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_WARN, DLT_STRING(LT_HDR), + DLT_STRING("DBus client already registered with BusName :"), + DLT_STRING(arg_BusName), + DLT_STRING("and ObjName :"), + DLT_STRING(arg_ObjName)); + retVal = PERS_COM_FAILURE; /* PERS_COM_IPC_ERR_ALREADY_DONE */ + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + + /* Acquire mutex on array of DBus client info */ + if(0 != pthread_mutex_lock (&g_persIpcDBusClientInfoArrayMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + retVal = PERS_COM_FAILURE; + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + + /* Add DBus info for the new client */ + if(g_persIpcDBusClientInfoArraySize >= g_persIpcDBusClientInfoMaxArraySize) + { + if(g_persIpcDBusClientInfoArraySize > 0) + { + tmpPersIpcDBusClientInfoArray = g_persIpcDBusClientInfoArray; + + g_persIpcDBusClientInfoMaxArraySize *= 2; + } + else + { + g_persIpcDBusClientInfoMaxArraySize = PERS_IPC_INIT_DBUS_INFO_ARRAY_SIZE; + } + + g_persIpcDBusClientInfoArray = (persIpcDBusClientInfo_s**)malloc(g_persIpcDBusClientInfoMaxArraySize * sizeof(*g_persIpcDBusClientInfoArray)); + if(NIL == g_persIpcDBusClientInfoArray) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Error allocating memory for client info mapping list.")); + g_persIpcDBusClientInfoArray = tmpPersIpcDBusClientInfoArray; + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + retVal = PERS_COM_ERR_MALLOC; + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + else + { + (void)memset(g_persIpcDBusClientInfoArray, 0, g_persIpcDBusClientInfoMaxArraySize * sizeof(*g_persIpcDBusClientInfoArray)); + } + + if(g_persIpcDBusClientInfoArraySize > 0) + { + (void)memcpy(g_persIpcDBusClientInfoArray, tmpPersIpcDBusClientInfoArray, g_persIpcDBusClientInfoArraySize * sizeof(*g_persIpcDBusClientInfoArray)); + } + } + + pNewClientInfo = NIL; + pNewClientInfo = (persIpcDBusClientInfo_s*)malloc(sizeof(*pNewClientInfo)); + if(NIL == pNewClientInfo) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Error allocating memory for client info.")); + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + retVal = PERS_COM_ERR_MALLOC; + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + else + { + (void)memset(pNewClientInfo, 0, sizeof(*pNewClientInfo)); + } + + /* received Bus Name should be a null terminated string */ + pNewClientInfo->busName = (pstr_t)malloc((strlen(arg_BusName) + 1) * sizeof(*(pNewClientInfo->busName))); + if(NIL == pNewClientInfo->busName) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Error allocating memory for client info data (busName).")); + (void)free(pNewClientInfo); + pNewClientInfo = NIL; + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + retVal = PERS_COM_ERR_MALLOC; + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + else + { + (void)memset(pNewClientInfo->busName, 0, (strlen(arg_BusName) + 1) * sizeof(*(pNewClientInfo->busName))); + (void)memcpy(pNewClientInfo->busName, arg_BusName, (strlen(arg_BusName) * sizeof(*(pNewClientInfo->busName)))); + } + + // received object name should be a null terminated string + pNewClientInfo->objName = (pstr_t)malloc((strlen(arg_ObjName) + 1) * sizeof(*(pNewClientInfo->objName)));/*DG C8MR2R-MISRA-C:2004 Rule 20.4-SSW_Administrator_0002*/ + if(NIL == pNewClientInfo->objName) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Error allocating memory for client info data (objName).")); + (void)free(pNewClientInfo->busName); + (void)free(pNewClientInfo); + pNewClientInfo = NIL; + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + retVal = PERS_COM_ERR_MALLOC; + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + else + { + (void)memset(pNewClientInfo->objName, 0, (strlen(arg_ObjName) + 1) * sizeof(*(pNewClientInfo->objName))); + (void)memcpy(pNewClientInfo->objName, arg_ObjName, (strlen(arg_ObjName) * sizeof(*(pNewClientInfo->objName)))); + } + + g_persIpcDBusClientInfoArray[g_persIpcDBusClientInfoArraySize++] = pNewClientInfo; + + clientId = g_persIpcDBusClientInfoArraySize - 1; + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG, DLT_STRING(LT_HDR), + DLT_STRING("ClientId :"), + DLT_UINT32(clientId), + DLT_STRING("for BusName :"), + DLT_STRING(arg_BusName), + DLT_STRING("and ObjName :"), + DLT_STRING(arg_ObjName)); + + /* Release array mutex */ + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + + /* Forward the call to the PAS callback */ + retVal = g_pPersIpcPASInfo.pRegCB( clientId, /* clientId is the array index */ + arg_NotificationFlag, + arg_TimeoutMs); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR, DLT_STRING(LT_HDR), + DLT_STRING("RegisterPersAdminNotification client callback failed with error code :"), + DLT_INT(retVal)); + + /* + * remove the registered client if the PAS callback returned an error, + * and forward the error to the PCL client + */ + + if(0 != pthread_mutex_lock (&g_persIpcDBusClientInfoArrayMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + }else + { + (void)free(g_persIpcDBusClientInfoArray[clientId]->busName); + (void)free(g_persIpcDBusClientInfoArray[clientId]->objName); + (void)free(g_persIpcDBusClientInfoArray[clientId]); + g_persIpcDBusClientInfoArray[clientId] = NIL; + --g_persIpcDBusClientInfoArraySize; + + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + } + } + + oip_persistence_admin_complete_register_pers_admin_notification( object, + invocation, + (gint)retVal); + + return(TRUE); +} + + +/** + * \brief UnregisterPersAdminNotification DBus method callback + * + * \note Handler for UnregisterPersAdminNotification. + * Signature based on generated code. + */ +static gboolean OnHandleUnregisterPersAdminNotification(OipPersistenceAdmin *object, + GDBusMethodInvocation *invocation, + const gchar *arg_BusName, + const gchar *arg_ObjName, + gint arg_NotificationFlag, + guint arg_TimeoutMs) /* currently not used */ +{ + sint_t retVal = PERS_COM_SUCCESS; + uint32_t clientId; + + if((NIL == arg_BusName) || (NIL == arg_ObjName)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Invalid parameter in UnregisterPersAdminNotification handler.")); + retVal = PERS_COM_ERR_INVALID_PARAM; + oip_persistence_admin_complete_un_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG, DLT_STRING(LT_HDR), + DLT_STRING("UnregisterPersAdminNotification called for BusName :"), + DLT_STRING(arg_BusName), + DLT_STRING("and ObjName :"), + DLT_STRING(arg_ObjName), + DLT_STRING("with params : NotificationFlag="), + DLT_INT(arg_NotificationFlag), + DLT_STRING(" TimeoutMs="), + DLT_INT(arg_TimeoutMs)); + + /* Check if client is registered */ + retVal = persIpcGetIdForDBusInfo( (pstr_t)arg_BusName, + (pstr_t)arg_ObjName, + &clientId); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_WARN, DLT_STRING(LT_HDR), + DLT_STRING("DBus client not registered. BusName :"), + DLT_STRING(arg_BusName), + DLT_STRING(" and ObjName :"), + DLT_STRING(arg_ObjName)); + retVal = PERS_COM_ERR_NOT_FOUND; + oip_persistence_admin_complete_un_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); + } + + /* Forward the call to the PAS callback */ + retVal = g_pPersIpcPASInfo.pUnRegCB(clientId, /* clientId is the array index */ + arg_NotificationFlag); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR, DLT_STRING(LT_HDR), + DLT_STRING("UnregisterPersAdminNotification client callback failed with error code :"), + DLT_INT(retVal)); + } + else + { + /* remove the registered client if the PAS callback returned success */ + if(0 != pthread_mutex_lock (&g_persIpcDBusClientInfoArrayMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + } + else + { + (void)free(g_persIpcDBusClientInfoArray[clientId]->busName); + (void)free(g_persIpcDBusClientInfoArray[clientId]->objName); + (void)free(g_persIpcDBusClientInfoArray[clientId]); + g_persIpcDBusClientInfoArray[clientId] = NIL; + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + } + } + + oip_persistence_admin_complete_un_register_pers_admin_notification( object, + invocation, + (gint)retVal); + return(TRUE); +} + + +/** + * \brief PersAdminRequestCompleted DBus method callback + * + * \note Handler for PersistenceAdminRequestCompleted. + * Signature based on generated code. + */ +static gboolean OnHandlePersAdminRequestCompleted( OipPersistenceAdmin *object, + GDBusMethodInvocation *invocation, + guint arg_RequestId, + gint arg_StatusFlag) +{ + sint_t retVal = PERS_COM_SUCCESS; + const gchar * senderBusName = NIL; + uint32_t clientId; + + /* Get the sender BusName */ + senderBusName = g_dbus_method_invocation_get_sender(invocation); + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG, DLT_STRING(LT_HDR), + DLT_STRING("PersistenceAdminRequestCompleted called by "), + DLT_STRING(senderBusName), + DLT_STRING("with params : RequestId="), + DLT_UINT32(arg_RequestId), + DLT_STRING("and StatusFlag="), + DLT_INT(arg_StatusFlag)); + + retVal = persIpcGetIdForDBusInfo( (pstr_t)senderBusName, + NIL, + &clientId); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("DBus client not registered. BusName :"), + DLT_STRING(senderBusName)); + retVal = PERS_COM_ERR_NOT_FOUND; + oip_persistence_admin_complete_persistence_admin_request_completed( object, + invocation, + (gint)retVal); + return (TRUE); + } + + /* Forward the call to the PAS callback */ + retVal = g_pPersIpcPASInfo.pReqCompleteCB( clientId, + arg_RequestId, + arg_StatusFlag); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("PersistenceAdminRequestCompleted client callback failed with error code :"), + DLT_INT(retVal)); + } + + oip_persistence_admin_complete_persistence_admin_request_completed( object, + invocation, + (gint)retVal); + + return (TRUE); +} + + +/** + * \brief PersAdminRequest DBus method callback + * + * \note Handler for PersistenceAdminRequest. + * Signature based on generated code. + */ +static gboolean OnHandlePersAdminRequest( OipPersistenceAdminconsumer *object, + GDBusMethodInvocation *invocation, + guint arg_RequestId, + gint arg_StatusFlag ) +{ + sint_t retVal = PERS_COM_SUCCESS; + + DLT_LOG(persComIpcDLTCtx, DLT_LOG_DEBUG, DLT_STRING(LT_HDR), + DLT_STRING("PersistenceAdminRequest called with params : RequestId="), + DLT_UINT(arg_RequestId), + DLT_STRING("and StatusFlag="), + DLT_INT(arg_StatusFlag)); + + /* Forward the call to the PCL callback */ + retVal = g_pPersIpcPCLInfo.pReqCB( arg_RequestId, + arg_StatusFlag ); + if(PERS_COM_SUCCESS != retVal) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("PersistenceAdminRequest client callback failed with error code :"), + DLT_INT(retVal)); + } + + oip_persistence_adminconsumer_complete_persistence_admin_request( object, + invocation, + (gint)retVal); + + return (TRUE); +} + + +/** + * \brief Function that exports the org.genivi.persistence.admin interface over DBus + * + * \param connection: Connection over which the interface should be exported + * + * \return true if successful, false otherwise + */ +static bool_t ExportPersistenceAdminIF(GDBusConnection *connection) +{ + GError *pError = NIL; + + /* Create object to offer on the DBus */ + g_persIpcDBusPASSkeleton = NIL; + g_persIpcDBusPASSkeleton = (OipPersistenceAdminSkeleton*) oip_persistence_admin_skeleton_new(); + if(NIL == g_persIpcDBusPASSkeleton) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create PersistenceAdmin object.")); + return false; + } + + (void)g_signal_connect(g_persIpcDBusPASSkeleton, "handle-register-pers-admin-notification", G_CALLBACK(&OnHandleRegisterPersAdminNotification), NIL); + (void)g_signal_connect(g_persIpcDBusPASSkeleton, "handle-un-register-pers-admin-notification", G_CALLBACK(&OnHandleUnregisterPersAdminNotification), NIL); + (void)g_signal_connect(g_persIpcDBusPASSkeleton, "handle-persistence-admin-request-completed", G_CALLBACK(&OnHandlePersAdminRequestCompleted), NIL); + + + /* Attach interfaces to the objects and export them */ + if(FALSE == g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(g_persIpcDBusPASSkeleton), + connection, + PERSISTENCE_ADMIN_OBJ_PATH, + &pError)) + { + /* Error: PersistenceAdmin interface could not be exported. */ + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR, DLT_STRING(LT_HDR), + DLT_STRING("Failed to export PersistenceAdmin interface. Error :"), + DLT_STRING(pError->message)); + g_error_free(pError); + g_object_unref(g_persIpcDBusPASSkeleton); + g_persIpcDBusPASSkeleton = NIL; + return false; + } + + return true; +} + + +/** + * \brief Function that exports the org.genivi.persistence.adminconsumer interface over DBus + * + * \param connection: Connection over which the interface should be exported + * + * \return true if successful, false otherwise + */ +static bool_t ExportPersistenceAdminConsumerIF(GDBusConnection *connection) +{ + GError *pError = NIL; + + /* Create object to offer on the DBus */ + g_persIpcDBusPCLSkeleton = NIL; + g_persIpcDBusPCLSkeleton = (OipPersistenceAdminconsumerSkeleton*)oip_persistence_adminconsumer_skeleton_new(); + if(NIL == g_persIpcDBusPCLSkeleton) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create PersistenceAdminConsumer object.")); + return false; + } + + (void)g_signal_connect(g_persIpcDBusPCLSkeleton, "handle-persistence-admin-request", G_CALLBACK(&OnHandlePersAdminRequest), NIL); + + /* Attach interfaces to the objects and export them */ + if(FALSE == g_dbus_interface_skeleton_export( G_DBUS_INTERFACE_SKELETON(g_persIpcDBusPCLSkeleton), + connection, + PERSISTENCE_ADMIN_CONSUMER_OBJ_PATH, + &pError)) + { + /* Error: PersistenceAdminConsumer interface could not be exported. */ + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR, DLT_STRING(LT_HDR), + DLT_STRING("Failed to export PersistenceAdminConsumer interface. Error :"), + DLT_STRING(pError->message)); + g_error_free(pError); + g_object_unref(g_persIpcDBusPCLSkeleton); + g_persIpcDBusPCLSkeleton = NIL; + return false; + } + return true; +} + + +/* PAS DBus loop thread */ +static void* persIpcPASLoopThread(void *lpParam) +{ + uint32_t u32ConnectionId = 0; + + /* Initialize glib */ + g_type_init(); /* deprecated. Since GLib 2.36, the type system is initialized automatically and this function does nothing.*/ + + /* Create the main loop */ + g_pPASMainLoop = g_main_loop_new(NIL, FALSE); + if(NIL == g_pPASMainLoop) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to create DBus main loop.")); + + /* Notify that the DBus connection is not ready */ + if(0 != pthread_mutex_lock (&g_PASDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + } + else + { + g_PASDBusMainLoopThreadFlag = DBUS_MAIN_LOOP_THREAD_FLAG_SET; + (void)pthread_cond_signal (&g_PASDBusMainLoopThreadFlagCV); + (void)pthread_mutex_unlock (&g_PASDBusMainLoopThreadFlagMtx); + } + return NIL; + } + + /* Connect to the D-Bus. Obtain a bus name to offer PAS objects */ + u32ConnectionId = g_bus_own_name( PERSISTENCE_ADMIN_BUS_TYPE + , PERSISTENCE_ADMIN_BUS_NAME + , G_BUS_NAME_OWNER_FLAGS_NONE + , &OnBusAcquired_cb + , &OnNameAcquired_cb + , &OnNameLost_cb + , NIL + , NIL); + + /* The main loop is only canceled if the Node is completely shut down or the D-Bus connection fails */ + g_main_loop_run(g_pPASMainLoop); + + /* If the main loop returned, clean up. Release bus name and main loop */ + g_bus_unown_name(u32ConnectionId); + g_main_loop_unref(g_pPASMainLoop); + g_pPASMainLoop = NIL; + + /* Release the skeleton object */ + if(NIL != g_persIpcDBusPASSkeleton) + { + g_object_unref(g_persIpcDBusPASSkeleton); + g_persIpcDBusPASSkeleton = NIL; + } + + return NIL; +} + + +/* PCL DBus loop thread */ +static void* persIpcPCLLoopThread(void *lpParam) +{ + GError *pGError = NIL; + + /* Initialize glib */ + g_type_init(); /* deprecated. Since GLib 2.36, the type system is initialized automatically and this function does nothing.*/ + + /* Create the main loop */ + g_pPCLMainLoop = g_main_loop_new(NIL, FALSE); + + /* Connect to D-Bus */ + g_pPCLDBusConnection = g_bus_get_sync( PERSISTENCE_ADMIN_BUS_TYPE, + NULL, + &pGError); + + if(NIL == g_pPCLDBusConnection) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to obtain a DBus connection. Error :"), + DLT_STRING(pGError->message)); + g_error_free(pGError); + g_main_loop_unref(g_pPCLMainLoop); + if(0 != pthread_mutex_lock (&g_PCLDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + } + else + { + g_PCLDBusMainLoopThreadFlag = DBUS_MAIN_LOOP_THREAD_FLAG_SET; + (void)pthread_cond_signal (&g_PCLDBusMainLoopThreadFlagCV); + (void)pthread_mutex_unlock (&g_PCLDBusMainLoopThreadFlagMtx); + } + return NIL; + } + + + /* DBus connection initialized */ + g_bPCLDBusConnInit = true; + + /* Notify the DBus connection is ready (or not available) */ + if(0 != pthread_mutex_lock (&g_PCLDBusMainLoopThreadFlagMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + } + g_PCLDBusMainLoopThreadFlag = DBUS_MAIN_LOOP_THREAD_FLAG_SET; + (void)pthread_cond_signal (&g_PCLDBusMainLoopThreadFlagCV); + (void)pthread_mutex_unlock (&g_PCLDBusMainLoopThreadFlagMtx); + + g_main_loop_run(g_pPCLMainLoop); + + g_bPCLDBusConnInit = false; + + /* If the main loop returned, clean up */ + g_main_loop_unref(g_pPCLMainLoop); + + /* Release the skeleton object */ + if(NIL != g_persIpcDBusPCLSkeleton) + { + g_object_unref(g_persIpcDBusPCLSkeleton); + g_persIpcDBusPCLSkeleton = NIL; + } + + /* Release any created proxy object */ + if(NIL != g_persIpcDBusPASProxy) + { + g_object_unref(g_persIpcDBusPASProxy); + g_persIpcDBusPASProxy = NIL; + } + + return NIL; +} + + +/* Get DBus client ID */ +static sint_t persIpcGetIdForDBusInfo(const pstr_t busName, + const pstr_t objName, + uint32_t *clientID) +{ + uint32_t clientIdx; + + if((NIL == busName) || (NIL == clientID)) + { + return PERS_COM_ERR_INVALID_PARAM; + } + + /* Acquire mutex on array of DBus client info */ + if(0 != pthread_mutex_lock (&g_persIpcDBusClientInfoArrayMtx)) + { + DLT_LOG(persComIpcDLTCtx, DLT_LOG_ERROR,DLT_STRING(LT_HDR), + DLT_STRING("Failed to lock mutex.")); + return PERS_COM_FAILURE; + } + + /* Check if client already registered */ + for(clientIdx = 0; clientIdx < g_persIpcDBusClientInfoArraySize; ++clientIdx) + { + if(NIL != g_persIpcDBusClientInfoArray[clientIdx]) + { + if(0 == strcmp(busName, g_persIpcDBusClientInfoArray[clientIdx]->busName)) + { + if(NIL != objName) + { + if(0 == strcmp(objName, g_persIpcDBusClientInfoArray[clientIdx]->objName)) + { + (*clientID) = clientIdx; + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_SUCCESS; + } + } + else + { + (*clientID) = clientIdx; + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + return PERS_COM_SUCCESS; + } + } + } + } + + /* Release array mutex */ + (void)pthread_mutex_unlock (&g_persIpcDBusClientInfoArrayMtx); + + return PERS_COM_ERR_NOT_FOUND; +} |