1 /******************************************************************************
4 * Company XS Embedded GmbH
5 *****************************************************************************/
6 /******************************************************************************
7 * This Source Code Form is subject to the terms of the
8 * Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed
9 * with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 ******************************************************************************/
12 * @file persistence_client_library_dbus_service.c
13 * @ingroup Persistence client library
14 * @author Ingo Huerner
15 * @brief Implementation of the persistence client library dbus service.
20 #include "persistence_client_library_dbus_service.h"
21 #include "persistence_client_library_lc_interface.h"
22 #include "persistence_client_library_pas_interface.h"
23 #include "persistence_client_library_dbus_cmd.h"
24 #include "persistence_client_library_data_organization.h"
34 pthread_cond_t gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
35 pthread_mutex_t gDbusInitializedMtx = PTHREAD_MUTEX_INITIALIZER;
37 pthread_mutex_t gDbusPendingRegMtx = PTHREAD_MUTEX_INITIALIZER;
40 pthread_mutex_t gDeliverpMtx = PTHREAD_MUTEX_INITIALIZER;
42 pthread_mutex_t gMainCondMtx = PTHREAD_MUTEX_INITIALIZER;
43 pthread_cond_t gMainLoopCond = PTHREAD_COND_INITIALIZER;
45 pthread_t gMainLoopThread;
48 const char* gDbusLcConsDest = "org.genivi.NodeStateManager";
50 const char* gDbusLcConsterface = "org.genivi.NodeStateManager.LifeCycleConsumer";
51 const char* gDbusLcConsPath = "/org/genivi/NodeStateManager/LifeCycleConsumer";
52 const char* gDbusLcInterface = "org.genivi.NodeStateManager.Consumer";
53 const char* gDbusLcCons = "/org/genivi/NodeStateManager/Consumer";
54 const char* gDbusLcConsMsg = "LifecycleRequest";
56 const char* gDbusPersAdminConsInterface = "org.genivi.persistence.adminconsumer";
57 const char* gPersAdminConsumerPath = "/org/genivi/persistence/adminconsumer";
58 const char* gDbusPersAdminPath = "/org/genivi/persistence/admin";
59 const char* gDbusPersAdminInterface = "org.genivi.persistence.admin";
60 const char* gDbusPersAdminConsMsg = "PersistenceAdminRequest";
62 /// communication channel into the dbus mainloop
63 static int gPipeFd[2] = {0};
66 typedef enum EDBusObjectType
76 typedef struct SObjectEntry
78 tDBusObjectType objtype; /// libdbus' object
81 DBusWatch * watch; /// watch "object"
82 DBusTimeout * timeout; /// timeout "object"
89 typedef struct SPollInfo
91 int nfds; /// number of polls
92 struct pollfd fds[10]; /// poll file descriptors array
93 tObjectEntry objects[10]; /// poll object
97 /// polling information
98 static tPollInfo gPollInfo; /// polling information
100 int bContinue = 0; /// indicator if dbus mainloop shall continue
102 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
105 /* function to unregister ojbect path message handler */
106 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
110 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("unregisterObjectPath\n"));
113 /* catches messages not directed to any registered object path ("garbage collector") */
114 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
116 DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
119 // org.genivi.persistence.admin S I G N A L
120 if((0==strcmp(gDbusPersAdminInterface, dbus_message_get_interface(message))))
122 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
124 if((0==strcmp("PersistenceModeChanged", dbus_message_get_member(message))))
126 // to do handle signal
127 result = signal_persModeChange(connection, message);
131 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback - unknown signal:"), DLT_STRING(dbus_message_get_interface(message)) );
135 // org.genivi.persistence.admin S I G N A L
136 else if((0==strcmp(gDbusPersAdminConsInterface, dbus_message_get_interface(message))))
138 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
140 pclNotification_s notifyStruct;
141 int validMessage = 0;
143 if((0==strcmp("PersistenceResChange", dbus_message_get_member(message))))
145 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_changed;
148 else if((0==strcmp("PersistenceResDelete", dbus_message_get_member(message))))
150 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_deleted;
153 else if((0==strcmp("PersistenceRes", dbus_message_get_member(message))))
155 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_created;
159 if(validMessage == 1)
163 dbus_error_init (&error);
168 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, ¬ifyStruct.resource_id,
169 DBUS_TYPE_STRING, &ldbid,
170 DBUS_TYPE_STRING, &user_no,
171 DBUS_TYPE_STRING, &seat_no,
174 reply = dbus_message_new_error(message, error.name, error.message);
178 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback - DBus No memory"), DLT_STRING(dbus_message_get_interface(message)) );
181 if (!dbus_connection_send(connection, reply, 0))
183 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback - DBus No memory"), DLT_STRING(dbus_message_get_interface(message)) );
186 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;;
187 dbus_message_unref(reply);
191 notifyStruct.ldbid = atoi(ldbid);
192 notifyStruct.user_no = atoi(user_no);
193 notifyStruct.seat_no = atoi(seat_no);
195 // call the registered callback function
196 if(gChangeNotifyCallback != NULL )
198 gChangeNotifyCallback(¬ifyStruct);
202 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback - gChangeNotifyCallback is not set (possibly NULL)") );
204 result = DBUS_HANDLER_RESULT_HANDLED;
206 dbus_connection_flush(connection);
210 // org.genivi.persistence.admin P R O P E R T Y
211 else if((0==strcmp("org.freedesktop.DBus.Properties", dbus_message_get_interface(message))))
213 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
215 if((0==strcmp("EggDBusChanged", dbus_message_get_member(message))))
217 DBusMessageIter array;
218 DBusMessageIter dict;
219 DBusMessageIter variant;
221 char* dictString = NULL;
224 dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, 0, &dict);
225 dbus_message_iter_get_basic(&dict, &dictString);
227 dbus_message_iter_open_container(&dict,DBUS_TYPE_VARIANT, NULL, &variant);
228 dbus_message_iter_get_basic(&dict, &value);
230 dbus_message_iter_close_container(&dict, &variant);
231 dbus_message_iter_close_container(&array, &dict);
233 // to do handle signal
234 result = DBUS_HANDLER_RESULT_HANDLED;
238 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback - unknown property:"), DLT_STRING(dbus_message_get_interface(message)) );
243 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback - not a signal:"), DLT_STRING(dbus_message_get_member(message)) );
251 static void unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
255 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("unregisterObjectPathFallback\n"));
260 void* run_mainloop(void* dataPtr)
262 // persistence admin message
263 static const struct DBusObjectPathVTable vtablePersAdmin
264 = {unregisterMessageHandler, checkPersAdminMsg, NULL, NULL, NULL, NULL};
267 static const struct DBusObjectPathVTable vtableLifecycle
268 = {unregisterMessageHandler, checkLifecycleMsg, NULL, NULL, NULL, NULL};
271 static const struct DBusObjectPathVTable vtableFallback
272 = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, NULL, NULL, NULL};
275 mainLoop(vtablePersAdmin, vtableLifecycle, vtableFallback, dataPtr);
282 int setup_dbus_mainloop(void)
286 DBusConnection* conn = NULL;
288 const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
290 dbus_error_init(&err);
292 // wait until dbus main loop has been setup and running
293 pthread_mutex_lock(&gDbusInitializedMtx);
295 // Connect to the bus and check for errors
298 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("setup_dbus_mainloop - Use specific dbus address:"), DLT_STRING(pAddress) );
300 conn = dbus_connection_open_private(pAddress, &err);
304 if(!dbus_bus_register(conn, &err))
306 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("dbus_bus_register() :"), DLT_STRING(err.message) );
307 dbus_error_free (&err);
308 pthread_mutex_unlock(&gDbusInitializedMtx);
314 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("dbus_connection_open_private() :"), DLT_STRING(err.message) );
315 dbus_error_free(&err);
316 pthread_mutex_unlock(&gDbusInitializedMtx);
322 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("Use default dbus bus (DBUS_BUS_SYSTEM)"));
324 conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
327 // create here the dbus connection and pass to main loop
328 rval = pthread_create(&gMainLoopThread, NULL, run_mainloop, conn);
331 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("pthread_create( DBUS run_mainloop ) returned an error:"), DLT_INT(rval) );
332 pthread_mutex_unlock(&gDbusInitializedMtx);
336 (void)pthread_setname_np(gMainLoopThread, "pclDbusLoop");
338 // wait for condition variable
339 pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
341 pthread_mutex_unlock(&gDbusInitializedMtx);
350 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
352 dbus_bool_t result = FALSE;
355 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
357 int flags = dbus_watch_get_flags(watch);
359 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
360 pEntry->objtype = OT_WATCH;
361 pEntry->watch = watch;
363 gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
365 if (TRUE==dbus_watch_get_enabled(watch))
367 if (flags&DBUS_WATCH_READABLE)
369 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
371 if (flags&DBUS_WATCH_WRITABLE)
373 gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
387 static void removeWatch(DBusWatch *watch, void *data)
389 void* w_data = dbus_watch_get_data(watch);
393 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("removeWatch called "), DLT_INT( (int)watch) );
398 dbus_watch_set_data(watch, NULL, NULL);
403 static void watchToggled(DBusWatch *watch, void *data)
406 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("watchToggled called "), DLT_INT( (int)watch) );
408 if(dbus_watch_get_enabled(watch))
409 addWatch(watch, data);
411 removeWatch(watch, data);
416 static dbus_bool_t addTimeout(DBusTimeout *timeout, void *data)
419 dbus_bool_t ret = FALSE;
421 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
423 const int interval = dbus_timeout_get_interval(timeout);
424 if ((0<interval)&&(TRUE==dbus_timeout_get_enabled(timeout)))
426 const int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
429 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
430 if (-1!=timerfd_settime(tfd, 0, &its, NULL))
432 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
433 pEntry->objtype = OT_TIMEOUT;
434 pEntry->timeout = timeout;
435 gPollInfo.fds[gPollInfo.nfds].fd = tfd;
436 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
442 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout - timerfd_settime() failed"), DLT_STRING(strerror(errno)) );
447 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout - timerfd_create() failed"), DLT_STRING(strerror(errno)) );
453 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout - cannot create another fd to be poll()'ed"));
460 static void removeTimeout(DBusTimeout *timeout, void *data)
462 int i = gPollInfo.nfds;
465 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
469 if (-1==close(gPollInfo.fds[i].fd))
471 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("removeTimeout - close() timerfd"), DLT_STRING(strerror(errno)) );
475 while (gPollInfo.nfds>i)
477 gPollInfo.fds[i] = gPollInfo.fds[i+1];
478 gPollInfo.objects[i] = gPollInfo.objects[i+1];
482 gPollInfo.fds[gPollInfo.nfds].fd = -1;
483 gPollInfo.objects[gPollInfo.nfds].objtype = OT_NONE;
489 /** callback for libdbus' when timeout changed */
490 static void timeoutToggled(DBusTimeout *timeout, void *data)
492 int i = gPollInfo.nfds;
495 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
496 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("timeoutToggled") );
499 const int interval = (TRUE==dbus_timeout_get_enabled(timeout))?dbus_timeout_get_interval(timeout):0;
500 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
501 if (-1!=timerfd_settime(gPollInfo.fds[i].fd, 0, &its, NULL))
503 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("timeoutToggled - timerfd_settime()"), DLT_STRING(strerror(errno)) );
510 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
511 DBusObjectPathVTable vtableFallback, void* userData)
514 // lock mutex to make sure dbus main loop is running
515 pthread_mutex_lock(&gDbusInitializedMtx);
517 DBusConnection* conn = (DBusConnection*)userData;
518 dbus_error_init(&err);
520 if (dbus_error_is_set(&err))
522 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - Connection Error:"), DLT_STRING(err.message) );
523 dbus_error_free(&err);
525 else if (NULL != conn)
527 dbus_connection_set_exit_on_disconnect(conn, FALSE);
528 //if (-1 == (gEfds = eventfd(0, 0)))
529 if (-1 == (pipe(gPipeFd)))
531 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - eventfd() failed w/ errno:"), DLT_INT(errno) );
536 memset(&gPollInfo, 0 , sizeof(gPollInfo));
539 gPollInfo.fds[0].fd = gPipeFd[0];
540 gPollInfo.fds[0].events = POLLIN;
542 dbus_bus_add_match(conn, "type='signal',interface='org.genivi.persistence.admin',member='PersistenceModeChanged',path='/org/genivi/persistence/admin'", &err);
544 // register for messages
545 if ( (TRUE==dbus_connection_register_object_path(conn, gDbusLcConsPath, &vtable2, userData))
546 #if USE_PASINTERFACE == 1
547 && (TRUE==dbus_connection_register_object_path(conn, gPersAdminConsumerPath, &vtable, userData))
549 && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
551 if( (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
552 || (TRUE!=dbus_connection_set_timeout_functions(conn, addTimeout, removeTimeout, timeoutToggled, NULL, NULL)) )
554 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - dbus_connection_set_watch_functions() failed"));
558 pthread_cond_signal(&gDbusInitializedCond);
559 pthread_mutex_unlock(&gDbusInitializedMtx);
562 bContinue = 0; /* assume error */
564 while(DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
566 while ((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, -1)))&&(EINTR==errno));
570 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - poll() failed w/ errno "), DLT_INT(errno) );
581 for (i=0; gPollInfo.nfds>i && !bQuit; ++i)
584 if (0!=gPollInfo.fds[i].revents)
586 if (OT_TIMEOUT==gPollInfo.objects[i].objtype)
588 /* time-out occured */
589 unsigned long long nExpCount = 0;
591 if ((ssize_t)sizeof(nExpCount)!=read(gPollInfo.fds[i].fd, &nExpCount, sizeof(nExpCount)))
593 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - read failed"));
595 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - timeout"));
597 if (FALSE==dbus_timeout_handle(gPollInfo.objects[i].timeout))
599 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - dbus_timeout_handle() failed!?"));
603 else if (gPollInfo.fds[i].fd == gPipeFd[0])
606 /* internal command */
607 if (0!=(gPollInfo.fds[i].revents & POLLIN))
609 MainLoopData_u readData;
611 while ((-1==(ret = read(gPollInfo.fds[i].fd, readData.payload, 128)))&&(EINTR == errno));
614 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - read() failed"), DLT_STRING(strerror(errno)) );
618 pthread_mutex_lock(&gMainCondMtx);
619 //printf("--- *** --- Receive => mainloop => cmd: %d | string: %s | size: %d\n\n", readData.message.cmd, readData.message.string, ret);
620 DLT_LOG(gPclDLTContext, DLT_LOG_INFO, DLT_STRING("mainLoop - receive cmd:"), DLT_INT(readData.message.cmd));
621 switch (readData.message.cmd)
623 case CMD_PAS_BLOCK_AND_WRITE_BACK:
624 process_block_and_write_data_back(readData.message.params[1] /*requestID*/, readData.message.params[0] /*status*/);
625 process_send_pas_request(conn, readData.message.params[1] /*request*/, readData.message.params[0] /*status*/);
627 case CMD_LC_PREPARE_SHUTDOWN:
628 process_prepare_shutdown(Shutdown_Full);
629 process_send_lifecycle_request(conn, readData.message.params[1] /*requestID*/, readData.message.params[0] /*status*/);
631 case CMD_SEND_NOTIFY_SIGNAL:
632 process_send_notification_signal(conn, readData.message.params[0] /*ldbid*/, readData.message.params[1], /*user*/
633 readData.message.params[2] /*seat*/, readData.message.params[3], /*reason*/
634 readData.message.string);
636 case CMD_REG_NOTIFY_SIGNAL:
637 process_reg_notification_signal(conn, readData.message.params[0] /*ldbid*/, readData.message.params[1], /*user*/
638 readData.message.params[2] /*seat*/, readData.message.params[3], /*,policy*/
639 readData.message.string);
641 case CMD_SEND_PAS_REGISTER:
642 process_send_pas_register(conn, readData.message.params[0] /*regType*/, readData.message.params[1] /*notifyFlag*/);
644 case CMD_SEND_LC_REGISTER:
645 process_send_lifecycle_register(conn, readData.message.params[0] /*regType*/, readData.message.params[1] /*mode*/);
652 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop - command not handled"), DLT_INT(readData.message.cmd) );
655 pthread_cond_signal(&gMainLoopCond);
656 pthread_mutex_unlock(&gMainCondMtx);
664 if (0!=(gPollInfo.fds[i].revents & POLLIN))
666 flags |= DBUS_WATCH_READABLE;
668 if (0!=(gPollInfo.fds[i].revents & POLLOUT))
670 flags |= DBUS_WATCH_WRITABLE;
672 if (0!=(gPollInfo.fds[i].revents & POLLERR))
674 flags |= DBUS_WATCH_ERROR;
676 if (0!=(gPollInfo.fds[i].revents & POLLHUP))
678 flags |= DBUS_WATCH_HANGUP;
680 bContinue = dbus_watch_handle(gPollInfo.objects[i].watch, flags);
686 while (0!=bContinue);
688 #if USE_PASINTERFACE == 1
689 dbus_connection_unregister_object_path(conn, gPersAdminConsumerPath);
691 dbus_connection_unregister_object_path(conn, gDbusLcConsPath);
692 dbus_connection_unregister_object_path(conn, "/");
698 dbus_connection_close(conn);
699 dbus_connection_unref(conn);
703 pthread_cond_signal(&gDbusInitializedCond);
704 pthread_mutex_unlock(&gDbusInitializedMtx);
710 int deliverToMainloop(MainLoopData_u* payload)
714 pthread_mutex_lock(&gDeliverpMtx);
716 pthread_mutex_lock(&gMainCondMtx);
718 deliverToMainloop_NM(payload);
720 pthread_cond_wait(&gMainLoopCond, &gMainCondMtx);
721 pthread_mutex_unlock(&gMainCondMtx);
724 pthread_mutex_unlock(&gDeliverpMtx);
729 int deliverToMainloop_NM(MainLoopData_u* payload)
731 int rval = 0, length = 128;
733 //length = sizeof(payload->message) + strlen(payload->message.string) + 1; // TODO calculate the correct length of the message
735 //printf("--- *** --- Send => deliverToMainloop_NM => %d: | String: %s | size: %d\n", payload->message.cmd, payload->message.string, length);
737 if(-1 == write(gPipeFd[1], payload->payload, length))
739 DLT_LOG(gPclDLTContext, DLT_LOG_ERROR, DLT_STRING("deliverToMainloop => failed to write to pipe"), DLT_INT(errno));