summaryrefslogtreecommitdiff
path: root/res/res_pjsip/location.c
diff options
context:
space:
mode:
authorMatthew Jordan <mjordan@digium.com>2013-12-20 21:32:13 +0000
committerMatthew Jordan <mjordan@digium.com>2013-12-20 21:32:13 +0000
commitb172d369c4057cddad18c0d6b1100233c07ebbd7 (patch)
tree0665c20e48161773916473a951bac27315d26d2b /res/res_pjsip/location.c
parenta0c288bb23164c6ff91019172980c8aff6fd8c8d (diff)
res_pjsip: Add PJSIP CLI commands
Implements the following cli commands: pjsip list aors pjsip list auths pjsip list channels pjsip list contacts pjsip list endpoints pjsip show aor(s) pjsip show auth(s) pjsip show channels pjsip show endpoint(s) Also... Minor modifications made to the AMI command implementations to facilitate reuse. New function ast_variable_list_sort added to config.c and config.h to implement variable list sorting. (issue ASTERISK-22610) patches: pjsip_cli_v2.patch uploaded by george.joseph (License 6322) ........ Merged revisions 404480 from http://svn.asterisk.org/svn/asterisk/branches/12 git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404507 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_pjsip/location.c')
-rw-r--r--res/res_pjsip/location.c245
1 files changed, 228 insertions, 17 deletions
diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c
index 52f69cfd8..3bd4dea10 100644
--- a/res/res_pjsip/location.c
+++ b/res/res_pjsip/location.c
@@ -25,6 +25,7 @@
#include "asterisk/astobj2.h"
#include "asterisk/sorcery.h"
#include "include/res_pjsip_private.h"
+#include "asterisk/res_pjsip_cli.h"
/*! \brief Destructor for AOR */
static void aor_destroy(void *obj)
@@ -284,12 +285,37 @@ int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
return 0;
}
-int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
- on_contact_t on_contact, void *arg)
+static void destroy_contact_pair(void *obj)
+{
+ struct ast_sip_aor_contact_pair *pair = obj;
+ ao2_cleanup(pair->aor);
+ ao2_cleanup(pair->contact);
+}
+
+static struct ast_sip_aor_contact_pair *create_contact_pair(
+ struct ast_sip_aor *aor, struct ast_sip_contact *contact)
+{
+ struct ast_sip_aor_contact_pair *pair = ao2_alloc(
+ sizeof(*pair), destroy_contact_pair);
+
+ if (!pair) {
+ return NULL;
+ }
+
+ pair->aor = aor;
+ pair->contact = contact;
+
+ ao2_ref(pair->aor, +1);
+ ao2_ref(pair->contact, +1);
+
+ return pair;
+}
+
+int ast_sip_for_each_contact(struct ast_sip_aor *aor,
+ ao2_callback_fn on_contact, void *arg)
{
RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
struct ast_sip_contact *contact;
- int num;
struct ao2_iterator i;
if (!on_contact ||
@@ -297,13 +323,13 @@ int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
return 0;
}
- num = ao2_container_count(contacts);
i = ao2_iterator_init(contacts, 0);
while ((contact = ao2_iterator_next(&i))) {
- int res = on_contact(aor, contact, --num == 0, arg);
+ int res;
+ RAII_VAR(struct ast_sip_aor_contact_pair *,
+ acp, create_contact_pair(aor, contact), ao2_cleanup);
- ao2_ref(contact, -1);
- if (res) {
+ if (!acp || (res = on_contact(acp, arg, 0))) {
ao2_iterator_destroy(&i);
return -1;
}
@@ -312,18 +338,13 @@ int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
return 0;
}
-int ast_sip_contact_to_str(const struct ast_sip_aor *aor,
- const struct ast_sip_contact *contact,
- int last, void *arg)
+int ast_sip_contact_to_str(void *object, void *arg, int flags)
{
+ struct ast_sip_aor_contact_pair *acp = object;
struct ast_str **buf = arg;
- ast_str_append(buf, 0, "%s/%s",
- ast_sorcery_object_get_id(aor), contact->uri);
-
- if (!last) {
- ast_str_append(buf, 0, ",");
- }
+ ast_str_append(buf, 0, "%s/%s,",
+ ast_sorcery_object_get_id(acp->aor), acp->contact->uri);
return 0;
}
@@ -335,7 +356,7 @@ static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf)
static int format_ami_aor_handler(void *obj, void *arg, int flags)
{
- const struct ast_sip_aor *aor = obj;
+ struct ast_sip_aor *aor = obj;
struct ast_sip_ami *ami = arg;
const struct ast_sip_endpoint *endpoint = ami->arg;
RAII_VAR(struct ast_str *, buf,
@@ -352,6 +373,7 @@ static int format_ami_aor_handler(void *obj, void *arg, int flags)
sip_aor_to_ami(aor, &buf);
ast_str_append(&buf, 0, "Contacts: ");
ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &buf);
+ ast_str_truncate(buf, -1);
ast_str_append(&buf, 0, "\r\n");
num = ao2_container_count(contacts);
@@ -377,6 +399,193 @@ struct ast_sip_endpoint_formatter endpoint_aor_formatter = {
.format_ami = format_ami_endpoint_aor
};
+static int populate_contact_container(void *obj, void *arg, int flags)
+{
+ struct ast_sip_aor_contact_pair *acp = obj;
+ struct ao2_container *container = arg;
+ ao2_link_flags(container, acp, OBJ_NOLOCK);
+ return 0;
+}
+
+static int gather_aor_channels(void *obj, void *arg, int flags)
+{
+ struct ast_sip_aor *aor = obj;
+ struct ao2_container *container = arg;
+ ast_sip_for_each_contact(aor, populate_contact_container, container);
+ return 0;
+}
+
+static struct ao2_container *cli_get_contact_container(struct ast_sorcery *sip_sorcery)
+{
+ 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;
+
+ parent_container = ast_sorcery_retrieve_by_fields(sip_sorcery, "aor",
+ AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+ if (!parent_container) {
+ return NULL;
+ }
+
+ 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;
+ }
+
+ ao2_container_dup(s_parent_container, parent_container, OBJ_ORDER_ASCENDING);
+
+ child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
+ if (!child_container) {
+ return NULL;
+ }
+
+ ao2_callback(s_parent_container, OBJ_NODATA, gather_aor_channels, child_container);
+
+ return child_container;
+}
+
+
+static int cli_print_contact_header(void *obj, void *arg, int flags)
+{
+ struct ast_sip_cli_context *context = arg;
+ int indent = CLI_INDENT_TO_SPACES(context->indent_level);
+ int filler = CLI_LAST_TABSTOP - indent - 18;
+
+ if (!context->output_buffer) {
+ return -1;
+ }
+ ast_str_append(&context->output_buffer, 0,
+ "%*s: <Aor/ContactUri%*.*s> <Status....> <RTT(ms)..>\n",
+ indent, "Contact", filler, filler, CLI_HEADER_FILLER);
+
+ return 0;
+}
+
+static int cli_print_contact_body(void *obj, void *arg, int flags)
+{
+ struct ast_sip_aor_contact_pair *acp = obj;
+ struct ast_sip_cli_context *context = arg;
+ char *print_name = NULL;
+ int print_name_len;
+ int indent;
+ int flexwidth;
+
+ RAII_VAR(struct ast_sip_contact_status *, status,
+ ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(acp->contact)),
+ ao2_cleanup);
+
+ if (!context->output_buffer) {
+ return -1;
+ }
+
+ print_name_len = strlen(ast_sorcery_object_get_id(acp->aor))
+ + strlen(acp->contact->uri) + 2;
+ if (!(print_name = alloca(print_name_len))) {
+ return -1;
+ }
+ snprintf(print_name, print_name_len, "%s/%s",
+ ast_sorcery_object_get_id(acp->aor), acp->contact->uri);
+
+ 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 %11.3f\n",
+ indent,
+ "Contact",
+ flexwidth, flexwidth,
+ print_name,
+ (status ? (status->status == AVAILABLE ? "Avail" : "Unavail") : "Unknown"),
+ (status ? ((long long) status->rtt) / 1000.0 : NAN));
+
+ return 0;
+}
+
+static struct ao2_container *cli_get_aor_container(struct ast_sorcery *sip_sorcery)
+{
+ return ast_sorcery_retrieve_by_fields(sip_sorcery, "aor",
+ AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+}
+
+static int cli_print_aor_header(void *obj, void *arg, int flags)
+{
+ struct ast_sip_cli_context *context = arg;
+ struct ast_sip_cli_formatter_entry *formatter_entry;
+
+ int indent = CLI_INDENT_TO_SPACES(context->indent_level);
+ int filler = CLI_LAST_TABSTOP - indent - 7;
+
+ if (!context->output_buffer) {
+ return -1;
+ }
+ ast_str_append(&context->output_buffer, 0,
+ "%*s: <Aor%*.*s> <MaxContact>\n",
+ indent, "Aor", filler, filler, CLI_HEADER_FILLER);
+
+ if (context->recurse) {
+ context->indent_level++;
+ formatter_entry = ast_sip_lookup_cli_formatter("contact");
+ if (formatter_entry) {
+ formatter_entry->print_header(NULL, context, 0);
+ }
+ context->indent_level--;
+ }
+ return 0;
+}
+
+static int cli_print_aor_body(void *obj, void *arg, int flags)
+{
+ struct ast_sip_aor *aor = obj;
+ struct ast_sip_cli_context *context = arg;
+ struct ast_sip_cli_formatter_entry *formatter_entry;
+ int indent;
+ int flexwidth;
+
+ if (!context->output_buffer) {
+ return -1;
+ }
+
+ context->current_aor = aor;
+
+ indent = CLI_INDENT_TO_SPACES(context->indent_level);
+ flexwidth = CLI_LAST_TABSTOP - indent - 12;
+
+ ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %12d\n",
+ indent,
+ "Aor",
+ flexwidth, flexwidth,
+ ast_sorcery_object_get_id(aor), aor->max_contacts);
+
+ if (context->recurse) {
+ context->indent_level++;
+ formatter_entry = ast_sip_lookup_cli_formatter("contact");
+ if (formatter_entry) {
+ ast_sip_for_each_contact(aor, formatter_entry->print_body, context);
+ }
+ context->indent_level--;
+ }
+
+ if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
+ ast_str_append(&context->output_buffer, 0, "\n");
+ ast_sip_cli_print_sorcery_objectset(aor, context, 0);
+ }
+
+ return 0;
+}
+
+static struct ast_sip_cli_formatter_entry cli_contact_formatter = {
+ .name = "contact",
+ .print_header = cli_print_contact_header,
+ .print_body = cli_print_contact_body,
+ .get_container = cli_get_contact_container,
+};
+
+static struct ast_sip_cli_formatter_entry cli_aor_formatter = {
+ .name = "aor",
+ .print_header = cli_print_aor_header,
+ .print_body = cli_print_aor_body,
+ .get_container = cli_get_aor_container,
+};
+
/*! \brief Initialize sorcery with location support */
int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery)
{
@@ -408,6 +617,8 @@ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery)
ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
ast_sip_register_endpoint_formatter(&endpoint_aor_formatter);
+ ast_sip_register_cli_formatter(&cli_contact_formatter);
+ ast_sip_register_cli_formatter(&cli_aor_formatter);
return 0;
}