diff options
author | Suchang Woo <suchang.woo@samsung.com> | 2015-07-16 17:12:54 +0900 |
---|---|---|
committer | Suchang Woo <suchang.woo@samsung.com> | 2015-07-16 17:28:30 +0900 |
commit | d966429452d4ff6a3527f0deb8db63be5b87f720 (patch) | |
tree | a811fe0a17e1c6b69868cf1176eb99815227238b /common | |
parent | 99b1d99a4f93a6bf0786abc6ae5ad1f3d9415933 (diff) | |
download | buxton2-master.tar.gz buxton2-master.tar.bz2 buxton2-master.zip |
Signed-off-by: Suchang Woo <suchang.woo@samsung.com>
Diffstat (limited to 'common')
-rw-r--r-- | common/backend.h | 74 | ||||
-rw-r--r-- | common/backends.c | 205 | ||||
-rw-r--r-- | common/backends.h | 31 | ||||
-rw-r--r-- | common/common.c | 127 | ||||
-rw-r--r-- | common/common.h | 124 | ||||
-rw-r--r-- | common/config.c | 305 | ||||
-rw-r--r-- | common/config.h | 30 | ||||
-rw-r--r-- | common/direct.c | 548 | ||||
-rw-r--r-- | common/direct.h | 44 | ||||
-rw-r--r-- | common/log.h | 49 | ||||
-rw-r--r-- | common/proto.c | 328 | ||||
-rw-r--r-- | common/proto.h | 33 | ||||
-rw-r--r-- | common/serialize.c | 970 | ||||
-rw-r--r-- | common/serialize.h | 70 |
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); + |