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_admin_service_mockup.c
13 * @ingroup Persistence client library test
14 * @author Ingo Huerner
15 * @brief Persistence Administration Serivce mockup
23 #include <unistd.h> /* exit */
28 #include <dbus/dbus.h>
31 #include <sys/eventfd.h>
36 * To test the PAS notifications the "./persistence_client_library_dbus_test" can be used.
37 * Use the dbus-send command to send shutdown notification to registered client if the lifecycle mockup will be used.
38 * To get the correct destionation (example is :1.11) see console when this application has been started.
39 * You sould find something like:
40 * " checkAdminMsg ==> busName: :1.79 | objName: /org/genivi/persistence/adminconsumer | notificationFlag: 19 | gTimeoutMs: 5000"
41 * when a client registeres itself to the lifecycle mockup.
42 * Now use the the destination ":1.79" to communicate with the client library for dest in dbus-send command.
45 dbus-send --system --dest=:1.11 --type=method_call --print-reply /org/genivi/persistence/adminconsumer org.genivi.persistence.adminconsumer.PersistenceAdminRequest int32:17 int32:22
48 int32:17 => PAS message block and write back
49 int32:2 => PAS message unblock
51 dbus-send return message value 32768 ==> invalid message:
52 method return sender=:1.72 -> dest=:1.74 reply_serial=2
55 dbus-send return message value 1 ==> OK:
56 method return sender=:1.72 -> dest=:1.76 reply_serial=2
63 /// command definitions for main loop
66 CMD_NONE = 0, /// command none
67 CMD_PAS_BLOCK_AND_WRITE_BACK, /// command block access and write data back
68 CMD_LC_PREPARE_SHUTDOWN, /// command to prepare shutdown
69 CMD_QUIT, /// quit command
74 /// pipe file descriptors
79 pthread_mutex_t gDbusInitializedMtx = PTHREAD_MUTEX_INITIALIZER;
80 pthread_cond_t gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
83 typedef struct SPollInfo
86 struct pollfd fds[10];
87 DBusWatch * watches[10];
91 /// polling information
92 static tPollInfo gPollInfo;
96 DBusConnection* gDbusConn = NULL;
99 DBusConnection* get_dbus_connection(void)
104 //------------------------------------------------------------------------
105 // debugging only until "correct" exit of main loop is possible!!!!!
106 //------------------------------------------------------------------------
108 static int endLoop = 0;
110 void sigHandler(int signo)
116 printf("* * * * S I G H U P * * * *\n");
123 //------------------------------------------------------------------------
126 static int setupSignalHandler(const int nSignal, void (*pHandler)(int))
128 struct sigaction sa_old;
129 int ret = sigaction(nSignal, NULL, &sa_old);
132 if (pHandler!=sa_old.sa_handler)
134 /* setup own signal handler */
135 struct sigaction sa_new;
136 memset(&sa_new, 0, sizeof(sa_new));
137 sa_new.sa_handler = pHandler;
139 ret = sigaction(nSignal, &sa_new, 0);
148 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
152 int checkAdminMsg(DBusConnection *connection, DBusMessage *message)
154 char* busName = NULL;
155 char* objName = NULL;
156 int32_t notificationFlag = 0;
157 uint32_t gTimeoutMs = 0;
158 int msgReturn = 123321;
162 dbus_error_init (&error);
164 if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &busName, // bus name
165 DBUS_TYPE_STRING, &objName,
166 DBUS_TYPE_INT32, ¬ificationFlag,
167 DBUS_TYPE_UINT32, &gTimeoutMs,
170 reply = dbus_message_new_error(message, error.name, error.message);
174 //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
175 printf("DBus No memory\n");
178 if (!dbus_connection_send(connection, reply, 0))
180 //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
181 printf("DBus No memory\n");
184 dbus_message_unref(reply);
186 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
190 printf(" checkAdminMsg ==> busName: %s | objName: %s | notificationFlag: %d | gTimeoutMs: %u\n\n", busName, objName, notificationFlag, gTimeoutMs);
191 reply = dbus_message_new_method_return(message);
195 //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
196 printf("DBus No memory\n");
199 if (!dbus_message_append_args(reply, DBUS_TYPE_INT32, &msgReturn, DBUS_TYPE_INVALID))
201 //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
202 printf("DBus No memory\n");
205 if (!dbus_connection_send(connection, reply, NULL))
207 //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
208 printf("DBus No memory\n");
211 dbus_connection_flush(connection);
212 dbus_message_unref(reply);
214 return DBUS_HANDLER_RESULT_HANDLED;
219 DBusHandlerResult checkPersAdminMsg(DBusConnection * connection, DBusMessage * message, void * user_data)
221 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
223 //printf("checkPersAdminMsg '%s' -> '%s'\n", dbus_message_get_interface(message), dbus_message_get_member(message));
224 if((0==strcmp("org.genivi.persistence.admin", dbus_message_get_interface(message))))
226 if((0==strcmp("RegisterPersAdminNotification", dbus_message_get_member(message))))
228 printf(" ==> org.genivi.persistence.admin - received - ==> RegisterPersAdminNotification \n");
230 result = checkAdminMsg(connection, message);
232 else if((0==strcmp("UnRegisterPersAdminNotification", dbus_message_get_member(message))))
234 printf(" ==> org.genivi.persistence.admin - received - ==> UnRegisterPersAdminNotification \n");
236 result = checkAdminMsg(connection, message);
238 else if((0==strcmp("PersistenceAdminRequestCompleted", dbus_message_get_member(message))))
240 printf(" ==> org.genivi.persistence.admin - received - ==> PersistenceAdminRequestCompleted \n");
244 printf(" ==> org.genivi.persistence.admin - received U N KN O W N-'%s'\n", dbus_message_get_interface(message));
249 printf(" ==> org.genivi.persistence - received U N KN O W N-'%s'\n", dbus_message_get_interface(message));
255 /* function to unregister ojbect path message handler */
256 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
258 printf("unregisterObjectPath\n");
261 /* catches messages not directed to any registered object path ("garbage collector") */
262 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
264 DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
266 printf("handleObjectPathMessageFallback Object: '%s' -> Interface: '%s' -> Message: '%s'\n",
267 dbus_message_get_sender(message), dbus_message_get_interface(message), dbus_message_get_member(message) );
274 static void unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
276 printf("unregisterObjectPathFallback\n");
284 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
286 dbus_bool_t result = FALSE;
288 //printf("addWatch called @%08x flags: %08x enabled: %c\n", (unsigned int)watch, dbus_watch_get_flags(watch), TRUE==dbus_watch_get_enabled(watch)?'x':'-');
290 if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
292 int flags = dbus_watch_get_flags(watch);
294 gPollInfo.watches[gPollInfo.nfds] = watch;
296 gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
298 if (TRUE==dbus_watch_get_enabled(watch))
300 if (flags&DBUS_WATCH_READABLE)
302 gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
304 if (flags&DBUS_WATCH_WRITABLE)
306 gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
310 /* wakeup main-loop, just in case */
311 static const uint64_t cmd = CMD_REQUEST_NAME;
312 if (sizeof(uint64_t)!=write(gEfds, &cmd, sizeof(uint64_t)))
314 fprintf(stderr, "write failed w/ errno %d\n", errno);
325 static void removeWatch(DBusWatch *watch, void *data)
327 void* w_data = dbus_watch_get_data(watch);
329 printf("removeWatch called @0x%08x\n", (int)watch);
334 dbus_watch_set_data(watch, NULL, NULL);
338 static void watchToggled(DBusWatch *watch, void *data)
340 printf("watchToggled called @0x%08x\n", (int)watch);
342 if(dbus_watch_get_enabled(watch))
343 addWatch(watch, data);
345 removeWatch(watch, data);
349 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtableFallback, void* userData)
352 // lock mutex to make sure dbus main loop is running
353 pthread_mutex_lock(&gDbusInitializedMtx);
355 setupSignalHandler(SIGTERM, sigHandler);
356 setupSignalHandler(SIGQUIT, sigHandler);
357 setupSignalHandler(SIGINT, sigHandler);
358 setupSignalHandler(SIGHUP, sigHandler);
360 DBusConnection* conn = (DBusConnection*)userData;
361 dbus_error_init(&err);
363 if (dbus_error_is_set(&err))
365 printf("Connection Error (%s)\n", err.message);
366 dbus_error_free(&err);
368 else if (NULL != conn)
370 dbus_connection_set_exit_on_disconnect (conn, FALSE);
371 printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
372 if (-1 == (gEfds = eventfd(0, 0)))
374 printf("eventfd() failed w/ errno %d\n", errno);
380 memset(&gPollInfo, 0 , sizeof(gPollInfo));
383 gPollInfo.fds[0].fd = gEfds;
384 gPollInfo.fds[0].events = POLLIN;
386 // register for messages
387 if ( (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/admin", &vtable, userData))
388 && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
390 if (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
392 printf("dbus_connection_set_watch_functions() failed\n");
398 pthread_cond_signal(&gDbusInitializedCond);
399 pthread_mutex_unlock(&gDbusInitializedMtx);
402 bContinue = 0; /* assume error */
404 while(DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
406 while((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, 500)))&&(EINTR==errno));
410 printf("poll() failed w/ errno %d\n", errno);
417 for (i=0; gPollInfo.nfds>i; ++i)
419 if (0!=gPollInfo.fds[i].revents)
421 if (gPollInfo.fds[i].fd==gEfds)
423 if (0!=(gPollInfo.fds[i].revents & POLLIN))
426 while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
429 printf("read() failed w/ errno %d | %s\n", errno, strerror(errno));
435 case CMD_REQUEST_NAME:
436 if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER !=dbus_bus_request_name(conn, "org.genivi.persistence.admin", DBUS_NAME_FLAG_DO_NOT_QUEUE, &err))
438 fprintf(stderr, "Cannot acquire name 'org.genivi.persistence.admin': \n \"(%s)\". Bailing out!\n", err.message);
439 dbus_error_free(&err);
447 printf("command %d not handled!\n", buf[0]);
456 if (0!=(gPollInfo.fds[i].revents & POLLIN))
458 flags |= DBUS_WATCH_READABLE;
460 if (0!=(gPollInfo.fds[i].revents & POLLOUT))
462 flags |= DBUS_WATCH_WRITABLE;
464 if (0!=(gPollInfo.fds[i].revents & POLLERR))
466 flags |= DBUS_WATCH_ERROR;
468 if (0!=(gPollInfo.fds[i].revents & POLLHUP))
470 flags |= DBUS_WATCH_HANGUP;
472 //printf("handle watch @0x%08x flags: %04x\n", (int)gPollInfo.watches[i], flags);
473 bContinue = dbus_watch_handle(gPollInfo.watches[i], flags);
481 while (0!=bContinue);
483 dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/admin");
484 dbus_connection_unregister_object_path(conn, "/");
488 dbus_connection_close(conn);
489 dbus_connection_unref(conn);
493 pthread_cond_signal(&gDbusInitializedCond);
494 pthread_mutex_unlock(&gDbusInitializedMtx);
499 void* run_mainloop(void* dataPtr)
501 // persistence admin message
502 static const struct DBusObjectPathVTable vtablePersAdmin
503 = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
506 static const struct DBusObjectPathVTable vtableFallback
507 = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
510 mainLoop(vtablePersAdmin, vtableFallback, dataPtr);
512 printf("Exit dbus main loop!!!!\n");
518 int setup_dbus_mainloop(void)
523 const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
524 dbus_error_init(&err);
526 // enable locking of data structures in the D-Bus library for multi threading.
527 dbus_threads_init_default();
529 // Connect to the bus and check for errors
532 printf("Use specific dbus address: %s\n !", pAddress);
533 gDbusConn = dbus_connection_open_private(pAddress, &err);
535 if(gDbusConn != NULL)
537 if(!dbus_bus_register(gDbusConn, &err))
539 printf("dbus_bus_register() Error %s\n", err.message);
540 dbus_error_free (&err);
545 printf("Registered connection successfully !\n");
550 printf("dbus_connection_open() Error %s\n",err.message);
551 dbus_error_free(&err);
556 printf("Use default dbus bus!!!!!!\n");
557 gDbusConn = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err);
560 // wain until dbus main loop has been setup and running
561 pthread_mutex_lock(&gDbusInitializedMtx);
563 // create here the dbus connection and pass to main loop
564 rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
567 fprintf(stderr, "Server: - ERROR! pthread_create( run_mainloop ) returned: %d\n", rval);
570 // wait for condition variable
571 pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
573 pthread_mutex_unlock(&gDbusInitializedMtx);
579 int main(int argc, char *argv[])
581 setup_dbus_mainloop();
583 printf("Wait, press enter to exit!!\n");
585 printf("Exiting Persistence Admin mockup!!\n");