diff options
Diffstat (limited to 'res/res_pjsip/pjsip_configuration.c')
-rw-r--r-- | res/res_pjsip/pjsip_configuration.c | 664 |
1 files changed, 636 insertions, 28 deletions
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); } |