926bf3793cb1e3754abed954a1180b814594739d
[asterisk/asterisk.git] / res / res_pjsip / pjsip_configuration.c
1 /*
2  * sip_cli_commands.c
3  *
4  *  Created on: Jan 25, 2013
5  *      Author: mjordan
6  */
7
8 #include "asterisk.h"
9
10 #include <pjsip.h>
11 #include <pjsip_ua.h>
12
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"
23 #include "asterisk/statsd.h"
24
25 /*! \brief Number of buckets for persistent endpoint information */
26 #define PERSISTENT_BUCKETS 53
27
28 /*! \brief Persistent endpoint information */
29 struct sip_persistent_endpoint {
30         /*! \brief Asterisk endpoint itself */
31         struct ast_endpoint *endpoint;
32         /*! \brief AORs that we should react to */
33         char *aors;
34 };
35
36 /*! \brief Container for persistent endpoint information */
37 static struct ao2_container *persistent_endpoints;
38
39 static struct ast_sorcery *sip_sorcery;
40
41 /*! \brief Hashing function for persistent endpoint information */
42 static int persistent_endpoint_hash(const void *obj, const int flags)
43 {
44         const struct sip_persistent_endpoint *persistent = obj;
45         const char *id = (flags & OBJ_KEY ? obj : ast_endpoint_get_resource(persistent->endpoint));
46
47         return ast_str_hash(id);
48 }
49
50 /*! \brief Comparison function for persistent endpoint information */
51 static int persistent_endpoint_cmp(void *obj, void *arg, int flags)
52 {
53         const struct sip_persistent_endpoint *persistent1 = obj;
54         const struct sip_persistent_endpoint *persistent2 = arg;
55         const char *id = (flags & OBJ_KEY ? arg : ast_endpoint_get_resource(persistent2->endpoint));
56
57         return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
58 }
59
60 /*! \brief Callback function for changing the state of an endpoint */
61 static int persistent_endpoint_update_state(void *obj, void *arg, int flags)
62 {
63         struct sip_persistent_endpoint *persistent = obj;
64         struct ast_endpoint *endpoint = persistent->endpoint;
65         struct ast_sip_contact_status *status = arg;
66         struct ao2_container *contacts;
67         struct ast_json *blob;
68         struct ao2_iterator i;
69         struct ast_sip_contact *contact;
70         enum ast_endpoint_state state = AST_ENDPOINT_OFFLINE;
71
72         if (status) {
73                 char rtt[32];
74
75                 /* If the status' aor isn't one of the endpoint's, we skip */
76                 if (!strstr(persistent->aors, status->aor)) {
77                         return 0;
78                 }
79
80                 snprintf(rtt, sizeof(rtt), "%" PRId64, status->rtt);
81                 blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
82                         "contact_status", ast_sip_get_contact_status_label(status->status),
83                         "aor", status->aor,
84                         "uri", status->uri,
85                         "roundtrip_usec", rtt,
86                         "endpoint_name", ast_endpoint_get_resource(endpoint));
87                 ast_endpoint_blob_publish(endpoint, ast_endpoint_contact_state_type(), blob);
88                 ast_json_unref(blob);
89         }
90
91         /* Find all the contacts for this endpoint.  If ANY are available,
92          * mark the endpoint as ONLINE.
93          */
94         contacts = ast_sip_location_retrieve_contacts_from_aor_list(persistent->aors);
95         if (contacts) {
96                 i = ao2_iterator_init(contacts, 0);
97                 while (state == AST_ENDPOINT_OFFLINE && (contact = ao2_iterator_next(&i))) {
98                         struct ast_sip_contact_status *contact_status;
99                         const char *contact_id = ast_sorcery_object_get_id(contact);
100
101                         contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
102                                 CONTACT_STATUS, contact_id);
103
104                         if (contact_status && contact_status->status != UNAVAILABLE) {
105                                 state = AST_ENDPOINT_ONLINE;
106                         }
107                         ao2_cleanup(contact_status);
108                         ao2_ref(contact, -1);
109                 }
110                 ao2_iterator_destroy(&i);
111                 ao2_ref(contacts, -1);
112         }
113
114         /* If there was no state change, don't publish anything. */
115         if (ast_endpoint_get_state(endpoint) == state) {
116                 return 0;
117         }
118
119         if (state == AST_ENDPOINT_ONLINE) {
120                 ast_endpoint_set_state(endpoint, AST_ENDPOINT_ONLINE);
121                 blob = ast_json_pack("{s: s}", "peer_status", "Reachable");
122                 ast_verb(1, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(endpoint));
123         } else {
124                 ast_endpoint_set_state(endpoint, AST_ENDPOINT_OFFLINE);
125                 blob = ast_json_pack("{s: s}", "peer_status", "Unreachable");
126                 ast_verb(1, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(endpoint));
127         }
128
129         ast_endpoint_blob_publish(endpoint, ast_endpoint_state_type(), blob);
130         ast_json_unref(blob);
131         ast_devstate_changed(AST_DEVICE_UNKNOWN, AST_DEVSTATE_CACHABLE, "PJSIP/%s", ast_endpoint_get_resource(endpoint));
132
133         return 0;
134 }
135
136 /*! \brief Function called when a contact is created */
137 static void persistent_endpoint_contact_created_observer(const void *object)
138 {
139         const struct ast_sip_contact *contact = object;
140         struct ast_sip_contact_status *contact_status;
141
142         contact_status = ast_sorcery_alloc(ast_sip_get_sorcery(), CONTACT_STATUS,
143                 ast_sorcery_object_get_id(contact));
144         if (!contact_status) {
145                 ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
146                         contact->aor, contact->uri);
147                 return;
148         }
149         ast_string_field_set(contact_status, uri, contact->uri);
150
151         contact_status->status = CREATED;
152
153         ast_verb(1, "Contact %s/%s has been created\n",contact->aor, contact->uri);
154
155         ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status);
156         ao2_cleanup(contact_status);
157 }
158
159 /*! \brief Function called when a contact is deleted */
160 static void persistent_endpoint_contact_deleted_observer(const void *object)
161 {
162         const struct ast_sip_contact *contact = object;
163         struct ast_sip_contact_status *contact_status;
164
165         contact_status = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), CONTACT_STATUS, ast_sorcery_object_get_id(contact));
166         if (!contact_status) {
167                 ast_log(LOG_ERROR, "Unable to create ast_sip_contact_status for contact %s/%s\n",
168                         contact->aor, contact->uri);
169                 return;
170         }
171
172         ast_verb(1, "Contact %s/%s has been deleted\n", contact->aor, contact->uri);
173         ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
174                 "-1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
175         ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
176                 "+1", 1.0, ast_sip_get_contact_status_label(REMOVED));
177
178         ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status);
179         ast_sorcery_delete(ast_sip_get_sorcery(), contact_status);
180         ao2_cleanup(contact_status);
181 }
182
183 /*! \brief Observer for contacts so state can be updated on respective endpoints */
184 static const struct ast_sorcery_observer state_contact_observer = {
185         .created = persistent_endpoint_contact_created_observer,
186         .deleted = persistent_endpoint_contact_deleted_observer,
187 };
188
189 /*! \brief Function called when a contact_status is updated */
190 static void persistent_endpoint_contact_status_observer(const void *object)
191 {
192         struct ast_sip_contact_status *contact_status = (struct ast_sip_contact_status *)object;
193
194         /* If rtt_start is set (this is the outgoing OPTIONS), ignore. */
195         if (contact_status->rtt_start.tv_sec > 0) {
196                 return;
197         }
198
199         if (contact_status->status != contact_status->last_status) {
200                 ast_verb(1, "Contact %s/%s is now %s.  RTT: %.3f msec\n", contact_status->aor, contact_status->uri,
201                         ast_sip_get_contact_status_label(contact_status->status),
202                         contact_status->rtt / 1000.0);
203
204                 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
205                         "-1", 1.0, ast_sip_get_contact_status_label(contact_status->last_status));
206                 ast_statsd_log_string_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE,
207                         "+1", 1.0, ast_sip_get_contact_status_label(contact_status->status));
208
209                 ast_test_suite_event_notify("AOR_CONTACT_UPDATE",
210                         "Contact: %s\r\n"
211                                 "Status: %s",
212                         ast_sorcery_object_get_id(contact_status),
213                         ast_sip_get_contact_status_label(contact_status->status));
214
215                 ao2_callback(persistent_endpoints, OBJ_NODATA, persistent_endpoint_update_state, contact_status);
216         } else {
217                 ast_debug(3, "Contact %s/%s status didn't change: %s, RTT: %.3f msec\n",
218                         contact_status->aor, contact_status->uri, ast_sip_get_contact_status_label(contact_status->status),
219                         contact_status->rtt / 1000.0);
220         }
221
222         ast_statsd_log_full_va("PJSIP.contacts.%s.rtt", AST_STATSD_TIMER,
223                 contact_status->status != AVAILABLE ? -1 : contact_status->rtt / 1000, 1.0, ast_sorcery_object_get_id(contact_status));
224 }
225
226 /*! \brief Observer for contacts so state can be updated on respective endpoints */
227 static const struct ast_sorcery_observer state_contact_status_observer = {
228         .updated = persistent_endpoint_contact_status_observer,
229 };
230
231 static void endpoint_deleted_observer(const void *object)
232 {
233         const struct ast_sip_endpoint *endpoint = object;
234
235         ao2_find(persistent_endpoints, ast_endpoint_get_resource(endpoint->persistent), OBJ_SEARCH_KEY | OBJ_UNLINK | OBJ_NODATA);
236 }
237
238 static const struct ast_sorcery_observer endpoint_observers = {
239         .deleted = endpoint_deleted_observer,
240 };
241
242 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
243 {
244         struct ast_sip_endpoint *endpoint = obj;
245
246         if (!strcasecmp(var->value, "rfc4733")) {
247                 endpoint->dtmf = AST_SIP_DTMF_RFC_4733;
248         } else if (!strcasecmp(var->value, "inband")) {
249                 endpoint->dtmf = AST_SIP_DTMF_INBAND;
250         } else if (!strcasecmp(var->value, "info")) {
251                 endpoint->dtmf = AST_SIP_DTMF_INFO;
252         } else if (!strcasecmp(var->value, "auto")) {
253                 endpoint->dtmf = AST_SIP_DTMF_AUTO;
254         } else if (!strcasecmp(var->value, "none")) {
255                 endpoint->dtmf = AST_SIP_DTMF_NONE;
256         } else {
257                 return -1;
258         }
259
260         return 0;
261 }
262
263 static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
264 {
265         const struct ast_sip_endpoint *endpoint = obj;
266
267         switch (endpoint->dtmf) {
268         case AST_SIP_DTMF_RFC_4733 :
269                 *buf = "rfc4733"; break;
270         case AST_SIP_DTMF_INBAND :
271                 *buf = "inband"; break;
272         case AST_SIP_DTMF_INFO :
273                 *buf = "info"; break;
274        case AST_SIP_DTMF_AUTO :
275                 *buf = "auto"; break;
276         default:
277                 *buf = "none";
278         }
279
280         *buf = ast_strdup(*buf);
281         return 0;
282 }
283
284 static int prack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
285 {
286         struct ast_sip_endpoint *endpoint = obj;
287
288         /* clear all */
289         endpoint->extensions.flags &= ~(PJSIP_INV_SUPPORT_100REL | PJSIP_INV_REQUIRE_100REL);
290
291         if (ast_true(var->value)) {
292                 endpoint->extensions.flags |= PJSIP_INV_SUPPORT_100REL;
293         } else if (!strcasecmp(var->value, "required")) {
294                 endpoint->extensions.flags |= PJSIP_INV_REQUIRE_100REL;
295         } else if (!ast_false(var->value)){
296                 return -1;
297         }
298
299         return 0;
300 }
301
302 static int prack_to_str(const void *obj, const intptr_t *args, char **buf)
303 {
304         const struct ast_sip_endpoint *endpoint = obj;
305
306         if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_100REL) {
307                 *buf = "required";
308         } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_100REL) {
309                 *buf = "yes";
310         } else {
311                 *buf = "no";
312         }
313
314         *buf = ast_strdup(*buf);
315         return 0;
316 }
317
318 static int timers_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
319 {
320         struct ast_sip_endpoint *endpoint = obj;
321
322         /* clear all */
323         endpoint->extensions.flags &= ~(PJSIP_INV_SUPPORT_TIMER | PJSIP_INV_REQUIRE_TIMER
324                                         | PJSIP_INV_ALWAYS_USE_TIMER);
325
326         /* set only the specified flag and let pjsip normalize if needed */
327         if (ast_true(var->value)) {
328                 endpoint->extensions.flags |= PJSIP_INV_SUPPORT_TIMER;
329         } else if (!strcasecmp(var->value, "required")) {
330                 endpoint->extensions.flags |= PJSIP_INV_REQUIRE_TIMER;
331         } else if (!strcasecmp(var->value, "always") || !strcasecmp(var->value, "forced")) {
332                 endpoint->extensions.flags |= PJSIP_INV_ALWAYS_USE_TIMER;
333         } else if (!ast_false(var->value)) {
334                 return -1;
335         }
336
337         return 0;
338 }
339
340 static int timers_to_str(const void *obj, const intptr_t *args, char **buf)
341 {
342         const struct ast_sip_endpoint *endpoint = obj;
343
344         if (endpoint->extensions.flags & PJSIP_INV_ALWAYS_USE_TIMER) {
345                 *buf = "always";
346         } else if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_TIMER) {
347                 *buf = "required";
348         } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_TIMER) {
349                 *buf = "yes";
350         } else {
351                 *buf = "no";
352         }
353
354         *buf = ast_strdup(*buf);
355         return 0;
356 }
357
358 void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *auths)
359 {
360         int i;
361         size_t size;
362
363         if (!auths) {
364                 return;
365         }
366
367         size = AST_VECTOR_SIZE(auths);
368
369         for (i = 0; i < size; ++i) {
370                 const char *name = AST_VECTOR_REMOVE_UNORDERED(auths, 0);
371                 ast_free((char *) name);
372         }
373         AST_VECTOR_FREE(auths);
374 }
375
376 int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *value)
377 {
378         char *auth_names = ast_strdupa(value);
379         char *val;
380
381         ast_assert(auths != NULL);
382
383         if (AST_VECTOR_SIZE(auths)) {
384                 ast_sip_auth_vector_destroy(auths);
385         }
386         if (AST_VECTOR_INIT(auths, 1)) {
387                 return -1;
388         }
389
390         while ((val = strsep(&auth_names, ","))) {
391                 if (ast_strlen_zero(val)) {
392                         continue;
393                 }
394
395                 val = ast_strdup(val);
396                 if (!val) {
397                         goto failure;
398                 }
399                 if (AST_VECTOR_APPEND(auths, val)) {
400                         goto failure;
401                 }
402         }
403         return 0;
404
405 failure:
406         ast_sip_auth_vector_destroy(auths);
407         return -1;
408 }
409
410 static int inbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
411 {
412         struct ast_sip_endpoint *endpoint = obj;
413
414         return ast_sip_auth_vector_init(&endpoint->inbound_auths, var->value);
415 }
416
417 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
418 {
419         struct ast_sip_endpoint *endpoint = obj;
420
421         return ast_sip_auth_vector_init(&endpoint->outbound_auths, var->value);
422 }
423
424 int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf)
425 {
426         if (!auths || !AST_VECTOR_SIZE(auths)) {
427                 return 0;
428         }
429
430         if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
431                 return -1;
432         }
433
434         /* I feel like accessing the vector's elem array directly is cheating...*/
435         ast_join_delim(*buf, MAX_OBJECT_FIELD, auths->elems, AST_VECTOR_SIZE(auths), ',');
436         return 0;
437 }
438
439 static int inbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
440 {
441         const struct ast_sip_endpoint *endpoint = obj;
442         return ast_sip_auths_to_str(&endpoint->inbound_auths, buf);
443 }
444
445 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
446 {
447         const struct ast_sip_endpoint *endpoint = obj;
448         return ast_sip_auths_to_str(&endpoint->outbound_auths, buf);
449 }
450
451 static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
452 {
453         struct ast_sip_endpoint *endpoint = obj;
454         char *idents = ast_strdupa(var->value);
455         char *val;
456
457         while ((val = strsep(&idents, ","))) {
458                 if (!strcasecmp(val, "username")) {
459                         endpoint->ident_method |= AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME;
460                 } else {
461                         ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n",
462                                         val, ast_sorcery_object_get_id(endpoint));
463                         return -1;
464                 }
465         }
466         return 0;
467 }
468
469 static int ident_to_str(const void *obj, const intptr_t *args, char **buf)
470 {
471         const struct ast_sip_endpoint *endpoint = obj;
472         switch (endpoint->ident_method) {
473         case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME :
474                 *buf = "username"; break;
475         default:
476                 return 0;
477         }
478
479         *buf = ast_strdup(*buf);
480         return 0;
481 }
482
483 static int redirect_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
484 {
485         struct ast_sip_endpoint *endpoint = obj;
486
487         if (!strcasecmp(var->value, "user")) {
488                 endpoint->redirect_method = AST_SIP_REDIRECT_USER;
489         } else if (!strcasecmp(var->value, "uri_core")) {
490                 endpoint->redirect_method = AST_SIP_REDIRECT_URI_CORE;
491         } else if (!strcasecmp(var->value, "uri_pjsip")) {
492                 endpoint->redirect_method = AST_SIP_REDIRECT_URI_PJSIP;
493         } else {
494                 ast_log(LOG_ERROR, "Unrecognized redirect method %s specified for endpoint %s\n",
495                         var->value, ast_sorcery_object_get_id(endpoint));
496                 return -1;
497         }
498
499         return 0;
500 }
501
502 static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
503 {
504         struct ast_sip_endpoint *endpoint = obj;
505
506         if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
507                 endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
508         } else if (!strcasecmp(var->value, "update")) {
509                 endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
510         } else {
511                 ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
512                                 var->value, var->name, ast_sorcery_object_get_id(endpoint));
513                 return -1;
514         }
515         return 0;
516 }
517
518 static const char *id_configuration_refresh_methods[] = {
519         [AST_SIP_SESSION_REFRESH_METHOD_INVITE] = "invite",
520         [AST_SIP_SESSION_REFRESH_METHOD_UPDATE] = "update"
521 };
522
523 static int direct_media_method_to_str(const void *obj, const intptr_t *args, char **buf)
524 {
525         const struct ast_sip_endpoint *endpoint = obj;
526         if (ARRAY_IN_BOUNDS(endpoint->id.refresh_method, id_configuration_refresh_methods)) {
527                 *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
528         }
529         return 0;
530 }
531
532 static int connected_line_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
533 {
534         struct ast_sip_endpoint *endpoint = obj;
535
536         if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
537                 endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
538         } else if (!strcasecmp(var->value, "update")) {
539                 endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
540         } else {
541                 ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
542                                 var->value, var->name, ast_sorcery_object_get_id(endpoint));
543                 return -1;
544         }
545         return 0;
546 }
547
548 static int connected_line_method_to_str(const void *obj, const intptr_t *args, char **buf)
549 {
550         const struct ast_sip_endpoint *endpoint = obj;
551         *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
552         return 0;
553 }
554
555 static int direct_media_glare_mitigation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
556 {
557         struct ast_sip_endpoint *endpoint = obj;
558
559         if (!strcasecmp(var->value, "none")) {
560                 endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE;
561         } else if (!strcasecmp(var->value, "outgoing")) {
562                 endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING;
563         } else if (!strcasecmp(var->value, "incoming")) {
564                 endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING;
565         } else {
566                 ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
567                                 var->value, var->name, ast_sorcery_object_get_id(endpoint));
568                 return -1;
569         }
570
571         return 0;
572 }
573
574 static const char *direct_media_glare_mitigation_map[] = {
575         [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE] = "none",
576         [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING] = "outgoing",
577         [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING] = "incoming"
578 };
579
580 static int direct_media_glare_mitigation_to_str(const void *obj, const intptr_t *args, char **buf)
581 {
582         const struct ast_sip_endpoint *endpoint = obj;
583         if (ARRAY_IN_BOUNDS(endpoint->media.direct_media.glare_mitigation, direct_media_glare_mitigation_map)) {
584                 *buf = ast_strdup(direct_media_glare_mitigation_map[endpoint->media.direct_media.glare_mitigation]);
585         }
586
587         return 0;
588 }
589
590 static int caller_id_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
591 {
592         struct ast_sip_endpoint *endpoint = obj;
593         char cid_name[80] = { '\0' };
594         char cid_num[80] = { '\0' };
595
596         ast_callerid_split(var->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
597         if (!ast_strlen_zero(cid_name)) {
598                 endpoint->id.self.name.str = ast_strdup(cid_name);
599                 if (!endpoint->id.self.name.str) {
600                         return -1;
601                 }
602                 endpoint->id.self.name.valid = 1;
603         }
604         if (!ast_strlen_zero(cid_num)) {
605                 endpoint->id.self.number.str = ast_strdup(cid_num);
606                 if (!endpoint->id.self.number.str) {
607                         return -1;
608                 }
609                 endpoint->id.self.number.valid = 1;
610         }
611         return 0;
612 }
613
614 static int caller_id_to_str(const void *obj, const intptr_t *args, char **buf)
615 {
616         const struct ast_sip_endpoint *endpoint = obj;
617         const char *name = S_COR(endpoint->id.self.name.valid,
618                                  endpoint->id.self.name.str, NULL);
619         const char *number = S_COR(endpoint->id.self.number.valid,
620                                    endpoint->id.self.number.str, NULL);
621
622         /* make sure size is at least 10 - that should cover the "<unknown>"
623            case as well as any additional formatting characters added in
624            the name and/or number case. */
625         int size = 10;
626         size += name ? strlen(name) : 0;
627         size += number ? strlen(number) : 0;
628
629         if (!(*buf = ast_calloc(size + 1, sizeof(char)))) {
630                 return -1;
631         }
632
633         ast_callerid_merge(*buf, size + 1, name, number, NULL);
634         return 0;
635 }
636
637 static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
638 {
639         struct ast_sip_endpoint *endpoint = obj;
640         int callingpres = ast_parse_caller_presentation(var->value);
641         if (callingpres == -1 && sscanf(var->value, "%d", &callingpres) != 1) {
642                 return -1;
643         }
644         endpoint->id.self.number.presentation = callingpres;
645         endpoint->id.self.name.presentation = callingpres;
646         return 0;
647 }
648
649 static int caller_id_privacy_to_str(const void *obj, const intptr_t *args, char **buf)
650 {
651         const struct ast_sip_endpoint *endpoint = obj;
652         const char *presentation = ast_named_caller_presentation(
653                 endpoint->id.self.name.presentation);
654
655         *buf = ast_strdup(presentation);
656         return 0;
657 }
658
659 static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
660 {
661         struct ast_sip_endpoint *endpoint = obj;
662         endpoint->id.self.tag = ast_strdup(var->value);
663         return endpoint->id.self.tag ? 0 : -1;
664 }
665
666 static int caller_id_tag_to_str(const void *obj, const intptr_t *args, char **buf)
667 {
668         const struct ast_sip_endpoint *endpoint = obj;
669         *buf = ast_strdup(endpoint->id.self.tag);
670         return 0;
671 }
672
673 static int media_encryption_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
674 {
675         struct ast_sip_endpoint *endpoint = obj;
676
677         if (!strcasecmp("no", var->value)) {
678                 endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
679         } else if (!strcasecmp("sdes", var->value)) {
680                 endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_SDES;
681         } else if (!strcasecmp("dtls", var->value)) {
682                 endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
683                 return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes");
684         } else {
685                 return -1;
686         }
687
688         return 0;
689 }
690
691 static const char *media_encryption_map[] = {
692         [AST_SIP_MEDIA_TRANSPORT_INVALID] = "invalid",
693         [AST_SIP_MEDIA_ENCRYPT_NONE] = "no",
694         [AST_SIP_MEDIA_ENCRYPT_SDES] = "sdes",
695         [AST_SIP_MEDIA_ENCRYPT_DTLS] = "dtls",
696 };
697
698 static int media_encryption_to_str(const void *obj, const intptr_t *args, char **buf)
699 {
700         const struct ast_sip_endpoint *endpoint = obj;
701         if (ARRAY_IN_BOUNDS(endpoint->media.rtp.encryption, media_encryption_map)) {
702                 *buf = ast_strdup(media_encryption_map[
703                                           endpoint->media.rtp.encryption]);
704         }
705         return 0;
706 }
707
708 static int group_handler(const struct aco_option *opt,
709                          struct ast_variable *var, void *obj)
710 {
711         struct ast_sip_endpoint *endpoint = obj;
712
713         if (!strncmp(var->name, "call_group", 10)) {
714                 endpoint->pickup.callgroup = ast_get_group(var->value);
715         } else if (!strncmp(var->name, "pickup_group", 12)) {
716                 endpoint->pickup.pickupgroup = ast_get_group(var->value);
717         } else {
718                 return -1;
719         }
720
721         return 0;
722 }
723
724 static int callgroup_to_str(const void *obj, const intptr_t *args, char **buf)
725 {
726         const struct ast_sip_endpoint *endpoint = obj;
727
728         if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
729                 return -1;
730         }
731
732         ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.callgroup);
733         return 0;
734 }
735
736 static int pickupgroup_to_str(const void *obj, const intptr_t *args, char **buf)
737 {
738         const struct ast_sip_endpoint *endpoint = obj;
739
740         if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
741                 return -1;
742         }
743
744         ast_print_group(*buf, MAX_OBJECT_FIELD, endpoint->pickup.pickupgroup);
745         return 0;
746 }
747
748 static int named_groups_handler(const struct aco_option *opt,
749                                 struct ast_variable *var, void *obj)
750 {
751         struct ast_sip_endpoint *endpoint = obj;
752
753         if (!strncmp(var->name, "named_call_group", 16)) {
754                 if (ast_strlen_zero(var->value)) {
755                         endpoint->pickup.named_callgroups =
756                                 ast_unref_namedgroups(endpoint->pickup.named_callgroups);
757                 } else if (!(endpoint->pickup.named_callgroups =
758                       ast_get_namedgroups(var->value))) {
759                         return -1;
760                 }
761         } else if (!strncmp(var->name, "named_pickup_group", 18)) {
762                 if (ast_strlen_zero(var->value)) {
763                         endpoint->pickup.named_pickupgroups =
764                                 ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
765                 } else if (!(endpoint->pickup.named_pickupgroups =
766                       ast_get_namedgroups(var->value))) {
767                         return -1;
768                 }
769         } else {
770                 return -1;
771         }
772
773         return 0;
774 }
775
776 static int named_callgroups_to_str(const void *obj, const intptr_t *args, char **buf)
777 {
778         const struct ast_sip_endpoint *endpoint = obj;
779         RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
780
781         ast_print_namedgroups(&str, endpoint->pickup.named_callgroups);
782         *buf = ast_strdup(ast_str_buffer(str));
783         return 0;
784 }
785
786 static int named_pickupgroups_to_str(const void *obj, const intptr_t *args, char **buf)
787 {
788         const struct ast_sip_endpoint *endpoint = obj;
789         RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
790
791         ast_print_namedgroups(&str, endpoint->pickup.named_pickupgroups);
792         *buf = ast_strdup(ast_str_buffer(str));
793         return 0;
794 }
795
796 static int dtls_handler(const struct aco_option *opt,
797                          struct ast_variable *var, void *obj)
798 {
799         struct ast_sip_endpoint *endpoint = obj;
800         char *name = ast_strdupa(var->name);
801         char *front, *back, *buf = name;
802
803         /* strip out underscores in the name */
804         front = strtok_r(buf, "_", &back);
805         while (front) {
806                 int size = strlen(front);
807                 ast_copy_string(buf, front, size + 1);
808                 buf += size;
809                 front = strtok_r(NULL, "_", &back);
810         }
811
812         return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, name, var->value);
813 }
814
815 static int dtlsverify_to_str(const void *obj, const intptr_t *args, char **buf)
816 {
817         const struct ast_sip_endpoint *endpoint = obj;
818         *buf = ast_strdup(AST_YESNO(endpoint->media.rtp.dtls_cfg.verify));
819         return 0;
820 }
821
822 static int dtlsrekey_to_str(const void *obj, const intptr_t *args, char **buf)
823 {
824         const struct ast_sip_endpoint *endpoint = obj;
825
826         return ast_asprintf(
827                 buf, "%u", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1;
828 }
829
830 static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf)
831 {
832         const struct ast_sip_endpoint *endpoint = obj;
833         *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.certfile);
834         return 0;
835 }
836
837 static int dtlsprivatekey_to_str(const void *obj, const intptr_t *args, char **buf)
838 {
839         const struct ast_sip_endpoint *endpoint = obj;
840         *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.pvtfile);
841         return 0;
842 }
843
844 static int dtlscipher_to_str(const void *obj, const intptr_t *args, char **buf)
845 {
846         const struct ast_sip_endpoint *endpoint = obj;
847         *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cipher);
848         return 0;
849 }
850
851 static int dtlscafile_to_str(const void *obj, const intptr_t *args, char **buf)
852 {
853         const struct ast_sip_endpoint *endpoint = obj;
854         *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cafile);
855         return 0;
856 }
857
858 static int dtlscapath_to_str(const void *obj, const intptr_t *args, char **buf)
859 {
860         const struct ast_sip_endpoint *endpoint = obj;
861         *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.capath);
862         return 0;
863 }
864
865 static const char *ast_rtp_dtls_setup_map[] = {
866         [AST_RTP_DTLS_SETUP_ACTIVE] = "active",
867         [AST_RTP_DTLS_SETUP_PASSIVE] = "passive",
868         [AST_RTP_DTLS_SETUP_ACTPASS] = "actpass",
869         [AST_RTP_DTLS_SETUP_HOLDCONN] = "holdconn",
870 };
871
872 static int dtlssetup_to_str(const void *obj, const intptr_t *args, char **buf)
873 {
874         const struct ast_sip_endpoint *endpoint = obj;
875         if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.default_setup, ast_rtp_dtls_setup_map)) {
876                 *buf = ast_strdup(ast_rtp_dtls_setup_map[endpoint->media.rtp.dtls_cfg.default_setup]);
877         }
878         return 0;
879 }
880
881 static const char *ast_rtp_dtls_fingerprint_map[] = {
882         [AST_RTP_DTLS_HASH_SHA256] = "SHA-256",
883         [AST_RTP_DTLS_HASH_SHA1] = "SHA-1",
884 };
885
886 static int dtlsfingerprint_to_str(const void *obj, const intptr_t *args, char **buf)
887 {
888         const struct ast_sip_endpoint *endpoint = obj;
889         if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.hash, ast_rtp_dtls_fingerprint_map)) {
890                 *buf = ast_strdup(ast_rtp_dtls_fingerprint_map[endpoint->media.rtp.dtls_cfg.hash]);
891         }
892         return 0;
893 }
894
895 static int t38udptl_ec_handler(const struct aco_option *opt,
896         struct ast_variable *var, void *obj)
897 {
898         struct ast_sip_endpoint *endpoint = obj;
899
900         if (!strcmp(var->value, "none")) {
901                 endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_NONE;
902         } else if (!strcmp(var->value, "fec")) {
903                 endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_FEC;
904         } else if (!strcmp(var->value, "redundancy")) {
905                 endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_REDUNDANCY;
906         } else {
907                 return -1;
908         }
909
910         return 0;
911 }
912
913 static const char *ast_t38_ec_modes_map[] = {
914         [UDPTL_ERROR_CORRECTION_NONE] = "none",
915         [UDPTL_ERROR_CORRECTION_FEC] = "fec",
916         [UDPTL_ERROR_CORRECTION_REDUNDANCY] = "redundancy"
917 };
918
919 static int t38udptl_ec_to_str(const void *obj, const intptr_t *args, char **buf)
920 {
921         const struct ast_sip_endpoint *endpoint = obj;
922         if (ARRAY_IN_BOUNDS(endpoint->media.t38.error_correction, ast_t38_ec_modes_map)) {
923                 *buf = ast_strdup(ast_t38_ec_modes_map[
924                                           endpoint->media.t38.error_correction]);
925         }
926         return 0;
927 }
928
929 static int tos_handler(const struct aco_option *opt,
930         struct ast_variable *var, void *obj)
931 {
932         struct ast_sip_endpoint *endpoint = obj;
933         unsigned int value;
934
935         if (ast_str2tos(var->value, &value)) {
936                 ast_log(LOG_ERROR, "Error configuring endpoint '%s' - Could not "
937                         "interpret '%s' value '%s'\n",
938                         ast_sorcery_object_get_id(endpoint), var->name, var->value);
939                 return -1;
940         }
941
942         if (!strcmp(var->name, "tos_audio")) {
943                 endpoint->media.tos_audio = value;
944         } else if (!strcmp(var->name, "tos_video")) {
945                 endpoint->media.tos_video = value;
946         } else {
947                 /* If we reach this point, someone called the tos_handler when they shouldn't have. */
948                 ast_assert(0);
949                 return -1;
950         }
951         return 0;
952 }
953
954 static int tos_audio_to_str(const void *obj, const intptr_t *args, char **buf)
955 {
956         const struct ast_sip_endpoint *endpoint = obj;
957
958         if (ast_asprintf(buf, "%u", endpoint->media.tos_audio) == -1) {
959                 return -1;
960         }
961         return 0;
962 }
963
964 static int tos_video_to_str(const void *obj, const intptr_t *args, char **buf)
965 {
966         const struct ast_sip_endpoint *endpoint = obj;
967
968         if (ast_asprintf(buf, "%u", endpoint->media.tos_video) == -1) {
969                 return -1;
970         }
971         return 0;
972 }
973
974 static int set_var_handler(const struct aco_option *opt,
975         struct ast_variable *var, void *obj)
976 {
977         struct ast_sip_endpoint *endpoint = obj;
978         struct ast_variable *new_var;
979         char *name;
980         char *val;
981
982         if (ast_strlen_zero(var->value)) {
983                 return 0;
984         }
985
986         name = ast_strdupa(var->value);
987         val = strchr(name, '=');
988
989         if (!val) {
990                 return -1;
991         }
992
993         *val++ = '\0';
994
995         if (!(new_var = ast_variable_new(name, val, ""))) {
996                 return -1;
997         }
998
999         ast_variable_list_append(&endpoint->channel_vars, new_var);
1000
1001         return 0;
1002 }
1003
1004 static int set_var_to_str(const void *obj, const intptr_t *args, char **buf)
1005 {
1006         struct ast_str *str = ast_str_create(MAX_OBJECT_FIELD);
1007         const struct ast_sip_endpoint *endpoint = obj;
1008         struct ast_variable *var;
1009
1010         for (var = endpoint->channel_vars; var; var = var->next) {
1011                 ast_str_append(&str, 0, "%s=%s,", var->name, var->value);
1012         }
1013
1014         *buf = ast_strdup(ast_str_truncate(str, -1));
1015         ast_free(str);
1016         return 0;
1017 }
1018
1019 static int set_var_to_vl(const void *obj, struct ast_variable **fields)
1020 {
1021         const struct ast_sip_endpoint *endpoint = obj;
1022         if (endpoint->channel_vars) {
1023                 *fields = ast_variables_dup(endpoint->channel_vars);
1024         }
1025         return 0;
1026 }
1027
1028
1029 static void *sip_nat_hook_alloc(const char *name)
1030 {
1031         return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
1032 }
1033
1034 /*! \brief Destructor function for persistent endpoint information */
1035 static void persistent_endpoint_destroy(void *obj)
1036 {
1037         struct sip_persistent_endpoint *persistent = obj;
1038
1039         ast_endpoint_shutdown(persistent->endpoint);
1040         ast_free(persistent->aors);
1041 }
1042
1043 /*! \brief Internal function which finds (or creates) persistent endpoint information */
1044 static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_sip_endpoint *endpoint)
1045 {
1046         RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup);
1047         SCOPED_AO2LOCK(lock, persistent_endpoints);
1048
1049         if (!(persistent = ao2_find(persistent_endpoints, ast_sorcery_object_get_id(endpoint), OBJ_KEY | OBJ_NOLOCK))) {
1050                 if (!(persistent = ao2_alloc(sizeof(*persistent), persistent_endpoint_destroy))) {
1051                         return NULL;
1052                 }
1053
1054                 if (!(persistent->endpoint = ast_endpoint_create("PJSIP", ast_sorcery_object_get_id(endpoint)))) {
1055                         return NULL;
1056                 }
1057
1058                 persistent->aors = ast_strdup(endpoint->aors);
1059
1060                 if (ast_strlen_zero(persistent->aors)) {
1061                         ast_endpoint_set_state(persistent->endpoint, AST_ENDPOINT_UNKNOWN);
1062                 } else {
1063                         persistent_endpoint_update_state(persistent, NULL, 0);
1064                 }
1065
1066                 ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
1067         }
1068
1069         ao2_ref(persistent->endpoint, +1);
1070         return persistent->endpoint;
1071 }
1072
1073 /*! \brief Callback function for when an object is finalized */
1074 static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *obj)
1075 {
1076         struct ast_sip_endpoint *endpoint = obj;
1077
1078         if (!(endpoint->persistent = persistent_endpoint_find_or_create(endpoint))) {
1079                 return -1;
1080         }
1081
1082         if (endpoint->extensions.timer.min_se < 90) {
1083                 ast_log(LOG_ERROR, "Session timer minimum expires time must be 90 or greater on endpoint '%s'\n",
1084                         ast_sorcery_object_get_id(endpoint));
1085                 return -1;
1086         } else if (endpoint->extensions.timer.sess_expires < endpoint->extensions.timer.min_se) {
1087                 ast_log(LOG_ERROR, "Session timer expires must be greater than minimum session expires time on endpoint '%s'\n",
1088                         ast_sorcery_object_get_id(endpoint));
1089                 return -1;
1090         }
1091
1092         return 0;
1093 }
1094
1095 const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint)
1096 {
1097         char device[MAX_OBJECT_FIELD];
1098
1099         snprintf(device, MAX_OBJECT_FIELD, "PJSIP/%s", ast_sorcery_object_get_id(endpoint));
1100         return ast_devstate2str(ast_device_state(device));
1101 }
1102
1103 struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
1104         const struct ast_sip_endpoint *endpoint)
1105 {
1106         return ast_endpoint_latest_snapshot(
1107                 ast_endpoint_get_tech(endpoint->persistent),
1108                 ast_endpoint_get_resource(endpoint->persistent));
1109 }
1110
1111 int ast_sip_for_each_channel_snapshot(
1112         const struct ast_endpoint_snapshot *endpoint_snapshot,
1113         ao2_callback_fn on_channel_snapshot, void *arg)
1114 {
1115         int num, num_channels = endpoint_snapshot->num_channels;
1116
1117         if (!on_channel_snapshot || !num_channels) {
1118                 return 0;
1119         }
1120
1121         for (num = 0; num < num_channels; ++num) {
1122                 RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1123                 int res;
1124
1125                 snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);
1126                 if (!snapshot) {
1127                         continue;
1128                 }
1129
1130                 res = on_channel_snapshot(snapshot, arg, 0);
1131                 if (res) {
1132                         return -1;
1133                 }
1134         }
1135         return 0;
1136 }
1137
1138 int ast_sip_for_each_channel(
1139         const struct ast_sip_endpoint *endpoint,
1140         ao2_callback_fn on_channel_snapshot, void *arg)
1141 {
1142         RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1143         return ast_sip_for_each_channel_snapshot(endpoint_snapshot, on_channel_snapshot, arg);
1144 }
1145
1146 static int active_channels_to_str_cb(void *object, void *arg, int flags)
1147 {
1148         const struct ast_channel_snapshot *snapshot = object;
1149         struct ast_str **buf = arg;
1150         ast_str_append(buf, 0, "%s,", snapshot->name);
1151         return 0;
1152 }
1153
1154 static void active_channels_to_str(const struct ast_sip_endpoint *endpoint,
1155                                    struct ast_str **str)
1156 {
1157
1158         RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot,
1159                  ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1160
1161         if (endpoint_snapshot) {
1162                 return;
1163         }
1164
1165         ast_sip_for_each_channel_snapshot(endpoint_snapshot,
1166                                           active_channels_to_str_cb, str);
1167         ast_str_truncate(*str, -1);
1168 }
1169
1170 #define AMI_DEFAULT_STR_SIZE 512
1171
1172 struct ast_str *ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
1173 {
1174         struct ast_str *buf = ast_str_create(AMI_DEFAULT_STR_SIZE);
1175
1176         if (!(buf)) {
1177                 astman_send_error_va(ami->s, ami->m, "Unable create event "
1178                                      "for %s\n", event);
1179                 return NULL;
1180         }
1181
1182         ast_str_set(&buf, 0, "Event: %s\r\n", event);
1183         if (!ast_strlen_zero(ami->action_id)) {
1184                 ast_str_append(&buf, 0, "ActionID: %s\r\n", ami->action_id);
1185         }
1186         return buf;
1187 }
1188
1189 static void sip_sorcery_object_ami_set_type_name(const void *obj, struct ast_str **buf)
1190 {
1191         ast_str_append(buf, 0, "ObjectType: %s\r\n",
1192                        ast_sorcery_object_get_type(obj));
1193         ast_str_append(buf, 0, "ObjectName: %s\r\n",
1194                        ast_sorcery_object_get_id(obj));
1195 }
1196
1197 int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
1198 {
1199         RAII_VAR(struct ast_variable *, objset, ast_sorcery_objectset_create2(
1200                          ast_sip_get_sorcery(), obj, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
1201         struct ast_variable *i;
1202
1203         if (!objset) {
1204                 return -1;
1205         }
1206
1207         sip_sorcery_object_ami_set_type_name(obj, buf);
1208
1209         for (i = objset; i; i = i->next) {
1210                 RAII_VAR(char *, camel, ast_to_camel_case(i->name), ast_free);
1211                 ast_str_append(buf, 0, "%s: %s\r\n", camel, i->value);
1212         }
1213
1214         return 0;
1215 }
1216
1217 static int sip_endpoints_aors_ami(void *obj, void *arg, int flags)
1218 {
1219         struct ast_sip_aor *aor = obj;
1220         struct ast_str **buf = arg;
1221
1222         ast_str_append(buf, 0, "Contacts: ");
1223         ast_sip_for_each_contact(aor, ast_sip_contact_to_str, arg);
1224         ast_str_append(buf, 0, "\r\n");
1225
1226         return 0;
1227 }
1228
1229 static int sip_endpoint_to_ami(const struct ast_sip_endpoint *endpoint,
1230                                struct ast_str **buf)
1231 {
1232         if (ast_sip_sorcery_object_to_ami(endpoint, buf)) {
1233                 return -1;
1234         }
1235
1236         ast_str_append(buf, 0, "DeviceState: %s\r\n",
1237                        ast_sip_get_device_state(endpoint));
1238
1239         ast_str_append(buf, 0, "ActiveChannels: ");
1240         active_channels_to_str(endpoint, buf);
1241         ast_str_append(buf, 0, "\r\n");
1242
1243         return 0;
1244 }
1245
1246 static int format_ami_endpoint(const struct ast_sip_endpoint *endpoint,
1247                                struct ast_sip_ami *ami)
1248 {
1249         RAII_VAR(struct ast_str *, buf,
1250                  ast_sip_create_ami_event("EndpointDetail", ami), ast_free);
1251
1252         if (!buf) {
1253                 return -1;
1254         }
1255
1256         sip_endpoint_to_ami(endpoint, &buf);
1257         astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1258         return 0;
1259 }
1260
1261 #define AMI_SHOW_ENDPOINTS "PJSIPShowEndpoints"
1262 #define AMI_SHOW_ENDPOINT "PJSIPShowEndpoint"
1263
1264 static int ami_show_endpoint(struct mansession *s, const struct message *m)
1265 {
1266         struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"),
1267                 .count = 0, };
1268         RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1269         const char *endpoint_name = astman_get_header(m, "Endpoint");
1270         int count = 0;
1271
1272         if (ast_strlen_zero(endpoint_name)) {
1273                 astman_send_error_va(s, m, "%s requires an endpoint name\n",
1274                         AMI_SHOW_ENDPOINT);
1275                 return 0;
1276         }
1277
1278         if (!strncasecmp(endpoint_name, "pjsip/", 6)) {
1279                 endpoint_name += 6;
1280         }
1281
1282         if (!(endpoint = ast_sorcery_retrieve_by_id(
1283                       ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
1284                 astman_send_error_va(s, m, "Unable to retrieve endpoint %s\n",
1285                         endpoint_name);
1286                 return 0;
1287         }
1288
1289         astman_send_listack(s, m, "Following are Events for each object associated with the the Endpoint",
1290                 "start");
1291
1292         /* the endpoint detail needs to always come first so apply as such */
1293         if (format_ami_endpoint(endpoint, &ami) ||
1294             ast_sip_format_endpoint_ami(endpoint, &ami, &count)) {
1295                 astman_send_error_va(s, m, "Unable to format endpoint %s\n",
1296                         endpoint_name);
1297         }
1298
1299         astman_send_list_complete_start(s, m, "EndpointDetailComplete", ami.count + 1);
1300         astman_send_list_complete_end(s);
1301
1302         return 0;
1303 }
1304
1305 static int format_str_append_auth(const struct ast_sip_auth_vector *auths,
1306                                   struct ast_str **buf)
1307 {
1308         char *str = NULL;
1309         if (ast_sip_auths_to_str(auths, &str)) {
1310                 return -1;
1311         }
1312         ast_str_append(buf, 0, "%s", str ? str : "");
1313         ast_free(str);
1314         return 0;
1315 }
1316
1317 static int format_ami_endpoints(void *obj, void *arg, int flags)
1318 {
1319
1320         struct ast_sip_endpoint *endpoint = obj;
1321         struct ast_sip_ami *ami = arg;
1322         RAII_VAR(struct ast_str *, buf,
1323                  ast_sip_create_ami_event("EndpointList", ami), ast_free);
1324
1325         if (!buf) {
1326                 return CMP_STOP;
1327         }
1328
1329         sip_sorcery_object_ami_set_type_name(endpoint, &buf);
1330         ast_str_append(&buf, 0, "Transport: %s\r\n",
1331                        endpoint->transport);
1332         ast_str_append(&buf, 0, "Aor: %s\r\n",
1333                        endpoint->aors);
1334
1335         ast_str_append(&buf, 0, "Auths: ");
1336         format_str_append_auth(&endpoint->inbound_auths, &buf);
1337         ast_str_append(&buf, 0, "\r\n");
1338
1339         ast_str_append(&buf, 0, "OutboundAuths: ");
1340         format_str_append_auth(&endpoint->outbound_auths, &buf);
1341         ast_str_append(&buf, 0, "\r\n");
1342
1343         ast_sip_for_each_aor(endpoint->aors,
1344                              sip_endpoints_aors_ami, &buf);
1345
1346         ast_str_append(&buf, 0, "DeviceState: %s\r\n",
1347                        ast_sip_get_device_state(endpoint));
1348
1349         ast_str_append(&buf, 0, "ActiveChannels: ");
1350         active_channels_to_str(endpoint, &buf);
1351         ast_str_append(&buf, 0, "\r\n");
1352
1353         astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1354         return 0;
1355 }
1356
1357 static int ami_show_endpoints(struct mansession *s, const struct message *m)
1358 {
1359         struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1360         RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
1361         int num;
1362
1363         endpoints = ast_sip_get_endpoints();
1364         if (!endpoints) {
1365                 astman_send_error(s, m, "Could not get endpoints\n");
1366                 return 0;
1367         }
1368
1369         if (!(num = ao2_container_count(endpoints))) {
1370                 astman_send_error(s, m, "No endpoints found\n");
1371                 return 0;
1372         }
1373
1374         astman_send_listack(s, m, "A listing of Endpoints follows, presented as EndpointList events",
1375                 "start");
1376
1377         ao2_callback(endpoints, OBJ_NODATA, format_ami_endpoints, &ami);
1378
1379         astman_send_list_complete_start(s, m, "EndpointListComplete", num);
1380         astman_send_list_complete_end(s);
1381         return 0;
1382 }
1383
1384 static struct ao2_container *cli_endpoint_get_container(const char *regex)
1385 {
1386         RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
1387         struct ao2_container *s_container;
1388
1389         container = ast_sorcery_retrieve_by_regex(sip_sorcery, "endpoint", regex);
1390         if (!container) {
1391                 return NULL;
1392         }
1393
1394         s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0,
1395                 (void *)ast_sorcery_object_id_sort, (void *)ast_sorcery_object_id_compare);
1396         if (!s_container) {
1397                 return NULL;
1398         }
1399
1400         if (ao2_container_dup(s_container, container, 0)) {
1401                 ao2_ref(s_container, -1);
1402                 return NULL;
1403         }
1404
1405         return s_container;
1406 }
1407
1408 static int cli_channel_populate_container(void *obj, void *arg, int flags)
1409 {
1410         struct ast_channel_snapshot *snapshot = obj;
1411
1412         ao2_link(arg, snapshot);
1413
1414         return 0;
1415 }
1416
1417 static int cli_channel_iterate(void *container, ao2_callback_fn callback, void *args)
1418 {
1419         const struct ast_sip_endpoint *endpoint = container;
1420
1421         ast_sip_for_each_channel(endpoint, callback, args);
1422
1423         return 0;
1424 }
1425
1426 static int cli_channel_sort(const void *obj, const void *arg, int flags)
1427 {
1428         const struct ast_channel_snapshot *left_obj = obj;
1429         const struct ast_channel_snapshot *right_obj = arg;
1430         const char *right_key = arg;
1431         int cmp;
1432
1433         switch (flags & OBJ_SEARCH_MASK) {
1434         case OBJ_SEARCH_OBJECT:
1435                 right_key = right_obj->name;
1436                 /* Fall through */
1437         case OBJ_SEARCH_KEY:
1438                 cmp = strcmp(left_obj->name, right_key);
1439                 break;
1440         case OBJ_SEARCH_PARTIAL_KEY:
1441                 cmp = strncmp(left_obj->name, right_key, strlen(right_key));
1442                 break;
1443         default:
1444                 cmp = 0;
1445                 break;
1446         }
1447
1448         return cmp;
1449 }
1450
1451 static int cli_channel_compare(void *obj, void *arg, int flags)
1452 {
1453         const struct ast_channel_snapshot *left_obj = obj;
1454         const struct ast_channel_snapshot *right_obj = arg;
1455         const char *right_key = arg;
1456         int cmp = 0;
1457
1458         switch (flags & OBJ_SEARCH_MASK) {
1459         case OBJ_SEARCH_OBJECT:
1460                 right_key = right_obj->name;
1461                 /* Fall through */
1462         case OBJ_SEARCH_KEY:
1463                 if (strcmp(left_obj->name, right_key) == 0) {
1464                         cmp = CMP_MATCH | CMP_STOP;
1465                 }
1466                 break;
1467         case OBJ_SEARCH_PARTIAL_KEY:
1468                 if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
1469                         cmp = CMP_MATCH;
1470                 }
1471                 break;
1472         default:
1473                 cmp = 0;
1474                 break;
1475         }
1476
1477         return cmp;
1478 }
1479
1480 static int cli_channel_hash(const void *obj, int flags)
1481 {
1482         const struct ast_channel_snapshot *snapshot = obj;
1483
1484         if (flags & OBJ_SEARCH_OBJECT) {
1485                 return ast_str_hash(snapshot->name);
1486         } else if (flags & OBJ_SEARCH_KEY) {
1487                 return ast_str_hash(obj);
1488         }
1489
1490         return -1;
1491 }
1492
1493 static int cli_endpoint_gather_channels(void *obj, void *arg, int flags)
1494 {
1495         struct ast_sip_endpoint *endpoint = obj;
1496         struct ao2_container *channels = arg;
1497
1498         ast_sip_for_each_channel(endpoint, cli_channel_populate_container, channels);
1499
1500         return 0;
1501 }
1502
1503 static int cli_filter_channels(void *obj, void *arg, int flags)
1504 {
1505         struct ast_channel_snapshot *channel = obj;
1506         regex_t *regexbuf = arg;
1507
1508         if (!regexec(regexbuf, channel->name, 0, NULL, 0)
1509                 || !regexec(regexbuf, channel->appl, 0, NULL, 0)) {
1510                 return 0;
1511         }
1512
1513         return CMP_MATCH;
1514 }
1515
1516 static struct ao2_container *cli_channel_get_container(const char *regex)
1517 {
1518         RAII_VAR(struct ao2_container *, parent_container, NULL, ao2_cleanup);
1519         struct ao2_container *child_container;
1520         regex_t regexbuf;
1521
1522         parent_container = cli_endpoint_get_container("");
1523         if (!parent_container) {
1524                 return NULL;
1525         }
1526         child_container = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, 17,
1527                 cli_channel_hash, cli_channel_sort, cli_channel_compare);
1528         if (!child_container) {
1529                 return NULL;
1530         }
1531
1532         ao2_callback(parent_container, OBJ_NODATA, cli_endpoint_gather_channels, child_container);
1533
1534         if (!ast_strlen_zero(regex)) {
1535                 if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
1536                         ao2_ref(child_container, -1);
1537                         return NULL;
1538                 }
1539                 ao2_callback(child_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_channels, &regexbuf);
1540                 regfree(&regexbuf);
1541         }
1542
1543         return child_container;
1544 }
1545
1546 static const char *cli_channel_get_id(const void *obj)
1547 {
1548         const struct ast_channel_snapshot *snapshot = obj;
1549
1550         return snapshot->name;
1551 }
1552
1553 static void *cli_channel_retrieve_by_id(const char *id)
1554 {
1555         RAII_VAR(struct ao2_container *, container, cli_channel_get_container(""), ao2_cleanup);
1556
1557         return ao2_find(container, id, OBJ_KEY | OBJ_NOLOCK);
1558 }
1559
1560 static int cli_channel_print_header(void *obj, void *arg, int flags)
1561 {
1562         struct ast_sip_cli_context *context = arg;
1563         int indent = CLI_INDENT_TO_SPACES(context->indent_level);
1564         int filler = CLI_LAST_TABSTOP - indent - 13;
1565
1566         ast_assert(context->output_buffer != NULL);
1567
1568         ast_str_append(&context->output_buffer, 0,
1569                 "%*s:  <ChannelId%*.*s>  <State.....>  <Time(sec)>\n",
1570                 indent, "Channel", filler, filler, CLI_HEADER_FILLER);
1571         if (context->recurse) {
1572                 context->indent_level++;
1573                 indent = CLI_INDENT_TO_SPACES(context->indent_level);
1574                 filler = CLI_LAST_TABSTOP - indent - 38;
1575                 ast_str_append(&context->output_buffer, 0,
1576                         "%*s: <DialedExten%*.*s>  CLCID: <ConnectedLineCID.......>\n",
1577                         indent, "Exten", filler, filler, CLI_HEADER_FILLER);
1578                 context->indent_level--;
1579         }
1580
1581         return 0;
1582 }
1583
1584 static int cli_channel_print_body(void *obj, void *arg, int flags)
1585 {
1586         const struct ast_channel_snapshot *snapshot = obj;
1587         struct ast_sip_cli_context *context = arg;
1588         struct timeval current_time;
1589         char *print_name = NULL;
1590         int print_name_len;
1591         int indent;
1592         int flexwidth;
1593
1594         ast_assert(context->output_buffer != NULL);
1595
1596         gettimeofday(&current_time, NULL);
1597
1598         print_name_len = strlen(snapshot->name) + strlen(snapshot->appl) + 2;
1599         if (!(print_name = alloca(print_name_len))) {
1600                 return -1;
1601         }
1602
1603         snprintf(print_name, print_name_len, "%s/%s", snapshot->name, snapshot->appl);
1604
1605         indent = CLI_INDENT_TO_SPACES(context->indent_level);
1606         flexwidth = CLI_LAST_TABSTOP - indent;
1607
1608         ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s  %11ld\n",
1609                 CLI_INDENT_TO_SPACES(context->indent_level), "Channel",
1610                 flexwidth, flexwidth,
1611                 print_name,
1612                 ast_state2str(snapshot->state),
1613                 current_time.tv_sec - snapshot->creationtime.tv_sec);
1614
1615         if (context->recurse) {
1616                 context->indent_level++;
1617                 indent = CLI_INDENT_TO_SPACES(context->indent_level);
1618                 flexwidth = CLI_LAST_TABSTOP - indent - 25;
1619
1620                 ast_str_append(&context->output_buffer, 0,
1621                         "%*s: %-*.*s  CLCID: \"%s\" <%s>\n",
1622                         indent, "Exten",
1623                         flexwidth, flexwidth,
1624                         snapshot->exten,
1625                         snapshot->connected_name,
1626                         snapshot->connected_number
1627                         );
1628                 context->indent_level--;
1629                 if (context->indent_level == 0) {
1630                         ast_str_append(&context->output_buffer, 0, "\n");
1631                 }
1632         }
1633
1634         return 0;
1635 }
1636
1637 static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args)
1638 {
1639         ao2_callback(obj, OBJ_NODATA, callback, args);
1640
1641         return 0;
1642 }
1643
1644 static void *cli_endpoint_retrieve_by_id(const char *id)
1645 {
1646         return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
1647 }
1648
1649 static void cli_endpoint_print_child_header(char *type, struct ast_sip_cli_context *context)
1650 {
1651         RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
1652
1653         formatter_entry = ast_sip_lookup_cli_formatter(type);
1654         if (formatter_entry) {
1655                 formatter_entry->print_header(NULL, context, 0);
1656         }
1657 }
1658
1659 static int cli_endpoint_print_header(void *obj, void *arg, int flags)
1660 {
1661         struct ast_sip_cli_context *context = arg;
1662
1663         ast_assert(context->output_buffer != NULL);
1664
1665         ast_str_append(&context->output_buffer, 0,
1666                         " Endpoint:  <Endpoint/CID.....................................>  <State.....>  <Channels.>\n");
1667
1668         if (context->recurse) {
1669                 context->indent_level++;
1670                 cli_endpoint_print_child_header("auth", context);
1671                 cli_endpoint_print_child_header("aor", context);
1672                 cli_endpoint_print_child_header("transport", context);
1673                 cli_endpoint_print_child_header("identify", context);
1674                 cli_endpoint_print_child_header("channel", context);
1675                 context->indent_level--;
1676         }
1677
1678         return 0;
1679 }
1680
1681 static void cli_endpoint_print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
1682 {
1683         RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
1684
1685         formatter_entry = ast_sip_lookup_cli_formatter(type);
1686         if (formatter_entry) {
1687                 formatter_entry->iterate((void *)obj, formatter_entry->print_body, context);
1688         }
1689 }
1690
1691 static int cli_endpoint_print_body(void *obj, void *arg, int flags)
1692 {
1693         struct ast_sip_endpoint *endpoint = obj;
1694         RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1695         struct ast_sip_cli_context *context = arg;
1696         const char *id = ast_sorcery_object_get_id(endpoint);
1697         char *print_name = NULL;
1698         int print_name_len;
1699         char *number = S_COR(endpoint->id.self.number.valid,
1700                 endpoint->id.self.number.str, NULL);
1701         int indent;
1702         int flexwidth;
1703
1704         ast_assert(context->output_buffer != NULL);
1705
1706         if (number) {
1707                 print_name_len = strlen(id) + strlen(number) + 2;
1708                 if (!(print_name = alloca(print_name_len))) {
1709                         return -1;
1710                 }
1711                 snprintf(print_name, print_name_len, "%s/%s", id, number);
1712         }
1713
1714         indent = CLI_INDENT_TO_SPACES(context->indent_level);
1715         flexwidth = CLI_LAST_TABSTOP - indent - 2;
1716
1717         ast_str_append(&context->output_buffer, 0, "%*s:  %-*.*s  %-12.12s  %d of %.0f\n",
1718                 indent, "Endpoint",
1719                 flexwidth, flexwidth, print_name ? print_name : id,
1720                 ast_sip_get_device_state(endpoint),
1721                 endpoint_snapshot->num_channels,
1722                 (double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
1723                                                                                                                 INFINITY
1724                                                                                                                 );
1725
1726         if (context->recurse) {
1727                 context->indent_level++;
1728
1729                 context->auth_direction = "Out";
1730                 cli_endpoint_print_child_body("auth", &endpoint->outbound_auths, context);
1731                 context->auth_direction = "In";
1732                 cli_endpoint_print_child_body("auth", &endpoint->inbound_auths, context);
1733
1734                 cli_endpoint_print_child_body("aor", endpoint->aors, context);
1735                 cli_endpoint_print_child_body("transport", endpoint, context);
1736                 cli_endpoint_print_child_body("identify", endpoint, context);
1737                 cli_endpoint_print_child_body("channel", endpoint, context);
1738
1739                 context->indent_level--;
1740
1741                 if (context->indent_level == 0) {
1742                         ast_str_append(&context->output_buffer, 0, "\n");
1743                 }
1744         }
1745
1746         if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
1747                 ast_str_append(&context->output_buffer, 0, "\n");
1748                 ast_sip_cli_print_sorcery_objectset(endpoint, context, 0);
1749         }
1750
1751         return 0;
1752 }
1753
1754 static struct ast_cli_entry cli_commands[] = {
1755         AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Channels",
1756                 .command = "pjsip list channels",
1757                 .usage = "Usage: pjsip list channels [ like <pattern> ]\n"
1758                                 "       List the active PJSIP channels\n"
1759                                 "       Optional regular expression pattern is used to filter the list.\n"),
1760         AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channels",
1761                 .command = "pjsip show channels",
1762                 .usage = "Usage: pjsip show channels [ like <pattern> ]\n"
1763                                 "       List(detailed) the active PJSIP channels\n"
1764                                 "       Optional regular expression pattern is used to filter the list.\n"),
1765         AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Channel",
1766                 .command = "pjsip show channel",
1767                 .usage = "Usage: pjsip show channel\n"
1768                                  "       List(detailed) the active PJSIP channel\n"),
1769
1770         AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
1771                 .command = "pjsip list endpoints",
1772                 .usage = "Usage: pjsip list endpoints [ like <pattern> ]\n"
1773                                 "       List the configured PJSIP endpoints\n"
1774                                 "       Optional regular expression pattern is used to filter the list.\n"),
1775         AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoints",
1776                 .command = "pjsip show endpoints",
1777                 .usage = "Usage: pjsip show endpoints [ like <pattern> ]\n"
1778                                 "       List(detailed) the configured PJSIP endpoints\n"
1779                                 "       Optional regular expression pattern is used to filter the list.\n"),
1780         AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoint",
1781                 .command = "pjsip show endpoint",
1782                 .usage = "Usage: pjsip show endpoint <id>\n"
1783                                  "       Show the configured PJSIP endpoint\n"),
1784 };
1785
1786 struct ast_sip_cli_formatter_entry *channel_formatter;
1787 struct ast_sip_cli_formatter_entry *endpoint_formatter;
1788
1789 int ast_res_pjsip_initialize_configuration(void)
1790 {
1791         if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) ||
1792             ast_manager_register_xml(AMI_SHOW_ENDPOINT, EVENT_FLAG_SYSTEM, ami_show_endpoint)) {
1793                 return -1;
1794         }
1795
1796         if (!(persistent_endpoints = ao2_container_alloc(PERSISTENT_BUCKETS, persistent_endpoint_hash, persistent_endpoint_cmp))) {
1797                 return -1;
1798         }
1799
1800         if (!(sip_sorcery = ast_sorcery_open())) {
1801                 ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
1802                 return -1;
1803         }
1804
1805         ast_sip_initialize_cli();
1806
1807         if (ast_sip_initialize_sorcery_auth()) {
1808                 ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
1809                 ast_sorcery_unref(sip_sorcery);
1810                 sip_sorcery = NULL;
1811                 return -1;
1812         }
1813
1814         ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "pjsip.conf,criteria=type=endpoint");
1815         ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
1816
1817         if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, sip_endpoint_apply_handler)) {
1818                 ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
1819                 ast_sorcery_unref(sip_sorcery);
1820                 sip_sorcery = NULL;
1821                 return -1;
1822         }
1823
1824         if (ast_sorcery_internal_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL)) {
1825                 ast_log(LOG_ERROR, "Failed to register nat_hook\n");
1826         }
1827
1828         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
1829         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
1830         ast_sorcery_object_field_register_alias(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.codecs));
1831         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.codecs));
1832         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, NULL, 0, 0);
1833         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6));
1834         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric));
1835         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ice_support));
1836         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_ptime", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_ptime));
1837         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_rport", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.force_rport));
1838         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rewrite_contact", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.rewrite_contact));
1839         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
1840         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
1841         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
1842         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, NULL, 0, 0);
1843         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, NULL, 0, 0);
1844         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));
1845         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));
1846         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, NULL, 0, 0);
1847         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, NULL, 0, 0);
1848         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
1849         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "media_address", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.address));
1850         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bind_rtp_to_media_address", "no", OPT_BOOL_T, 1, STRFLDSET(struct ast_sip_endpoint, media.bind_rtp_to_media_address));
1851         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username", ident_handler, ident_to_str, NULL, 0, 0);
1852         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled));
1853         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);
1854         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);
1855         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);
1856         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));
1857         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, NULL, 0, 0);
1858         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);
1859         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, NULL, 0, 0);
1860         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_inbound));
1861         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_outbound));
1862         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_pai));
1863         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_rpid", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_rpid));
1864         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rpid_immediate", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.rpid_immediate));
1865         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion));
1866         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes));
1867         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
1868         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0);
1869         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
1870         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
1871         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));
1872         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_keepalive", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.keepalive));
1873         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.timeout));
1874         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_timeout_hold", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.timeout_hold));
1875         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
1876         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
1877         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
1878         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, NULL, 0, 0);
1879         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, NULL, 0, 0);
1880         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, NULL, 0, 0);
1881         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));
1882         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.enabled));
1883         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0);
1884         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram));
1885         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect));
1886         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat));
1887         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6));
1888         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));
1889         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "language", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, language));
1890         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_on_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.onfeature));
1891         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_off_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.offfeature));
1892         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_transfer", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowtransfer));
1893         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "user_eq_phone", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, usereqphone));
1894         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_passthrough", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, moh_passthrough));
1895         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_owner", "-", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpowner));
1896         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));
1897         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);
1898         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);
1899         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));
1900         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
1901         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
1902         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));
1903         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromuser));
1904         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
1905         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser));
1906         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
1907         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "no", dtls_handler, dtlsverify_to_str, NULL, 0, 0);
1908         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "0", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);
1909         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);
1910         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);
1911         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);
1912         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, NULL, 0, 0);
1913         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, NULL, 0, 0);
1914         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, NULL, 0, 0);
1915         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_fingerprint", "", dtls_handler, dtlsfingerprint_to_str, NULL, 0, 0);
1916         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));
1917         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));
1918         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "g726_non_standard", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.g726_non_standard));
1919         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0);
1920         ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0);
1921         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, message_context));
1922         ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, accountcode));
1923
1924         if (ast_sip_initialize_sorcery_transport()) {
1925                 ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
1926                 ast_sorcery_unref(sip_sorcery);
1927                 sip_sorcery = NULL;
1928                 return -1;
1929         }
1930
1931         if (ast_sip_initialize_sorcery_location()) {
1932                 ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
1933                 ast_sorcery_unref(sip_sorcery);
1934                 sip_sorcery = NULL;
1935                 return -1;
1936         }
1937
1938         if (ast_sip_initialize_sorcery_qualify()) {
1939                 ast_log(LOG_ERROR, "Failed to register SIP qualify support with sorcery\n");
1940                 ast_sorcery_unref(sip_sorcery);
1941                 sip_sorcery = NULL;
1942                 return -1;
1943         }
1944
1945         ast_sorcery_observer_add(sip_sorcery, "endpoint", &endpoint_observers);
1946         ast_sorcery_observer_add(sip_sorcery, "contact", &state_contact_observer);
1947         ast_sorcery_observer_add(sip_sorcery, CONTACT_STATUS, &state_contact_status_observer);
1948
1949         if (ast_sip_initialize_sorcery_domain_alias()) {
1950                 ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
1951                 ast_sorcery_unref(sip_sorcery);
1952                 sip_sorcery = NULL;
1953                 return -1;
1954         }
1955
1956         if (ast_sip_initialize_sorcery_global()) {
1957                 ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
1958                 ast_sorcery_unref(sip_sorcery);
1959                 sip_sorcery = NULL;
1960                 return -1;
1961         }
1962
1963         channel_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1964         if (!channel_formatter) {
1965                 ast_log(LOG_ERROR, "Unable to allocate memory for channel_formatter\n");
1966                 ast_sorcery_unref(sip_sorcery);
1967                 sip_sorcery = NULL;
1968                 return -1;
1969         }
1970         channel_formatter->name = "channel";
1971         channel_formatter->print_header = cli_channel_print_header;
1972         channel_formatter->print_body = cli_channel_print_body;
1973         channel_formatter->get_container = cli_channel_get_container;
1974         channel_formatter->iterate = cli_channel_iterate;
1975         channel_formatter->retrieve_by_id = cli_channel_retrieve_by_id;
1976         channel_formatter->get_id = cli_channel_get_id;
1977
1978         endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1979         if (!endpoint_formatter) {
1980                 ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n");
1981                 ast_sorcery_unref(sip_sorcery);
1982                 sip_sorcery = NULL;
1983                 return -1;
1984         }
1985         endpoint_formatter->name = "endpoint";
1986         endpoint_formatter->print_header = cli_endpoint_print_header;
1987         endpoint_formatter->print_body = cli_endpoint_print_body;
1988         endpoint_formatter->get_container = cli_endpoint_get_container;
1989         endpoint_formatter->iterate = cli_endpoint_iterate;
1990         endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id;
1991         endpoint_formatter->get_id = ast_sorcery_object_get_id;
1992
1993         ast_sip_register_cli_formatter(channel_formatter);
1994         ast_sip_register_cli_formatter(endpoint_formatter);
1995         ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
1996
1997         ast_sorcery_load(sip_sorcery);
1998
1999         return 0;
2000 }
2001
2002 void ast_res_pjsip_destroy_configuration(void)
2003 {
2004         ast_sorcery_observer_remove(sip_sorcery, CONTACT_STATUS, &state_contact_status_observer);
2005         ast_sorcery_observer_remove(sip_sorcery, "contact", &state_contact_observer);
2006         ast_sip_destroy_sorcery_global();
2007         ast_sip_destroy_sorcery_location();
2008         ast_sip_destroy_sorcery_auth();
2009         ast_sip_destroy_sorcery_transport();
2010         ast_manager_unregister(AMI_SHOW_ENDPOINT);
2011         ast_manager_unregister(AMI_SHOW_ENDPOINTS);
2012         ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
2013         ast_sip_unregister_cli_formatter(endpoint_formatter);
2014         ast_sip_unregister_cli_formatter(channel_formatter);
2015         ast_sorcery_unref(sip_sorcery);
2016         ao2_cleanup(persistent_endpoints);
2017 }
2018
2019 int ast_res_pjsip_reload_configuration(void)
2020 {
2021         if (sip_sorcery) {
2022                 ast_sorcery_reload(sip_sorcery);
2023         }
2024         return 0;
2025 }
2026
2027 static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription)
2028 {
2029         ast_string_field_free_memory(&subscription->mwi);
2030 }
2031
2032 static void info_configuration_destroy(struct ast_sip_endpoint_info_configuration *info)
2033 {
2034         ast_string_field_free_memory(&info->recording);
2035 }
2036
2037 static void media_configuration_destroy(struct ast_sip_endpoint_media_configuration *media)
2038 {
2039         ast_string_field_free_memory(&media->rtp);
2040         ast_string_field_free_memory(media);
2041 }
2042
2043 static void endpoint_destructor(void* obj)
2044 {
2045         struct ast_sip_endpoint *endpoint = obj;
2046
2047         ast_string_field_free_memory(endpoint);
2048
2049         ao2_ref(endpoint->media.codecs, -1);
2050         subscription_configuration_destroy(&endpoint->subscription);
2051         info_configuration_destroy(&endpoint->info);
2052         media_configuration_destroy(&endpoint->media);
2053         ast_sip_auth_vector_destroy(&endpoint->inbound_auths);
2054         ast_sip_auth_vector_destroy(&endpoint->outbound_auths);
2055         ast_party_id_free(&endpoint->id.self);
2056         endpoint->pickup.named_callgroups = ast_unref_namedgroups(endpoint->pickup.named_callgroups);
2057         endpoint->pickup.named_pickupgroups = ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
2058         ao2_cleanup(endpoint->persistent);
2059         ast_variables_destroy(endpoint->channel_vars);
2060 }
2061
2062 static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)
2063 {
2064         return ast_string_field_init(&subscription->mwi, 64);
2065 }
2066
2067 static int init_info_configuration(struct ast_sip_endpoint_info_configuration *info)
2068 {
2069         return ast_string_field_init(&info->recording, 32);
2070 }
2071
2072 static int init_media_configuration(struct ast_sip_endpoint_media_configuration *media)
2073 {
2074         return ast_string_field_init(media, 64) || ast_string_field_init(&media->rtp, 32);
2075 }
2076
2077 void *ast_sip_endpoint_alloc(const char *name)
2078 {
2079         struct ast_sip_endpoint *endpoint = ast_sorcery_generic_alloc(sizeof(*endpoint), endpoint_destructor);
2080         if (!endpoint) {
2081                 return NULL;
2082         }
2083         if (ast_string_field_init(endpoint, 64)) {
2084                 ao2_cleanup(endpoint);
2085                 return NULL;
2086         }
2087         if (!(endpoint->media.codecs = ast_format_cap_alloc(AST_FORMAT_CAP_FLAG_DEFAULT))) {
2088                 ao2_cleanup(endpoint);
2089                 return NULL;
2090         }
2091         if (init_subscription_configuration(&endpoint->subscription)) {
2092                 ao2_cleanup(endpoint);
2093                 return NULL;
2094         }
2095         if (init_info_configuration(&endpoint->info)) {
2096                 ao2_cleanup(endpoint);
2097                 return NULL;
2098         }
2099         if (init_media_configuration(&endpoint->media)) {
2100                 ao2_cleanup(endpoint);
2101                 return NULL;
2102         }
2103         ast_party_id_init(&endpoint->id.self);
2104         return endpoint;
2105 }
2106
2107 struct ao2_container *ast_sip_get_endpoints(void)
2108 {
2109         struct ao2_container *endpoints;
2110
2111         endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
2112
2113         return endpoints;
2114 }
2115
2116 struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void)
2117 {
2118         RAII_VAR(char *, name, ast_sip_global_default_outbound_endpoint(), ast_free);
2119         return ast_strlen_zero(name) ? NULL : ast_sorcery_retrieve_by_id(
2120                 sip_sorcery, "endpoint", name);
2121 }
2122
2123 int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
2124 {
2125         int i;
2126
2127         for (i = 0; i < AST_VECTOR_SIZE(auths); ++i) {
2128                 /* Using AST_VECTOR_GET is safe since the vector is immutable */
2129                 const char *name = AST_VECTOR_GET(auths, i);
2130                 out[i] = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, name);
2131                 if (!out[i]) {
2132                         ast_log(LOG_NOTICE, "Couldn't find auth '%s'. Cannot authenticate\n", name);
2133                         return -1;
2134                 }
2135         }
2136
2137         return 0;
2138 }
2139
2140 void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
2141 {
2142         int i;
2143         for (i = 0; i < num_auths; ++i) {
2144                 ao2_cleanup(auths[i]);
2145         }
2146 }
2147
2148 struct ast_sorcery *ast_sip_get_sorcery(void)
2149 {
2150         return sip_sorcery;
2151 }