pjsip_cli: Create pjsip show channel and contact, and general cli code cleanup.

Created the 'pjsip show channel' and 'pjsip show contact' commands.
Refactored out the hated ast_hashtab.  Replaced with ao2_container.
Cleaned up function naming.  Internal only, no public name changes.
Cleaned up whitespace and brace formatting in cli code.
Changed some NULL checking from "if"s to ast_asserts.
Fixed some register/unregister ordering to reduce deadlock potential.
Fixed ast_sip_location_add_contact where the 'name' buffer was too short.
Fixed some self-assignment issues in res_pjsip_outbound_registration.

(closes issue ASTERISK-23276)
Review: http://reviewboard.asterisk.org/r/3283/
........

Merged revisions 410287 from http://svn.asterisk.org/svn/asterisk/branches/12


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@410288 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
George Joseph
2014-03-08 16:50:36 +00:00
parent 5ca081e053
commit 3ff60b75b1
11 changed files with 751 additions and 388 deletions

View File

@@ -181,7 +181,7 @@ struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_na
int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
struct timeval expiration_time, const char *path_info, const char *user_agent)
{
char name[AST_UUID_STR_LEN];
char name[MAX_OBJECT_FIELD * 2 + 3];
RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), uri);
@@ -279,21 +279,21 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab
return 0;
}
static int contact_to_vl(void *object, void *arg, int flags)
static int contact_to_var_list(void *object, void *arg, int flags)
{
struct ast_sip_contact *contact = object;
struct ast_sip_contact_wrapper *wrapper = object;
struct ast_variable **var = arg;
ast_variable_list_append(&*var, ast_variable_new("contact", contact->uri, ""));
ast_variable_list_append(&*var, ast_variable_new("contact", wrapper->contact->uri, ""));
return 0;
}
static int contacts_to_vl(const void *obj, struct ast_variable **fields)
static int contacts_to_var_list(const void *obj, struct ast_variable **fields)
{
const struct ast_sip_aor *aor = obj;
ast_sip_for_each_contact(aor, contact_to_vl, fields);
ast_sip_for_each_contact(aor, contact_to_var_list, fields);
return 0;
}
@@ -323,12 +323,21 @@ int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
return 0;
}
static void contact_wrapper_destroy(void *obj)
{
struct ast_sip_contact_wrapper *wrapper = obj;
ast_free(wrapper->aor_id);
ast_free(wrapper->contact_id);
ao2_ref(wrapper->contact, -1);
}
int ast_sip_for_each_contact(const 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;
struct ao2_iterator i;
int res = 0;
void *object = NULL;
if (!on_contact ||
!(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
@@ -336,26 +345,44 @@ int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
}
i = ao2_iterator_init(contacts, 0);
while ((contact = ao2_iterator_next(&i))) {
int res;
while ((object = ao2_iterator_next(&i))) {
RAII_VAR(struct ast_sip_contact *, contact, object, ao2_cleanup);
RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
const char *aor_id = ast_sorcery_object_get_id(aor);
ast_sorcery_object_set_extended(contact, "@aor_id", ast_sorcery_object_get_id(aor));
if ((res = on_contact(contact, arg, 0))) {
ao2_iterator_destroy(&i);
return -1;
wrapper = ao2_alloc(sizeof(struct ast_sip_contact_wrapper), contact_wrapper_destroy);
if (!wrapper) {
res = -1;
break;
}
wrapper->contact_id = ast_malloc(strlen(aor_id) + strlen(contact->uri) + 2);
if (!wrapper->contact_id) {
res = -1;
break;
}
sprintf(wrapper->contact_id, "%s/%s", aor_id, contact->uri);
wrapper->aor_id = ast_strdup(aor_id);
if (!wrapper->aor_id) {
res = -1;
break;
}
wrapper->contact = contact;
ao2_bump(wrapper->contact);
if ((res = on_contact(wrapper, arg, 0))) {
break;
}
}
ao2_iterator_destroy(&i);
return 0;
return res;
}
int ast_sip_contact_to_str(void *object, void *arg, int flags)
{
struct ast_sip_contact *contact = object;
struct ast_sip_contact_wrapper *wrapper = object;
struct ast_str **buf = arg;
ast_str_append(buf, 0, "%s/%s,",
ast_sorcery_object_get_extended(contact, "aor_id"), contact->uri);
ast_str_append(buf, 0, "%s,", wrapper->contact_id);
return 0;
}
@@ -448,10 +475,10 @@ struct ast_sip_endpoint_formatter endpoint_aor_formatter = {
.format_ami = format_ami_endpoint_aor
};
static struct ao2_container *cli_get_aor_container(void)
static struct ao2_container *cli_aor_get_container(void)
{
RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
RAII_VAR(struct ao2_container *, s_container, NULL, ao2_cleanup);
struct ao2_container *s_container;
container = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
@@ -460,90 +487,144 @@ static struct ao2_container *cli_get_aor_container(void)
}
s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
ast_sorcery_object_id_compare, NULL);
ast_sorcery_object_id_sort, ast_sorcery_object_id_compare);
if (!s_container) {
return NULL;
}
if (ao2_container_dup(s_container, container, 0)) {
ao2_ref(s_container, -1);
return NULL;
}
ao2_ref(s_container, +1);
return s_container;
}
static int populate_contact_container(void *obj, void *arg, int flags)
static int cli_contact_populate_container(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
struct ao2_container *container = arg;
ao2_link(arg, obj);
ao2_link(container, contact);
return 0;
}
static int gather_aor_contacts(void *obj, void *arg, int flags)
static int cli_aor_gather_contacts(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;
return ast_sip_for_each_contact(aor, cli_contact_populate_container, arg);
}
static int cli_contact_compare(const void *left, const void *right, int flags)
static const char *cli_contact_get_id(const void *obj)
{
const struct ast_sip_contact *left_contact = left;
const struct ast_sip_contact *right_contact = right;
int rc;
if (!left_contact || !right_contact) {
return 0;
}
rc = strcmp(ast_sorcery_object_get_extended(left_contact, "aor_id"),
ast_sorcery_object_get_extended(right_contact, "aor_id"));
if (rc) {
return rc;
}
return strcmp(left_contact->uri, right_contact->uri);
const struct ast_sip_contact_wrapper *wrapper = obj;
return wrapper->contact_id;
}
static struct ao2_container *cli_get_contact_container(void)
static int cli_contact_sort(const void *obj, const void *arg, int flags)
{
const struct ast_sip_contact_wrapper *left_wrapper = obj;
const struct ast_sip_contact_wrapper *right_wrapper = arg;
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_wrapper->contact_id;
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcmp(left_wrapper->contact_id, right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
cmp = strncmp(left_wrapper->contact_id, right_key, strlen(right_key));
break;
default:
cmp = 0;
break;
}
return cmp;
}
static int cli_contact_compare(void *obj, void *arg, int flags)
{
const struct ast_sip_contact_wrapper *left_wrapper = obj;
const struct ast_sip_contact_wrapper *right_wrapper = arg;
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_wrapper->contact_id;
/* Fall through */
case OBJ_SEARCH_KEY:
if (strcmp(left_wrapper->contact_id, right_key) == 0) {;
cmp = CMP_MATCH | CMP_STOP;
}
break;
case OBJ_SEARCH_PARTIAL_KEY:
if (strncmp(left_wrapper->contact_id, right_key, strlen(right_key)) == 0) {
cmp = CMP_MATCH;
}
break;
default:
cmp = 0;
break;
}
return cmp;
}
static int cli_contact_hash(const void *obj, int flags)
{
const struct ast_sip_contact_wrapper *wrapper = obj;
if (flags & OBJ_SEARCH_OBJECT) {
return ast_str_hash(wrapper->contact_id);
} else if (flags & OBJ_SEARCH_KEY) {
return ast_str_hash(obj);
}
return -1;
}
static int cli_contact_iterate(void *container, ao2_callback_fn callback, void *args)
{
return ast_sip_for_each_contact(container, callback, args);
}
static struct ao2_container *cli_contact_get_container(void)
{
RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
struct ao2_container *child_container;
parent_container = cli_get_aor_container();
parent_container = cli_aor_get_container();
if (!parent_container) {
return NULL;
}
child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
cli_contact_compare, NULL);
child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
cli_contact_hash, cli_contact_sort, cli_contact_compare);
if (!child_container) {
return NULL;
}
ao2_ref(child_container, +1);
ao2_callback(parent_container, OBJ_NODATA, gather_aor_contacts, child_container);
ao2_callback(parent_container, OBJ_NODATA, cli_aor_gather_contacts, child_container);
return child_container;
}
static int cli_contact_iterator(const void *container, ao2_callback_fn callback, void *args)
static void *cli_contact_retrieve_by_id(const char *id)
{
const struct ast_sip_aor *array = container;
return ast_sip_for_each_contact(array, callback, args);
return ao2_find(cli_contact_get_container(), id, OBJ_KEY | OBJ_NOLOCK);
}
static int cli_print_contact_header(void *obj, void *arg, int flags)
static int cli_contact_print_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_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <Aor/ContactUri%*.*s> <Status....> <RTT(ms)..>\n",
indent, "Contact", filler, filler, CLI_HEADER_FILLER);
@@ -551,27 +632,20 @@ static int cli_print_contact_header(void *obj, void *arg, int flags)
return 0;
}
static int cli_print_contact_body(void *obj, void *arg, int flags)
static int cli_contact_print_body(void *obj, void *arg, int flags)
{
struct ast_sip_contact *contact = obj;
struct ast_sip_contact_wrapper *wrapper = obj;
struct ast_sip_contact *contact = wrapper->contact;
struct ast_sip_cli_context *context = arg;
char *print_name = NULL;
int print_name_len;
int indent;
int flexwidth;
const char *aor_id = ast_sorcery_object_get_extended(contact, "aor_id");
RAII_VAR(struct ast_sip_contact_status *, status,
ast_sorcery_retrieve_by_id( ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact)),
ao2_cleanup);
if (!context->output_buffer) {
return -1;
}
print_name_len = strlen(aor_id) + strlen(contact->uri) + 2;
print_name = ast_alloca(print_name_len);
snprintf(print_name, print_name_len, "%s/%s", aor_id, contact->uri);
ast_assert(contact->uri != NULL);
ast_assert(context->output_buffer != NULL);
indent = CLI_INDENT_TO_SPACES(context->indent_level);
flexwidth = CLI_LAST_TABSTOP - indent - 2;
@@ -580,31 +654,40 @@ static int cli_print_contact_body(void *obj, void *arg, int flags)
indent,
"Contact",
flexwidth, flexwidth,
print_name,
wrapper->contact_id,
(status ? (status->status == AVAILABLE ? "Avail" : "Unavail") : "Unknown"),
(status ? ((long long) status->rtt) / 1000.0 : NAN));
return 0;
}
static int cli_aor_iterator(const void *container, ao2_callback_fn callback, void *args)
static int cli_aor_iterate(void *container, ao2_callback_fn callback, void *args)
{
const char *aor_list = container;
return ast_sip_for_each_aor(aor_list, callback, args);
}
static int cli_print_aor_header(void *obj, void *arg, int flags)
static void *cli_aor_retrieve_by_id(const char *id)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", id);
}
static const char *cli_aor_get_id(const void *obj)
{
return ast_sorcery_object_get_id(obj);
}
static int cli_aor_print_header(void *obj, void *arg, int flags)
{
struct ast_sip_cli_context *context = arg;
struct ast_sip_cli_formatter_entry *formatter_entry;
RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
int indent = CLI_INDENT_TO_SPACES(context->indent_level);
int filler = CLI_LAST_TABSTOP - indent - 7;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <Aor%*.*s> <MaxContact>\n",
indent, "Aor", filler, filler, CLI_HEADER_FILLER);
@@ -612,27 +695,26 @@ static int cli_print_aor_header(void *obj, void *arg, int flags)
if (context->recurse) {
context->indent_level++;
formatter_entry = ast_sip_lookup_cli_formatter("contact");
if (formatter_entry && formatter_entry->print_header) {
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)
static int cli_aor_print_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;
RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
int indent;
int flexwidth;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
context->current_aor = aor;
// context->current_aor = aor;
indent = CLI_INDENT_TO_SPACES(context->indent_level);
flexwidth = CLI_LAST_TABSTOP - indent - 12;
@@ -647,8 +729,8 @@ static int cli_print_aor_body(void *obj, void *arg, int flags)
context->indent_level++;
formatter_entry = ast_sip_lookup_cli_formatter("contact");
if (formatter_entry && formatter_entry->print_body && formatter_entry->iterator) {
formatter_entry->iterator(aor, formatter_entry->print_body, context);
if (formatter_entry) {
formatter_entry->iterate(aor, formatter_entry->print_body, context);
}
context->indent_level--;
@@ -666,24 +748,6 @@ static int cli_print_aor_body(void *obj, void *arg, int flags)
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,
.iterator = cli_contact_iterator,
.comparator = cli_contact_compare,
};
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,
.iterator = cli_aor_iterator,
.comparator = ast_sorcery_object_id_compare,
};
static struct ast_cli_entry cli_commands[] = {
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Aors",
.command = "pjsip list aors",
@@ -706,8 +770,15 @@ static struct ast_cli_entry cli_commands[] = {
.command = "pjsip show contacts",
.usage = "Usage: pjsip show contacts\n"
" Show the configured PJSIP contacts\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contact",
.command = "pjsip show contact",
.usage = "Usage: pjsip show contact\n"
" Show the configured PJSIP contact\n"),
};
struct ast_sip_cli_formatter_entry *contact_formatter;
struct ast_sip_cli_formatter_entry *aor_formatter;
/*! \brief Initialize sorcery with location support */
int ast_sip_initialize_sorcery_location(void)
{
@@ -737,23 +808,52 @@ int ast_sip_initialize_sorcery_location(void)
ast_sorcery_object_field_register(sorcery, "aor", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, authenticate_qualify));
ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_vl, 0, 0);
ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0);
ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path));
ast_sip_register_endpoint_formatter(&endpoint_aor_formatter);
ast_sip_register_cli_formatter(&cli_contact_formatter);
ast_sip_register_cli_formatter(&cli_aor_formatter);
contact_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!contact_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for contact_formatter\n");
return -1;
}
contact_formatter->name = "contact";
contact_formatter->print_header = cli_contact_print_header;
contact_formatter->print_body = cli_contact_print_body;
contact_formatter->get_container = cli_contact_get_container;
contact_formatter->iterate = cli_contact_iterate;
contact_formatter->get_id = cli_contact_get_id;
contact_formatter->retrieve_by_id = cli_contact_retrieve_by_id;
aor_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!aor_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for aor_formatter\n");
return -1;
}
aor_formatter->name = "aor";
aor_formatter->print_header = cli_aor_print_header;
aor_formatter->print_body = cli_aor_print_body;
aor_formatter->get_container = cli_aor_get_container;
aor_formatter->iterate = cli_aor_iterate;
aor_formatter->get_id = cli_aor_get_id;
aor_formatter->retrieve_by_id = cli_aor_retrieve_by_id;
ast_sip_register_cli_formatter(contact_formatter);
ast_sip_register_cli_formatter(aor_formatter);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
return 0;
}
int ast_sip_destroy_sorcery_location(void)
{
ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_sip_unregister_cli_formatter(&cli_contact_formatter);
ast_sip_unregister_cli_formatter(&cli_aor_formatter);
ast_sip_unregister_cli_formatter(contact_formatter);
ast_sip_unregister_cli_formatter(aor_formatter);
return 0;
}