Changed file and key-value API according GENIVI naming conventions
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_dbus_service.c
1 /******************************************************************************
2  * Project         Persistency
3  * (c) copyright   2012
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 ******************************************************************************/
11  /**
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.
16  * @see
17  */
18
19
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
24 #include <stdio.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29
30
31 pthread_mutex_t gDbusInitializedMtx  = PTHREAD_MUTEX_INITIALIZER;
32 pthread_cond_t  gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
33
34 /// polling structure
35 typedef struct SPollInfo
36 {
37    int nfds;
38    struct pollfd fds[10];
39    DBusWatch * watches[10];
40 } tPollInfo;
41
42
43 /// polling information
44 static tPollInfo gPollInfo;
45
46
47 /// dbus connection
48 DBusConnection* gDbusConn = NULL;
49
50
51 DBusConnection* get_dbus_connection(void)
52 {
53    return gDbusConn;
54 }
55
56 //------------------------------------------------------------------------
57 // debugging only until "correct" exit of main loop is possible!!!!!
58 //------------------------------------------------------------------------
59 #include "signal.h"
60 static int endLoop = 0;
61
62 void sigHandler(int signo)
63 {
64    endLoop = 1;
65 }
66 //------------------------------------------------------------------------
67
68
69
70 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
71
72
73 /* function to unregister ojbect path message handler */
74 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
75 {
76    printf("unregisterObjectPath\n");
77 }
78
79 /* catches messages not directed to any registered object path ("garbage collector") */
80 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
81 {
82    DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
83
84    printf("handleObjectPathMessageFallback Object: '%s' -> Interface: '%s' -> Message: '%s'\n",
85           dbus_message_get_sender(message), dbus_message_get_interface(message), dbus_message_get_member(message) );
86
87    // org.genivi.persistence.admin  S I G N A L
88    if((0==strcmp("org.genivi.persistence.admin", dbus_message_get_interface(message))))
89    {
90       // printf("checkPersAdminSignalInterface '%s' -> '%s'\n", dbus_message_get_interface(message), dbus_message_get_member(message));
91       if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
92       {
93          printf("  checkPersAdminSignal signal\n");
94          if((0==strcmp("PersistenceModeChanged", dbus_message_get_member(message))))
95          {
96             printf("  checkPersAdminSignal message\n");
97             // to do handle signal
98             result = signal_persModeChange(connection, message);
99          }
100          else
101          {
102             printf("handleObjectPathMessageFallback -> unknown signal '%s'\n", dbus_message_get_interface(message));
103          }
104       }
105    }
106
107    // org.genivi.persistence.admin  P R O P E R T Y
108    else  if((0==strcmp("org.freedesktop.DBus.Properties", dbus_message_get_interface(message))))
109    {
110       if(dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
111       {
112          if((0==strcmp("EggDBusChanged", dbus_message_get_member(message))))
113          {
114             DBusMessageIter array;
115             DBusMessageIter dict;
116             DBusMessageIter variant;
117
118             char* dictString = NULL;
119             int value = 0;
120
121             dbus_message_iter_open_container(&array, DBUS_TYPE_DICT_ENTRY, 0, &dict);
122             dbus_message_iter_get_basic(&dict, &dictString);
123
124             dbus_message_iter_open_container(&dict,DBUS_TYPE_VARIANT, NULL, &variant);
125             dbus_message_iter_get_basic(&dict, &value);
126
127             dbus_message_iter_close_container(&dict, &variant);
128             dbus_message_iter_close_container(&array, &dict);
129
130             printf("handleObjectPathMessageFallback ==> value: %d \n", value);
131             // to do handle signal
132             result = DBUS_HANDLER_RESULT_HANDLED;
133          }
134          else
135          {
136             printf("handleObjectPathMessageFallback -> unknown property '%s'\n", dbus_message_get_interface(message));
137          }
138       }
139       else
140       {
141          printf("handleObjectPathMessageFallback -> not a signal '%s'\n", dbus_message_get_member(message));
142       }
143    }
144
145    return result;
146 }
147
148
149
150 static void  unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
151 {
152    printf("unregisterObjectPathFallback\n");
153 }
154
155
156
157 void* run_mainloop(void* dataPtr)
158 {
159    // persistence admin message
160    static const struct DBusObjectPathVTable vtablePersAdmin
161       = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
162
163    // lifecycle message
164    static const struct DBusObjectPathVTable vtableLifecycle
165       = {unregisterMessageHandler, checkLifecycleMsg, NULL, };
166
167    // fallback
168    static const struct DBusObjectPathVTable vtableFallback
169       = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
170
171    // setup the dbus
172    mainLoop(vtablePersAdmin, vtableLifecycle, vtableFallback, dataPtr);
173
174    printf("Exit dbus main loop!!!!\n");
175
176    return NULL;
177 }
178
179
180
181 int setup_dbus_mainloop(void)
182 {
183    int rval = 0;
184    pthread_t thread;
185    DBusError err;
186    const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
187    dbus_error_init(&err);
188
189    // enable locking of data structures in the D-Bus library for multi threading.
190    dbus_threads_init_default();
191
192    // Connect to the bus and check for errors
193    if(pAddress != NULL)
194    {
195       printf("Use specific dbus address: %s\n !", pAddress);
196       gDbusConn = dbus_connection_open(pAddress, &err);
197
198       if(gDbusConn != NULL)
199       {
200          if(!dbus_bus_register(gDbusConn, &err))
201          {
202             printf("dbus_bus_register() Error %s\n", err.message);
203             dbus_error_free (&err);
204             return -1;
205          }
206          else
207          {
208             printf("Registered connection successfully !\n");
209          }
210       }
211       else
212       {
213          printf("dbus_connection_open() Error %s\n",err.message);
214          dbus_error_free(&err);
215       }
216    }
217    else
218    {
219       printf("Use default dbus bus!!!!!!\n");
220       gDbusConn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
221    }
222
223    // wain until dbus main loop has been setup and running
224    pthread_mutex_lock(&gDbusInitializedMtx);
225
226    // create here the dbus connection and pass to main loop
227    rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
228    if(rval)
229    {
230      fprintf(stderr, "Server: - ERROR! pthread_create( run_mainloop ) returned: %d\n", rval);
231    }
232
233    // wait for condition variable
234    pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
235
236    pthread_mutex_unlock(&gDbusInitializedMtx);
237    return rval;
238 }
239
240
241
242
243
244 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
245 {
246    dbus_bool_t result = FALSE;
247
248    //printf("addWatch called @%08x flags: %08x enabled: %c\n", (unsigned int)watch, dbus_watch_get_flags(watch), TRUE==dbus_watch_get_enabled(watch)?'x':'-');
249
250    if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
251    {
252       int flags = dbus_watch_get_flags(watch);
253
254       gPollInfo.watches[gPollInfo.nfds] = watch;
255
256       gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
257
258       if (TRUE==dbus_watch_get_enabled(watch))
259       {
260          if (flags&DBUS_WATCH_READABLE)
261          {
262             gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
263          }
264          if (flags&DBUS_WATCH_WRITABLE)
265          {
266             gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
267          }
268
269          ++gPollInfo.nfds;
270       }
271
272       result = TRUE;
273    }
274
275    return result;
276 }
277
278
279
280 static void removeWatch(DBusWatch *watch, void *data)
281 {
282    printf("removeWatch called @0x%08x\n", (int)watch);
283 }
284
285
286
287 static void watchToggled(DBusWatch *watch, void *data)
288 {
289    printf("watchToggled called @0x%08x\n", (int)watch);
290 }
291
292
293
294 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
295              DBusObjectPathVTable vtableFallback, void* userData)
296 {
297    DBusError err;
298    // lock mutex to make sure dbus main loop is running
299    pthread_mutex_lock(&gDbusInitializedMtx);
300
301    signal(SIGTERM, sigHandler);
302    signal(SIGQUIT, sigHandler);
303    signal(SIGINT,  sigHandler);
304
305    DBusConnection* conn = (DBusConnection*)userData;
306    dbus_error_init(&err);
307
308    if (dbus_error_is_set(&err))
309    {
310       printf("Connection Error (%s)\n", err.message);
311       dbus_error_free(&err);
312    }
313    else if (NULL != conn)
314    {
315       dbus_connection_set_exit_on_disconnect (conn, FALSE);
316       printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
317       if (0!=pipe(gPipefds))
318       {
319          printf("pipe() failed w/ errno %d\n", errno);
320       }
321       else
322       {
323          int ret;
324          int bContinue = 0;
325          memset(&gPollInfo, 0 , sizeof(gPollInfo));
326
327          gPollInfo.nfds = 1;
328          gPollInfo.fds[0].fd = gPipefds[0];
329          gPollInfo.fds[0].events = POLLIN;
330
331          dbus_bus_add_match(conn, "type='signal',interface='org.genivi.persistence.admin',member='PersistenceModeChanged',path='/org/genivi/persistence/admin'", &err);
332
333          // register for messages
334          if (   (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/adminconsumer", &vtable, userData))
335              && (TRUE==dbus_connection_register_object_path(conn, "/com/contiautomotive/NodeStateManager/LifecycleConsumer", &vtable2, userData))
336              && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
337          {
338             if (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
339             {
340                printf("dbus_connection_set_watch_functions() failed\n");
341             }
342             else
343             {
344                char buf[64];
345
346                pthread_cond_signal(&gDbusInitializedCond);
347                pthread_mutex_unlock(&gDbusInitializedMtx);
348                do
349                {
350                   bContinue = 0; /* assume error */
351
352                   while(DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
353
354                   while((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, 500)))&&(EINTR==errno));
355
356                   if(0>ret)
357                   {
358                      printf("poll() failed w/ errno %d\n", errno);
359                   }
360                   else
361                   {
362                      int i;
363                      bContinue = 1;
364
365                      for (i=0; gPollInfo.nfds>i; ++i)
366                      {
367                         if (0!=gPollInfo.fds[i].revents)
368                         {
369                            if (gPollInfo.fds[i].fd==gPipefds[0])
370                            {
371                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
372                               {
373                                  bContinue = TRUE;
374                                  while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
375                                  if (0>ret)
376                                  {
377                                     printf("read() failed w/ errno %d\n", errno);
378                                  }
379                                  else if (sizeof(int)==ret)
380                                  {
381                                     switch (buf[0])
382                                     {
383                                        case CMD_PAS_BLOCK_AND_WRITE_BACK:
384                                           process_block_and_write_data_back(buf[1]);
385                                           break;
386                                        case CMD_LC_PREPARE_SHUTDOWN:
387                                           process_prepare_shutdown(buf[1]);
388                                           break;
389                                        case CMD_QUIT:
390                                           bContinue = FALSE;
391                                           break;
392                                        default:
393                                           printf("command %d not handled!\n", buf[0]);
394                                           break;
395                                     }
396                                  }
397                                  else
398                                  {
399                                     printf("read() returned %d (%s)\n", ret, buf);
400                                  }
401                               }
402                            }
403                            else
404                            {
405                               int flags = 0;
406                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
407                               {
408                                  flags |= DBUS_WATCH_READABLE;
409                               }
410                               if (0!=(gPollInfo.fds[i].revents & POLLOUT))
411                               {
412                                  flags |= DBUS_WATCH_WRITABLE;
413                               }
414                               if (0!=(gPollInfo.fds[i].revents & POLLERR))
415                               {
416                                  flags |= DBUS_WATCH_ERROR;
417                               }
418                               if (0!=(gPollInfo.fds[i].revents & POLLHUP))
419                               {
420                                  flags |= DBUS_WATCH_HANGUP;
421                               }
422                               //printf("handle watch @0x%08x flags: %04x\n", (int)gPollInfo.watches[i], flags);
423                               bContinue = dbus_watch_handle(gPollInfo.watches[i], flags);
424                            }
425                         }
426                      }
427                   }
428                   if(endLoop == 1)
429                      break;
430                }
431                while (0!=bContinue);
432             }
433             dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/adminconsumer");
434             dbus_connection_unregister_object_path(conn, "/com/contiautomotive/NodeStateManager/LifecycleConsumer");
435             dbus_connection_unregister_object_path(conn, "/");
436          }
437          close(gPipefds[1]);
438          close(gPipefds[0]);
439       }
440       dbus_connection_unref(conn);
441       dbus_shutdown();
442    }
443
444    pthread_cond_signal(&gDbusInitializedCond);
445    pthread_mutex_unlock(&gDbusInitializedMtx);
446    return 0;
447 }
448