summaryrefslogtreecommitdiff
path: root/res/res_pjsip/location.c
diff options
context:
space:
mode:
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;
}