Change libdbus to gdbus and add proxy pool 55/93555/5
authorpr.jung <pr.jung@samsung.com>
Mon, 24 Oct 2016 10:57:23 +0000 (19:57 +0900)
committerpr.jung <pr.jung@samsung.com>
Thu, 27 Oct 2016 06:34:47 +0000 (15:34 +0900)
- 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 <pr.jung@samsung.com>
src/dbus.c
src/dbus.h

index 53db49b..0a8c18c 100644 (file)
@@ -20,6 +20,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include "common.h"
 /* -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, &param[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;
 }
index 8c66655..65bf222 100644 (file)
@@ -20,7 +20,7 @@
 #ifndef __DBUS_H__
 #define __DBUS_H__
 
-#include <dbus/dbus.h>
+#include <gio/gio.h>
 
 /*
  * 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