summaryrefslogtreecommitdiffstats
path: root/ll-database-binding/src
diff options
context:
space:
mode:
authorLoïc Collignon <loic.collignon@iot.bzh>2017-10-24 13:34:38 +0200
committerLoïc Collignon <loic.collignon@iot.bzh>2017-10-24 13:34:38 +0200
commit97325dd67f3b7858bd093fc161d0a56e7c7bc9bd (patch)
tree6478f34c28889205ddd7f000e3dd75aef68316cd /ll-database-binding/src
parent4f50493fc0ef4d0c33124ebf52908849196ad685 (diff)
replaced store binding with a database binding based on a berkeley db
Change-Id: I03978ecbf996ebc6d53a88dfd2b275051080016f Signed-off-by: Loïc Collignon <loic.collignon@iot.bzh>
Diffstat (limited to 'll-database-binding/src')
-rw-r--r--ll-database-binding/src/.ll-database-binding.c.swpbin0 -> 16384 bytes
-rw-r--r--ll-database-binding/src/CMakeLists.txt13
-rw-r--r--ll-database-binding/src/export.map1
-rw-r--r--ll-database-binding/src/ll-database-binding.c389
-rw-r--r--ll-database-binding/src/utils.h72
5 files changed, 475 insertions, 0 deletions
diff --git a/ll-database-binding/src/.ll-database-binding.c.swp b/ll-database-binding/src/.ll-database-binding.c.swp
new file mode 100644
index 0000000..54fb691
--- /dev/null
+++ b/ll-database-binding/src/.ll-database-binding.c.swp
Binary files differ
diff --git a/ll-database-binding/src/CMakeLists.txt b/ll-database-binding/src/CMakeLists.txt
new file mode 100644
index 0000000..904b857
--- /dev/null
+++ b/ll-database-binding/src/CMakeLists.txt
@@ -0,0 +1,13 @@
+PROJECT_TARGET_ADD(ll-database-binding)
+
+find_package(BerkeleyDB REQUIRED)
+include_directories(${DB_INCLUDE_DIR})
+
+add_library(ll-database-binding MODULE ll-database-binding.c utils.h)
+target_link_libraries(ll-database-binding ${DB_LIBRARY})
+
+set_target_properties(ll-database-binding PROPERTIES
+ PREFIX "afb-"
+ LABELS "BINDING"
+ LINK_FLAGS ${BINDINGS_LINK_FLAG}
+ OUTPUT_NAME ${TARGET_NAME})
diff --git a/ll-database-binding/src/export.map b/ll-database-binding/src/export.map
new file mode 100644
index 0000000..ee2f413
--- /dev/null
+++ b/ll-database-binding/src/export.map
@@ -0,0 +1 @@
+{ global: afbBindingV*; local: *; };
diff --git a/ll-database-binding/src/ll-database-binding.c b/ll-database-binding/src/ll-database-binding.c
new file mode 100644
index 0000000..adaf023
--- /dev/null
+++ b/ll-database-binding/src/ll-database-binding.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2017 IoT.bzh
+ *
+ * author: Loïc Collignon <loic.collignon@iot.bzh>
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/limits.h>
+#include <json-c/json.h>
+#include <db.h>
+
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+
+#include "utils.h"
+
+#define DBFILE "/ll-database-binding.db"
+#define USERNAME "agl"
+#define APPNAME "firefox"
+
+// ----- Globals -----
+DB* database;
+char* database_file;
+
+// ----- Binding's declarations -----
+int ll_database_binding_init();
+void verb_read(struct afb_req req);
+void verb_update(struct afb_req req);
+void verb_delete(struct afb_req req);
+
+void verb_insert(struct afb_req req);
+void verb_update(struct afb_req req);
+void verb_delete(struct afb_req req);
+void verb_read(struct afb_req req);
+
+// ----- Binding's implementations -----
+
+/**
+ * @brief Initialize the binding.
+ * @return Exit code, zero if success.
+ */
+int ll_database_binding_init()
+{
+ struct passwd pwd;
+ struct passwd* result;
+ char* buf;
+ size_t bufsize;
+ int ret;
+
+ bufsize = sysconf(_SC_GETPW_R_SIZE_MAX);
+ if (bufsize == -1) bufsize = 16384;
+ buf = malloc(bufsize);
+ if (buf == NULL)
+ {
+ AFB_ERROR("Allocation failed!");
+ return 1;
+ }
+
+ ret = getpwuid_r(getuid(), &pwd, buf, bufsize, &result);
+ if (result == NULL)
+ {
+ free(buf);
+ if (ret == 0) AFB_ERROR("User not found");
+ else AFB_ERROR("getpwuid_r failed with %d code", ret);
+ return 1;
+ }
+
+ bufsize = strlen(result->pw_dir) + strlen(DBFILE) + 1;
+ database_file = malloc(bufsize);
+ if (database_file == NULL)
+ {
+ free(buf);
+ AFB_ERROR("Allocation failed!");
+ return 1;
+ }
+
+ memset(database_file, 0, bufsize);
+ strcat(database_file, result->pw_dir);
+ strcat(database_file, DBFILE);
+ free(buf);
+
+ AFB_INFO("The database file is '%s'", database_file);
+
+ if ((ret = db_create(&database, NULL, 0)) != 0)
+ {
+ AFB_ERROR("Failed to create database: %s.", db_strerror(ret));
+ free(database_file);
+ return 1;
+ }
+
+ if ((ret = database->open(database, NULL, database_file, NULL, DB_BTREE, DB_CREATE, 0664)) != 0)
+ {
+ AFB_ERROR("Failed to open the '%s' database: %s.", database_file, db_strerror(ret));
+ database->close(database, 0);
+ free(database_file);
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * @brief Handle the @c read verb.
+ * @param[in] req The query.
+ */
+void verb_insert(struct afb_req req)
+{
+ DBT key;
+ DBT data;
+ int ret;
+
+ char* rkey;
+ const char* tag;
+ const char* value;
+
+ struct json_object* args;
+ struct json_object* item;
+
+ args = afb_req_json(req);
+
+ if (!args)
+ {
+ afb_req_fail(req, "No argument provided.", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(args, "key", &item) || !item) tag = NULL;
+ else tag = json_object_get_string(item);
+
+ if (!tag || !strlen(tag))
+ {
+ afb_req_fail(req, "No tag provided.", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(args, "value", &item) || !item) value = NULL;
+ else value = json_object_get_string(item);
+
+ if (!value || !strlen(value))
+ {
+ afb_req_fail(req, "No value provided.", NULL);
+ return;
+ }
+
+ rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
+ strcpy(rkey, USERNAME);
+ strcat(rkey, ":");
+ strcat(rkey, APPNAME);
+ strcat(rkey, ":");
+ strcat(rkey, tag);
+
+ AFB_INFO("insert: key=%s, value=%s", rkey, value);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ key.data = rkey;
+ key.size = strlen(rkey);
+
+ data.data = (void*)value;
+ data.size = strlen(value);
+
+ if ((ret = database->put(database, NULL, &key, &data, DB_NOOVERWRITE)) == 0)
+ afb_req_success_f(req, NULL, "db success: insertion %s=%s.", (char*)key.data, (char*)data.data);
+ else
+ afb_req_fail_f(req, "Failed to insert datas.", "db fail: insertion : %s=%s - %s", (char*)key.data, (char*)data.data, db_strerror(ret));
+ free(rkey);
+}
+
+void verb_update(struct afb_req req)
+{
+ DBT key;
+ DBT data;
+ int ret;
+
+ char* rkey;
+ const char* tag;
+ const char* value;
+
+ struct json_object* args;
+ struct json_object* item;
+
+ args = afb_req_json(req);
+ // username should be get from identity binding
+ // application should be get from smack
+ // tag should be get using get_json_string(args, "tag");
+
+ if (!args)
+ {
+ afb_req_fail(req, "No argument provided.", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(args, "tag", &item) || !item) tag = NULL;
+ else tag = json_object_get_string(item);
+
+ if (!tag || !strlen(tag))
+ {
+ afb_req_fail(req, "No tag provided.", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(args, "value", &item) || !item) value = NULL;
+ else value = json_object_get_string(item);
+
+ if (!value || !strlen(value))
+ {
+ afb_req_fail(req, "No value provided.", NULL);
+ return;
+ }
+
+ rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
+ strcpy(rkey, USERNAME);
+ strcat(rkey, ":");
+ strcat(rkey, APPNAME);
+ strcat(rkey, ":");
+ strcat(rkey, tag);
+
+ AFB_INFO("update: key=%s, value=%s", rkey, value);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ key.data = rkey;
+ key.size = strlen(rkey);
+
+ data.data = (void*)value;
+ data.size = strlen(value);
+
+ if ((ret = database->put(database, NULL, &key, &data, 0)) == 0)
+ afb_req_success_f(req, NULL, "db success: update %s=%s.", (char*)key.data, (char*)data.data);
+ else
+ afb_req_fail_f(req, "Failed to update datas.", "db fail: update %s=%s - %s", (char*)key.data, (char*)data.data, db_strerror(ret));
+ free(rkey);
+}
+
+void verb_delete(struct afb_req req)
+{
+ DBT key;
+ int ret;
+
+ char* rkey;
+ const char* tag;
+
+ struct json_object* args;
+ struct json_object* item;
+
+ args = afb_req_json(req);
+
+ if (!args)
+ {
+ afb_req_fail(req, "No argument provided.", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(args, "tag", &item) || !item) tag = NULL;
+ else tag = json_object_get_string(item);
+
+ if (!tag || !strlen(tag))
+ {
+ afb_req_fail(req, "No tag provided.", NULL);
+ return;
+ }
+
+ rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
+ strcpy(rkey, USERNAME);
+ strcat(rkey, ":");
+ strcat(rkey, APPNAME);
+ strcat(rkey, ":");
+ strcat(rkey, tag);
+
+ AFB_INFO("delete: key=%s", rkey);
+
+ memset(&key, 0, sizeof(key));
+
+ key.data = rkey;
+ key.size = strlen(rkey);
+
+ if ((ret = database->del(database, NULL, &key, 0)) == 0)
+ afb_req_success_f(req, NULL, "db success: delete %s.", (char *)key.data);
+ else
+ afb_req_fail_f(req, "Failed to delete datas.", "db fail: delete %s - %s", (char*)key.data, db_strerror(ret));
+ free(rkey);
+}
+
+void verb_read(struct afb_req req)
+{
+ DB* dbp;
+ DBT key;
+ DBT data;
+ int ret;
+
+ char* rkey;
+ const char* tag;
+ char value[4096];
+
+ struct json_object* args;
+ struct json_object* item;
+ struct json_object* result;
+ struct json_object* val;
+
+ args = afb_req_json(req);
+
+ if (!args)
+ {
+ afb_req_fail(req, "No argument provided.", NULL);
+ return;
+ }
+
+ if (!json_object_object_get_ex(args, "tag", &item) || !item) tag = NULL;
+ else tag = json_object_get_string(item);
+
+ if (!tag || !strlen(tag))
+ {
+ afb_req_fail(req, "No tag provided.", NULL);
+ return;
+ }
+
+ rkey = malloc(strlen(USERNAME) + strlen(APPNAME) + strlen(tag) + 3);
+ strcpy(rkey, USERNAME);
+ strcat(rkey, ":");
+ strcat(rkey, APPNAME);
+ strcat(rkey, ":");
+ strcat(rkey, tag);
+
+ AFB_INFO("update: key=%s, value=%s", rkey, value);
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ memset(&value, 0, 4096);
+
+ key.data = rkey;
+ key.size = strlen(rkey);
+
+ data.data = value;
+ data.ulen = 4096;
+ data.flags = DB_DBT_USERMEM;
+
+ if ((ret = database->get(database, NULL, &key, &data, 0)) == 0)
+ {
+ result = json_object_new_object();
+ val = json_tokener_parse((char*)data.data);
+ json_object_object_add(result, "value", val ? val : json_object_new_string((char*)data.data));
+
+ afb_req_success_f(req, result, "db success: read %s=%s.", (char*)key.data, (char*)data.data);
+ }
+ else
+ afb_req_fail_f(req, "Failed to read datas.", "db fail: read %s - %s", (char*)key.data, db_strerror(ret));
+ free(rkey);
+}
+
+// ----- Binding's configuration -----
+static const struct afb_auth ll_database_binding_auths[] = {
+};
+
+static const afb_verb_v2 ll_database_binding_verbs[]= {
+ REGISTER_VERB(insert, NULL, NULL, AFB_SESSION_NONE_V2),
+ REGISTER_VERB(update, NULL, NULL, AFB_SESSION_NONE_V2),
+ REGISTER_VERB(delete, NULL, NULL, AFB_SESSION_NONE_V2),
+ REGISTER_VERB(read, NULL, NULL, AFB_SESSION_NONE_V2),
+ { .verb = NULL}
+};
+
+const struct afb_binding_v2 afbBindingV2 = {
+ .api = "ll-database",
+ .specification = NULL,
+ .verbs = ll_database_binding_verbs,
+ .preinit = NULL,
+ .init = ll_database_binding_init,
+ .onevent = NULL,
+ .noconcurrency = 0
+};
diff --git a/ll-database-binding/src/utils.h b/ll-database-binding/src/utils.h
new file mode 100644
index 0000000..093d591
--- /dev/null
+++ b/ll-database-binding/src/utils.h
@@ -0,0 +1,72 @@
+/*
+* Copyright 2017 IoT.bzh
+*
+* author: Loïc Collignon <loic.collignon@iot.bzh>
+*
+* 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.
+*/
+
+#ifndef _BINDING_UTILS_H_
+#define _BINDING_UTILS_H_
+
+#include <string.h>
+#include <json-c/json.h>
+
+#ifndef AFB_BINDING_VERSION
+#define AFB_BINDING_VERSION 2
+#endif
+#include <afb/afb-binding.h>
+
+#define REGISTER_VERB(n, a, i, s) { .verb = #n, .callback = verb_##n, .auth = a, .info = i, .session = s }
+
+/**
+ * @brief Get a string from a json object.
+ * @param[in] obj Json object from wich the string is queried.
+ * @param[in] name Name of the string to get.
+ * @return The string value.
+ */
+static inline const char* get_json_string(struct json_object* obj, const char* name)
+{
+ struct json_object* item = NULL;
+ if (!obj || !name || !strlen(name)) return NULL;
+ if (!json_object_object_get_ex(obj, name, &item) || !item) return NULL;
+ return json_object_get_string(item);
+}
+
+/**
+ * @brief Add a string key/value to a json object.
+ * @param[in] obj The json object to which the key/value is added.
+ * @param[in] key The key to add.
+ * @param[in] value The value to add.
+ */
+static inline void json_object_add_string(struct json_object* obj, const char* key, const char* value)
+{
+ json_object_object_add(obj, key, json_object_new_string(value));
+}
+
+/**
+ * @brief Send an @c event with the specified @c message then fail with the same @c message.
+ * @param[in] req The query to fail.
+ * @param[in] event The event to push.
+ * @param[in] message The message to push with the event and use as a fail message.
+ */
+static inline void afb_fail_ex(struct afb_req req, struct afb_event event, const char* message)
+{
+ struct json_object* result = json_object_new_object();
+ json_object_add_string(result, "message", message);
+ afb_event_push(event, result);
+
+ afb_req_fail(req, message, NULL);
+}
+
+#endif // _BINDING_UTILS_H_