app: Change async call timeout to 120sec.
[platform/core/system/storaged.git] / apps / extended-sd / src / dbus-call.c
1 /*
2  * system-dbus
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <errno.h>
24 #include <stdarg.h>
25
26 #include "dbus-call.h"
27 #include "log-util.h"
28
29 #define DBUS_REPLY_TIMEOUT      (-1)
30 #define DBUS_MAXIMUM_NAME_LENGTH 255
31
32 struct pending_call_data {
33         dbus_pending_cb func;
34         void *data;
35 };
36
37 struct proxy_node {
38         GDBusProxy *proxy;
39         char *dest;
40         char *path;
41         char *interface;
42 };
43
44 static GList *proxy_pool;
45 static pthread_mutex_t dmutex = PTHREAD_MUTEX_INITIALIZER;
46 static int bus_init;
47 static guint signal_id = 0;
48
49 static int g_dbus_error_to_errno(int code)
50 {
51         /**
52          * if device is not supported,
53          * deviced does not register the method call of the device.
54          * in this case, dbus will return UNKNOWN_METHOD error.
55          */
56         /* refer to gio/gioenums.h */
57         if (code == G_DBUS_ERROR_ACCESS_DENIED)
58                 return -EACCES;
59         else if (code == G_DBUS_ERROR_UNKNOWN_METHOD)
60                 return -ENOTSUP;
61         return -ECOMM;
62 }
63
64 static GVariant *append_g_variant(const char *sig, char *param[])
65 {
66         GVariantBuilder builder;
67         GVariantBuilder *sub_builder;
68         GVariant *var;
69         struct dbus_int *array_int;
70         char *ch;
71         int i, j;
72
73         if (!sig || !param)
74                 return NULL;
75
76         g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE);
77
78         for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) {
79                 switch (*ch) {
80                 case 'i':
81                         g_variant_builder_add(&builder, "i", atoi(param[i]));
82                         break;
83                 case 'u':
84                         g_variant_builder_add(&builder, "u", strtoul(param[i], NULL, 10));
85                         break;
86                 case 't':
87                         g_variant_builder_add(&builder, "t", atoll(param[i]));
88                         break;
89                 case 's':
90                         g_variant_builder_add(&builder, "s", param[i]);
91                         break;
92                 case 'a':
93                         ++ch;
94                         switch (*ch) {
95                         case 'i':
96                                 sub_builder = g_variant_builder_new(G_VARIANT_TYPE("ai"));
97                                 array_int = (struct dbus_int *)param[i];
98                                 for (j = 0; j < array_int->size; j++)
99                                         g_variant_builder_add(sub_builder, "i", array_int->list[j]);
100                                 var = g_variant_new("ai", sub_builder);
101                                 g_variant_builder_unref(sub_builder);
102                                 g_variant_builder_add_value(&builder, var);
103                                 break;
104                         default:
105                                 break;
106                         }
107                         break;
108                 default:
109                         return NULL;
110                 }
111         }
112
113         return g_variant_builder_end(&builder);
114 }
115
116 static struct proxy_node *find_matched_proxy_node(const char *dest,
117                 const char *path,
118                 const char *interface)
119 {
120         GList *elem;
121         struct proxy_node *node;
122         int plen;
123
124         if (!dest || !path || !interface)
125                 return NULL;
126
127         plen = strlen(path) + 1;
128
129         /* find matched proxy object */
130         for (elem = proxy_pool; elem; elem = elem->next) {
131                 node = elem->data;
132                 if (!node)
133                         continue;
134                 if (!strncmp(node->dest, dest, DBUS_MAXIMUM_NAME_LENGTH) &&
135                     !strncmp(node->path, path, plen) &&
136                     !strncmp(node->interface, interface,
137                             DBUS_MAXIMUM_NAME_LENGTH))
138                         return node;
139         }
140
141         return NULL;
142 }
143
144 static void on_name_vanished(GDBusConnection *connection,
145                 const gchar *name,
146                 gpointer user_data)
147 {
148         GList *elem;
149         GList *next;
150         struct proxy_node *node;
151
152         pthread_mutex_lock(&dmutex);
153         for (elem = proxy_pool, next = g_list_next(elem); elem;
154                 elem = next, next = g_list_next(elem)) {
155                 node = elem->data;
156                 if (!node)
157                         continue;
158                 proxy_pool = g_list_delete_link(proxy_pool, elem);
159                 g_object_unref(node->proxy);
160                 free(node->dest);
161                 free(node->path);
162                 free(node->interface);
163                 free(node);
164         }
165         pthread_mutex_unlock(&dmutex);
166 }
167
168 static GDBusProxy *get_proxy_from_proxy_pool(const char *dest,
169                 const char *path,
170                 const char *interface,
171                 GError **err)
172 {
173         GDBusConnection *conn;
174         GDBusProxy *proxy;
175         struct proxy_node *node;
176
177         if (!dest || !path || !interface) {
178                 if (err)
179                         g_set_error(err, G_IO_ERROR,
180                                         G_IO_ERROR_INVALID_ARGUMENT,
181                                         "Cannot determine destination address");
182                 return NULL;
183         }
184
185         /* find matched proxy node in proxy pool */
186         node = find_matched_proxy_node(dest, path, interface);
187         if (node)
188                 return node->proxy;
189
190         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, err);
191         if (!conn)
192                 return NULL;
193
194         if (!bus_init) {
195                 bus_init++;
196                 g_bus_watch_name_on_connection(conn,
197                         STORAGED_BUS_NAME,
198                         G_BUS_NAME_WATCHER_FLAGS_NONE,
199                         NULL,
200                         on_name_vanished,
201                         NULL,
202                         NULL);
203         }
204
205         proxy = g_dbus_proxy_new_sync(conn,
206                         G_DBUS_PROXY_FLAGS_NONE,
207                         NULL,      /* GDBusinterfaceinfo */
208                         dest,      /* bus name */
209                         path,      /* object path */
210                         interface, /* interface name */
211                         NULL,      /* GCancellable */
212                         err);
213         if (!proxy)
214                 return NULL;
215
216         node = malloc(sizeof(struct proxy_node));
217         if (!node) {
218                 g_object_unref(proxy);
219                 if (err)
220                         g_set_error(err, G_IO_ERROR,
221                                         G_IO_ERROR_FAILED,
222                                         "Cannot allocate proxy_node memory");
223                 return NULL;
224         }
225
226         node->proxy = proxy;
227         node->dest = strdup(dest);
228         node->path = strdup(path);
229         node->interface = strdup(interface);
230
231         proxy_pool = g_list_append(proxy_pool, node);
232
233         return proxy;
234 }
235
236 int dbus_method_sync(const char *dest, const char *path,
237                 const char *interface, const char *method,
238                 const char *sig, char *param[])
239 {
240         GDBusProxy *proxy;
241         GError *err = NULL;
242         GVariant *output;
243         int result;
244
245 #if !GLIB_CHECK_VERSION(2, 35, 0)
246         g_type_init();
247 #endif
248
249         pthread_mutex_lock(&dmutex);
250         proxy = get_proxy_from_proxy_pool(dest, path, interface, &err);
251         if (!proxy) {
252                 pthread_mutex_unlock(&dmutex);
253                 DMSG_ERR("fail to get proxy from proxy pool : %s-%s (%d-%s)",
254                                 interface, method, err->code, err->message);
255                 result = g_dbus_error_to_errno(err->code);
256                 g_clear_error(&err);
257                 return result;
258         }
259
260         output = g_dbus_proxy_call_sync(proxy,
261                         method,                       /* method name */
262                         append_g_variant(sig, param), /* parameters */
263                         G_DBUS_CALL_FLAGS_NONE,
264                         DBUS_REPLY_TIMEOUT,           /* timeout */
265                         NULL,                         /* GCancellable */
266                         &err);
267         pthread_mutex_unlock(&dmutex);
268
269         if (!output) {
270                 if (!err) {
271                         DMSG_ERR("g_dbus_proxy_call_sync error : %s-%s",
272                                         interface, method);
273                         return -EPERM;
274                 }
275                 DMSG_ERR("g_dbus_proxy_call_sync error : %s-%s (%d-%s)",
276                                 interface, method, err->code, err->message);
277                 result = g_dbus_error_to_errno(err->code);
278                 g_clear_error(&err);
279                 return result;
280         }
281
282         /* get output value */
283         g_variant_get(output, "(i)", &result);
284
285         g_variant_unref(output);
286
287         return result;
288 }
289
290 int dbus_method_sync_with_reply(const char *dest,
291                 const char *path, const char *interface,
292                 const char *method, const char *sig,
293                 char *param[], GVariant **info)
294 {
295         GDBusProxy *proxy;
296         GError *err = NULL;
297         GVariant *output;
298         int result;
299
300 #if !GLIB_CHECK_VERSION(2, 35, 0)
301         g_type_init();
302 #endif
303
304         pthread_mutex_lock(&dmutex);
305         proxy = get_proxy_from_proxy_pool(dest, path, interface, &err);
306         if (!proxy) {
307                 pthread_mutex_unlock(&dmutex);
308                 _E("fail to get proxy from proxy pool : %s-%s (%d-%s)",
309                                 interface, method, err->code, err->message);
310                 result = g_dbus_error_to_errno(err->code);
311                 g_clear_error(&err);
312                 return result;
313         }
314
315         output = g_dbus_proxy_call_sync(proxy,
316                         method,                       /* method name */
317                         append_g_variant(sig, param), /* parameters */
318                         G_DBUS_CALL_FLAGS_NONE,
319                         DBUS_REPLY_TIMEOUT,           /* timeout */
320                         NULL,                         /* GCancellable */
321                         &err);
322         pthread_mutex_unlock(&dmutex);
323         if (!output) {
324                 if (!err) {
325                         _E("g_dbus_proxy_call_sync error : %s-%s",
326                                         interface, method);
327                         return -EPERM;
328                 }
329                 _E("g_dbus_proxy_call_sync error : %s-%s (%d-%s)",
330                                 interface, method, err->code, err->message);
331                 result = g_dbus_error_to_errno(err->code);
332                 g_clear_error(&err);
333                 return result;
334         }
335
336         *info = output;
337         return 0;
338 }
339
340 static void cb_pending(GDBusProxy *proxy,
341                 GAsyncResult *res,
342                 gpointer user_data)
343 {
344         struct pending_call_data *data = user_data;
345         GError *err = NULL;
346         GVariant *output;
347
348         output = g_dbus_proxy_call_finish(proxy,
349                         res, /* GAsyncResult */
350                         &err);
351         if (!output)
352                 DMSG_ERR("g_dbus_proxy_call_finish error : %d-%s",
353                                 err->code, err->message);
354
355         if (data && data->func)
356                 data->func(data->data, output, err);
357         free(data);
358
359         if (err)
360                 g_clear_error(&err);
361         if (output)
362                 g_variant_unref(output);
363 }
364
365 int dbus_method_async_with_reply(const char *dest, const char *path,
366                 const char *interface, const char *method,
367                 const char *sig, char *param[],
368                 dbus_pending_cb cb, int timeout, void *data)
369 {
370         GDBusProxy *proxy;
371         GError *err = NULL;
372         struct pending_call_data *pdata;
373         int result;
374
375 #if !GLIB_CHECK_VERSION(2, 35, 0)
376         g_type_init();
377 #endif
378
379         pthread_mutex_lock(&dmutex);
380         proxy = get_proxy_from_proxy_pool(dest, path, interface, &err);
381         if (!proxy) {
382                 pthread_mutex_unlock(&dmutex);
383                 DMSG_ERR("fail to get proxy from proxy pool : %s-%s (%d-%s)",
384                                 interface, method, err->code, err->message);
385                 result = g_dbus_error_to_errno(err->code);
386                 g_clear_error(&err);
387                 return result;
388         }
389
390         pdata = malloc(sizeof(struct pending_call_data));
391         if (!pdata) {
392                 pthread_mutex_unlock(&dmutex);
393                 DMSG_ERR("malloc error : %s-%s",
394                                 interface, method);
395                 return -ENOMEM;
396         }
397
398         pdata->func = cb;
399         pdata->data = data;
400
401         g_dbus_proxy_call(proxy,
402                         method,                          /* method name */
403                         append_g_variant(sig, param),    /* parameters */
404                         G_DBUS_CALL_FLAGS_NONE,
405                         timeout, //DBUS_REPLY_TIMEOUT,   /* timeout */
406                         NULL,                            /* GCancellable */
407                         (GAsyncReadyCallback)cb_pending, /* GAsyncReadyCallback */
408                         pdata);                          /* user data */
409         pthread_mutex_unlock(&dmutex);
410
411         return 0;
412 }
413
414 static GDBusConnection *get_dbus_connection(void)
415 {
416         GError *err = NULL;
417         static GDBusConnection *conn;
418
419         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
420         if (!conn) {
421                 if (err)
422                         _D("Fail to get dbus connection: %s", err->message);
423                 else
424                         _D("Fail to get dbus connection");
425                 return NULL;
426         }
427
428         return conn;
429 }
430
431 static void storage_signal_callback(GDBusConnection *conn,
432                 const gchar *sender,
433                 const gchar *path,
434                 const gchar *iface,
435                 const gchar *signal,
436                 GVariant *params,
437                 gpointer user_data)
438 {
439         size_t iface_len, signal_len;
440         appdata_s *ad = (appdata_s *)user_data;
441         int id;
442
443         if (!params || !sender || !path || !iface || !signal)
444                 return;
445
446         iface_len = strlen(iface) + 1;
447         signal_len = strlen(signal) + 1;
448
449         if (strncmp(iface, STORAGED_INTERFACE_BLOCK_MANAGER, iface_len))
450                 return;
451
452         if (strncmp(signal, "DeviceRemoved", signal_len))
453                 return;
454
455         g_variant_get(params, "(issssssisibii)", NULL, NULL, NULL, NULL,
456                         NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &id);
457         if (id == ad->storage_id) {
458                 DMSG("Storage is removed");
459                 ui_app_exit();
460         }
461 }
462
463 int register_signal_handler(appdata_s *ad)
464 {
465         GDBusConnection *conn;
466
467         conn = get_dbus_connection();
468         if (!conn) {
469                 _E("Failed to get dbus connection");
470                 return -EPERM;
471         }
472
473         signal_id = g_dbus_connection_signal_subscribe(conn,
474                         NULL,
475                         STORAGED_INTERFACE_BLOCK_MANAGER,
476                         NULL,
477                         NULL,
478                         NULL,
479                         G_DBUS_SIGNAL_FLAGS_NONE,
480                         storage_signal_callback,
481                         ad,
482                         NULL);
483         if (signal_id == 0) {
484                 _E("Failed to subscrive bus signal");
485                 return -EPERM;
486         }
487
488         return 0;
489 }
490
491 int unregister_signal_handler()
492 {
493         GDBusConnection *conn;
494
495         conn = get_dbus_connection();
496         if (!conn) {
497                 _E("Failed to get dbus connection");
498                 return -EPERM;
499         }
500
501         g_dbus_connection_signal_unsubscribe(conn, signal_id);
502
503         return 0;
504 }