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