From: Sungtae Kim Date: Sun, 14 Jan 2018 18:33:15 +0000 (+0100) Subject: res_pjsip: Add AMI action 'PJSIPShowContacts' X-Git-Tag: 16.0.0-rc1~392^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5b8e71ab9fe3577c43c893133cf62334ae056138;p=thirdparty%2Fasterisk.git res_pjsip: Add AMI action 'PJSIPShowContacts' Add an AMI action which provides information on all configured Contacts. ASTERISK-27581 Change-Id: I2eed42c74bbc725fad26b8b33b1a5b3161950c73 --- diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 0311dfd4b3..1f658323d8 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -2362,6 +2362,77 @@ + + + Provide details about a contact section. + + + The object's type. This will always be 'contact'. + + + The name of this object. + + + IP address of the last Via header in REGISTER request. + Will only appear in the event if available. + + + Port number of the last Via header in REGISTER request. + Will only appear in the event if available. + + + The elapsed time in decimal seconds after which an OPTIONS + message is sent before the contact is considered unavailable. + + + Content of the Call-ID header in REGISTER request. + Will only appear in the event if available. + + + Asterisk Server name. + + + If true delete the contact on Asterisk restart/boot. + + + The Path header received on the REGISTER. + + + The name of the endpoint associated with this information. + + + A boolean indicating whether a qualify should be authenticated. + + + This contact's URI. + + + The interval in seconds at which the contact will be qualified. + + + Content of the User-Agent header in REGISTER request + + + Absolute time that this contact is no longer valid after + + + The contact's outbound proxy. + + + This contact's status. + + + + + + + + + The round trip time in microseconds. + + + + Provide details about a contact's status. @@ -2378,6 +2449,7 @@ + @@ -2574,6 +2646,33 @@ + + + Lists PJSIP Contacts. + + + + Provides a listing of all Contacts. For each Contact a ContactList + event is raised that contains relevant attributes and status information. + Once all contacts have been listed a ContactListComplete event + is issued. + + + + + + + + + Provide final information about a contact list. + + + + + + + + ***/ diff --git a/res/res_pjsip/pjsip_options.c b/res/res_pjsip/pjsip_options.c index 9d7402b2a4..3465eae34a 100644 --- a/res/res_pjsip/pjsip_options.c +++ b/res/res_pjsip/pjsip_options.c @@ -929,6 +929,91 @@ static int ami_contact_cb(void *obj, void *arg, int flags) return 0; } +static struct ao2_container *get_all_contacts(void) +{ + struct ao2_container *contacts; + + contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact", + AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL); + + return contacts; +} + +static int sip_contact_to_ami(const struct ast_sip_contact *contact, + struct ast_str **buf) +{ + return ast_sip_sorcery_object_to_ami(contact, buf); +} + +static int format_ami_contactlist_handler(void *obj, void *arg, int flags) +{ + struct ast_sip_contact *contact = obj; + struct ast_sip_ami *ami = arg; + struct ast_str *buf; + struct ast_sip_contact_status *status; + + buf = ast_sip_create_ami_event("ContactList", ami); + + if (!buf) { + return CMP_STOP; + } + + if (sip_contact_to_ami(contact, &buf)) { + ast_free(buf); + return CMP_STOP; + } + + /* Add extra info */ + status = ast_sorcery_retrieve_by_id( + ast_sip_get_sorcery(), CONTACT_STATUS, + ast_sorcery_object_get_id(contact)); + ast_str_append(&buf, 0, "Status: %s\r\n", + ast_sip_get_contact_status_label(status ? status->status : UNKNOWN)); + if (!status || status->status == UNKNOWN) { + ast_str_append(&buf, 0, "RoundtripUsec: N/A\r\n"); + } else { + ast_str_append(&buf, 0, "RoundtripUsec: %" PRId64 "\r\n", status->rtt); + } + + astman_append(ami->s, "%s\r\n", ast_str_buffer(buf)); + + ami->count++; + + ast_free(buf); + + return 0; +} + +static int ami_show_contacts(struct mansession *s, const struct message *m) +{ + struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), }; + struct ao2_container *contacts; + + contacts = get_all_contacts(); + if (!contacts) { + astman_send_error(s, m, "Could not get Contacts\n"); + return 0; + } + + if (!ao2_container_count(contacts)) { + astman_send_error(s, m, "No Contacts found\n"); + ao2_ref(contacts, -1); + return 0; + } + + astman_send_listack(s, m, "A listing of Contacts follows, presented as ContactList events", + "start"); + + ao2_callback(contacts, OBJ_NODATA, format_ami_contactlist_handler, &ami); + + astman_send_list_complete_start(s, m, "ContactListComplete", ami.count); + astman_send_list_complete_end(s); + + ao2_ref(contacts, -1); + + return 0; +} + static int ami_sip_qualify(struct mansession *s, const struct message *m) { const char *endpoint_name = astman_get_header(m, "Endpoint"); @@ -1479,6 +1564,7 @@ int ast_res_pjsip_init_options_handling(int reload) internal_sip_register_endpoint_formatter(&contact_status_formatter); ast_manager_register_xml("PJSIPQualify", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_sip_qualify); + ast_manager_register_xml("PJSIPShowContacts", EVENT_FLAG_SYSTEM, ami_show_contacts); ast_cli_register_multiple(cli_options, ARRAY_LEN(cli_options)); update_all_unqualified_endpoints(); @@ -1491,6 +1577,7 @@ void ast_res_pjsip_cleanup_options_handling(void) { ast_cli_unregister_multiple(cli_options, ARRAY_LEN(cli_options)); ast_manager_unregister("PJSIPQualify"); + ast_manager_unregister("PJSIPShowContacts"); internal_sip_unregister_endpoint_formatter(&contact_status_formatter); ast_sorcery_observer_remove(ast_sip_get_sorcery(), "aor", &observer_callbacks_options);