4 * Created on: Jan 25, 2013
13 #include "asterisk/res_pjsip.h"
14 #include "include/res_pjsip_private.h"
15 #include "asterisk/res_pjsip_cli.h"
16 #include "asterisk/acl.h"
17 #include "asterisk/manager.h"
18 #include "asterisk/astobj2.h"
19 #include "asterisk/utils.h"
20 #include "asterisk/sorcery.h"
21 #include "asterisk/callerid.h"
22 #include "asterisk/test.h"
24 /*! \brief Number of buckets for persistent endpoint information */
25 #define PERSISTENT_BUCKETS 53
27 /*! \brief Persistent endpoint information */
28 struct sip_persistent_endpoint {
29 /*! \brief Asterisk endpoint itself */
30 struct ast_endpoint *endpoint;
31 /*! \brief AORs that we should react to */
35 /*! \brief Container for persistent endpoint information */
36 static struct ao2_container *persistent_endpoints;
38 static struct ast_sorcery *sip_sorcery;
40 /*! \brief Hashing function for persistent endpoint information */
41 static int persistent_endpoint_hash(const void *obj, const int flags)
43 const struct sip_persistent_endpoint *persistent = obj;
44 const char *id = (flags & OBJ_KEY ? obj : ast_endpoint_get_resource(persistent->endpoint));
46 return ast_str_hash(id);
49 /*! \brief Comparison function for persistent endpoint information */
50 static int persistent_endpoint_cmp(void *obj, void *arg, int flags)
52 const struct sip_persistent_endpoint *persistent1 = obj;
53 const struct sip_persistent_endpoint *persistent2 = arg;
54 const char *id = (flags & OBJ_KEY ? arg : ast_endpoint_get_resource(persistent2->endpoint));
56 return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
59 /*! \brief Structure for communicating contact status to
60 * persistent_endpoint_update_state from the contact/contact_status
63 struct sip_contact_status {
65 enum ast_sip_contact_status_type status;
69 /*! \brief Callback function for changing the state of an endpoint */
70 static int persistent_endpoint_update_state(void *obj, void *arg, void *data, int flags)
72 struct sip_persistent_endpoint *persistent = obj;
73 struct ast_endpoint *endpoint = persistent->endpoint;
75 struct sip_contact_status *status = data;
76 struct ao2_container *contacts;
77 struct ast_json *blob;
78 struct ao2_iterator i;
79 struct ast_sip_contact *contact;
80 enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
82 if (!ast_strlen_zero(aor)) {
83 if (!strstr(persistent->aors, aor)) {
89 snprintf(rtt, 31, "%" PRId64, status->rtt);
90 blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
91 "contact_status", ast_sip_get_contact_status_label(status->status),
94 "roundtrip_usec", rtt,
95 "endpoint_name", ast_endpoint_get_resource(endpoint));
96 ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
100 /* Find all the contacts for this endpoint. If ANY are available,
101 * mark the endpoint as ONLINE.
103 contacts = ast_sip_location_retrieve_contacts_from_aor_list(persistent->aors);
105 i = ao2_iterator_init(contacts, 0);
106 while (state == AST_ENDPOINT_OFFLINE && (contact = ao2_iterator_next(&i))) {
107 struct ast_sip_contact_status *contact_status;
108 const char *contact_id = ast_sorcery_object_get_id(contact);
110 contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
111 CONTACT_STATUS, contact_id);
113 if (contact_status && contact_status->status != UNAVAILABLE) {
114 state = AST_ENDPOINT_ONLINE;
116 ao2_cleanup(contact_status);
117 ao2_ref(contact, -1);
119 ao2_iterator_destroy(&i);
120 ao2_ref(contacts, -1);
123 /* If there was no state change, don't publish anything. */
124 if (ast_endpoint_get_state(endpoint) == state) {
128 if (state == AST_ENDPOINT_ONLINE) {
129 ast_endpoint_set_state(endpoint, AST_ENDPOINT_ONLINE);
130 blob = ast_json_pack("{s: s}", "peer_status", "Reachable");
131 ast_verb(1, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint));
133 ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE);
134 blob = ast_json_pack("{s: s}", "peer_status", "Unreachable");
135 ast_verb(1, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint));
138 ast_endpoint_blob_publish(endpoint, ast_endpoint_state_type(), blob);
139 ast_json_unref(blob);
140 ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint));
145 /*! \brief Function called when stuff relating to a contact happens (created/deleted) */
146 static void persistent_endpoint_contact_created_observer(const void *object)
148 const struct ast_sip_contact *contact = object;
149 char *id = ast_strdupa(ast_sorcery_object_get_id(contact));
151 char *contact_uri = NULL;
152 struct sip_contact_status status;
155 /* Dynamic contacts are delimited with ";@" and static ones with "@@" */
156 if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
163 status.uri = contact_uri;
164 status.status = CREATED;
167 ast_verb(1, "Contact %s/%s has been created\n", aor, contact_uri);
169 ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
172 /*! \brief Function called when stuff relating to a contact happens (created/deleted) */
173 static void persistent_endpoint_contact_deleted_observer(const void *object)
175 char *id = ast_strdupa(ast_sorcery_object_get_id(object));
177 char *contact_uri = NULL;
178 struct sip_contact_status status;
181 /* Dynamic contacts are delimited with ";@" and static ones with "@@" */
182 if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
189 ast_verb(1, "Contact %s/%s has been deleted\n", aor, contact_uri);
191 status.uri = contact_uri;
192 status.status = REMOVED;
195 ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
198 /*! \brief Observer for contacts so state can be updated on respective endpoints */
199 static const struct ast_sorcery_observer state_contact_observer = {
200 .created = persistent_endpoint_contact_created_observer,
201 .deleted = persistent_endpoint_contact_deleted_observer,
204 /*! \brief Function called when stuff relating to a contact status happens (updated) */
205 static void persistent_endpoint_contact_status_observer(const void *object)
207 const struct ast_sip_contact_status *contact_status = object;
208 char *id = ast_strdupa(ast_sorcery_object_get_id(object));
210 char *contact_uri = NULL;
211 struct sip_contact_status status;
213 /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
214 if (contact_status->rtt_start.tv_sec > 0) {
219 /* Dynamic contacts are delimited with ";@" and static ones with "@@" */
220 if ((contact_uri = strstr(id, ";@")) || (contact_uri = strstr(id, "@@"))) {
227 if (contact_status->status == contact_status->last_status) {
228 ast_debug(3, "Contact %s status didn't change: %s, RTT: %.3f msec\n",
229 contact_uri, ast_sip_get_contact_status_label(contact_status->status),
230 contact_status->rtt / 1000.0);
233 ast_verb(1, "Contact %s/%s is now %s. RTT: %.3f msec\n", aor, contact_uri,
234 ast_sip_get_contact_status_label(contact_status->status),
235 contact_status->rtt / 1000.0);
238 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
241 ast_sorcery_object_get_id(contact_status),
242 ast_sip_get_contact_status_label(contact_status->status));
244 status.uri = contact_uri;
245 status.status = contact_status->status;
246 status.rtt = contact_status->rtt;
248 ao2_callback_data(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, aor, &status);
251 /*! \brief Observer for contacts so state can be updated on respective endpoints */
252 static const struct ast_sorcery_observer state_contact_status_observer = {
253 .updated = persistent_endpoint_contact_status_observer,
256 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
258 struct ast_sip_endpoint *endpoint = obj;
260 if (!strcasecmp(var->value, "rfc4733")) {
261 endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
262 } else if (!strcasecmp(var->value, "inband")) {
263 endpoint->dtmf = AST_SIP_DTMF_INBAND;
264 } else if (!strcasecmp(var->value, "info")) {
265 endpoint->dtmf = AST_SIP_DTMF_INFO;
266 } else if (!strcasecmp(var->value, "auto")) {
267 endpoint->dtmf = AST_SIP_DTMF_AUTO;
268 } else if (!strcasecmp(var->value, "none")) {
269 endpoint->dtmf = AST_SIP_DTMF_NONE;
277 static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
279 const struct ast_sip_endpoint *endpoint = obj;
281 switch (endpoint->dtmf) {
282 case AST_SIP_DTMF_RFC_4733 :
283 *buf = "rfc4733"; break;
284 case AST_SIP_DTMF_INBAND :
285 *buf = "inband"; break;
286 case AST_SIP_DTMF_INFO :
287 *buf = "info"; break;
288 case AST_SIP_DTMF_AUTO :
289 *buf = "auto"; break;
294 *buf = ast_strdup(*buf);
298 static int prack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
300 struct ast_sip_endpoint *endpoint = obj;
303 endpoint->extensions.flags &= ~(PJSIP_INV_SUPPORT_100REL | PJSIP_INV_REQUIRE_100REL);
305 if (ast_true(var->value)) {
306 endpoint->extensions.flags |= PJSIP_INV_SUPPORT_100REL;
307 } else if (!strcasecmp(var->value, "required")) {
308 endpoint->extensions.flags |= PJSIP_INV_REQUIRE_100REL;
309 } else if (!ast_false(var->value)){
316 static int prack_to_str(const void *obj, const intptr_t *args, char **buf)
318 const struct ast_sip_endpoint *endpoint = obj;
320 if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_100REL) {
322 } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_100REL) {
328 *buf = ast_strdup(*buf);
332 static int timers_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
334 struct ast_sip_endpoint *endpoint = obj;
337 endpoint->extensions.flags &= ~(PJSIP_INV_SUPPORT_TIMER | PJSIP_INV_REQUIRE_TIMER
338 | PJSIP_INV_ALWAYS_USE_TIMER);
340 /* set only the specified flag and let pjsip normalize if needed */
341 if (ast_true(var->value)) {
342 endpoint->extensions.flags |= PJSIP_INV_SUPPORT_TIMER;
343 } else if (!strcasecmp(var->value, "required")) {
344 endpoint->extensions.flags |= PJSIP_INV_REQUIRE_TIMER;
345 } else if (!strcasecmp(var->value, "always") || !strcasecmp(var->value, "forced")) {
346 endpoint->extensions.flags |= PJSIP_INV_ALWAYS_USE_TIMER;
347 } else if (!ast_false(var->value)) {
354 static int timers_to_str(const void *obj, const intptr_t *args, char **buf)
356 const struct ast_sip_endpoint *endpoint = obj;
358 if (endpoint->extensions.flags & PJSIP_INV_ALWAYS_USE_TIMER) {
360 } else if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_TIMER) {
362 } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_TIMER) {
368 *buf = ast_strdup(*buf);
372 void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *auths)
381 size = AST_VECTOR_SIZE(auths);
383 for (i = 0; i < size; ++i) {
384 const char *name = AST_VECTOR_REMOVE_UNORDERED(auths, 0);
385 ast_free((char *) name);
387 AST_VECTOR_FREE(auths);
390 int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *value)
392 char *auth_names = ast_strdupa(value);
395 ast_assert(auths != NULL);
397 if (AST_VECTOR_SIZE(auths)) {
398 ast_sip_auth_vector_destroy(auths);
400 if (AST_VECTOR_INIT(auths, 1)) {
404 while ((val = strsep(&auth_names, ","))) {
405 val = ast_strdup(val);
409 if (AST_VECTOR_APPEND(auths, val)) {
416 ast_sip_auth_vector_destroy(auths);
420 static int inbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
422 struct ast_sip_endpoint *endpoint = obj;
424 return ast_sip_auth_vector_init(&endpoint->inbound_auths, var->value);
427 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
429 struct ast_sip_endpoint *endpoint = obj;
431 return ast_sip_auth_vector_init(&endpoint->outbound_auths, var->value);
434 int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf)
436 if (!auths || !AST_VECTOR_SIZE(auths)) {
440 if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
444 /* I feel like accessing the vector's elem array directly is cheating...*/
445 ast_join_delim(*buf, MAX_OBJECT_FIELD, auths->elems, AST_VECTOR_SIZE(auths), ',');
449 static int inbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
451 const struct ast_sip_endpoint *endpoint = obj;
452 return ast_sip_auths_to_str(&endpoint->inbound_auths, buf);
455 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
457 const struct ast_sip_endpoint *endpoint = obj;
458 return ast_sip_auths_to_str(&endpoint->outbound_auths, buf);
461 static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
463 struct ast_sip_endpoint *endpoint = obj;
464 char *idents = ast_strdupa(var->value);
467 while ((val = strsep(&idents, ","))) {
468 if (!strcasecmp(val, "username")) {
469 endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME;
471 ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n",
472 val, ast_sorcery_object_get_id(endpoint));
479 static int ident_to_str(const void *obj, const intptr_t *args, char **buf)
481 const struct ast_sip_endpoint *endpoint = obj;
482 switch (endpoint->ident_method) {
483 case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME :
484 *buf = "username"; break;
489 *buf = ast_strdup(*buf);
493 static int redirect_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
495 struct ast_sip_endpoint *endpoint = obj;
497 if (!strcasecmp(var->value, "user")) {
498 endpoint->redirect_method = AST_SIP_REDIRECT_USER;
499 } else if (!strcasecmp(var->value, "uri_core")) {
500 endpoint->redirect_method = AST_SIP_REDIRECT_URI_CORE;
501 } else if (!strcasecmp(var->value, "uri_pjsip")) {
502 endpoint->redirect_method = AST_SIP_REDIRECT_URI_PJSIP;
504 ast_log(LOG_ERROR, "Unrecognized redirect method %s specified for endpoint %s\n",
505 var->value, ast_sorcery_object_get_id(endpoint));
512 static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
514 struct ast_sip_endpoint *endpoint = obj;
516 if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
517 endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
518 } else if (!strcasecmp(var->value, "update")) {
519 endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
521 ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
522 var->value, var->name, ast_sorcery_object_get_id(endpoint));
528 static const char *id_configuration_refresh_methods[] = {
529 [AST_SIP_SESSION_REFRESH_METHOD_INVITE] = "invite",
530 [AST_SIP_SESSION_REFRESH_METHOD_UPDATE] = "update"
533 static int direct_media_method_to_str(const void *obj, const intptr_t *args, char **buf)
535 const struct ast_sip_endpoint *endpoint = obj;
536 if (ARRAY_IN_BOUNDS(endpoint->id.refresh_method, id_configuration_refresh_methods)) {
537 *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
542 static int connected_line_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
544 struct ast_sip_endpoint *endpoint = obj;
546 if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
547 endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
548 } else if (!strcasecmp(var->value, "update")) {
549 endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
551 ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
552 var->value, var->name, ast_sorcery_object_get_id(endpoint));
558 static int connected_line_method_to_str(const void *obj, const intptr_t *args, char **buf)
560 const struct ast_sip_endpoint *endpoint = obj;
561 *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
565 static int direct_media_glare_mitigation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
567 struct ast_sip_endpoint *endpoint = obj;
569 if (!strcasecmp(var->value, "none")) {
570 endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE;
571 } else if (!strcasecmp(var->value, "outgoing")) {
572 endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING;
573 } else if (!strcasecmp(var->value, "incoming")) {
574 endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING;
576 ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
577 var->value, var->name, ast_sorcery_object_get_id(endpoint));
584 static const char *direct_media_glare_mitigation_map[] = {
585 [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE] = "none",
586 [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING] = "outgoing",
587 [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING] = "incoming"
590 static int direct_media_glare_mitigation_to_str(const void *obj, const intptr_t *args, char **buf)
592 const struct ast_sip_endpoint *endpoint = obj;
593 if (ARRAY_IN_BOUNDS(endpoint->media.direct_media.glare_mitigation, direct_media_glare_mitigation_map)) {
594 *buf = ast_strdup(direct_media_glare_mitigation_map[endpoint->media.direct_media.glare_mitigation]);
600 static int caller_id_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
602 struct ast_sip_endpoint *endpoint = obj;
603 char cid_name[80] = { '\0' };
604 char cid_num[80] = { '\0' };
606 ast_callerid_split(var->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
607 if (!ast_strlen_zero(cid_name)) {
608 endpoint->id.self.name.str = ast_strdup(cid_name);
609 if (!endpoint->id.self.name.str) {
612 endpoint->id.self.name.valid = 1;
614 if (!ast_strlen_zero(cid_num)) {
615 endpoint->id.self.number.str = ast_strdup(cid_num);
616 if (!endpoint->id.self.number.str) {
619 endpoint->id.self.number.valid = 1;
624 static int caller_id_to_str(const void *obj, const intptr_t *args, char **buf)
626 const struct ast_sip_endpoint *endpoint = obj;
627 const char *name = S_COR(endpoint->id.self.name.valid,
628 endpoint->id.self.name.str, NULL);
629 const char *number = S_COR(endpoint->id.self.number.valid,
630 endpoint->id.self.number.str, NULL);
632 /* make sure size is at least 10 - that should cover the "<unknown>"
633 case as well as any additional formatting characters added in
634 the name and/or number case. */
636 size += name ? strlen(name) : 0;
637 size += number ? strlen(number) : 0;
639 if (!(*buf = ast_calloc(size + 1, sizeof(char)))) {
643 ast_callerid_merge(*buf, size + 1, name, number, NULL);
647 static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
649 struct ast_sip_endpoint *endpoint = obj;
650 int callingpres = ast_parse_caller_presentation(var->value);
651 if (callingpres == -1 && sscanf(var->value, "%d", &callingpres) != 1) {
654 endpoint->id.self.number.presentation = callingpres;
655 endpoint->id.self.name.presentation = callingpres;
659 static int caller_id_privacy_to_str(const void *obj, const intptr_t *args, char **buf)
661 const struct ast_sip_endpoint *endpoint = obj;
662 const char *presentation = ast_named_caller_presentation(
663 endpoint->id.self.name.presentation);
665 *buf = ast_strdup(presentation);
669 static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
671 struct ast_sip_endpoint *endpoint = obj;
672 endpoint->id.self.tag = ast_strdup(var->value);
673 return endpoint->id.self.tag ? 0 : -1;
676 static int caller_id_tag_to_str(const void *obj, const intptr_t *args, char **buf)
678 const struct ast_sip_endpoint *endpoint = obj;
679 *buf = ast_strdup(endpoint->id.self.tag);
683 static int media_encryption_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
685 struct ast_sip_endpoint *endpoint = obj;
687 if (!strcasecmp("no", var->value)) {
688 endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
689 } else if (!strcasecmp("sdes", var->value)) {
690 endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_SDES;
691 } else if (!strcasecmp("dtls", var->value)) {
692 endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
693 ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes");
701 static const char *media_encryption_map[] = {
702 [AST_SIP_MEDIA_TRANSPORT_INVALID] = "invalid",
703 [AST_SIP_MEDIA_ENCRYPT_NONE] = "none",
704 [AST_SIP_MEDIA_ENCRYPT_SDES] = "sdes",
705 [AST_SIP_MEDIA_ENCRYPT_DTLS] = "dtls",
708 static int media_encryption_to_str(const void *obj, const intptr_t *args, char **buf)
710 const struct ast_sip_endpoint *endpoint = obj;
711 if (ARRAY_IN_BOUNDS(endpoint->media.rtp.encryption, media_encryption_map)) {
712 *buf = ast_strdup(media_encryption_map[
713 endpoint->media.rtp.encryption]);
718 static int group_handler(const struct aco_option *opt,
719 struct ast_variable *var, void *obj)
721 struct ast_sip_endpoint *endpoint = obj;
723 if (!strncmp(var->name, "call_group", 10)) {
724 endpoint->pickup.callgroup = ast_get_group(var->value);
725 } else if (!strncmp(var->name, "pickup_group", 12)) {
726 endpoint->pickup.pickupgroup = ast_get_group(var->value);
734 static int callgroup_to_str(const void *obj, const intptr_t *args, char **buf)
736 const struct ast_sip_endpoint *endpoint = obj;
738 if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
742 ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.callgroup);
746 static int pickupgroup_to_str(const void *obj, const intptr_t *args, char **buf)
748 const struct ast_sip_endpoint *endpoint = obj;
750 if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
754 ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.pickupgroup);
758 static int named_groups_handler(const struct aco_option *opt,
759 struct ast_variable *var, void *obj)
761 struct ast_sip_endpoint *endpoint = obj;
763 if (!strncmp(var->name, "named_call_group", 16)) {
764 if (ast_strlen_zero(var->value)) {
765 endpoint->pickup.named_callgroups =
766 ast_unref_namedgroups(endpoint->pickup.named_callgroups);
767 } else if (!(endpoint->pickup.named_callgroups =
768 ast_get_namedgroups(var->value))) {
771 } else if (!strncmp(var->name, "named_pickup_group", 18)) {
772 if (ast_strlen_zero(var->value)) {
773 endpoint->pickup.named_pickupgroups =
774 ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
775 } else if (!(endpoint->pickup.named_pickupgroups =
776 ast_get_namedgroups(var->value))) {
786 static int named_callgroups_to_str(const void *obj, const intptr_t *args, char **buf)
788 const struct ast_sip_endpoint *endpoint = obj;
789 RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
791 ast_print_namedgroups(&str, endpoint->pickup.named_callgroups);
792 *buf = ast_strdup(ast_str_buffer(str));
796 static int named_pickupgroups_to_str(const void *obj, const intptr_t *args, char **buf)
798 const struct ast_sip_endpoint *endpoint = obj;
799 RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
801 ast_print_namedgroups(&str, endpoint->pickup.named_pickupgroups);
802 *buf = ast_strdup(ast_str_buffer(str));
806 static int dtls_handler(const struct aco_option *opt,
807 struct ast_variable *var, void *obj)
809 struct ast_sip_endpoint *endpoint = obj;
810 char *name = ast_strdupa(var->name);
811 char *front, *back, *buf = name;
813 /* strip out underscores in the name */
814 front = strtok_r(buf, "_", &back);
816 int size = strlen(front);
817 ast_copy_string(buf, front, size + 1);
819 front = strtok_r(NULL, "_", &back);
822 return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, name, var->value);
825 static int dtlsverify_to_str(const void *obj, const intptr_t *args, char **buf)
827 const struct ast_sip_endpoint *endpoint = obj;
828 *buf = ast_strdup(AST_YESNO(endpoint->media.rtp.dtls_cfg.verify));
832 static int dtlsrekey_to_str(const void *obj, const intptr_t *args, char **buf)
834 const struct ast_sip_endpoint *endpoint = obj;
837 buf, "%u", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1;
840 static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf)
842 const struct ast_sip_endpoint *endpoint = obj;
843 *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.certfile);
847 static int dtlsprivatekey_to_str(const void *obj, const intptr_t *args, char **buf)
849 const struct ast_sip_endpoint *endpoint = obj;
850 *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.pvtfile);
854 static int dtlscipher_to_str(const void *obj, const intptr_t *args, char **buf)
856 const struct ast_sip_endpoint *endpoint = obj;
857 *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cipher);
861 static int dtlscafile_to_str(const void *obj, const intptr_t *args, char **buf)
863 const struct ast_sip_endpoint *endpoint = obj;
864 *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cafile);
868 static int dtlscapath_to_str(const void *obj, const intptr_t *args, char **buf)
870 const struct ast_sip_endpoint *endpoint = obj;
871 *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.capath);
875 static const char *ast_rtp_dtls_setup_map[] = {
876 [AST_RTP_DTLS_SETUP_ACTIVE] = "active",
877 [AST_RTP_DTLS_SETUP_PASSIVE] = "passive",
878 [AST_RTP_DTLS_SETUP_ACTPASS] = "actpass",
879 [AST_RTP_DTLS_SETUP_HOLDCONN] = "holdconn",
882 static int dtlssetup_to_str(const void *obj, const intptr_t *args, char **buf)
884 const struct ast_sip_endpoint *endpoint = obj;
885 if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.default_setup, ast_rtp_dtls_setup_map)) {
886 *buf = ast_strdup(ast_rtp_dtls_setup_map[endpoint->media.rtp.dtls_cfg.default_setup]);
891 static const char *ast_rtp_dtls_fingerprint_map[] = {
892 [AST_RTP_DTLS_HASH_SHA256] = "SHA-256",
893 [AST_RTP_DTLS_HASH_SHA1] = "SHA-1",
896 static int dtlsfingerprint_to_str(const void *obj, const intptr_t *args, char **buf)
898 const struct ast_sip_endpoint *endpoint = obj;
899 if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.hash, ast_rtp_dtls_fingerprint_map)) {
900 *buf = ast_strdup(ast_rtp_dtls_fingerprint_map[endpoint->media.rtp.dtls_cfg.hash]);
905 static int t38udptl_ec_handler(const struct aco_option *opt,
906 struct ast_variable *var, void *obj)
908 struct ast_sip_endpoint *endpoint = obj;
910 if (!strcmp(var->value, "none")) {
911 endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_NONE;
912 } else if (!strcmp(var->value, "fec")) {
913 endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_FEC;
914 } else if (!strcmp(var->value, "redundancy")) {
915 endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_REDUNDANCY;
923 static const char *ast_t38_ec_modes_map[] = {
924 [UDPTL_ERROR_CORRECTION_NONE] = "none",
925 [UDPTL_ERROR_CORRECTION_FEC] = "fec",
926 [UDPTL_ERROR_CORRECTION_REDUNDANCY] = "redundancy"
929 static int t38udptl_ec_to_str(const void *obj, const intptr_t *args, char **buf)
931 const struct ast_sip_endpoint *endpoint = obj;
932 if (ARRAY_IN_BOUNDS(endpoint->media.t38.error_correction, ast_t38_ec_modes_map)) {
933 *buf = ast_strdup(ast_t38_ec_modes_map[
934 endpoint->media.t38.error_correction]);
939 static int tos_handler(const struct aco_option *opt,
940 struct ast_variable *var, void *obj)
942 struct ast_sip_endpoint *endpoint = obj;
945 if (ast_str2tos(var->value, &value)) {
946 ast_log(LOG_ERROR, "Error configuring endpoint '%s' - Could not "
947 "interpret '%s' value '%s'\n",
948 ast_sorcery_object_get_id(endpoint), var->name, var->value);
952 if (!strcmp(var->name, "tos_audio")) {
953 endpoint->media.tos_audio = value;
954 } else if (!strcmp(var->name, "tos_video")) {
955 endpoint->media.tos_video = value;
957 /* If we reach this point, someone called the tos_handler when they shouldn't have. */
964 static int tos_audio_to_str(const void *obj, const intptr_t *args, char **buf)
966 const struct ast_sip_endpoint *endpoint = obj;
968 if (ast_asprintf(buf, "%u", endpoint->media.tos_audio) == -1) {
974 static int tos_video_to_str(const void *obj, const intptr_t *args, char **buf)
976 const struct ast_sip_endpoint *endpoint = obj;
978 if (ast_asprintf(buf, "%u", endpoint->media.tos_video) == -1) {
984 static int set_var_handler(const struct aco_option *opt,
985 struct ast_variable *var, void *obj)
987 struct ast_sip_endpoint *endpoint = obj;
988 struct ast_variable *new_var;
992 if (ast_strlen_zero(var->value)) {
996 name = ast_strdupa(var->value);
997 val = strchr(name, '=');
1005 if (!(new_var = ast_variable_new(name, val, ""))) {
1009 ast_variable_list_append(&endpoint->channel_vars, new_var);
1014 static int set_var_to_str(const void *obj, const intptr_t *args, char **buf)
1016 struct ast_str *str = ast_str_create(MAX_OBJECT_FIELD);
1017 const struct ast_sip_endpoint *endpoint = obj;
1018 struct ast_variable *var;
1020 for (var = endpoint->channel_vars; var; var = var->next) {
1021 ast_str_append(&str, 0, "%s=%s,", var->name, var->value);
1024 *buf = ast_strdup(ast_str_truncate(str, -1));
1029 static int set_var_to_vl(const void *obj, struct ast_variable **fields)
1031 const struct ast_sip_endpoint *endpoint = obj;
1032 if (endpoint->channel_vars) {
1033 *fields = ast_variables_dup(endpoint->channel_vars);
1039 static void *sip_nat_hook_alloc(const char *name)
1041 return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
1044 /*! \brief Destructor function for persistent endpoint information */
1045 static void persistent_endpoint_destroy(void *obj)
1047 struct sip_persistent_endpoint *persistent = obj;
1049 ast_endpoint_shutdown(persistent->endpoint);
1050 ast_free(persistent->aors);
1053 /*! \brief Internal function which finds (or creates) persistent endpoint information */
1054 static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_sip_endpoint *endpoint)
1056 RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup);
1057 SCOPED_AO2LOCK(lock, persistent_endpoints);
1059 if (!(persistent = ao2_find(persistent_endpoints, ast_sorcery_object_get_id(endpoint), OBJ_KEY | OBJ_NOLOCK))) {
1060 if (!(persistent = ao2_alloc(sizeof(*persistent), persistent_endpoint_destroy))) {
1064 if (!(persistent->endpoint = ast_endpoint_create("PJSIP", ast_sorcery_object_get_id(endpoint)))) {
1068 persistent->aors = ast_strdup(endpoint->aors);
1070 if (ast_strlen_zero(persistent->aors)) {
1071 ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN);
1073 persistent_endpoint_update_state(persistent, NULL, NULL, 0);
1076 ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
1079 ao2_ref(persistent->endpoint, +1);
1080 return persistent->endpoint;
1083 /*! \brief Helper function which validates an outbound proxy */
1084 static int outbound_proxy_validate(void *data)
1086 const char *proxy = data;
1089 static const pj_str_t ROUTE_HNAME = { "Route", 5 };
1091 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Outbound Proxy Validation", 256, 256);
1096 pj_strdup2_with_null(pool, &tmp, proxy);
1097 if (!pjsip_parse_hdr(pool, &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL)) {
1098 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1102 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1106 /*! \brief Callback function for when an object is finalized */
1107 static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *obj)
1109 struct ast_sip_endpoint *endpoint = obj;
1111 if (!(endpoint->persistent = persistent_endpoint_find_or_create(endpoint))) {
1115 if (!ast_strlen_zero(endpoint->outbound_proxy) &&
1116 ast_sip_push_task_synchronous(NULL, outbound_proxy_validate, (char*)endpoint->outbound_proxy)) {
1117 ast_log(LOG_ERROR, "Invalid outbound proxy '%s' specified on endpoint '%s'\n",
1118 endpoint->outbound_proxy, ast_sorcery_object_get_id(endpoint));
1120 } else if (endpoint->extensions.timer.min_se < 90) {
1121 ast_log(LOG_ERROR, "Session timer minimum expires time must be 90 or greater on endpoint '%s'\n",
1122 ast_sorcery_object_get_id(endpoint));
1124 } else if (endpoint->extensions.timer.sess_expires < endpoint->extensions.timer.min_se) {
1125 ast_log(LOG_ERROR, "Session timer expires must be greater than minimum session expires time on endpoint '%s'\n",
1126 ast_sorcery_object_get_id(endpoint));
1133 const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint)
1135 char device[MAX_OBJECT_FIELD];
1137 snprintf(device, MAX_OBJECT_FIELD, "PJSIP/%s", ast_sorcery_object_get_id(endpoint));
1138 return ast_devstate2str(ast_device_state(device));
1141 struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
1142 const struct ast_sip_endpoint *endpoint)
1144 return ast_endpoint_latest_snapshot(
1145 ast_endpoint_get_tech(endpoint->persistent),
1146 ast_endpoint_get_resource(endpoint->persistent));
1149 int ast_sip_for_each_channel_snapshot(
1150 const struct ast_endpoint_snapshot *endpoint_snapshot,
1151 ao2_callback_fn on_channel_snapshot, void *arg)
1153 int num, num_channels = endpoint_snapshot->num_channels;
1155 if (!on_channel_snapshot || !num_channels) {
1159 for (num = 0; num < num_channels; ++num) {
1160 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1163 snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);
1168 res = on_channel_snapshot(snapshot, arg, 0);
1176 int ast_sip_for_each_channel(
1177 const struct ast_sip_endpoint *endpoint,
1178 ao2_callback_fn on_channel_snapshot, void *arg)
1180 RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1181 return ast_sip_for_each_channel_snapshot(endpoint_snapshot, on_channel_snapshot, arg);
1184 static int active_channels_to_str_cb(void *object, void *arg, int flags)
1186 const struct ast_channel_snapshot *snapshot = object;
1187 struct ast_str **buf = arg;
1188 ast_str_append(buf, 0, "%s,", snapshot->name);
1192 static void active_channels_to_str(const struct ast_sip_endpoint *endpoint,
1193 struct ast_str **str)
1196 RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot,
1197 ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1199 if (endpoint_snapshot) {
1203 ast_sip_for_each_channel_snapshot(endpoint_snapshot,
1204 active_channels_to_str_cb, str);
1205 ast_str_truncate(*str, -1);
1208 #define AMI_DEFAULT_STR_SIZE 512
1210 struct ast_str *ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
1212 struct ast_str *buf = ast_str_create(AMI_DEFAULT_STR_SIZE);
1215 astman_send_error_va(ami->s, ami->m, "Unable create event "
1220 ast_str_set(&buf, 0, "Event: %s\r\n", event);
1221 if (!ast_strlen_zero(ami->action_id)) {
1222 ast_str_append(&buf, 0, "ActionID: %s\r\n", ami->action_id);
1227 static void sip_sorcery_object_ami_set_type_name(const void *obj, struct ast_str **buf)
1229 ast_str_append(buf, 0, "ObjectType: %s\r\n",
1230 ast_sorcery_object_get_type(obj));
1231 ast_str_append(buf, 0, "ObjectName: %s\r\n",
1232 ast_sorcery_object_get_id(obj));
1235 int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
1237 RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2(
1238 ast_sip_get_sorcery(), obj, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
1239 struct ast_variable *i;
1245 sip_sorcery_object_ami_set_type_name(obj, buf);
1247 for (i = objset; i; i = i->next) {
1248 RAII_VAR(char *, camel, ast_to_camel_case(i->name), ast_free);
1249 ast_str_append(buf, 0, "%s: %s\r\n", camel, i->value);
1255 static int sip_endpoints_aors_ami(void *obj, void *arg, int flags)
1257 struct ast_sip_aor *aor = obj;
1258 struct ast_str **buf = arg;
1260 ast_str_append(buf, 0, "Contacts: ");
1261 ast_sip_for_each_contact(aor, ast_sip_contact_to_str, arg);
1262 ast_str_append(buf, 0, "\r\n");
1267 static int sip_endpoint_to_ami(const struct ast_sip_endpoint *endpoint,
1268 struct ast_str **buf)
1270 if (ast_sip_sorcery_object_to_ami(endpoint, buf)) {
1274 ast_str_append(buf, 0, "DeviceState: %s\r\n",
1275 ast_sip_get_device_state(endpoint));
1277 ast_str_append(buf, 0, "ActiveChannels: ");
1278 active_channels_to_str(endpoint, buf);
1279 ast_str_append(buf, 0, "\r\n");
1284 static int format_ami_endpoint(const struct ast_sip_endpoint *endpoint,
1285 struct ast_sip_ami *ami)
1287 RAII_VAR(struct ast_str *, buf,
1288 ast_sip_create_ami_event("EndpointDetail", ami), ast_free);
1294 sip_endpoint_to_ami(endpoint, &buf);
1295 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1299 #define AMI_SHOW_ENDPOINTS "PJSIPShowEndpoints"
1300 #define AMI_SHOW_ENDPOINT "PJSIPShowEndpoint"
1302 static int ami_show_endpoint(struct mansession *s, const struct message *m)
1304 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"),
1306 RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1307 const char *endpoint_name = astman_get_header(m, "Endpoint");
1310 if (ast_strlen_zero(endpoint_name)) {
1311 astman_send_error_va(s, m, "%s requires an endpoint name\n",
1316 if (!strncasecmp(endpoint_name, "pjsip/", 6)) {
1320 if (!(endpoint = ast_sorcery_retrieve_by_id(
1321 ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
1322 astman_send_error_va(s, m, "Unable to retrieve endpoint %s\n",
1327 astman_send_listack(s, m, "Following are Events for each object associated with the the Endpoint",
1330 /* the endpoint detail needs to always come first so apply as such */
1331 if (format_ami_endpoint(endpoint, &ami) ||
1332 ast_sip_format_endpoint_ami(endpoint, &ami, &count)) {
1333 astman_send_error_va(s, m, "Unable to format endpoint %s\n",
1337 astman_send_list_complete_start(s, m, "EndpointDetailComplete", ami.count + 1);
1338 astman_send_list_complete_end(s);
1343 static int format_str_append_auth(const struct ast_sip_auth_vector *auths,
1344 struct ast_str **buf)
1347 if (ast_sip_auths_to_str(auths, &str)) {
1350 ast_str_append(buf, 0, "%s", str ? str : "");
1355 static int format_ami_endpoints(void *obj, void *arg, int flags)
1358 struct ast_sip_endpoint *endpoint = obj;
1359 struct ast_sip_ami *ami = arg;
1360 RAII_VAR(struct ast_str *, buf,
1361 ast_sip_create_ami_event("EndpointList", ami), ast_free);
1367 sip_sorcery_object_ami_set_type_name(endpoint, &buf);
1368 ast_str_append(&buf, 0, "Transport: %s\r\n",
1369 endpoint->transport);
1370 ast_str_append(&buf, 0, "Aor: %s\r\n",
1373 ast_str_append(&buf, 0, "Auths: ");
1374 format_str_append_auth(&endpoint->inbound_auths, &buf);
1375 ast_str_append(&buf, 0, "\r\n");
1377 ast_str_append(&buf, 0, "OutboundAuths: ");
1378 format_str_append_auth(&endpoint->outbound_auths, &buf);
1379 ast_str_append(&buf, 0, "\r\n");
1381 ast_sip_for_each_aor(endpoint->aors,
1382 sip_endpoints_aors_ami, &buf);
1384 ast_str_append(&buf, 0, "DeviceState: %s\r\n",
1385 ast_sip_get_device_state(endpoint));
1387 ast_str_append(&buf, 0, "ActiveChannels: ");
1388 active_channels_to_str(endpoint, &buf);
1389 ast_str_append(&buf, 0, "\r\n");
1391 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1395 static int ami_show_endpoints(struct mansession *s, const struct message *m)
1397 struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1398 RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
1401 endpoints = ast_sip_get_endpoints();
1403 astman_send_error(s, m, "Could not get endpoints\n");
1407 if (!(num = ao2_container_count(endpoints))) {
1408 astman_send_error(s, m, "No endpoints found\n");
1412 astman_send_listack(s, m, "A listing of Endpoints follows, presented as EndpointList events",
1415 ao2_callback(endpoints, OBJ_NODATA, format_ami_endpoints, &ami);
1417 astman_send_list_complete_start(s, m, "EndpointListComplete", num);
1418 astman_send_list_complete_end(s);
1422 static struct ao2_container *cli_endpoint_get_container(void)
1424 RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
1425 struct ao2_container *s_container;
1427 container = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint",
1428 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
1433 s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
1434 (void *)ast_sorcery_object_id_sort, (void *)ast_sorcery_object_id_compare);
1439 if (ao2_container_dup(s_container, container, 0)) {
1440 ao2_ref(s_container, -1);
1447 static int cli_channel_populate_container(void *obj, void *arg, int flags)
1449 struct ast_channel_snapshot *snapshot = obj;
1451 ao2_link(arg, snapshot);
1456 static int cli_channel_iterate(void *container, ao2_callback_fn callback, void *args)
1458 const struct ast_sip_endpoint *endpoint = container;
1460 ast_sip_for_each_channel(endpoint, callback, args);
1465 static int cli_channel_sort(const void *obj, const void *arg, int flags)
1467 const struct ast_channel_snapshot *left_obj = obj;
1468 const struct ast_channel_snapshot *right_obj = arg;
1469 const char *right_key = arg;
1472 switch (flags & OBJ_SEARCH_MASK) {
1473 case OBJ_SEARCH_OBJECT:
1474 right_key = right_obj->name;
1476 case OBJ_SEARCH_KEY:
1477 cmp = strcmp(left_obj->name, right_key);
1479 case OBJ_SEARCH_PARTIAL_KEY:
1480 cmp = strncmp(left_obj->name, right_key, strlen(right_key));
1490 static int cli_channel_compare(void *obj, void *arg, int flags)
1492 const struct ast_channel_snapshot *left_obj = obj;
1493 const struct ast_channel_snapshot *right_obj = arg;
1494 const char *right_key = arg;
1497 switch (flags & OBJ_SEARCH_MASK) {
1498 case OBJ_SEARCH_OBJECT:
1499 right_key = right_obj->name;
1501 case OBJ_SEARCH_KEY:
1502 if (strcmp(left_obj->name, right_key) == 0) {
1503 cmp = CMP_MATCH | CMP_STOP;
1506 case OBJ_SEARCH_PARTIAL_KEY:
1507 if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
1519 static int cli_channel_hash(const void *obj, int flags)
1521 const struct ast_channel_snapshot *snapshot = obj;
1523 if (flags & OBJ_SEARCH_OBJECT) {
1524 return ast_str_hash(snapshot->name);
1525 } else if (flags & OBJ_SEARCH_KEY) {
1526 return ast_str_hash(obj);
1532 static int cli_endpoint_gather_channels(void *obj, void *arg, int flags)
1534 struct ast_sip_endpoint *endpoint = obj;
1535 struct ao2_container *channels = arg;
1537 ast_sip_for_each_channel(endpoint, cli_channel_populate_container, channels);
1542 static struct ao2_container *cli_channel_get_container(void)
1544 RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
1545 struct ao2_container *child_container;
1547 parent_container = cli_endpoint_get_container();
1548 if (!parent_container) {
1551 child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
1552 cli_channel_hash, cli_channel_sort, cli_channel_compare);
1553 if (!child_container) {
1557 ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container);
1559 return child_container;
1562 static const char *cli_channel_get_id(const void *obj)
1564 const struct ast_channel_snapshot *snapshot = obj;
1566 return snapshot->name;
1569 static void *cli_channel_retrieve_by_id(const char *id)
1571 RAII_VAR(struct ao2_container *, container, cli_channel_get_container(), ao2_cleanup);
1573 return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
1576 static int cli_channel_print_header(void *obj, void *arg, int flags)
1578 struct ast_sip_cli_context *context = arg;
1579 int indent = CLI_INDENT_TO_SPACES(context->indent_level);
1580 int filler = CLI_LAST_TABSTOP - indent - 13;
1582 ast_assert(context->output_buffer != NULL);
1584 ast_str_append(&context->output_buffer, 0,
1585 "%*s: <ChannelId%*.*s> <State.....> <Time(sec)>\n",
1586 indent, "Channel", filler, filler, CLI_HEADER_FILLER);
1587 if (context->recurse) {
1588 context->indent_level++;
1589 indent = CLI_INDENT_TO_SPACES(context->indent_level);
1590 filler = CLI_LAST_TABSTOP - indent - 38;
1591 ast_str_append(&context->output_buffer, 0,
1592 "%*s: <DialedExten%*.*s> CLCID: <ConnectedLineCID.......>\n",
1593 indent, "Exten", filler, filler, CLI_HEADER_FILLER);
1594 context->indent_level--;
1600 static int cli_channel_print_body(void *obj, void *arg, int flags)
1602 const struct ast_channel_snapshot *snapshot = obj;
1603 struct ast_sip_cli_context *context = arg;
1604 struct timeval current_time;
1605 char *print_name = NULL;
1610 ast_assert(context->output_buffer != NULL);
1612 gettimeofday(¤t_time, NULL);
1614 print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
1615 if (!(print_name = alloca(print_name_len))) {
1619 snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
1621 indent = CLI_INDENT_TO_SPACES(context->indent_level);
1622 flexwidth = CLI_LAST_TABSTOP - indent;
1624 ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s %11ld\n",
1625 CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
1626 flexwidth, flexwidth,
1628 ast_state2str(snapshot->state),
1629 current_time.tv_sec - snapshot->creationtime.tv_sec);
1631 if (context->recurse) {
1632 context->indent_level++;
1633 indent = CLI_INDENT_TO_SPACES(context->indent_level);
1634 flexwidth = CLI_LAST_TABSTOP - indent - 25;
1636 ast_str_append(&context->output_buffer, 0,
1637 "%*s: %-*.*s CLCID: \"%s\" <%s>\n",
1639 flexwidth, flexwidth,
1641 snapshot->connected_name,
1642 snapshot->connected_number
1644 context->indent_level--;
1645 if (context->indent_level == 0) {
1646 ast_str_append(&context->output_buffer, 0, "\n");
1653 static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args)
1655 ao2_callback(obj, OBJ_NODATA, callback, args);
1660 static void *cli_endpoint_retrieve_by_id(const char *id)
1662 return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
1665 static void cli_endpoint_print_child_header(char *type, struct ast_sip_cli_context *context)
1667 RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
1669 formatter_entry = ast_sip_lookup_cli_formatter(type);
1670 if (formatter_entry) {
1671 formatter_entry->print_header(NULL, context, 0);
1675 static int cli_endpoint_print_header(void *obj, void *arg, int flags)
1677 struct ast_sip_cli_context *context = arg;
1679 ast_assert(context->output_buffer != NULL);
1681 ast_str_append(&context->output_buffer, 0,
1682 " Endpoint: <Endpoint/CID.....................................> <State.....> <Channels.>\n");
1684 if (context->recurse) {
1685 context->indent_level++;
1686 cli_endpoint_print_child_header("auth", context);
1687 cli_endpoint_print_child_header("aor", context);
1688 cli_endpoint_print_child_header("transport", context);
1689 cli_endpoint_print_child_header("identify", context);
1690 cli_endpoint_print_child_header("channel", context);
1691 context->indent_level--;
1697 static void cli_endpoint_print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
1699 RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
1701 formatter_entry = ast_sip_lookup_cli_formatter(type);
1702 if (formatter_entry) {
1703 formatter_entry->iterate((void *)obj, formatter_entry->print_body, context);
1707 static int cli_endpoint_print_body(void *obj, void *arg, int flags)
1709 struct ast_sip_endpoint *endpoint = obj;
1710 RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1711 struct ast_sip_cli_context *context = arg;
1712 const char *id = ast_sorcery_object_get_id(endpoint);
1713 char *print_name = NULL;
1715 char *number = S_COR(endpoint->id.self.number.valid,
1716 endpoint->id.self.number.str, NULL);
1720 ast_assert(context->output_buffer != NULL);
1723 print_name_len = strlen(id) + strlen(number) + 2;
1724 if (!(print_name = alloca(print_name_len))) {
1727 snprintf(print_name, print_name_len, "%s/%s", id, number);
1730 indent = CLI_INDENT_TO_SPACES(context->indent_level);
1731 flexwidth = CLI_LAST_TABSTOP - indent - 2;
1733 ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s %d of %.0f\n",
1735 flexwidth, flexwidth, print_name ? print_name : id,
1736 ast_sip_get_device_state(endpoint),
1737 endpoint_snapshot->num_channels,
1738 (double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
1742 if (context->recurse) {
1743 context->indent_level++;
1745 context->auth_direction = "Out";
1746 cli_endpoint_print_child_body("auth", &endpoint->outbound_auths, context);
1747 context->auth_direction = "In";
1748 cli_endpoint_print_child_body("auth", &endpoint->inbound_auths, context);
1750 cli_endpoint_print_child_body("aor", endpoint->aors, context);
1751 cli_endpoint_print_child_body("transport", endpoint, context);
1752 cli_endpoint_print_child_body("identify", endpoint, context);
1753 cli_endpoint_print_child_body("channel", endpoint, context);
1755 context->indent_level--;
1757 if (context->indent_level == 0) {
1758 ast_str_append(&context->output_buffer, 0, "\n");
1762 if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
1763 ast_str_append(&context->output_buffer, 0, "\n");
1764 ast_sip_cli_print_sorcery_objectset(endpoint, context, 0);
1770 static struct ast_cli_entry cli_commands[] = {
1771 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
1772 .command = "pjsip list channels",
1773 .usage = "Usage: pjsip list channels\n"
1774 " List the active PJSIP channels\n"),
1775 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
1776 .command = "pjsip show channels",
1777 .usage = "Usage: pjsip show channels\n"
1778 " List(detailed) the active PJSIP channels\n"),
1779 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel",
1780 .command = "pjsip show channel",
1781 .usage = "Usage: pjsip show channel\n"
1782 " List(detailed) the active PJSIP channel\n"),
1784 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
1785 .command = "pjsip list endpoints",
1786 .usage = "Usage: pjsip list endpoints\n"
1787 " List the configured PJSIP endpoints\n"),
1788 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoints",
1789 .command = "pjsip show endpoints",
1790 .usage = "Usage: pjsip show endpoints\n"
1791 " List(detailed) the configured PJSIP endpoints\n"),
1792 AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoint",
1793 .command = "pjsip show endpoint",
1794 .usage = "Usage: pjsip show endpoint <id>\n"
1795 " Show the configured PJSIP endpoint\n"),
1798 struct ast_sip_cli_formatter_entry *channel_formatter;
1799 struct ast_sip_cli_formatter_entry *endpoint_formatter;
1801 int ast_res_pjsip_initialize_configuration(void)
1803 if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) ||
1804 ast_manager_register_xml(AMI_SHOW_ENDPOINT, EVENT_FLAG_SYSTEM, ami_show_endpoint)) {
1808 if (!(persistent_endpoints = ao2_container_alloc(PERSISTENT_BUCKETS, persistent_endpoint_hash, persistent_endpoint_cmp))) {
1812 if (!(sip_sorcery = ast_sorcery_open())) {
1813 ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
1817 ast_sip_initialize_cli();
1819 if (ast_sip_initialize_sorcery_auth()) {
1820 ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
1821 ast_sorcery_unref(sip_sorcery);
1826 ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "pjsip.conf,criteria=type=endpoint");
1827 ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
1829 if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, sip_endpoint_apply_handler)) {
1830 ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
1831 ast_sorcery_unref(sip_sorcery);
1836 if (ast_sorcery_internal_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL)) {
1837 ast_log(LOG_ERROR, "Failed to register nat_hook\n");
1840 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
1841 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
1842 ast_sorcery_object_field_register_alias(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.codecs));
1843 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.codecs));
1844 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, NULL, 0, 0);
1845 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6));
1846 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric));
1847 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ice_support));
1848 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_ptime", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_ptime));
1849 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_rport", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.force_rport));
1850 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rewrite_contact", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.rewrite_contact));
1851 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
1852 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
1853 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
1854 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, NULL, 0, 0);
1855 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, NULL, 0, 0);
1856 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));
1857 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));
1858 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, NULL, 0, 0);
1859 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, NULL, 0, 0);
1860 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
1861 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.address));
1862 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, NULL, 0, 0);
1863 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled));
1864 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "direct_media_method", "invite", direct_media_method_handler, direct_media_method_to_str, NULL, 0, 0);
1865 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "connected_line_method", "invite", connected_line_method_handler, connected_line_method_to_str, NULL, 0, 0);
1866 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, NULL, 0, 0);
1867 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));
1868 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, NULL, 0, 0);
1869 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_privacy", "allowed_not_screened", caller_id_privacy_handler, caller_id_privacy_to_str, NULL, 0, 0);
1870 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, NULL, 0, 0);
1871 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_inbound));
1872 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_outbound));
1873 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_pai));
1874 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_rpid", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_rpid));
1875 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rpid_immediate", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.rpid_immediate));
1876 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion));
1877 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes));
1878 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
1879 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0);
1880 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
1881 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
1882 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_use_received_transport", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_received_transport));
1883 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
1884 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
1885 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
1886 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, NULL, 0, 0);
1887 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, NULL, 0, 0);
1888 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, NULL, 0, 0);
1889 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));
1890 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.enabled));
1891 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0);
1892 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram));
1893 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect));
1894 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat));
1895 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6));
1896 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));
1897 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "language", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, language));
1898 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_on_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.onfeature));
1899 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_off_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.offfeature));
1900 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_transfer", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowtransfer));
1901 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "user_eq_phone", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, usereqphone));
1902 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_passthrough", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, moh_passthrough));
1903 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_owner", "-", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpowner));
1904 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));
1905 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);
1906 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);
1907 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));
1908 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
1909 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
1910 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));
1911 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser));
1912 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
1913 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser));
1914 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
1915 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "no", dtls_handler, dtlsverify_to_str, NULL, 0, 0);
1916 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "0", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);
1917 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);
1918 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);
1919 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);
1920 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, NULL, 0, 0);
1921 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, NULL, 0, 0);
1922 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, NULL, 0, 0);
1923 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_fingerprint", "", dtls_handler, dtlsfingerprint_to_str, NULL, 0, 0);
1924 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));
1925 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_encryption_optimistic", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.encryption_optimistic));
1926 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0);
1927 ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0);
1928 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, message_context));
1929 ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 1, STRFLDSET(struct ast_sip_endpoint, accountcode));
1931 if (ast_sip_initialize_sorcery_transport()) {
1932 ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
1933 ast_sorcery_unref(sip_sorcery);
1938 if (ast_sip_initialize_sorcery_location()) {
1939 ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
1940 ast_sorcery_unref(sip_sorcery);
1945 if (ast_sip_initialize_sorcery_qualify()) {
1946 ast_log(LOG_ERROR, "Failed to register SIP qualify support with sorcery\n");
1947 ast_sorcery_unref(sip_sorcery);
1952 ast_sorcery_observer_add(sip_sorcery, "contact", &state_contact_observer);
1953 ast_sorcery_observer_add(sip_sorcery, CONTACT_STATUS, &state_contact_status_observer);
1955 if (ast_sip_initialize_sorcery_domain_alias()) {
1956 ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
1957 ast_sorcery_unref(sip_sorcery);
1962 if (ast_sip_initialize_sorcery_global()) {
1963 ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
1964 ast_sorcery_unref(sip_sorcery);
1969 channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1970 if (!channel_formatter) {
1971 ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n");
1972 ast_sorcery_unref(sip_sorcery);
1976 channel_formatter->name = "channel";
1977 channel_formatter->print_header = cli_channel_print_header;
1978 channel_formatter->print_body = cli_channel_print_body;
1979 channel_formatter->get_container = cli_channel_get_container;
1980 channel_formatter->iterate = cli_channel_iterate;
1981 channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
1982 channel_formatter->get_id = cli_channel_get_id;
1984 endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1985 if (!endpoint_formatter) {
1986 ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n");
1987 ast_sorcery_unref(sip_sorcery);
1991 endpoint_formatter->name = "endpoint";
1992 endpoint_formatter->print_header = cli_endpoint_print_header;
1993 endpoint_formatter->print_body = cli_endpoint_print_body;
1994 endpoint_formatter->get_container = cli_endpoint_get_container;
1995 endpoint_formatter->iterate = cli_endpoint_iterate;
1996 endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id;
1997 endpoint_formatter->get_id = ast_sorcery_object_get_id;
1999 ast_sip_register_cli_formatter(channel_formatter);
2000 ast_sip_register_cli_formatter(endpoint_formatter);
2001 ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
2003 ast_sorcery_load(sip_sorcery);
2008 void ast_res_pjsip_destroy_configuration(void)
2010 ast_sorcery_observer_remove(sip_sorcery, CONTACT_STATUS, &state_contact_status_observer);
2011 ast_sorcery_observer_remove(sip_sorcery, "contact", &state_contact_observer);
2012 ast_sip_destroy_sorcery_global();
2013 ast_sip_destroy_sorcery_location();
2014 ast_sip_destroy_sorcery_auth();
2015 ast_sip_destroy_sorcery_transport();
2016 ast_manager_unregister(AMI_SHOW_ENDPOINT);
2017 ast_manager_unregister(AMI_SHOW_ENDPOINTS);
2018 ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
2019 ast_sip_unregister_cli_formatter(endpoint_formatter);
2020 ast_sip_unregister_cli_formatter(channel_formatter);
2021 ast_sorcery_unref(sip_sorcery);
2022 ao2_cleanup(persistent_endpoints);
2025 int ast_res_pjsip_reload_configuration(void)
2028 ast_sorcery_reload(sip_sorcery);
2033 static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription)
2035 ast_string_field_free_memory(&subscription->mwi);
2038 static void info_configuration_destroy(struct ast_sip_endpoint_info_configuration *info)
2040 ast_string_field_free_memory(&info->recording);
2043 static void media_configuration_destroy(struct ast_sip_endpoint_media_configuration *media)
2045 ast_string_field_free_memory(&media->rtp);
2046 ast_string_field_free_memory(media);
2049 static void endpoint_destructor(void* obj)
2051 struct ast_sip_endpoint *endpoint = obj;
2053 ast_string_field_free_memory(endpoint);
2055 ao2_ref(endpoint->media.codecs, -1);
2056 subscription_configuration_destroy(&endpoint->subscription);
2057 info_configuration_destroy(&endpoint->info);
2058 media_configuration_destroy(&endpoint->media);
2059 ast_sip_auth_vector_destroy(&endpoint->inbound_auths);
2060 ast_sip_auth_vector_destroy(&endpoint->outbound_auths);
2061 ast_party_id_free(&endpoint->id.self);
2062 endpoint->pickup.named_callgroups = ast_unref_namedgroups(endpoint->pickup.named_callgroups);
2063 endpoint->pickup.named_pickupgroups = ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
2064 ao2_cleanup(endpoint->persistent);
2065 ast_variables_destroy(endpoint->channel_vars);
2068 static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)
2070 return ast_string_field_init(&subscription->mwi, 64);
2073 static int init_info_configuration(struct ast_sip_endpoint_info_configuration *info)
2075 return ast_string_field_init(&info->recording, 32);
2078 static int init_media_configuration(struct ast_sip_endpoint_media_configuration *media)
2080 return ast_string_field_init(media, 64) || ast_string_field_init(&media->rtp, 32);
2083 void *ast_sip_endpoint_alloc(const char *name)
2085 struct ast_sip_endpoint *endpoint = ast_sorcery_generic_alloc(sizeof(*endpoint), endpoint_destructor);
2089 if (ast_string_field_init(endpoint, 64)) {
2090 ao2_cleanup(endpoint);
2093 if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2094 ao2_cleanup(endpoint);
2097 if (init_subscription_configuration(&endpoint->subscription)) {
2098 ao2_cleanup(endpoint);
2101 if (init_info_configuration(&endpoint->info)) {
2102 ao2_cleanup(endpoint);
2105 if (init_media_configuration(&endpoint->media)) {
2106 ao2_cleanup(endpoint);
2109 ast_party_id_init(&endpoint->id.self);
2113 struct ao2_container *ast_sip_get_endpoints(void)
2115 struct ao2_container *endpoints;
2117 endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
2122 struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void)
2124 RAII_VAR(char *, name, ast_sip_global_default_outbound_endpoint(), ast_free);
2125 return ast_strlen_zero(name) ? NULL : ast_sorcery_retrieve_by_id(
2126 sip_sorcery, "endpoint", name);
2129 int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
2133 for (i = 0; i < AST_VECTOR_SIZE(auths); ++i) {
2134 /* Using AST_VECTOR_GET is safe since the vector is immutable */
2135 const char *name = AST_VECTOR_GET(auths, i);
2136 out[i] = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, name);
2138 ast_log(LOG_NOTICE, "Couldn't find auth '%s'. Cannot authenticate\n", name);
2146 void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
2149 for (i = 0; i < num_auths; ++i) {
2150 ao2_cleanup(auths[i]);
2154 struct ast_sorcery *ast_sip_get_sorcery(void)