Rewrite NTS Framework.
[sim/o1-interface.git] / ntsimulator / ntsim-ng / core / context.c
diff --git a/ntsimulator/ntsim-ng/core/context.c b/ntsimulator/ntsim-ng/core/context.c
new file mode 100644 (file)
index 0000000..9bc57f2
--- /dev/null
@@ -0,0 +1,370 @@
+/*************************************************************************
+*
+* Copyright 2020 highstreet technologies GmbH and others
+*
+* 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 "context.h"
+#include "utils/log_utils.h"
+#include "utils/sys_utils.h"
+#include <sysrepo.h>
+#include "core/session.h"
+#include <dirent.h>
+#include <libgen.h>
+#include <assert.h>
+
+//private variables for context state
+struct lys_ident_with_childcount {
+    struct lys_ident *ident;
+    int children;
+};
+static struct lys_ident_with_childcount *identities;
+static int identities_size;                 //number of found identities
+
+struct features_with_info {
+    char *name;
+    bool enabled;
+};
+static struct features_with_info *features;
+static int features_size;
+
+
+//private functions
+static bool check_identity_of_type(const struct lys_ident *ident, const struct lys_ident *type);
+static int identity_get_id(const struct lys_ident *ident);
+
+int context_init(const struct ly_ctx *ly_ctx) {
+    log_message(2, "context_init() begin\n");
+
+    identities = 0;
+    identities_size = 0;
+
+    features = 0;
+    features_size = 0;
+
+    log_message(2, "loading modules\n");
+    uint32_t idx = 0;
+    struct lys_module *module;
+    while((module = (struct lys_module *)ly_ctx_get_module_iter(ly_ctx, &idx)) != 0) {
+        log_message(2, "MODULE %s\n", module->name);
+        log_message(2, "  prefix: %s\n", module->prefix);
+        log_message(2, "  namespace: %s\n", module->ns);
+        log_message(2, "  imports [%d]", module->imp_size);
+        if(module->imp_size) {
+            log_message(2, ": ");
+            for(int i = 0; i < module->imp_size; i++) {
+                log_message(2, "%s(%s), ", module->imp[i].module->name, module->imp[i].module->prefix);
+            }
+        }
+        log_message(2, "\n");
+        log_message(2, "  implemented: %d\n", module->implemented);
+        
+        if(module->implemented) {
+            log_message(2, "  IDENT count: %d\n", module->ident_size);
+            if(module->ident_size) {
+                //add to list of identities
+                identities = (struct lys_ident_with_childcount *)realloc(identities, sizeof(struct lys_ident_with_childcount) * (identities_size + module->ident_size));
+                if(!identities) {
+                    log_error("bad realloc");
+                    return 1;
+                }
+
+                for(int i = 0; i < module->ident_size; i++) {
+                    identities[identities_size].ident = &module->ident[i];
+                    identities[identities_size].children = 0;
+                    identities_size++;
+
+                    if(module->ident[i].base_size) {
+                        log_message(2, "  IDENT[%d]  %s with base %s:%s\n", i, module->ident[i].name, module->ident[i].base[0]->module->name, module->ident[i].base[0]->name);
+                        int id = identity_get_id(module->ident[i].base[0]);
+                        if(id != -1) {
+                            identities[id].children++;
+                        }
+                    }
+                    else {
+                        log_message(2, "  IDENT[%d]  %s as base\n", i, module->ident[i].name);
+                    }
+                }
+            }
+
+
+            log_message(2, "  FEATURES count: %d\n", module->features_size);
+            if(module->features_size) {
+                //add to list of features
+                features = (struct features_with_info *)realloc(features, sizeof(struct features_with_info) * (features_size + module->features_size));
+                if(!features) {
+                    log_error("bad realloc");
+                    return 1;
+                }
+
+                for(int i = 0; i < module->features_size; i++) {
+                    asprintf(&features[features_size].name, "%s:%s", module->name, module->features[i].name);
+                    features[features_size].enabled = (lys_features_state(module, module->features[i].name) == 1);
+                    log_message(2, "  FEATURE[%d]  %s iffeature_size=%d enabled=%d\n", i, module->features[i].name, module->features[i].iffeature_size, features[features_size].enabled);
+                    features_size++;
+                }
+            }
+        }
+        else {
+            log_message(2, "Module not implemented, skipping...\n");
+        }
+
+        log_message(2, " ----\n");
+    }
+
+    log_message(2, "context_init() finished\n");
+
+    return 0;
+}
+
+void context_free(void) {
+    log_message(2, "context_free()... ");
+    free(identities);
+    identities_size = 0;
+
+    for(int i = 0; i < features_size; i++) {
+        free(features[i].name);
+    }
+    free(features);   
+    log_message(2, "done\n");
+}
+
+int context_get_identity_leafs_of_type(const struct lys_ident *ident, struct lys_ident ***found) {
+
+    *found = (struct lys_ident **)malloc(sizeof(struct lys_ident *) * identities_size);
+    if(!*found) {
+        log_error("bad malloc");
+    }
+
+    int count = 0;
+    for(int i = 0; i < identities_size; i++) {
+        if(check_identity_of_type(identities[i].ident, ident)) {
+            if(identities[i].children == 0) {
+                (*found)[count] = identities[i].ident;
+                count++;
+            }
+        }
+    }
+
+    if(count == 0) {
+        log_error("no identities found");
+    }
+    else {
+        *found = (struct lys_ident **)realloc(*found, sizeof(struct lys_ident *) * count);
+    }
+
+    return count;
+}
+
+int context_get_features(char ***found_features) {
+    char **ftrs = (char **)malloc(sizeof(char *) * features_size);
+    if(!ftrs) {
+        log_error("could not alloc");
+        return 0;
+    }
+
+    for(int i = 0; i < features_size; i++) {
+        ftrs[i] = (char *)malloc(sizeof(char) * (strlen(features[i].name) + 1));
+        if(!ftrs) {
+            log_error("could not alloc");
+            return 0;
+        }
+
+        strcpy(ftrs[i], features[i].name);
+    }
+
+    *found_features = ftrs;
+    return features_size;
+}
+
+bool context_get_feature_enabled(const char *feature) {
+    for(int i = 0; i < features_size; i++) {
+        if(strcmp(feature, features[i].name) == 0) {
+            return features[i].enabled;
+        }
+    }
+    return false;
+}
+
+bool context_feature_enable(const char *feature) {
+    assert(feature);
+
+    char mod[96];
+    char feat[96];
+
+    mod[0] = 0;
+    feat[0] = 0;
+
+    int i = 0;
+    int j = 0;
+    while((i < strlen(feature)) && (feature[i] != ':')) {
+        mod[j] = feature[i];
+        j++;
+        i++;
+    }
+    mod[j] = 0;
+    
+    i++;
+    j = 0;
+    while(i < strlen(feature)) {
+        feat[j] = feature[i];
+        j++;
+        i++;
+    }
+    feat[j] = 0;
+
+    int rc;
+    if((rc = sr_enable_module_feature(session_connection, mod, feat)) != SR_ERR_OK) {
+        return false;
+    }
+    
+    return true;
+}
+
+bool context_module_install(const char *name, const char *path) {
+    assert(name);
+    assert(path);
+
+    char *searchpath = strdup(path);
+    int rc = sr_install_module(session_connection, path, dirname(searchpath), 0, 0);
+    free(searchpath);
+    if(rc != SR_ERR_OK) {
+        /* succeed if the module is already installed */
+        if(rc != SR_ERR_EXISTS) {
+            return false;
+        }
+    }
+
+    char *data_path = str_replace(path, ".yang", ".xml");
+    if(file_exists(data_path)) {
+        rc = sr_install_module_data(session_connection, name, 0, data_path, LYD_XML);
+        if(rc != SR_ERR_OK) {
+            log_message(1, " xml error    ");
+            sr_remove_module(session_connection, name);
+            context_apply_changes();
+            return false;
+        }
+    }
+    free(data_path);
+
+    //apply changes
+    if(!context_apply_changes()) {
+        sr_remove_module(session_connection, name);
+        context_apply_changes();
+        return false;
+    }
+
+    return true;
+}
+
+bool context_module_set_access(const char *module_name) {
+    assert(module_name);
+
+    if(sr_set_module_access(session_connection, module_name, "root", "root", 0666) != SR_ERR_OK) {
+        return false;
+    }
+
+    return true;
+}
+
+bool context_apply_changes(void) {
+    int rc;
+    uint32_t connection_count = 0;
+
+    session_context = 0;
+    sr_disconnect(session_connection);
+    session_connection = 0;
+
+    /* get connection count */
+    if((rc = sr_connection_count(&connection_count)) != SR_ERR_OK) {
+        log_error("sr_connection_count() failed to get connection count");
+        return false;
+    }
+
+    if(connection_count) {
+        log_error("cannot apply changes because of existing connections");
+        return false;
+    }
+
+    if((rc = sr_connect(SR_CONN_ERR_ON_SCHED_FAIL, &session_connection)) != SR_ERR_OK) {
+        if((rc = sr_connect(0, &session_connection)) != SR_ERR_OK) {
+            log_error("failed to reconnect to sysrepo");
+        }
+        return false;
+    }
+
+    /* get context */
+    session_context = (struct ly_ctx *)sr_get_context(session_connection);
+    if(session_context == 0) {
+        log_error("sr_get_context failed");
+        return false;
+    }
+
+    return true;
+}
+
+bool context_yang_is_module(const char *path) {
+    assert(path);
+
+    bool ret = false;
+    struct ly_ctx *ctx = ly_ctx_new(0, 0);
+    if(!ctx) {
+        log_error("ly_ctx_new failed");
+    }
+
+    char *searchpath = strdup(path);
+    ly_ctx_set_searchdir(ctx, dirname(searchpath));
+    const struct lys_module *mod = lys_parse_path(ctx, path, LYS_YANG);
+    if((!mod) && (ly_vecode(ctx) == LYVE_SUBMODULE)) {
+        ret = true;
+    }
+
+    free(searchpath);
+    ly_ctx_destroy(ctx, 0);
+    return ret;
+}
+
+
+static bool check_identity_of_type(const struct lys_ident *ident, const struct lys_ident *type) {
+    assert(type);
+
+    if((ident->name == type->name) && (ident->module->name == type->module->name)) {
+        return true;
+    }
+    else if(ident->base_size != 0) {
+        bool result = false;
+        for(int i = 0; i < ident->base_size; i++) {
+            result |= check_identity_of_type(ident->base[i], type);
+        }
+        return result;
+    }
+    else {
+        return false;
+    }
+
+}
+
+static int identity_get_id(const struct lys_ident *ident) {
+    assert(ident);
+
+    for(int i = 0; i < identities_size; i++) {
+        if((ident->name == identities[i].ident->name) && (ident->module->name == identities[i].ident->module->name)) {
+            return i;
+        }
+    }
+
+    return -1;
+}