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"
31 pthread_mutex_t gDbusInitializedMtx = PTHREAD_MUTEX_INITIALIZER;
32 pthread_cond_t gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
34 typedef enum EDBusObjectType
42 typedef struct SObjectEntry
44 tDBusObjectType objtype; /** libdbus' object */
47 DBusWatch * watch; /** watch "object" */
48 DBusTimeout * timeout; /** timeout "object" */
55 typedef struct SPollInfo
58 struct pollfd fds[10];
59 tObjectEntry objects[10];
63 /// polling information
64 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 printf("handleObjectPathMessageFallback Object: '%s' -> Interface: '%s' -> Message: '%s'\n",
105 dbus_message_get_sender(message), dbus_message_get_interface(message), dbus_message_get_member(message) );
107 // org.genivi.persistence.admin S I G N A L
108 if((0==strcmp("org.genivi.persistence.admin", dbus_message_get_interface(message))))
110 // printf("checkPersAdminSignalInterface '%s' -> '%s'\n", dbus_message_get_interface(message), dbus_message_get_member(message));
111 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
113 printf(" checkPersAdminSignal signal\n");
114 if((0==strcmp("PersistenceModeChanged", dbus_message_get_member(message))))
116 printf(" checkPersAdminSignal message\n");
117 // to do handle signal
118 result = signal_persModeChange(connection, message);
122 printf("handleObjectPathMessageFallback -> unknown signal '%s'\n", dbus_message_get_interface(message));
127 // org.genivi.persistence.admin P R O P E R T Y
128 else if((0==strcmp("org.freedesktop.DBus.Properties", dbus_message_get_interface(message))))
130 if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
132 if((0==strcmp("EggDBusChanged", dbus_message_get_member(message))))
134 DBusMessageIter array;
135 DBusMessageIter dict;
136 DBusMessageIter variant;
138 char* dictString = NULL;
141 dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, 0, &dict);
142 dbus_message_iter_get_basic(&dict, &dictString);
144 dbus_message_iter_open_container(&dict,DBUS_TYPE_VARIANT, NULL, &variant);
145 dbus_message_iter_get_basic(&dict, &value);
147 dbus_message_iter_close_container(&dict, &variant);
148 dbus_message_iter_close_container(&array, &dict);
150 printf("handleObjectPathMessageFallback ==> value: %d \n", value);
151 // to do handle signal
152 result = DBUS_HANDLER_RESULT_HANDLED;
156 printf("handleObjectPathMessageFallback -> unknown property '%s'\n", dbus_message_get_interface(message));
161 printf("handleObjectPathMessageFallback -> not a signal '%s'\n", dbus_message_get_member(message));
170 static void unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
172 printf("unregisterObjectPathFallback\n");
177 void* run_mainloop(void* dataPtr)
179 // persistence admin message
180 static const struct DBusObjectPathVTable vtablePersAdmin
181 = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
184 static const struct DBusObjectPathVTable vtableLifecycle
185 = {unregisterMessageHandler, checkLifecycleMsg, NULL, };
188 static const struct DBusObjectPathVTable vtableFallback
189 = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
192 mainLoop(vtablePersAdmin, vtableLifecycle, vtableFallback, dataPtr);
194 printf("Exit dbus main loop!!!!\n");
201 int setup_dbus_mainloop(void)
206 const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
207 dbus_error_init(&err);
209 // enable locking of data structures in the D-Bus library for multi threading.
210 dbus_threads_init_default();
212 // Connect to the bus and check for errors
215 printf("Use specific dbus address: %s\n !", pAddress);
216 gDbusConn = dbus_connection_open(pAddress, &err);
218 if(gDbusConn != NULL)
220 if(!dbus_bus_register(gDbusConn, &err))
222 printf("dbus_bus_register() Error %s\n", err.message);
223 dbus_error_free (&err);
228 printf("Registered connection successfully !\n");
233 printf("dbus_connection_open() Error %s\n",err.message);
234 dbus_error_free(&err);
239 printf("Use default dbus bus (DBUS_BUS_SYSTEM) !!!!!!\n");
240 gDbusConn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
243 // wain until dbus main loop has been setup and running
244 pthread_mutex_lock(&gDbusInitializedMtx);
246 // create here the dbus connection and pass to main loop
247 rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
250 fprintf(stderr, "Server: - ERROR! pthread_create( run_mainloop ) returned: %d\n", rval);
253 // wait for condition variable
254 pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
256 pthread_mutex_unlock(&gDbusInitializedMtx);
264 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
266 dbus_bool_t result = FALSE;
268 //fprintf(stderr, "addWatch called @%08x flags: %08x enabled: %c\n", (unsigned int)watch, dbus_watch_get_flags(watch), TRUE==dbus_watch_get_enabled(watch)?'x':'-');
270 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
272 int flags = dbus_watch_get_flags(watch);
274 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
275 pEntry->objtype = OT_WATCH;
276 pEntry->watch = watch;
278 gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
280 if (TRUE==dbus_watch_get_enabled(watch))
282 if (flags&DBUS_WATCH_READABLE)
284 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
286 if (flags&DBUS_WATCH_WRITABLE)
288 gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
302 static void removeWatch(DBusWatch *watch, void *data)
304 printf("removeWatch called @0x%08x\n", (int)watch);
309 static void watchToggled(DBusWatch *watch, void *data)
311 printf("watchToggled called @0x%08x\n", (int)watch);
316 static dbus_bool_t addTimeout(DBusTimeout *timeout, void *data)
318 dbus_bool_t ret = FALSE;
320 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
322 const int interval = dbus_timeout_get_interval(timeout);
323 if ((0<interval)&&(TRUE==dbus_timeout_get_enabled(timeout)))
325 const int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC);
328 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
329 if (-1!=timerfd_settime(tfd, 0, &its, NULL))
331 tObjectEntry * const pEntry = &gPollInfo.objects[gPollInfo.nfds];
332 pEntry->objtype = OT_TIMEOUT;
333 pEntry->timeout = timeout;
334 gPollInfo.fds[gPollInfo.nfds].fd = tfd;
335 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
341 fprintf(stderr, "timerfd_settime() failed %d '%s'\n", errno, strerror(errno));
346 fprintf(stderr, "timerfd_create() failed %d '%s'\n", errno, strerror(errno));
352 fprintf(stderr, "cannot create another fd to be poll()'ed\n");
360 static void removeTimeout(DBusTimeout *timeout, void *data)
363 int i = gPollInfo.nfds;
364 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
368 if (-1==close(gPollInfo.fds[i].fd))
370 fprintf(stderr, "close() timerfd #%d failed %d '%s'\n", gPollInfo.fds[i].fd, errno, strerror(errno));
374 while (gPollInfo.nfds>i)
376 gPollInfo.fds[i] = gPollInfo.fds[i+1];
377 gPollInfo.objects[i] = gPollInfo.objects[i+1];
381 gPollInfo.fds[gPollInfo.nfds].fd = -1;
382 gPollInfo.objects[gPollInfo.nfds].objtype = OT_NONE;
388 /** callback for libdbus' when timeout changed */
389 static void timeoutToggled(DBusTimeout *timeout, void *data)
391 int i = gPollInfo.nfds;
392 while ((0<i--)&&(timeout!=gPollInfo.objects[i].timeout));
393 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);
396 const int interval = (TRUE==dbus_timeout_get_enabled(timeout))?dbus_timeout_get_interval(timeout):0;
397 const struct itimerspec its = { .it_value= {interval/1000, interval%1000} };
398 if (-1!=timerfd_settime(gPollInfo.fds[i].fd, 0, &its, NULL))
400 fprintf(stderr, "timerfd_settime() %d failed %d '%s'\n", interval, errno, strerror(errno));
407 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
408 DBusObjectPathVTable vtableFallback, void* userData)
411 // lock mutex to make sure dbus main loop is running
412 pthread_mutex_lock(&gDbusInitializedMtx);
414 signal(SIGTERM, sigHandler);
415 signal(SIGQUIT, sigHandler);
416 signal(SIGINT, sigHandler);
418 DBusConnection* conn = (DBusConnection*)userData;
419 dbus_error_init(&err);
421 if (dbus_error_is_set(&err))
423 printf("Connection Error (%s)\n", err.message);
424 dbus_error_free(&err);
426 else if (NULL != conn)
428 dbus_connection_set_exit_on_disconnect (conn, FALSE);
429 //printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
430 if (-1 == (gEfds = eventfd(0, 0)))
432 printf("eventfd() failed w/ errno %d\n", errno);
438 memset(&gPollInfo, 0 , sizeof(gPollInfo));
441 gPollInfo.fds[0].fd = gEfds;
442 gPollInfo.fds[0].events = POLLIN;
444 dbus_bus_add_match(conn, "type='signal',interface='org.genivi.persistence.admin',member='PersistenceModeChanged',path='/org/genivi/persistence/admin'", &err);
446 // register for messages
447 if ( (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/adminconsumer", &vtable, userData))
448 && (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/NodeStateManager/LifeCycleConsumer", &vtable2, userData))
449 && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
451 if( (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
452 || (TRUE!=dbus_connection_set_timeout_functions(conn, addTimeout, removeTimeout, timeoutToggled, NULL, NULL)) )
454 printf("dbus_connection_set_watch_functions() failed\n");
458 pthread_cond_signal(&gDbusInitializedCond);
459 pthread_mutex_unlock(&gDbusInitializedMtx);
462 bContinue = 0; /* assume error */
464 while (DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
466 while ((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, -1)))&&(EINTR==errno));
470 fprintf(stderr, "poll() failed w/ errno %d\n", errno);
480 for (i=0; gPollInfo.nfds>i; ++i)
483 if (0!=gPollInfo.fds[i].revents)
485 //fprintf(stderr, "\t[%d] revents 0x%04x\n", i, gPollInfo.fds[i].revents);
487 if (OT_TIMEOUT==gPollInfo.objects[i].objtype)
489 /* time-out occured */
490 unsigned long long nExpCount = 0;
491 if ((ssize_t)sizeof(nExpCount)!=read(gPollInfo.fds[i].fd, &nExpCount, sizeof(nExpCount)))
493 fprintf(stderr, "read failed!?\n");
495 fprintf(stderr, "timeout %x #%d!\n", (int)gPollInfo.objects[i].timeout, (int)nExpCount);
496 if (FALSE==dbus_timeout_handle(gPollInfo.objects[i].timeout))
498 fprintf(stderr, "dbus_timeout_handle() failed!?\n");
502 else if (gPollInfo.fds[i].fd==gEfds)
504 /* internal command */
505 if (0!=(gPollInfo.fds[i].revents & POLLIN))
509 while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
512 printf("read() failed w/ errno %d | %s\n", errno, strerror(errno));
518 case CMD_PAS_BLOCK_AND_WRITE_BACK:
519 process_block_and_write_data_back((buf[2]), buf[1]);
521 case CMD_LC_PREPARE_SHUTDOWN:
522 process_prepare_shutdown((buf[2]), buf[1]);
528 printf("command %d not handled!\n", buf[0]);
537 if (0!=(gPollInfo.fds[i].revents & POLLIN))
539 flags |= DBUS_WATCH_READABLE;
541 if (0!=(gPollInfo.fds[i].revents & POLLOUT))
543 flags |= DBUS_WATCH_WRITABLE;
545 if (0!=(gPollInfo.fds[i].revents & POLLERR))
547 flags |= DBUS_WATCH_ERROR;
549 if (0!=(gPollInfo.fds[i].revents & POLLHUP))
551 flags |= DBUS_WATCH_HANGUP;
554 bContinue = dbus_watch_handle(gPollInfo.objects[i].watch, flags);
562 while (0!=bContinue);
564 dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/adminconsumer");
565 dbus_connection_unregister_object_path(conn, "/org/genivi/NodeStateManager/LifeCycleConsumer");
566 dbus_connection_unregister_object_path(conn, "/");
570 dbus_connection_unref(conn);
574 pthread_cond_signal(&gDbusInitializedCond);
575 pthread_mutex_unlock(&gDbusInitializedMtx);