04b5cd42821f4278e96cc4bebc3c16c1f5ff556e
[platform/core/system/storaged.git] / src / shared / dbus.c
1 /*
2  * storaged
3  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License"),
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 #include <dbus/dbus.h>
22 #include <stdbool.h>
23 #include <limits.h>
24 #include "fd_handler.h"
25 #include "dbus.h"
26 #include "log.h"
27
28 /* -1 is a default timeout value, it's converted to 25*1000 internally. */
29 #define DBUS_REPLY_TIMEOUT  (-1)
30
31 struct dbus_handle_s {
32         DBusConnection *conn;
33         char *name;
34         GList *method_handle_list;
35 };
36
37 struct dbus_method_reply_handle_s {
38         struct dbus_handle_s *handle;
39         DBusMessage *msg;
40 };
41
42 struct dbus_method_handle_s {
43         struct dbus_handle_s *handle;
44         const char *path;
45         const dbus_interface_s *iface;
46         void (*method_handle_received)(void *method_handle, void *data);
47         void *data;
48 };
49
50 struct signal_info {
51         const char *path;
52         const char *iface;
53         const char *name;
54         dbus_signal_received cb;
55         destroy_notified free_func;
56         void *data;
57         guint handler;
58 };
59
60 struct pending_call_data {
61         dbus_pending_cb func;
62         void *data;
63 };
64
65 static GList *connection_handle_list;
66 static GList *signal_handler_list;
67
68 static DBusConnection *get_dbus_connection(void)
69 {
70         static DBusConnection *conn;
71         DBusError err;
72
73         if (conn)
74                 return conn;
75
76         dbus_error_init(&err);
77
78         conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
79         if (!conn) {
80                 if (dbus_error_is_set(&err)) {
81                         _E("dbus_bus_get error(%s, %s)", err.name, err.message);
82                         dbus_error_free(&err);
83                 } else
84                         _E("dbus_bus_get error");
85         }
86
87         return conn;
88 }
89
90 int dbus_get_connection(dbus_handle_h *handle)
91 {
92         static DBusConnection *conn;
93         struct dbus_handle_s *h;
94         int ret;
95
96         if (!handle)
97                 return -EINVAL;
98
99         h = calloc(1, sizeof(struct dbus_handle_s));
100         if (!h) {
101                 _E("calloc() failed");
102                 return -ENOMEM;
103         }
104
105         conn = get_dbus_connection();
106         if (!conn) {
107                 _E("Failed to get dbus connection");
108                 ret = -ECOMM;
109                 goto out;
110         }
111
112         h->conn = conn;
113         *handle = h;
114
115         connection_handle_list = g_list_append(connection_handle_list, h);
116
117         return 0;
118
119 out:
120         free(h);
121         return ret;
122 }
123
124 int get_dbus_method_sender_name(dbus_method_reply_handle_h reply_handle,
125                 char *name, size_t len)
126 {
127         struct dbus_method_reply_handle_s *reply = reply_handle;
128         const char *sender;
129
130         if (!reply || !reply->msg || !name)
131                 return -EINVAL;
132
133         sender = dbus_message_get_sender(reply->msg);
134         snprintf(name, len, "%s", sender);
135
136         return 0;
137 }
138
139 int get_dbus_method_sender_pid(dbus_method_reply_handle_h reply_handle)
140 {
141         char *param[1];
142         pid_t pid;
143         char name[NAME_MAX];
144         DBusMessage *msg;
145         DBusError err;
146         int ret;
147
148         ret = get_dbus_method_sender_name(reply_handle, name, sizeof(name));
149         if (ret < 0)
150                 return ret;
151
152         param[0] = name;
153         ret = call_dbus_method_sync(DBUS_SERVICE_DBUS,
154                         DBUS_PATH_DBUS,
155                         DBUS_INTERFACE_DBUS,
156                         "GetConnectionUnixProcessID",
157                         "s", param, DBUS_REPLY_TIMEOUT,
158                         &msg);
159         if (ret < 0) {
160                 _E("Faild to get pid of sender(%s)", name);
161                 return ret;
162         }
163
164         dbus_error_init(&err);
165
166         ret = dbus_message_get_args(msg, &err, DBUS_TYPE_INT32, &pid, DBUS_TYPE_INVALID);
167         dbus_message_unref(msg);
168         if (dbus_error_is_set(&err)) {
169                 _E("no message : [%s:%s]", err.name, err.message);
170                 dbus_error_free(&err);
171                 return -ENOMSG;
172         }
173         if (!ret) {
174                 _E("no message");
175                 return -ENOMSG;
176         }
177
178         return pid;
179 }
180
181 DBusMessage *make_dbus_reply_message(dbus_method_reply_handle_h reply_handle)
182 {
183         struct dbus_method_reply_handle_s *reply = reply_handle;
184
185         if (!reply || !(reply->msg)) {
186                 _E("Invalid parameter");
187                 return NULL;
188         }
189
190         return dbus_message_new_method_return(reply->msg);
191 }
192
193 DBusMessage *make_dbus_reply_message_simple(dbus_method_reply_handle_h reply_handle, int result)
194 {
195         DBusMessage *rep;
196         DBusMessageIter iter;
197         rep = make_dbus_reply_message(reply_handle);
198         dbus_message_iter_init_append(rep, &iter);
199         dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32, &result);
200         return rep;
201 }
202
203 void reply_dbus_method_result(dbus_method_reply_handle_h reply_handle, DBusMessage *reply_msg)
204 {
205         struct dbus_method_reply_handle_s *reply = reply_handle;
206
207         if (!reply || !reply_msg)
208                 return;
209
210         dbus_connection_send(reply->handle->conn, reply_msg, NULL);
211         dbus_message_unref(reply_msg);
212         if (reply)
213                 free(reply);
214 }
215
216 static DBusHandlerResult method_call_handler(DBusConnection *connection,
217                 DBusMessage *msg, void *user_data)
218 {
219         int i;
220         struct dbus_method_handle_s *mh = user_data;
221         struct dbus_method_reply_handle_s *reply;
222         const dbus_interface_s *iface;
223         const dbus_method_s *methods;
224         DBusMessage *result = NULL;
225
226         _D("Method call handler");
227
228         if (!msg || !mh) {
229                 return DBUS_HANDLER_RESULT_HANDLED;
230         }
231
232         iface = mh->iface;
233         methods = iface->methods;
234
235         for (i = 0 ; i < iface->nr_methods ; i++) {
236                 if (dbus_message_is_method_call(msg, iface->name, methods[i].member) != TRUE)
237                         continue;
238
239                 reply = calloc(1, sizeof(struct dbus_method_reply_handle_s));
240                 if (!reply) {
241                         _E("calloc() failed");
242                         return DBUS_HANDLER_RESULT_HANDLED;
243                 }
244
245                 reply->handle = mh->handle;
246                 reply->msg = dbus_message_ref(msg);
247                 result = methods[i].func(reply, msg);
248                 if (!result)
249                         _E("result == NULL");
250                 break;
251         }
252
253         if (result)
254                 reply_dbus_method_result(reply, result);
255
256         return DBUS_HANDLER_RESULT_HANDLED;
257 }
258
259 static const DBusObjectPathVTable path_vtable = {
260         NULL,
261         method_call_handler,
262         NULL, NULL, NULL, NULL,
263 };
264
265 static gboolean register_methods(gpointer data)
266 {
267         dbus_bool_t ret;
268         struct dbus_method_handle_s *mh = data;
269
270         if (!mh)
271                 return FALSE;
272
273         ret = dbus_connection_register_object_path(mh->handle->conn,
274                         mh->path, &path_vtable, mh);
275         if (ret == FALSE) {
276                 _E("Failed to register methods (%s)", mh->path);
277                 return FALSE;
278         }
279
280         if (mh->method_handle_received)
281                 mh->method_handle_received(mh, mh->data);
282
283         _I("object path(%s)", mh->path);
284
285         return FALSE;
286 }
287
288 struct watch_info {
289         DBusWatch *watch;
290         void *data;
291 };
292
293 static fd_handler_h watch_handler;
294
295 static bool watch_changed_cb(int fd, void *data)
296 {
297         struct watch_info *winfo = data;
298
299         dbus_watch_handle(winfo->watch, DBUS_WATCH_READABLE | DBUS_WATCH_ERROR);
300
301         return true;
302 }
303
304 static void free_watch_info(void *data)
305 {
306         if (data)
307                 free(data);
308 }
309
310 static dbus_bool_t add_watch_cb(DBusWatch *watch, void *data)
311 {
312         int fd;
313         int ret;
314         struct watch_info *winfo;
315         dbus_bool_t enabled;
316
317         _I("add_watch_cb %s", (dbus_watch_get_enabled(watch) == 0 ? "disabled": "enabled"));
318
319         enabled = dbus_watch_get_enabled(watch);
320
321         if (watch_handler || !enabled)
322                 return TRUE;
323
324         winfo = calloc(1, sizeof(struct watch_info));
325         if (!winfo) {
326                 _E("calloc() failed");
327                 return TRUE;
328         }
329
330         winfo->watch = watch;
331         winfo->data = NULL;
332
333         fd = dbus_watch_get_unix_fd(watch);
334         ret = add_fd_read_handler(fd, watch_changed_cb, winfo, free_watch_info, &watch_handler);
335         if (ret < 0)
336                 _E("Failed to add fd handler (%d)", ret);
337
338         return TRUE;
339 }
340
341 static void remove_watch_cb(DBusWatch *watch, void *data)
342 {
343         int ret;
344
345         if (!watch_handler)
346                 return;
347
348         ret = remove_fd_read_handler(&watch_handler);
349         if (ret < 0)
350                 _E("Failed to remove fd handler (%d)", ret);
351         watch_handler = NULL;
352 }
353
354 static void toggle_watch_cb(DBusWatch *watch, void *data)
355 {
356         return;
357 }
358
359 static dbus_bool_t add_timeout_cb(DBusTimeout *timeout, void *data)
360 {
361         return TRUE;
362 }
363
364 static void remove_timeout_cb(DBusTimeout *timeout, void *data)
365 {
366         return;
367 }
368
369 static void toggle_timeout_cb(DBusTimeout *timeout, void *data)
370 {
371         return;
372 }
373
374 static gboolean dispatch_idler_cb(gpointer data)
375 {
376         DBusConnection *conn = data;
377
378         if (!conn) {
379                 _E("conn == NULL");
380                 return FALSE;
381         }
382
383         dbus_connection_ref(conn);
384
385         while (dbus_connection_get_dispatch_status(conn) == DBUS_DISPATCH_DATA_REMAINS) {
386                 dbus_connection_dispatch(conn);
387         }
388
389         dbus_connection_unref(conn);
390
391         return FALSE;
392 }
393
394 static void dispatch_status_cb(DBusConnection *conn, DBusDispatchStatus new_status, void *data)
395 {
396         if (new_status == DBUS_DISPATCH_DATA_REMAINS)
397                 g_idle_add(dispatch_idler_cb, conn);
398 }
399
400 int register_dbus_methods(dbus_handle_h handle,
401                 const char *object_path, const dbus_interface_s *interface,
402                 void (*method_handle_received)(dbus_method_handle_h method_handle, void *data),
403                 void *data)
404 {
405         struct dbus_method_handle_s *mh;
406         struct dbus_handle_s *h = handle;
407         static bool set_dispatch = false;
408
409         if (!h || !(h->conn) || !object_path || !interface)
410                 return -EINVAL;
411
412         mh = calloc(1, sizeof(struct dbus_method_handle_s));
413         if (!mh) {
414                 _E("calloc() failed");
415                 return -ENOMEM;
416         }
417
418         mh->handle = h;
419         mh->path = object_path;
420         mh->iface = interface;
421         mh->method_handle_received = method_handle_received;
422         mh->data = data;
423
424         h->method_handle_list = g_list_append(h->method_handle_list, mh);
425
426         if (!set_dispatch) {
427                 set_dispatch = true;
428
429                 dbus_connection_set_watch_functions(h->conn,
430                                 add_watch_cb, remove_watch_cb, toggle_watch_cb,
431                                 NULL, NULL);
432
433                 dbus_connection_set_timeout_functions(h->conn,
434                                 add_timeout_cb, remove_timeout_cb, toggle_timeout_cb,
435                                 NULL, NULL);
436
437                 dbus_connection_set_dispatch_status_function(h->conn,
438                                 dispatch_status_cb, NULL, NULL);
439         }
440
441         dispatch_status_cb(h->conn, dbus_connection_get_dispatch_status(h->conn), NULL);
442
443         register_methods(mh);
444
445         return 0;
446 }
447
448 void unregister_dbus_methods(dbus_handle_h handle, dbus_method_handle_h method_handle)
449 {
450         GList *l;
451         struct dbus_method_handle_s *item;
452         struct dbus_handle_s *h = handle;
453         struct dbus_method_handle_s *mh = method_handle;
454
455         if (!h || !h->conn)
456                 return;
457         if (!mh)
458                 return;
459
460         for (l = h->method_handle_list ; l && (item = l->data) ;
461                         l = g_list_next(l), item = NULL) {
462                 if (item == mh) {
463                         h->method_handle_list = g_list_remove(h->method_handle_list, item);
464                         break;
465                 }
466         }
467
468         if (!item)
469                 return;
470
471         dbus_connection_unregister_object_path(h->conn, item->path);
472         free(item);
473 }
474
475 static int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
476 {
477         char *ch;
478         int i;
479         int int_type;
480         dbus_bool_t bool_type;
481         unsigned long long int64_type;
482         DBusMessageIter arr;
483         struct dbus_byte *byte;
484
485         if (!sig || !param)
486                 return 0;
487
488         for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
489                 switch (*ch) {
490                 case 'b':
491                         bool_type = (atoi(param[i]) == 0 ? FALSE : TRUE);
492                         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
493                         break;
494                 case 'i':
495                         int_type = atoi(param[i]);
496                         dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
497                         break;
498                 case 'u':
499                         int_type = strtoul(param[i], NULL, 10);
500                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
501                         break;
502                 case 't':
503                         int64_type = atoll(param[i]);
504                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
505                         break;
506                 case 's':
507                         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &param[i]);
508                         break;
509                 case 'a':
510                         ++ch;
511                         switch (*ch) {
512                         case 'y':
513                                 ++i;
514                                 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
515                                 byte = (struct dbus_byte *)param[i];
516                                 dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size);
517                                 dbus_message_iter_close_container(iter, &arr);
518                                 break;
519                         default:
520                                 break;
521                         }
522                         break;
523                 default:
524                         return -EINVAL;
525                 }
526         }
527
528         return 0;
529 }
530
531 int broadcast_dbus_signal(const char *path, const char *iface,
532                 const char *name, const char *sig, char *param[])
533 {
534         DBusConnection *conn;
535         DBusMessage *msg;
536         DBusMessageIter iter;
537         int ret;
538
539         conn = get_dbus_connection();
540         if (!conn) {
541                 _E("Failed to get dbus connection");
542                 return -ECOMM;
543         }
544
545         msg = dbus_message_new_signal(path, iface, name);
546         if (!msg) {
547                 _E("fail to allocate new %s.%s signal", iface, name);
548                 return -EPERM;
549         }
550
551         dbus_message_iter_init_append(msg, &iter);
552         ret = append_variant(&iter, sig, param);
553         if (ret < 0) {
554                 _E("append_variant error(%d)", ret);
555                 return -EPERM;
556         }
557
558         ret = dbus_connection_send(conn, msg, NULL);
559         dbus_message_unref(msg);
560         if (ret != TRUE) {
561                 _E("dbus_connection_send error(%s:%s-%s)", path, iface, name);
562                 return -ECOMM;
563         }
564
565         return 0;
566 }
567
568 static void release_signal_info(struct signal_info *info)
569 {
570         if (info) {
571                 if (info->free_func)
572                         info->free_func(info->data);
573                 free(info);
574         }
575 }
576
577 static struct signal_info *find_signal_info(const char *path,
578                 const char *iface, const char *name, dbus_signal_received cb)
579 {
580         GList *l;
581         size_t path_len, iface_len, name_len;
582         struct signal_info *info;
583
584         path_len = strlen(path) + 1;
585         iface_len = strlen(iface) + 1;
586         name_len = strlen(name) + 1;
587
588         for (l = signal_handler_list ; l && (info = l->data) ; l = g_list_next(l), info = NULL) {
589                 if (strncmp(info->path, path, path_len))
590                         continue;
591                 if (strncmp(info->iface, iface, iface_len))
592                         continue;
593                 if (strncmp(info->name, name, name_len))
594                         continue;
595                 if (cb && info->cb != cb)
596                         continue;
597                 return info;
598         }
599
600         return NULL;
601 }
602
603 static void call_signal_callbacks(const char *path,
604                 const char *iface, const char *name, DBusMessage *msg)
605 {
606         GList *l;
607         size_t path_len, iface_len, name_len;
608         struct signal_info *info;
609
610         path_len = strlen(path) + 1;
611         iface_len = strlen(iface) + 1;
612         name_len = strlen(name) + 1;
613
614         for (l = signal_handler_list ; l && (info = l->data) ; l = g_list_next(l), info = NULL) {
615                 _I("path(%s), info(%s), name(%s)", info->path, info->iface, info->name);
616                 if (strncmp(info->path, path, path_len))
617                         continue;
618                 if (strncmp(info->iface, iface, iface_len))
619                         continue;
620                 if (strncmp(info->name, name, name_len))
621                         continue;
622                 if (info->cb)
623                         info->cb(NULL, path, iface, name, msg, info->data);
624         }
625 }
626
627 static int make_match(const char *path, const char *iface,
628                 const char *name, char *buf, size_t len)
629 {
630         if (!path || !iface || ! name || !buf)
631                 return -EINVAL;
632
633         snprintf(buf, len,
634                         "type='signal',path=%s,interface=%s,member=%s",
635                         path, iface, name);
636
637         return 0;
638 }
639
640 void unregister_dbus_signal_all(void)
641 {
642         GList *l, *l_next;
643         struct signal_info *info;
644         char match[256];
645         int ret;
646         DBusConnection *conn;
647
648         for (l = signal_handler_list, l_next = g_list_next(l) ;
649                         l && (info = l->data) ;
650                         l = l_next, l_next = g_list_next(l), info = NULL) {
651                 signal_handler_list = g_list_remove(signal_handler_list, info);
652
653                 ret = make_match(info->path, info->iface, info->name,
654                                 match, sizeof(match));
655                 if (ret == 0) {
656                         conn = get_dbus_connection();
657                         if (conn)
658                                 dbus_bus_remove_match(conn, match, NULL);
659                 }
660
661                 release_signal_info(info);
662         }
663 }
664
665 static DBusHandlerResult signal_filter(DBusConnection *conn, DBusMessage *msg, void *data)
666 {
667         const char *path, *iface, *name;
668
669         if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
670                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
671
672         path = dbus_message_get_path(msg);
673         iface = dbus_message_get_interface(msg);
674         name = dbus_message_get_member(msg);
675
676         call_signal_callbacks(path, iface, name, msg);
677
678         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
679 }
680
681 int register_dbus_signal(const char *path,
682                 const char *interface, const char *name,
683                 dbus_signal_received cb, void *data,
684                 destroy_notified free_func)
685 {
686         struct signal_info *info;
687         DBusConnection *conn;
688         static int add_filter = 0;
689         char match[256];
690         int ret;
691
692         conn = get_dbus_connection();
693         if (!conn) {
694                 _E("Failed to get dbus connection");
695                 return -ECOMM;
696         }
697
698         info = find_signal_info(path, interface, name, cb);
699         if (info)
700                 return -EEXIST;
701
702         info = calloc(1, sizeof(struct signal_info));
703         if (!info) {
704                 _E("calloc failed");
705                 return -ENOMEM;
706         }
707
708         info->path = path;
709         info->iface = interface;
710         info->name = name;
711         info->cb = cb;
712         info->free_func = free_func;
713         info->data = data;
714
715         if (add_filter == 0) {
716                 add_filter = 1;
717                 dbus_connection_add_filter(conn, signal_filter, NULL, NULL);
718         }
719
720         ret = make_match(path, interface, name, match, sizeof(match));
721         if (ret < 0) {
722                 _E("Failed to make match (%d)", ret);
723                 free(info);
724                 return ret;
725         }
726         dbus_bus_add_match(conn, match, NULL);
727
728         signal_handler_list = g_list_append(signal_handler_list, info);
729
730         return 0;
731 }
732
733 int unregister_dbus_signal(const char *path,
734                 const char *interface, const char *name,
735                 dbus_signal_received cb)
736 {
737         struct signal_info *info;
738         DBusConnection *conn;
739         char match[256];
740         int ret;
741
742         conn = get_dbus_connection();
743         if (!conn) {
744                 _E("Failed to get dbus connection");
745                 return -ECOMM;
746         }
747
748         info = find_signal_info(path, interface, name, cb);
749         if (!info)
750                 return -ENOENT;
751
752         signal_handler_list = g_list_remove(signal_handler_list, info);
753         release_signal_info(info);
754
755         ret = make_match(path, interface, name, match, sizeof(match));
756         if (ret < 0) {
757                 _E("Failed to make match (%d)", ret);
758                 return ret;
759         }
760
761         dbus_bus_remove_match(conn, match, NULL);
762
763         return 0;
764 }
765
766 int call_dbus_method_sync(const char *dest, const char *path,
767                 const char *interface, const char *method,
768                 const char *sig, char *param[], int timeout,
769                 DBusMessage **reply)
770 {
771         DBusConnection *conn;
772         DBusMessage *msg;
773         DBusMessageIter iter;
774         DBusMessage *rep;
775         DBusError err;
776         int r;
777
778         if (!dest || !path || !interface || !method || !reply)
779                 return -EINVAL;
780
781         conn = get_dbus_connection();
782         if (!conn) {
783                 _E("Failed to get dbus connection");
784                 return -ECOMM;
785         }
786
787         msg = dbus_message_new_method_call(dest, path, interface, method);
788         if (!msg) {
789                 _E("dbus_message_new_method_call(%s:%s-%s)",
790                                 path, interface, method);
791                 return -EPERM;
792         }
793
794         dbus_message_iter_init_append(msg, &iter);
795         r = append_variant(&iter, sig, param);
796         if (r < 0) {
797                 _E("append_variant error(%d) %s %s:%s-%s",
798                                 r, dest, path, interface, method);
799                 dbus_message_unref(msg);
800                 return r;
801         }
802
803         dbus_error_init(&err);
804
805         rep = dbus_connection_send_with_reply_and_block(conn, msg, timeout, &err);
806         dbus_message_unref(msg);
807         if (dbus_error_is_set(&err)) {
808                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
809                                 err.name, err.message, dest, path, interface, method);
810                 dbus_error_free(&err);
811                 return -EPERM;
812         }
813         if (!rep) {
814                 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
815                                 dest, path, interface, method);
816                 return -EPERM;
817         }
818
819         *reply = rep;
820
821         return 0;
822 }
823
824 int call_dbus_method_sync_pairs(const char *dest,
825                 const char *path, const char *interface, const char *method,
826                 int num, va_list args)
827 {
828         DBusConnection *conn;
829         DBusMessage *msg;
830         DBusMessageIter iter;
831         DBusMessageIter aiter, piter;
832         DBusMessage *reply;
833         DBusError err;
834         char *key, *value;
835         int ret, result;
836         int i;
837
838         if (!dest || !path || !interface || !method)
839                 return -EINVAL;
840
841         conn = get_dbus_connection();
842         if (!conn) {
843                 _E("Failed to get dbus connection");
844                 return -ECOMM;
845         }
846
847         msg = dbus_message_new_method_call(dest, path, interface, method);
848         if (!msg) {
849                 _E("dbus_message_new_method_call(%s:%s-%s)",
850                                 path, interface, method);
851                 return -EPERM;
852         }
853
854         dbus_message_iter_init_append(msg, &iter);
855         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
856
857         for (i = 0 ; i < num ; i = i + 2) {
858                 key = va_arg(args, char *);
859                 value = va_arg(args, char *);
860                 _I("key(%s), value(%s)", key, value);
861                 dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &piter);
862                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &key);
863                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &value);
864                 dbus_message_iter_close_container(&aiter, &piter);
865         }
866
867         dbus_message_iter_close_container(&iter, &aiter);
868
869         dbus_error_init(&err);
870
871         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
872         if (!reply) {
873                 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
874                                 dest, path, interface, method);
875         }
876
877         if (dbus_error_is_set(&err)) {
878                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
879                                 err.name, err.message, dest, path, interface, method);
880                 dbus_error_free(&err);
881                 reply = NULL;
882         }
883         dbus_message_unref(msg);
884
885         if (!reply)
886                 return -EPERM;
887
888         ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
889         dbus_message_unref(reply);
890         if (!ret) {
891                 _E("no message : [%s:%s] %s %s:%s-%s",
892                                 err.name, err.message, dest, path, interface, method);
893                 dbus_error_free(&err);
894                 return -ENOMSG;
895         }
896
897         return result;
898 }
899
900 int call_dbus_method_async_pairs(const char *dest,
901                 const char *path, const char *interface, const char *method,
902                 int num, va_list args)
903 {
904         DBusConnection *conn;
905         DBusMessage *msg;
906         DBusMessageIter iter;
907         DBusMessageIter aiter, piter;
908         char *key, *value;
909         int ret, i;
910
911         if (!dest || !path || !interface || !method)
912                 return -EINVAL;
913
914         conn = get_dbus_connection();
915         if (!conn) {
916                 _E("Failed to get dbus connection");
917                 return -ECOMM;
918         }
919
920         msg = dbus_message_new_method_call(dest, path, interface, method);
921         if (!msg) {
922                 _E("dbus_message_new_method_call(%s:%s-%s)",
923                                 path, interface, method);
924                 return -EPERM;
925         }
926
927         dbus_message_iter_init_append(msg, &iter);
928         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
929
930         for (i = 0 ; i < num ; i = i + 2) {
931                 key = va_arg(args, char *);
932                 value = va_arg(args, char *);
933                 _I("key(%s), value(%s)", key, value);
934                 dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &piter);
935                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &key);
936                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &value);
937                 dbus_message_iter_close_container(&aiter, &piter);
938         }
939
940         dbus_message_iter_close_container(&iter, &aiter);
941
942         ret = dbus_connection_send(conn, msg, NULL);
943         dbus_message_unref(msg);
944         if (ret != TRUE) {
945                 _E("dbus_connection_send error(%s %s:%s-%s)",
946                                 dest, path, interface, method);
947                 return -ECOMM;
948         }
949
950         return 0;
951 }
952
953 static void cb_pending(DBusPendingCall *pending, void *user_data)
954 {
955         DBusMessage *msg;
956         struct pending_call_data *data = user_data;
957         int ret;
958
959         ret = dbus_pending_call_get_completed(pending);
960         if (!ret) {
961                 _I("dbus_pending_call_get_completed() fail");
962                 dbus_pending_call_unref(pending);
963                 return;
964         }
965
966         msg = dbus_pending_call_steal_reply(pending);
967         if (!msg) {
968                 _E("message is NULL");
969                 if (data->func)
970                         data->func(data->data, NULL, -ECOMM);
971                 return;
972         }
973
974         if (data->func)
975                 data->func(data->data, msg, 0);
976
977         dbus_message_unref(msg);
978         dbus_pending_call_unref(pending);
979 }
980
981 int call_dbus_method_async(const char *dest, const char *path,
982                 const char *interface, const char *method,
983                 const char *sig, char *param[],
984                 dbus_pending_cb cb, int timeout, void *data)
985 {
986         DBusConnection *conn;
987         DBusMessage *msg;
988         DBusMessageIter iter;
989         DBusPendingCall *pending = NULL;
990         struct pending_call_data *pdata;
991         int ret;
992
993         conn = get_dbus_connection();
994         if (!conn) {
995                 _E("Failed to get dbus connection");
996                 return -ECOMM;
997         }
998
999         pdata = calloc(1, sizeof(struct pending_call_data));
1000         if (!pdata) {
1001                 _E("malloc error : %s-%s", interface, method);
1002                 return -ENOMEM;
1003         }
1004
1005         pdata->func = cb;
1006         pdata->data = data;
1007
1008         msg = dbus_message_new_method_call(dest, path, interface, method);
1009         if (!msg) {
1010                 _E("dbus_message_new_method_call(%s:%s-%s)",
1011                                 path, interface, method);
1012                 return -EBADMSG;
1013         }
1014
1015         dbus_message_iter_init_append(msg, &iter);
1016         ret = append_variant(&iter, sig, param);
1017         if (ret < 0) {
1018                 _E("append_variant error(%d)%s %s:%s-%s",
1019                                 ret, dest, path, interface, method);
1020                 dbus_message_unref(msg);
1021                 return ret;
1022         }
1023
1024         ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
1025         if (!ret) {
1026                 dbus_message_unref(msg);
1027                 _E("dbus_connection_send error(%s %s:%s-%s)",
1028                                 dest, path, interface, method);
1029                 return -ECOMM;
1030         }
1031
1032         dbus_message_unref(msg);
1033
1034         if (cb && pending) {
1035                 pdata = calloc(1, sizeof(struct pending_call_data));
1036                 if (!pdata) {
1037                         _E("malloc error : %s-%s", interface, method);
1038                         return -ENOMEM;
1039                 }
1040
1041                 pdata->func = cb;
1042                 pdata->data = data;
1043
1044                 ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
1045                 if (!ret) {
1046                         free(pdata);
1047                         dbus_pending_call_cancel(pending);
1048                         return -ECOMM;
1049                 }
1050         }
1051
1052         return 0;
1053 }