From 197d9acab4fb5097d3dce56227c2096abdc075bd Mon Sep 17 00:00:00 2001 From: Sebastien Douheret Date: Thu, 24 May 2018 15:48:18 +0200 Subject: Convert binding to use the controller Change-Id: Iae15b07ee768584d7a1a958fb7e119bca65c29e4 Signed-off-by: Sebastien Douheret --- src/plugins/CMakeLists.txt | 42 ++++++++++ src/plugins/supervisor-api.c | 164 ++++++++++++++++++++++++++++++++++++ src/plugins/supervisor-api.h | 36 ++++++++ src/plugins/supervisor.c | 194 +++++++++++++++++++++++++++++++++++++++++++ src/plugins/supervisor.h | 53 ++++++++++++ 5 files changed, 489 insertions(+) create mode 100644 src/plugins/CMakeLists.txt create mode 100644 src/plugins/supervisor-api.c create mode 100644 src/plugins/supervisor-api.h create mode 100644 src/plugins/supervisor.c create mode 100644 src/plugins/supervisor.h (limited to 'src/plugins') diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt new file mode 100644 index 0000000..1c1c557 --- /dev/null +++ b/src/plugins/CMakeLists.txt @@ -0,0 +1,42 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Romain Forlot +# +# 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. +########################################################################### + +PROJECT_TARGET_ADD(supervisor) + + # Define targets + ADD_LIBRARY(${TARGET_NAME} MODULE + ${TARGET_NAME}-api.c + ${TARGET_NAME}.c + ../utils/list.c) + + # Alsa Plugin properties + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + LABELS "PLUGIN" + PREFIX "" + SUFFIX ".ctlso" + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + afb-helpers + ${link_libraries} + ) + + target_include_directories(${TARGET_NAME} + PRIVATE "${CMAKE_SOURCE_DIR}/app-controller/ctl-lib") diff --git a/src/plugins/supervisor-api.c b/src/plugins/supervisor-api.c new file mode 100644 index 0000000..0c1a5bc --- /dev/null +++ b/src/plugins/supervisor-api.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author "Sebastien Douheret" + * + * 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 "ctl-plugin.h" +#include "supervisor-api.h" +#include "supervisor.h" +#include "wrap-json.h" + +CTLP_CAPI_REGISTER("supervisor"); + +CTLP_ONLOAD(plugin, ret) +{ + return 0; +} + +CTLP_CAPI(list, source, argsJ, eventJ) +{ + json_object *result, *item = NULL; + DAEMONS_T* daemons = NULL; + + getDaemons(source->api, &daemons); + if (daemons == NULL) { + AFB_ApiError(source->api, "failed"); + return ERROR; + } + + result = json_object_new_array(); + + for (int i = 0; i < daemons->count; i++) { + wrap_json_pack(&item, "{si ss sb sb so so so}", + "pid", daemons->daemons[i]->pid, + "name", daemons->daemons[i]->name, + "isServer", daemons->daemons[i]->isServer, + "isClient", daemons->daemons[i]->isClient, + "ws_servers", daemons->daemons[i]->ws_servers, + "ws_clients", daemons->daemons[i]->ws_clients, + "apis", daemons->daemons[i]->apis); + //, "config", daemons->daemons[i]->config); + json_object_array_add(result, item); + } + AFB_ReqSucess(source->request, result, NULL); + return 0; +} + +CTLP_CAPI(trace, source, argsJ, eventJ) +{ + int rc; + json_object* result = NULL; + DAEMONS_T* daemons = NULL; + const char* ws_name; + const char* wsn; + + if (wrap_json_unpack(argsJ, "{s:?s}", "ws", &ws_name)) { + AFB_ReqFail(source->request, "Failed", "Error processing arguments."); + return ERROR; + } + AFB_ApiNotice(source->api, "Trace ws: %s", ws_name); + + getDaemons(source->api, &daemons); + if (daemons == NULL || daemons->count <= 0) { + AFB_ReqFail(source->request, "failed", "No daemon found"); + } + + // search server and client pid + DAEMON_T *pid_s = NULL, *pid_c = NULL; + for (int i = 0; i < daemons->count; i++) { + AFB_ApiDebug(source->api, "_DEBUG_ svr %s", + json_object_to_json_string(daemons->daemons[i]->ws_servers)); + AFB_ApiDebug(source->api, "_DEBUG_ cli %s", + json_object_to_json_string(daemons->daemons[i]->ws_clients)); + + json_object* ws_servers = daemons->daemons[i]->ws_servers; + for (int j = 0; j < json_object_array_length(ws_servers); j++) { + + wsn = json_object_get_string(json_object_array_get_idx(ws_servers, j++)); + if (wsn && strstr(wsn, ws_name) != NULL) { + pid_s = daemons->daemons[i]; + break; + } + } + + json_object* ws_clients = daemons->daemons[i]->ws_clients; + for (int j = 0; j < json_object_array_length(ws_clients); j++) { + wsn = json_object_get_string(json_object_array_get_idx(ws_clients, j++)); + if (wsn && strstr(wsn, ws_name) != NULL) { + pid_c = daemons->daemons[i]; + break; + } + } + + if (pid_s != NULL && pid_c != NULL) { + if ((rc = trace_exchange(source->api, pid_s, pid_c)) < 0) { + AFB_ReqFailF(source->request, "failed", "Trace error %d", rc); + } + break; + } + } + + if (pid_s == NULL || pid_c == NULL) { + AFB_ReqFail(source->request, "failed", "Cannot determine Server or Client"); + return ERROR; + } + + AFB_ReqSucessF(source->request, result, "Tracing Server pid=%d <-> Client pid=%d", pid_s->pid, pid_c->pid); + + return 0; +} + +/* SEB TODO +void xds_event_cb(const char* evtname, json_object* j_event) +{ + int rc; + METRIC_T metric; + const char* type = NULL; + struct json_object* request = NULL; + + AFB_NOTICE("RECV Event %s : %s", evtname, + json_object_to_json_string(j_event)); + + if (strcmp(evtname, "supervisor/trace") != 0) { + return; + } + + if ((rc = wrap_json_unpack(j_event, "{s:?s}", "type", &type)) < 0) { + AFB_ERROR("Cannot decode event type"); + return; + } + + if (strcmp(type, "request") == 0) { + + if (!json_object_object_get_ex(j_event, "request", &request)) { + AFB_ERROR("Cannot decode event request"); + return; + } + metric.name = "trace"; + metric.data = request; + + rc = harvester_post_data(&metric); + if (rc < 0) { + AFB_ERROR("ERROR harvester_post_data: rc %d", rc); + } + } +} +*/ diff --git a/src/plugins/supervisor-api.h b/src/plugins/supervisor-api.h new file mode 100644 index 0000000..beadeca --- /dev/null +++ b/src/plugins/supervisor-api.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author "Sebastien Douheret" + * + * 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 +#include "wrap-json.h" +#include "filescan-utils.h" + +#define SRV_HARVESTER_NAME "harvester" + +#define META_SOURCENAME GetBinderName(); +#define META_IDENTITY "" // FIXME + +#ifndef ERROR + #define ERROR -1 +#endif + +typedef struct metric_t { + char* name; + json_object* data; + struct timespec timestamp; +} METRIC_T; diff --git a/src/plugins/supervisor.c b/src/plugins/supervisor.c new file mode 100644 index 0000000..649713e --- /dev/null +++ b/src/plugins/supervisor.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2018 "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 +#include +#include + +#include "ctl-plugin.h" +#include "supervisor-api.h" +#include "supervisor.h" +#include "wrap-json.h" + +struct afb_cred { + int refcount; + uid_t uid; + gid_t gid; + pid_t pid; + const char* user; + const char* label; + const char* id; +}; + +static const char* null_str = "null"; + +struct decode_daemon_str { + DAEMONS_T* daemons; + AFB_ApiT api; + const char* ignored_daemon; +}; + +static void decode_daemons_cb(void* closure, json_object* obj, const char* fName) +{ + int rc; + struct afb_cred cred; + json_object *j_response, *j_query, *j_config, *j_ws_servers, *j_ws_clients; + json_object *j_name, *j_apis; + struct decode_daemon_str* clStr = (struct decode_daemon_str*)closure; + DAEMON_T* daemon = calloc(sizeof(DAEMON_T), 1); + + if (!clStr->daemons) + return; + + if ((rc = wrap_json_unpack(obj, "{si si si ss ss ss}", "pid", &cred.pid, + "uid", &cred.uid, "gid", &cred.gid, "id", &cred.id, + "label", &cred.label, "user", &cred.user)) + < 0) { + // TODO + return; + } + + AFB_ApiInfo(clStr->api, "Get config of pid %d", cred.pid); + daemon->pid = cred.pid; + + // Get config + wrap_json_pack(&j_query, "{s:i}", "pid", cred.pid); + rc = AFB_ServiceSync(clStr->api, SRV_SUPERVISOR_NAME, "config", j_query, &j_response); + if (rc < 0) { + AFB_ApiError(clStr->api, "Cannot get config of pid %d", cred.pid); + return; + } + + AFB_ApiDebug(clStr->api, "%s config result, res=%s", SRV_SUPERVISOR_NAME, + json_object_to_json_string(j_response)); + + if (json_object_object_get_ex(j_response, "response", &j_config)) { + // FIXME : implement free + daemon->config = j_config; + + rc = wrap_json_unpack(j_config, "{s:o s:o s:o}", + "name", &j_name, + "ws_servers", &j_ws_servers, + "ws_clients", &j_ws_clients); + if (rc < 0) { + AFB_ApiError(clStr->api, "Error decoding config response %s", wrap_json_get_error_string(rc)); + return; + } + + daemon->name = json_object_is_type(j_name, json_type_null) ? null_str : json_object_get_string(j_name); + + // ignored some daemon + if (clStr->ignored_daemon != NULL && strstr(daemon->name, clStr->ignored_daemon) != NULL) { + free(daemon); + return; + } + + daemon->ws_servers = j_ws_servers; + daemon->isServer = (json_object_array_length(j_ws_servers) > 0); + daemon->ws_clients = j_ws_clients; + daemon->isClient = (json_object_array_length(j_ws_clients) > 0); + } + + // Get apis + // '{"pid":6262,"api":"monitor","verb":"get","args":{"apis":true}} + wrap_json_pack(&j_query, "{si ss ss s {sb}}", + "pid", cred.pid, + "api", "monitor", + "verb", "get", + "args", "apis", true); + rc = AFB_ServiceSync(clStr->api, SRV_SUPERVISOR_NAME, "do", j_query, &j_response); + if (rc < 0) { + AFB_ApiError(clStr->api, "Cannot get apis of pid %d", cred.pid); + return; + } else { + AFB_ApiDebug(clStr->api, "%s do ...get apis result, res=%s", SRV_SUPERVISOR_NAME, json_object_to_json_string(j_response)); + + if (json_object_object_get_ex(j_response, "response", &j_config) && json_object_object_get_ex(j_config, "apis", &j_apis)) { + daemon->apis = j_apis; + } + } + clStr->daemons->daemons[clStr->daemons->count] = daemon; + clStr->daemons->count++; +} + +int getDaemons(AFB_ApiT apiHandle, DAEMONS_T** daemons) +{ + int rc; + json_object *j_response, *j_daemons = NULL; + + *daemons = calloc(sizeof(DAEMONS_T), 1); + + if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "discover", NULL, + &j_response)) + < 0) { + return rc; + } + + if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "list", NULL, + &j_response)) + < 0) { + return rc; + } + + AFB_ApiDebug(apiHandle, "%s list result, res=%s", SRV_SUPERVISOR_NAME, json_object_to_json_string(j_response)); + + if (json_object_object_get_ex(j_response, "response", &j_daemons)) { + struct decode_daemon_str str = { + *daemons, + apiHandle, + GetBinderName() + }; + wrap_json_object_for_all(j_daemons, decode_daemons_cb, &str); + } + + return 0; +} + +int trace_exchange(AFB_ApiT apiHandle, DAEMON_T* svr, DAEMON_T* cli) +{ + int rc; + json_object *j_response, *j_query; + + if (svr == NULL || cli == NULL) { + return -1; + } + + wrap_json_pack(&j_query, "{s:i, s:{s:s}}", "pid", svr->pid, "add", + "request", "common"); + if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, + &j_response)) + < 0) { + AFB_ApiError(apiHandle, "ERROR trace %d result: %s", svr->pid, + json_object_to_json_string(j_response)); + return rc; + } + + wrap_json_pack(&j_query, "{s:i}", "pid", cli->pid); + if ((rc = AFB_ServiceSync(apiHandle, SRV_SUPERVISOR_NAME, "trace", j_query, + &j_response)) + < 0) { + AFB_ApiError(apiHandle, "ERROR trace %d result: %s", cli->pid, + json_object_to_json_string(j_response)); + return rc; + } + + return 0; +} + +int supervisor_init(void) +{ + return 0; +} diff --git a/src/plugins/supervisor.h b/src/plugins/supervisor.h new file mode 100644 index 0000000..3311734 --- /dev/null +++ b/src/plugins/supervisor.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author "Sebastien Douheret" + * + * 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 +#include "wrap-json.h" + +#define SRV_SUPERVISOR_NAME "supervisor" + +// FIXME Use chained list instead of static array +#define MAX_CLIENTS 32 +#define MAX_SERVERS 32 +#define MAX_DAEMONS 1024 + + +typedef struct daemon +{ + int pid; + const char* name; + bool isServer; + bool isClient; + //char *ws_clients[MAX_CLIENTS]; + //char *ws_servers[MAX_SERVERS]; + json_object *ws_clients; + json_object *ws_servers; + json_object *config; + json_object *apis; +} DAEMON_T; + +typedef struct daemons_result_ +{ + int count; + DAEMON_T *daemons[MAX_DAEMONS]; +} DAEMONS_T; + + +extern int getDaemons(AFB_ApiT apiHandle, DAEMONS_T **daemons); +extern int trace_exchange(AFB_ApiT apiHandle, DAEMON_T *svr, DAEMON_T *cli); +extern int supervisor_init(void); -- cgit 1.2.3-korg