common: Remove readdir
[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         bool found = false;
455
456         if (!h || !h->conn)
457                 return;
458         if (!mh)
459                 return;
460
461         for (l = h->method_handle_list ; l && (item = l->data) ;
462                         l = g_list_next(l), item = NULL) {
463                 if (item == mh) {
464                         h->method_handle_list = g_list_remove(h->method_handle_list, item);
465                         found = true;
466                         break;
467                 }
468         }
469
470         if (!found)
471                 return;
472
473         dbus_connection_unregister_object_path(h->conn, item->path);
474         free(item);
475 }
476
477 static int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
478 {
479         char *ch;
480         int i;
481         int int_type;
482         dbus_bool_t bool_type;
483         unsigned long long int64_type;
484         DBusMessageIter arr;
485         struct dbus_byte *byte;
486
487         if (!sig || !param)
488                 return 0;
489
490         for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
491                 switch (*ch) {
492                 case 'b':
493                         bool_type = (atoi(param[i]) == 0 ? FALSE : TRUE);
494                         dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
495                         break;
496                 case 'i':
497                         int_type = atoi(param[i]);
498                         dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
499                         break;
500                 case 'u':
501                         int_type = strtoul(param[i], NULL, 10);
502                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
503                         break;
504                 case 't':
505                         int64_type = atoll(param[i]);
506                         dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
507                         break;
508                 case 's':
509                         dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &param[i]);
510                         break;
511                 case 'a':
512                         ++ch;
513                         switch (*ch) {
514                         case 'y':
515                                 ++i;
516                                 dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr);
517                                 byte = (struct dbus_byte *)param[i];
518                                 dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size);
519                                 dbus_message_iter_close_container(iter, &arr);
520                                 break;
521                         default:
522                                 break;
523                         }
524                         break;
525                 default:
526                         return -EINVAL;
527                 }
528         }
529
530         return 0;
531 }
532
533 int broadcast_dbus_signal(const char *path, const char *iface,
534                 const char *name, const char *sig, char *param[])
535 {
536         DBusConnection *conn;
537         DBusMessage *msg;
538         DBusMessageIter iter;
539         int ret;
540
541         conn = get_dbus_connection();
542         if (!conn) {
543                 _E("Failed to get dbus connection");
544                 return -ECOMM;
545         }
546
547         msg = dbus_message_new_signal(path, iface, name);
548         if (!msg) {
549                 _E("fail to allocate new %s.%s signal", iface, name);
550                 return -EPERM;
551         }
552
553         dbus_message_iter_init_append(msg, &iter);
554         ret = append_variant(&iter, sig, param);
555         if (ret < 0) {
556                 _E("append_variant error(%d)", ret);
557                 return -EPERM;
558         }
559
560         ret = dbus_connection_send(conn, msg, NULL);
561         dbus_message_unref(msg);
562         if (ret != TRUE) {
563                 _E("dbus_connection_send error(%s:%s-%s)", path, iface, name);
564                 return -ECOMM;
565         }
566
567         return 0;
568 }
569
570 static void release_signal_info(struct signal_info *info)
571 {
572         if (info) {
573                 if (info->free_func)
574                         info->free_func(info->data);
575                 free(info);
576         }
577 }
578
579 static struct signal_info *find_signal_info(const char *path,
580                 const char *iface, const char *name, dbus_signal_received cb)
581 {
582         GList *l;
583         size_t path_len, iface_len, name_len;
584         struct signal_info *info;
585
586         path_len = strlen(path) + 1;
587         iface_len = strlen(iface) + 1;
588         name_len = strlen(name) + 1;
589
590         for (l = signal_handler_list ; l && (info = l->data) ; l = g_list_next(l), info = NULL) {
591                 if (strncmp(info->path, path, path_len))
592                         continue;
593                 if (strncmp(info->iface, iface, iface_len))
594                         continue;
595                 if (strncmp(info->name, name, name_len))
596                         continue;
597                 if (cb && info->cb != cb)
598                         continue;
599                 return info;
600         }
601
602         return NULL;
603 }
604
605 static void call_signal_callbacks(const char *path,
606                 const char *iface, const char *name, DBusMessage *msg)
607 {
608         GList *l;
609         size_t path_len, iface_len, name_len;
610         struct signal_info *info;
611
612         path_len = strlen(path) + 1;
613         iface_len = strlen(iface) + 1;
614         name_len = strlen(name) + 1;
615
616         for (l = signal_handler_list ; l && (info = l->data) ; l = g_list_next(l), info = NULL) {
617                 _I("path(%s), info(%s), name(%s)", info->path, info->iface, info->name);
618                 if (strncmp(info->path, path, path_len))
619                         continue;
620                 if (strncmp(info->iface, iface, iface_len))
621                         continue;
622                 if (strncmp(info->name, name, name_len))
623                         continue;
624                 if (info->cb)
625                         info->cb(NULL, path, iface, name, msg, info->data);
626         }
627 }
628
629 static int make_match(const char *path, const char *iface,
630                 const char *name, char *buf, size_t len)
631 {
632         if (!path || !iface || ! name || !buf)
633                 return -EINVAL;
634
635         snprintf(buf, len,
636                         "type='signal',path=%s,interface=%s,member=%s",
637                         path, iface, name);
638
639         return 0;
640 }
641
642 void unregister_dbus_signal_all(void)
643 {
644         GList *l, *l_next;
645         struct signal_info *info;
646         char match[256];
647         int ret;
648         DBusConnection *conn;
649
650         for (l = signal_handler_list, l_next = g_list_next(l) ;
651                         l && (info = l->data) ;
652                         l = l_next, l_next = g_list_next(l), info = NULL) {
653                 signal_handler_list = g_list_remove(signal_handler_list, info);
654
655                 ret = make_match(info->path, info->iface, info->name,
656                                 match, sizeof(match));
657                 if (ret == 0) {
658                         conn = get_dbus_connection();
659                         if (conn)
660                                 dbus_bus_remove_match(conn, match, NULL);
661                 }
662
663                 release_signal_info(info);
664         }
665 }
666
667 static DBusHandlerResult signal_filter(DBusConnection *conn, DBusMessage *msg, void *data)
668 {
669         const char *path, *iface, *name;
670
671         if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
672                 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
673
674         path = dbus_message_get_path(msg);
675         iface = dbus_message_get_interface(msg);
676         name = dbus_message_get_member(msg);
677
678         call_signal_callbacks(path, iface, name, msg);
679
680         return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
681 }
682
683 int register_dbus_signal(const char *path,
684                 const char *interface, const char *name,
685                 dbus_signal_received cb, void *data,
686                 destroy_notified free_func)
687 {
688         struct signal_info *info;
689         DBusConnection *conn;
690         static int add_filter = 0;
691         char match[256];
692         int ret;
693
694         conn = get_dbus_connection();
695         if (!conn) {
696                 _E("Failed to get dbus connection");
697                 return -ECOMM;
698         }
699
700         info = find_signal_info(path, interface, name, cb);
701         if (info)
702                 return -EEXIST;
703
704         info = calloc(1, sizeof(struct signal_info));
705         if (!info) {
706                 _E("calloc failed");
707                 return -ENOMEM;
708         }
709
710         info->path = path;
711         info->iface = interface;
712         info->name = name;
713         info->cb = cb;
714         info->free_func = free_func;
715         info->data = data;
716
717         if (add_filter == 0) {
718                 add_filter = 1;
719                 dbus_connection_add_filter(conn, signal_filter, NULL, NULL);
720         }
721
722         ret = make_match(path, interface, name, match, sizeof(match));
723         if (ret < 0) {
724                 _E("Failed to make match (%d)", ret);
725                 free(info);
726                 return ret;
727         }
728         dbus_bus_add_match(conn, match, NULL);
729
730         signal_handler_list = g_list_append(signal_handler_list, info);
731
732         return 0;
733 }
734
735 int unregister_dbus_signal(const char *path,
736                 const char *interface, const char *name,
737                 dbus_signal_received cb)
738 {
739         struct signal_info *info;
740         DBusConnection *conn;
741         char match[256];
742         int ret;
743
744         conn = get_dbus_connection();
745         if (!conn) {
746                 _E("Failed to get dbus connection");
747                 return -ECOMM;
748         }
749
750         info = find_signal_info(path, interface, name, cb);
751         if (!info)
752                 return -ENOENT;
753
754         signal_handler_list = g_list_remove(signal_handler_list, info);
755         release_signal_info(info);
756
757         ret = make_match(path, interface, name, match, sizeof(match));
758         if (ret < 0) {
759                 _E("Failed to make match (%d)", ret);
760                 return ret;
761         }
762
763         dbus_bus_remove_match(conn, match, NULL);
764
765         return 0;
766 }
767
768 int call_dbus_method_sync(const char *dest, const char *path,
769                 const char *interface, const char *method,
770                 const char *sig, char *param[], int timeout,
771                 DBusMessage **reply)
772 {
773         DBusConnection *conn;
774         DBusMessage *msg;
775         DBusMessageIter iter;
776         DBusMessage *rep;
777         DBusError err;
778         int r;
779
780         if (!dest || !path || !interface || !method || !reply)
781                 return -EINVAL;
782
783         conn = get_dbus_connection();
784         if (!conn) {
785                 _E("Failed to get dbus connection");
786                 return -ECOMM;
787         }
788
789         msg = dbus_message_new_method_call(dest, path, interface, method);
790         if (!msg) {
791                 _E("dbus_message_new_method_call(%s:%s-%s)",
792                                 path, interface, method);
793                 return -EPERM;
794         }
795
796         dbus_message_iter_init_append(msg, &iter);
797         r = append_variant(&iter, sig, param);
798         if (r < 0) {
799                 _E("append_variant error(%d) %s %s:%s-%s",
800                                 r, dest, path, interface, method);
801                 dbus_message_unref(msg);
802                 return r;
803         }
804
805         dbus_error_init(&err);
806
807         rep = dbus_connection_send_with_reply_and_block(conn, msg, timeout, &err);
808         dbus_message_unref(msg);
809         if (dbus_error_is_set(&err)) {
810                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
811                                 err.name, err.message, dest, path, interface, method);
812                 dbus_error_free(&err);
813                 return -EPERM;
814         }
815         if (!rep) {
816                 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
817                                 dest, path, interface, method);
818                 return -EPERM;
819         }
820
821         *reply = rep;
822
823         return 0;
824 }
825
826 int call_dbus_method_sync_pairs(const char *dest,
827                 const char *path, const char *interface, const char *method,
828                 int num, va_list args)
829 {
830         DBusConnection *conn;
831         DBusMessage *msg;
832         DBusMessageIter iter;
833         DBusMessageIter aiter, piter;
834         DBusMessage *reply;
835         DBusError err;
836         char *key, *value;
837         int ret, result;
838         int i;
839
840         if (!dest || !path || !interface || !method)
841                 return -EINVAL;
842
843         conn = get_dbus_connection();
844         if (!conn) {
845                 _E("Failed to get dbus connection");
846                 return -ECOMM;
847         }
848
849         msg = dbus_message_new_method_call(dest, path, interface, method);
850         if (!msg) {
851                 _E("dbus_message_new_method_call(%s:%s-%s)",
852                                 path, interface, method);
853                 return -EPERM;
854         }
855
856         dbus_message_iter_init_append(msg, &iter);
857         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
858
859         for (i = 0 ; i < num ; i = i + 2) {
860                 key = va_arg(args, char *);
861                 value = va_arg(args, char *);
862                 _I("key(%s), value(%s)", key, value);
863                 dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &piter);
864                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &key);
865                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &value);
866                 dbus_message_iter_close_container(&aiter, &piter);
867         }
868
869         dbus_message_iter_close_container(&iter, &aiter);
870
871         dbus_error_init(&err);
872
873         reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
874         if (!reply) {
875                 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
876                                 dest, path, interface, method);
877         }
878
879         if (dbus_error_is_set(&err)) {
880                 _E("dbus_connection_send error(%s:%s) %s %s:%s-%s",
881                                 err.name, err.message, dest, path, interface, method);
882                 dbus_error_free(&err);
883                 reply = NULL;
884         }
885         dbus_message_unref(msg);
886
887         if (!reply)
888                 return -EPERM;
889
890         ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
891         dbus_message_unref(reply);
892         if (!ret) {
893                 _E("no message : [%s:%s] %s %s:%s-%s",
894                                 err.name, err.message, dest, path, interface, method);
895                 dbus_error_free(&err);
896                 return -ENOMSG;
897         }
898
899         return result;
900 }
901
902 int call_dbus_method_async_pairs(const char *dest,
903                 const char *path, const char *interface, const char *method,
904                 int num, va_list args)
905 {
906         DBusConnection *conn;
907         DBusMessage *msg;
908         DBusMessageIter iter;
909         DBusMessageIter aiter, piter;
910         char *key, *value;
911         int ret, i;
912
913         if (!dest || !path || !interface || !method)
914                 return -EINVAL;
915
916         conn = get_dbus_connection();
917         if (!conn) {
918                 _E("Failed to get dbus connection");
919                 return -ECOMM;
920         }
921
922         msg = dbus_message_new_method_call(dest, path, interface, method);
923         if (!msg) {
924                 _E("dbus_message_new_method_call(%s:%s-%s)",
925                                 path, interface, method);
926                 return -EPERM;
927         }
928
929         dbus_message_iter_init_append(msg, &iter);
930         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
931
932         for (i = 0 ; i < num ; i = i + 2) {
933                 key = va_arg(args, char *);
934                 value = va_arg(args, char *);
935                 _I("key(%s), value(%s)", key, value);
936                 dbus_message_iter_open_container(&aiter, DBUS_TYPE_DICT_ENTRY, NULL, &piter);
937                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &key);
938                 dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING, &value);
939                 dbus_message_iter_close_container(&aiter, &piter);
940         }
941
942         dbus_message_iter_close_container(&iter, &aiter);
943
944         ret = dbus_connection_send(conn, msg, NULL);
945         dbus_message_unref(msg);
946         if (ret != TRUE) {
947                 _E("dbus_connection_send error(%s %s:%s-%s)",
948                                 dest, path, interface, method);
949                 return -ECOMM;
950         }
951
952         return 0;
953 }
954
955 static void cb_pending(DBusPendingCall *pending, void *user_data)
956 {
957         DBusMessage *msg;
958         struct pending_call_data *data = user_data;
959         int ret;
960
961         ret = dbus_pending_call_get_completed(pending);
962         if (!ret) {
963                 _I("dbus_pending_call_get_completed() fail");
964                 dbus_pending_call_unref(pending);
965                 return;
966         }
967
968         msg = dbus_pending_call_steal_reply(pending);
969         if (!msg) {
970                 _E("message is NULL");
971                 if (data->func)
972                         data->func(data->data, NULL, -ECOMM);
973                 return;
974         }
975
976         if (data->func)
977                 data->func(data->data, msg, 0);
978
979         dbus_message_unref(msg);
980         dbus_pending_call_unref(pending);
981 }
982
983 int call_dbus_method_async(const char *dest, const char *path,
984                 const char *interface, const char *method,
985                 const char *sig, char *param[],
986                 dbus_pending_cb cb, int timeout, void *data)
987 {
988         DBusConnection *conn;
989         DBusMessage *msg;
990         DBusMessageIter iter;
991         DBusPendingCall *pending = NULL;
992         struct pending_call_data *pdata;
993         int ret;
994
995         conn = get_dbus_connection();
996         if (!conn) {
997                 _E("Failed to get dbus connection");
998                 return -ECOMM;
999         }
1000
1001         msg = dbus_message_new_method_call(dest, path, interface, method);
1002         if (!msg) {
1003                 _E("dbus_message_new_method_call(%s:%s-%s)",
1004                                 path, interface, method);
1005                 return -EBADMSG;
1006         }
1007
1008         dbus_message_iter_init_append(msg, &iter);
1009         ret = append_variant(&iter, sig, param);
1010         if (ret < 0) {
1011                 _E("append_variant error(%d)%s %s:%s-%s",
1012                                 ret, dest, path, interface, method);
1013                 dbus_message_unref(msg);
1014                 return ret;
1015         }
1016
1017         ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
1018         if (!ret) {
1019                 dbus_message_unref(msg);
1020                 _E("dbus_connection_send error(%s %s:%s-%s)",
1021                                 dest, path, interface, method);
1022                 return -ECOMM;
1023         }
1024
1025         dbus_message_unref(msg);
1026
1027         if (cb && pending) {
1028                 pdata = calloc(1, sizeof(struct pending_call_data));
1029                 if (!pdata) {
1030                         _E("malloc error : %s-%s", interface, method);
1031                         return -ENOMEM;
1032                 }
1033
1034                 pdata->func = cb;
1035                 pdata->data = data;
1036
1037                 ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
1038                 if (!ret) {
1039                         free(pdata);
1040                         dbus_pending_call_cancel(pending);
1041                         return -ECOMM;
1042                 }
1043         }
1044
1045         return 0;
1046 }