diff options
Diffstat (limited to 'res/res_pjsip/location.c')
-rw-r--r-- | res/res_pjsip/location.c | 245 |
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; } |