Skip to content
Snippets Groups Projects
data.c 80.2 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	}
    
    	ast_str_reset(current_path);
    	if (path) {
    		ast_str_set(&current_path, 0, "%s.%s", ast_str_buffer(path), name);
    	} else {
    		ast_str_set(&current_path, 0, "%s", name);
    	}
    
    	i = ao2_iterator_init(container, 0);
    	while ((node = ao2_iterator_next(&i))) {
    		/* terminal node, print it. */
    		if (node->type != AST_DATA_CONTAINER) {
    			astman_append(s, "%d-%s.%s", id, ast_str_buffer(current_path),
    					node->name);
    		}
    		switch (node->type) {
    		case AST_DATA_CONTAINER:
    			data_result_manager_output(s, node->name, node->children, current_path, ++current_id);
    			break;
    		case AST_DATA_INTEGER:
    			astman_append(s, ": %d\r\n", node->payload.sint);
    			break;
    
    		case AST_DATA_TIMESTAMP:
    		case AST_DATA_SECONDS:
    		case AST_DATA_MILLISECONDS:
    
    		case AST_DATA_UNSIGNED_INTEGER:
    			astman_append(s, ": %u\r\n", node->payload.uint);
    			break;
    
    		case AST_DATA_PASSWORD:
    			astman_append(s, ": %s\r\n", node->payload.str);
    			break;
    
    		case AST_DATA_STRING:
    			astman_append(s, ": %s\r\n", node->payload.str);
    			break;
    
    		case AST_DATA_CHARACTER:
    			astman_append(s, ": %c\r\n", node->payload.character);
    			break;
    
    		case AST_DATA_IPADDR:
    			astman_append(s, ": %s\r\n", ast_inet_ntoa(node->payload.ipaddr));
    			break;
    		case AST_DATA_POINTER:
    			break;
    		case AST_DATA_DOUBLE:
    			astman_append(s, ": %f\r\n", node->payload.dbl);
    			break;
    		case AST_DATA_BOOLEAN:
    			astman_append(s, ": %s\r\n",
    				(node->payload.boolean ? "True" : "False"));
    			break;
    		}
    
    		ao2_ref(node, -1);
    	}
    	ao2_iterator_destroy(&i);
    
    	ast_free(current_path);
    }
    
    /*!
     * \internal
     * \brief Implements the manager action: "DataGet".
     */
    static int manager_data_get(struct mansession *s, const struct message *m)
    {
    	const char *path = astman_get_header(m, "Path");
    	const char *search = astman_get_header(m, "Search");
    	const char *filter = astman_get_header(m, "Filter");
    	const char *id = astman_get_header(m, "ActionID");
    	struct ast_data *res;
    	struct ast_data_query query = {
    		.version = AST_DATA_QUERY_VERSION,
    		.path = (char *) path,
    		.search = (char *) search,
    		.filter = (char *) filter,
    	};
    
    	if (ast_strlen_zero(path)) {
    		astman_send_error(s, m, "'Path' parameter not specified");
    		return 0;
    	}
    
    	res = ast_data_get(&query);
    	if (!res) {
    		astman_send_error(s, m, "No data returned");
    		return 0;
    	}
    
    	astman_append(s, "Event: DataGet Tree\r\n");
    	if (!ast_strlen_zero(id)) {
    		astman_append(s, "ActionID: %s\r\n", id);
    	}
    	data_result_manager_output(s, res->name, res->children, NULL, 0);
    	astman_append(s, "\r\n");
    
    	ast_data_free(res);
    
    	return RESULT_SUCCESS;
    }
    
    
    static int data_add_codec(struct ast_data *codecs, struct ast_format *format) {
    	struct ast_data *codec;
    	struct ast_codec *tmp;
    
    	tmp = ast_codec_get_by_id(ast_format_get_codec_id(format));
    	if (!tmp) {
    		return -1;
    	}
    
    	codec = ast_data_add_node(codecs, "codec");
    	if (!codec) {
    		ao2_ref(tmp, -1);
    		return -1;
    	}
    
    	ast_data_add_str(codec, "name", tmp->name);
    	ast_data_add_int(codec, "samplespersecond", tmp->sample_rate);
    	ast_data_add_str(codec, "description", tmp->description);
    	ast_data_add_int(codec, "frame_length", tmp->minimum_bytes);
    	ao2_ref(tmp, -1);
    
    	return 0;
    }
    
    
    int ast_data_add_codec(struct ast_data *root, const char *node_name, struct ast_format *format)
    
    
    	codecs = ast_data_add_node(root, node_name);
    	if (!codecs) {
    		return -1;
    	}
    
    	return data_add_codec(codecs, format);
    
    }
    
    int ast_data_add_codecs(struct ast_data *root, const char *node_name, struct ast_format_cap *cap)
    {
    
    	struct ast_data *codecs;
    	size_t i;
    	size_t count;
    
    
    	codecs = ast_data_add_node(root, node_name);
    	if (!codecs) {
    		return -1;
    	}
    
    		struct ast_format *fmt;
    
    		fmt = ast_format_cap_get_format(cap, i);
    		if (!fmt) {
    			return -1;
    
    
    		if (data_add_codec(codecs, fmt)) {
    			ao2_ref(fmt, -1);
    			return -1;
    		}
    
    		ao2_ref(fmt, -1);
    
    #ifdef TEST_FRAMEWORK
    
    /*!
     * \internal
     * \brief Structure used to test how to add a complete structure,
     *        and how to compare it.
     */
    struct test_structure {
    	int a_int;
    	unsigned int b_bool:1;
    	char *c_str;
    	unsigned int a_uint;
    };
    
    /*!
     * \internal
     * \brief test_structure mapping.
     */
    #define DATA_EXPORT_TEST_STRUCTURE(MEMBER)                              \
    	MEMBER(test_structure, a_int, AST_DATA_INTEGER)                 \
    	MEMBER(test_structure, b_bool, AST_DATA_BOOLEAN)                \
    	MEMBER(test_structure, c_str, AST_DATA_STRING)                  \
    	MEMBER(test_structure, a_uint, AST_DATA_UNSIGNED_INTEGER)
    
    AST_DATA_STRUCTURE(test_structure, DATA_EXPORT_TEST_STRUCTURE);
    
    /*!
     * \internal
     * \brief Callback implementation.
     */
    static int test_data_full_provider(const struct ast_data_search *search,
    		struct ast_data *root)
    {
    	struct ast_data *test_structure;
    	struct test_structure local_test_structure = {
    		.a_int = 10,
    		.b_bool = 1,
    		.c_str = "test string",
    		.a_uint = 20
    	};
    
    	test_structure = ast_data_add_node(root, "test_structure");
    	if (!test_structure) {
    		ast_debug(1, "Internal data api error\n");
    		return 0;
    	}
    
    	/* add the complete structure. */
    	ast_data_add_structure(test_structure, test_structure, &local_test_structure);
    
    
    	if (!ast_data_search_match(search, test_structure)) {
    		ast_data_remove_node(root, test_structure);
    	}
    
    
    	return 0;
    }
    
    /*!
     * \internal
     * \brief Handler definition for the full provider.
     */
    static const struct ast_data_handler full_provider = {
    	.version = AST_DATA_HANDLER_VERSION,
    	.get = test_data_full_provider
    };
    
    /*!
     * \internal
     * \brief Structure used to define multiple providers at once.
     */
    static const struct ast_data_entry test_providers[] = {
    	AST_DATA_ENTRY("test/node1/node11/node111", &full_provider)
    };
    
    AST_TEST_DEFINE(test_data_get)
    {
    	struct ast_data *res, *node;
    	struct ast_data_iterator *i;
    	struct ast_data_query query = {
    		.version = AST_DATA_QUERY_VERSION,
    		.path = "test/node1/node11/node111",
    		.search = "node111/test_structure/a_int=10",
    		.filter = "node111/test_structure/a*int"
    	};
    
    	switch (cmd) {
    	case TEST_INIT:
    		info->name = "data_test";
    
    		info->summary = "Data API unit test";
    		info->description =
    			"Tests whether data API get implementation works as expected.";
    		return AST_TEST_NOT_RUN;
    	case TEST_EXECUTE:
    		break;
    	}
    
    	ast_data_register_multiple_core(test_providers, ARRAY_LEN(test_providers));
    
    	res = ast_data_get(&query);
    	if (!res) {
    		ast_test_status_update(test, "Unable to get tree.");
    		ast_data_unregister("test/node1/node11/node111");
    		return AST_TEST_FAIL;
    	}
    
    	/* initiate the iterator and check for errors. */
    	i = ast_data_iterator_init(res, "test_structure/");
    	if (!i) {
    		ast_test_status_update(test, "Unable to initiate the iterator.");
    		ast_data_free(res);
    		ast_data_unregister("test/node1/node11/node111");
    		return AST_TEST_FAIL;
    	}
    
    	/* walk the returned nodes. */
    	while ((node = ast_data_iterator_next(i))) {
    		if (!strcmp(ast_data_retrieve_name(node), "a_int")) {
    			if (ast_data_retrieve_int(node, "/") != 10) {
    				ast_data_iterator_end(i);
    				ast_data_free(res);
    				ast_data_unregister("test/node1/node11/node111");
    				return AST_TEST_FAIL;
    			}
    		} else if (!strcmp(ast_data_retrieve_name(node), "a_uint")) {
    			if (ast_data_retrieve_uint(node, "/") != 20) {
    				ast_data_iterator_end(i);
    				ast_data_free(res);
    				ast_data_unregister("test/node1/node11/node111");
    				return AST_TEST_FAIL;
    			}
    		}
    	}
    
    	/* finish the iterator. */
    	ast_data_iterator_end(i);
    
    	ast_data_free(res);
    
    	ast_data_unregister("test/node1/node11/node111");
    
    	return AST_TEST_PASS;
    }
    
    #endif
    
    
    Richard Mudgett's avatar
    Richard Mudgett committed
    /*!
     * \internal
     * \brief Clean up resources on Asterisk shutdown
     */
    
    static void data_shutdown(void)
    {
    	ast_manager_unregister("DataGet");
    
    	ast_cli_unregister_multiple(cli_data, ARRAY_LEN(cli_data));
    
    	ao2_t_ref(root_data.container, -1, "Unref root_data.container in data_shutdown");
    
    	root_data.container = NULL;
    
    	ast_rwlock_destroy(&root_data.lock);
    
    	AST_TEST_UNREGISTER(test_data_get);
    
    int ast_data_init(void)
    {
    	int res = 0;
    
    	ast_rwlock_init(&root_data.lock);
    
    	if (!(root_data.container = ao2_container_alloc(NUM_DATA_NODE_BUCKETS,
    		data_provider_hash, data_provider_cmp))) {
    		return -1;
    	}
    
    	res |= ast_cli_register_multiple(cli_data, ARRAY_LEN(cli_data));
    
    
    	res |= ast_manager_register_xml_core("DataGet", 0, manager_data_get);
    
    
    	AST_TEST_REGISTER(test_data_get);
    
    
    	ast_register_cleanup(data_shutdown);