New release 0.2.3, for 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    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    // enable locking of data structures in the D-Bus library for multi threading.
146    dbus_threads_init_default();
147
148    // Connect to the bus and check for errors
149    if(pAddress != NULL)
150    {
151       printf("Use specific dbus address: %s\n !", pAddress);
152       gDbusConn = dbus_connection_open(pAddress, &err);
153
154       if(gDbusConn != NULL)
155       {
156          if(!dbus_bus_register(gDbusConn, &err))
157          {
158             printf("dbus_bus_register() Error %s\n", err.message);
159             dbus_error_free (&err);
160             return -1;
161          }
162          else
163          {
164             printf("Registered connection successfully !\n");
165          }
166       }
167       else
168       {
169          printf("dbus_connection_open() Error %s\n",err.message);
170          dbus_error_free(&err);
171       }
172    }
173    else
174    {
175       printf("Use default dbus bus!!!!!!\n");
176       gDbusConn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
177    }
178
179    // create here the dbus connection and pass to main loop
180    rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
181
182    if (rval)
183    {
184      fprintf(stderr, "Server: - ERROR! pthread_create( run_mainloop ) returned: %d\n", rval);
185    }
186    return rval;
187 }
188
189
190
191
192
193 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
194 {
195    dbus_bool_t result = FALSE;
196
197    //printf("addWatch called @%08x flags: %08x enabled: %c\n", (unsigned int)watch, dbus_watch_get_flags(watch), TRUE==dbus_watch_get_enabled(watch)?'x':'-');
198
199    if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
200    {
201       int flags = dbus_watch_get_flags(watch);
202
203       gPollInfo.watches[gPollInfo.nfds] = watch;
204
205       gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
206
207       if (TRUE==dbus_watch_get_enabled(watch))
208       {
209          if (flags&DBUS_WATCH_READABLE)
210          {
211             gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
212          }
213          if (flags&DBUS_WATCH_WRITABLE)
214          {
215             gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
216          }
217
218          ++gPollInfo.nfds;
219       }
220
221       result = TRUE;
222    }
223
224    return result;
225 }
226
227
228
229 static void removeWatch(DBusWatch *watch, void *data)
230 {
231    printf("removeWatch called @0x%08x\n", (int)watch);
232 }
233
234
235
236 static void watchToggled(DBusWatch *watch, void *data)
237 {
238    printf("watchToggled called @0x%08x\n", (int)watch);
239 }
240
241
242
243 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtable2,
244              DBusObjectPathVTable vtableFallback, void* userData)
245 {
246    DBusError err;
247
248    signal(SIGTERM, sigHandler);
249    signal(SIGQUIT, sigHandler);
250    signal(SIGINT,  sigHandler);
251
252    DBusConnection* conn = (DBusConnection*)userData;
253
254    dbus_error_init(&err);
255
256    if (dbus_error_is_set(&err))
257    {
258       printf("Connection Error (%s)\n", err.message);
259       dbus_error_free(&err);
260    }
261    else if (NULL != conn)
262    {
263       dbus_connection_set_exit_on_disconnect (conn, FALSE);
264
265       printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
266
267       if (0!=pipe(gPipefds))
268       {
269          printf("pipe() failed w/ errno %d\n", errno);
270       }
271       else
272       {
273          int ret;
274          int bContinue = 0;
275          memset(&gPollInfo, 0 , sizeof(gPollInfo));
276
277          gPollInfo.nfds = 1;
278          gPollInfo.fds[0].fd = gPipefds[0];
279          gPollInfo.fds[0].events = POLLIN;
280
281          if (   (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/adminconsumer", &vtable, userData))
282              && (TRUE==dbus_connection_register_object_path(conn, "/com/contiautomotive/NodeStateManager/LifecycleConsumer", &vtable2, userData))
283              && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
284          {
285             if (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
286             {
287                printf("dbus_connection_set_watch_functions() failed\n");
288             }
289             else
290             {
291                char buf[64];
292
293                // minloop is running now, release mutex
294                pthread_mutex_unlock(&gDbusInitializedMtx);
295                do
296                {
297                   bContinue = 0; /* assume error */
298
299                   while (DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
300
301                   while ((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, 500)))&&(EINTR==errno));
302
303                   if(0>ret)
304                   {
305                      printf("poll() failed w/ errno %d\n", errno);
306                   }
307                   else
308                   {
309                      int i;
310                      bContinue = 1;
311
312                      for (i=0; gPollInfo.nfds>i; ++i)
313                      {
314                         if (0!=gPollInfo.fds[i].revents)
315                         {
316                            if (gPollInfo.fds[i].fd==gPipefds[0])
317                            {
318                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
319                               {
320                                  bContinue = TRUE;
321                                  while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
322                                  if (0>ret)
323                                  {
324                                     printf("read() failed w/ errno %d\n", errno);
325                                  }
326                                  else if (sizeof(int)==ret)
327                                  {
328                                     switch (buf[0])
329                                     {
330                                        case CMD_PAS_BLOCK_AND_WRITE_BACK:
331                                           process_block_and_write_data_back();
332                                           break;
333                                        case CMD_LC_PREPARE_SHUTDOWN:
334                                           process_prepare_shutdown(buf[1]);
335                                           break;
336                                        case CMD_QUIT:
337                                           bContinue = FALSE;
338                                           break;
339                                        default:
340                                           printf("command %d not handled!\n", buf[0]);
341                                           break;
342                                     }
343                                  }
344                                  else
345                                  {
346                                     printf("read() returned %d (%s)\n", ret, buf);
347                                  }
348                               }
349                            }
350                            else
351                            {
352                               int flags = 0;
353                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
354                               {
355                                  flags |= DBUS_WATCH_READABLE;
356                               }
357                               if (0!=(gPollInfo.fds[i].revents & POLLOUT))
358                               {
359                                  flags |= DBUS_WATCH_WRITABLE;
360                               }
361                               if (0!=(gPollInfo.fds[i].revents & POLLERR))
362                               {
363                                  flags |= DBUS_WATCH_ERROR;
364                               }
365                               if (0!=(gPollInfo.fds[i].revents & POLLHUP))
366                               {
367                                  flags |= DBUS_WATCH_HANGUP;
368                               }
369                               //printf("handle watch @0x%08x flags: %04x\n", (int)gPollInfo.watches[i], flags);
370                               bContinue = dbus_watch_handle(gPollInfo.watches[i], flags);
371                            }
372                         }
373                      }
374                   }
375                   if(endLoop == 1)
376                      break;
377                }
378                while (0!=bContinue);
379             }
380             dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/adminconsumer");
381             //dbus_connection_unregister_object_path(conn, "/com/");
382             dbus_connection_unregister_object_path(conn, "/");
383          }
384          close(gPipefds[1]);
385          close(gPipefds[0]);
386       }
387       dbus_connection_unref(conn);
388       dbus_shutdown();
389    }
390    return 0;
391 }
392