From: pr.jung Date: Mon, 24 Oct 2016 10:57:23 +0000 (+0900) Subject: Change libdbus to gdbus and add proxy pool X-Git-Tag: submit/tizen/20161028.042000~4 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bf2f7c30c56ead7b4ea3f7312b8c53e53aabc934;p=platform%2Fcore%2Fsystem%2Flibsvi.git Change libdbus to gdbus and add proxy pool - Instead use async call for VibrateEffect, libsvi use sync call and deviced-vibrator return after parameter check(and security check). deviced-vibrator add idler callback for further operation for VibrateEffect(For async operation) Change-Id: I374ced886bc827bb9caa953874ccccb6a618a41a Signed-off-by: pr.jung --- diff --git a/src/dbus.c b/src/dbus.c index 53db49b..0a8c18c 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "common.h" @@ -29,111 +30,260 @@ /* -1 is a default timeout value, it's converted to 25*1000 internally. */ #define DBUS_REPLY_TIMEOUT (-1) -static int append_variant(DBusMessageIter *iter, const char *sig, char *param[]) +/** extract from dbus/dbus-protocol.h + * (GDbus use the same maximum value.) + * Max length in bytes of a bus name, interface, or member (not object + * path, paths are unlimited). This is limited because lots of stuff + * is O(n) in this number, plus it would be obnoxious to type in a + * paragraph-long method name so most likely something like that would + * be an exploit. + */ +#define DBUS_MAXIMUM_NAME_LENGTH 255 + +struct proxy_node { + GDBusProxy *proxy; + char *dest; + char *path; + char *interface; +}; + +static GList *proxy_pool; +static pthread_mutex_t dmutex = PTHREAD_MUTEX_INITIALIZER; +static int bus_init; + +static int g_dbus_error_to_errno(int code) { + /** + * if device is not supported, + * deviced does not register the method call of the device. + * in this case, dbus will return UNKNOWN_METHOD error. + */ + /* refer to gio/gioenums.h */ + if (code == G_DBUS_ERROR_ACCESS_DENIED) + return -EACCES; + else if (code == G_DBUS_ERROR_UNKNOWN_METHOD) + return -ENOTSUP; + return -ECOMM; +} + +static GVariant *append_g_variant(const char *sig, char *param[]) +{ + GVariantBuilder builder; char *ch; int i; - int int_type; - uint64_t int64_type; - DBusMessageIter arr; - struct dbus_byte *byte; + struct dbus_byte *bytes; if (!sig || !param) - return 0; + return NULL; + + g_variant_builder_init(&builder, G_VARIANT_TYPE_TUPLE); - for (ch = (char*)sig, i = 0; *ch != '\0'; ++i, ++ch) { + for (ch = (char *)sig, i = 0; *ch != '\0'; ++i, ++ch) { switch (*ch) { case 'i': - int_type = atoi(param[i]); - dbus_message_iter_append_basic(iter, DBUS_TYPE_INT32, &int_type); + g_variant_builder_add(&builder, "i", atoi(param[i])); break; case 'u': - int_type = strtoul(param[i], NULL, 10); - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &int_type); + g_variant_builder_add(&builder, "u", strtoul(param[i], NULL, 10)); break; case 't': - int64_type = atoll(param[i]); - dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &int64_type); + g_variant_builder_add(&builder, "t", atoll(param[i])); break; case 's': - dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, ¶m[i]); + g_variant_builder_add(&builder, "s", param[i]); break; case 'a': ++i, ++ch; switch (*ch) { case 'y': - dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &arr); - byte = (struct dbus_byte*)param[i]; - dbus_message_iter_append_fixed_array(&arr, DBUS_TYPE_BYTE, &(byte->data), byte->size); - dbus_message_iter_close_container(iter, &arr); + bytes = (struct dbus_byte *)param[i]; + g_variant_builder_add(&builder, "@ay", + g_variant_new_from_data(G_VARIANT_TYPE("ay"), + bytes->data, bytes->size, TRUE, NULL, NULL)); break; default: break; } break; default: - return -EINVAL; + return NULL; } } - return 0; + return g_variant_builder_end(&builder); } -int dbus_method_sync(const char *dest, const char *path, - const char *interface, const char *method, - const char *sig, char *param[]) +static struct proxy_node *find_matched_proxy_node(const char *dest, + const char *path, + const char *interface) { - DBusConnection *conn; - DBusMessage *msg; - DBusMessageIter iter; - DBusMessage *reply; - DBusError err; - int ret, result; - - conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); - if (!conn) { - _E("dbus_bus_get error"); //LCOV_EXCL_LINE - return -EPERM; + GList *elem; + struct proxy_node *node; + int plen; + + if (!dest || !path || !interface) + return NULL; + + plen = strlen(path) + 1; + + /* find matched proxy object */ + for (elem = proxy_pool; elem; elem = elem->next) { + node = elem->data; + if (!node) + continue; + if (!strncmp(node->dest, dest, DBUS_MAXIMUM_NAME_LENGTH) && + !strncmp(node->path, path, plen) && + !strncmp(node->interface, interface, + DBUS_MAXIMUM_NAME_LENGTH)) + return node; } - msg = dbus_message_new_method_call(dest, path, interface, method); - if (!msg) { - _E("dbus_message_new_method_call(%s:%s-%s)", //LCOV_EXCL_LINE - path, interface, method); - return -EBADMSG; + return NULL; +} + +static void on_name_vanished(GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + GList *elem; + GList *next; + struct proxy_node *node; + + pthread_mutex_lock(&dmutex); + for (elem = proxy_pool, next = g_list_next(elem); elem; + elem = next, next = g_list_next(elem)) { + node = elem->data; + if (!node) + continue; + proxy_pool = g_list_delete_link(proxy_pool, elem); + g_object_unref(node->proxy); + free(node->dest); + free(node->path); + free(node->interface); + free(node); } + pthread_mutex_unlock(&dmutex); +} + +static GDBusProxy *get_proxy_from_proxy_pool(const char *dest, + const char *path, + const char *interface, + GError **err) +{ + GDBusConnection *conn; + GDBusProxy *proxy; + struct proxy_node *node; - dbus_message_iter_init_append(msg, &iter); - ret = append_variant(&iter, sig, param); - if (ret < 0) { - _E("append_variant error(%d) %s %s:%s-%s", //LCOV_EXCL_LINE - ret, dest, path, interface, method); - dbus_message_unref(msg); - return ret; + if (!dest || !path || !interface) { + if (err) + g_set_error(err, G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "Cannot determine destination address"); + return NULL; } - dbus_error_init(&err); + /* find matched proxy node in proxy pool */ + node = find_matched_proxy_node(dest, path, interface); + if (node) + return node->proxy; - reply = dbus_connection_send_with_reply_and_block(conn, msg, DBUS_REPLY_TIMEOUT, &err); - dbus_message_unref(msg); - if (!reply) { - _E("dbus_connection_send error(%s:%s) %s %s:%s-%s", //LCOV_EXCL_LINE - err.name, err.message, dest, path, interface, method); - dbus_error_free(&err); //LCOV_EXCL_LINE System Error - return -ECOMM; + conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, err); + if (!conn) + return NULL; + + if (!bus_init) { + bus_init++; + g_bus_watch_name_on_connection(conn, + DEVICED_BUS_NAME, + G_BUS_NAME_WATCHER_FLAGS_NONE, + NULL, + on_name_vanished, + NULL, + NULL); + } + + proxy = g_dbus_proxy_new_sync(conn, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* GDBusinterfaceinfo */ + dest, /* bus name */ + path, /* object path */ + interface, /* interface name */ + NULL, /* GCancellable */ + err); + if (!proxy) + return NULL; + + node = malloc(sizeof(struct proxy_node)); + if (!node) { + g_object_unref(proxy); + if (err) + g_set_error(err, G_IO_ERROR, + G_IO_ERROR_FAILED, + "Cannot allocate proxy_node memory"); + return NULL; + } + + node->proxy = proxy; + node->dest = strdup(dest); + node->path = strdup(path); + node->interface = strdup(interface); + + proxy_pool = g_list_append(proxy_pool, node); + + return proxy; +} + +int dbus_method_sync(const char *dest, const char *path, + const char *interface, const char *method, + const char *sig, char *param[]) +{ + GDBusProxy *proxy; + GError *err = NULL; + GVariant *output; + int result; + +#if !GLIB_CHECK_VERSION(2,35,0) + g_type_init(); +#endif + + pthread_mutex_lock(&dmutex); + proxy = get_proxy_from_proxy_pool(dest, path, interface, &err); + if (!proxy) { + pthread_mutex_unlock(&dmutex); + _E("fail to get proxy from proxy pool : %s-%s (%d-%s)", + interface, method, err->code, err->message); + result = g_dbus_error_to_errno(err->code); + g_clear_error(&err); + return result; } - ret = dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &result, DBUS_TYPE_INVALID); - dbus_message_unref(reply); - if (!ret) { - if (dbus_error_is_set(&err)) { - _E("error : [%s:%s] %s %s:%s-%s", //LCOV_EXCL_LINE - err.name, err.message, dest, path, interface, method); - dbus_error_free(&err); //LCOV_EXCL_LINE System Error - } else - _E("no message"); //LCOV_EXCL_LINE - return -ENOMSG; + output = g_dbus_proxy_call_sync(proxy, + method, /* method name */ + append_g_variant(sig, param), /* parameters */ + G_DBUS_CALL_FLAGS_NONE, + DBUS_REPLY_TIMEOUT, /* timeout */ + NULL, /* GCancellable */ + &err); + pthread_mutex_unlock(&dmutex); + + if (!output) { + if (err) { + _E("g_dbus_proxy_call_sync error : %s-%s (%d-%s)", + interface, method, err->code, err->message); + result = g_dbus_error_to_errno(err->code); + g_clear_error(&err); + } else { + _E("g_dbus_proxy_call_sync error : %s-%s", + interface, method); + result = -ECOMM; + } + return result; } + /* get output value */ + g_variant_get(output, "(i)", &result); + + g_variant_unref(output); + return result; } diff --git a/src/dbus.h b/src/dbus.h index 8c66655..65bf222 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -20,7 +20,7 @@ #ifndef __DBUS_H__ #define __DBUS_H__ -#include +#include /* * Device daemon @@ -46,4 +46,10 @@ struct dbus_byte { int dbus_method_sync(const char *dest, const char *path, const char *interface, const char *method, const char *sig, char *param[]); + +/** + * If result is NULL, err is set. + * Do not invoke g_variant_unref() with result. + */ +typedef void (*dbus_pending_cb)(void *data, GVariant *result, GError *err); #endif