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