[asterisk-commits] mjordan: branch 12 r404480 - in /branches/12: ./ include/asterisk/ main/ res/...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Dec 20 15:23:27 CST 2013


Author: mjordan
Date: Fri Dec 20 15:23:24 2013
New Revision: 404480

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=404480
Log:
res_pjsip: Add PJSIP CLI commands

Implements the following cli commands:
pjsip list aors
pjsip list auths
pjsip list channels
pjsip list contacts
pjsip list endpoints
pjsip show aor(s)
pjsip show auth(s)
pjsip show channels
pjsip show endpoint(s)

Also...
Minor modifications made to the AMI command implementations to facilitate
reuse.

New function ast_variable_list_sort added to config.c and config.h to implement
variable list sorting. New api ast_sip_for_each_identify added to module
res_pjsip_endpoint_identifier_ip. Required new files
res_pjsip_endpoint_identifier_ip.h and
res_pjsip_endpoint_identifier_ip.exports.in.

(issue ASTERISK-22610)
patches:
  pjsip_cli_v2.patch uploaded by george.joseph (License 6322)

Added:
    branches/12/include/asterisk/res_pjsip_cli.h
      - copied unchanged from r404455, team/mjordan/pjsip-cli/include/asterisk/res_pjsip_cli.h
    branches/12/res/res_pjsip/pjsip_cli.c
      - copied unchanged from r404455, team/mjordan/pjsip-cli/res/res_pjsip/pjsip_cli.c
Modified:
    branches/12/   (props changed)
    branches/12/CREDITS
    branches/12/include/asterisk/config.h
    branches/12/include/asterisk/res_pjsip.h
    branches/12/include/asterisk/sorcery.h
    branches/12/main/channel.c
    branches/12/main/config.c
    branches/12/main/sorcery.c
    branches/12/res/res_pjsip/config_auth.c
    branches/12/res/res_pjsip/include/res_pjsip_private.h
    branches/12/res/res_pjsip/location.c
    branches/12/res/res_pjsip/pjsip_configuration.c
    branches/12/res/res_pjsip_endpoint_identifier_ip.c
    branches/12/res/res_pjsip_registrar.c

Propchange: branches/12/
------------------------------------------------------------------------------
    automerge = *

Propchange: branches/12/
------------------------------------------------------------------------------
    automerge-email = mjordan at digium.com

Propchange: branches/12/
------------------------------------------------------------------------------
    svnmerge-integrated = /branches/12:1-404442

Modified: branches/12/CREDITS
URL: http://svnview.digium.com/svn/asterisk/branches/12/CREDITS?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/CREDITS (original)
+++ branches/12/CREDITS Fri Dec 20 15:23:24 2013
@@ -276,6 +276,8 @@
 	* Andrew "lathama" Latham <lathama at gmail dot com>
 		Doxygen, HTTP-Static, Phoneprov, make update
 
+	* George Joseph - PJSIP CLI commands, PJSIP_HEADER dialplan function
+
 === OTHER CONTRIBUTIONS ===
 
  We'd like to thank the following for their listed contributions.

Modified: branches/12/include/asterisk/config.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/config.h?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/include/asterisk/config.h (original)
+++ branches/12/include/asterisk/config.h Fri Dec 20 15:23:24 2013
@@ -691,6 +691,7 @@
 void ast_variable_append(struct ast_category *category, struct ast_variable *variable);
 void ast_variable_insert(struct ast_category *category, struct ast_variable *variable, const char *line);
 int ast_variable_delete(struct ast_category *category, const char *variable, const char *match, const char *line);
+struct ast_variable *ast_variable_list_sort(struct ast_variable *start);
 
 /*!
  * \brief Update variable value within a config

Modified: branches/12/include/asterisk/res_pjsip.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/res_pjsip.h?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/include/asterisk/res_pjsip.h (original)
+++ branches/12/include/asterisk/res_pjsip.h Fri Dec 20 15:23:24 2013
@@ -38,6 +38,9 @@
 #include <pjlib.h>
 /* Needed for ast_rtp_dtls_cfg struct */
 #include "asterisk/rtp_engine.h"
+/* Needed for ast_sip_for_each_channel_snapshot struct */
+#include "asterisk/stasis_channels.h"
+#include "asterisk/stasis_endpoints.h"
 
 /* Forward declarations of PJSIP stuff */
 struct pjsip_rx_data;
@@ -209,6 +212,17 @@
 	unsigned int remove_existing;
 	/*! Any permanent configured contacts */
 	struct ao2_container *permanent_contacts;
+};
+
+/*!
+ * \brief Aor/Contact pair used for ast_sip_for_each_contact callback.
+ */
+struct ast_sip_aor_contact_pair {
+	SORCERY_OBJECT(details);
+	/*! Aor */
+	struct ast_sip_aor *aor;
+	/*! Contact */
+	struct ast_sip_contact *contact;
 };
 
 /*!
@@ -1550,13 +1564,6 @@
 	mod_data[id] = ast_sip_dict_set(pool, mod_data[id], key, val)
 
 /*!
- * \brief Function pointer for contact callbacks.
- */
-typedef int (*on_contact_t)(const struct ast_sip_aor *aor,
-			    const struct ast_sip_contact *contact,
-			    int last, void *arg);
-
-/*!
  * \brief For every contact on an AOR call the given 'on_contact' handler.
  *
  * \param aor the aor containing a list of contacts to iterate
@@ -1564,21 +1571,18 @@
  * \param arg user data passed to handler
  * \retval 0 Success, non-zero on failure
  */
-int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
-			     on_contact_t on_contact, void *arg);
+int ast_sip_for_each_contact(struct ast_sip_aor *aor,
+		ao2_callback_fn on_contact, void *arg);
 
 /*!
  * \brief Handler used to convert a contact to a string.
  *
- * \param aor the aor containing a list of contacts to iterate
- * \param contact the contact to convert
- * \param last is this the last contact
+ * \param object the ast_sip_aor_contact_pair containing a list of contacts to iterate and the contact
  * \param arg user data passed to handler
+ * \param flags
  * \retval 0 Success, non-zero on failure
  */
-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);
 
 /*!
  * \brief For every aor in the comma separated aors string call the
@@ -1699,4 +1703,47 @@
 int ast_sip_format_auths_ami(const struct ast_sip_auth_array *auths,
 			     struct ast_sip_ami *ami);
 
+/*!
+ * \brief Retrieve the endpoint snapshot for an endpoint
+ *
+ * \param endpoint The endpoint whose snapshot is to be retreieved.
+ * \retval The endpoint snapshot
+ */
+struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
+	const struct ast_sip_endpoint *endpoint);
+
+/*!
+ * \brief Retrieve the device state for an endpoint.
+ *
+ * \param endpoint The endpoint whose state is to be retrieved.
+ * \retval The device state.
+ */
+const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint);
+
+/*!
+ * \brief For every channel snapshot on an endpoint snapshot call the given
+ *        'on_channel_snapshot' handler.
+ *
+ * \param endpoint_snapshot snapshot of an endpoint
+ * \param on_channel_snapshot callback for each channel snapshot
+ * \param arg user data passed to handler
+ * \retval 0 Success, non-zero on failure
+ */
+int ast_sip_for_each_channel_snapshot(const struct ast_endpoint_snapshot *endpoint_snapshot,
+		ao2_callback_fn on_channel_snapshot,
+				      void *arg);
+
+/*!
+ * \brief For every channel snapshot on an endpoint all the given
+ *        'on_channel_snapshot' handler.
+ *
+ * \param endpoint endpoint
+ * \param on_channel_snapshot callback for each channel snapshot
+ * \param arg user data passed to handler
+ * \retval 0 Success, non-zero on failure
+ */
+int ast_sip_for_each_channel(const struct ast_sip_endpoint *endpoint,
+		ao2_callback_fn on_channel_snapshot,
+				      void *arg);
+
 #endif /* _RES_PJSIP_H */

Modified: branches/12/include/asterisk/sorcery.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/include/asterisk/sorcery.h?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/include/asterisk/sorcery.h (original)
+++ branches/12/include/asterisk/sorcery.h Fri Dec 20 15:23:24 2013
@@ -823,6 +823,12 @@
  */
 int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value);
 
+/*!
+ * \brief Sorcery object comparator based on id.
+ */
+int ast_sorcery_object_id_compare(const void *obj_left, const void *obj_right, int flags);
+
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: branches/12/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/channel.c?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/main/channel.c (original)
+++ branches/12/main/channel.c Fri Dec 20 15:23:24 2013
@@ -733,6 +733,8 @@
 		return "Dialing Offhook";
 	case AST_STATE_PRERING:
 		return "Pre-ring";
+	case AST_STATE_MUTE:
+		return "Mute";
 	default:
 		if (!(buf = ast_threadstorage_get(&state2str_threadbuf, STATE2STR_BUFSIZE)))
 			return "Unknown";

Modified: branches/12/main/config.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/config.c?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/main/config.c (original)
+++ branches/12/main/config.c Fri Dec 20 15:23:24 2013
@@ -70,6 +70,7 @@
 
 static struct ao2_container *cfg_hooks;
 static void config_hook_exec(const char *filename, const char *module, struct ast_config *cfg);
+inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2);
 
 /*! \brief Structure to keep comments for rewriting configuration files */
 struct ast_comment {
@@ -579,6 +580,39 @@
 	}
 
 	return (cat) ? cat->root : NULL;
+}
+
+inline struct ast_variable *variable_list_switch(struct ast_variable *l1, struct ast_variable *l2)
+{
+    l1->next = l2->next;
+    l2->next = l1;
+    return l2;
+}
+
+struct ast_variable *ast_variable_list_sort(struct ast_variable *start)
+{
+	struct ast_variable *p, *q, *top;
+	int changed = 1;
+	top = ast_calloc(1, sizeof(struct ast_variable));
+	top->next = start;
+	if (start != NULL && start->next != NULL) {
+		while (changed) {
+			changed = 0;
+			q = top;
+			p = top->next;
+			while (p->next != NULL) {
+				if (p->next != NULL && strcmp(p->name, p->next->name) > 0) {
+					q->next = variable_list_switch(p, p->next);
+
+					changed = 1;
+				}
+				q = p;
+				if (p->next != NULL)
+					p = p->next;
+			}
+		}
+	}
+	return top->next;
 }
 
 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)

Modified: branches/12/main/sorcery.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/main/sorcery.c?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/main/sorcery.c (original)
+++ branches/12/main/sorcery.c Fri Dec 20 15:23:24 2013
@@ -1583,3 +1583,11 @@
 	ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
 		sorcery_observer_remove, cbs);
 }
+
+int ast_sorcery_object_id_compare(const void *obj_left, const void *obj_right, int flags)
+{
+	if (!obj_left || !obj_right) {
+		return 0;
+	}
+	return strcmp(ast_sorcery_object_get_id(obj_left), ast_sorcery_object_get_id(obj_right));
+}

Modified: branches/12/res/res_pjsip/config_auth.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_pjsip/config_auth.c?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/res/res_pjsip/config_auth.c (original)
+++ branches/12/res/res_pjsip/config_auth.c Fri Dec 20 15:23:24 2013
@@ -23,7 +23,9 @@
 #include "asterisk/res_pjsip.h"
 #include "asterisk/logger.h"
 #include "asterisk/sorcery.h"
+#include "asterisk/cli.h"
 #include "include/res_pjsip_private.h"
+#include "asterisk/res_pjsip_cli.h"
 
 static void auth_destroy(void *obj)
 {
@@ -194,6 +196,59 @@
 
 static struct ast_sip_endpoint_formatter endpoint_auth_formatter = {
 	.format_ami = format_ami_endpoint_auth
+};
+
+static struct ao2_container *cli_get_auth_container(struct ast_sorcery *sip_sorcery)
+{
+	return ast_sorcery_retrieve_by_fields(sip_sorcery, "auth",
+				AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
+}
+
+static int cli_print_auth_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_str_append(&context->output_buffer, 0,
+		"%*s:  <AuthId/UserName%*.*s>\n", indent, "I/OAuth", filler, filler, CLI_HEADER_FILLER);
+
+	return 0;
+}
+
+static int cli_print_auth_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;
+	}
+
+	snprintf(title, 32, "%sAuth",context->auth_direction ? context->auth_direction : "");
+
+	ast_str_append(&context->output_buffer, 0, "%*s:  %s/%s\n",
+		CLI_INDENT_TO_SPACES(context->indent_level), title,
+		ast_sorcery_object_get_id(auth), auth->auth_user);
+
+	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(auth, context, 0);
+	}
+
+	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,
 };
 
 /*! \brief Initialize sorcery with auth support */
@@ -221,5 +276,7 @@
 			"userpass", auth_type_handler, auth_type_to_str, 0, 0);
 
 	ast_sip_register_endpoint_formatter(&endpoint_auth_formatter);
-	return 0;
-}
+	ast_sip_register_cli_formatter(&cli_auth_formatter);
+
+	return 0;
+}

Modified: branches/12/res/res_pjsip/include/res_pjsip_private.h
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_pjsip/include/res_pjsip_private.h?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/res/res_pjsip/include/res_pjsip_private.h (original)
+++ branches/12/res/res_pjsip/include/res_pjsip_private.h Fri Dec 20 15:23:24 2013
@@ -9,8 +9,6 @@
 #define RES_PJSIP_PRIVATE_H_
 
 #include "asterisk/module.h"
-#include "asterisk/stasis_channels.h"
-#include "asterisk/stasis_endpoints.h"
 
 struct ao2_container;
 struct ast_threadpool_options;
@@ -87,25 +85,6 @@
 void sip_get_threadpool_options(struct ast_threadpool_options *threadpool_options);
 
 /*!
- * \brief Function pointer for channel snapshot callbacks.
- */
-typedef int (*on_channel_snapshot_t)(
-	const struct ast_channel_snapshot *snapshot, int last, void *arg);
-
-/*!
- * \brief For every channel snapshot on an endpoint snapshot call the given
- *        'on_channel_snapshot' handler.
- *
- * \param endpoint_snapshot snapshot of an endpoint
- * \param on_channel_snapshot callback for each channel snapshot
- * \param arg user data passed to handler
- * \retval 0 Success, non-zero on failure
- */
-int ast_sip_for_each_channel_snapshot(const struct ast_endpoint_snapshot *endpoint_snapshot,
-				      on_channel_snapshot_t on_channel_snapshot,
-				      void *arg);
-
-/*!
  * \brief Retrieve the name of the default outbound endpoint.
  *
  * \note This returns a memory allocated copy of the name that
@@ -116,4 +95,10 @@
  */
 char *ast_sip_global_default_outbound_endpoint(void);
 
+/*!
+ * \brief Functions for initializing and destroying the CLI.
+ */
+int ast_sip_initialize_cli(struct ast_sorcery *sip_sorcery);
+void ast_sip_destroy_cli(void);
+
 #endif /* RES_PJSIP_PRIVATE_H_ */

Modified: branches/12/res/res_pjsip/location.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_pjsip/location.c?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/res/res_pjsip/location.c (original)
+++ branches/12/res/res_pjsip/location.c Fri Dec 20 15:23:24 2013
@@ -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 @@
 	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 @@
 		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);
-
-		ao2_ref(contact, -1);
-		if (res) {
+		int res;
+		RAII_VAR(struct ast_sip_aor_contact_pair *,
+			 acp, create_contact_pair(aor, contact), ao2_cleanup);
+
+		if (!acp || (res = on_contact(acp, arg, 0))) {
 			ao2_iterator_destroy(&i);
 			return -1;
 		}
@@ -312,18 +338,13 @@
 	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 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 @@
 	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);
@@ -375,6 +397,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 */
@@ -408,6 +617,8 @@
 	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);
-	return 0;
-}
-
+	ast_sip_register_cli_formatter(&cli_contact_formatter);
+	ast_sip_register_cli_formatter(&cli_aor_formatter);
+	return 0;
+}
+

Modified: branches/12/res/res_pjsip/pjsip_configuration.c
URL: http://svnview.digium.com/svn/asterisk/branches/12/res/res_pjsip/pjsip_configuration.c?view=diff&rev=404480&r1=404479&r2=404480
==============================================================================
--- branches/12/res/res_pjsip/pjsip_configuration.c (original)
+++ branches/12/res/res_pjsip/pjsip_configuration.c Fri Dec 20 15:23:24 2013
@@ -12,7 +12,8 @@
 
 #include "asterisk/res_pjsip.h"
 #include "include/res_pjsip_private.h"
-#include "asterisk/cli.h"
+#include "asterisk/res_pjsip_cli.h"
+#include "asterisk/acl.h"
 #include "asterisk/manager.h"
 #include "asterisk/astobj2.h"
 #include "asterisk/utils.h"
@@ -97,131 +98,6 @@
 	.deleted = persistent_endpoint_contact_observer,
 };
 
-static char *handle_cli_show_endpoints(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
-	struct ao2_iterator it_endpoints;
-	struct ast_sip_endpoint *endpoint;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "pjsip show endpoints";
-		e->usage =
-			"Usage: pjsip show endpoints\n"
-			"       Show the registered PJSIP endpoints\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	endpoints = ast_sip_get_endpoints();
-	if (!endpoints) {
-		return CLI_FAILURE;
-	}
-
-	if (!ao2_container_count(endpoints)) {
-		ast_cli(a->fd, "No endpoints found\n");
-		return CLI_SUCCESS;
-	}
-
-	ast_cli(a->fd, "Endpoints:\n");
-	it_endpoints = ao2_iterator_init(endpoints, 0);
-	while ((endpoint = ao2_iterator_next(&it_endpoints))) {
-		ast_cli(a->fd, "%s\n", ast_sorcery_object_get_id(endpoint));
-		ao2_ref(endpoint, -1);
-	}
-	ao2_iterator_destroy(&it_endpoints);
-	return CLI_SUCCESS;
-}
-
-static int show_contact(void *obj, void *arg, int flags)
-{
-	struct ast_sip_contact *contact = obj;
-	struct ast_cli_args *a = arg;
-	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);
-
-	ast_cli(a->fd, "\tContact %s:\n", contact->uri);
-
-	if (!status) {
-		ast_cli(a->fd, "\tStatus not found!\n");
-		return 0;
-	}
-
-	ast_cli(a->fd, "\t\tavailable = %s\n", status->status ? "yes" : "no");
-
-	if (status->status) {
-		ast_cli(a->fd, "\t\tRTT = %lld microseconds\n", (long long)status->rtt);
-	}
-
-	return 0;
-}
-
-static void show_endpoint(struct ast_sip_endpoint *endpoint, struct ast_cli_args *a)
-{
-	char *aor_name, *aors;
-
-	if (ast_strlen_zero(endpoint->aors)) {
-		return;
-	}
-
-	aors = ast_strdupa(endpoint->aors);
-
-	while ((aor_name = strsep(&aors, ","))) {
-		RAII_VAR(struct ast_sip_aor *, aor,
-			 ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
-		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
-
-		if (!aor || !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
-			continue;
-		}
-
-		ast_cli(a->fd, "AOR %s:\n", ast_sorcery_object_get_id(aor));
-		ao2_callback(contacts, OBJ_NODATA, show_contact, a);
-	}
-
-	return;
-}
-
-static char *cli_show_endpoint(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
-	const char *endpoint_name;
-
-	switch (cmd) {
-	case CLI_INIT:
-		e->command = "pjsip show endpoint";
-		e->usage =
-			"Usage: pjsip show endpoint <endpoint>\n"
-			"       Show the given PJSIP endpoint.\n";
-		return NULL;
-	case CLI_GENERATE:
-		return NULL;
-	}
-
-	if (a->argc != 4) {
-		return CLI_SHOWUSAGE;
-	}
-
-	endpoint_name = a->argv[3];
-
-	if (!(endpoint = ast_sorcery_retrieve_by_id(
-		      ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
-		ast_cli(a->fd, "Unable to retrieve endpoint %s\n", endpoint_name);
-		return CLI_FAILURE;
-	}
-
-	ast_cli(a->fd, "Endpoint %s:\n", endpoint_name);
-	show_endpoint(endpoint, a);
-
-	return CLI_SUCCESS;
-}
-
-static struct ast_cli_entry cli_commands[] = {
-	AST_CLI_DEFINE(handle_cli_show_endpoints, "Show PJSIP Endpoints"),
-	AST_CLI_DEFINE(cli_show_endpoint, "Show PJSIP Endpoint")
-};
 
 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
 {
@@ -963,7 +839,7 @@
 	return 0;
 }
 
-static const char *get_device_state(const struct ast_sip_endpoint *endpoint)
+const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint)
 {
 	char device[MAX_OBJECT_FIELD];
 
@@ -971,7 +847,7 @@
 	return ast_devstate2str(ast_device_state(device));
 }
 
-static struct ast_endpoint_snapshot *sip_get_endpoint_snapshot(
+struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
 	const struct ast_sip_endpoint *endpoint)
 {
 	return ast_endpoint_latest_snapshot(
@@ -981,46 +857,44 @@
 
 int ast_sip_for_each_channel_snapshot(
 	const struct ast_endpoint_snapshot *endpoint_snapshot,
-	on_channel_snapshot_t on_channel_snapshot, void *arg)
+	ao2_callback_fn on_channel_snapshot, void *arg)
 {
 	int num, num_channels = endpoint_snapshot->num_channels;
-	RAII_VAR(struct stasis_cache *, cache, NULL, ao2_cleanup);
-
-	if (!on_channel_snapshot || !num_channels ||
-	    !(cache = ast_channel_cache())) {
+
+	if (!on_channel_snapshot || !num_channels) {
 		return 0;
 	}
 
-	ao2_ref(cache, +1);
-
 	for (num = 0; num < num_channels; ++num) {
-		RAII_VAR(struct stasis_message *, msg, NULL, ao2_cleanup);
-		struct ast_channel_snapshot *snapshot;
-
-		msg = stasis_cache_get(cache, ast_channel_snapshot_type(),
-			endpoint_snapshot->channel_ids[num]);
-
-		if (!(snapshot = stasis_message_data(msg))) {
+		RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
+		int res;
+
+		snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);
+		if (!snapshot) {
 			continue;
 		}
 
-		if (on_channel_snapshot(
-			    snapshot, num == (num_channels - 1), arg)) {
+		res = on_channel_snapshot(snapshot, arg, 0);
+		if (res) {
 			return -1;
 		}
 	}
 	return 0;
 }
 
-static int active_channels_to_str_cb(const struct ast_channel_snapshot *snapshot,
-				     int last, void *arg)
-{
+int ast_sip_for_each_channel(
+	const struct ast_sip_endpoint *endpoint,
+	ao2_callback_fn on_channel_snapshot, void *arg)
+{
+	RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
+	return ast_sip_for_each_channel_snapshot(endpoint_snapshot, on_channel_snapshot, arg);
+}
+
+static int active_channels_to_str_cb(void *object, void *arg, int flags)
+{
+	const struct ast_channel_snapshot *snapshot = object;
 	struct ast_str **buf = arg;
-	if (last) {
-		ast_str_append(buf, 0, "%s", snapshot->name);
-	} else {
-		ast_str_append(buf, 0, "%s,", snapshot->name);
-	}
+	ast_str_append(buf, 0, "%s,", snapshot->name);
 	return 0;
 }
 
@@ -1029,7 +903,7 @@
 {
 
 	RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot,
-		 sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
+		 ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
 
 	if (endpoint_snapshot) {
 		return;
@@ -1037,6 +911,7 @@
 
 	ast_sip_for_each_channel_snapshot(endpoint_snapshot,
 					  active_channels_to_str_cb, str);
+	ast_str_truncate(*str, -1);
 }
 
 #define AMI_DEFAULT_STR_SIZE 512
@@ -1085,7 +960,7 @@
 
 static int sip_endpoints_aors_ami(void *obj, void *arg, int flags)
 {
-	const struct ast_sip_aor *aor = obj;
+	struct ast_sip_aor *aor = obj;
 	struct ast_str **buf = arg;
 
 	ast_str_append(buf, 0, "Contacts: ");
@@ -1103,7 +978,7 @@
 	}
 
 	ast_str_append(buf, 0, "DeviceState: %s\r\n",
-		       get_device_state(endpoint));
+		       ast_sip_get_device_state(endpoint));
 
 	ast_str_append(buf, 0, "ActiveChannels: ");
 	active_channels_to_str(endpoint, buf);
@@ -1213,7 +1088,7 @@
 			     sip_endpoints_aors_ami, &buf);
 
 	ast_str_append(&buf, 0, "DeviceState: %s\r\n",
-		       get_device_state(endpoint));
+		       ast_sip_get_device_state(endpoint));
 
 	ast_str_append(&buf, 0, "ActiveChannels: ");
 	active_channels_to_str(endpoint, &buf);
@@ -1251,11 +1126,241 @@
 	return 0;
 }
 
+static int populate_channel_container(void *obj, void *arg, int flags) {
+	struct ast_channel_snapshot *snapshot = obj;
+	struct ao2_container *container = arg;
+	ao2_link_flags(container, snapshot, OBJ_NOLOCK);
+	return 0;
+}
+
+static int gather_endpoint_channels(void *obj, void *arg, int flags) {
+	struct ast_sip_endpoint *endpoint = obj;
+	struct ao2_container *channels = arg;
+	ast_sip_for_each_channel(endpoint, populate_channel_container, channels);
+	return 0;
+}
+
+static struct ao2_container *cli_get_channel_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, "endpoint",
+				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;
+	}
+
+	if (ao2_container_dup(s_parent_container, parent_container, OBJ_ORDER_ASCENDING)) {
+		return NULL;
+	}
+
+	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_endpoint_channels, child_container);
+
+	return child_container;
+}
+
+static int cli_print_channel_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_str_append(&context->output_buffer, 0,
+		"%*s:  <ChannelId%*.*s>  <State.....>  <Time(sec)>\n",
+		indent, "Channel", filler, filler, CLI_HEADER_FILLER);
+
+	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) {
+	struct ast_channel_snapshot *snapshot = obj;
+	struct ast_sip_cli_context *context = arg;
+	struct timeval current_time;
+	char *print_name = NULL;
+	int print_name_len;
+	int indent;
+	int flexwidth;
+
+	if (!context->output_buffer) {
+		return -1;
+	}
+
+	gettimeofday(&current_time, NULL);
+
+	print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
+	if (!(print_name = alloca(print_name_len))) {
+		return -1;
+	}
+
+	snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
+
+	indent = CLI_INDENT_TO_SPACES(context->indent_level);
+	flexwidth = CLI_LAST_TABSTOP - indent;
+
+	ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %11ld\n",
+		CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
+		flexwidth, flexwidth,
+		print_name,
+		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--;
+	return 0;
+}
+
+static struct ao2_container *cli_get_endpoint_container(struct ast_sorcery *sip_sorcery)
+{
+	return ast_sip_get_endpoints();
+}
+
+static int cli_print_endpoint_header(void *obj, void *arg, int flags)
+{
+	struct ast_sip_cli_context *context = arg;
+	struct ast_sip_cli_formatter_entry *formatter_entry;
+
+	if (!context->output_buffer) {
+		return -1;
+	}
+	ast_str_append(&context->output_buffer, 0,
+			" <Endpoint/CID................................................>  <State.....>  <Channels.>\n");
+
+	if (context->recurse) {
+		context->indent_level++;
+		formatter_entry = ast_sip_lookup_cli_formatter("auth");
+		if (formatter_entry) {
+			formatter_entry->print_header(NULL, context, 0);
+		}
+		formatter_entry = ast_sip_lookup_cli_formatter("aor");
+		if (formatter_entry) {
+			formatter_entry->print_header(NULL, context, 0);
+		}
+		formatter_entry = ast_sip_lookup_cli_formatter("identify");
+		if (formatter_entry) {
+			formatter_entry->print_header(NULL, context, 0);
+		}
+		formatter_entry = ast_sip_lookup_cli_formatter("channel");
+		if (formatter_entry) {
+			formatter_entry->print_header(NULL, context, 0);
+		}
+		context->indent_level--;
+	}
+	return 0;
+}
+
+static int cli_print_endpoint_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);
+	struct ast_sip_cli_context *context = arg;
+	const char *id = ast_sorcery_object_get_id(endpoint);
+	struct ast_sip_cli_formatter_entry *formatter_entry;
+	char *print_name = NULL;
+	int print_name_len;
+	char *number = S_COR(endpoint->id.self.number.valid,
+		endpoint->id.self.number.str, NULL);
+
+	if (!context->output_buffer) {
+		return -1;
+	}
+
+	context->current_endpoint = endpoint;
+
+	if (number) {
+		print_name_len = strlen(id) + strlen(number) + 2;
+		if (!(print_name = alloca(print_name_len))) {
+			return -1;
+		}
+		snprintf(print_name, print_name_len, "%s/%s", id, number);
+	}
+
+	ast_str_append(&context->output_buffer, 0, " %-62s  %-12.12s  %d of %.0f\n",
+		print_name ? print_name : id,
+		ast_sip_get_device_state(endpoint),
+		endpoint_snapshot->num_channels,
+		(double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
+														INFINITY
+														);
+
+	if (context->recurse) {
+		context->indent_level++;
+
+		formatter_entry = ast_sip_lookup_cli_formatter("auth");
+		if (formatter_entry) {
+			context->auth_direction = "Out";
+			ast_sip_for_each_auth(&endpoint->outbound_auths, formatter_entry->print_body, context);
+			context->auth_direction = "In";
+			ast_sip_for_each_auth(&endpoint->inbound_auths, formatter_entry->print_body, context);
+		}
+		formatter_entry = ast_sip_lookup_cli_formatter("aor");
+		if (formatter_entry) {
+			ast_sip_for_each_aor(endpoint->aors, formatter_entry->print_body, context);
+		}
+		formatter_entry = ast_sip_lookup_cli_formatter("channel");
+		if (formatter_entry) {
+			ast_sip_for_each_channel(endpoint, formatter_entry->print_body, context);
+		}
+
+		context->indent_level--;
+	}
+
+	if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {

[... 86 lines stripped ...]



More information about the asterisk-commits mailing list