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