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 "../include_protected/persistence_client_library_data_organization.h"
31 pthread_cond_t gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
32 pthread_mutex_t gDbusInitializedMtx = PTHREAD_MUTEX_INITIALIZER;
33 pthread_mutex_t gDbusPendingRegMtx = PTHREAD_MUTEX_INITIALIZER;
36 typedef enum EDBusObjectType
44 typedef struct SObjectEntry
46 tDBusObjectType objtype; /** libdbus' object */
49 DBusWatch * watch; /** watch "object" */
50 DBusTimeout * timeout; /** timeout "object" */
57 typedef struct SPollInfo
60 struct pollfd fds[10];
61 tObjectEntry objects[10];
65 /// polling information
66 static tPollInfo gPollInfo;
70 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
73 /* function to unregister ojbect path message handler */
74 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
76 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("unregisterObjectPath\n"));
79 /* catches messages not directed to any registered object path ("garbage collector") */
80 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
82 DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
84 // org.genivi.persistence.admin S I G N A L
85 if((0==strcmp("org.genivi.persistence.admin", dbus_message_get_interface(message))))
87 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
89 if((0==strcmp("PersistenceModeChanged", dbus_message_get_member(message))))
91 // to do handle signal
92 result = signal_persModeChange(connection, message);
96 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback -> unknown signal:"), DLT_STRING(dbus_message_get_interface(message)) );
100 // org.genivi.persistence.admin S I G N A L
101 else if((0==strcmp("org.genivi.persistence.adminconsumer", dbus_message_get_interface(message))))
103 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
105 pclNotification_s notifyStruct;
106 int validMessage = 0;
108 if((0==strcmp("PersistenceResChange", dbus_message_get_member(message))))
110 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_changed;
113 else if((0==strcmp("PersistenceResDelete", dbus_message_get_member(message))))
115 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_deleted;
118 else if((0==strcmp("PersistenceRes", dbus_message_get_member(message))))
120 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_created;
124 if(validMessage == 1)
128 dbus_error_init (&error);
133 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, ¬ifyStruct.resource_id,
134 DBUS_TYPE_STRING, &ldbid,
135 DBUS_TYPE_STRING, &user_no,
136 DBUS_TYPE_STRING, &seat_no,
139 reply = dbus_message_new_error(message, error.name, error.message);
143 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback => DBus No memory"), DLT_STRING(dbus_message_get_interface(message)) );
146 if (!dbus_connection_send(connection, reply, 0))
148 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback => DBus No memory"), DLT_STRING(dbus_message_get_interface(message)) );
151 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;;
152 dbus_message_unref(reply);
156 notifyStruct.ldbid = atoi(ldbid);
157 notifyStruct.user_no = atoi(user_no);
158 notifyStruct.seat_no = atoi(seat_no);
160 // call the registered callback function
161 gChangeNotifyCallback(¬ifyStruct);
163 result = DBUS_HANDLER_RESULT_HANDLED;
165 dbus_connection_flush(connection);
169 // org.genivi.persistence.admin P R O P E R T Y
170 else if((0==strcmp("org.freedesktop.DBus.Properties", dbus_message_get_interface(message))))
172 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
174 if((0==strcmp("EggDBusChanged", dbus_message_get_member(message))))
176 DBusMessageIter array;
177 DBusMessageIter dict;
178 DBusMessageIter variant;
180 char* dictString = NULL;
183 dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, 0, &dict);
184 dbus_message_iter_get_basic(&dict, &dictString);
186 dbus_message_iter_open_container(&dict,DBUS_TYPE_VARIANT, NULL, &variant);
187 dbus_message_iter_get_basic(&dict, &value);
189 dbus_message_iter_close_container(&dict, &variant);
190 dbus_message_iter_close_container(&array, &dict);
192 // to do handle signal
193 result = DBUS_HANDLER_RESULT_HANDLED;
197 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback -> unknown property:"), DLT_STRING(dbus_message_get_interface(message)) );
202 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback -> not a signal:"), DLT_STRING(dbus_message_get_member(message)) );
211 static void unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
213 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("unregisterObjectPathFallback\n"));
218 void* run_mainloop(void* dataPtr)
220 // persistence admin message
221 static const struct DBusObjectPathVTable vtablePersAdmin
222 = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
225 static const struct DBusObjectPathVTable vtableLifecycle
226 = {unregisterMessageHandler, checkLifecycleMsg, NULL, };
229 static const struct DBusObjectPathVTable vtableFallback
230 = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
233 mainLoop(vtablePersAdmin, vtableLifecycle, vtableFallback, dataPtr);
240 int setup_dbus_mainloop(void)
245 DBusConnection* conn = NULL;
247 const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
249 // enable locking of data structures in the D-Bus library for multi threading.
250 dbus_threads_init_default();
252 dbus_error_init(&err);
254 // wain until dbus main loop has been setup and running
255 pthread_mutex_lock(&gDbusInitializedMtx);
257 // Connect to the bus and check for errors
260 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("setup_dbus_mainloop -> Use specific dbus address:"), DLT_STRING(pAddress) );
262 conn = dbus_connection_open_private(pAddress, &err);
266 if(!dbus_bus_register(conn, &err))
268 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("dbus_bus_register() Error :"), DLT_STRING(err.message) );
269 dbus_error_free (&err);
275 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("dbus_connection_open_private() Error :"), DLT_STRING(err.message) );
276 dbus_error_free(&err);
282 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("Use default dbus bus (DBUS_BUS_SYSTEM)"));
284 conn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
287 // create here the dbus connection and pass to main loop
288 rval = pthread_create(&thread, NULL, run_mainloop, conn);
291 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pthread_create( DBUS run_mainloop ) returned an error:"), DLT_INT(rval) );
295 // wait for condition variable
296 pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
298 pthread_mutex_unlock(&gDbusInitializedMtx);
306 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
308 dbus_bool_t result = FALSE;
310 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
312 int flags = dbus_watch_get_flags(watch);
314 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
315 pEntry->objtype = OT_WATCH;
316 pEntry->watch = watch;
318 gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
320 if (TRUE==dbus_watch_get_enabled(watch))
322 if (flags&DBUS_WATCH_READABLE)
324 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
326 if (flags&DBUS_WATCH_WRITABLE)
328 gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
342 static void removeWatch(DBusWatch *watch, void *data)
344 void* w_data = dbus_watch_get_data(watch);
346 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("removeWatch called "), DLT_INT( (int)watch) );
351 dbus_watch_set_data(watch, NULL, NULL);
356 static void watchToggled(DBusWatch *watch, void *data)
358 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("watchToggled called "), DLT_INT( (int)watch) );
360 if(dbus_watch_get_enabled(watch))
361 addWatch(watch, data);
363 removeWatch(watch, data);
368 static dbus_bool_t addTimeout(DBusTimeout *timeout, void *data)
370 dbus_bool_t ret = FALSE;
372 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
374 const int interval = dbus_timeout_get_interval(timeout);
375 if ((0<interval)&&(TRUE==dbus_timeout_get_enabled(timeout)))
377 const int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
380 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
381 if (-1!=timerfd_settime(tfd, 0, &its, NULL))
383 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
384 pEntry->objtype = OT_TIMEOUT;
385 pEntry->timeout = timeout;
386 gPollInfo.fds[gPollInfo.nfds].fd = tfd;
387 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
393 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout => timerfd_settime() failed"), DLT_STRING(strerror(errno)) );
398 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout => timerfd_create() failed"), DLT_STRING(strerror(errno)) );
404 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout => cannot create another fd to be poll()'ed"));
412 static void removeTimeout(DBusTimeout *timeout, void *data)
415 int i = gPollInfo.nfds;
416 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
420 if (-1==close(gPollInfo.fds[i].fd))
422 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("removeTimeout => close() timerfd"), DLT_STRING(strerror(errno)) );
426 while (gPollInfo.nfds>i)
428 gPollInfo.fds[i] = gPollInfo.fds[i+1];
429 gPollInfo.objects[i] = gPollInfo.objects[i+1];
433 gPollInfo.fds[gPollInfo.nfds].fd = -1;
434 gPollInfo.objects[gPollInfo.nfds].objtype = OT_NONE;
440 /** callback for libdbus' when timeout changed */
441 static void timeoutToggled(DBusTimeout *timeout, void *data)
443 int i = gPollInfo.nfds;
444 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
445 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("timeoutToggled") );
448 const int interval = (TRUE==dbus_timeout_get_enabled(timeout))?dbus_timeout_get_interval(timeout):0;
449 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
450 if (-1!=timerfd_settime(gPollInfo.fds[i].fd, 0, &its, NULL))
452 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("timeoutToggled => timerfd_settime()"), DLT_STRING(strerror(errno)) );
459 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
460 DBusObjectPathVTable vtableFallback, void* userData)
463 // lock mutex to make sure dbus main loop is running
464 pthread_mutex_lock(&gDbusInitializedMtx);
466 DBusConnection* conn = (DBusConnection*)userData;
467 dbus_error_init(&err);
469 if (dbus_error_is_set(&err))
471 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => Connection Error:"), DLT_STRING(err.message) );
472 dbus_error_free(&err);
474 else if (NULL != conn)
476 dbus_connection_set_exit_on_disconnect(conn, FALSE);
477 if (-1 == (gEfds = eventfd(0, EFD_NONBLOCK)))
479 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => eventfd() failed w/ errno:"), DLT_INT(errno) );
484 memset(&gPollInfo, 0 , sizeof(gPollInfo));
487 gPollInfo.fds[0].fd = gEfds;
488 gPollInfo.fds[0].events = POLLIN;
490 dbus_bus_add_match(conn, "type='signal',interface='org.genivi.persistence.admin',member='PersistenceModeChanged',path='/org/genivi/persistence/admin'", &err);
492 // register for messages
493 if ( (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/adminconsumer", &vtable, userData))
494 && (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/NodeStateManager/LifeCycleConsumer", &vtable2, userData))
495 && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
497 if( (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
498 || (TRUE!=dbus_connection_set_timeout_functions(conn, addTimeout, removeTimeout, timeoutToggled, NULL, NULL)) )
500 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => dbus_connection_set_watch_functions() failed"));
504 pthread_cond_signal(&gDbusInitializedCond);
505 pthread_mutex_unlock(&gDbusInitializedMtx);
508 bContinue = 0; /* assume error */
510 while (DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
512 while ((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, -1)))&&(EINTR==errno));
516 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => poll() failed w/ errno "), DLT_INT(errno) );
526 for (i=0; gPollInfo.nfds>i; ++i)
529 if (0!=gPollInfo.fds[i].revents)
531 if (OT_TIMEOUT==gPollInfo.objects[i].objtype)
533 /* time-out occured */
534 unsigned long long nExpCount = 0;
535 if ((ssize_t)sizeof(nExpCount)!=read(gPollInfo.fds[i].fd, &nExpCount, sizeof(nExpCount)))
537 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => read failed"));
539 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => timeout"));
541 if (FALSE==dbus_timeout_handle(gPollInfo.objects[i].timeout))
543 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => dbus_timeout_handle() failed!?"));
547 else if (gPollInfo.fds[i].fd == gEfds)
549 /* internal command */
550 if (0!=(gPollInfo.fds[i].revents & POLLIN))
554 while ((-1==(ret = read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR == errno));
557 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => read() failed"), DLT_STRING(strerror(errno)) );
558 printf(" * mainloop: read F A I L E D\n");
562 printf(" * mainloop: dispatch command => [0]: %d | [1]: %d | [2]: %d\n", buf[0], buf[1], buf[2]);
565 case CMD_PAS_BLOCK_AND_WRITE_BACK:
566 process_block_and_write_data_back((buf[2]), buf[1]);
568 case CMD_LC_PREPARE_SHUTDOWN:
569 printf(" CMD => Prepare shutdown\n");
570 process_prepare_shutdown((buf[2]), buf[1]);
572 case CMD_SEND_NOTIFY_SIGNAL:
573 printf(" CMD => Send notification signal\n");
574 process_send_notification_signal(conn);
576 case CMD_REG_NOTIFY_SIGNAL:
577 printf(" CMD => Register notification signal\n");
578 process_reg_notification_signal(conn);
580 case CMD_SEND_PAS_REQUEST:
581 printf(" CMD => Admin request => request: %d | status: %d\n", (buf[2]), buf[1]);
582 process_send_pas_request(conn, (buf[2]), buf[1]);
584 case CMD_SEND_PAS_REGISTER:
585 printf(" CMD => Admin register => mode: %d | type: %d\n", (buf[2]), buf[1]);
586 process_send_pas_register(conn, (buf[1]), buf[2]);
588 case CMD_SEND_LC_REQUEST:
589 printf(" CMD => Lifecycle request => request: %d | status\n", (buf[2]), buf[1]);
590 process_send_lifecycle_request(conn, (buf[2]), buf[1]);
592 case CMD_SEND_LC_REGISTER:
593 printf(" CMD => Lifecycle register => mode: %d | type: %d\n", (buf[2]), buf[1]);
594 process_send_lifecycle_register(conn, (buf[1]), buf[2]);
600 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => command not handled"), DLT_INT(buf[0]) );
609 if (0!=(gPollInfo.fds[i].revents & POLLIN))
611 flags |= DBUS_WATCH_READABLE;
613 if (0!=(gPollInfo.fds[i].revents & POLLOUT))
615 flags |= DBUS_WATCH_WRITABLE;
617 if (0!=(gPollInfo.fds[i].revents & POLLERR))
619 flags |= DBUS_WATCH_ERROR;
621 if (0!=(gPollInfo.fds[i].revents & POLLHUP))
623 flags |= DBUS_WATCH_HANGUP;
626 bContinue = dbus_watch_handle(gPollInfo.objects[i].watch, flags);
632 while (0!=bContinue);
634 dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/adminconsumer");
635 dbus_connection_unregister_object_path(conn, "/org/genivi/NodeStateManager/LifeCycleConsumer");
636 dbus_connection_unregister_object_path(conn, "/");
640 dbus_connection_close(conn);
641 dbus_connection_unref(conn);
645 pthread_cond_signal(&gDbusInitializedCond);
646 pthread_mutex_unlock(&gDbusInitializedMtx);