res_pjsip: Updates and adds more PJSIP CLI commands.
[asterisk/asterisk.git] / res / res_pjsip / pjsip_configuration.c
index c21582e..deb374e 100644 (file)
@@ -1168,48 +1168,83 @@ static int ami_show_endpoints(struct mansession *s, const struct message *m)
        return 0;
 }
 
        return 0;
 }
 
-static int populate_channel_container(void *obj, void *arg, int flags) {
+static struct ao2_container *cli_get_endpoint_container(void)
+{
+       RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
+       RAII_VAR(struct ao2_container *, s_container, NULL, ao2_cleanup);
+
+       container = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint",
+               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+       if (!container) {
+               return NULL;
+       }
+
+       s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
+               ast_sorcery_object_id_compare, NULL);
+       if (!s_container) {
+               return NULL;
+       }
+
+       if (ao2_container_dup(s_container, container, 0)) {
+               return NULL;
+       }
+       ao2_ref(s_container, +1);
+       return s_container;
+}
+
+static int populate_channel_container(void *obj, void *arg, int flags)
+{
        struct ast_channel_snapshot *snapshot = obj;
        struct ao2_container *container = arg;
        struct ast_channel_snapshot *snapshot = obj;
        struct ao2_container *container = arg;
-       ao2_link_flags(container, snapshot, OBJ_NOLOCK);
+
+       ao2_link(container, snapshot);
        return 0;
 }
 
        return 0;
 }
 
-static int gather_endpoint_channels(void *obj, void *arg, int flags) {
+static int cli_channel_iterator(const void *container, ao2_callback_fn callback, void *args)
+{
+       const struct ast_sip_endpoint *array = container;
+
+       return ast_sip_for_each_channel(array, callback, args);
+}
+
+static int gather_endpoint_channels(void *obj, void *arg, int flags)
+{
        struct ast_sip_endpoint *endpoint = obj;
        struct ao2_container *channels = arg;
        struct ast_sip_endpoint *endpoint = obj;
        struct ao2_container *channels = arg;
+
        ast_sip_for_each_channel(endpoint, populate_channel_container, channels);
        return 0;
 }
 
        ast_sip_for_each_channel(endpoint, populate_channel_container, channels);
        return 0;
 }
 
-static struct ao2_container *cli_get_channel_container(struct ast_sorcery *sip_sorcery)
+static int cli_channel_compare(const void *left, const void *right, int flags)
 {
 {
-       RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
-       RAII_VAR(struct ao2_container *, s_parent_container, NULL, ao2_cleanup);
-       struct ao2_container *child_container;
+       const struct ast_channel_snapshot *left_snap = left;
+       const struct ast_channel_snapshot *right_snap = right;
 
 
-       parent_container = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint",
-                               AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
-       if (!parent_container) {
-               return NULL;
+       if (!left_snap || !right_snap) {
+               return 0;
        }
        }
+       return strcmp(left_snap->name, right_snap->name);
+}
 
 
-       s_parent_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, &ast_sorcery_object_id_compare, NULL);
-       if (!s_parent_container) {
-               return NULL;
-       }
+static struct ao2_container *cli_get_channel_container(void)
+{
+       RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
+       RAII_VAR(struct ao2_container *, child_container, NULL, ao2_cleanup);
 
 
-       if (ao2_container_dup(s_parent_container, parent_container, OBJ_ORDER_ASCENDING)) {
+       parent_container = cli_get_endpoint_container();
+       if (!parent_container) {
                return NULL;
        }
                return NULL;
        }
-
-       child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
+       child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
+               cli_channel_compare, NULL);
        if (!child_container) {
                return NULL;
        }
 
        if (!child_container) {
                return NULL;
        }
 
-       ao2_callback(s_parent_container, OBJ_NODATA, gather_endpoint_channels, child_container);
-
+       ao2_callback(parent_container, OBJ_NODATA, gather_endpoint_channels, child_container);
+       ao2_ref(child_container, +1);
        return child_container;
 }
 
        return child_container;
 }
 
@@ -1236,7 +1271,8 @@ static int cli_print_channel_header(void *obj, void *arg, int flags)
        return 0;
 }
 
        return 0;
 }
 
-static int cli_print_channel_body(void *obj, void *arg, int flags) {
+static int cli_print_channel_body(void *obj, void *arg, int flags)
+{
        struct ast_channel_snapshot *snapshot = obj;
        struct ast_sip_cli_context *context = arg;
        struct timeval current_time;
        struct ast_channel_snapshot *snapshot = obj;
        struct ast_sip_cli_context *context = arg;
        struct timeval current_time;
@@ -1272,7 +1308,8 @@ static int cli_print_channel_body(void *obj, void *arg, int flags) {
        indent = CLI_INDENT_TO_SPACES(context->indent_level);
        flexwidth = CLI_LAST_TABSTOP - indent - 25;
 
        indent = CLI_INDENT_TO_SPACES(context->indent_level);
        flexwidth = CLI_LAST_TABSTOP - indent - 25;
 
-       ast_str_append(&context->output_buffer, 0, "%*s:  %-7s  Exten: %-*.*s  CLCID: \"%s\" <%s>\n",
+       ast_str_append(&context->output_buffer, 0,
+               "%*s:  %-7s  Exten: %-*.*s  CLCID: \"%s\" <%s>\n",
                indent, "Codec",
                snapshot->nativeformats,
                flexwidth, flexwidth,
                indent, "Codec",
                snapshot->nativeformats,
                flexwidth, flexwidth,
@@ -1281,58 +1318,76 @@ static int cli_print_channel_body(void *obj, void *arg, int flags) {
                snapshot->connected_number
                );
        context->indent_level--;
                snapshot->connected_number
                );
        context->indent_level--;
+       if (context->indent_level == 0) {
+               ast_str_append(&context->output_buffer, 0, "\n");
+       }
+
        return 0;
 }
 
        return 0;
 }
 
-static struct ao2_container *cli_get_endpoint_container(struct ast_sorcery *sip_sorcery)
+static int cli_endpoint_iterator(const void *container, ao2_callback_fn callback,
+       void *args)
 {
 {
-       return ast_sip_get_endpoints();
+       struct ao2_container *ao2container = (struct ao2_container *) container;
+
+       ao2_callback(ao2container, OBJ_NODATA, callback, args);
+       return 0;
+}
+
+static void print_child_header(char *type, struct ast_sip_cli_context *context)
+{
+       struct ast_sip_cli_formatter_entry *formatter_entry;
+
+       formatter_entry = ast_sip_lookup_cli_formatter(type);
+       if (formatter_entry && formatter_entry->print_header) {
+               formatter_entry->print_header(NULL, context, 0);
+       }
 }
 
 static int cli_print_endpoint_header(void *obj, void *arg, int flags)
 {
        struct ast_sip_cli_context *context = arg;
 }
 
 static int cli_print_endpoint_header(void *obj, void *arg, int flags)
 {
        struct ast_sip_cli_context *context = arg;
-       struct ast_sip_cli_formatter_entry *formatter_entry;
 
        if (!context->output_buffer) {
                return -1;
        }
        ast_str_append(&context->output_buffer, 0,
 
        if (!context->output_buffer) {
                return -1;
        }
        ast_str_append(&context->output_buffer, 0,
-                       " <Endpoint/CID................................................>  <State.....>  <Channels.>\n");
+                       " Endpoint:  <Endpoint/CID.....................................>  <State.....>  <Channels.>\n");
 
        if (context->recurse) {
                context->indent_level++;
 
        if (context->recurse) {
                context->indent_level++;
-               formatter_entry = ast_sip_lookup_cli_formatter("auth");
-               if (formatter_entry) {
-                       formatter_entry->print_header(NULL, context, 0);
-               }
-               formatter_entry = ast_sip_lookup_cli_formatter("aor");
-               if (formatter_entry) {
-                       formatter_entry->print_header(NULL, context, 0);
-               }
-               formatter_entry = ast_sip_lookup_cli_formatter("identify");
-               if (formatter_entry) {
-                       formatter_entry->print_header(NULL, context, 0);
-               }
-               formatter_entry = ast_sip_lookup_cli_formatter("channel");
-               if (formatter_entry) {
-                       formatter_entry->print_header(NULL, context, 0);
-               }
+               print_child_header("auth", context);
+               print_child_header("aor", context);
+               print_child_header("transport", context);
+               print_child_header("identify", context);
+               print_child_header("channel", context);
                context->indent_level--;
        }
        return 0;
 }
 
                context->indent_level--;
        }
        return 0;
 }
 
-static int cli_print_endpoint_body(void *obj, void *arg, int flags) {
+static void print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
+{
+       struct ast_sip_cli_formatter_entry *formatter_entry;
+
+       formatter_entry = ast_sip_lookup_cli_formatter(type);
+       if (formatter_entry && formatter_entry->print_body && formatter_entry->iterator) {
+               formatter_entry->iterator(obj, formatter_entry->print_body, context);
+       }
+}
+
+static int cli_print_endpoint_body(void *obj, void *arg, int flags)
+{
        struct ast_sip_endpoint *endpoint = obj;
        RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
        struct ast_sip_cli_context *context = arg;
        const char *id = ast_sorcery_object_get_id(endpoint);
        struct ast_sip_endpoint *endpoint = obj;
        RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
        struct ast_sip_cli_context *context = arg;
        const char *id = ast_sorcery_object_get_id(endpoint);
-       struct ast_sip_cli_formatter_entry *formatter_entry;
        char *print_name = NULL;
        int print_name_len;
        char *number = S_COR(endpoint->id.self.number.valid,
                endpoint->id.self.number.str, NULL);
        char *print_name = NULL;
        int print_name_len;
        char *number = S_COR(endpoint->id.self.number.valid,
                endpoint->id.self.number.str, NULL);
+       int indent;
+       int flexwidth;
 
        if (!context->output_buffer) {
                return -1;
 
        if (!context->output_buffer) {
                return -1;
@@ -1348,8 +1403,12 @@ static int cli_print_endpoint_body(void *obj, void *arg, int flags) {
                snprintf(print_name, print_name_len, "%s/%s", id, number);
        }
 
                snprintf(print_name, print_name_len, "%s/%s", id, number);
        }
 
-       ast_str_append(&context->output_buffer, 0, " %-62s  %-12.12s  %d of %.0f\n",
-               print_name ? print_name : id,
+       indent = CLI_INDENT_TO_SPACES(context->indent_level);
+       flexwidth = CLI_LAST_TABSTOP - indent - 2;
+
+       ast_str_append(&context->output_buffer, 0, "%*s:  %-*.*s  %-12.12s  %d of %.0f\n",
+               indent, "Endpoint",
+               flexwidth, flexwidth, print_name ? print_name : id,
                ast_sip_get_device_state(endpoint),
                endpoint_snapshot->num_channels,
                (double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
                ast_sip_get_device_state(endpoint),
                endpoint_snapshot->num_channels,
                (double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
@@ -1359,23 +1418,21 @@ static int cli_print_endpoint_body(void *obj, void *arg, int flags) {
        if (context->recurse) {
                context->indent_level++;
 
        if (context->recurse) {
                context->indent_level++;
 
-               formatter_entry = ast_sip_lookup_cli_formatter("auth");
-               if (formatter_entry) {
-                       context->auth_direction = "Out";
-                       ast_sip_for_each_auth(&endpoint->outbound_auths, formatter_entry->print_body, context);
-                       context->auth_direction = "In";
-                       ast_sip_for_each_auth(&endpoint->inbound_auths, formatter_entry->print_body, context);
-               }
-               formatter_entry = ast_sip_lookup_cli_formatter("aor");
-               if (formatter_entry) {
-                       ast_sip_for_each_aor(endpoint->aors, formatter_entry->print_body, context);
-               }
-               formatter_entry = ast_sip_lookup_cli_formatter("channel");
-               if (formatter_entry) {
-                       ast_sip_for_each_channel(endpoint, formatter_entry->print_body, context);
-               }
+               context->auth_direction = "Out";
+               print_child_body("auth", &endpoint->outbound_auths, context);
+               context->auth_direction = "In";
+               print_child_body("auth", &endpoint->inbound_auths, context);
+
+               print_child_body("aor", endpoint->aors, context);
+               print_child_body("transport", endpoint, context);
+               print_child_body("identify", endpoint, context);
+               print_child_body("channel", endpoint, context);
 
                context->indent_level--;
 
                context->indent_level--;
+
+               if (context->indent_level == 0) {
+                       ast_str_append(&context->output_buffer, 0, "\n");
+               }
        }
 
        if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
        }
 
        if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
@@ -1391,6 +1448,8 @@ static struct ast_sip_cli_formatter_entry cli_channel_formatter = {
        .print_header = cli_print_channel_header,
        .print_body = cli_print_channel_body,
        .get_container = cli_get_channel_container,
        .print_header = cli_print_channel_header,
        .print_body = cli_print_channel_body,
        .get_container = cli_get_channel_container,
+       .iterator = cli_channel_iterator,
+       .comparator = cli_channel_compare,
 };
 
 static struct ast_sip_cli_formatter_entry cli_endpoint_formatter = {
 };
 
 static struct ast_sip_cli_formatter_entry cli_endpoint_formatter = {
@@ -1398,8 +1457,33 @@ static struct ast_sip_cli_formatter_entry cli_endpoint_formatter = {
        .print_header = cli_print_endpoint_header,
        .print_body = cli_print_endpoint_body,
        .get_container = cli_get_endpoint_container,
        .print_header = cli_print_endpoint_header,
        .print_body = cli_print_endpoint_body,
        .get_container = cli_get_endpoint_container,
+       .iterator = cli_endpoint_iterator,
+       .comparator = ast_sorcery_object_id_compare,
 };
 
 };
 
+static struct ast_cli_entry cli_commands[] = {
+       AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
+               .command = "pjsip list channels",
+               .usage = "Usage: pjsip list channels\n"
+                                "       List the active PJSIP channels\n"),
+       AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
+               .command = "pjsip show channels",
+               .usage = "Usage: pjsip show channels\n"
+                                "       List(detailed) the active PJSIP channels\n"),
+
+       AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
+               .command = "pjsip list endpoints",
+               .usage = "Usage: pjsip list endpoints\n"
+                                "       List the configured PJSIP endpoints\n"),
+       AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoints",
+               .command = "pjsip show endpoints",
+               .usage = "Usage: pjsip show endpoints\n"
+                                "       List(detailed) the configured PJSIP endpoints\n"),
+       AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoint",
+               .command = "pjsip show endpoint",
+               .usage = "Usage: pjsip show endpoint <id>\n"
+                                "       Show the configured PJSIP endpoint\n"),
+};
 
 int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info)
 {
 
 int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info)
 {
@@ -1420,12 +1504,9 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
 
        ast_sorcery_apply_config(sip_sorcery, "res_pjsip");
 
 
        ast_sorcery_apply_config(sip_sorcery, "res_pjsip");
 
-       ast_sip_initialize_cli(sip_sorcery);
-       ast_sip_register_cli_formatter(&cli_channel_formatter);
-       ast_sip_register_cli_formatter(&cli_endpoint_formatter);
+       ast_sip_initialize_cli();
 
 
-
-       if (ast_sip_initialize_sorcery_auth(sip_sorcery)) {
+       if (ast_sip_initialize_sorcery_auth()) {
                ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
@@ -1527,21 +1608,21 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, 0, 0);
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, 0, 0);
 
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, 0, 0);
        ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, 0, 0);
 
-       if (ast_sip_initialize_sorcery_transport(sip_sorcery)) {
+       if (ast_sip_initialize_sorcery_transport()) {
                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
                ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
-       if (ast_sip_initialize_sorcery_location(sip_sorcery)) {
+       if (ast_sip_initialize_sorcery_location()) {
                ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
                ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
-       if (ast_sip_initialize_sorcery_qualify(sip_sorcery)) {
+       if (ast_sip_initialize_sorcery_qualify()) {
                ast_log(LOG_ERROR, "Failed to register SIP qualify support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                ast_log(LOG_ERROR, "Failed to register SIP qualify support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
@@ -1550,20 +1631,24 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
 
        ast_sorcery_observer_add(sip_sorcery, "contact", &state_contact_observer);
 
 
        ast_sorcery_observer_add(sip_sorcery, "contact", &state_contact_observer);
 
-       if (ast_sip_initialize_sorcery_domain_alias(sip_sorcery)) {
+       if (ast_sip_initialize_sorcery_domain_alias()) {
                ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
                ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
-       if (ast_sip_initialize_sorcery_global(sip_sorcery)) {
+       if (ast_sip_initialize_sorcery_global()) {
                ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
                ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
                ast_sorcery_unref(sip_sorcery);
                sip_sorcery = NULL;
                return -1;
        }
 
+       ast_sip_register_cli_formatter(&cli_channel_formatter);
+       ast_sip_register_cli_formatter(&cli_endpoint_formatter);
+       ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
+
        ast_sorcery_load(sip_sorcery);
 
        return 0;
        ast_sorcery_load(sip_sorcery);
 
        return 0;
@@ -1571,6 +1656,10 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
 
 void ast_res_pjsip_destroy_configuration(void)
 {
 
 void ast_res_pjsip_destroy_configuration(void)
 {
+       ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
+       ast_sip_destroy_sorcery_location();
+       ast_sip_destroy_sorcery_auth();
+       ast_sip_destroy_sorcery_transport();
        ast_manager_unregister(AMI_SHOW_ENDPOINT);
        ast_manager_unregister(AMI_SHOW_ENDPOINTS);
        ast_sorcery_unref(sip_sorcery);
        ast_manager_unregister(AMI_SHOW_ENDPOINT);
        ast_manager_unregister(AMI_SHOW_ENDPOINTS);
        ast_sorcery_unref(sip_sorcery);