/* * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * Copyright (C) 2019 iopsys Software Solutions AB * Author: Imen Bhiri * Author: Feten Besbes * Author: Mohamed Kallel * Author: Anis Ellouze */ #include #include #include #include #include #include #include #include #include "dmubus.h" #include "dmmem.h" #include "dmcommon.h" #define DELIMITOR "," #define UBUS_BUFFEER_SIZE 1024 * 8 struct dmubus_ctx dmubus_ctx; #if DM_USE_LIBUBUS struct ubus_context *ubus_ctx; static int timeout = 1000; const char *ubus_socket = NULL; json_object *json_res = NULL; static inline bool dmblobmsg_add_object(struct blob_buf *b, json_object *obj) { json_object_object_foreach(obj, key, val) { if (!blobmsg_add_json_element(b, key, val)) return false; } return true; } static inline bool dmblobmsg_json_object_from_uargs(struct blob_buf *b, char *key, char *val) { bool status; json_object *jobj = json_object_new_object(); json_object *jstring = json_object_new_string(val); json_object_object_add(jobj,key, jstring); status = dmblobmsg_add_object(b, jobj); json_object_put(jobj); return status; } #endif static inline int ubus_arg_cmp(struct ubus_arg *src_args, int src_size, struct ubus_arg dst_args[], int dst_size) { if (src_size != dst_size) return -1; int i; for (i = 0; i < src_size; i++) { if (strcmp( src_args[i].key, dst_args[i].key) != 0 || strcmp( src_args[i].val, dst_args[i].val) != 0) return -1; } return 0; } #if DM_USE_LIBUBUS static void receive_call_result_data(struct ubus_request *req, int type, struct blob_attr *msg) { if (!msg) return; char *str = blobmsg_format_json_indent(msg, true, -1); if (!str) { json_res = NULL; return; } json_res = json_tokener_parse((const char *)str); free(str); //MEM should be free and not dmfree if (json_res != NULL && (is_error(json_res))) { json_object_put(json_res); json_res = NULL; } } #endif int dmubus_call_set(char *obj, char *method, struct ubus_arg u_args[], int u_args_size) { #if !DM_USE_LIBUBUS char bufargs[256], *p; int i, r; p = bufargs; if (u_args_size) { sprintf(p, "{"); for (i = 0; i < u_args_size; i++) { p += strlen(p); if (i == 0){ if(u_args[i].type != Integer) sprintf(p, "\"%s\": \"%s\"", u_args[i].key, u_args[i].val); else sprintf(p, "\"%s\": %s", u_args[i].key, u_args[i].val); } else{ if(u_args[i].type != Integer) sprintf(p, ", \"%s\": \"%s\"", u_args[i].key, u_args[i].val); else sprintf(p, ", \"%s\": %s", u_args[i].key, u_args[i].val); } } p += strlen(p); sprintf(p, "}"); DMCMD("ubus", 7, "-S", "-t", "1", "call", obj, method, bufargs); //TODO wait to fix uloop ubus freeze } else { DMCMD("ubus", 6, "-S", "-t", "1", "call", obj, method); //TODO wait to fix uloop ubus freeze } return 0; #else struct blob_buf b = {0}; uint32_t id; int ret; json_res = NULL; ubus_ctx = ubus_connect(ubus_socket); if (!ubus_ctx) return 0; blob_buf_init(&b, 0); int i=0; for (i = 0; i < u_args_size; i++) { if (!dmblobmsg_json_object_from_uargs(&b, u_args[i].key, u_args[i].val)) goto end_error; } ret = ubus_lookup_id(ubus_ctx, obj, &id); ubus_invoke(ubus_ctx, id, method, b.head, receive_call_result_data, NULL, timeout); blob_buf_free(&b); if (json_res != NULL) { json_object_put(json_res); json_res = NULL; } return 0; end_error: blob_buf_free(&b); return NULL; #endif } static inline json_object *ubus_call_req(char *obj, char *method, struct ubus_arg u_args[], int u_args_size) { #if !DM_USE_LIBUBUS json_object *res = NULL; char *ubus_return, bufargs[256], *p; int i, pp = 0, r; p = bufargs; if (u_args_size) { sprintf(p, "{"); for (i = 0; i < u_args_size; i++) { p += strlen(p); if (i == 0) sprintf(p, "\"%s\": \"%s\"", u_args[i].key, u_args[i].val); else sprintf(p, ", \"%s\": \"%s\"", u_args[i].key, u_args[i].val); } p += strlen(p); sprintf(p, "}"); pp = dmcmd("ubus", 7, "-S", "-t", "3", "call", obj, method, bufargs); //TODO wait to fix uloop ubus freeze } else { pp = dmcmd("ubus", 6, "-S", "-t", "3", "call", obj, method); //TODO wait to fix uloop ubus freeze } if (pp) { dmcmd_read_alloc(pp, &ubus_return); close(pp); if (ubus_return) { res = json_tokener_parse(ubus_return); if (res != NULL && (is_error(res))) { json_object_put(res); res = NULL; } } } return res; #else struct blob_buf b = {0}; uint32_t id; int ret; json_res = NULL; ubus_ctx = ubus_connect(ubus_socket); if (!ubus_ctx) return NULL; blob_buf_init(&b, 0); int i=0; for (i = 0; i < u_args_size; i++) { if (!dmblobmsg_json_object_from_uargs(&b, u_args[i].key, u_args[i].val)) goto end_error; } ret = ubus_lookup_id(ubus_ctx, obj, &id); ubus_invoke(ubus_ctx, id, method, b.head, receive_call_result_data, NULL, timeout); blob_buf_free(&b); return json_res; end_error: blob_buf_free(&b); return NULL; #endif } int dmubus_call(char *obj, char *method, struct ubus_arg u_args[], int u_args_size, json_object **req_res) { struct ubus_obj *i = NULL; struct ubus_meth *j = NULL; struct ubus_msg *k = NULL; json_object **jr; bool found = false; *req_res = NULL; list_for_each_entry(i, &dmubus_ctx.obj_head, list) { if (strcmp(obj, i->name) == 0) { found = true; break; } } if (!found) { i = dmcalloc(1, sizeof(struct ubus_obj)); //init method head INIT_LIST_HEAD(&i->method_head); i->name = dmstrdup(obj); list_add(&i->list, &dmubus_ctx.obj_head); } found = false; list_for_each_entry(j, &i->method_head, list) { if (strcmp(method, j->name) == 0) { *req_res = j->res; found = true; break; } } if (!found) { j = dmcalloc(1, sizeof(struct ubus_meth)); //init message head INIT_LIST_HEAD(&j->msg_head); j->name = dmstrdup(method); list_add(&j->list, &i->method_head); jr = &j->res; } // Arguments if (u_args_size != 0) { found = false; int n=0; list_for_each_entry(k, &j->msg_head, list) { if (ubus_arg_cmp(k->ug, k->ug_size, u_args, u_args_size) == 0) { *req_res = k->res; found = true; break; } } if (!found) { k = dmcalloc(1, sizeof(struct ubus_msg)); list_add(&k->list, &j->msg_head); k->ug = dmcalloc(u_args_size, sizeof(struct ubus_arg)); k->ug_size = u_args_size; jr = &k->res; int c; for (c = 0; c < u_args_size; c++) { k->ug[c].key = dmstrdup(u_args[c].key); k->ug[c].val = dmstrdup(u_args[c].val); } } } if (!found) { *jr = ubus_call_req(obj, method, u_args, u_args_size); *req_res = *jr; } return 0; } void dmubus_ctx_free(struct dmubus_ctx *ctx) { struct ubus_obj *i, *_i; struct ubus_meth *j, *_j; struct ubus_msg *k, *_k; list_for_each_entry_safe(i, _i, &ctx->obj_head, list) { list_for_each_entry_safe(j, _j, &i->method_head, list) { list_for_each_entry_safe(k, _k, &j->msg_head, list) { if(k->ug_size != 0) { int c; for (c = 0; c < k->ug_size; c++) { dmfree(k->ug[c].key); dmfree(k->ug[c].val); } dmfree(k->ug); } list_del(&k->list); if(k->res) json_object_put(k->res); dmfree(k); } list_del(&j->list); if(j->res) json_object_put(j->res); dmfree(j->name); dmfree(j); } list_del(&i->list); dmfree(i->name); dmfree(i); } }