| #include "rpc.h" | |
| //static unsigned short int instance_id = 0; | |
| struct tr069_instance * malloc_instance(struct tr069_obj * obj, struct tr069_instance * parent, int id) | |
| { | |
| struct tr069_instance * instance = (struct tr069_instance *)tr069_malloc(sizeof(struct tr069_instance)); | |
| if (instance == NULL) { | |
| TR069_ERR("Malloc instance failed!"); | |
| return NULL; | |
| } | |
| //TR069_DEBUG("%s: %s old %p", __func__, obj->name, obj->instance_list); | |
| memset(instance, 0, sizeof(struct tr069_instance)); | |
| instance->id = (id > 0) ? id : ++obj->instance_cnt; | |
| instance->parent = parent; | |
| instance->next = obj->instance_list; | |
| //TR069_DEBUG("%s: %s new %p", __func__, obj->name, obj->instance_list); | |
| obj->instance_list = instance; | |
| return instance; | |
| } | |
| int free_instance(struct tr069_obj * obj, struct tr069_instance * is) | |
| { | |
| struct tr069_instance * backup = obj->instance_list; | |
| TR069_DEBUG("%s: %s(%p)", __func__, obj->name, is); | |
| if (obj->instance_list == is) { | |
| obj->instance_list = is->next; | |
| if (obj->del_obj) obj->del_obj(obj, is); | |
| tr069_free(is); | |
| return 0; | |
| } | |
| while (backup) { | |
| if (backup->next == is) { | |
| backup->next = is->next; | |
| if (obj->del_obj) obj->del_obj(obj, is); | |
| tr069_free(is); | |
| return 0; | |
| } | |
| backup = backup->next; | |
| } | |
| TR069_DEBUG("%s: failed", __func__); | |
| return -1; | |
| } | |
| #define MAX_TRACE_DEEP 20 | |
| static struct tr069_instance * instance_stack[MAX_TRACE_DEEP] = {NULL}; | |
| static int instance_index = 0; | |
| static void push_instance(struct tr069_instance * instance) | |
| { | |
| instance_stack[instance_index == 0 ? instance_index : ++instance_index] = instance; | |
| } | |
| /* | |
| static struct tr069_instance * pop_instance(void) | |
| { | |
| return instance_stack[instance_index--]; | |
| } | |
| */ | |
| struct tr069_instance * top_instance(void) | |
| { | |
| return instance_stack[instance_index]; | |
| } | |
| static void reset_stack(void) | |
| { | |
| memset(instance_stack, 0, sizeof(instance_stack)); | |
| instance_index = 0; | |
| } | |
| #if 1 | |
| // This API used by user | |
| extern struct tr069_obj root_obj[]; | |
| int rpc_add_obj_api(const char * path, int id, struct tr069_instance ** ppis) | |
| { | |
| struct tr069_obj * obj = find_obj(root_obj, path); | |
| struct tr069_instance * pis = NULL; | |
| int ret = 0; | |
| if (!obj) { | |
| TR069_ERR("RPC add object failed, cannot find object..."); | |
| return -1; | |
| } | |
| pis = malloc_instance(obj, top_instance(), id); | |
| if (pis) { | |
| *ppis = pis; | |
| if (obj->add_obj) | |
| ret = obj->add_obj(obj, pis); | |
| //TR069_DEBUG("%s: %s new %p next %p", __func__, path, pis, pis->next); | |
| if (ret) { | |
| TR069_ERR("%s: Add object failed:%s", __func__, path); | |
| free_instance(obj, pis); | |
| *ppis = NULL; | |
| return -1; | |
| } | |
| return pis->id; | |
| } | |
| return -1; | |
| } | |
| #endif | |
| static struct tr069_instance * __find_instance(struct tr069_obj * obj, const char * id) | |
| { | |
| struct tr069_instance * is = obj->instance_list; | |
| while (is) { | |
| if (is->parent == top_instance()) { | |
| if (*id == '[') { | |
| struct tr069_param * p = obj->param_list; | |
| while (p && p->name) { | |
| if (!strcmp(p->name, "Alias")) { | |
| if (p->get_value) { | |
| char * value = NULL; | |
| p->get_value(is, &value); | |
| if (value) { | |
| if (!strncmp(id + 1, value, strlen(value))) { | |
| TR069_DEBUG("find_instance: Handle alias instance %s", id); | |
| tr069_free(value); | |
| return is; | |
| } | |
| tr069_free(value); | |
| value = NULL; | |
| } | |
| } | |
| } | |
| p++; | |
| } | |
| } else if (is->id == atoi(id)) { | |
| TR069_DEBUG("find_instance: return instance for %s(%s)", obj->name, id); | |
| return is; | |
| } | |
| } | |
| is = is->next; | |
| } | |
| TR069_DEBUG("find_instance: return NULL instance with %s", obj->name); | |
| return NULL; | |
| } | |
| static struct tr069_obj * __find_obj(struct tr069_obj * root, char ** trace) | |
| { | |
| struct tr069_obj * p = root; | |
| while (p && p->name) { | |
| if (!strcmp(*trace, p->name)) { | |
| if (*(trace + 1) == NULL) { | |
| return p; | |
| } else { | |
| char ** next = trace + 1; | |
| // If next object is instance, find instance and push to stack | |
| if (isdigit(**next) || (**next == '[')) { | |
| // Push to stack | |
| push_instance(__find_instance(p, *next)); | |
| if (*(next + 1) == NULL) | |
| return p; | |
| next++; | |
| } | |
| return __find_obj(p->obj_list, next); | |
| } | |
| } | |
| p++; | |
| } | |
| return NULL; | |
| } | |
| struct tr069_obj * find_obj(struct tr069_obj * root, const char * path) | |
| { | |
| char * trace[MAX_TRACE_DEEP] = {0}; | |
| struct tr069_obj * obj; | |
| char * pos, * temp_path; | |
| char ** trace_index = &trace[0]; | |
| int len = strlen(path); | |
| if (path[len - 1] != '.' || *path == '.') { | |
| TR069_ERR("Bat agr @%s:%d", __func__, __LINE__); | |
| return NULL; | |
| } | |
| reset_stack(); | |
| pos = temp_path = tr069_strdup(path); | |
| while (pos != (temp_path + len)) { | |
| char * c; | |
| // Add trace deep check | |
| *trace_index = tr069_strdup(pos); | |
| c = strchr(*trace_index, '.'); | |
| if (c == NULL) { | |
| // assert, add free code | |
| tr069_free(*trace_index); | |
| tr069_free(temp_path); | |
| TR069_ERR("Assert failed @%s:%d", __func__, __LINE__); | |
| return NULL; | |
| } | |
| *c = '\0'; | |
| trace_index++; | |
| pos = strchr(pos, '.'); | |
| if(pos){ | |
| pos++; | |
| }else{ | |
| break; | |
| } | |
| } | |
| tr069_free(temp_path); | |
| instance_index = 0; | |
| obj = __find_obj(root, &trace[0]); | |
| if (!obj) TR069_ERR("%s: failed, %s", __func__, path); | |
| // Free trace data | |
| trace_index = &trace[0]; | |
| while (*trace_index) { | |
| tr069_free(*trace_index); | |
| *trace_index = NULL; | |
| trace_index++; | |
| } | |
| return obj; | |
| } | |
| static struct tr069_param * __find_param(struct tr069_obj * object, char * path) | |
| { | |
| struct tr069_param * p = object->param_list; | |
| while (p && p->name) { | |
| if (!strcmp(path, p->name)) { | |
| return p; | |
| } | |
| p++; | |
| } | |
| return NULL; | |
| } | |
| struct tr069_param * find_param(struct tr069_obj * root, const char * path) | |
| { | |
| char * trace[MAX_TRACE_DEEP + 1] = {0}; | |
| struct tr069_obj * obj; | |
| struct tr069_param * param = NULL; | |
| char * pos, * temp_path; | |
| char ** trace_index = &trace[0]; | |
| int len = strlen(path); | |
| int deep = 0; | |
| if (*path == '.') { | |
| TR069_ERR("Bat agr @%s:%d", __func__, __LINE__); | |
| return NULL; | |
| } | |
| reset_stack(); | |
| pos = temp_path = tr069_strdup(path); | |
| while (pos != (temp_path + len)) { | |
| char * c; | |
| *trace_index = tr069_strdup(pos); | |
| c = strchr(*trace_index, '.'); | |
| if (c == NULL) { | |
| // Means path end, so we can find object first | |
| tr069_free(*trace_index); | |
| *trace_index = NULL; | |
| obj = __find_obj(root, &trace[0]); | |
| if (obj == NULL) { | |
| // Failed | |
| TR069_ERR("Failed when try find object for find parameter"); | |
| break; | |
| } | |
| param = __find_param(obj, pos); | |
| break; | |
| } | |
| *c = '\0'; | |
| pos = strchr(pos, '.'); | |
| if(pos){ | |
| pos++; | |
| trace_index++; | |
| deep++; | |
| if (deep >= MAX_TRACE_DEEP) TR069_ERR("Failed! %s:%d", __func__, __LINE__); | |
| }else{ | |
| break; | |
| } | |
| } | |
| tr069_free(temp_path); | |
| // Free all trace data | |
| trace_index = &trace[0]; | |
| while (*trace_index) { | |
| tr069_free(*trace_index); | |
| *trace_index = NULL; | |
| trace_index++; | |
| } | |
| if (!param) TR069_ERR("%s: failed, %s", __func__, path); | |
| return param; | |
| } | |
| static int __walk_obj_and_paramet(struct tr069_obj * root, | |
| struct tr069_instance * instance, walk_obj_paramet_cb callback, struct walk_context * data, int flag) | |
| { | |
| struct tr069_param * paramet; | |
| struct tr069_instance * is; | |
| struct tr069_obj * obj = root; | |
| char temp[16]; | |
| // Walk all object | |
| while (obj && obj->name) { | |
| // Push current object name to stack | |
| TR069_DEBUG("%s: object %s(%s)", __func__, obj->name, | |
| obj->type == TR069OBJ_TYPE_NORMAL ? "normal" : "instance"); | |
| if (data->stack[data->index] == NULL) { | |
| data->stack[data->index] = obj->name; | |
| } else { | |
| data->stack[++data->index] = obj->name; | |
| } | |
| // Callback notify to user | |
| if (callback) callback(obj, NULL, NULL, data, TR069_TYPE_OBJECT); | |
| // Walk all paramet | |
| if (obj->type == TR069OBJ_TYPE_NORMAL) { | |
| paramet = obj->param_list; | |
| while (paramet && paramet->name) { | |
| TR069_DEBUG(" parameter %s", paramet->name); | |
| // Push current parameter name to stack | |
| data->stack[++data->index] = paramet->name; | |
| // Callback notify to user | |
| if (callback) callback(NULL, paramet, instance, data, TR069_TYPE_PARAMETER); | |
| // Pop name | |
| data->stack[data->index--] = NULL; | |
| paramet++; | |
| } | |
| // Walk next object && parameter | |
| if (obj->obj_list) | |
| __walk_obj_and_paramet(obj->obj_list, instance, callback, data, 0); | |
| } else { | |
| int i = 0; | |
| is = obj->instance_list; | |
| if (is) i = ++data->index; | |
| while (is) { | |
| // Push instance ID to stack | |
| TR069_DEBUG(" now %p, next %p", is, is->next); | |
| snprintf(temp, 16, "%d", is->id); | |
| data->stack[i] = temp; | |
| if (is->parent == NULL || | |
| data->instance_stack[data->instance_index] == is->parent->id) { | |
| data->instance_stack[++data->instance_index] = is->id; | |
| // Walk all parameter | |
| paramet = obj->param_list; | |
| while (paramet && paramet->name) { | |
| TR069_DEBUG(" parameter %s", paramet->name); | |
| // Push current parameter name to stack | |
| data->stack[++data->index] = paramet->name; | |
| // Callback notify to user | |
| if (callback) callback(NULL, paramet, is, data, TR069_TYPE_PARAMETER); | |
| // Pop name | |
| data->stack[data->index--] = NULL; | |
| paramet++; | |
| } | |
| if (obj->obj_list) { | |
| __walk_obj_and_paramet(obj->obj_list, is, callback, data, 0); | |
| } | |
| data->instance_stack[data->instance_index--] = -1; | |
| } | |
| is = is->next; | |
| } | |
| if (obj->instance_list) data->stack[data->index--] = NULL; | |
| } | |
| // Pop object name | |
| data->stack[data->index--] = NULL; | |
| if (flag) { | |
| break; // If the flag set, do not continue process next object under the same parent | |
| } else { | |
| obj++; | |
| } | |
| } | |
| return 0; | |
| } | |
| int walk_obj_and_paramet(struct tr069_obj * root, | |
| struct tr069_instance * instance, walk_obj_paramet_cb callback, void * data, int flag) | |
| { | |
| UNUSED(flag); | |
| struct walk_context * context = tr069_malloc(sizeof(struct walk_context)); | |
| if (context == NULL) { | |
| TR069_ERR("Can not malloc memory for walk context..."); | |
| return -1; | |
| } | |
| memset(context, 0, sizeof(struct walk_context)); | |
| context->userdata = data; | |
| __walk_obj_and_paramet(root, instance, callback, context, 1); | |
| TR069_DEBUG("%s: after quit index %d", __func__, context->index); | |
| tr069_free(context); | |
| return 0; | |
| } | |
| const char * rpc_type2string(int type) | |
| { | |
| switch (type) { | |
| case TR069_STRING: | |
| return "xsdstring"; | |
| case TR069_INT: | |
| return "xsdint"; | |
| case TR069_UINT: | |
| return "xsdunsignedInt"; | |
| case TR069_BOOL: | |
| return "xsdboolean"; | |
| case TR069_DATATIME: | |
| return "xsddateTime"; | |
| case TR069_ULONG: | |
| return "xsdunsignedLong"; | |
| case TR069_HEX: | |
| return "xsdhexBinary"; | |
| default: | |
| TR069_DEBUG("type2string with unknow type...\n"); | |
| return ""; | |
| } | |
| } |