Move from mulit-threaded to single-threaded dbus communication
[profile/ivi/persistence-client-library.git] / src / persistence_client_library_dbus_cmd.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_cmd.c
13  * @ingroup        Persistence client library
14  * @author         Ingo Huerner
15  * @brief          Implementation of the persistence client library dbus commands.
16  * @see
17  */
18
19 #include "persistence_client_library_dbus_cmd.h"
20
21 #include "persistence_client_library_handle.h"
22 #include "persistence_client_library_itzam_errors.h"
23 #include "persistence_client_library_custom_loader.h"
24 #include "persistence_client_library_prct_access.h"
25
26 #include "../include_protected/persistence_client_library_data_organization.h"
27 #include "../include_protected/persistence_client_library_db_access.h"
28
29 #include <itzam.h>
30
31
32 // function prototype
33 void msg_pending_func(DBusPendingCall *call, void *data);
34
35
36
37 void process_reg_notification_signal(DBusConnection* conn)
38 {
39    char ruleChanged[DbusMatchRuleSize] = {0};
40    char ruleDeleted[DbusMatchRuleSize] = {0};
41    char ruleCreated[DbusMatchRuleSize] = {0};
42
43    // add match for  c h a n g e
44    snprintf(ruleChanged, DbusMatchRuleSize,
45             "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResChange',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'",
46             gRegNotifykey, gRegNotifyLdbid, gRegNotifyUserNo, gRegNotifySeatNo);
47
48    // add match for  d e l e t e
49    snprintf(ruleDeleted, DbusMatchRuleSize,
50             "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResDelete',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'",
51             gRegNotifykey, gRegNotifyLdbid, gRegNotifyUserNo, gRegNotifySeatNo);
52
53    // add match for  c r e a t e
54    snprintf(ruleCreated, DbusMatchRuleSize,
55             "type='signal',interface='org.genivi.persistence.adminconsumer',member='PersistenceResCreate',path='/org/genivi/persistence/adminconsumer',arg0='%s',arg1='%u',arg2='%u',arg3='%u'",
56             gRegNotifykey, gRegNotifyLdbid, gRegNotifyUserNo, gRegNotifySeatNo);
57
58    if(gRegNotifyPolicy == Notify_register)
59    {
60       dbus_bus_add_match(conn, ruleChanged, NULL);
61       dbus_bus_add_match(conn, ruleDeleted, NULL);
62       dbus_bus_add_match(conn, ruleCreated, NULL);
63    }
64    else if(gRegNotifyPolicy == Notify_unregister)
65    {
66       dbus_bus_remove_match(conn, ruleChanged, NULL);
67       dbus_bus_remove_match(conn, ruleDeleted, NULL);
68       dbus_bus_remove_match(conn, ruleCreated, NULL);
69    }
70
71    dbus_connection_flush(conn);  // flush the connection to add the match
72 }
73
74
75
76 void process_send_notification_signal(DBusConnection* conn)
77 {
78    dbus_bool_t ret;
79    DBusMessage* message;
80    const char* notifyReason = NULL;
81
82    char ldbidArray[DbusSubMatchSize] = {0};
83    char userArray[DbusSubMatchSize]  = {0};
84    char seatArray[DbusSubMatchSize]  = {0};
85    char* pldbidArra = ldbidArray;
86    char* puserArray = userArray;
87    char* pseatArray = seatArray;
88    char* pnotifyKey = gSendNotifykey;
89
90    switch(gSendNotifyReason)
91    {
92       case pclNotifyStatus_deleted:
93          notifyReason = gDeleteSignal;
94          break;
95       case  pclNotifyStatus_created:
96          notifyReason = gCreateSignal;
97          break;
98       case pclNotifyStatus_changed:
99          notifyReason = gChangeSignal;
100          break;
101       default:
102          notifyReason = NULL;
103          break;
104    }
105
106    if(notifyReason != NULL)
107    {
108       // dbus_bus_add_match is used for the notification mechanism,
109       // and this works only for type DBUS_TYPE_STRING as message arguments
110       // this is the reason to use string instead of integer types directly
111       snprintf(ldbidArray, DbusSubMatchSize, "%d", gSendNotifyLdbid);
112       snprintf(userArray,  DbusSubMatchSize, "%d", gSendNotifyUserNo);
113       snprintf(seatArray,  DbusSubMatchSize, "%d", gSendNotifySeatNo);
114
115       //printf("process_send_Notification_Signal => key: %s | lbid: %d | gUserNo: %d | gSeatNo: %d | gReason: %d \n", gNotifykey, gLdbid, gUserNo, gSeatNo, gReason);
116       message = dbus_message_new_signal("/org/genivi/persistence/adminconsumer",    // const char *path,
117                                         "org.genivi.persistence.adminconsumer",     // const char *interface,
118                                         notifyReason);                                 // const char *name
119
120       ret = dbus_message_append_args(message, DBUS_TYPE_STRING, &pnotifyKey,
121                                               DBUS_TYPE_STRING, &pldbidArra,
122                                               DBUS_TYPE_STRING, &puserArray,
123                                               DBUS_TYPE_STRING, &pseatArray,
124                                               DBUS_TYPE_INVALID);
125       if(ret == TRUE)
126       {
127          // Send the signal
128          if(conn != NULL)
129          {
130             if(dbus_connection_send(conn, message, 0) == TRUE)
131             {
132                // Free the signal now we have finished with it
133                dbus_message_unref(message);
134             }
135             else
136             {
137                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("process_send_Notification_Signal ==> failed to send dbus message!!"));
138             }
139          }
140          else
141          {
142             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("process_send_Notification_Signal ==> E R R O R  C O N E C T I O N  NULL!!"));
143          }
144       }
145       else
146       {
147          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("process_send_Notification_Signal ==> ERROR dbus_message_append_args"));
148       }
149    }
150    else
151    {
152       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("process_send_Notification_Signal ==> ERROR invalid notification reason"));
153    }
154 }
155
156
157
158 void process_block_and_write_data_back(unsigned int requestID, unsigned int status)
159 {
160    // lock persistence data access
161    pers_lock_access();
162    // sync data back to memory device
163    pers_data_sync();
164    // send complete notification
165    pers_admin_service_data_sync_complete(requestID, status);
166 }
167
168
169
170 void process_prepare_shutdown(unsigned char requestId, unsigned int status)
171 {
172    int i = 0;
173    //GvdbTable* resourceTable = NULL;
174    itzam_btree* resourceTable = NULL;
175    itzam_state  state = ITZAM_FAILED;
176
177    // block write
178    pers_lock_access();
179
180    // flush open files to disk
181    for(i=0; i<MaxPersHandle; i++)
182    {
183       int tmp = i;
184       if(gOpenFdArray[tmp] == FileOpen)
185       {
186          fsync(tmp);
187          close(tmp);
188       }
189    }
190
191    // close open gvdb persistence resource configuration table
192    for(i=0; i< PrctDbTableSize; i++)
193    {
194      resourceTable = get_resource_cfg_table_by_idx(i);
195      // dereference opend database
196      if(resourceTable != NULL)
197      {
198         state = itzam_btree_close(resourceTable);
199         if (state != ITZAM_OKAY)
200         {
201            DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("process_prepare_shutdown => itzam_btree_close: Itzam problem"), DLT_STRING(STATE_MESSAGES[state]));
202         }
203      }
204    }
205
206    //close opend database
207    pers_db_close_all();
208
209
210    // unload custom client libraries
211    for(i=0; i<PersCustomLib_LastEntry; i++)
212    {
213       if(gPersCustomFuncs[i].custom_plugin_deinit != NULL)
214       {
215          // deinitialize plugin
216          gPersCustomFuncs[i].custom_plugin_deinit();
217          // close library handle
218          dlclose(gPersCustomFuncs[i].handle);
219       }
220    }
221
222    // notify lifecycle shutdown OK
223    send_prepare_shutdown_complete((int)requestId, (int)status);
224 }
225
226
227
228 void process_send_pas_request(DBusConnection* conn, unsigned int requestID, int status)
229 {
230    DBusError error;
231    DBusPendingCall* pending = NULL;
232    dbus_error_init (&error);
233    int rval = 0;
234
235    DBusMessage* message = dbus_message_new_method_call("org.genivi.persistence.admin",       // destination
236                                                       "/org/genivi/persistence/admin",       // path
237                                                        "org.genivi.persistence.admin",       // interface
238                                                        "PersistenceAdminRequestCompleted");  // method
239    if(message != NULL)
240    {
241       dbus_message_append_args(message, DBUS_TYPE_UINT32, &requestID,
242                                         DBUS_TYPE_INT32,  &status,
243                                         DBUS_TYPE_INVALID);
244
245       if(conn != NULL)
246       {
247          //replyMsg = dbus_connection_send_with_reply_and_block(conn, message, gTimeoutMs, &error);
248          dbus_connection_send_with_reply(conn,        //    the connection
249                                          message,       // the message to write
250                                          &pending,      // pending
251                                          gTimeoutMs);   // timeout in milliseconds or -1 for default
252
253          dbus_connection_flush(conn);
254
255          if(!dbus_pending_call_set_notify(pending, msg_pending_func, "PersistenceAdminRequestCompleted", NULL))
256          {
257             printf("process_send_pas_request => dbus_pending_call_set_notify: FAILED\n");
258          }
259          dbus_pending_call_unref(pending);
260       }
261       else
262       {
263          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_pas_request => ERROR: Invalid connection") );
264       }
265       dbus_message_unref(message);
266    }
267    else
268    {
269       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_pas_request => ERROR: Invalid message") );
270    }
271 }
272
273
274 void process_send_pas_register(DBusConnection* conn, int regType, int notificationFlag)
275 {
276    DBusError error;
277    dbus_error_init (&error);
278    DBusPendingCall* pending = NULL;
279
280    char* method = NULL;
281    printf("    process_send_pas_register => regType: %d | notificaiton flag: %d\n", regType, notificationFlag);
282
283    if(regType == 0)
284       method = "UnRegisterPersAdminNotification";
285    else if(regType == 1)
286       method = "RegisterPersAdminNotification";
287
288    if(conn != NULL)
289    {
290       const char* objName = "/org/genivi/persistence/adminconsumer";
291       const char* busName = dbus_bus_get_unique_name(conn);
292
293       if(busName != NULL)
294       {
295          DBusMessage* message = dbus_message_new_method_call("org.genivi.persistence.admin",    // destination
296                                                             "/org/genivi/persistence/admin",    // path
297                                                              "org.genivi.persistence.admin",    // interface
298                                                              method);                           // method
299
300          if(message != NULL)
301          {
302             dbus_message_append_args(message, DBUS_TYPE_STRING, &busName,  // bus name
303                                               DBUS_TYPE_STRING, &objName,
304                                               DBUS_TYPE_INT32,  &notificationFlag,
305                                               DBUS_TYPE_UINT32, &gTimeoutMs,
306                                               DBUS_TYPE_INVALID);
307
308             dbus_connection_send_with_reply(conn,           //    the connection
309                                             message,        // the message to write
310                                             &pending,       // pending
311                                             gTimeoutMs);    // timeout in milliseconds or -1 for default
312
313             dbus_connection_flush(conn);
314
315             if(!dbus_pending_call_set_notify(pending, msg_pending_func, method, NULL))
316             {
317                printf("process_send_pas_register => dbus_pending_call_set_notify: FAILED\n");
318             }
319             dbus_pending_call_unref(pending);
320          }
321          else
322          {
323             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_pas_register =>  ERROR: Invalid message") );
324          }
325          dbus_message_unref(message);
326       }
327       else
328       {
329          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_pas_register =>  ERROR: Invalid busname") );
330       }
331    }
332    else
333    {
334       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_pas_register =>  ERROR: Invalid connection") );
335    }
336 }
337
338
339 void process_send_lifecycle_register(DBusConnection* conn, int regType, int shutdownMode)
340 {
341    int rval = 0;
342
343    DBusError error;
344    dbus_error_init (&error);
345
346    char* method = NULL;
347    printf("    process_send_lifecycle_register => reg: %d | shutdownMode flag: %d\n", regType, shutdownMode);
348
349    if(regType == 1)
350       method = "RegisterShutdownClient";
351    else if(regType == 0)
352       method = "UnRegisterShutdownClient";
353
354    if(conn != NULL)
355    {
356       const char* objName = "/org/genivi/NodeStateManager/LifeCycleConsumer";
357       const char* busName = dbus_bus_get_unique_name(conn);
358
359       DBusMessage* message = dbus_message_new_method_call("org.genivi.NodeStateManager",           // destination
360                                                           "/org/genivi/NodeStateManager/Consumer", // path
361                                                           "org.genivi.NodeStateManager.Consumer",  // interface
362                                                           method);                                 // method
363       if(message != NULL)
364       {
365          if(regType == 1)   // register
366          {
367             dbus_message_append_args(message, DBUS_TYPE_STRING, &busName,
368                                               DBUS_TYPE_STRING, &objName,
369                                               DBUS_TYPE_UINT32, &shutdownMode,
370                                               DBUS_TYPE_UINT32, &gTimeoutMs, DBUS_TYPE_INVALID);
371          }
372          else           // unregister
373          {
374             dbus_message_append_args(message, DBUS_TYPE_STRING, &busName,
375                                               DBUS_TYPE_STRING, &objName,
376                                               DBUS_TYPE_UINT32, &shutdownMode, DBUS_TYPE_INVALID);
377          }
378
379          if(conn != NULL)
380          {
381             if(!dbus_connection_send(conn, message, 0))
382             {
383                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_register => Access denied"), DLT_STRING(error.message) );
384                rval = -1;
385             }
386             dbus_connection_flush(conn);
387          }
388          else
389          {
390             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_register => ERROR: Invalid connection"));
391             rval = -1;
392          }
393          dbus_message_unref(message);
394       }
395       else
396       {
397          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_register => ERROR: Invalid message"));
398       }
399    }
400    else
401    {
402       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_register => ERROR: connection isn NULL"));
403    }
404 }
405
406
407
408 void process_send_lifecycle_request(DBusConnection* conn, int requestId, int status)
409 {
410    int rval = 0;
411    DBusError error;
412    dbus_error_init (&error);
413
414    printf("    process_send_lifecycle_request => requestID: %d | status: %d\n", requestId, status);
415
416    if(conn != NULL)
417    {
418       DBusMessage* message = dbus_message_new_method_call("org.genivi.NodeStateManager",           // destination
419                                                          "/org/genivi/NodeStateManager/Consumer",  // path
420                                                           "org.genivi.NodeStateManager.Consumer",  // interface
421                                                           "LifecycleRequestComplete");             // method
422       if(message != NULL)
423       {
424          dbus_message_append_args(message, DBUS_TYPE_INT32, &requestId,
425                                            DBUS_TYPE_INT32, &status,
426                                            DBUS_TYPE_INVALID);
427
428          if(conn != NULL)
429          {
430             if(!dbus_connection_send(conn, message, 0))
431             {
432                DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_request => Access denied"), DLT_STRING(error.message) );
433                rval = -1;
434             }
435
436             dbus_connection_flush(conn);
437          }
438          else
439          {
440             DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_request => ERROR: Invalid connection"));
441             rval = -1;
442          }
443          dbus_message_unref(message);
444       }
445       else
446       {
447          DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_request => ERROR: Invalid message"));
448          rval = -1;
449       }
450    }
451    else
452    {
453       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("send_lifecycle_request => ERROR: connection isn NULL"));
454       rval = -1;
455    }
456 }
457
458
459
460 void msg_pending_func(DBusPendingCall *call, void *data)
461 {
462    int replyArg = -1;
463    DBusError err;
464    dbus_error_init(&err);
465
466    DBusMessage *message = dbus_pending_call_steal_reply(call);
467
468    if (dbus_set_error_from_message(&err, message))
469    {
470       DLT_LOG(gDLTContext, DLT_LOG_ERROR, DLT_STRING("msg_pending_func ==> Access denied") );
471    }
472    else
473    {
474       DLT_LOG(gDLTContext, DLT_LOG_INFO, DLT_STRING("msg_pending_func ==> UNlock mutex") );
475       dbus_message_get_args(message, &err, DBUS_TYPE_INT32, &replyArg, DBUS_TYPE_INVALID);
476    }
477
478    gDbusPendingRvalue = replyArg;   // set the return value
479    dbus_message_unref(message);
480
481    // unlock the mutex because we have received the reply to the dbus message
482    printf("msg_pending_func => mutex unlock: %s \n",(char*)(data));
483    pthread_mutex_unlock(&gDbusPendingRegMtx);
484    printf("msg_pending_func <= mutex unlock\n");
485 }
486
487
488
489