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;
461 for (l = h->method_handle_list ; l && (item = l->data) ;
462 l = g_list_next(l), item = NULL) {
464 h->method_handle_list = g_list_remove(h->method_handle_list, item);
473 dbus_connection_unregister_object_path(h->conn, item->path);
477 static int append_variant(DBusMessageIter *iter, const char *sig, char *param[])
482 dbus_bool_t bool_type;
483 unsigned long long int64_type;
485 struct dbus_byte *byte;
490 for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) {
493 bool_type = (atoi(param[i]) == 0 ? FALSE : TRUE);
494 dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &bool_type);
497 int_type = atoi(param[i]);
498 dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type);
501 int_type = strtoul(param[i], NULL, 10);
502 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type);
505 int64_type = atoll(param[i]);
506 dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type);
509 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, ¶m[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);
533 int broadcast_dbus_signal(const char *path, const char *iface,
534 const char *name, const char *sig, char *param[])
536 DBusConnection *conn;
538 DBusMessageIter iter;
541 conn = get_dbus_connection();
543 _E("Failed to get dbus connection");
547 msg = dbus_message_new_signal(path, iface, name);
549 _E("fail to allocate new %s.%s signal", iface, name);
553 dbus_message_iter_init_append(msg, &iter);
554 ret = append_variant(&iter, sig, param);
556 _E("append_variant error(%d)", ret);
560 ret = dbus_connection_send(conn, msg, NULL);
561 dbus_message_unref(msg);
563 _E("dbus_connection_send error(%s:%s-%s)", path, iface, name);
570 static void release_signal_info(struct signal_info *info)
574 info->free_func(info->data);
579 static struct signal_info *find_signal_info(const char *path,
580 const char *iface, const char *name, dbus_signal_received cb)
583 size_t path_len, iface_len, name_len;
584 struct signal_info *info;
586 path_len = strlen(path) + 1;
587 iface_len = strlen(iface) + 1;
588 name_len = strlen(name) + 1;
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))
593 if (strncmp(info->iface, iface, iface_len))
595 if (strncmp(info->name, name, name_len))
597 if (cb && info->cb != cb)
605 static void call_signal_callbacks(const char *path,
606 const char *iface, const char *name, DBusMessage *msg)
609 size_t path_len, iface_len, name_len;
610 struct signal_info *info;
612 path_len = strlen(path) + 1;
613 iface_len = strlen(iface) + 1;
614 name_len = strlen(name) + 1;
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))
620 if (strncmp(info->iface, iface, iface_len))
622 if (strncmp(info->name, name, name_len))
625 info->cb(NULL, path, iface, name, msg, info->data);
629 static int make_match(const char *path, const char *iface,
630 const char *name, char *buf, size_t len)
632 if (!path || !iface || ! name || !buf)
636 "type='signal',path=%s,interface=%s,member=%s",
642 void unregister_dbus_signal_all(void)
645 struct signal_info *info;
648 DBusConnection *conn;
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);
655 ret = make_match(info->path, info->iface, info->name,
656 match, sizeof(match));
658 conn = get_dbus_connection();
660 dbus_bus_remove_match(conn, match, NULL);
663 release_signal_info(info);
667 static DBusHandlerResult signal_filter(DBusConnection *conn, DBusMessage *msg, void *data)
669 const char *path, *iface, *name;
671 if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
672 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
674 path = dbus_message_get_path(msg);
675 iface = dbus_message_get_interface(msg);
676 name = dbus_message_get_member(msg);
678 call_signal_callbacks(path, iface, name, msg);
680 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
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)
688 struct signal_info *info;
689 DBusConnection *conn;
690 static int add_filter = 0;
694 conn = get_dbus_connection();
696 _E("Failed to get dbus connection");
700 info = find_signal_info(path, interface, name, cb);
704 info = calloc(1, sizeof(struct signal_info));
711 info->iface = interface;
714 info->free_func = free_func;
717 if (add_filter == 0) {
719 dbus_connection_add_filter(conn, signal_filter, NULL, NULL);
722 ret = make_match(path, interface, name, match, sizeof(match));
724 _E("Failed to make match (%d)", ret);
728 dbus_bus_add_match(conn, match, NULL);
730 signal_handler_list = g_list_append(signal_handler_list, info);
735 int unregister_dbus_signal(const char *path,
736 const char *interface, const char *name,
737 dbus_signal_received cb)
739 struct signal_info *info;
740 DBusConnection *conn;
744 conn = get_dbus_connection();
746 _E("Failed to get dbus connection");
750 info = find_signal_info(path, interface, name, cb);
754 signal_handler_list = g_list_remove(signal_handler_list, info);
755 release_signal_info(info);
757 ret = make_match(path, interface, name, match, sizeof(match));
759 _E("Failed to make match (%d)", ret);
763 dbus_bus_remove_match(conn, match, NULL);
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,
773 DBusConnection *conn;
775 DBusMessageIter iter;
780 if (!dest || !path || !interface || !method || !reply)
783 conn = get_dbus_connection();
785 _E("Failed to get dbus connection");
789 msg = dbus_message_new_method_call(dest, path, interface, method);
791 _E("dbus_message_new_method_call(%s:%s-%s)",
792 path, interface, method);
796 dbus_message_iter_init_append(msg, &iter);
797 r = append_variant(&iter, sig, param);
799 _E("append_variant error(%d) %s %s:%s-%s",
800 r, dest, path, interface, method);
801 dbus_message_unref(msg);
805 dbus_error_init(&err);
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);
816 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
817 dest, path, interface, method);
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)
830 DBusConnection *conn;
832 DBusMessageIter iter;
833 DBusMessageIter aiter, piter;
840 if (!dest || !path || !interface || !method)
843 conn = get_dbus_connection();
845 _E("Failed to get dbus connection");
849 msg = dbus_message_new_method_call(dest, path, interface, method);
851 _E("dbus_message_new_method_call(%s:%s-%s)",
852 path, interface, method);
856 dbus_message_iter_init_append(msg, &iter);
857 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
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);
869 dbus_message_iter_close_container(&iter, &aiter);
871 dbus_error_init(&err);
873 reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err);
875 _E("dbus_connection_send error(No reply) %s %s:%s-%s",
876 dest, path, interface, method);
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);
885 dbus_message_unref(msg);
890 ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID);
891 dbus_message_unref(reply);
893 _E("no message : [%s:%s] %s %s:%s-%s",
894 err.name, err.message, dest, path, interface, method);
895 dbus_error_free(&err);
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)
906 DBusConnection *conn;
908 DBusMessageIter iter;
909 DBusMessageIter aiter, piter;
913 if (!dest || !path || !interface || !method)
916 conn = get_dbus_connection();
918 _E("Failed to get dbus connection");
922 msg = dbus_message_new_method_call(dest, path, interface, method);
924 _E("dbus_message_new_method_call(%s:%s-%s)",
925 path, interface, method);
929 dbus_message_iter_init_append(msg, &iter);
930 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{ss}", &aiter);
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);
942 dbus_message_iter_close_container(&iter, &aiter);
944 ret = dbus_connection_send(conn, msg, NULL);
945 dbus_message_unref(msg);
947 _E("dbus_connection_send error(%s %s:%s-%s)",
948 dest, path, interface, method);
955 static void cb_pending(DBusPendingCall *pending, void *user_data)
958 struct pending_call_data *data = user_data;
961 ret = dbus_pending_call_get_completed(pending);
963 _I("dbus_pending_call_get_completed() fail");
964 dbus_pending_call_unref(pending);
968 msg = dbus_pending_call_steal_reply(pending);
970 _E("message is NULL");
972 data->func(data->data, NULL, -ECOMM);
977 data->func(data->data, msg, 0);
979 dbus_message_unref(msg);
980 dbus_pending_call_unref(pending);
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)
988 DBusConnection *conn;
990 DBusMessageIter iter;
991 DBusPendingCall *pending = NULL;
992 struct pending_call_data *pdata;
995 conn = get_dbus_connection();
997 _E("Failed to get dbus connection");
1001 msg = dbus_message_new_method_call(dest, path, interface, method);
1003 _E("dbus_message_new_method_call(%s:%s-%s)",
1004 path, interface, method);
1008 dbus_message_iter_init_append(msg, &iter);
1009 ret = append_variant(&iter, sig, param);
1011 _E("append_variant error(%d)%s %s:%s-%s",
1012 ret, dest, path, interface, method);
1013 dbus_message_unref(msg);
1017 ret = dbus_connection_send_with_reply(conn, msg, &pending, timeout);
1019 dbus_message_unref(msg);
1020 _E("dbus_connection_send error(%s %s:%s-%s)",
1021 dest, path, interface, method);
1025 dbus_message_unref(msg);
1027 if (cb && pending) {
1028 pdata = calloc(1, sizeof(struct pending_call_data));
1030 _E("malloc error : %s-%s", interface, method);
1037 ret = dbus_pending_call_set_notify(pending, cb_pending, pdata, free);
1040 dbus_pending_call_cancel(pending);