summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorSuchang Woo <suchang.woo@samsung.com>2015-07-16 17:12:54 +0900
committerSuchang Woo <suchang.woo@samsung.com>2015-07-16 17:28:30 +0900
commitd966429452d4ff6a3527f0deb8db63be5b87f720 (patch)
treea811fe0a17e1c6b69868cf1176eb99815227238b /common
parent99b1d99a4f93a6bf0786abc6ae5ad1f3d9415933 (diff)
downloadbuxton2-master.tar.gz
buxton2-master.tar.bz2
buxton2-master.zip
Initial importHEADmaster
Signed-off-by: Suchang Woo <suchang.woo@samsung.com>
Diffstat (limited to 'common')
-rw-r--r--common/backend.h74
-rw-r--r--common/backends.c205
-rw-r--r--common/backends.h31
-rw-r--r--common/common.c127
-rw-r--r--common/common.h124
-rw-r--r--common/config.c305
-rw-r--r--common/config.h30
-rw-r--r--common/direct.c548
-rw-r--r--common/direct.h44
-rw-r--r--common/log.h49
-rw-r--r--common/proto.c328
-rw-r--r--common/proto.h33
-rw-r--r--common/serialize.c970
-rw-r--r--common/serialize.h70
14 files changed, 2938 insertions, 0 deletions
diff --git a/common/backend.h b/common/backend.h
new file mode 100644
index 0000000..7e04922
--- /dev/null
+++ b/common/backend.h
@@ -0,0 +1,74 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdlib.h>
+
+#ifndef EXPORT
+# define EXPORT __attribute__((visibility("default")))
+#endif
+
+typedef int (*backend_module_init)(void);
+typedef void (*backend_module_exit)(void);
+
+typedef int (*backend_open_db)(const char *dbpath);
+typedef int (*backend_remove_db)(const char *dbpath);
+typedef int (*backend_set_value)(const char *dbpath,
+ const char *key, const void *data, int dlen);
+typedef int (*backend_get_value)(const char *dbpath,
+ const char *key, void **data, int *dlen);
+typedef int (*backend_unset_value)(const char *dbpath, const char *key);
+typedef int (*backend_list_keys)(const char *dbpath,
+ char ***keys, unsigned int *klen);
+
+struct backend {
+ const char *name;
+
+ backend_module_init module_init;
+ backend_module_exit module_exit;
+
+ backend_open_db open_db;
+ backend_remove_db remove_db;
+ backend_set_value set_value;
+ backend_get_value get_value;
+ backend_unset_value unset_value;
+ backend_list_keys list_keys;
+
+ void *reserved[7];
+};
+
+static inline void backend_list_free(char **keys)
+{
+ char **k;
+
+ if (!keys)
+ return;
+
+ k = keys;
+ while (*k) {
+ free(*k);
+ k++;
+ }
+
+ free(keys);
+}
+
+#define BUXTON_BACKEND_SYMBOL "buxton_backend"
+#define DEFINE_BUXTON_BACKEND EXPORT const struct backend buxton_backend
+
diff --git a/common/backends.c b/common/backends.c
new file mode 100644
index 0000000..fbeaf53
--- /dev/null
+++ b/common/backends.c
@@ -0,0 +1,205 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <dlfcn.h>
+
+#include <glib.h>
+
+#include "backend.h"
+#include "log.h"
+
+static GHashTable *backends;
+
+struct module {
+ void *handle;
+ const struct backend *backend;
+};
+
+static void free_backend(struct module *mod)
+{
+ if (!mod)
+ return;
+
+ if (mod->backend && mod->backend->module_exit)
+ mod->backend->module_exit();
+
+ if (mod->handle)
+ dlclose(mod->handle);
+
+ free(mod);
+}
+
+const struct backend *backend_get(const char *name)
+{
+ struct module *mod;
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!backends) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ mod = g_hash_table_lookup(backends, name);
+ if (!mod)
+ errno = ENOENT;
+
+ return mod->backend;
+}
+
+static struct module *load_module(const char *moddir, const char *modname)
+{
+ struct module *mod;
+ const struct backend *backend;
+ void *handle;
+ int r;
+ char modpath[FILENAME_MAX];
+
+ assert(moddir);
+ assert(modname);
+
+ snprintf(modpath, sizeof(modpath), "%s/%s", moddir, modname);
+
+ handle = dlopen(modpath, RTLD_NOW);
+ if (!handle) {
+ bxt_err("load '%s' error: %s", modpath, dlerror());
+ return NULL;
+ }
+
+ mod = calloc(1, sizeof(*mod));
+ if (!mod) {
+ bxt_err("load '%s' error: Not enough space", modpath);
+ goto err;
+ }
+
+ dlerror();
+ backend = dlsym(handle, BUXTON_BACKEND_SYMBOL);
+ if (!backend) {
+ bxt_err("load '%s' error: %s", modpath, dlerror());
+ goto err;
+ }
+
+ if (!backend->name || !*backend->name) {
+ bxt_err("load '%s' error: no name", modpath);
+ goto err;
+ }
+
+ if (!backend->module_init) {
+ bxt_err("load '%s' error: no init", modpath);
+ goto err;
+ }
+
+ r = backend->module_init();
+ if (r) {
+ bxt_err("load '%s' error: init: %d", modpath, errno);
+ goto err;
+ }
+
+ mod->handle = handle;
+ mod->backend = backend;
+
+ return mod;
+
+err:
+ dlclose(handle);
+ free(mod);
+ return NULL;
+}
+
+static int load_modules(const char *moddir)
+{
+ DIR *dir;
+ struct dirent *de;
+ char *ext;
+ struct module *mod;
+
+ assert(moddir);
+ assert(backends);
+
+ dir = opendir(moddir);
+ if (!dir) {
+ bxt_err("opendir error: %d", errno);
+ return -1;
+ }
+
+ while ((de = readdir(dir)) != NULL) {
+ ext = strrchr(de->d_name, '.');
+ if (!ext)
+ continue;
+
+ if (strncmp(ext, ".so", sizeof(".so")))
+ continue;
+
+ mod = load_module(moddir, de->d_name);
+ if (mod) {
+ g_hash_table_insert(backends,
+ (gpointer)mod->backend->name, mod);
+ }
+ }
+
+ closedir(dir);
+
+ return 0;
+}
+
+GList *backend_list(void)
+{
+ GList *list;
+
+ if (!backends)
+ return NULL;
+
+ list = g_hash_table_get_keys(backends);
+
+ return list;
+}
+
+void backend_exit(void)
+{
+ g_hash_table_destroy(backends);
+ backends = NULL;
+}
+
+int backend_init(const char *moddir)
+{
+ if (!moddir || !*moddir) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (backends)
+ return 0;
+
+ backends = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify)free_backend);
+ if (!backends) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return load_modules(moddir);
+}
+
diff --git a/common/backends.h b/common/backends.h
new file mode 100644
index 0000000..46cb1c6
--- /dev/null
+++ b/common/backends.h
@@ -0,0 +1,31 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <glib.h>
+
+#include "backend.h"
+
+int backend_init(const char *moddir);
+void backend_exit(void);
+const struct backend *backend_get(const char *name);
+
+/* Do not free the content of list. use g_list_free() */
+GList *backend_list(void);
+
diff --git a/common/common.c b/common/common.c
new file mode 100644
index 0000000..daf90fd
--- /dev/null
+++ b/common/common.c
@@ -0,0 +1,127 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <errno.h>
+
+#include "common.h"
+
+struct buxton_layer *layer_create(const char *layer_name)
+{
+ struct buxton_layer *layer;
+
+ if (!layer_name || !*layer_name) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ layer = calloc(1, sizeof(*layer));
+ if (!layer)
+ return NULL;
+
+ layer->name = strdup(layer_name);
+ if (!layer->name) {
+ free(layer);
+ return NULL;
+ }
+
+ layer->refcnt = 1;
+ layer->uid = getuid();
+ layer->type = BUXTON_LAYER_NORMAL;
+
+ return layer;
+}
+
+/* ignore ref. count */
+void layer_free(struct buxton_layer *layer)
+{
+ if (!layer)
+ return;
+
+ free(layer->name);
+ free(layer);
+}
+
+struct buxton_layer *layer_ref(struct buxton_layer *layer)
+{
+ if (!layer)
+ return NULL;
+
+ layer->refcnt++;
+
+ return layer;
+}
+
+struct buxton_layer *layer_unref(struct buxton_layer *layer)
+{
+ if (!layer)
+ return NULL;
+
+ layer->refcnt--;
+ if (layer->refcnt == 0) {
+ layer_free(layer);
+ return NULL;
+ }
+
+ return layer;
+}
+
+void value_free(struct buxton_value *val)
+{
+ if (!val)
+ return;
+
+ switch (val->type) {
+ case BUXTON_TYPE_STRING:
+ free(val->value.s);
+ break;
+ default:
+ break;
+ }
+}
+
+char *get_search_key(const struct buxton_layer *layer, const char *key,
+ const char *uid)
+{
+ char *lykey;
+ int keylen;
+
+ if (!layer || !key || !*key) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ keylen = strlen(layer->name) + strlen(key) + 2;
+
+ if (uid)
+ keylen += strlen(uid) + 1;
+
+ lykey = malloc(keylen);
+ if (!lykey)
+ return NULL;
+
+ snprintf(lykey, keylen, "%s\t%s%s%s", layer->name, key,
+ uid ? "\t" : "", uid ? uid : "");
+
+ return lykey;
+}
+
diff --git a/common/common.h b/common/common.h
new file mode 100644
index 0000000..7d2838e
--- /dev/null
+++ b/common/common.h
@@ -0,0 +1,124 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+#include "buxton2.h"
+
+#ifndef CONFPATH
+# warning "CONFPATH is not set. default value is used"
+# define CONFPATH "/etc/buxton.conf"
+#endif
+
+#ifndef MODULE_DIR
+# warning "MODULE_DIR is not set. default value is used"
+# define MODULE_DIR "/usr/lib/buxton"
+#endif
+
+#ifndef DB_DIR
+# warning "DB_DIR is not set. default value is used"
+# define DB_DIR "/var/lib/buxton"
+#endif
+
+#ifndef TMPFS_DIR
+# warning "TMPFS_DIR is not set. default value is used"
+# define TMPFS_DIR "/run/buxton"
+#endif
+
+#ifndef SOCKPATH
+# warning "SOCKPATH is not set. default value is used"
+# define SOCKPATH "/run/buxton-0"
+#endif
+
+enum layer_type {
+ LAYER_UNKNWON = 0,
+ LAYER_SYSTEM,
+ LAYER_USER,
+ LAYER_MAX, /* sentinel value */
+};
+
+enum storage_type {
+ STORAGE_UNKNOWN = 0,
+ STORAGE_PERSISTENT,
+ STORAGE_VOLATILE,
+ STORAGE_MAX, /* sentinel value */
+};
+
+struct layer {
+ gchar *name;
+ enum layer_type type;
+ gchar *backend;
+ enum storage_type storage;
+ gchar *description;
+};
+
+enum message_type {
+ MSG_UNKNOWN = 0,
+ /* basic request */
+ MSG_SET,
+ MSG_GET,
+ MSG_CREAT,
+ MSG_UNSET,
+ MSG_LIST,
+ MSG_NOTIFY,
+ MSG_UNNOTIFY,
+ MSG_NOTI,
+ /* privilege request */
+ MSG_SET_WP,
+ MSG_SET_RP,
+ MSG_GET_WP,
+ MSG_GET_RP,
+ MSG_MAX, /* sentinel value */
+};
+
+struct buxton_layer {
+ int refcnt;
+ char *name;
+ uid_t uid;
+ enum buxton_layer_type type;
+};
+
+struct buxton_layer *layer_create(const char *layer_name);
+void layer_free(struct buxton_layer *layer);
+
+struct buxton_layer *layer_ref(struct buxton_layer *layer);
+struct buxton_layer *layer_unref(struct buxton_layer *layer);
+
+struct buxton_value {
+ enum buxton_key_type type;
+ union {
+ char *s;
+ int32_t i;
+ uint32_t u;
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ int32_t b;
+ } value;
+};
+
+void value_free(struct buxton_value *val);
+
+char *get_search_key(const struct buxton_layer *layer, const char *key,
+ const char *uid);
+
diff --git a/common/config.c b/common/config.c
new file mode 100644
index 0000000..db144d7
--- /dev/null
+++ b/common/config.c
@@ -0,0 +1,305 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <glib.h>
+
+#include "log.h"
+#include "config.h"
+
+#define K_TYPE "Type"
+#define K_BACKEND "Backend"
+#define K_STORAGE "Storage"
+#define K_DESC "Description"
+
+#define K_T_SYSTEM "System"
+#define K_T_USER "User"
+
+#define K_B_DB "persistent"
+#define K_B_MEM "volatile"
+
+static GHashTable *layers;
+
+static void free_layer(struct layer *layer)
+{
+ if (!layer)
+ return;
+
+ g_free(layer->name);
+ g_free(layer->backend);
+ g_free(layer->description);
+ free(layer);
+}
+
+static GKeyFile *load_conf(const char *confpath)
+{
+ GKeyFile *kf;
+ gboolean b;
+ GError *err;
+
+ assert(confpath);
+
+ kf = g_key_file_new();
+ if (!kf) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ err = NULL;
+ b = g_key_file_load_from_file(kf, confpath, G_KEY_FILE_NONE, &err);
+ if (!b) {
+ bxt_err("Load '%s' error: %s", confpath,
+ err ? err->message : "");
+ g_clear_error(&err);
+ g_key_file_free(kf);
+ return NULL;
+ }
+
+ return kf;
+}
+
+static struct layer *create_layer(GKeyFile *kf, gchar *name)
+{
+ GError *err;
+ struct layer *layer;
+ gchar *s;
+
+ assert(name && *name);
+
+ layer = calloc(1, sizeof(*layer));
+ if (!layer)
+ goto err;
+
+ /* 'Type' */
+ err = NULL;
+ s = g_key_file_get_string(kf, name, K_TYPE, &err);
+ if (!s) {
+ bxt_err("Layer '%s' : %s",
+ name, err ? err->message : "");
+ g_clear_error(&err);
+ goto err;
+ }
+
+ if (!strncmp(s, K_T_SYSTEM, sizeof(K_T_SYSTEM)))
+ layer->type = LAYER_SYSTEM;
+ else if (!strncmp(s, K_T_USER, sizeof(K_T_USER)))
+ layer->type = LAYER_USER;
+
+ g_free(s);
+
+ /* 'Backend' */
+ s = g_key_file_get_string(kf, name, K_BACKEND, &err);
+ if (!s) {
+ bxt_err("Layer '%s' : %s",
+ name, err ? err->message : "");
+ g_clear_error(&err);
+ goto err;
+ }
+
+ layer->backend = s;
+
+ /* 'Storage' */
+ s = g_key_file_get_string(kf, name, K_STORAGE, &err);
+ if (!s) {
+ bxt_err("Layer '%s' : %s",
+ name, err ? err->message : "");
+ g_clear_error(&err);
+ goto err;
+ }
+
+ if (!strncasecmp(s, K_B_DB, sizeof(K_B_DB)))
+ layer->storage = STORAGE_PERSISTENT;
+ else if (!strncasecmp(s, K_B_MEM, sizeof(K_B_MEM)))
+ layer->storage = STORAGE_VOLATILE;
+
+ g_free(s);
+
+ /* 'Description' */
+ s = g_key_file_get_string(kf, name, K_DESC, &err);
+ if (!s) {
+ bxt_err("Layer '%s' : %s",
+ name, err ? err->message : "");
+ g_clear_error(&err);
+ goto err;
+ }
+
+ layer->description = s;
+
+ /* Layer name */
+ layer->name = name;
+
+ return layer;
+
+err:
+ g_free(name);
+ free_layer(layer);
+
+ return NULL;
+}
+
+static gboolean has_backend(GList *backends, const char *name)
+{
+ GList *l;
+
+ if (!name || !*name)
+ return FALSE;
+
+ for (l = backends; l; l = g_list_next(l)) {
+ const char *nm = l->data;
+
+ if (nm && !strcmp(name, nm))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void add_layers(GKeyFile *kf, GList *backends)
+{
+ gchar **lays;
+ int i;
+ struct layer *layer;
+ struct layer *f;
+ gboolean b;
+
+ assert(kf);
+ assert(layers);
+
+ lays = g_key_file_get_groups(kf, NULL);
+ if (!lays) {
+ bxt_err("No specified layers");
+ return;
+ }
+
+ i = 0;
+ while (lays[i]) {
+ layer = create_layer(kf, lays[i++]);
+ if (!layer)
+ continue;
+
+ b = has_backend(backends, layer->backend);
+ if (!b) {
+ bxt_err("Layer '%s' : invalid backend", layer->name);
+ free_layer(layer);
+ continue;
+ }
+
+ f = g_hash_table_lookup(layers, layer->name);
+ if (f) {
+ bxt_err("Layer '%s' : already exists", layer->name);
+ free_layer(layer);
+ continue;
+ }
+
+ if (layer->type == LAYER_UNKNWON) {
+ bxt_err("Layer '%s' : unknwon type", layer->name);
+ free_layer(layer);
+ continue;
+ }
+
+ if (layer->storage == STORAGE_UNKNOWN) {
+ bxt_err("Layer '%s' : unknwon storage type",
+ layer->name);
+ free_layer(layer);
+ continue;
+ }
+
+ g_hash_table_insert(layers, layer->name, layer);
+ }
+
+ g_free(lays);
+}
+
+const struct layer *conf_get_layer(const char *name)
+{
+ const struct layer *layer;
+
+ if (!name || !*name) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ if (!layers) {
+ errno = ENOENT;
+ return NULL;
+ }
+
+ layer = g_hash_table_lookup(layers, name);
+ if (!layer) {
+ bxt_dbg("Layer '%s' not exist", name);
+ errno = ENOENT;
+ }
+
+ return layer;
+}
+
+int conf_remove(const char *name)
+{
+ const struct layer *layer;
+ gboolean b;
+
+ layer = conf_get_layer(name);
+ if (!layer)
+ return -1;
+
+ b = g_hash_table_remove(layers, name);
+
+ return b ? 0 : -1;
+}
+
+void conf_exit(void)
+{
+ g_hash_table_destroy(layers);
+ layers = NULL;
+}
+
+int conf_init(const char *confpath, GList *backends)
+{
+ GKeyFile *kf;
+
+ if (!confpath || !*confpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (layers)
+ return 0;
+
+ kf = load_conf(confpath);
+ if (!kf)
+ return -1;
+
+ layers = g_hash_table_new_full(g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify)free_layer);
+ if (!layers) {
+ errno = ENOMEM;
+ g_key_file_free(kf);
+ return -1;
+ }
+
+ add_layers(kf, backends);
+
+ g_key_file_free(kf);
+
+ return 0;
+}
diff --git a/common/config.h b/common/config.h
new file mode 100644
index 0000000..52bce85
--- /dev/null
+++ b/common/config.h
@@ -0,0 +1,30 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <glib.h>
+
+#include "common.h"
+
+int conf_init(const char *confpath, GList *backends);
+void conf_exit(void);
+
+const struct layer *conf_get_layer(const char *name);
+int conf_remove(const char *name);
+
diff --git a/common/direct.c b/common/direct.c
new file mode 100644
index 0000000..1725863
--- /dev/null
+++ b/common/direct.c
@@ -0,0 +1,548 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "buxton2.h"
+
+#include "common.h"
+#include "log.h"
+#include "direct.h"
+#include "config.h"
+#include "backends.h"
+#include "serialize.h"
+
+static int get_path(uid_t uid, enum buxton_layer_type type,
+ const struct layer *ly, char *path, int sz)
+{
+ const char *prefix;
+ char suffix[16];
+
+ if (!ly || !path || sz <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (type == BUXTON_LAYER_NORMAL && ly->storage == STORAGE_VOLATILE)
+ prefix = TMPFS_DIR;
+ else
+ prefix = DB_DIR;
+
+ if (type == BUXTON_LAYER_NORMAL && ly->type == LAYER_USER)
+ snprintf(suffix, sizeof(suffix), "-%u", uid);
+ else
+ suffix[0] = '\0';
+
+ snprintf(path, sz, "%s/%s%s.db", prefix, ly->name, suffix);
+
+ return 0;
+}
+
+static int get_raw(const struct layer *ly, uid_t uid,
+ enum buxton_layer_type type, const char *key,
+ uint8_t **data, int *len)
+{
+ int r;
+ const struct backend *backend;
+ char path[FILENAME_MAX];
+
+ assert(ly);
+ assert(key);
+ assert(data);
+ assert(len);
+
+ backend = backend_get(ly->backend);
+ assert(backend);
+
+ if (!backend->get_value) {
+ bxt_err("Get: backend '%s' has no get func", backend->name);
+ return -1;
+ }
+
+ r = get_path(uid, type, ly, path, sizeof(path));
+ if (r == -1)
+ return -1;
+
+ r = backend->get_value(path, key, (void **)data, len);
+ if (r == -1) {
+ if (errno != ENOENT)
+ bxt_err("Get: get_value: %d", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int get_val(const struct layer *ly, uid_t uid,
+ enum buxton_layer_type type, const char *key,
+ char **rpriv, char **wpriv, struct buxton_value *val)
+{
+ int r;
+ uint8_t *data;
+ int len;
+
+ assert(ly);
+ assert(key);
+
+ r = get_raw(ly, uid, type, key, &data, &len);
+ if (r == -1)
+ return -1;
+
+ r = deserialz_data(data, len, rpriv, wpriv, val);
+
+ free(data);
+
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+int direct_get(const struct buxton_layer *layer,
+ const char *key, struct buxton_value *val)
+{
+ int r;
+ const struct layer *ly;
+ struct buxton_value base_val;
+ struct buxton_value db_val;
+
+ if (!layer || !key || !*key || !val) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ /* First, refer to base db */
+ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, NULL, NULL,
+ &base_val);
+ if (r == -1)
+ return -1;
+
+ if (layer->type == BUXTON_LAYER_BASE) {
+ *val = base_val;
+ return 0;
+ }
+
+ /* DB backend System layer has no normal db */
+ if (ly->type == LAYER_SYSTEM && ly->storage == STORAGE_PERSISTENT) {
+ *val = base_val;
+ return 0;
+ }
+
+ r = get_val(ly, layer->uid, BUXTON_LAYER_NORMAL, key, NULL, NULL,
+ &db_val);
+ if (r == -1 && errno != ENOENT) {
+ value_free(&base_val);
+ return -1;
+ }
+
+ if (errno == ENOENT) {
+ *val = base_val;
+ return 0;
+ }
+
+ value_free(&base_val);
+ *val = db_val;
+
+ return 0;
+}
+
+int direct_check(const struct buxton_layer *layer, const char *key)
+{
+ int r;
+ const struct layer *ly;
+ struct buxton_value val;
+
+ if (!layer || !key || !*key) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, NULL, NULL, &val);
+ if (r == -1)
+ return -1;
+
+ value_free(&val);
+
+ return 0;
+}
+
+static int set_raw(const struct layer *ly, uid_t uid,
+ enum buxton_layer_type type, const char *key,
+ uint8_t *data, int len)
+{
+ int r;
+ const struct backend *backend;
+ char path[FILENAME_MAX];
+
+ assert(ly);
+ assert(key);
+ assert(data);
+ assert(len > 0);
+
+ backend = backend_get(ly->backend);
+ assert(backend);
+
+ if (!backend->set_value) {
+ bxt_err("Set: backend '%s' has no set func", backend->name);
+ return -1;
+ }
+
+ r = get_path(uid, type, ly, path, sizeof(path));
+ if (r == -1)
+ return -1;
+
+ r = backend->set_value(path, key, data, len);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+static int set_val(const struct layer *ly, uid_t uid,
+ enum buxton_layer_type type, const char *key,
+ const char *rpriv, const char *wpriv,
+ const struct buxton_value *val)
+{
+ int r;
+ uint8_t *data;
+ int len;
+
+ assert(val);
+
+ r = serialz_data(rpriv ? rpriv : "", wpriv ? wpriv : "", val,
+ &data, &len);
+ if (r == -1)
+ return -1;
+
+ r = set_raw(ly, uid, type, key, data, len);
+
+ free(data);
+
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+int direct_set(const struct buxton_layer *layer,
+ const char *key, const struct buxton_value *val)
+{
+ int r;
+ const struct layer *ly;
+ char *rp;
+ char *wp;
+
+ if (!layer || !key || !*key || !val) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, &rp, &wp, NULL);
+ if (r == -1)
+ return -1;
+
+ r = set_val(ly, layer->uid, layer->type, key, rp, wp, val);
+
+ free(rp);
+ free(wp);
+
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+int direct_create(const struct buxton_layer *layer, const char *key,
+ const char *rpriv, const char *wpriv,
+ const struct buxton_value *val)
+{
+ int r;
+ const struct layer *ly;
+
+ if (!layer || !key || !*key || !val) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ r = check_key_name(key);
+ if (r == -1)
+ return -1;
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, NULL, NULL, NULL);
+ if (r == -1 && errno != ENOENT)
+ return -1;
+
+ if (r == 0) {
+ errno = EEXIST;
+ return -1;
+ }
+
+ r = set_val(ly, layer->uid, BUXTON_LAYER_BASE, key, rpriv, wpriv, val);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+int direct_unset(const struct buxton_layer *layer, const char *key)
+{
+ int r;
+ const struct layer *ly;
+ const struct backend *backend;
+ char path[FILENAME_MAX];
+
+ if (!layer || !key || !*key) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ backend = backend_get(ly->backend);
+ assert(backend);
+
+ if (!backend->unset_value) {
+ bxt_err("Unset: backend '%s' has no unset func",
+ backend->name);
+ return -1;
+ }
+
+ r = get_path(layer->uid, layer->type, ly, path, sizeof(path));
+ if (r == -1)
+ return -1;
+
+ r = backend->unset_value(path, key);
+ if (r == -1) {
+ bxt_err("Unset: unset_value: %d", errno);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int comp_str(const void *pa, const void *pb)
+{
+ const char *sa = pa ? *(char * const *)pa : "";
+ const char *sb = pb ? *(char * const *)pb : "";
+
+ return strcmp(sa, sb);
+}
+
+int direct_list(const struct buxton_layer *layer,
+ char ***names, unsigned int *len)
+{
+ int r;
+ const struct layer *ly;
+ const struct backend *backend;
+ char path[FILENAME_MAX];
+ unsigned int _len;
+
+ if (!layer || !names) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ backend = backend_get(ly->backend);
+ assert(backend);
+
+ if (!backend->list_keys) {
+ bxt_err("List: backend '%s' has no list func",
+ backend->name);
+ return -1;
+ }
+
+ r = get_path(layer->uid, BUXTON_LAYER_BASE, ly, path, sizeof(path));
+ if (r == -1)
+ return -1;
+
+ r = backend->list_keys(path, names, &_len);
+ if (r == -1) {
+ bxt_err("List: list_keys: %d", errno);
+ return -1;
+ }
+
+ if (_len > 1)
+ qsort(*names, _len, sizeof(char *), comp_str);
+
+ if (len)
+ *len = _len;
+
+ return 0;
+}
+
+int direct_get_priv(const struct buxton_layer *layer,
+ const char *key, enum buxton_priv_type type, char **priv)
+{
+ int r;
+ const struct layer *ly;
+ char **rp;
+ char **wp;
+
+ if (!layer || !key || !*key || !priv) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch (type) {
+ case BUXTON_PRIV_READ:
+ rp = priv;
+ wp = NULL;
+ break;
+ case BUXTON_PRIV_WRITE:
+ rp = NULL;
+ wp = priv;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, rp, wp, NULL);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+int direct_set_priv(const struct buxton_layer *layer,
+ const char *key, enum buxton_priv_type type, const char *priv)
+{
+ int r;
+ const struct layer *ly;
+ char *rp;
+ char *wp;
+ const char *t_rp;
+ const char *t_wp;
+ struct buxton_value val;
+
+ if (!layer || !key || !*key || !priv) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ switch (type) {
+ case BUXTON_PRIV_READ:
+ case BUXTON_PRIV_WRITE:
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ ly = conf_get_layer(layer->name);
+ if (!ly)
+ return -1;
+
+ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, &rp, &wp, &val);
+ if (r == -1)
+ return -1;
+
+ switch (type) {
+ case BUXTON_PRIV_READ:
+ t_rp = priv;
+ t_wp = wp;
+ break;
+ case BUXTON_PRIV_WRITE:
+ t_rp = rp;
+ t_wp = priv;
+ break;
+ default: /* Never reach */
+ t_rp = rp;
+ t_wp = wp;
+ break;
+ }
+
+ r = set_val(ly, layer->uid, BUXTON_LAYER_BASE, key, t_rp, t_wp, &val);
+
+ value_free(&val);
+ free(rp);
+ free(wp);
+
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+void direct_exit(void)
+{
+ conf_exit();
+ backend_exit();
+}
+
+int direct_init(const char *moddir, const char *confpath)
+{
+ int r;
+ GList *backends;
+
+ if (!moddir || !*moddir || !confpath || !*confpath) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ r = backend_init(moddir);
+ if (r == -1)
+ return -1;
+
+ backends = backend_list();
+ if (!backends)
+ return -1;
+
+ r = conf_init(confpath, backends);
+
+ g_list_free(backends);
+
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
diff --git a/common/direct.h b/common/direct.h
new file mode 100644
index 0000000..722f62d
--- /dev/null
+++ b/common/direct.h
@@ -0,0 +1,44 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "buxton2.h"
+
+int direct_init(const char *moddir, const char *confpath);
+void direct_exit(void);
+
+int direct_get(const struct buxton_layer *layer,
+ const char *key, struct buxton_value *val);
+int direct_set(const struct buxton_layer *layer,
+ const char *key, const struct buxton_value *val);
+int direct_check(const struct buxton_layer *layer, const char *key);
+
+int direct_create(const struct buxton_layer *layer, const char *key,
+ const char *rprive, const char *wpriv,
+ const struct buxton_value *val);
+int direct_unset(const struct buxton_layer *layer, const char *key);
+
+int direct_list(const struct buxton_layer *layer,
+ char ***names, unsigned int *len);
+
+int direct_get_priv(const struct buxton_layer *layer,
+ const char *key, enum buxton_priv_type type, char **priv);
+int direct_set_priv(const struct buxton_layer *layer,
+ const char *key, enum buxton_priv_type type, const char *priv);
+
diff --git a/common/log.h b/common/log.h
new file mode 100644
index 0000000..0de5696
--- /dev/null
+++ b/common/log.h
@@ -0,0 +1,49 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#if defined(_DLOG_H_)
+
+# define bxt_info(fmt, ...) LOGI(fmt, ##__VA_ARGS__)
+# define bxt_err(fmt, ...) LOGE(fmt, ##__VA_ARGS__)
+# define bxt_dbg(fmt, ...) LOGD(fmt, ##__VA_ARGS__)
+
+#else /* _DLOG_H_ */
+
+# include <stdio.h>
+
+# if defined(NDEBUG)
+
+# define bxt_info(fmt, ...) printf("Buxton: " fmt "\n", ##__VA_ARGS__)
+# define bxt_err(fmt, ...) \
+ fprintf(stderr, "Buxton: " fmt "\n", ##__VA_ARGS__)
+# define bxt_dbg(fmt, ...) do { } while (0)
+
+# else /* NDEBUG */
+
+# define bxt_info(fmt, ...) printf("Buxton: " fmt "\n", ##__VA_ARGS__)
+# define bxt_err(fmt, ...) \
+ fprintf(stderr, "Buxton:Err: " fmt "\n", ##__VA_ARGS__)
+# define bxt_dbg(fmt, ...) \
+ printf("Buxton:D:%s:%d: " fmt "\n", __func__, __LINE__, \
+ ##__VA_ARGS__)
+
+# endif
+
+#endif /* _DLOG_H_ */
diff --git a/common/proto.c b/common/proto.c
new file mode 100644
index 0000000..b87e396
--- /dev/null
+++ b/common/proto.c
@@ -0,0 +1,328 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <poll.h>
+
+#include "common.h"
+#include "log.h"
+#include "proto.h"
+
+#define SEND_TIMEOUT_MSEC 1000
+#define SEND_PACKET_MAX 8192
+
+struct recv_info {
+ int fd;
+
+ recv_callback callback;
+ void *user_data;
+
+ enum message_type type;
+ uint8_t *data;
+ int32_t len;
+
+ int32_t recved;
+};
+
+static GList *recv_list;
+
+static struct recv_info *find_rif(int fd)
+{
+ GList *l;
+
+ for (l = recv_list; l; l = g_list_next(l)) {
+ if (((struct recv_info *)l->data)->fd == fd)
+ return l->data;
+ }
+
+ return NULL;
+}
+
+static int recv_first(int fd, recv_callback callback, void *user_data)
+{
+ int r;
+ struct recv_info *rif;
+ uint32_t hdr;
+
+ rif = calloc(1, sizeof(*rif));
+ if (!rif)
+ return -1;
+
+ rif->fd = fd;
+ rif->callback = callback;
+ rif->user_data = user_data;
+
+ r = recv(fd, &hdr, sizeof(uint32_t), 0);
+ if (r <= 0) {
+ free(rif);
+ if (r == 0)
+ bxt_dbg("recv: fd %d closed", fd);
+ else
+ bxt_err("recv: fd %d errno %d", fd, errno);
+
+ return -1;
+ }
+
+ rif->type = hdr >> 24;
+ rif->len = hdr & 0xffffff;
+ if (rif->len == 0) {
+ free(rif);
+ bxt_err("recv: fd %d invalid header %x", fd, hdr);
+ return -1;
+ }
+
+ rif->data = malloc(rif->len);
+ if (!rif->data) {
+ free(rif);
+ return -1;
+ }
+
+ recv_list = g_list_append(recv_list, rif);
+
+ bxt_dbg("rif %p type %d len %d added", rif, rif->type, rif->len);
+
+ return 0;
+
+}
+
+static void remove_rif(struct recv_info *rif)
+{
+ if (!rif)
+ return;
+
+ recv_list = g_list_remove(recv_list, rif);
+ free(rif->data);
+ free(rif);
+}
+
+static int recv_cont(struct recv_info *rif)
+{
+ int r;
+
+ assert(rif);
+
+ r = recv(rif->fd, &rif->data[rif->recved], rif->len - rif->recved, 0);
+ if (r <= 0) {
+ if (r == 0)
+ bxt_dbg("recv: fd %d closed", rif->fd);
+ else
+ bxt_err("recv: fd %d errno %d", rif->fd, errno);
+
+ remove_rif(rif);
+ return -1;
+ }
+ rif->recved += r;
+
+ if (rif->recved > rif->len) {
+ bxt_err("recv: fd %d expected %d > received %d", rif->fd,
+ rif->len, rif->recved);
+ remove_rif(rif);
+ return -1;
+ }
+
+ if (rif->recved == rif->len) {
+ bxt_dbg("rif %p received %d / %d", rif, rif->recved, rif->len);
+
+ assert(rif->callback);
+ rif->callback(rif->user_data, rif->type, rif->data, rif->len);
+ remove_rif(rif);
+ }
+
+ return 0;
+}
+
+int proto_recv_frag(int fd, recv_callback callback, void *user_data)
+{
+ int r;
+ struct recv_info *rif;
+
+ if (fd < 0 || !callback) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ rif = find_rif(fd);
+ if (!rif)
+ r = recv_first(fd, callback, user_data);
+ else
+ r = recv_cont(rif);
+
+ return r;
+}
+
+
+int proto_send_block(int fd, enum message_type type, uint8_t *data, int32_t len)
+{
+ int r;
+ uint32_t hdr;
+ int sent;
+ struct pollfd fds[1];
+ int s;
+
+ if (fd < 0 || !data || len <= 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ bxt_dbg("send: fd %d type %d len %d start", fd, type, len);
+ hdr = (type << 24) | (len & 0xffffff);
+
+ r = send(fd, &hdr, sizeof(uint32_t), 0);
+ if (r == -1) {
+ bxt_err("send: fd %d errno %d", fd, errno);
+ return -1;
+ }
+
+ sent = 0;
+ while (len > sent) {
+ fds[0].fd = fd;
+ fds[0].events = POLLOUT;
+ fds[0].revents = 0;
+
+ /* CAN BE BLOCKED ! */
+ r = poll(fds, 1, SEND_TIMEOUT_MSEC);
+ if (r == -1) {
+ bxt_err("send: fd %d poll errno %d", fd, errno);
+ return -1;
+ }
+ if (r == 0) {
+ bxt_err("send: fd %d timeout", fd);
+ return -1;
+ }
+
+ s = len - sent;
+ if (s > SEND_TIMEOUT_MSEC)
+ s = SEND_TIMEOUT_MSEC;
+
+ r = send(fd, &data[sent], s, 0);
+ if (r == -1) {
+ bxt_err("send: fd %d errno %d", fd, errno);
+ return -1;
+ }
+
+ sent += r;
+ }
+ bxt_dbg("send: fd %d sent %d", fd, sent);
+
+ return 0;
+}
+
+int proto_send(int fd, enum message_type type, uint8_t *data, int32_t len)
+{
+ int r;
+ uint32_t hdr;
+ uint8_t *buf;
+
+ assert(fd >= 0);
+ assert(data);
+ assert(len > 0);
+
+ buf = malloc(len + sizeof(uint32_t));
+ if (!buf) {
+ bxt_err("send: send buffer alloc error");
+ return -1;
+ }
+
+ hdr = (type << 24) | (len & 0xffffff);
+
+ memcpy(buf, &hdr, sizeof(uint32_t));
+ memcpy(buf + sizeof(uint32_t), data, len);
+
+ r = send(fd, buf, len + sizeof(uint32_t), 0);
+
+ free(buf);
+
+ if (r == -1) {
+ bxt_err("send: fd %d errno %d", fd, errno);
+ return -1;
+ }
+
+ if (r != len + sizeof(uint32_t))
+ bxt_err("send: %d / %d byte", r,
+ (int32_t)(len + sizeof(uint32_t)));
+
+ return 0;
+}
+
+int proto_recv(int fd, enum message_type *type, uint8_t **data, int32_t *len)
+{
+ int r;
+ uint32_t hdr;
+ uint8_t *_data;
+ int32_t _len;
+ enum message_type _type;
+
+ assert(fd >= 0);
+ assert(type);
+ assert(data);
+ assert(len);
+
+ r = recv(fd, &hdr, sizeof(uint32_t), 0);
+ if (r <= 0) {
+ if (r == 0)
+ bxt_dbg("recv: fd %d closed", fd);
+ else
+ bxt_err("recv: fd %d errno %d", fd, errno);
+
+ return -1;
+ }
+
+ _type = hdr >> 24;
+ _len = hdr & 0xffffff;
+
+ if (_len == 0) {
+ bxt_err("recv: fd %d Invalid message", fd);
+ return -1;
+ }
+
+ _data = malloc(_len);
+ if (!_data) {
+ /* flush ? */
+ return -1;
+ }
+
+ r = recv(fd, _data, _len, 0);
+ if (r <= 0) {
+ if (r == 0)
+ bxt_dbg("recv: fd %d closed", fd);
+ else
+ bxt_err("recv: fd %d errno %d", fd, errno);
+
+ free(_data);
+
+ return -1;
+ }
+
+ if (r != _len) {
+ bxt_err("recv: fd %d expect size %d > received %d",
+ fd, _len, r);
+ free(_data);
+ return -1;
+ }
+
+ *type = _type;
+ *data = _data;
+ *len = _len;
+
+ return 0;
+}
diff --git a/common/proto.h b/common/proto.h
new file mode 100644
index 0000000..39e923a
--- /dev/null
+++ b/common/proto.h
@@ -0,0 +1,33 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "common.h"
+
+int proto_send(int fd, enum message_type type, uint8_t *data, int32_t len);
+int proto_recv(int fd, enum message_type *type, uint8_t **data, int32_t *len);
+
+typedef void (*recv_callback)(void *user_data,
+ enum message_type type, uint8_t *data, int32_t len);
+int proto_recv_frag(int fd, recv_callback callback, void *user_data);
+int proto_send_block(int fd, enum message_type type, uint8_t *data,
+ int32_t len);
+
diff --git a/common/serialize.c b/common/serialize.c
new file mode 100644
index 0000000..2cda9c1
--- /dev/null
+++ b/common/serialize.c
@@ -0,0 +1,970 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <glib.h>
+
+#include "buxton2.h"
+
+#include "serialize.h"
+#include "log.h"
+
+#define KEY_NAME_MAX 4096
+#define VALUE_MAX 4096
+
+int check_key_name(const char *key)
+{
+ const char *p;
+ int len;
+
+ len = 0;
+ p = key;
+ while (*p) {
+ /* from 0x21 '!' to 0x7e '~' */
+ if (*p < 0x21 || *p > 0x7e) {
+ errno = EINVAL;
+ bxt_err("Key name has invalid character '%x'", *p);
+ return -1;
+ }
+ p++;
+ len++;
+ if (len > KEY_NAME_MAX) {
+ errno = ENAMETOOLONG;
+ bxt_err("Key name is too long");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static inline int check_val(const char *s)
+{
+ if (!s)
+ return 0;
+
+ if (strlen(s) > VALUE_MAX) {
+ errno = EMSGSIZE;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_values(const char *rpriv, const char *wpriv,
+ const struct buxton_value *val)
+{
+ int r;
+
+ r = check_val(rpriv);
+ if (r == -1) {
+ bxt_err("Read priv. string length is too long");
+ return -1;
+ }
+
+ r = check_val(wpriv);
+ if (r == -1) {
+ bxt_err("Write priv. string length is too long");
+ return -1;
+ }
+
+ if (val && val->type == BUXTON_TYPE_STRING) {
+ r = check_val(val->value.s);
+ if (r == -1) {
+ bxt_err("Value string length is too long");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+static GVariant *val_to_gv(const struct buxton_value *val)
+{
+ GVariant *gv;
+
+ if (!val)
+ return g_variant_new_tuple(NULL, 0);
+
+ switch (val->type) {
+ case BUXTON_TYPE_STRING:
+ if (!val->value.s) {
+ bxt_err("Serialize: value has NULL string");
+ return NULL;
+ }
+
+ gv = g_variant_new_string(val->value.s);
+ break;
+ case BUXTON_TYPE_INT32:
+ gv = g_variant_new_int32(val->value.i);
+ break;
+ case BUXTON_TYPE_UINT32:
+ gv = g_variant_new_uint32(val->value.u);
+ break;
+ case BUXTON_TYPE_INT64:
+ gv = g_variant_new_int64(val->value.i64);
+ break;
+ case BUXTON_TYPE_UINT64:
+ gv = g_variant_new_uint64(val->value.u64);
+ break;
+ case BUXTON_TYPE_DOUBLE:
+ gv = g_variant_new_double(val->value.d);
+ break;
+ case BUXTON_TYPE_BOOLEAN:
+ gv = g_variant_new_boolean(val->value.b);
+ break;
+ default:
+ bxt_err("Serialize: Invalid value type: %d", val->type);
+ gv = NULL;
+ break;
+ }
+
+ return gv;
+}
+
+static uint8_t *gv_to_data(GVariant *gv, int *len)
+{
+ uint8_t *data;
+ int _len;
+
+ assert(gv);
+ assert(len);
+
+ _len = g_variant_get_size(gv);
+ assert(_len > 0);
+
+ data = malloc(_len);
+ if (!data)
+ return NULL;
+
+ g_variant_store(gv, data);
+
+ *len = _len;
+
+ return data;
+}
+
+/*
+ * Data format = v Variant v
+ *
+ * In an initial version,
+ * Variant v = (ssv) read privilege s, write priv. w, value v
+ *
+ */
+int serialz_data(const char *rpriv, const char *wpriv,
+ const struct buxton_value *val,
+ uint8_t **data, int *len)
+{
+ GVariant *gv;
+ GVariant *vv;
+ GVariant *v;
+ int _len;
+ uint8_t *_data;
+ int r;
+
+ if (!rpriv || !wpriv || !val || !data || !len) {
+ errno = EINVAL;
+ bxt_err("serialize data: invalid argument:%s%s%s%s%s",
+ rpriv ? "" : " read priv",
+ wpriv ? "" : " write priv",
+ val ? "" : " value",
+ data ? "" : " data",
+ len ? "" : " len");
+
+ return -1;
+ }
+
+ r = check_values(rpriv, wpriv, val);
+ if (r == -1)
+ return -1;
+
+ v = val_to_gv(val);
+ if (!v) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ vv = g_variant_new("(ssv)", rpriv, wpriv, v);
+ assert(vv);
+
+ gv = g_variant_new_variant(vv);
+ assert(gv);
+
+ _data = gv_to_data(gv, &_len);
+
+ g_variant_unref(gv);
+
+ if (!_data)
+ return -1;
+
+ *data = _data;
+ *len = _len;
+
+ return 0;
+}
+
+static int gv_to_val(GVariant *v, struct buxton_value *val)
+{
+ const char *t;
+ const char *s;
+
+ assert(v);
+ assert(val);
+
+ t = g_variant_get_type_string(v);
+ assert(t);
+
+ if (!strncmp(t, "()", sizeof("()"))) {
+ val->type = BUXTON_TYPE_UNKNOWN;
+ return 0;
+ }
+
+ switch (*t) {
+ case 's':
+ val->type = BUXTON_TYPE_STRING;
+
+ s = g_variant_get_string(v, NULL);
+ assert(s);
+
+ val->value.s = strdup(s);
+ if (!val->value.s)
+ return -1;
+
+ break;
+ case 'i':
+ val->type = BUXTON_TYPE_INT32;
+ val->value.i = g_variant_get_int32(v);
+ break;
+ case 'u':
+ val->type = BUXTON_TYPE_UINT32;
+ val->value.u = g_variant_get_uint32(v);
+ break;
+ case 'x':
+ val->type = BUXTON_TYPE_INT64;
+ val->value.i64 = g_variant_get_int64(v);
+ break;
+ case 't':
+ val->type = BUXTON_TYPE_UINT64;
+ val->value.u64 = g_variant_get_uint64(v);
+ break;
+ case 'd':
+ val->type = BUXTON_TYPE_DOUBLE;
+ val->value.d = g_variant_get_double(v);
+ break;
+ case 'b':
+ val->type = BUXTON_TYPE_BOOLEAN;
+ val->value.b = g_variant_get_boolean(v);
+ break;
+ default:
+ bxt_err("DeSerialz: Invalid variant type: %s", t);
+ errno = EBADMSG;
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int gv_to_values(GVariant *gv, char **rpriv, char **wpriv,
+ struct buxton_value *val)
+{
+ GVariant *v;
+ const char *vt;
+ const char *rp;
+ const char *wp;
+ int r;
+
+ assert(gv);
+
+ if (!rpriv && !wpriv && !val)
+ return 0;
+
+ vt = g_variant_get_type_string(gv);
+ if (strncmp(vt, "(ssv)", sizeof("(ssv)"))) {
+ bxt_err("Deserialize: Unsupported type: %s", vt);
+ errno = EBADMSG;
+ return -1;
+ }
+
+ g_variant_get(gv, "(&s&sv)", &rp, &wp, &v);
+ assert(rp);
+ assert(wp);
+ assert(v);
+
+ if (rpriv) {
+ *rpriv = strdup(rp);
+ if (!*rpriv) {
+ g_variant_unref(v);
+ return -1;
+ }
+ }
+
+ if (wpriv) {
+ *wpriv = strdup(wp);
+ if (!*wpriv) {
+ if (rpriv)
+ free(*rpriv);
+
+ g_variant_unref(v);
+ return -1;
+ }
+ }
+
+ if (val) {
+ memset(val, 0, sizeof(*val));
+ r = gv_to_val(v, val);
+ if (r == -1) {
+ if (rpriv)
+ free(*rpriv);
+
+ if (wpriv)
+ free(*wpriv);
+
+ g_variant_unref(v);
+ return -1;
+ }
+ }
+
+ g_variant_unref(v);
+
+ return 0;
+}
+
+int deserialz_data(uint8_t *data, int len,
+ char **rpriv, char **wpriv, struct buxton_value *val)
+{
+ GVariant *gv;
+ GVariant *v;
+ char *_rpriv;
+ char *_wpriv;
+ struct buxton_value _val;
+ int r;
+
+ if (!data || len <= 0) {
+ errno = EINVAL;
+ bxt_err("Deserialize data: invalid argument:%s%s",
+ data ? "" : " data", len > 0 ? "" : " len");
+ return -1;
+ }
+
+ gv = g_variant_new_from_data(G_VARIANT_TYPE("v"),
+ data, len, TRUE, NULL, NULL);
+ assert(gv);
+
+ g_variant_get(gv, "v", &v);
+ assert(v);
+
+ r = gv_to_values(v,
+ rpriv ? &_rpriv : NULL,
+ wpriv ? &_wpriv : NULL,
+ val ? &_val : NULL);
+
+ g_variant_unref(v);
+ g_variant_unref(gv);
+
+ if (r == -1)
+ return -1;
+
+ if (rpriv)
+ *rpriv = _rpriv;
+
+ if (wpriv)
+ *wpriv = _wpriv;
+
+ if (val)
+ *val = _val;
+
+ return 0;
+}
+
+void free_request(struct request *req)
+{
+ if (!req)
+ return;
+
+ layer_free(req->layer);
+ free(req->rpriv);
+ free(req->wpriv);
+ free(req->key);
+ value_free(req->val);
+ free(req->val);
+}
+
+static int check_value(const struct buxton_value *val)
+{
+ if (!val) {
+ bxt_err("Serialize: value is NULL");
+ return -1;
+ }
+
+ switch (val->type) {
+ case BUXTON_TYPE_STRING:
+ if (!val->value.s) {
+ bxt_err("Serialize: value has NULL string");
+ return -1;
+ }
+ break;
+ case BUXTON_TYPE_INT32:
+ case BUXTON_TYPE_UINT32:
+ case BUXTON_TYPE_INT64:
+ case BUXTON_TYPE_UINT64:
+ case BUXTON_TYPE_DOUBLE:
+ case BUXTON_TYPE_BOOLEAN:
+ break;
+ default:
+ bxt_err("Serialize: buxton_value has unknown type");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int check_request(enum message_type type,
+ const char *key, const struct buxton_value *val)
+{
+ int r;
+
+ switch (type) {
+ case MSG_SET:
+ case MSG_CREAT:
+ case MSG_NOTI:
+ case MSG_SET_WP:
+ case MSG_SET_RP:
+ r = check_value(val);
+ if (r == -1)
+ goto err;
+ case MSG_GET:
+ case MSG_UNSET:
+ case MSG_NOTIFY:
+ case MSG_UNNOTIFY:
+ case MSG_GET_WP:
+ case MSG_GET_RP:
+ if (!key || !*key) {
+ bxt_err("Serialize: key is NULL or empty string");
+ goto err;
+ }
+
+ r = check_key_name(key);
+ if (r == -1)
+ return -1;
+ case MSG_LIST:
+ break;
+ default:
+ bxt_err("Serialize: message type is invalid: %d", type);
+ goto err;
+ }
+
+ return 0;
+
+err:
+ errno = EINVAL;
+
+ return -1;
+}
+
+int serialz_request(const struct request *req, uint8_t **data, int *len)
+{
+ int r;
+ GVariant *gv;
+ GVariant *vv;
+ GVariant *v;
+ int _len;
+ uint8_t *_data;
+
+ if (!data || !len || !req || !req->layer) {
+ errno = EINVAL;
+ bxt_err("Serialize request: invalid argument:%s%s%s%s",
+ data ? "" : " data",
+ len ? "" : " len",
+ req ? "" : " req",
+ req->layer ? "" : " layer");
+ return -1;
+ }
+
+ r = check_request(req->type, req->key, req->val);
+ if (r == -1)
+ return -1;
+
+ v = val_to_gv(req->val);
+ if (!v) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ vv = g_variant_new("(uuissssv)",
+ req->msgid,
+ req->layer->uid,
+ req->layer->type,
+ req->layer->name,
+ req->rpriv ? req->rpriv : "",
+ req->wpriv ? req->wpriv : "",
+ req->key ? req->key : "",
+ v);
+ assert(vv);
+
+ gv = g_variant_new("(qv)", req->type, vv);
+ assert(gv);
+
+ _data = gv_to_data(gv, &_len);
+
+ g_variant_unref(gv);
+
+ if (!_data)
+ return -1;
+
+ *data = _data;
+ *len = _len;
+
+ return 0;
+}
+
+static inline int _strdup(const char *src, char **dest)
+{
+ char *s;
+
+ assert(dest);
+
+ if (!src) {
+ *dest = NULL;
+ return 0;
+ }
+
+ s = strdup(src);
+ if (!s)
+ return -1;
+
+ *dest = s;
+
+ return 0;
+}
+
+static int set_req(struct buxton_value *val, const char *lnm, uid_t uid,
+ enum buxton_layer_type type, const char *rp, const char *wp,
+ const char *key, struct request *req)
+{
+ int r;
+
+ assert(req);
+
+ req->val = val;
+
+ if (lnm && *lnm) {
+ req->layer = layer_create(lnm);
+ if (!req->layer)
+ return -1;
+
+ req->layer->uid = uid;
+ req->layer->type = type;
+ } else {
+ req->layer = NULL;
+ }
+
+ r = _strdup(rp, &req->rpriv);
+ if (r == -1)
+ return -1;
+
+ r = _strdup(wp, &req->wpriv);
+ if (r == -1)
+ return -1;
+
+ r = _strdup(key, &req->key);
+ if (r == -1)
+ return -1;
+
+ return 0;
+}
+
+static int gv_to_req(GVariant *gv, struct request *req)
+{
+ const char *vt;
+ uint32_t uid;
+ int32_t type;
+ const char *lnm;
+ const char *key;
+ const char *rp;
+ const char *wp;
+ GVariant *v;
+ int r;
+ struct buxton_value *val;
+
+ assert(gv);
+ assert(req);
+
+ vt = g_variant_get_type_string(gv);
+ if (strncmp(vt, "(uuissssv)", sizeof("(uuissssv)"))) {
+ bxt_err("DeSerialz: Unsupported type: %s", vt);
+ errno = EBADMSG;
+ return -1;
+ }
+
+ val = calloc(1, sizeof(*val));
+ if (!val)
+ return -1;
+
+ g_variant_get(gv, "(uui&s&s&s&sv)", &req->msgid, &uid, &type,
+ &lnm, &rp, &wp, &key, &v);
+ assert(v);
+ assert(lnm);
+ assert(rp);
+ assert(wp);
+ assert(key);
+
+ r = gv_to_val(v, val);
+
+ g_variant_unref(v);
+
+ if (r == -1) {
+ free(val);
+ return -1;
+ }
+
+ if (val->type == BUXTON_TYPE_UNKNOWN) {
+ free(val);
+ val = NULL;
+ }
+
+ r = set_req(val, lnm, uid, type, rp, wp, key, req);
+ if (r == -1)
+ free_request(req);
+
+ return r;
+}
+
+int deserialz_request(uint8_t *data, int len, struct request *req)
+{
+ GVariant *gv;
+ GVariant *v;
+ int r;
+ struct request _req;
+
+ if (!data || len <= 0 || !req) {
+ errno = EINVAL;
+ bxt_err("Deserialize request: invalid argument:%s%s%s",
+ data ? "" : " data",
+ len > 0 ? "" : " len",
+ req ? "" : " req");
+ return -1;
+ }
+
+ gv = g_variant_new_from_data(G_VARIANT_TYPE("(qv)"),
+ data, len, TRUE, NULL, NULL);
+ assert(gv);
+
+ memset(&_req, 0, sizeof(_req));
+
+ g_variant_get(gv, "(qv)", &_req.type, &v);
+ assert(v);
+
+ r = gv_to_req(v, &_req);
+
+ g_variant_unref(v);
+ g_variant_unref(gv);
+
+ if (r == -1)
+ return -1;
+
+ *req = _req;
+
+ return 0;
+}
+
+void free_response(struct response *res)
+{
+ if (!res)
+ return;
+
+ value_free(res->val);
+ free(res->val);
+ buxton_free_keys(res->names);
+}
+
+static int check_response(enum message_type type, int32_t res,
+ const struct buxton_value *val, char * const *names)
+{
+ int r;
+
+ if (res)
+ return 0;
+
+ switch (type) {
+ case MSG_LIST:
+ if (!names) {
+ bxt_err("Serialize: names is NULL");
+ goto err;
+ }
+ break;
+ case MSG_GET:
+ case MSG_GET_WP:
+ case MSG_GET_RP:
+ r = check_value(val);
+ if (r == -1)
+ goto err;
+ break;
+ case MSG_SET:
+ case MSG_CREAT:
+ case MSG_UNSET:
+ case MSG_NOTIFY:
+ case MSG_UNNOTIFY:
+ case MSG_SET_WP:
+ case MSG_SET_RP:
+ break;
+ case MSG_NOTI:
+ errno = ENOTSUP;
+ bxt_err("Serialize: MSG_NOTI type has no response");
+ return -1;
+ default:
+ goto err;
+ }
+
+ return 0;
+
+err:
+ errno = EINVAL;
+
+ return -1;
+}
+
+static int res_to_gv(enum message_type type, int32_t res,
+ const struct buxton_value *val, char * const *names,
+ GVariant **gv)
+{
+ GVariantBuilder *builder;
+ GVariant *v;
+
+ assert(gv);
+
+ if (res) {
+ *gv = g_variant_new_tuple(NULL, 0);
+ return 0;
+ }
+
+ switch (type) {
+ case MSG_LIST:
+ builder = g_variant_builder_new(G_VARIANT_TYPE("as"));
+ assert(names);
+ while (*names) {
+ g_variant_builder_add(builder, "s", *names);
+ names++;
+ }
+ v = g_variant_new("as", builder);
+ assert(v);
+ g_variant_builder_unref(builder);
+ break;
+ case MSG_GET:
+ case MSG_GET_WP:
+ case MSG_GET_RP:
+ if (val) {
+ v = val_to_gv(val);
+ if (!v) {
+ errno = EINVAL;
+ return -1;
+ }
+ } else {
+ v = g_variant_new_tuple(NULL, 0);
+ }
+ break;
+ default:
+ v = g_variant_new_tuple(NULL, 0);
+ break;
+ }
+
+ *gv = v;
+
+ return 0;
+}
+
+int serialz_response(enum message_type type, uint32_t msgid, int32_t res,
+ const struct buxton_value *val, uint32_t nmlen,
+ char * const *names, uint8_t **data, int *len)
+{
+ int r;
+ GVariant *gv;
+ GVariant *vv;
+ GVariant *v;
+ int _len;
+ uint8_t *_data;
+
+ if (!data || !len) {
+ errno = EINVAL;
+ bxt_err("Serialize response: invalid argument:%s%s",
+ data ? "" : " data",
+ len ? "" : " len");
+ return -1;
+ }
+
+ r = check_response(type, res, val, names);
+ if (r == -1)
+ return -1;
+
+ r = res_to_gv(type, res, val, names, &v);
+ if (r == -1)
+ return -1;
+
+ assert(v);
+ vv = g_variant_new("(uiuv)", msgid, res, nmlen, v);
+ assert(vv);
+
+ gv = g_variant_new("(qv)", type, vv);
+ assert(gv);
+
+ _data = gv_to_data(gv, &_len);
+
+ g_variant_unref(gv);
+
+ if (!_data)
+ return -1;
+
+ *data = _data;
+ *len = _len;
+
+ return 0;
+}
+
+static int gv_to_res_list(GVariant *gv, struct response *res)
+{
+ GVariantIter iter;
+ gsize len;
+ const char *s;
+ int i;
+
+ g_variant_iter_init(&iter, gv);
+ len = g_variant_iter_n_children(&iter);
+ assert(len >= 0);
+
+ res->names = calloc(len + 1, sizeof(void *));
+ if (!res->names)
+ return -1;
+
+ i = 0;
+ while (g_variant_iter_next(&iter, "&s", &s)) {
+ assert(s);
+ res->names[i] = strdup(s);
+ if (!res->names[i])
+ break;
+ i++;
+
+ assert(i <= len);
+ }
+ /* NULL terminated */
+ res->names[i] = NULL;
+
+ if (i < len) {
+ buxton_free_keys(res->names);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int gv_to_res(GVariant *gv, struct response *res)
+{
+ const char *vt;
+ GVariant *v;
+ struct buxton_value *val;
+ int r;
+
+ assert(gv);
+ assert(res);
+
+ vt = g_variant_get_type_string(gv);
+ if (strncmp(vt, "(uiuv)", sizeof("(uiuv)"))) {
+ bxt_err("DeSerialz: Unsupported type: %s", vt);
+ errno = EBADMSG;
+ return -1;
+ }
+
+ g_variant_get(gv, "(uiuv)", &res->msgid, &res->res, &res->nmlen, &v);
+
+ if (res->res)
+ return 0;
+
+ if (res->type == MSG_LIST) {
+ r = gv_to_res_list(v, res);
+ g_variant_unref(v);
+ return r;
+ }
+
+ val = calloc(1, sizeof(*val));
+ if (!val) {
+ g_variant_unref(v);
+ return -1;
+ }
+
+ r = gv_to_val(v, val);
+ if (r == -1) {
+ free(val);
+ g_variant_unref(v);
+ return -1;
+ }
+
+ g_variant_unref(v);
+
+ if (val->type == BUXTON_TYPE_UNKNOWN) {
+ free(val);
+ val = NULL;
+ }
+
+ res->val = val;
+
+ return 0;
+}
+
+int deserialz_response(uint8_t *data, int len, struct response *res)
+{
+ GVariant *gv;
+ GVariant *v;
+ int r;
+ struct response _res;
+
+ if (!data || len <= 0 || !res) {
+ errno = EINVAL;
+ bxt_err("Deserialize response: invalid argument:%s%s%s",
+ data ? "" : " data",
+ len > 0 ? "" : " len",
+ res ? "" : " response");
+ return -1;
+ }
+
+ gv = g_variant_new_from_data(G_VARIANT_TYPE("(qv)"),
+ data, len, TRUE, NULL, NULL);
+ assert(gv);
+
+ memset(&_res, 0, sizeof(_res));
+
+ g_variant_get(gv, "(qv)", &_res.type, &v);
+ assert(v);
+
+ r = gv_to_res(v, &_res);
+
+ g_variant_unref(v);
+ g_variant_unref(gv);
+
+ if (r == -1) {
+ free_response(&_res);
+ return -1;
+ }
+
+ *res = _res;
+
+ return 0;
+}
+
diff --git a/common/serialize.h b/common/serialize.h
new file mode 100644
index 0000000..e5ef8ef
--- /dev/null
+++ b/common/serialize.h
@@ -0,0 +1,70 @@
+/*
+ * Buxton
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+
+#include "buxton2.h"
+
+#include "common.h"
+
+int check_key_name(const char *key);
+
+int serialz_data(const char *rpriv, const char *wpriv,
+ const struct buxton_value *val,
+ uint8_t **data, int *len);
+
+int deserialz_data(uint8_t *data, int len,
+ char **rpriv, char **wpriv, struct buxton_value *val);
+
+
+struct request {
+ enum message_type type;
+ uint32_t msgid;
+ struct buxton_layer *layer;
+ char *rpriv;
+ char *wpriv;
+ char *key;
+ struct buxton_value *val;
+};
+
+int serialz_request(const struct request *req, uint8_t **data, int *len);
+
+int deserialz_request(uint8_t *data, int len, struct request *req);
+
+void free_request(struct request *req);
+
+
+int serialz_response(enum message_type type, uint32_t msgid, int32_t res,
+ const struct buxton_value *val, uint32_t nmlen,
+ char * const *names, uint8_t **data, int *len);
+
+struct response {
+ enum message_type type;
+ uint32_t msgid;
+ int32_t res;
+ struct buxton_value *val;
+ uint32_t nmlen;
+ char **names;
+};
+
+int deserialz_response(uint8_t *data, int len, struct response *res);
+
+void free_response(struct response *res);
+