diff options
author | Kevin Harwell <kharwell@digium.com> | 2013-11-23 17:26:57 +0000 |
---|---|---|
committer | Kevin Harwell <kharwell@digium.com> | 2013-11-23 17:26:57 +0000 |
commit | 05cbf8df9b2ea0b41e049698b9f51ee4365ceab0 (patch) | |
tree | 896d138372ec9fc2f443374c6f200a0f67725fbb /res/res_pjsip | |
parent | 14a74529344ef5229f100c81bc969f34e27112b3 (diff) |
res_pjsip: AMI commands and events.
Created the following AMI commands and corresponding events for res_pjsip:
PJSIPShowEndpoints - Provides a listing of all pjsip endpoints and a few
select attributes on each.
Events:
EndpointList - for each endpoint a few attributes.
EndpointlistComplete - after all endpoints have been listed.
PJSIPShowEndpoint - Provides a detail list of attributes for a specified
endpoint.
Events:
EndpointDetail - attributes on an endpoint.
AorDetail - raised for each AOR on an endpoint.
AuthDetail - raised for each associated inbound and outbound auth
TransportDetail - transport attributes.
IdentifyDetail - attributes for the identify object associated with
the endpoint.
EndpointDetailComplete - last event raised after all detail events.
PJSIPShowRegistrationsInbound - Provides a detail listing of all inbound
registrations.
Events:
InboundRegistrationDetail - inbound registration attributes for each
registration.
InboundRegistrationDetailComplete - raised after all detail records have
been listed.
PJSIPShowRegistrationsOutbound - Provides a detail listing of all outbound
registrations.
Events:
OutboundRegistrationDetail - outbound registration attributes for each
registration.
OutboundRegistrationDetailComplete - raised after all detail records
have been listed.
PJSIPShowSubscriptionsInbound - A detail listing of all inbound subscriptions
and their attributes.
Events:
SubscriptionDetail - on each subscription detailed attributes
SubscriptionDetailComplete - raised after all detail records have
been listed.
PJSIPShowSubscriptionsOutbound - A detail listing of all outboundbound
subscriptions and their attributes.
Events:
SubscriptionDetail - on each subscription detailed attributes
SubscriptionDetailComplete - raised after all detail records have
been listed.
(issue ASTERISK-22609)
Reported by: Matt Jordan
Review: https://reviewboard.asterisk.org/r/2959/
........
Merged revisions 403131 from http://svn.asterisk.org/svn/asterisk/branches/12
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@403133 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res/res_pjsip')
-rw-r--r-- | res/res_pjsip/config_auth.c | 100 | ||||
-rw-r--r-- | res/res_pjsip/config_transport.c | 159 | ||||
-rw-r--r-- | res/res_pjsip/include/res_pjsip_private.h | 25 | ||||
-rw-r--r-- | res/res_pjsip/location.c | 118 | ||||
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 664 |
5 files changed, 1028 insertions, 38 deletions
diff --git a/res/res_pjsip/config_auth.c b/res/res_pjsip/config_auth.c index 860f33b56..afa26867e 100644 --- a/res/res_pjsip/config_auth.c +++ b/res/res_pjsip/config_auth.c @@ -23,6 +23,7 @@ #include "asterisk/res_pjsip.h" #include "asterisk/logger.h" #include "asterisk/sorcery.h" +#include "include/res_pjsip_private.h" static void auth_destroy(void *obj) { @@ -61,6 +62,24 @@ static int auth_type_handler(const struct aco_option *opt, struct ast_variable * return 0; } +static const char *auth_types_map[] = { + [AST_SIP_AUTH_TYPE_USER_PASS] = "userpass", + [AST_SIP_AUTH_TYPE_MD5] = "md5" +}; + +const char *ast_sip_auth_type_to_str(enum ast_sip_auth_type type) +{ + return ARRAY_IN_BOUNDS(type, auth_types_map) ? + auth_types_map[type] : ""; +} + +static int auth_type_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_auth *auth = obj; + *buf = ast_strdup(ast_sip_auth_type_to_str(auth->type)); + return 0; +} + static int auth_apply(const struct ast_sorcery *sorcery, void *obj) { struct ast_sip_auth *auth = obj; @@ -99,6 +118,84 @@ static int auth_apply(const struct ast_sorcery *sorcery, void *obj) return res; } +int ast_sip_for_each_auth(const struct ast_sip_auth_array *array, + ao2_callback_fn on_auth, void *arg) +{ + int i; + + if (!array || !array->num) { + return 0; + } + + for (i = 0; i < array->num; ++i) { + RAII_VAR(struct ast_sip_auth *, auth, ast_sorcery_retrieve_by_id( + ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, + array->names[i]), ao2_cleanup); + + if (!auth) { + continue; + } + + if (on_auth(auth, arg, 0)) { + return -1; + } + } + + return 0; +} + +static int sip_auth_to_ami(const struct ast_sip_auth *auth, + struct ast_str **buf) +{ + return ast_sip_sorcery_object_to_ami(auth, buf); +} + +static int format_ami_auth_handler(void *obj, void *arg, int flags) +{ + const struct ast_sip_auth *auth = obj; + struct ast_sip_ami *ami = arg; + const struct ast_sip_endpoint *endpoint = ami->arg; + RAII_VAR(struct ast_str *, buf, + ast_sip_create_ami_event("AuthDetail", ami), ast_free); + + if (!buf) { + return -1; + } + + if (sip_auth_to_ami(auth, &buf)) { + return -1; + } + + if (endpoint) { + ast_str_append(&buf, 0, "EndpointName: %s\r\n", + ast_sorcery_object_get_id(endpoint)); + } + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + return 0; +} + +int ast_sip_format_auths_ami(const struct ast_sip_auth_array *auths, + struct ast_sip_ami *ami) +{ + return ast_sip_for_each_auth(auths, format_ami_auth_handler, ami); +} + +static int format_ami_endpoint_auth(const struct ast_sip_endpoint *endpoint, + struct ast_sip_ami *ami) +{ + ami->arg = (void *)endpoint; + if (ast_sip_format_auths_ami(&endpoint->inbound_auths, ami)) { + return -1; + } + + return ast_sip_format_auths_ami(&endpoint->outbound_auths, ami); +} + +static struct ast_sip_endpoint_formatter endpoint_auth_formatter = { + .format_ami = format_ami_endpoint_auth +}; + /*! \brief Initialize sorcery with auth support */ int ast_sip_initialize_sorcery_auth(struct ast_sorcery *sorcery) { @@ -121,7 +218,8 @@ int ast_sip_initialize_sorcery_auth(struct ast_sorcery *sorcery) ast_sorcery_object_field_register(sorcery, SIP_SORCERY_AUTH_TYPE, "nonce_lifetime", "32", OPT_UINT_T, 0, FLDSET(struct ast_sip_auth, nonce_lifetime)); ast_sorcery_object_field_register_custom(sorcery, SIP_SORCERY_AUTH_TYPE, "auth_type", - "userpass", auth_type_handler, NULL, 0, 0); + "userpass", auth_type_handler, auth_type_to_str, 0, 0); + ast_sip_register_endpoint_formatter(&endpoint_auth_formatter); return 0; } diff --git a/res/res_pjsip/config_transport.c b/res/res_pjsip/config_transport.c index 4ace1821b..370e49cb0 100644 --- a/res/res_pjsip/config_transport.c +++ b/res/res_pjsip/config_transport.c @@ -26,6 +26,45 @@ #include "asterisk/astobj2.h" #include "asterisk/sorcery.h" #include "asterisk/acl.h" +#include "include/res_pjsip_private.h" + +static int sip_transport_to_ami(const struct ast_sip_transport *transport, + struct ast_str **buf) +{ + return ast_sip_sorcery_object_to_ami(transport, buf); +} + +static int format_ami_endpoint_transport(const struct ast_sip_endpoint *endpoint, + struct ast_sip_ami *ami) +{ + RAII_VAR(struct ast_str *, buf, + ast_sip_create_ami_event("TransportDetail", ami), ast_free); + RAII_VAR(struct ast_sip_transport *, + transport, ast_sorcery_retrieve_by_id( + ast_sip_get_sorcery(), "transport", + endpoint->transport), ao2_cleanup); + if (!buf) { + return -1; + } + + if (!transport) { + astman_send_error_va(ami->s, ami->m, "Unable to retrieve " + "transport %s\n", endpoint->transport); + return -1; + } + + sip_transport_to_ami(transport, &buf); + + ast_str_append(&buf, 0, "EndpointName: %s\r\n", + ast_sorcery_object_get_id(endpoint)); + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + return 0; +} + +struct ast_sip_endpoint_formatter endpoint_transport_formatter = { + .format_ami = format_ami_endpoint_transport +}; static int destroy_transport_state(void *data) { @@ -213,6 +252,25 @@ static int transport_protocol_handler(const struct aco_option *opt, struct ast_v return 0; } +static const char *transport_types[] = { + [AST_TRANSPORT_UDP] = "udp", + [AST_TRANSPORT_TCP] = "tcp", + [AST_TRANSPORT_TLS] = "tls", + [AST_TRANSPORT_WS] = "ws", + [AST_TRANSPORT_WSS] = "wss" +}; + +static int transport_protocol_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + + if (ARRAY_IN_BOUNDS(transport->type, transport_types)) { + *buf = ast_strdup(transport_types[transport->type]); + } + + return 0; +} + /*! \brief Custom handler for turning a string bind into a pj_sockaddr */ static int transport_bind_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -222,6 +280,20 @@ static int transport_bind_handler(const struct aco_option *opt, struct ast_varia return (pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&buf, var->value), &transport->host) != PJ_SUCCESS) ? -1 : 0; } +static int transport_bind_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + + if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { + return -1; + } + + /* include port as well as brackets if IPv6 */ + pj_sockaddr_print(&transport->host, *buf, MAX_OBJECT_FIELD, 1 | 2); + + return 0; +} + /*! \brief Custom handler for TLS boolean settings */ static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -240,6 +312,27 @@ static int transport_tls_bool_handler(const struct aco_option *opt, struct ast_v return 0; } +static int verify_server_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + *buf = ast_strdup(AST_YESNO(transport->tls.verify_server)); + return 0; +} + +static int verify_client_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + *buf = ast_strdup(AST_YESNO(transport->tls.verify_client)); + return 0; +} + +static int require_client_cert_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + *buf = ast_strdup(AST_YESNO(transport->tls.require_client_cert)); + return 0; +} + /*! \brief Custom handler for TLS method setting */ static int transport_tls_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -264,6 +357,24 @@ static int transport_tls_method_handler(const struct aco_option *opt, struct ast return 0; } +static const char *tls_method_map[] = { + [PJSIP_SSL_DEFAULT_METHOD] = "default", + [PJSIP_SSL_UNSPECIFIED_METHOD] = "unspecified", + [PJSIP_TLSV1_METHOD] = "tlsv1", + [PJSIP_SSLV2_METHOD] = "sslv2", + [PJSIP_SSLV3_METHOD] = "sslv3", + [PJSIP_SSLV23_METHOD] = "sslv23", +}; + +static int tls_method_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_transport *transport = obj; + if (ARRAY_IN_BOUNDS(transport->tls.method, tls_method_map)) { + *buf = ast_strdup(tls_method_map[transport->tls.method]); + } + return 0; +} + /*! \brief Custom handler for TLS cipher setting */ static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -291,6 +402,27 @@ static int transport_tls_cipher_handler(const struct aco_option *opt, struct ast } } +static int transport_tls_cipher_to_str(const void *obj, const intptr_t *args, char **buf) +{ + RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); + const struct ast_sip_transport *transport = obj; + int i; + + if (!str) { + return -1; + } + + for (i = 0; i < transport->tls.ciphers_num; ++i) { + ast_str_append(&str, 0, "%s", pj_ssl_cipher_name(transport->ciphers[i])); + if (i < transport->tls.ciphers_num - 1) { + ast_str_append(&str, 0, ","); + } + } + + *buf = ast_strdup(ast_str_buffer(str)); + return 0; +} + /*! \brief Custom handler for localnet setting */ static int transport_localnet_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -304,6 +436,16 @@ static int transport_localnet_handler(const struct aco_option *opt, struct ast_v return error; } +static int localnet_to_str(const void *obj, const intptr_t *args, char **buf) +{ + RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); + const struct ast_sip_transport *transport = obj; + + ast_ha_join(transport->localnet, &str); + *buf = ast_strdup(ast_str_buffer(str)); + return 0; +} + /*! \brief Initialize sorcery with transport support */ int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery) { @@ -314,8 +456,8 @@ int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery) } ast_sorcery_object_field_register(sorcery, "transport", "type", "", OPT_NOOP_T, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "protocol", "udp", transport_protocol_handler, transport_protocol_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "bind", "", transport_bind_handler, transport_bind_to_str, 0, 0); ast_sorcery_object_field_register(sorcery, "transport", "async_operations", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, async_operations)); ast_sorcery_object_field_register(sorcery, "transport", "ca_list_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, ca_list_file)); ast_sorcery_object_field_register(sorcery, "transport", "cert_file", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, cert_file)); @@ -325,14 +467,15 @@ int ast_sip_initialize_sorcery_transport(struct ast_sorcery *sorcery) ast_sorcery_object_field_register(sorcery, "transport", "external_signaling_port", "0", OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_transport, external_signaling_port), 0, 65535); ast_sorcery_object_field_register(sorcery, "transport", "external_media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, external_media_address)); ast_sorcery_object_field_register(sorcery, "transport", "domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_transport, domain)); - ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_server", "", transport_tls_bool_handler, verify_server_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "verify_client", "", transport_tls_bool_handler, verify_client_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "require_client_cert", "", transport_tls_bool_handler, require_client_cert_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "method", "", transport_tls_method_handler, tls_method_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "cipher", "", transport_tls_cipher_handler, transport_tls_cipher_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sorcery, "transport", "local_net", "", transport_localnet_handler, localnet_to_str, 0, 0); ast_sorcery_object_field_register(sorcery, "transport", "tos", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_transport, tos)); 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); return 0; } diff --git a/res/res_pjsip/include/res_pjsip_private.h b/res/res_pjsip/include/res_pjsip_private.h index c3e6c2192..0ee62529f 100644 --- a/res/res_pjsip/include/res_pjsip_private.h +++ b/res/res_pjsip/include/res_pjsip_private.h @@ -8,13 +8,17 @@ #ifndef RES_PJSIP_PRIVATE_H_ #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; /*! * \brief Initialize the configuration for res_pjsip */ -int ast_res_pjsip_initialize_configuration(void); +int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info); /*! * \brief Annihilate the configuration objects @@ -82,4 +86,23 @@ void ast_res_pjsip_cleanup_options_handling(void); */ 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); + #endif /* RES_PJSIP_PRIVATE_H_ */ diff --git a/res/res_pjsip/location.c b/res/res_pjsip/location.c index 8569e7a38..7f4889fe8 100644 --- a/res/res_pjsip/location.c +++ b/res/res_pjsip/location.c @@ -300,6 +300,123 @@ static int permanent_uri_handler(const struct aco_option *opt, struct ast_variab return 0; } +int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg) +{ + char *copy, *name; + + if (!on_aor || ast_strlen_zero(aors)) { + return 0; + } + + copy = ast_strdupa(aors); + while ((name = strsep(©, ","))) { + RAII_VAR(struct ast_sip_aor *, aor, + ast_sip_location_retrieve_aor(name), ao2_cleanup); + + if (!aor) { + continue; + } + + if (on_aor(aor, arg, 0)) { + return -1; + } + } + ast_free(copy); + return 0; +} + +int ast_sip_for_each_contact(const struct ast_sip_aor *aor, + on_contact_t 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 || + !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) { + return 0; + } + + num = ao2_container_count(contacts); + i = ao2_iterator_init(contacts, 0); + while ((contact = ao2_iterator_next(&i))) { + int res = on_contact(aor, contact, --num == 0, arg); + + ao2_ref(contact, -1); + if (res) { + return -1; + } + } + ao2_iterator_destroy(&i); + return 0; +} + +int ast_sip_contact_to_str(const struct ast_sip_aor *aor, + const struct ast_sip_contact *contact, + int last, void *arg) +{ + 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, ","); + } + + return 0; +} + +static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf) +{ + return ast_sip_sorcery_object_to_ami(aor, buf); +} + +static int format_ami_aor_handler(void *obj, void *arg, int flags) +{ + const 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, + ast_sip_create_ami_event("AorDetail", ami), ast_free); + + int num; + RAII_VAR(struct ao2_container *, contacts, + ast_sip_location_retrieve_aor_contacts(aor), ao2_cleanup); + + if (!buf) { + return -1; + } + + 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_append(&buf, 0, "\r\n"); + + num = ao2_container_count(contacts); + ast_str_append(&buf, 0, "TotalContacts: %d\r\n", num); + ast_str_append(&buf, 0, "ContactsRegistered: %d\r\n", + num - ao2_container_count(aor->permanent_contacts)); + ast_str_append(&buf, 0, "EndpointName: %s\r\n", + ast_sorcery_object_get_id(endpoint)); + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + return 0; +} + +static int format_ami_endpoint_aor(const struct ast_sip_endpoint *endpoint, + struct ast_sip_ami *ami) +{ + ami->arg = (void *)endpoint; + return ast_sip_for_each_aor(endpoint->aors, + format_ami_aor_handler, ami); +} + +struct ast_sip_endpoint_formatter endpoint_aor_formatter = { + .format_ami = format_ami_endpoint_aor +}; + /*! \brief Initialize sorcery with location support */ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery) { @@ -328,6 +445,7 @@ int ast_sip_initialize_sorcery_location(struct ast_sorcery *sorcery) ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, NULL, 0, 0); ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes)); + ast_sip_register_endpoint_formatter(&endpoint_aor_formatter); return 0; } diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c index d8e781a56..24c53e8a9 100644 --- a/res/res_pjsip/pjsip_configuration.c +++ b/res/res_pjsip/pjsip_configuration.c @@ -13,11 +13,11 @@ #include "asterisk/res_pjsip.h" #include "include/res_pjsip_private.h" #include "asterisk/cli.h" +#include "asterisk/manager.h" #include "asterisk/astobj2.h" #include "asterisk/utils.h" #include "asterisk/sorcery.h" #include "asterisk/callerid.h" -#include "asterisk/stasis_endpoints.h" /*! \brief Number of buckets for persistent endpoint information */ #define PERSISTENT_BUCKETS 53 @@ -242,6 +242,25 @@ static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, return 0; } +static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + switch (endpoint->dtmf) { + case AST_SIP_DTMF_RFC_4733 : + *buf = "rfc4733"; break; + case AST_SIP_DTMF_INBAND : + *buf = "inband"; break; + case AST_SIP_DTMF_INFO : + *buf = "info"; break; + default: + *buf = "none"; + } + + *buf = ast_strdup(*buf); + return 0; +} + static int prack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -259,6 +278,22 @@ static int prack_handler(const struct aco_option *opt, struct ast_variable *var, return 0; } +static int prack_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_100REL) { + *buf = "required"; + } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_100REL) { + *buf = "yes"; + } else { + *buf = "no"; + } + + *buf = ast_strdup(*buf); + return 0; +} + static int timers_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -278,6 +313,24 @@ static int timers_handler(const struct aco_option *opt, struct ast_variable *var return 0; } +static int timers_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + if (endpoint->extensions.flags & PJSIP_INV_ALWAYS_USE_TIMER) { + *buf = "always"; + } else if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_TIMER) { + *buf = "required"; + } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_TIMER) { + *buf = "yes"; + } else { + *buf = "no"; + } + + *buf = ast_strdup(*buf); + return 0; +} + void ast_sip_auth_array_destroy(struct ast_sip_auth_array *auths) { int i; @@ -344,6 +397,32 @@ static int outbound_auth_handler(const struct aco_option *opt, struct ast_variab return ast_sip_auth_array_init(&endpoint->outbound_auths, var->value); } +int ast_sip_auths_to_str(const struct ast_sip_auth_array *auths, char **buf) +{ + if (!auths || !auths->num) { + return 0; + } + + if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { + return -1; + } + + ast_join_delim(*buf, MAX_OBJECT_FIELD, auths->names, auths->num, ','); + return 0; +} + +static int inbound_auths_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + return ast_sip_auths_to_str(&endpoint->inbound_auths, buf); +} + +static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + return ast_sip_auths_to_str(&endpoint->outbound_auths, buf); +} + static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -362,6 +441,20 @@ static int ident_handler(const struct aco_option *opt, struct ast_variable *var, return 0; } +static int ident_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + switch (endpoint->ident_method) { + case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME : + *buf = "username"; break; + default: + return 0; + } + + *buf = ast_strdup(*buf); + return 0; +} + static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -378,6 +471,20 @@ static int direct_media_method_handler(const struct aco_option *opt, struct ast_ return 0; } +static const char *id_configuration_refresh_methods[] = { + [AST_SIP_SESSION_REFRESH_METHOD_INVITE] = "invite", + [AST_SIP_SESSION_REFRESH_METHOD_UPDATE] = "update" +}; + +static int direct_media_method_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + if (ARRAY_IN_BOUNDS(endpoint->id.refresh_method, id_configuration_refresh_methods)) { + *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]); + } + return 0; +} + static int connected_line_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -394,6 +501,13 @@ static int connected_line_method_handler(const struct aco_option *opt, struct as return 0; } +static int connected_line_method_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]); + return 0; +} + static int direct_media_glare_mitigation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -413,6 +527,22 @@ static int direct_media_glare_mitigation_handler(const struct aco_option *opt, s return 0; } +static const char *direct_media_glare_mitigation_map[] = { + [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE] = "none", + [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING] = "outgoing", + [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING] = "incoming" +}; + +static int direct_media_glare_mitigation_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + if (ARRAY_IN_BOUNDS(endpoint->media.direct_media.glare_mitigation, direct_media_glare_mitigation_map)) { + *buf = ast_strdup(direct_media_glare_mitigation_map[endpoint->media.direct_media.glare_mitigation]); + } + + return 0; +} + static int caller_id_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -437,6 +567,29 @@ static int caller_id_handler(const struct aco_option *opt, struct ast_variable * return 0; } +static int caller_id_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + const char *name = S_COR(endpoint->id.self.name.valid, + endpoint->id.self.name.str, NULL); + const char *number = S_COR(endpoint->id.self.number.valid, + endpoint->id.self.number.str, NULL); + + /* make sure size is at least 10 - that should cover the "<unknown>" + case as well as any additional formatting characters added in + the name and/or number case. */ + int size = 10; + size += name ? strlen(name) : 0; + size += number ? strlen(number) : 0; + + if (!(*buf = ast_calloc(size + 1, sizeof(char)))) { + return -1; + } + + ast_callerid_merge(*buf, size + 1, name, number, NULL); + return 0; +} + static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -449,6 +602,16 @@ static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_va return 0; } +static int caller_id_privacy_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + const char *presentation = ast_named_caller_presentation( + endpoint->id.self.name.presentation); + + *buf = ast_strdup(presentation); + return 0; +} + static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -456,6 +619,13 @@ static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variab return endpoint->id.self.tag ? 0 : -1; } +static int caller_id_tag_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(endpoint->id.self.tag); + return 0; +} + static int media_encryption_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { struct ast_sip_endpoint *endpoint = obj; @@ -474,6 +644,23 @@ static int media_encryption_handler(const struct aco_option *opt, struct ast_var return 0; } +static const char *media_encryption_map[] = { + [AST_SIP_MEDIA_TRANSPORT_INVALID] = "invalid", + [AST_SIP_MEDIA_ENCRYPT_NONE] = "none", + [AST_SIP_MEDIA_ENCRYPT_SDES] = "sdes", + [AST_SIP_MEDIA_ENCRYPT_DTLS] = "dtls", +}; + +static int media_encryption_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + if (ARRAY_IN_BOUNDS(endpoint->media.rtp.encryption, media_encryption_map)) { + *buf = ast_strdup(media_encryption_map[ + endpoint->media.rtp.encryption]); + } + return 0; +} + static int group_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -494,6 +681,30 @@ static int group_handler(const struct aco_option *opt, return 0; } +static int callgroup_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { + return -1; + } + + ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.callgroup); + return 0; +} + +static int pickupgroup_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) { + return -1; + } + + ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.pickupgroup); + return 0; +} + static int named_groups_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -516,6 +727,26 @@ static int named_groups_handler(const struct aco_option *opt, return 0; } +static int named_callgroups_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); + + ast_print_namedgroups(&str, endpoint->pickup.named_callgroups); + *buf = ast_strdup(ast_str_buffer(str)); + return 0; +} + +static int named_pickupgroups_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free); + + ast_print_namedgroups(&str, endpoint->pickup.named_pickupgroups); + *buf = ast_strdup(ast_str_buffer(str)); + return 0; +} + static int dtls_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -535,6 +766,72 @@ static int dtls_handler(const struct aco_option *opt, return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, name, var->value); } +static int dtlsverify_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(AST_YESNO(endpoint->media.rtp.dtls_cfg.verify)); + return 0; +} + +static int dtlsrekey_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + + return ast_asprintf( + buf, "%d", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1; +} + +static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.certfile); + return 0; +} + +static int dtlsprivatekey_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.pvtfile); + return 0; +} + +static int dtlscipher_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cipher); + return 0; +} + +static int dtlscafile_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cafile); + return 0; +} + +static int dtlscapath_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.capath); + return 0; +} + +static const char *ast_rtp_dtls_setup_map[] = { + [AST_RTP_DTLS_SETUP_ACTIVE] = "active", + [AST_RTP_DTLS_SETUP_PASSIVE] = "passive", + [AST_RTP_DTLS_SETUP_ACTPASS] = "actpass", + [AST_RTP_DTLS_SETUP_HOLDCONN] = "holdconn", +}; + +static int dtlssetup_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.default_setup, ast_rtp_dtls_setup_map)) { + *buf = ast_strdup(ast_rtp_dtls_setup_map[endpoint->media.rtp.dtls_cfg.default_setup]); + } + return 0; +} + static int t38udptl_ec_handler(const struct aco_option *opt, struct ast_variable *var, void *obj) { @@ -553,6 +850,22 @@ static int t38udptl_ec_handler(const struct aco_option *opt, return 0; } +static const char *ast_t38_ec_modes_map[] = { + [UDPTL_ERROR_CORRECTION_NONE] = "none", + [UDPTL_ERROR_CORRECTION_FEC] = "fec", + [UDPTL_ERROR_CORRECTION_REDUNDANCY] = "redundancy" +}; + +static int t38udptl_ec_to_str(const void *obj, const intptr_t *args, char **buf) +{ + const struct ast_sip_endpoint *endpoint = obj; + if (ARRAY_IN_BOUNDS(endpoint->media.t38.error_correction, ast_t38_ec_modes_map)) { + *buf = ast_strdup(ast_t38_ec_modes_map[ + endpoint->media.t38.error_correction]); + } + return 0; +} + static void *sip_nat_hook_alloc(const char *name) { return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL); @@ -631,12 +944,305 @@ static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *o return 0; } -int ast_res_pjsip_initialize_configuration(void) +static const char *get_device_state(const struct ast_sip_endpoint *endpoint) +{ + char device[MAX_OBJECT_FIELD]; + + snprintf(device, MAX_OBJECT_FIELD, "PJSIP/%s", ast_sorcery_object_get_id(endpoint)); + return ast_devstate2str(ast_device_state(device)); +} + +static struct ast_endpoint_snapshot *sip_get_endpoint_snapshot( + const struct ast_sip_endpoint *endpoint) +{ + return ast_endpoint_latest_snapshot( + ast_endpoint_get_tech(endpoint->persistent), + ast_endpoint_get_resource(endpoint->persistent)); +} + +int ast_sip_for_each_channel_snapshot( + const struct ast_endpoint_snapshot *endpoint_snapshot, + on_channel_snapshot_t 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())) { + 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))) { + continue; + } + + if (on_channel_snapshot( + snapshot, num == (num_channels - 1), arg)) { + return -1; + } + } + return 0; +} + +static int active_channels_to_str_cb(const struct ast_channel_snapshot *snapshot, + int last, void *arg) +{ + struct ast_str **buf = arg; + if (last) { + ast_str_append(buf, 0, "%s", snapshot->name); + } else { + ast_str_append(buf, 0, "%s,", snapshot->name); + } + return 0; +} + +static void active_channels_to_str(const struct ast_sip_endpoint *endpoint, + struct ast_str **str) +{ + + RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, + sip_get_endpoint_snapshot(endpoint), ao2_cleanup); + + if (endpoint_snapshot) { + return; + } + + ast_sip_for_each_channel_snapshot(endpoint_snapshot, + active_channels_to_str_cb, str); +} + +#define AMI_DEFAULT_STR_SIZE 512 + +struct ast_str *ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami) +{ + struct ast_str *buf = ast_str_create(AMI_DEFAULT_STR_SIZE); + + if (!(buf)) { + astman_send_error_va(ami->s, ami->m, "Unable create event " + "for %s\n", event); + return NULL; + } + + ast_str_set(&buf, 0, "Event: %s\r\n", event); + return buf; +} + +static void sip_sorcery_object_ami_set_type_name(const void *obj, struct ast_str **buf) +{ + ast_str_append(buf, 0, "ObjectType: %s\r\n", + ast_sorcery_object_get_type(obj)); + ast_str_append(buf, 0, "ObjectName: %s\r\n", + ast_sorcery_object_get_id(obj)); +} + +int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf) +{ + RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create( + ast_sip_get_sorcery(), obj), ast_variables_destroy); + struct ast_variable *i; + + if (!objset) { + return -1; + } + + sip_sorcery_object_ami_set_type_name(obj, buf); + + for (i = objset; i; i = i->next) { + RAII_VAR(char *, camel, ast_to_camel_case(i->name), ast_free); + ast_str_append(buf, 0, "%s: %s\r\n", camel, i->value); + } + + return 0; +} + +static int sip_endpoints_aors_ami(void *obj, void *arg, int flags) +{ + const struct ast_sip_aor *aor = obj; + struct ast_str **buf = arg; + + ast_str_append(buf, 0, "Contacts: "); + ast_sip_for_each_contact(aor, ast_sip_contact_to_str, arg); + ast_str_append(buf, 0, "\r\n"); + + return 0; +} + +static int sip_endpoint_to_ami(const struct ast_sip_endpoint *endpoint, + struct ast_str **buf) +{ + if (ast_sip_sorcery_object_to_ami(endpoint, buf)) { + return -1; + } + + ast_str_append(buf, 0, "DeviceState: %s\r\n", + get_device_state(endpoint)); + + ast_str_append(buf, 0, "ActiveChannels: "); + active_channels_to_str(endpoint, buf); + ast_str_append(buf, 0, "\r\n"); + + return 0; +} + +static int format_ami_endpoint(const struct ast_sip_endpoint *endpoint, + struct ast_sip_ami *ami) +{ + RAII_VAR(struct ast_str *, buf, + ast_sip_create_ami_event("EndpointDetail", ami), ast_free); + + if (!buf) { + return -1; + } + + sip_endpoint_to_ami(endpoint, &buf); + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + return 0; +} + +#define AMI_SHOW_ENDPOINTS "PJSIPShowEndpoints" +#define AMI_SHOW_ENDPOINT "PJSIPShowEndpoint" + +static int ami_show_endpoint(struct mansession *s, const struct message *m) +{ + struct ast_sip_ami ami = { .s = s, .m = m }; + RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup); + const char *endpoint_name = astman_get_header(m, "Endpoint"); + int count = 0; + + if (ast_strlen_zero(endpoint_name)) { + astman_send_error_va(s, m, "%s requires an endpoint name\n", + AMI_SHOW_ENDPOINT); + return 0; + } + + if (!strncasecmp(endpoint_name, "pjsip/", 6)) { + endpoint_name += 6; + } + + if (!(endpoint = ast_sorcery_retrieve_by_id( + ast_sip_get_sorcery(), "endpoint", endpoint_name))) { + astman_send_error_va(s, m, "Unable to retrieve endpoint %s\n", + endpoint_name); + return -1; + } + + astman_send_listack(s, m, "Following are Events for each object " + "associated with the the Endpoint", "start"); + + /* the endpoint detail needs to always come first so apply as such */ + if (format_ami_endpoint(endpoint, &ami) || + ast_sip_format_endpoint_ami(endpoint, &ami, &count)) { + astman_send_error_va(s, m, "Unable to format endpoint %s\n", + endpoint_name); + } + + astman_append(s, + "Event: EndpointDetailComplete\r\n" + "EventList: Complete\r\n" + "ListItems: %d\r\n\r\n", count + 1); + return 0; +} + +static int format_str_append_auth(const struct ast_sip_auth_array *auths, + struct ast_str **buf) +{ + char *str = NULL; + if (ast_sip_auths_to_str(auths, &str)) { + return -1; + } + ast_str_append(buf, 0, "%s", str ? str : ""); + ast_free(str); + return 0; +} + +static int format_ami_endpoints(void *obj, void *arg, int flags) +{ + + struct ast_sip_endpoint *endpoint = obj; + struct ast_sip_ami *ami = arg; + RAII_VAR(struct ast_str *, buf, + ast_sip_create_ami_event("EndpointList", ami), ast_free); + + if (!buf) { + return -1; + } + + sip_sorcery_object_ami_set_type_name(endpoint, &buf); + ast_str_append(&buf, 0, "Transport: %s\r\n", + endpoint->transport); + ast_str_append(&buf, 0, "Aor: %s\r\n", + endpoint->aors); + + ast_str_append(&buf, 0, "Auths: "); + format_str_append_auth(&endpoint->inbound_auths, &buf); + ast_str_append(&buf, 0, "\r\n"); + + ast_str_append(&buf, 0, "OutboundAuths: "); + format_str_append_auth(&endpoint->outbound_auths, &buf); + ast_str_append(&buf, 0, "\r\n"); + + ast_sip_for_each_aor(endpoint->aors, + sip_endpoints_aors_ami, &buf); + + ast_str_append(&buf, 0, "DeviceState: %s\r\n", + get_device_state(endpoint)); + + ast_str_append(&buf, 0, "ActiveChannels: "); + active_channels_to_str(endpoint, &buf); + ast_str_append(&buf, 0, "\r\n"); + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + return 0; +} + +static int ami_show_endpoints(struct mansession *s, const struct message *m) +{ + struct ast_sip_ami ami = { .s = s, .m = m }; + RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup); + int num; + + endpoints = ast_sip_get_endpoints(); + if (!endpoints) { + return -1; + } + + if (!(num = ao2_container_count(endpoints))) { + astman_send_error(s, m, "No endpoints found\n"); + return 0; + } + + astman_send_listack(s, m, "A listing of Endpoints follows, " + "presented as EndpointList events", "start"); + + ao2_callback(endpoints, OBJ_NODATA, format_ami_endpoints, &ami); + + astman_append(s, + "Event: EndpointListComplete\r\n" + "EventList: Complete\r\n" + "ListItems: %d\r\n\r\n", num); + return 0; +} + +int ast_res_pjsip_initialize_configuration(const struct ast_module_info *ast_module_info) { if (ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands))) { return -1; } + 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; + } + if (!(persistent_endpoints = ao2_container_alloc(PERSISTENT_BUCKETS, persistent_endpoint_hash, persistent_endpoint_cmp))) { return -1; } @@ -672,7 +1278,7 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.prefs, media.codecs)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.prefs, media.codecs)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ice_support)); @@ -682,23 +1288,23 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_min_se", "90", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, extensions.timer.min_se)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "timers_sess_expires", "1800", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, extensions.timer.sess_expires)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.address)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "connected_line_method", "invite", connected_line_method_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_glare_mitigation", "none", direct_media_glare_mitigation_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, direct_media_method_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "connected_line_method", "invite", connected_line_method_handler, connected_line_method_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_glare_mitigation", "none", direct_media_glare_mitigation_handler, direct_media_glare_mitigation_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "disable_direct_media_on_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.disable_on_nat)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "", caller_id_privacy_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "", caller_id_privacy_handler, caller_id_privacy_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_inbound)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_outbound)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_pai)); @@ -706,17 +1312,17 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "device_state_busy_at", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, devicestate_busy_at)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.enabled)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat)); @@ -738,14 +1344,14 @@ int ast_res_pjsip_initialize_configuration(void) ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser)); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine)); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, NULL, 0, 0); - ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, NULL, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "", dtls_handler, dtlsverify_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "", dtls_handler, dtlsrekey_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, 0, 0); + ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, 0, 0); ast_sorcery_object_field_register(sip_sorcery, "endpoint", "srtp_tag_32", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.srtp_tag_32)); if (ast_sip_initialize_sorcery_transport(sip_sorcery)) { @@ -793,6 +1399,8 @@ int ast_res_pjsip_initialize_configuration(void) void ast_res_pjsip_destroy_configuration(void) { ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands)); + ast_manager_unregister(AMI_SHOW_ENDPOINT); + ast_manager_unregister(AMI_SHOW_ENDPOINTS); ast_sorcery_unref(sip_sorcery); } |