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