3 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 #include <dbus/dbus.h>
24 #include "fd_handler.h"
28 /* -1 is a default timeout value, it's converted to 25*1000 internally. */
29 #define DBUS_REPLY_TIMEOUT (-1)
31 struct dbus_handle_s {
34 GList *method_handle_list;
37 struct dbus_method_reply_handle_s {
38 struct dbus_handle_s *handle;
42 struct dbus_method_handle_s {
43 struct dbus_handle_s *handle;
45 const dbus_interface_s *iface;
46 void (*method_handle_received)(void *method_handle, void *data);
54 dbus_signal_received cb;
55 destroy_notified free_func;
60 struct pending_call_data {
65 static GList *connection_handle_list;
66 static GList *signal_handler_list;
68 static DBusConnection *get_dbus_connection(void)
70 static DBusConnection *conn;
76 dbus_error_init(&err);
78 conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
80 if (dbus_error_is_set(&err)) {
81 _E("dbus_bus_get error(%s, %s)", err.name, err.message);
82 dbus_error_free(&err);
84 _E("dbus_bus_get error");
90 int dbus_get_connection(dbus_handle_h *handle)
92 static DBusConnection *conn;
93 struct dbus_handle_s *h;
99 h = calloc(1, sizeof(struct dbus_handle_s));
101 _E("calloc() failed");
105 conn = get_dbus_connection();
107 _E("Failed to get dbus connection");
115 connection_handle_list = g_list_append(connection_handle_list, h);
124 int get_dbus_method_sender_name(dbus_method_reply_handle_h reply_handle,
125 char *name, size_t len)
127 struct dbus_method_reply_handle_s *reply = reply_handle;
130 if (!reply || !reply->msg || !name)
133 sender = dbus_message_get_sender(reply->msg);
134 snprintf(name, len, "%s", sender);
139 int get_dbus_method_sender_pid(dbus_method_reply_handle_h reply_handle)
148 ret = get_dbus_method_sender_name(reply_handle, name, sizeof(name));
153 ret = call_dbus_method_sync(DBUS_SERVICE_DBUS,
156 "GetConnectionUnixProcessID",
157 "s", param, DBUS_REPLY_TIMEOUT,
160 _E("Faild to get pid of sender(%s)", name);
164 dbus_error_init(&err);
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);
181 DBusMessage *make_dbus_reply_message(dbus_method_reply_handle_h reply_handle)
183 struct dbus_method_reply_handle_s *reply = reply_handle;
185 if (!reply || !(reply->msg)) {
186 _E("Invalid parameter");
190 return dbus_message_new_method_return(reply->msg);
193 DBusMessage *make_dbus_reply_message_simple(dbus_method_reply_handle_h reply_handle, int result)
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);
203 void reply_dbus_method_result(dbus_method_reply_handle_h reply_handle, DBusMessage *reply_msg)
205 struct dbus_method_reply_handle_s *reply = reply_handle;
207 if (!reply || !reply_msg)
210 dbus_connection_send(reply->handle->conn, reply_msg, NULL);
211 dbus_message_unref(reply_msg);
216 static DBusHandlerResult method_call_handler(DBusConnection *connection,
217 DBusMessage *msg, void *user_data)
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;
226 _D("Method call handler");
229 return DBUS_HANDLER_RESULT_HANDLED;
233 methods = iface->methods;
235 for (i = 0 ; i < iface->nr_methods ; i++) {
236 if (dbus_message_is_method_call(msg, iface->name, methods[i].member) != TRUE)
239 reply = calloc(1, sizeof(struct dbus_method_reply_handle_s));
241 _E("calloc() failed");
242 return DBUS_HANDLER_RESULT_HANDLED;
245 reply->handle = mh->handle;
246 reply->msg = dbus_message_ref(msg);
247 result = methods[i].func(reply, msg);
249 _E("result == NULL");
254 reply_dbus_method_result(reply, result);
256 return DBUS_HANDLER_RESULT_HANDLED;
259 static const DBusObjectPathVTable path_vtable = {
262 NULL, NULL, NULL, NULL,
265 static gboolean register_methods(gpointer data)
268 struct dbus_method_handle_s *mh = data;
273 ret = dbus_connection_register_object_path(mh->handle->conn,
274 mh->path, &path_vtable, mh);
276 _E("Failed to register methods (%s)", mh->path);
280 if (mh->method_handle_received)
281 mh->method_handle_received(mh, mh->data);
283 _I("object path(%s)", mh->path);
293 static fd_handler_h watch_handler;
295 static bool watch_changed_cb(int fd, void *data)
297 struct watch_info *winfo = data;
299 dbus_watch_handle(winfo->watch, DBUS_WATCH_READABLE | DBUS_WATCH_ERROR);
304 static void free_watch_info(void *data)
310 static dbus_bool_t add_watch_cb(DBusWatch *watch, void *data)
314 struct watch_info *winfo;
317 _I("add_watch_cb %s", (dbus_watch_get_enabled(watch) == 0 ? "disabled": "enabled"));
319 enabled = dbus_watch_get_enabled(watch);
321 if (watch_handler || !enabled)
324 winfo = calloc(1, sizeof(struct watch_info));
326 _E("calloc() failed");
330 winfo->watch = watch;
333 fd = dbus_watch_get_unix_fd(watch);
334 ret = add_fd_read_handler(fd, watch_changed_cb, winfo, free_watch_info, &watch_handler);
336 _E("Failed to add fd handler (%d)", ret);
341 static void remove_watch_cb(DBusWatch *watch, void *data)
348 ret = remove_fd_read_handler(&watch_handler);
350 _E("Failed to remove fd handler (%d)", ret);
351 watch_handler = NULL;
354 static void toggle_watch_cb(DBusWatch *watch, void *data)
359 static dbus_bool_t add_timeout_cb(DBusTimeout *timeout, void *data)
364 static void remove_timeout_cb(DBusTimeout *timeout, void *data)
369 static void toggle_timeout_cb(DBusTimeout *timeout, void *data)
374 static gboolean dispatch_idler_cb(gpointer data)
376 DBusConnection *conn = data;
383 dbus_connection_ref(conn);
385 while (dbus_connection_get_dispatch_status(conn) == DBUS_DISPATCH_DATA_REMAINS) {
386 dbus_connection_dispatch(conn);
389 dbus_connection_unref(conn);
394 static void dispatch_status_cb(DBusConnection *conn, DBusDispatchStatus new_status, void *data)
396 if (new_status == DBUS_DISPATCH_DATA_REMAINS)
397 g_idle_add(dispatch_idler_cb, conn);
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),
405 struct dbus_method_handle_s *mh;
406 struct dbus_handle_s *h = handle;
407 static bool set_dispatch = false;
409 if (!h || !(h->conn) || !object_path || !interface)
412 mh = calloc(1, sizeof(struct dbus_method_handle_s));
414 _E("calloc() failed");
419 mh->path = object_path;
420 mh->iface = interface;
421 mh->method_handle_received = method_handle_received;
424 h->method_handle_list = g_list_append(h->method_handle_list, mh);
429 dbus_connection_set_watch_functions(h->conn,
430 add_watch_cb, remove_watch_cb, toggle_watch_cb,
433 dbus_connection_set_timeout_functions(h->conn,
434 add_timeout_cb, remove_timeout_cb, toggle_timeout_cb,
437 dbus_connection_set_dispatch_status_function(h->conn,
438 dispatch_status_cb, NULL, NULL);
441 dispatch_status_cb(h->conn, dbus_connection_get_dispatch_status(h->conn), NULL);
443 register_methods(mh);
448 void unregister_dbus_methods(dbus_handle_h handle, dbus_method_handle_h method_handle)
451 struct dbus_method_handle_s *item;
452 struct dbus_handle_s *h = handle;
453 struct dbus_method_handle_s *mh = method_handle;
460 for (l = h->method_handle_list ; l && (item = l->data) ;
461 l = g_list_next(l), item = NULL) {
463 h->method_handle_list = g_list_remove(h->method_handle_list, item);
471 dbus_connection_unregister_object_path(h->conn, item->path);
475 static int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
480 dbus_bool_t bool_type;
481 unsigned long long int64_type;
483 struct dbus_byte *byte;
488 for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
491 bool_type = (atoi(param[i]) == 0 ? FALSE : TRUE);
492 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
495 int_type = atoi(param[i]);
496 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
499 int_type = strtoul(param[i], NULL, 10);
500 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
503 int64_type = atoll(param[i]);
504 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
507 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, ¶m[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);
531 int broadcast_dbus_signal(const char *path, const char *iface,
532 const char *name, const char *sig, char *param[])
534 DBusConnection *conn;
536 DBusMessageIter iter;
539 conn = get_dbus_connection();
541 _E("Failed to get dbus connection");
545 msg = dbus_message_new_signal(path, iface, name);
547 _E("fail to allocate new %s.%s signal", iface, name);
551 dbus_message_iter_init_append(msg, &iter);
552 ret = append_variant(&iter, sig, param);
554 _E("append_variant error(%d)", ret);
558 ret = dbus_connection_send(conn, msg, NULL);
559 dbus_message_unref(msg);
561 _E("dbus_connection_send error(%s:%s-%s)", path, iface, name);
568 static void release_signal_info(struct signal_info *info)
572 info->free_func(info->data);
577 static struct signal_info *find_signal_info(const char *path,
578 const char *iface, const char *name, dbus_signal_received cb)
581 size_t path_len, iface_len, name_len;
582 struct signal_info *info;
584 path_len = strlen(path) + 1;
585 iface_len = strlen(iface) + 1;
586 name_len = strlen(name) + 1;
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))
591 if (strncmp(info->iface, iface, iface_len))
593 if (strncmp(info->name, name, name_len))
595 if (cb && info->cb != cb)
603 static void call_signal_callbacks(const char *path,
604 const char *iface, const char *name, DBusMessage *msg)
607 size_t path_len, iface_len, name_len;
608 struct signal_info *info;
610 path_len = strlen(path) + 1;
611 iface_len = strlen(iface) + 1;
612 name_len = strlen(name) + 1;
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))
618 if (strncmp(info->iface, iface, iface_len))
620 if (strncmp(info->name, name, name_len))
623 info->cb(NULL, path, iface, name, msg, info->data);
627 static int make_match(const char *path, const char *iface,
628 const char *name, char *buf, size_t len)
630 if (!path || !iface || ! name || !buf)
634 "type='signal',path=%s,interface=%s,member=%s",
640 void unregister_dbus_signal_all(void)
643 struct signal_info *info;
646 DBusConnection *conn;
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);
653 ret = make_match(info->path, info->iface, info->name,
654 match, sizeof(match));
656 conn = get_dbus_connection();
658 dbus_bus_remove_match(conn, match, NULL);
661 release_signal_info(info);
665 static DBusHandlerResult signal_filter(DBusConnection *conn, DBusMessage *msg, void *data)
667 const char *path, *iface, *name;
669 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
670 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
672 path = dbus_message_get_path(msg);
673 iface = dbus_message_get_interface(msg);
674 name = dbus_message_get_member(msg);
676 call_signal_callbacks(path, iface, name, msg);
678 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
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)
686 struct signal_info *info;
687 DBusConnection *conn;
688 static int add_filter = 0;
692 conn = get_dbus_connection();
694 _E("Failed to get dbus connection");
698 info = find_signal_info(path, interface, name, cb);
702 info = calloc(1, sizeof(struct signal_info));
709 info->iface = interface;
712 info->free_func = free_func;
715 if (add_filter == 0) {
717 dbus_connection_add_filter(conn, signal_filter, NULL, NULL);
720 ret = make_match(path, interface, name, match, sizeof(match));
722 _E("Failed to make match (%d)", ret);
726 dbus_bus_add_match(conn, match, NULL);
728 signal_handler_list = g_list_append(signal_handler_list, info);
733 int unregister_dbus_signal(const char *path,
734 const char *interface, const char *name,
735 dbus_signal_received cb)
737 struct signal_info *info;
738 DBusConnection *conn;
742 conn = get_dbus_connection();
744 _E("Failed to get dbus connection");
748 info = find_signal_info(path, interface, name, cb);
752 signal_handler_list = g_list_remove(signal_handler_list, info);
753 release_signal_info(info);
755 ret = make_match(path, interface, name, match, sizeof(match));
757 _E("Failed to make match (%d)", ret);
761 dbus_bus_remove_match(conn, match, NULL);
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,
771 DBusConnection *conn;
773 DBusMessageIter iter;
778 if (!dest || !path || !interface || !method || !reply)
781 conn = get_dbus_connection();
783 _E("Failed to get dbus connection");
787 msg = dbus_message_new_method_call(dest, path, interface, method);
789 _E("dbus_message_new_method_call(%s:%s-%s)",
790 path, interface, method);
794 dbus_message_iter_init_append(msg, &iter);
795 r = append_variant(&iter, sig, param);
797 _E("append_variant error(%d) %s %s:%s-%s",
798 r, dest, path, interface, method);
799 dbus_message_unref(msg);
803 dbus_error_init(&err);
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);
814 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
815 dest, path, interface, method);
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)
828 DBusConnection *conn;
830 DBusMessageIter iter;
831 DBusMessageIter aiter, piter;
838 if (!dest || !path || !interface || !method)
841 conn = get_dbus_connection();
843 _E("Failed to get dbus connection");
847 msg = dbus_message_new_method_call(dest, path, interface, method);
849 _E("dbus_message_new_method_call(%s:%s-%s)",
850 path, interface, method);
854 dbus_message_iter_init_append(msg, &iter);
855 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
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);
867 dbus_message_iter_close_container(&iter, &aiter);
869 dbus_error_init(&err);
871 reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
873 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
874 dest, path, interface, method);
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);
883 dbus_message_unref(msg);
888 ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
889 dbus_message_unref(reply);
891 _E("no message : [%s:%s] %s %s:%s-%s",
892 err.name, err.message, dest, path, interface, method);
893 dbus_error_free(&err);
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)
904 DBusConnection *conn;
906 DBusMessageIter iter;
907 DBusMessageIter aiter, piter;
911 if (!dest || !path || !interface || !method)
914 conn = get_dbus_connection();
916 _E("Failed to get dbus connection");
920 msg = dbus_message_new_method_call(dest, path, interface, method);
922 _E("dbus_message_new_method_call(%s:%s-%s)",
923 path, interface, method);
927 dbus_message_iter_init_append(msg, &iter);
928 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
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);
940 dbus_message_iter_close_container(&iter, &aiter);
942 ret = dbus_connection_send(conn, msg, NULL);
943 dbus_message_unref(msg);
945 _E("dbus_connection_send error(%s %s:%s-%s)",
946 dest, path, interface, method);
953 static void cb_pending(DBusPendingCall *pending, void *user_data)
956 struct pending_call_data *data = user_data;
959 ret = dbus_pending_call_get_completed(pending);
961 _I("dbus_pending_call_get_completed() fail");
962 dbus_pending_call_unref(pending);
966 msg = dbus_pending_call_steal_reply(pending);
968 _E("message is NULL");
970 data->func(data->data, NULL, -ECOMM);
975 data->func(data->data, msg, 0);
977 dbus_message_unref(msg);
978 dbus_pending_call_unref(pending);
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)
986 DBusConnection *conn;
988 DBusMessageIter iter;
989 DBusPendingCall *pending = NULL;
990 struct pending_call_data *pdata;
993 conn = get_dbus_connection();
995 _E("Failed to get dbus connection");
999 pdata = calloc(1, sizeof(struct pending_call_data));
1001 _E("malloc error : %s-%s", interface, method);
1008 msg = dbus_message_new_method_call(dest, path, interface, method);
1010 _E("dbus_message_new_method_call(%s:%s-%s)",
1011 path, interface, method);
1015 dbus_message_iter_init_append(msg, &iter);
1016 ret = append_variant(&iter, sig, param);
1018 _E("append_variant error(%d)%s %s:%s-%s",
1019 ret, dest, path, interface, method);
1020 dbus_message_unref(msg);
1024 ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
1026 dbus_message_unref(msg);
1027 _E("dbus_connection_send error(%s %s:%s-%s)",
1028 dest, path, interface, method);
1032 dbus_message_unref(msg);
1034 if (cb && pending) {
1035 pdata = calloc(1, sizeof(struct pending_call_data));
1037 _E("malloc error : %s-%s", interface, method);
1044 ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
1047 dbus_pending_call_cancel(pending);