Updated client library with version 0.1.5 (rev. 1665), for changes see change log
[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    Permission is hereby granted, free of charge, to any person obtaining
8    a copy of this software and associated documentation files (the "Software"),
9    to deal in the Software without restriction, including without limitation
10    the rights to use, copy, modify, merge, publish, distribute, sublicense,
11    and/or sell copies of the Software, and to permit persons to whom the
12    Software is furnished to do so, subject to the following conditions:
13
14    The above copyright notice and this permission notice shall be included
15    in all copies or substantial portions of the Software.
16
17    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
21    DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
23    OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 ******************************************************************************/
25  /**
26  * @file           persistence_client_library_dbus_service.c
27  * @ingroup        Persistence client library
28  * @author         Ingo Huerner
29  * @brief          Implementation of the persistence client library dbus service.
30  * @see
31  */
32
33 //#include "persistence_client_service_dbus_service.h"
34
35 #include "persistence_client_library_dbus_service.h"
36 #include "persistence_client_library_lc_interface.h"
37 #include "persistence_client_library_pas_interface.h"
38
39 #include <stdio.h>
40 #include <errno.h>
41 #include <string.h>
42 #include <unistd.h>
43 #include <stdlib.h>
44
45
46 /// polling structure
47 typedef struct SPollInfo
48 {
49    int nfds;
50    struct pollfd fds[10];
51    DBusWatch * watches[10];
52 } tPollInfo;
53
54
55 /// polling information
56 static tPollInfo gPollInfo;
57
58
59 /// dbus connection
60 DBusConnection* gDbusConn = NULL;
61
62
63 DBusConnection* get_dbus_connection(void)
64 {
65    return gDbusConn;
66 }
67
68 //------------------------------------------------------------------------
69 // debugging only until "correct" exit of main loop is possible!!!!!
70 //------------------------------------------------------------------------
71 #include "signal.h"
72 static int endLoop = 0;
73
74 void sigHandler(int signo)
75 {
76    endLoop = 1;
77 }
78 //------------------------------------------------------------------------
79
80 //const char* gPersDbusAdminInterface    =  "org.genivi.persistence.admin";
81 //const char* gPersDbusAdminPath         = "/org/genivi/persistence/admin";
82
83
84
85 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
86
87
88 /* function to unregister ojbect path message handler */
89 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
90 {
91    printf("unregisterObjectPath\n");
92 }
93
94 /* catches messages not directed to any registered object path ("garbage collector") */
95 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
96 {
97    printf("handleObjectPathMessageFallback '%s' -> '%s'\n", dbus_message_get_interface(message), dbus_message_get_member(message) );
98    return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
99 }
100
101
102
103 static void  unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
104 {
105    printf("unregisterObjectPathFallback\n");
106 }
107
108
109
110 void* run_mainloop(void* dataPtr)
111 {
112    // lock mutex to make sure dbus main loop is running
113    pthread_mutex_lock(&gDbusInitializedMtx);
114
115    // persistence admin message
116    static const struct DBusObjectPathVTable vtablePersAdmin
117       = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
118
119    // lifecycle message
120    static const struct DBusObjectPathVTable vtableLifecycle
121       = {unregisterMessageHandler, checkLifecycleMsg, NULL, };
122
123    // fallback
124    static const struct DBusObjectPathVTable vtableFallback
125       = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
126
127    // setup the dbus
128    mainLoop(vtablePersAdmin, vtableLifecycle, vtableFallback, dataPtr);
129
130    printf("Exit dbus main loop!!!!\n");
131
132    return NULL;
133 }
134
135
136
137 int setup_dbus_mainloop(void)
138 {
139    int rval = 0;
140    pthread_t thread;
141    DBusError err;
142    const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
143    dbus_error_init(&err);
144
145    // Connect to the bus and check for errors
146    if(pAddress != NULL)
147    {
148       printf("Use specific dbus address: %s\n !", pAddress);
149       gDbusConn = dbus_connection_open(pAddress, &err);
150
151       if(gDbusConn != NULL)
152       {
153          if(!dbus_bus_register(gDbusConn, &err))
154          {
155             printf("dbus_bus_register() Error %s\n", err.message);
156             dbus_error_free (&err);
157             return -1;
158          }
159          else
160          {
161             printf("Registered connection successfully !\n");
162          }
163       }
164       else
165       {
166          printf("dbus_connection_open() Error %s\n",err.message);
167          dbus_error_free(&err);
168       }
169    }
170    else
171    {
172       printf("Use default dbus bus!!!!!!\n");
173       gDbusConn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
174    }
175
176    // create here the dbus connection and pass to main loop
177    rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
178
179    if (rval)
180    {
181      fprintf(stderr, "Server: - ERROR! pthread_create( run_mainloop ) returned: %d\n", rval);
182    }
183    return rval;
184 }
185
186
187
188
189
190 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
191 {
192    dbus_bool_t result = FALSE;
193
194    //printf("addWatch called @%08x flags: %08x enabled: %c\n", (unsigned int)watch, dbus_watch_get_flags(watch), TRUE==dbus_watch_get_enabled(watch)?'x':'-');
195
196    if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
197    {
198       int flags = dbus_watch_get_flags(watch);
199
200       gPollInfo.watches[gPollInfo.nfds] = watch;
201
202       gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
203
204       if (TRUE==dbus_watch_get_enabled(watch))
205       {
206          if (flags&DBUS_WATCH_READABLE)
207          {
208             gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
209          }
210          if (flags&DBUS_WATCH_WRITABLE)
211          {
212             gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
213          }
214
215          ++gPollInfo.nfds;
216       }
217
218       result = TRUE;
219    }
220
221    return result;
222 }
223
224
225
226 static void removeWatch(DBusWatch *watch, void *data)
227 {
228    printf("removeWatch called @0x%08x\n", (int)watch);
229 }
230
231
232
233 static void watchToggled(DBusWatch *watch, void *data)
234 {
235    printf("watchToggled called @0x%08x\n", (int)watch);
236 }
237
238
239
240 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
241              DBusObjectPathVTable vtableFallback, void* userData)
242 {
243    DBusError err;
244
245    signal(SIGTERM, sigHandler);
246    signal(SIGQUIT, sigHandler);
247    signal(SIGINT,  sigHandler);
248
249    DBusConnection* conn = (DBusConnection*)userData;
250
251    dbus_error_init(&err);
252
253    if (dbus_error_is_set(&err))
254    {
255       printf("Connection Error (%s)\n", err.message);
256       dbus_error_free(&err);
257    }
258    else if (NULL != conn)
259    {
260       dbus_connection_set_exit_on_disconnect (conn, FALSE);
261
262       printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
263
264       if (0!=pipe(gPipefds))
265       {
266          printf("pipe() failed w/ errno %d\n", errno);
267       }
268       else
269       {
270          int ret;
271          int bContinue = 0;
272          memset(&gPollInfo, 0 , sizeof(gPollInfo));
273
274          gPollInfo.nfds = 1;
275          gPollInfo.fds[0].fd = gPipefds[0];
276          gPollInfo.fds[0].events = POLLIN;
277
278          if (   (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/adminconsumer", &vtable, userData))
279              && (TRUE==dbus_connection_register_object_path(conn, "/com/contiautomotive/NodeStateManager/LifecycleConsumer", &vtable2, userData))
280              && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
281          {
282             if (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
283             {
284                printf("dbus_connection_set_watch_functions() failed\n");
285             }
286             else
287             {
288                char buf[64];
289
290                // minloop is running now, release mutex
291                pthread_mutex_unlock(&gDbusInitializedMtx);
292                do
293                {
294                   bContinue = 0; /* assume error */
295
296                   while (DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
297
298                   while ((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, 500)))&&(EINTR==errno));
299
300                   if(0>ret)
301                   {
302                      printf("poll() failed w/ errno %d\n", errno);
303                   }
304                   else
305                   {
306                      int i;
307                      bContinue = 1;
308
309                      for (i=0; gPollInfo.nfds>i; ++i)
310                      {
311                         if (0!=gPollInfo.fds[i].revents)
312                         {
313                            if (gPollInfo.fds[i].fd==gPipefds[0])
314                            {
315                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
316                               {
317                                  bContinue = TRUE;
318                                  while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
319                                  if (0>ret)
320                                  {
321                                     printf("read() failed w/ errno %d\n", errno);
322                                  }
323                                  else if (sizeof(int)==ret)
324                                  {
325                                     switch (buf[0])
326                                     {
327                                        case CMD_PAS_BLOCK_AND_WRITE_BACK:
328                                           process_block_and_write_data_back();
329                                           break;
330                                        case CMD_LC_PREPARE_SHUTDOWN:
331                                           process_prepare_shutdown(buf[1]);
332                                           break;
333                                        case CMD_QUIT:
334                                           bContinue = FALSE;
335                                           break;
336                                        default:
337                                           printf("command %d not handled!\n", buf[0]);
338                                           break;
339                                     }
340                                  }
341                                  else
342                                  {
343                                     printf("read() returned %d (%s)\n", ret, buf);
344                                  }
345                               }
346                            }
347                            else
348                            {
349                               int flags = 0;
350                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
351                               {
352                                  flags |= DBUS_WATCH_READABLE;
353                               }
354                               if (0!=(gPollInfo.fds[i].revents & POLLOUT))
355                               {
356                                  flags |= DBUS_WATCH_WRITABLE;
357                               }
358                               if (0!=(gPollInfo.fds[i].revents & POLLERR))
359                               {
360                                  flags |= DBUS_WATCH_ERROR;
361                               }
362                               if (0!=(gPollInfo.fds[i].revents & POLLHUP))
363                               {
364                                  flags |= DBUS_WATCH_HANGUP;
365                               }
366                               //printf("handle watch @0x%08x flags: %04x\n", (int)gPollInfo.watches[i], flags);
367                               bContinue = dbus_watch_handle(gPollInfo.watches[i], flags);
368                            }
369                         }
370                      }
371                   }
372                   if(endLoop == 1)
373                      break;
374                }
375                while (0!=bContinue);
376             }
377             dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/adminconsumer");
378             //dbus_connection_unregister_object_path(conn, "/com/");
379             dbus_connection_unregister_object_path(conn, "/");
380          }
381          close(gPipefds[1]);
382          close(gPipefds[0]);
383       }
384       dbus_connection_unref(conn);
385       dbus_shutdown();
386    }
387    return 0;
388 }
389