From 33c2cd0236823d108cbb21af34b8d7843d117ac1 Mon Sep 17 00:00:00 2001 From: Fulup Ar Foll Date: Thu, 3 Aug 2017 21:56:01 +0200 Subject: Initial version of Policy Control --- PolicyCtl-afb/CMakeLists.txt | 58 +++++++++++++ PolicyCtl-afb/polctl-apidef.h | 90 ++++++++++++++++++++ PolicyCtl-afb/polctl-apidef.json | 175 +++++++++++++++++++++++++++++++++++++++ PolicyCtl-afb/polctl-binding.c | 174 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 497 insertions(+) create mode 100644 PolicyCtl-afb/CMakeLists.txt create mode 100644 PolicyCtl-afb/polctl-apidef.h create mode 100644 PolicyCtl-afb/polctl-apidef.json create mode 100644 PolicyCtl-afb/polctl-binding.c (limited to 'PolicyCtl-afb') diff --git a/PolicyCtl-afb/CMakeLists.txt b/PolicyCtl-afb/CMakeLists.txt new file mode 100644 index 0000000..d9776df --- /dev/null +++ b/PolicyCtl-afb/CMakeLists.txt @@ -0,0 +1,58 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll +# +# 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. +########################################################################### + + +# Generate API-v2 hat from OpenAPI json definition +macro(SET_TARGET_GENSKEL TARGET_NAME API_DEF_NAME) + add_custom_command(OUTPUT ${API_DEF_NAME}.h + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + DEPENDS ${API_DEF_NAME}.json + COMMAND afb-genskel ${API_DEF_NAME}.json >${API_DEF_NAME}.h + ) + add_custom_target(${API_DEF_NAME}_OPENAPI DEPENDS ${API_DEF_NAME}.h) + add_dependencies(${TARGET_NAME} ${API_DEF_NAME}_OPENAPI) + +endmacro(SET_TARGET_GENSKEL) + +# Add target to project dependency list +PROJECT_TARGET_ADD(polctl-afb) + + # Define project Targets + ADD_LIBRARY(${TARGET_NAME} MODULE polctl-binding.c ) + + # Generate API-v2 hat from OpenAPI json definition + SET_TARGET_GENSKEL(${TARGET_NAME} polctl-apidef) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "afb-" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME polctl + + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + audio-interface + ) + + # installation directory + INSTALL(TARGETS ${TARGET_NAME} + LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) + diff --git a/PolicyCtl-afb/polctl-apidef.h b/PolicyCtl-afb/polctl-apidef.h new file mode 100644 index 0000000..9e2b1a7 --- /dev/null +++ b/PolicyCtl-afb/polctl-apidef.h @@ -0,0 +1,90 @@ + +static const char _afb_description_v2_polctl[] = + "{\"openapi\":\"3.0.0\",\"$schema\":\"http:iot.bzh/download/openapi/schem" + "a-3.0/default-schema.json\",\"info\":{\"description\":\"\",\"title\":\"p" + "olctl\",\"version\":\"1.0\",\"x-binding-c-generator\":{\"api\":\"polctl\"" + ",\"version\":2,\"prefix\":\"polctl_\",\"postfix\":\"\",\"start\":null,\"" + "onevent\":null,\"init\":\"polctl_init\",\"scope\":\"\",\"private\":false" + "}},\"servers\":[{\"url\":\"ws://{host}:{port}/api/polctl\",\"description" + "\":\"Unicens2 API.\",\"variables\":{\"host\":{\"default\":\"localhost\"}" + ",\"port\":{\"default\":\"1234\"}},\"x-afb-events\":[{\"$ref\":\"#/compon" + "ents/schemas/afb-event\"}]}],\"components\":{\"schemas\":{\"afb-reply\":" + "{\"$ref\":\"#/components/schemas/afb-reply-v2\"},\"afb-event\":{\"$ref\"" + ":\"#/components/schemas/afb-event-v2\"},\"afb-reply-v2\":{\"title\":\"Ge" + "neric response.\",\"type\":\"object\",\"required\":[\"jtype\",\"request\"" + "],\"properties\":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-reply\"" + "},\"request\":{\"type\":\"object\",\"required\":[\"status\"],\"propertie" + "s\":{\"status\":{\"type\":\"string\"},\"info\":{\"type\":\"string\"},\"t" + "oken\":{\"type\":\"string\"},\"uuid\":{\"type\":\"string\"},\"reqid\":{\"" + "type\":\"string\"}}},\"response\":{\"type\":\"object\"}}},\"afb-event-v2" + "\":{\"type\":\"object\",\"required\":[\"jtype\",\"event\"],\"properties\"" + ":{\"jtype\":{\"type\":\"string\",\"const\":\"afb-event\"},\"event\":{\"t" + "ype\":\"string\"},\"data\":{\"type\":\"object\"}}}},\"x-permissions\":{\"" + "monitor\":{\"permission\":\"urn:AGL:permission:audio:public:monitor\"},\"" + "multimedia\":{\"permission\":\"urn:AGL:permission:audio:public:monitor\"" + "},\"navigation\":{\"permission\":\"urn:AGL:permission:audio:public:monit" + "or\"},\"emergency\":{\"permission\":\"urn:AGL:permission:audio:public:em" + "ergency\"}},\"responses\":{\"200\":{\"description\":\"A complex object a" + "rray response\",\"content\":{\"application/json\":{\"schema\":{\"$ref\":" + "\"#/components/schemas/afb-reply\"}}}}}},\"paths\":{\"/monitor\":{\"desc" + "ription\":\"Subcribe Audio Agent Policy Control End\",\"get\":{\"x-permi" + "ssions\":{\"$ref\":\"#/components/x-permissions/monitor\"},\"parameters\"" + ":[{\"in\":\"query\",\"name\":\"event_patern\",\"required\":true,\"schema" + "\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref\":\"#/componen" + "ts/responses/200\"}}}},\"/event_test\":{\"description\":\"Pause Resume T" + "est\",\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/" + "monitor\"},\"parameters\":[{\"in\":\"query\",\"name\":\"delay\",\"requir" + "ed\":false,\"schema\":{\"type\":\"interger\"}},{\"in\":\"query\",\"name\"" + ":\"count\",\"required\":false,\"schema\":{\"type\":\"interger\"}}],\"res" + "ponses\":{\"200\":{\"$ref\":\"#/components/responses/200\"}}}},\"/naviga" + "tion\":{\"description\":\"Request Access to Navigation Audio Channel.\"," + "\"get\":{\"x-permissions\":{\"$ref\":\"#/components/x-permissions/naviga" + "tion\"},\"parameters\":[{\"in\":\"query\",\"name\":\"zone\",\"required\"" + ":false,\"schema\":{\"type\":\"string\"}}],\"responses\":{\"200\":{\"$ref" + "\":\"#/components/responses/200\"}}}}}}" +; + +static const struct afb_auth _afb_auths_v2_polctl[] = { + { .type = afb_auth_Permission, .text = "urn:AGL:permission:audio:public:monitor" } +}; + + void polctl_monitor(struct afb_req req); + void polctl_event_test(struct afb_req req); + void polctl_navigation(struct afb_req req); + +static const struct afb_verb_v2 _afb_verbs_v2_polctl[] = { + { + .verb = "monitor", + .callback = polctl_monitor, + .auth = &_afb_auths_v2_polctl[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { + .verb = "event_test", + .callback = polctl_event_test, + .auth = &_afb_auths_v2_polctl[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { + .verb = "navigation", + .callback = polctl_navigation, + .auth = &_afb_auths_v2_polctl[0], + .info = NULL, + .session = AFB_SESSION_NONE_V2 + }, + { .verb = NULL } +}; + +const struct afb_binding_v2 afbBindingV2 = { + .api = "polctl", + .specification = _afb_description_v2_polctl, + .info = NULL, + .verbs = _afb_verbs_v2_polctl, + .preinit = NULL, + .init = polctl_init, + .onevent = NULL, + .noconcurrency = 0 +}; + diff --git a/PolicyCtl-afb/polctl-apidef.json b/PolicyCtl-afb/polctl-apidef.json new file mode 100644 index 0000000..65fe0ec --- /dev/null +++ b/PolicyCtl-afb/polctl-apidef.json @@ -0,0 +1,175 @@ +{ + "openapi": "3.0.0", + "$schema": "http:iot.bzh/download/openapi/schema-3.0/default-schema.json", + "info": { + "description": "", + "title": "polctl", + "version": "1.0", + "x-binding-c-generator": { + "api": "polctl", + "version": 2, + "prefix": "polctl_", + "postfix": "", + "start": null , + "onevent": null, + "init": "polctl_init", + "scope": "", + "private": false + } + }, + "servers": [ + { + "url": "ws://{host}:{port}/api/polctl", + "description": "Unicens2 API.", + "variables": { + "host": { + "default": "localhost" + }, + "port": { + "default": "1234" + } + }, + "x-afb-events": [ + { + "$ref": "#/components/schemas/afb-event" + } + ] + } + ], + "components": { + "schemas": { + "afb-reply": { + "$ref": "#/components/schemas/afb-reply-v2" + }, + "afb-event": { + "$ref": "#/components/schemas/afb-event-v2" + }, + "afb-reply-v2": { + "title": "Generic response.", + "type": "object", + "required": [ "jtype", "request" ], + "properties": { + "jtype": { + "type": "string", + "const": "afb-reply" + }, + "request": { + "type": "object", + "required": [ "status" ], + "properties": { + "status": { "type": "string" }, + "info": { "type": "string" }, + "token": { "type": "string" }, + "uuid": { "type": "string" }, + "reqid": { "type": "string" } + } + }, + "response": { "type": "object" } + } + }, + "afb-event-v2": { + "type": "object", + "required": [ "jtype", "event" ], + "properties": { + "jtype": { + "type": "string", + "const": "afb-event" + }, + "event": { "type": "string" }, + "data": { "type": "object" } + } + } + }, + "x-permissions": { + "monitor": { + "permission": "urn:AGL:permission:audio:public:monitor" + }, + "multimedia": { + "permission": "urn:AGL:permission:audio:public:monitor" + }, + "navigation": { + "permission": "urn:AGL:permission:audio:public:monitor" + }, + "emergency": { + "permission": "urn:AGL:permission:audio:public:emergency" + } + }, + "responses": { + "200": { + "description": "A complex object array response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/afb-reply" + } + } + } + } + } + }, + "paths": { + "/monitor": { + "description": "Subcribe Audio Agent Policy Control End", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/monitor" + }, + "parameters": [ + { + "in": "query", + "name": "event_patern", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": {"$ref": "#/components/responses/200"} + } + } + }, + "/event_test": { + "description": "Pause Resume Test", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/monitor" + }, + "parameters": [ + { + "in": "query", + "name": "delay", + "required": false, + "schema": { "type": "interger" } + }, + { + "in": "query", + "name": "count", + "required": false, + "schema": { "type": "interger" } + } + ], + "responses": { + "200": {"$ref": "#/components/responses/200"} + } + } + }, + "/navigation": { + "description": "Request Access to Navigation Audio Channel.", + "get": { + "x-permissions": { + "$ref": "#/components/x-permissions/navigation" + }, + "parameters": [ + { + "in": "query", + "name": "zone", + "required": false, + "schema": { "type": "string" } + } + ], + "responses": { + "200": {"$ref": "#/components/responses/200"} + } + } + } + } +} diff --git a/PolicyCtl-afb/polctl-binding.c b/PolicyCtl-afb/polctl-binding.c new file mode 100644 index 0000000..d24b036 --- /dev/null +++ b/PolicyCtl-afb/polctl-binding.c @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author Fulup Ar Foll + * + * 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 +#include +#include +#include + +#include "audio-interface.h" + +STATIC int polctl_init (); + +// Include Binding Stub generated from Json OpenAPI +#include "polctl-apidef.h" + +#define DEFAULT_PAUSE_DELAY 3000 +#define DEFAULT_TEST_COUNT 1 + +typedef int (*timerCallbackT)(void *context); + + +typedef struct { + int value; + const char *label; +} AutoTestCtxT; + +typedef struct TimerHandleS { + int count; + int delay; + AutoTestCtxT *context; + timerCallbackT callback; + sd_event_source *evtSource; +} TimerHandleT; + +static afb_event afbevt; + + +STATIC int TimerNext (sd_event_source* source, uint64_t timer, void* handle) { + TimerHandleT *timerHandle = (TimerHandleT*) handle; + int done; + uint64_t usec; + + // Rearm timer if needed + timerHandle->count --; + if (timerHandle->count == 0) sd_event_source_unref(source); + else { + // otherwise validate timer for a new run + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_source_set_enabled(source, SD_EVENT_ONESHOT); + sd_event_source_set_time(source, usec + timerHandle->delay); + } + + done= timerHandle->callback(timerHandle->context); + if (!done) goto OnErrorExit; + + return 0; + +OnErrorExit: + AFB_WARNING("TimerNext Fail tag=%s", timerHandle->context->label); + return -1; +} + +STATIC void TimerStart(TimerHandleT *timerHandle, timerCallbackT callback, void *context) { + uint64_t usec; + + // populate CB handle + timerHandle->callback=callback; + timerHandle->context=context; + + // set a timer with ~250us accuracy + sd_event_now(afb_daemon_get_event_loop(), CLOCK_MONOTONIC, &usec); + sd_event_add_time(afb_daemon_get_event_loop(), &timerHandle->evtSource, CLOCK_MONOTONIC, usec+timerHandle->delay, 250, TimerNext, timerHandle); +} + +STATIC int DoPauseResumeCB (void *context) { + AutoTestCtxT *ctx= (AutoTestCtxT*)context; + json_object *ctlEventJ; + + if (ctx->value) ctx->value =0; + else ctx->value =1; + + ctlEventJ = json_object_new_object(); + json_object_object_add(ctlEventJ,"action", json_object_new_string(ctx->label)); + json_object_object_add(ctlEventJ,"value" , json_object_new_int(ctx->value)); + int done = afb_event_push(afbevt, ctlEventJ); + + AFB_NOTICE ("DoPauseResumeCB {action: '%s', value:%d} status=%d", ctx->label, ctx->value, done); + + return (done); +} + +PUBLIC void polctl_event_test (afb_req request) { + json_object *queryJ, *tmpJ; + TimerHandleT *timerHandle = malloc (sizeof (TimerHandleT)); + AutoTestCtxT *context = calloc (1, sizeof (AutoTestCtxT)); + int done; + + queryJ= afb_req_json(request); + done=json_object_object_get_ex(queryJ, "label", &tmpJ); + if (!done) { + afb_req_fail_f(request, "TEST-LABEL-MISSING", "label is mandatory for event_test"); + goto OnErrorExit; + } + context->label = strdup(json_object_get_string (tmpJ)); + + json_object_object_get_ex(queryJ, "delay", &tmpJ); + timerHandle->delay = json_object_get_int (tmpJ) * 1000; + if (timerHandle->delay == 0) timerHandle->delay=DEFAULT_PAUSE_DELAY * 1000; + + json_object_object_get_ex(queryJ, "count", &tmpJ); + timerHandle->count = json_object_get_int (tmpJ); + if (timerHandle->count == 0) timerHandle->count=DEFAULT_TEST_COUNT; + + // start a lool timer + TimerStart (timerHandle, DoPauseResumeCB, context); + + afb_req_success(request, NULL, NULL); + return; + + OnErrorExit: + return; +} + + +PUBLIC void polctl_navigation (afb_req request) { + + AFB_NOTICE ("Enter polctl_navigation"); + afb_req_success(request, NULL, NULL); +} + +PUBLIC void polctl_monitor (afb_req request) { + + // subscribe Client to event + int err = afb_req_subscribe(request, afbevt); + if (err != 0) { + afb_req_fail_f(request, "register-event", "Fail to subscribe binder event"); + goto OnErrorExit; + } + + afb_req_success(request, NULL, NULL); + + OnErrorExit: + return; +} + +// Create Binding Event at Init +PUBLIC int polctl_init () { + AFB_DEBUG ("Audio Policy Control Binding Init"); + + // create binder event to send test pause/resume + afbevt = afb_daemon_make_event("request"); + if (!afb_event_is_valid(afbevt)) { + AFB_ERROR ("POLCTL_INIT: Cannot register polctl event"); + return (1); + } + + return 0; +} + -- cgit 1.2.3-korg