summaryrefslogtreecommitdiffstats
path: root/README.md
blob: eb54f712d93f4a9ae176b8d890e1f3b5c0392e45 (plain)
1
2
3
# Binding tester

You'll find the doc [here](http://docs.automotivelinux.org/docs/en/master/apis_services/reference/afb-test/0_Installation.html)
#n275'>275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 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
};