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"
32 pthread_mutex_t gDbusInitializedMtx = PTHREAD_MUTEX_INITIALIZER;
33 pthread_cond_t gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
35 typedef enum EDBusObjectType
43 typedef struct SObjectEntry
45 tDBusObjectType objtype; /** libdbus' object */
48 DBusWatch * watch; /** watch "object" */
49 DBusTimeout * timeout; /** timeout "object" */
56 typedef struct SPollInfo
59 struct pollfd fds[10];
60 tObjectEntry objects[10];
64 /// polling information
65 static tPollInfo gPollInfo;
68 DBusConnection* gDbusConn = NULL;
71 DBusConnection* get_dbus_connection(void)
76 //------------------------------------------------------------------------
77 // debugging only until "correct" exit of main loop is possible!!!!!
78 //------------------------------------------------------------------------
80 static int endLoop = 0;
82 void sigHandler(int signo)
86 //------------------------------------------------------------------------
90 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
93 /* function to unregister ojbect path message handler */
94 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
96 printf("unregisterObjectPath\n");
99 /* catches messages not directed to any registered object path ("garbage collector") */
100 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
102 DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
104 // org.genivi.persistence.admin S I G N A L
105 if((0==strcmp("org.genivi.persistence.admin", dbus_message_get_interface(message))))
107 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
109 if((0==strcmp("PersistenceModeChanged", dbus_message_get_member(message))))
111 // to do handle signal
112 result = signal_persModeChange(connection, message);
116 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback -> unknown signal:"), DLT_STRING(dbus_message_get_interface(message)) );
120 // org.genivi.persistence.admin S I G N A L
121 else if((0==strcmp("org.genivi.persistence.adminconsumer", dbus_message_get_interface(message))))
123 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
125 pclNotification_s notifyStruct;
126 int validMessage = 0;
128 if((0==strcmp("PersistenceResChange", dbus_message_get_member(message))))
130 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_changed;
133 else if((0==strcmp("PersistenceResDelete", dbus_message_get_member(message))))
135 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_deleted;
138 else if((0==strcmp("PersistenceRes", dbus_message_get_member(message))))
140 notifyStruct.pclKeyNotify_Status = pclNotifyStatus_created;
144 if(validMessage == 1)
148 dbus_error_init (&error);
153 if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, ¬ifyStruct.resource_id,
154 DBUS_TYPE_STRING, &ldbid,
155 DBUS_TYPE_STRING, &user_no,
156 DBUS_TYPE_STRING, &seat_no,
159 reply = dbus_message_new_error(message, error.name, error.message);
163 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback => DBus No memory"), DLT_STRING(dbus_message_get_interface(message)) );
166 if (!dbus_connection_send(connection, reply, 0))
168 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback => DBus No memory"), DLT_STRING(dbus_message_get_interface(message)) );
171 result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;;
172 dbus_message_unref(reply);
176 notifyStruct.ldbid = atoi(ldbid);
177 notifyStruct.user_no = atoi(user_no);
178 notifyStruct.seat_no = atoi(seat_no);
180 // call the registered callback function
181 gChangeNotifyCallback(¬ifyStruct);
183 result = DBUS_HANDLER_RESULT_HANDLED;
185 dbus_connection_flush(connection);
189 // org.genivi.persistence.admin P R O P E R T Y
190 else if((0==strcmp("org.freedesktop.DBus.Properties", dbus_message_get_interface(message))))
192 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
194 if((0==strcmp("EggDBusChanged", dbus_message_get_member(message))))
196 DBusMessageIter array;
197 DBusMessageIter dict;
198 DBusMessageIter variant;
200 char* dictString = NULL;
203 dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, 0, &dict);
204 dbus_message_iter_get_basic(&dict, &dictString);
206 dbus_message_iter_open_container(&dict,DBUS_TYPE_VARIANT, NULL, &variant);
207 dbus_message_iter_get_basic(&dict, &value);
209 dbus_message_iter_close_container(&dict, &variant);
210 dbus_message_iter_close_container(&array, &dict);
212 // to do handle signal
213 result = DBUS_HANDLER_RESULT_HANDLED;
217 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback -> unknown property:"), DLT_STRING(dbus_message_get_interface(message)) );
222 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("handleObjectPathMessageFallback -> not a signal:"), DLT_STRING(dbus_message_get_member(message)) );
231 static void unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
233 printf("unregisterObjectPathFallback\n");
238 void* run_mainloop(void* dataPtr)
240 // persistence admin message
241 static const struct DBusObjectPathVTable vtablePersAdmin
242 = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
245 static const struct DBusObjectPathVTable vtableLifecycle
246 = {unregisterMessageHandler, checkLifecycleMsg, NULL, };
249 static const struct DBusObjectPathVTable vtableFallback
250 = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
253 mainLoop(vtablePersAdmin, vtableLifecycle, vtableFallback, dataPtr);
260 int setup_dbus_mainloop(void)
265 const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
267 // enable locking of data structures in the D-Bus library for multi threading.
268 dbus_threads_init_default();
270 dbus_error_init(&err);
272 // wain until dbus main loop has been setup and running
273 pthread_mutex_lock(&gDbusInitializedMtx);
275 // Connect to the bus and check for errors
278 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("setup_dbus_mainloop -> Use specific dbus address:"), DLT_STRING(pAddress) );
280 gDbusConn = dbus_connection_open(pAddress, &err);
282 if(gDbusConn != NULL)
284 if(!dbus_bus_register(gDbusConn, &err))
286 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("dbus_bus_register() Error :"), DLT_STRING(err.message) );
287 dbus_error_free (&err);
293 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("dbus_connection_open() Error :"), DLT_STRING(err.message) );
294 dbus_error_free(&err);
299 DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("Use default dbus bus (DBUS_BUS_SYSTEM)"));
301 gDbusConn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
304 // create here the dbus connection and pass to main loop
305 rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
308 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("pthread_create( DBUS run_mainloop ) returned an error:"), DLT_INT(rval) );
311 // wait for condition variable
312 pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
314 pthread_mutex_unlock(&gDbusInitializedMtx);
322 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
324 dbus_bool_t result = FALSE;
326 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
328 int flags = dbus_watch_get_flags(watch);
330 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
331 pEntry->objtype = OT_WATCH;
332 pEntry->watch = watch;
334 gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
336 if (TRUE==dbus_watch_get_enabled(watch))
338 if (flags&DBUS_WATCH_READABLE)
340 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
342 if (flags&DBUS_WATCH_WRITABLE)
344 gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
358 static void removeWatch(DBusWatch *watch, void *data)
360 printf("removeWatch called @0x%08x\n", (int)watch);
365 static void watchToggled(DBusWatch *watch, void *data)
367 printf("watchToggled called @0x%08x\n", (int)watch);
372 static dbus_bool_t addTimeout(DBusTimeout *timeout, void *data)
374 dbus_bool_t ret = FALSE;
376 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
378 const int interval = dbus_timeout_get_interval(timeout);
379 if ((0<interval)&&(TRUE==dbus_timeout_get_enabled(timeout)))
381 const int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
384 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
385 if (-1!=timerfd_settime(tfd, 0, &its, NULL))
387 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
388 pEntry->objtype = OT_TIMEOUT;
389 pEntry->timeout = timeout;
390 gPollInfo.fds[gPollInfo.nfds].fd = tfd;
391 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
397 printf("timerfd_settime() failed %d '%s'\n", errno, strerror(errno));
398 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout => timerfd_settime() failed"), DLT_STRING(strerror(errno)) );
403 printf("timerfd_create() failed %d '%s'\n", errno, strerror(errno));
404 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout => timerfd_create() failed"), DLT_STRING(strerror(errno)) );
410 printf("cannot create another fd to be poll()'ed\n");
411 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("addTimeout => cannot create another fd to be poll()'ed"));
419 static void removeTimeout(DBusTimeout *timeout, void *data)
422 int i = gPollInfo.nfds;
423 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
427 if (-1==close(gPollInfo.fds[i].fd))
429 printf("removeTimeout => close() timerfd #%d failed %d '%s'\n", gPollInfo.fds[i].fd, errno, strerror(errno));
430 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("removeTimeout => close() timerfd"), DLT_STRING(strerror(errno)) );
434 while (gPollInfo.nfds>i)
436 gPollInfo.fds[i] = gPollInfo.fds[i+1];
437 gPollInfo.objects[i] = gPollInfo.objects[i+1];
441 gPollInfo.fds[gPollInfo.nfds].fd = -1;
442 gPollInfo.objects[gPollInfo.nfds].objtype = OT_NONE;
448 /** callback for libdbus' when timeout changed */
449 static void timeoutToggled(DBusTimeout *timeout, void *data)
451 int i = gPollInfo.nfds;
452 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
453 fprintf(stderr, "timeoutToggled @%x %c %dms @%d [%d]\n", (int)timeout, dbus_timeout_get_enabled(timeout)?'x':'-', dbus_timeout_get_interval(timeout), i, gPollInfo.nfds);
456 const int interval = (TRUE==dbus_timeout_get_enabled(timeout))?dbus_timeout_get_interval(timeout):0;
457 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
458 if (-1!=timerfd_settime(gPollInfo.fds[i].fd, 0, &its, NULL))
460 printf("timeoutToggled => timerfd_settime() %d failed %d '%s'\n", interval, errno, strerror(errno));
461 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("timeoutToggled => timerfd_settime()"), DLT_STRING(strerror(errno)) );
468 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
469 DBusObjectPathVTable vtableFallback, void* userData)
472 // lock mutex to make sure dbus main loop is running
473 pthread_mutex_lock(&gDbusInitializedMtx);
475 signal(SIGTERM, sigHandler);
476 signal(SIGQUIT, sigHandler);
477 signal(SIGINT, sigHandler);
479 DBusConnection* conn = (DBusConnection*)userData;
480 dbus_error_init(&err);
482 if (dbus_error_is_set(&err))
484 printf("mainLoop => Connection Error (%s)\n", err.message);
485 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => Connection Error:"), DLT_STRING(err.message) );
486 dbus_error_free(&err);
488 else if (NULL != conn)
490 dbus_connection_set_exit_on_disconnect (conn, FALSE);
491 //printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
492 if (-1 == (gEfds = eventfd(0, 0)))
494 printf("mainLoop => eventfd() failed w/ errno %d\n", errno);
495 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => eventfd() failed w/ errno:"), DLT_INT(errno) );
501 memset(&gPollInfo, 0 , sizeof(gPollInfo));
504 gPollInfo.fds[0].fd = gEfds;
505 gPollInfo.fds[0].events = POLLIN;
507 dbus_bus_add_match(conn, "type='signal',interface='org.genivi.persistence.admin',member='PersistenceModeChanged',path='/org/genivi/persistence/admin'", &err);
509 // register for messages
510 if ( (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/adminconsumer", &vtable, userData))
511 && (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/NodeStateManager/LifeCycleConsumer", &vtable2, userData))
512 && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
514 if( (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
515 || (TRUE!=dbus_connection_set_timeout_functions(conn, addTimeout, removeTimeout, timeoutToggled, NULL, NULL)) )
517 printf("mainLoop => dbus_connection_set_watch_functions() failed\n");
518 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => dbus_connection_set_watch_functions() failed"));
522 pthread_cond_signal(&gDbusInitializedCond);
523 pthread_mutex_unlock(&gDbusInitializedMtx);
526 bContinue = 0; /* assume error */
528 while (DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
530 while ((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, -1)))&&(EINTR==errno));
534 printf("mainLoop => poll() failed w/ errno %d\n", errno);
535 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => poll() failed w/ errno "), DLT_INT(errno) );
545 for (i=0; gPollInfo.nfds>i; ++i)
548 if (0!=gPollInfo.fds[i].revents)
550 //fprintf(stderr, "\t[%d] revents 0x%04x\n", i, gPollInfo.fds[i].revents);
552 if (OT_TIMEOUT==gPollInfo.objects[i].objtype)
554 /* time-out occured */
555 unsigned long long nExpCount = 0;
556 if ((ssize_t)sizeof(nExpCount)!=read(gPollInfo.fds[i].fd, &nExpCount, sizeof(nExpCount)))
558 printf("mainLoop => read failed!?\n");
559 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => read failed"));
561 printf("mainLoop => timeout %x #%d!\n", (int)gPollInfo.objects[i].timeout, (int)nExpCount);
562 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => timeout"));
564 if (FALSE==dbus_timeout_handle(gPollInfo.objects[i].timeout))
566 printf("mainLoop => dbus_timeout_handle() failed!?\n");
567 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => dbus_timeout_handle() failed!?"));
571 else if (gPollInfo.fds[i].fd==gEfds)
573 /* internal command */
574 if (0!=(gPollInfo.fds[i].revents & POLLIN))
578 while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
581 printf("mainLoop => read() failed w/ errno %d | %s\n", errno, strerror(errno));
582 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => read() failed"), DLT_STRING(strerror(errno)) );
588 case CMD_PAS_BLOCK_AND_WRITE_BACK:
589 process_block_and_write_data_back((buf[2]), buf[1]);
591 case CMD_LC_PREPARE_SHUTDOWN:
592 process_prepare_shutdown((buf[2]), buf[1]);
598 printf("command %d not handled!\n", buf[0]);
599 DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("mainLoop => command not handled"), DLT_INT(buf[0]) );
608 if (0!=(gPollInfo.fds[i].revents & POLLIN))
610 flags |= DBUS_WATCH_READABLE;
612 if (0!=(gPollInfo.fds[i].revents & POLLOUT))
614 flags |= DBUS_WATCH_WRITABLE;
616 if (0!=(gPollInfo.fds[i].revents & POLLERR))
618 flags |= DBUS_WATCH_ERROR;
620 if (0!=(gPollInfo.fds[i].revents & POLLHUP))
622 flags |= DBUS_WATCH_HANGUP;
625 bContinue = dbus_watch_handle(gPollInfo.objects[i].watch, flags);
633 while (0!=bContinue);
635 dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/adminconsumer");
636 dbus_connection_unregister_object_path(conn, "/org/genivi/NodeStateManager/LifeCycleConsumer");
637 dbus_connection_unregister_object_path(conn, "/");
641 dbus_connection_unref(conn);
645 pthread_cond_signal(&gDbusInitializedCond);
646 pthread_mutex_unlock(&gDbusInitializedMtx);