d714e552e1ed9c57da56df10dfd96da98caa7f5e
[profile/ivi/persistence-client-library.git] / test / persistence_admin_service_mockup.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_admin_service_mockup.c
13  * @ingroup        Persistence client library test
14  * @author         Ingo Huerner
15  * @brief          Persistence Administration Serivce mockup
16  * @see            
17  */
18
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <unistd.h>     /* exit */
24 #include <check.h>
25 #include <time.h>
26 #include <fcntl.h>
27 #include <sys/mman.h>
28 #include <dbus/dbus.h>
29 #include <poll.h>
30 #include <pthread.h>
31 #include <sys/eventfd.h>
32
33
34 /// command definitions for main loop
35 typedef enum ECmd
36 {
37    CMD_NONE = 0,                    /// command none
38    CMD_PAS_BLOCK_AND_WRITE_BACK,    /// command block access and write data back
39    CMD_LC_PREPARE_SHUTDOWN,         /// command to prepare shutdown
40    CMD_QUIT,                         /// quit command
41    CMD_REQUEST_NAME
42 } tCmd;
43
44
45 /// pipe file descriptors
46 int gEfds;
47
48
49
50 pthread_mutex_t gDbusInitializedMtx  = PTHREAD_MUTEX_INITIALIZER;
51 pthread_cond_t  gDbusInitializedCond = PTHREAD_COND_INITIALIZER;
52
53 /// polling structure
54 typedef struct SPollInfo
55 {
56    int nfds;
57    struct pollfd fds[10];
58    DBusWatch * watches[10];
59 } tPollInfo;
60
61
62 /// polling information
63 static tPollInfo gPollInfo;
64
65
66 /// dbus connection
67 DBusConnection* gDbusConn = NULL;
68
69
70 DBusConnection* get_dbus_connection(void)
71 {
72    return gDbusConn;
73 }
74
75 //------------------------------------------------------------------------
76 // debugging only until "correct" exit of main loop is possible!!!!!
77 //------------------------------------------------------------------------
78 #include "signal.h"
79 static int endLoop = 0;
80
81 void sigHandler(int signo)
82 {
83    endLoop = 1;
84 }
85 //------------------------------------------------------------------------
86
87
88
89 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
90
91
92
93 int checkAdminMsg(DBusConnection *connection, DBusMessage *message)
94 {
95    char* busName   = NULL;
96    char* objName = NULL;
97    int32_t  notificationFlag = 0;
98    uint32_t gTimeoutMs = 0;
99    int msgReturn = 123321;
100
101    DBusMessage *reply;
102    DBusError error;
103    dbus_error_init (&error);
104
105    if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &busName,  // bus name
106                                                 DBUS_TYPE_STRING, &objName,
107                                                 DBUS_TYPE_INT32,  &notificationFlag,
108                                                 DBUS_TYPE_UINT32, &gTimeoutMs,
109                                                 DBUS_TYPE_INVALID))
110    {
111       reply = dbus_message_new_error(message, error.name, error.message);
112
113       if (reply == 0)
114       {
115          //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
116          printf("DBus No memory\n");
117       }
118
119       if (!dbus_connection_send(connection, reply, 0))
120       {
121          //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
122          printf("DBus No memory\n");
123       }
124
125       dbus_message_unref(reply);
126
127       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
128    }
129
130
131    printf("   checkAdminMsg ==> busName: %s | objName: %s | notificationFlag: %u | gTimeoutMs: %d\n\n", busName, objName, notificationFlag, gTimeoutMs);
132    reply = dbus_message_new_method_return(message);
133
134    if (reply == 0)
135    {
136      //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
137       printf("DBus No memory\n");
138    }
139
140    if (!dbus_message_append_args(reply, DBUS_TYPE_INT32, &msgReturn, DBUS_TYPE_INVALID))
141    {
142      //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
143       printf("DBus No memory\n");
144    }
145
146    if (!dbus_connection_send(connection, reply, NULL))
147    {
148      //DLT_LOG(mgrContext, DLT_LOG_ERROR, DLT_STRING("DBus No memory"));
149       printf("DBus No memory\n");
150    }
151
152    dbus_connection_flush(connection);
153    dbus_message_unref(reply);
154
155    return DBUS_HANDLER_RESULT_HANDLED;
156 }
157
158
159
160 DBusHandlerResult checkPersAdminMsg(DBusConnection * connection, DBusMessage * message, void * user_data)
161 {
162    DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
163
164    //printf("checkPersAdminMsg '%s' -> '%s'\n", dbus_message_get_interface(message), dbus_message_get_member(message));
165    if((0==strcmp("org.genivi.persistence.admin", dbus_message_get_interface(message))))
166    {
167       if((0==strcmp("RegisterPersAdminNotification", dbus_message_get_member(message))))
168       {
169          printf(" ==> org.genivi.persistence.admin - received - ==> RegisterPersAdminNotification \n");
170
171          result = checkAdminMsg(connection, message);
172       }
173       else if((0==strcmp("UnRegisterPersAdminNotification", dbus_message_get_member(message))))
174       {
175          printf(" ==> org.genivi.persistence.admin - received - ==> UnRegisterPersAdminNotification \n");
176
177          result = checkAdminMsg(connection, message);
178       }
179       else
180       {
181          printf(" ==> org.genivi.persistence.admin - received U N KN O W N-'%s'\n", dbus_message_get_interface(message));
182       }
183    }
184    else
185    {
186       printf(" ==> org.genivi.persistence - received U N KN O W N-'%s'\n", dbus_message_get_interface(message));
187    }
188    return result;
189 }
190
191
192 /* function to unregister ojbect path message handler */
193 static void unregisterMessageHandler(DBusConnection *connection, void *user_data)
194 {
195    printf("unregisterObjectPath\n");
196 }
197
198 /* catches messages not directed to any registered object path ("garbage collector") */
199 static DBusHandlerResult handleObjectPathMessageFallback(DBusConnection * connection, DBusMessage * message, void * user_data)
200 {
201    DBusHandlerResult result = DBUS_HANDLER_RESULT_HANDLED;
202
203    printf("handleObjectPathMessageFallback Object: '%s' -> Interface: '%s' -> Message: '%s'\n",
204           dbus_message_get_sender(message), dbus_message_get_interface(message), dbus_message_get_member(message) );
205
206    return result;
207 }
208
209
210
211 static void  unregisterObjectPathFallback(DBusConnection *connection, void *user_data)
212 {
213    printf("unregisterObjectPathFallback\n");
214 }
215
216
217
218
219
220
221 static dbus_bool_t addWatch(DBusWatch *watch, void *data)
222 {
223    dbus_bool_t result = FALSE;
224
225    //printf("addWatch called @%08x flags: %08x enabled: %c\n", (unsigned int)watch, dbus_watch_get_flags(watch), TRUE==dbus_watch_get_enabled(watch)?'x':'-');
226
227    if (ARRAY_SIZE(gPollInfo.fds)>gPollInfo.nfds)
228    {
229       int flags = dbus_watch_get_flags(watch);
230
231       gPollInfo.watches[gPollInfo.nfds] = watch;
232
233       gPollInfo.fds[gPollInfo.nfds].fd = dbus_watch_get_unix_fd(watch);
234
235       if (TRUE==dbus_watch_get_enabled(watch))
236       {
237          if (flags&DBUS_WATCH_READABLE)
238          {
239             gPollInfo.fds[gPollInfo.nfds].events |= POLLIN;
240          }
241          if (flags&DBUS_WATCH_WRITABLE)
242          {
243             gPollInfo.fds[gPollInfo.nfds].events |= POLLOUT;
244          }
245
246          ++gPollInfo.nfds;
247          /* wakeup main-loop, just in case */
248          static const uint64_t cmd = CMD_REQUEST_NAME;
249          if (sizeof(uint64_t)!=write(gEfds, &cmd, sizeof(uint64_t)))
250          {
251             fprintf(stderr, "write failed w/ errno %d\n", errno);
252          }
253       }
254
255       result = TRUE;
256    }
257
258    return result;
259 }
260
261
262 static void removeWatch(DBusWatch *watch, void *data)
263 {
264    void* w_data = dbus_watch_get_data(watch);
265
266    printf("removeWatch called @0x%08x\n", (int)watch);
267
268    if(w_data)
269       free(w_data);
270
271    dbus_watch_set_data(watch, NULL, NULL);
272 }
273
274
275 static void watchToggled(DBusWatch *watch, void *data)
276 {
277    printf("watchToggled called @0x%08x\n", (int)watch);
278
279    if(dbus_watch_get_enabled(watch))
280       addWatch(watch, data);
281    else
282       removeWatch(watch, data);
283 }
284
285
286 int mainLoop(DBusObjectPathVTable vtable, DBusObjectPathVTable vtableFallback, void* userData)
287 {
288    DBusError err;
289    // lock mutex to make sure dbus main loop is running
290    pthread_mutex_lock(&gDbusInitializedMtx);
291
292    signal(SIGTERM, sigHandler);
293    signal(SIGQUIT, sigHandler);
294    signal(SIGINT,  sigHandler);
295
296    DBusConnection* conn = (DBusConnection*)userData;
297    dbus_error_init(&err);
298
299    if (dbus_error_is_set(&err))
300    {
301       printf("Connection Error (%s)\n", err.message);
302       dbus_error_free(&err);
303    }
304    else if (NULL != conn)
305    {
306       dbus_connection_set_exit_on_disconnect (conn, FALSE);
307       printf("connected as '%s'\n", dbus_bus_get_unique_name(conn));
308       if (-1 == (gEfds = eventfd(0, 0)))
309       {
310          printf("eventfd() failed w/ errno %d\n", errno);
311       }
312       else
313       {
314          int ret;
315          int bContinue = 0;
316          memset(&gPollInfo, 0 , sizeof(gPollInfo));
317
318          gPollInfo.nfds = 1;
319          gPollInfo.fds[0].fd = gEfds;
320          gPollInfo.fds[0].events = POLLIN;
321
322          // register for messages
323          if (   (TRUE==dbus_connection_register_object_path(conn, "/org/genivi/persistence/admin", &vtable, userData))
324              && (TRUE==dbus_connection_register_fallback(conn, "/", &vtableFallback, userData)) )
325          {
326             if (TRUE!=dbus_connection_set_watch_functions(conn, addWatch, removeWatch, watchToggled, NULL, NULL))
327             {
328                printf("dbus_connection_set_watch_functions() failed\n");
329             }
330             else
331             {
332                uint16_t buf[64];
333
334                pthread_cond_signal(&gDbusInitializedCond);
335                pthread_mutex_unlock(&gDbusInitializedMtx);
336                do
337                {
338                   bContinue = 0; /* assume error */
339
340                   while(DBUS_DISPATCH_DATA_REMAINS==dbus_connection_dispatch(conn));
341
342                   while((-1==(ret=poll(gPollInfo.fds, gPollInfo.nfds, 500)))&&(EINTR==errno));
343
344                   if(0>ret)
345                   {
346                      printf("poll() failed w/ errno %d\n", errno);
347                   }
348                   else
349                   {
350                      int i;
351                      bContinue = 1;
352
353                      for (i=0; gPollInfo.nfds>i; ++i)
354                      {
355                         if (0!=gPollInfo.fds[i].revents)
356                         {
357                            if (gPollInfo.fds[i].fd==gEfds)
358                            {
359                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
360                               {
361                                  bContinue = TRUE;
362                                  while ((-1==(ret=read(gPollInfo.fds[i].fd, buf, 64)))&&(EINTR==errno));
363                                  if (0>ret)
364                                  {
365                                     printf("read() failed w/ errno %d | %s\n", errno, strerror(errno));
366                                  }
367                                  else if (ret != -1)
368                                  {
369                                     switch (buf[0])
370                                     {
371                                     case CMD_REQUEST_NAME:
372                                        if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER !=dbus_bus_request_name(conn, "org.genivi.persistence.admin", DBUS_NAME_FLAG_DO_NOT_QUEUE, &err))
373                                        {
374                                           fprintf(stderr, "Cannot acquire name 'org.genivi.persistence.admin': \n    \"(%s)\". Bailing out!\n", err.message);
375                                           dbus_error_free(&err);
376                                           bContinue = FALSE;
377                                        }
378                                        break;
379                                        case CMD_QUIT:
380                                           bContinue = FALSE;
381                                           break;
382                                        default:
383                                           printf("command %d not handled!\n", buf[0]);
384                                           break;
385                                     }
386                                  }
387                               }
388                            }
389                            else
390                            {
391                               int flags = 0;
392                               if (0!=(gPollInfo.fds[i].revents & POLLIN))
393                               {
394                                  flags |= DBUS_WATCH_READABLE;
395                               }
396                               if (0!=(gPollInfo.fds[i].revents & POLLOUT))
397                               {
398                                  flags |= DBUS_WATCH_WRITABLE;
399                               }
400                               if (0!=(gPollInfo.fds[i].revents & POLLERR))
401                               {
402                                  flags |= DBUS_WATCH_ERROR;
403                               }
404                               if (0!=(gPollInfo.fds[i].revents & POLLHUP))
405                               {
406                                  flags |= DBUS_WATCH_HANGUP;
407                               }
408                               //printf("handle watch @0x%08x flags: %04x\n", (int)gPollInfo.watches[i], flags);
409                               bContinue = dbus_watch_handle(gPollInfo.watches[i], flags);
410                            }
411                         }
412                      }
413                   }
414                   if(endLoop == 1)
415                      break;
416                }
417                while (0!=bContinue);
418             }
419             dbus_connection_unregister_object_path(conn, "/org/genivi/persistence/admin");
420             dbus_connection_unregister_object_path(conn, "/");
421          }
422          close(gEfds);
423       }
424       //dbus_connection_close(conn);
425       dbus_connection_unref(conn);
426       dbus_shutdown();
427    }
428
429    pthread_cond_signal(&gDbusInitializedCond);
430    pthread_mutex_unlock(&gDbusInitializedMtx);
431    return 0;
432 }
433
434
435 void* run_mainloop(void* dataPtr)
436 {
437    // persistence admin message
438    static const struct DBusObjectPathVTable vtablePersAdmin
439       = {unregisterMessageHandler, checkPersAdminMsg, NULL, };
440
441    // fallback
442    static const struct DBusObjectPathVTable vtableFallback
443       = {unregisterObjectPathFallback, handleObjectPathMessageFallback, NULL, };
444
445    // setup the dbus
446    mainLoop(vtablePersAdmin, vtableFallback, dataPtr);
447
448    printf("Exit dbus main loop!!!!\n");
449
450    return NULL;
451 }
452
453
454 int setup_dbus_mainloop(void)
455 {
456    int rval = 0;
457    pthread_t thread;
458    DBusError err;
459    const char *pAddress = getenv("PERS_CLIENT_DBUS_ADDRESS");
460    dbus_error_init(&err);
461
462    // enable locking of data structures in the D-Bus library for multi threading.
463    dbus_threads_init_default();
464
465    // Connect to the bus and check for errors
466    if(pAddress != NULL)
467    {
468       printf("Use specific dbus address: %s\n !", pAddress);
469       gDbusConn = dbus_connection_open_private(pAddress, &err);
470
471       if(gDbusConn != NULL)
472       {
473          if(!dbus_bus_register(gDbusConn, &err))
474          {
475             printf("dbus_bus_register() Error %s\n", err.message);
476             dbus_error_free (&err);
477             return -1;
478          }
479          else
480          {
481             printf("Registered connection successfully !\n");
482          }
483       }
484       else
485       {
486          printf("dbus_connection_open() Error %s\n",err.message);
487          dbus_error_free(&err);
488       }
489    }
490    else
491    {
492       printf("Use default dbus bus!!!!!!\n");
493       gDbusConn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
494    }
495
496    // wain until dbus main loop has been setup and running
497    pthread_mutex_lock(&gDbusInitializedMtx);
498
499    // create here the dbus connection and pass to main loop
500    rval = pthread_create(&thread, NULL, run_mainloop, gDbusConn);
501    if(rval)
502    {
503      fprintf(stderr, "Server: - ERROR! pthread_create( run_mainloop ) returned: %d\n", rval);
504    }
505
506    // wait for condition variable
507    pthread_cond_wait(&gDbusInitializedCond, &gDbusInitializedMtx);
508
509    pthread_mutex_unlock(&gDbusInitializedMtx);
510    return rval;
511 }
512
513
514
515 int main(int argc, char *argv[])
516 {
517    setup_dbus_mainloop();
518
519    printf("Wait, press enter to exit!!\n");
520    getchar();
521    printf("Exiting Persistence Admin mockup!!\n");
522
523    return 0;
524 }
525