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
changes/97/197/1
George Joseph 11 years ago
parent 5ca081e053
commit 3ff60b75b1

@ -222,6 +222,19 @@ struct ast_sip_aor {
unsigned int support_path;
};
/*!
* \brief A wrapper for contact that adds the aor_id and
* a consistent contact id. Used by ast_sip_for_each_contact.
*/
struct ast_sip_contact_wrapper {
/*! The id of the parent aor. */
char *aor_id;
/*! The id of contact in form of aor_id/contact_uri. */
char *contact_id;
/*! Pointer to the actual contact. */
struct ast_sip_contact *contact;
};
/*!
* \brief DTMF modes for SIP endpoints
*/
@ -1620,7 +1633,8 @@ void *ast_sip_dict_set(pj_pool_t* pool, void *ht,
* \brief For every contact on an AOR call the given 'on_contact' handler.
*
* \param aor the aor containing a list of contacts to iterate
* \param on_contact callback on each contact on an AOR
* \param on_contact callback on each contact on an AOR. The object
* received by the callback will be a ast_sip_contact_wrapper structure.
* \param arg user data passed to handler
* \retval 0 Success, non-zero on failure
*/

@ -29,23 +29,20 @@
#define CLI_INDENT_TO_SPACES(x) ((x * 2) + 1 + CLI_MAX_TITLE_NAME)
/*
* \brief CLI Formatter Context
* \brief CLI Formatter Context passed to all formatters.
*/
struct ast_sip_cli_context {
int peers_mon_online;
int peers_mon_offline;
int peers_unmon_offline;
int peers_unmon_online;
/*! Buffer used to accumulate cli output. */
struct ast_str *output_buffer;
const struct ast_cli_args *a;
const struct ast_sip_endpoint *current_endpoint;
const struct ast_sip_auth *current_auth;
const struct ast_sip_aor *current_aor;
/*! Used to indicate which direction an auth is used for. "I" or "O" */
char *auth_direction;
unsigned int print_flags;
/*! Allows formatters to know how far to indent their output. */
int indent_level;
/*! Tells a formatter to dump its object_set. */
unsigned show_details : 1;
/*! Tells a formatter to descend into child objects. */
unsigned recurse : 1;
/*! Tells a formatter to dump it's object_set only if it's the root object. */
unsigned show_details_only_level_0 : 1;
};
@ -53,12 +50,24 @@ struct ast_sip_cli_context {
* \brief CLI Formatter Registry Entry
*/
struct ast_sip_cli_formatter_entry {
/*! A globally unique name for this formatter. If this formatter entry
* is for an existing sorcery object type, then this name must match
* the sorcery object type. Otherwise it can be any string as long as
* it's globally unique.
*/
const char *name;
/*! The callback used to print the object's column headers. */
ao2_callback_fn *print_header;
/*! The callback used to print the details of the object. */
ao2_callback_fn *print_body;
/*! The function used to retrieve a container of all objects of this type. */
struct ao2_container *(* get_container)(void);
int (* iterator)(const void *container, ao2_callback_fn callback, void *args);
ao2_sort_fn *comparator;
/*! The function used to iterate over a container of objects. */
int (* iterate)(void *container, ao2_callback_fn callback, void *args);
/*! The function used to retrieve a specific object from it's container. */
void *(* retrieve_by_id)(const char *id);
/*! The function used to retrieve an id string from an object. */
const char *(* get_id)(const void *obj);
};
/*!

@ -924,9 +924,19 @@ const char *ast_sorcery_object_get_extended(const void *object, const char *name
int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value);
/*!
* \brief Sorcery object comparator based on id.
* \brief ao2 object comparator based on sorcery id.
*/
int ast_sorcery_object_id_compare(const void *obj_left, const void *obj_right, int flags);
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags);
/*!
* \brief ao2 object sorter based on sorcery id.
*/
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags);
/*!
* \brief ao2 object hasher based on sorcery id.
*/
int ast_sorcery_object_id_hash(const void *obj, int flags);
/*!
* \brief Get the sorcery object type given a type name.

@ -1832,12 +1832,61 @@ void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *
sorcery_observer_remove, cbs);
}
int ast_sorcery_object_id_compare(const void *obj_left, const void *obj_right, int flags)
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
{
if (!obj_left || !obj_right) {
return 0;
const char *right_key = arg;
int cmp;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = ast_sorcery_object_get_id(arg);
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcmp(ast_sorcery_object_get_id(obj), right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
cmp = strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key));
break;
default:
cmp = 0;
break;
}
return cmp;
}
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
{
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = ast_sorcery_object_get_id(arg);
/* Fall through */
case OBJ_SEARCH_KEY:
if (strcmp(ast_sorcery_object_get_id(obj), right_key) == 0) {
cmp = CMP_MATCH | CMP_STOP;
}
break;
case OBJ_SEARCH_PARTIAL_KEY:
if (strncmp(ast_sorcery_object_get_id(obj), right_key, strlen(right_key)) == 0) {
cmp = CMP_MATCH;
}
break;
default:
cmp = 0;
break;
}
return cmp;
}
int ast_sorcery_object_id_hash(const void *obj, int flags) {
if (flags & OBJ_SEARCH_OBJECT) {
return ast_str_hash(ast_sorcery_object_get_id(obj));
} else if (flags & OBJ_SEARCH_KEY) {
return ast_str_hash(obj);
}
return strcmp(ast_sorcery_object_get_id(obj_left), ast_sorcery_object_get_id(obj_right));
return -1;
}
struct ast_sorcery_object_type *ast_sorcery_get_object_type(const struct ast_sorcery *sorcery,

@ -199,10 +199,10 @@ static struct ast_sip_endpoint_formatter endpoint_auth_formatter = {
.format_ami = format_ami_endpoint_auth
};
static struct ao2_container *cli_get_auth_container(void)
static struct ao2_container *cli_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(), "auth",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
@ -211,34 +211,36 @@ static struct ao2_container *cli_get_auth_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 cli_iterator(const void *container, ao2_callback_fn callback, void *args)
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
{
const struct ast_sip_auth_vector *vector = container;
return ast_sip_for_each_auth(container, callback, args);
}
return ast_sip_for_each_auth(vector, callback, args);
static void *cli_retrieve_by_id(const char *id)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, id);
}
static int cli_print_auth_header(void *obj, void *arg, int flags)
static int cli_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_MAX_WIDTH - indent - 20;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <AuthId/UserName%*.*s>\n", indent, "I/OAuth", filler, filler,
@ -247,17 +249,13 @@ static int cli_print_auth_header(void *obj, void *arg, int flags)
return 0;
}
static int cli_print_auth_body(void *obj, void *arg, int flags)
static int cli_print_body(void *obj, void *arg, int flags)
{
struct ast_sip_auth *auth = obj;
struct ast_sip_cli_context *context = arg;
char title[32];
context->current_auth = auth;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
snprintf(title, sizeof(title), "%sAuth",
context->auth_direction ? context->auth_direction : "");
@ -275,15 +273,6 @@ static int cli_print_auth_body(void *obj, void *arg, int flags)
return 0;
}
static struct ast_sip_cli_formatter_entry cli_auth_formatter = {
.name = SIP_SORCERY_AUTH_TYPE,
.print_header = cli_print_auth_header,
.print_body = cli_print_auth_body,
.get_container = cli_get_auth_container,
.iterator = cli_iterator,
.comparator = ast_sorcery_object_id_compare,
};
static struct ast_cli_entry cli_commands[] = {
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Auths",
.command = "pjsip list auths",
@ -299,6 +288,8 @@ static struct ast_cli_entry cli_commands[] = {
" Show the configured PJSIP Auth\n"),
};
static struct ast_sip_cli_formatter_entry *cli_formatter;
/*! \brief Initialize sorcery with auth support */
int ast_sip_initialize_sorcery_auth(void)
{
@ -326,7 +317,21 @@ int ast_sip_initialize_sorcery_auth(void)
"userpass", auth_type_handler, auth_type_to_str, NULL, 0, 0);
ast_sip_register_endpoint_formatter(&endpoint_auth_formatter);
ast_sip_register_cli_formatter(&cli_auth_formatter);
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!cli_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
return -1;
}
cli_formatter->name = SIP_SORCERY_AUTH_TYPE;
cli_formatter->print_header = cli_print_header;
cli_formatter->print_body = cli_print_body;
cli_formatter->get_container = cli_get_container;
cli_formatter->iterate = cli_iterator;
cli_formatter->get_id = ast_sorcery_object_get_id;
cli_formatter->retrieve_by_id = cli_retrieve_by_id;
ast_sip_register_cli_formatter(cli_formatter);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
return 0;
@ -335,6 +340,7 @@ int ast_sip_initialize_sorcery_auth(void)
int ast_sip_destroy_sorcery_auth(void)
{
ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_sip_unregister_cli_formatter(&cli_auth_formatter);
ast_sip_unregister_cli_formatter(cli_formatter);
return 0;
}

@ -509,7 +509,7 @@ static int tos_to_str(const void *obj, const intptr_t *args, char **buf)
static struct ao2_container *cli_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(), "transport",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
@ -518,19 +518,20 @@ static struct ao2_container *cli_get_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 cli_iterator(const void *container, ao2_callback_fn callback, void *args)
static int cli_iterate(void *container, ao2_callback_fn callback, void *args)
{
const struct ast_sip_endpoint *endpoint = container;
struct ast_sip_transport *transport = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
@ -539,18 +540,22 @@ static int cli_iterator(const void *container, ao2_callback_fn callback, void *a
if (!transport) {
return -1;
}
return callback(transport, args, 0);
}
static void *cli_retrieve_by_id(const char *id)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "transport", id);
}
static int cli_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_MAX_WIDTH - indent - 61;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <TransportId........> <Type> <cos> <tos> <BindAddress%*.*s>\n",
@ -565,9 +570,7 @@ static int cli_print_body(void *obj, void *arg, int flags)
struct ast_sip_cli_context *context = arg;
char hoststr[PJ_INET6_ADDRSTRLEN];
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
pj_sockaddr_print(&transport->host, hoststr, sizeof(hoststr), 3);
@ -586,15 +589,6 @@ static int cli_print_body(void *obj, void *arg, int flags)
return 0;
}
static struct ast_sip_cli_formatter_entry cli_formatter = {
.name = "transport",
.print_header = cli_print_header,
.print_body = cli_print_body,
.get_container = cli_get_container,
.iterator = cli_iterator,
.comparator = ast_sorcery_object_id_compare,
};
static struct ast_cli_entry cli_commands[] = {
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Transports",
.command = "pjsip list transports",
@ -610,6 +604,8 @@ static struct ast_cli_entry cli_commands[] = {
" Show the configured PJSIP Transport\n"),
};
static struct ast_sip_cli_formatter_entry *cli_formatter;
/*! \brief Initialize sorcery with transport support */
int ast_sip_initialize_sorcery_transport(void)
{
@ -643,7 +639,21 @@ int ast_sip_initialize_sorcery_transport(void)
ast_sorcery_object_field_register(sorcery, "transport", "cos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, cos));
ast_sip_register_endpoint_formatter(&endpoint_transport_formatter);
ast_sip_register_cli_formatter(&cli_formatter);
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!cli_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
return -1;
}
cli_formatter->name = "transport";
cli_formatter->print_header = cli_print_header;
cli_formatter->print_body = cli_print_body;
cli_formatter->get_container = cli_get_container;
cli_formatter->iterate = cli_iterate;
cli_formatter->get_id = ast_sorcery_object_get_id;
cli_formatter->retrieve_by_id = cli_retrieve_by_id;
ast_sip_register_cli_formatter(cli_formatter);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
return 0;
@ -652,6 +662,7 @@ int ast_sip_initialize_sorcery_transport(void)
int ast_sip_destroy_sorcery_transport(void)
{
ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_sip_unregister_cli_formatter(&cli_formatter);
ast_sip_unregister_cli_formatter(cli_formatter);
return 0;
}

@ -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);
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);
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;
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;
const struct ast_sip_contact_wrapper *wrapper = obj;
return wrapper->contact_id;
}
if (!left_contact || !right_contact) {
return 0;
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;
}
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 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 strcmp(left_contact->uri, right_contact->uri);
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_get_contact_container(void)
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;
}

@ -31,15 +31,7 @@
#include "asterisk/utils.h"
#include "asterisk/sorcery.h"
static struct ast_hashtab *formatter_registry;
struct ast_sip_cli_formatter_entry *ast_sip_lookup_cli_formatter(const char *name)
{
struct ast_sip_cli_formatter_entry fake_entry = {
.name = name,
};
return ast_hashtab_lookup(formatter_registry, &fake_entry);
}
static struct ao2_container *formatter_registry;
int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
{
@ -91,6 +83,7 @@ int ast_sip_cli_print_sorcery_objectset(void *obj, void *arg, int flags)
}
static char *complete_show_sorcery_object(struct ao2_container *container,
struct ast_sip_cli_formatter_entry *formatter_entry,
const char *word, int state)
{
char *result = NULL;
@ -101,9 +94,10 @@ static char *complete_show_sorcery_object(struct ao2_container *container,
void *object;
while ((object = ao2_t_iterator_next(&i, "iterate thru endpoints table"))) {
if (!strncasecmp(word, ast_sorcery_object_get_id(object), wordlen)
const char *id = formatter_entry->get_id(object);
if (!strncasecmp(word, id, wordlen)
&& ++which > state) {
result = ast_strdup(ast_sorcery_object_get_id(object));
result = ast_strdup(id);
}
ao2_t_ref(object, -1, "toss iterator endpoint ptr before break");
if (result) {
@ -111,6 +105,7 @@ static char *complete_show_sorcery_object(struct ao2_container *container,
}
}
ao2_iterator_destroy(&i);
return result;
}
@ -123,20 +118,15 @@ static void dump_str_and_free(int fd, struct ast_str *buf)
char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
RAII_VAR(void *, object, NULL, ao2_cleanup);
int is_container = 0;
const char *cmd1;
const char *cmd2;
const char *object_id;
char formatter_type[64];
struct ast_sip_cli_formatter_entry *formatter_entry;
struct ast_sip_cli_context context = {
.peers_mon_online = 0,
.peers_mon_offline = 0,
.peers_unmon_online = 0,
.peers_unmon_offline = 0,
.a = a,
.indent_level = 0,
.show_details = 0,
.show_details_only_level_0 = 0,
@ -203,7 +193,7 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_
if (cmd == CLI_GENERATE) {
ast_free(context.output_buffer);
return complete_show_sorcery_object(container, a->word, a->n);
return complete_show_sorcery_object(container, formatter_entry, a->word, a->n);
}
if (is_container) {
@ -219,8 +209,8 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_
ast_cli(a->fd, "No object specified.\n");
return CLI_FAILURE;
}
object = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), formatter_type,
object_id);
object = formatter_entry->retrieve_by_id(object_id);
if (!object) {
dump_str_and_free(a->fd, context.output_buffer);
ast_cli(a->fd, "Unable to find object %s.\n\n", object_id);
@ -234,44 +224,110 @@ char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_
return CLI_SUCCESS;
}
static int compare_formatters(const void *a, const void *b)
static int formatter_sort(const void *obj, const void *arg, int flags)
{
const struct ast_sip_cli_formatter_entry *afe = a;
const struct ast_sip_cli_formatter_entry *bfe = b;
if (!afe || !bfe) {
ast_log(LOG_ERROR, "One of the arguments to compare_formatters was NULL\n");
return -1;
const struct ast_sip_cli_formatter_entry *left_obj = obj;
const struct ast_sip_cli_formatter_entry *right_obj = arg;
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_obj->name;
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcmp(left_obj->name, right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
cmp = strncmp(left_obj->name, right_key, strlen(right_key));
break;
default:
cmp = 0;
break;
}
return strcmp(afe->name, bfe->name);
return cmp;
}
static unsigned int hash_formatters(const void *a)
static int formatter_compare(void *obj, void *arg, int flags)
{
const struct ast_sip_cli_formatter_entry *afe = a;
return ast_hashtab_hash_string(afe->name);
const struct ast_sip_cli_formatter_entry *left_obj = obj;
const struct ast_sip_cli_formatter_entry *right_obj = arg;
const char *right_key = arg;
int cmp = 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_obj->name;
/* Fall through */
case OBJ_SEARCH_KEY:
if (strcmp(left_obj->name, right_key) == 0) {;
cmp = CMP_MATCH | CMP_STOP;
}
break;
case OBJ_SEARCH_PARTIAL_KEY:
if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
cmp = CMP_MATCH;
}
break;
default:
cmp = 0;
break;
}
return cmp;
}
static int formatter_hash(const void *obj, int flags)
{
const struct ast_sip_cli_formatter_entry *left_obj = obj;
if (flags & OBJ_SEARCH_OBJECT) {
return ast_str_hash(left_obj->name);
} else if (flags & OBJ_SEARCH_KEY) {
return ast_str_hash(obj);
}
return -1;
}
struct ast_sip_cli_formatter_entry *ast_sip_lookup_cli_formatter(const char *name)
{
return ao2_find(formatter_registry, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
}
int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
{
ast_hashtab_insert_safe(formatter_registry, formatter);
ast_assert(formatter != NULL);
ast_assert(formatter->name != NULL);
ast_assert(formatter->print_body != NULL);
ast_assert(formatter->print_header != NULL);
ast_assert(formatter->get_container != NULL);
ast_assert(formatter->iterate != NULL);
ast_assert(formatter->get_id != NULL);
ast_assert(formatter->retrieve_by_id != NULL);
ao2_link(formatter_registry, formatter);
return 0;
}
int ast_sip_unregister_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
{
struct ast_sip_cli_formatter_entry *entry = ast_hashtab_lookup(formatter_registry, formatter);
if (!entry) {
return -1;
if (formatter) {
ao2_wrlock(formatter_registry);
if (ao2_ref(formatter, -1) == 2) {
ao2_unlink_flags(formatter_registry, formatter, OBJ_NOLOCK);
}
ao2_unlock(formatter_registry);
}
ast_hashtab_remove_this_object(formatter_registry, entry);
return 0;
}
int ast_sip_initialize_cli(void)
{
formatter_registry = ast_hashtab_create(17, compare_formatters,
ast_hashtab_resize_java, ast_hashtab_newsize_java, hash_formatters, 0);
formatter_registry = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
formatter_hash, formatter_sort, formatter_compare);
if (!formatter_registry) {
ast_log(LOG_ERROR, "Unable to create formatter_registry.\n");
return -1;
@ -282,7 +338,5 @@ int ast_sip_initialize_cli(void)
void ast_sip_destroy_cli(void)
{
if (formatter_registry) {
ast_hashtab_destroy(formatter_registry, ast_free_ptr);
}
ao2_ref(formatter_registry, -1);
}

@ -1217,10 +1217,10 @@ static int ami_show_endpoints(struct mansession *s, const struct message *m)
return 0;
}
static struct ao2_container *cli_get_endpoint_container(void)
static struct ao2_container *cli_endpoint_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(sip_sorcery, "endpoint",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
@ -1229,100 +1229,175 @@ static struct ao2_container *cli_get_endpoint_container(void)
}
s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
ast_sorcery_object_id_compare, NULL);
(void *)ast_sorcery_object_id_sort, (void *)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_channel_container(void *obj, void *arg, int flags)
static int cli_channel_populate_container(void *obj, void *arg, int flags)
{
struct ast_channel_snapshot *snapshot = obj;
struct ao2_container *container = arg;
ao2_link(container, snapshot);
ao2_link(arg, snapshot);
return 0;
}
static int cli_channel_iterator(const void *container, ao2_callback_fn callback, void *args)
static int cli_channel_iterate(void *container, ao2_callback_fn callback, void *args)
{
const struct ast_sip_endpoint *array = container;
const struct ast_sip_endpoint *endpoint = container;
ast_sip_for_each_channel(endpoint, callback, args);
return ast_sip_for_each_channel(array, callback, args);
return 0;
}
static int gather_endpoint_channels(void *obj, void *arg, int flags)
static int cli_channel_sort(const void *obj, const void *arg, int flags)
{
struct ast_sip_endpoint *endpoint = obj;
struct ao2_container *channels = arg;
const struct ast_channel_snapshot *left_obj = obj;
const struct ast_channel_snapshot *right_obj = arg;
const char *right_key = arg;
int cmp;
ast_sip_for_each_channel(endpoint, populate_channel_container, channels);
return 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_obj->name;
/* Fall through */
case OBJ_SEARCH_KEY:
cmp = strcmp(left_obj->name, right_key);
break;
case OBJ_SEARCH_PARTIAL_KEY:
cmp = strncmp(left_obj->name, right_key, strlen(right_key));
break;
default:
cmp = 0;
break;
}
return cmp;
}
static int cli_channel_compare(const void *left, const void *right, int flags)
static int cli_channel_compare(void *obj, void *arg, int flags)
{
const struct ast_channel_snapshot *left_snap = left;
const struct ast_channel_snapshot *right_snap = right;
const struct ast_channel_snapshot *left_obj = obj;
const struct ast_channel_snapshot *right_obj = arg;
const char *right_key = arg;
int cmp = 0;
if (!left_snap || !right_snap) {
return 0;
switch (flags & OBJ_SEARCH_MASK) {
case OBJ_SEARCH_OBJECT:
right_key = right_obj->name;
/* Fall through */
case OBJ_SEARCH_KEY:
if (strcmp(left_obj->name, right_key) == 0) {
cmp = CMP_MATCH | CMP_STOP;
}
break;
case OBJ_SEARCH_PARTIAL_KEY:
if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
cmp = CMP_MATCH;
}
break;
default:
cmp = 0;
break;
}
return strcmp(left_snap->name, right_snap->name);
return cmp;
}
static struct ao2_container *cli_get_channel_container(void)
static int cli_channel_hash(const void *obj, int flags)
{
const struct ast_channel_snapshot *snapshot = obj;
if (flags & OBJ_SEARCH_OBJECT) {
return ast_str_hash(snapshot->name);
} else if (flags & OBJ_SEARCH_KEY) {
return ast_str_hash(obj);
}
return -1;
}
static int cli_endpoint_gather_channels(void *obj, void *arg, int flags)
{
struct ast_sip_endpoint *endpoint = obj;
struct ao2_container *channels = arg;
ast_sip_for_each_channel(endpoint, cli_channel_populate_container, channels);
return 0;
}
static struct ao2_container *cli_channel_get_container(void)
{
RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
RAII_VAR(struct ao2_container *, child_container, NULL, ao2_cleanup);
struct ao2_container *child_container;
parent_container = cli_get_endpoint_container();
parent_container = cli_endpoint_get_container();
if (!parent_container) {
return NULL;
}
child_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
cli_channel_compare, NULL);
child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
cli_channel_hash, cli_channel_sort, cli_channel_compare);
if (!child_container) {
return NULL;
}
ao2_callback(parent_container, OBJ_NODATA, gather_endpoint_channels, child_container);
ao2_ref(child_container, +1);
ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container);
return child_container;
}
static int cli_print_channel_header(void *obj, void *arg, int flags)
static const char *cli_channel_get_id(const void *obj)
{
const struct ast_channel_snapshot *snapshot = obj;
return snapshot->name;
}
static void *cli_channel_retrieve_by_id(const char *id)
{
RAII_VAR(struct ao2_container *, container, cli_channel_get_container(), ao2_cleanup);
return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
}
static int cli_channel_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 - 13;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <ChannelId%*.*s> <State.....> <Time(sec)>\n",
indent, "Channel", filler, filler, CLI_HEADER_FILLER);
if (context->recurse) {
context->indent_level++;
indent = CLI_INDENT_TO_SPACES(context->indent_level);
filler = CLI_LAST_TABSTOP - indent - 38;
ast_str_append(&context->output_buffer, 0,
"%*s: <Codec> Exten: <DialedExten%*.*s> CLCID: <ConnectedLineCID.......>\n",
indent, "Codec", filler, filler, CLI_HEADER_FILLER);
context->indent_level--;
}
context->indent_level++;
indent = CLI_INDENT_TO_SPACES(context->indent_level);
filler = CLI_LAST_TABSTOP - indent - 38;
ast_str_append(&context->output_buffer, 0,
"%*s: <Codec> Exten: <DialedExten%*.*s> CLCID: <ConnectedLineCID.......>\n",
indent, "Codec", filler, filler, CLI_HEADER_FILLER);
context->indent_level--;
return 0;
}
static int cli_print_channel_body(void *obj, void *arg, int flags)
static int cli_channel_print_body(void *obj, void *arg, int flags)
{
struct ast_channel_snapshot *snapshot = obj;
const struct ast_channel_snapshot *snapshot = obj;
struct ast_sip_cli_context *context = arg;
struct timeval current_time;
char *print_name = NULL;
@ -1330,9 +1405,7 @@ static int cli_print_channel_body(void *obj, void *arg, int flags)
int indent;
int flexwidth;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
gettimeofday(&current_time, NULL);
@ -1353,79 +1426,84 @@ static int cli_print_channel_body(void *obj, void *arg, int flags)
ast_state2str(snapshot->state),
current_time.tv_sec - snapshot->creationtime.tv_sec);
context->indent_level++;
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",
indent, "Codec",
snapshot->nativeformats,
flexwidth, flexwidth,
snapshot->exten,
snapshot->connected_name,
snapshot->connected_number
);
context->indent_level--;
if (context->indent_level == 0) {
ast_str_append(&context->output_buffer, 0, "\n");
if (context->recurse) {
context->indent_level++;
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",
indent, "Codec",
snapshot->nativeformats,
flexwidth, flexwidth,
snapshot->exten,
snapshot->connected_name,
snapshot->connected_number
);
context->indent_level--;
if (context->indent_level == 0) {
ast_str_append(&context->output_buffer, 0, "\n");
}
}
return 0;
}
static int cli_endpoint_iterator(const void *container, ao2_callback_fn callback,
void *args)
static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args)
{
struct ao2_container *ao2container = (struct ao2_container *) container;
ao2_callback(obj, OBJ_NODATA, callback, args);
ao2_callback(ao2container, OBJ_NODATA, callback, args);
return 0;
}
static void print_child_header(char *type, struct ast_sip_cli_context *context)
static void *cli_endpoint_retrieve_by_id(const char *id)
{
struct ast_sip_cli_formatter_entry *formatter_entry;
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
}
static void cli_endpoint_print_child_header(char *type, struct ast_sip_cli_context *context)
{
RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
formatter_entry = ast_sip_lookup_cli_formatter(type);
if (formatter_entry && formatter_entry->print_header) {
if (formatter_entry) {
formatter_entry->print_header(NULL, context, 0);
}
}
static int cli_print_endpoint_header(void *obj, void *arg, int flags)
static int cli_endpoint_print_header(void *obj, void *arg, int flags)
{
struct ast_sip_cli_context *context = arg;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
" Endpoint: <Endpoint/CID.....................................> <State.....> <Channels.>\n");
if (context->recurse) {
context->indent_level++;
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);
cli_endpoint_print_child_header("auth", context);
cli_endpoint_print_child_header("aor", context);
cli_endpoint_print_child_header("transport", context);
cli_endpoint_print_child_header("identify", context);
cli_endpoint_print_child_header("channel", context);
context->indent_level--;
}
return 0;
}
static void print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
static void cli_endpoint_print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
{
struct ast_sip_cli_formatter_entry *formatter_entry;
RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
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);
if (formatter_entry) {
formatter_entry->iterate((void *)obj, formatter_entry->print_body, context);
}
}
static int cli_print_endpoint_body(void *obj, void *arg, int flags)
static int cli_endpoint_print_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);
@ -1438,11 +1516,7 @@ static int cli_print_endpoint_body(void *obj, void *arg, int flags)
int indent;
int flexwidth;
if (!context->output_buffer) {
return -1;
}
context->current_endpoint = endpoint;
ast_assert(context->output_buffer != NULL);
if (number) {
print_name_len = strlen(id) + strlen(number) + 2;
@ -1468,14 +1542,14 @@ static int cli_print_endpoint_body(void *obj, void *arg, int flags)
context->indent_level++;
context->auth_direction = "Out";
print_child_body("auth", &endpoint->outbound_auths, context);
cli_endpoint_print_child_body("auth", &endpoint->outbound_auths, context);
context->auth_direction = "In";
print_child_body("auth", &endpoint->inbound_auths, context);
cli_endpoint_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);
cli_endpoint_print_child_body("aor", endpoint->aors, context);
cli_endpoint_print_child_body("transport", endpoint, context);
cli_endpoint_print_child_body("identify", endpoint, context);
cli_endpoint_print_child_body("channel", endpoint, context);
context->indent_level--;
@ -1492,24 +1566,6 @@ static int cli_print_endpoint_body(void *obj, void *arg, int flags)
return 0;
}
static struct ast_sip_cli_formatter_entry cli_channel_formatter = {
.name = "channel",
.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 = {
.name = "endpoint",
.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",
@ -1519,6 +1575,10 @@ static struct ast_cli_entry cli_commands[] = {
.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, "Show PJSIP Channel",
.command = "pjsip show channel",
.usage = "Usage: pjsip show channel\n"
" List(detailed) the active PJSIP channel\n"),
AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
.command = "pjsip list endpoints",
@ -1534,9 +1594,11 @@ static struct ast_cli_entry cli_commands[] = {
" Show the configured PJSIP endpoint\n"),
};
struct ast_sip_cli_formatter_entry *channel_formatter;
struct ast_sip_cli_formatter_entry *endpoint_formatter;
int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info)
{
if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) ||
ast_manager_register_xml(AMI_SHOW_ENDPOINT, EVENT_FLAG_SYSTEM, ami_show_endpoint)) {
return -1;
@ -1563,7 +1625,6 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
}
ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "pjsip.conf,criteria=type=endpoint");
ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, sip_endpoint_apply_handler)) {
@ -1694,8 +1755,38 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
return -1;
}
ast_sip_register_cli_formatter(&cli_channel_formatter);
ast_sip_register_cli_formatter(&cli_endpoint_formatter);
channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!channel_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n");
ast_sorcery_unref(sip_sorcery);
sip_sorcery = NULL;
return -1;
}
channel_formatter->name = "channel";
channel_formatter->print_header = cli_channel_print_header;
channel_formatter->print_body = cli_channel_print_body;
channel_formatter->get_container = cli_channel_get_container;
channel_formatter->iterate = cli_channel_iterate;
channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
channel_formatter->get_id = cli_channel_get_id;
endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!endpoint_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n");
ast_sorcery_unref(sip_sorcery);
sip_sorcery = NULL;
return -1;
}
endpoint_formatter->name = "endpoint";
endpoint_formatter->print_header = cli_endpoint_print_header;
endpoint_formatter->print_body = cli_endpoint_print_body;
endpoint_formatter->get_container = cli_endpoint_get_container;
endpoint_formatter->iterate = cli_endpoint_iterate;
endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id;
endpoint_formatter->get_id = ast_sorcery_object_get_id;
ast_sip_register_cli_formatter(channel_formatter);
ast_sip_register_cli_formatter(endpoint_formatter);
ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_sorcery_load(sip_sorcery);
@ -1705,12 +1796,14 @@ int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_mod
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_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
ast_sip_unregister_cli_formatter(endpoint_formatter);
ast_sip_unregister_cli_formatter(channel_formatter);
ast_sorcery_unref(sip_sorcery);
}

@ -270,16 +270,14 @@ struct ast_sip_endpoint_formatter endpoint_identify_formatter = {
.format_ami = format_ami_endpoint_identify
};
static int populate_identify_container(void *obj, void *arg, int flags)
static int cli_populate_container(void *obj, void *arg, int flags)
{
struct ast_sip_ip_identify_match *ident = obj;
struct ao2_container *container = arg;
ao2_link(arg, obj);
ao2_link(container, ident);
return 0;
}
static int cli_iterator(const void *container, ao2_callback_fn callback, void *args)
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
{
const struct ast_sip_endpoint *endpoint = container;
struct ao2_container *identifies;
@ -301,16 +299,17 @@ static int cli_iterator(const void *container, ao2_callback_fn callback, void *a
return 0;
}
static int gather_endpoint_identifies(void *obj, void *arg, int flags)
static int cli_endpoint_gather_identifies(void *obj, void *arg, int flags)
{
struct ast_sip_endpoint *endpoint = obj;
struct ao2_container *container = arg;
cli_iterator(endpoint, populate_identify_container, container);
cli_iterator(endpoint, cli_populate_container, container);
return 0;
}
static struct ao2_container *cli_get_identify_container(void)
static struct ao2_container *cli_get_container(void)
{
RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
RAII_VAR(struct ao2_container *, s_parent_container, NULL, ao2_cleanup);
@ -323,7 +322,7 @@ static struct ao2_container *cli_get_identify_container(void)
}
s_parent_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_parent_container) {
return NULL;
}
@ -333,26 +332,28 @@ static struct ao2_container *cli_get_identify_container(void)
}
child_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 (!child_container) {
return NULL;
}
ao2_callback(s_parent_container, OBJ_NODATA, gather_endpoint_identifies, child_container);
ao2_ref(child_container, +1);
ao2_callback(s_parent_container, OBJ_NODATA, cli_endpoint_gather_identifies, child_container);
return child_container;
}
static void *cli_retrieve_by_id(const char *id)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "identify", id);
}
static int cli_print_identify_header(void *obj, void *arg, int flags)
static int cli_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_MAX_WIDTH - indent - 14;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
"%*s: <MatchList%*.*s>\n",
@ -361,15 +362,13 @@ static int cli_print_identify_header(void *obj, void *arg, int flags)
return 0;
}
static int cli_print_identify_body(void *obj, void *arg, int flags)
static int cli_print_body(void *obj, void *arg, int flags)
{
RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
struct ip_identify_match *ident = obj;
struct ast_sip_cli_context *context = arg;
if (!context->output_buffer || !str) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0, "%*s: ",
CLI_INDENT_TO_SPACES(context->indent_level), "Identify");
@ -379,14 +378,7 @@ static int cli_print_identify_body(void *obj, void *arg, int flags)
return 0;
}
static struct ast_sip_cli_formatter_entry cli_identify_formatter = {
.name = "identify",
.print_header = cli_print_identify_header,
.print_body = cli_print_identify_body,
.get_container = cli_get_identify_container,
.comparator = ast_sorcery_object_id_compare,
.iterator = cli_iterator,
};
static struct ast_sip_cli_formatter_entry *cli_formatter;
static int load_module(void)
{
@ -403,7 +395,21 @@ static int load_module(void)
ast_sip_register_endpoint_identifier(&ip_identifier);
ast_sip_register_endpoint_formatter(&endpoint_identify_formatter);
ast_sip_register_cli_formatter(&cli_identify_formatter);
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!cli_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
return -1;
}
cli_formatter->name = "identify";
cli_formatter->print_header = cli_print_header;
cli_formatter->print_body = cli_print_body;
cli_formatter->get_container = cli_get_container;
cli_formatter->iterate = cli_iterator;
cli_formatter->get_id = ast_sorcery_object_get_id;
cli_formatter->retrieve_by_id = cli_retrieve_by_id;
ast_sip_register_cli_formatter(cli_formatter);
return AST_MODULE_LOAD_SUCCESS;
}
@ -411,14 +417,16 @@ static int load_module(void)
static int reload_module(void)
{
ast_sorcery_reload_object(ast_sip_get_sorcery(), "identify");
return 0;
}
static int unload_module(void)
{
ast_sip_unregister_cli_formatter(&cli_identify_formatter);
ast_sip_unregister_cli_formatter(cli_formatter);
ast_sip_unregister_endpoint_formatter(&endpoint_identify_formatter);
ast_sip_unregister_endpoint_identifier(&ip_identifier);
return 0;
}

@ -1132,7 +1132,7 @@ static int ami_show_outbound_registrations(struct mansession *s,
static struct ao2_container *cli_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(), "registration",
AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
@ -1141,33 +1141,36 @@ static struct ao2_container *cli_get_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 cli_iterator(const void *container, ao2_callback_fn callback, void *args)
static int cli_iterator(void *container, ao2_callback_fn callback, void *args)
{
struct ao2_container *ao2container = (struct ao2_container *) container;
ao2_callback(container, OBJ_NODATA, callback, args);
ao2_callback(ao2container, OBJ_NODATA, callback, args);
return 0;
}
static void *cli_retrieve_by_id(const char *id)
{
return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "registration", id);
}
static int cli_print_header(void *obj, void *arg, int flags)
{
struct ast_sip_cli_context *context = arg;
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0,
" <Registration/ServerURI..............................> <Auth..........> <Status.......>\n");
@ -1182,9 +1185,7 @@ static int cli_print_body(void *obj, void *arg, int flags)
const char *id = ast_sorcery_object_get_id(registration);
#define REGISTRATION_URI_FIELD_LEN 53
if (!context->output_buffer) {
return -1;
}
ast_assert(context->output_buffer != NULL);
ast_str_append(&context->output_buffer, 0, " %-s/%-*.*s %-16s %-16s\n",
id,
@ -1205,15 +1206,6 @@ static int cli_print_body(void *obj, void *arg, int flags)
return 0;
}
static struct ast_sip_cli_formatter_entry cli_formatter = {
.name = "registration",
.print_header = cli_print_header,
.print_body = cli_print_body,
.get_container = cli_get_container,
.iterator = cli_iterator,
.comparator = ast_sorcery_object_id_compare,
};
/*
* A function pointer to callback needs to be within the
* module in order to avoid problems with an undefined
@ -1240,6 +1232,8 @@ static struct ast_cli_entry cli_outbound_registration[] = {
" Show the configured PJSIP Registration\n"),
};
static struct ast_sip_cli_formatter_entry *cli_formatter;
static int load_module(void)
{
ast_sorcery_apply_default(ast_sip_get_sorcery(), "registration", "config", "pjsip.conf,criteria=type=registration");
@ -1264,10 +1258,24 @@ static int load_module(void)
ast_sorcery_reload_object(ast_sip_get_sorcery(), "registration");
sip_outbound_registration_perform_all();
ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
ast_manager_register_xml("PJSIPUnregister", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_unregister);
ast_manager_register_xml("PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING,ami_show_outbound_registrations);
ast_sip_register_cli_formatter(&cli_formatter);
cli_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
if (!cli_formatter) {
ast_log(LOG_ERROR, "Unable to allocate memory for cli formatter\n");
return -1;
}
cli_formatter->name = "registration";
cli_formatter->print_header = cli_print_header;
cli_formatter->print_body = cli_print_body;
cli_formatter->get_container = cli_get_container;
cli_formatter->iterate = cli_iterator;
cli_formatter->get_id = ast_sorcery_object_get_id;
cli_formatter->retrieve_by_id = cli_retrieve_by_id;
ast_sip_register_cli_formatter(cli_formatter);
ast_cli_register_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
return AST_MODULE_LOAD_SUCCESS;
}
@ -1281,10 +1289,11 @@ static int reload_module(void)
static int unload_module(void)
{
ast_sip_unregister_cli_formatter(&cli_formatter);
ast_cli_unregister_multiple(cli_outbound_registration, ARRAY_LEN(cli_outbound_registration));
ast_sip_unregister_cli_formatter(cli_formatter);
ast_manager_unregister("PJSIPShowRegistrationsOutbound");
ast_manager_unregister("PJSIPUnregister");
return 0;
}

Loading…
Cancel
Save