Asterisk - The Open Source Telephony Project  21.4.1
pjsip_configuration.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Matt Jordan <mjordan@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 #include "asterisk.h"
20 
21 #include <pjsip.h>
22 #include <pjsip_ua.h>
23 
24 #include "asterisk/res_geolocation.h"
25 #include "asterisk/res_pjsip.h"
26 #include "include/res_pjsip_private.h"
27 #include "asterisk/res_pjsip_cli.h"
28 #include "asterisk/acl.h"
29 #include "asterisk/manager.h"
30 #include "asterisk/astobj2.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/sorcery.h"
33 #include "asterisk/callerid.h"
34 #include "asterisk/test.h"
35 #include "asterisk/statsd.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/stream.h"
38 #include "asterisk/stasis.h"
40 #include "asterisk/res_stir_shaken.h"
41 
42 /*! \brief Number of buckets for persistent endpoint information */
43 #define PERSISTENT_BUCKETS 53
44 
45 /*! \brief Persistent endpoint information */
47  /*! \brief Asterisk endpoint itself */
49 };
50 
51 /*! \brief Container for persistent endpoint information */
52 static struct ao2_container *persistent_endpoints;
53 
54 static struct ast_sorcery *sip_sorcery;
55 
56 static struct stasis_subscription *acl_change_sub;
57 
58 /*! \brief Hashing function for persistent endpoint information */
59 static int persistent_endpoint_hash(const void *obj, const int flags)
60 {
61  const struct sip_persistent_endpoint *persistent = obj;
62  const char *id = (flags & OBJ_KEY ? obj : ast_endpoint_get_resource(persistent->endpoint));
63 
64  return ast_str_hash(id);
65 }
66 
67 /*! \brief Comparison function for persistent endpoint information */
68 static int persistent_endpoint_cmp(void *obj, void *arg, int flags)
69 {
70  const struct sip_persistent_endpoint *persistent1 = obj;
71  const struct sip_persistent_endpoint *persistent2 = arg;
72  const char *id = (flags & OBJ_KEY ? arg : ast_endpoint_get_resource(persistent2->endpoint));
73 
74  return !strcmp(ast_endpoint_get_resource(persistent1->endpoint), id) ? CMP_MATCH | CMP_STOP : 0;
75 }
76 
77 static void endpoint_deleted_observer(const void *object)
78 {
79  const struct ast_sip_endpoint *endpoint = object;
80 
81  ao2_find(persistent_endpoints, ast_endpoint_get_resource(endpoint->persistent),
83 }
84 
85 static const struct ast_sorcery_observer endpoint_observers = {
86  .deleted = endpoint_deleted_observer,
87 };
88 
89 static int endpoint_acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
90 {
91  struct ast_sip_endpoint *endpoint = obj;
92  int error = 0;
93  int ignore;
94 
95  if (ast_strlen_zero(var->value)) return 0;
96 
97  if (!strncmp(var->name, "contact_", 8)) {
98  ast_append_acl(var->name + 8, var->value, &endpoint->contact_acl, &error, &ignore);
99  } else {
100  ast_append_acl(var->name, var->value, &endpoint->acl, &error, &ignore);
101  }
102 
103  return error;
104 }
105 
106 static int acl_to_str(const void *obj, const intptr_t *args, char **buf)
107 {
108  const struct ast_sip_endpoint *endpoint = obj;
109  struct ast_acl_list *acl_list;
110  struct ast_acl *first_acl;
111 
112  if (endpoint && !ast_acl_list_is_empty(acl_list=endpoint->acl)) {
113  AST_LIST_LOCK(acl_list);
114  first_acl = AST_LIST_FIRST(acl_list);
115  if (ast_strlen_zero(first_acl->name)) {
116  *buf = "deny/permit";
117  } else {
118  *buf = first_acl->name;
119  }
120  AST_LIST_UNLOCK(acl_list);
121  }
122 
123  *buf = ast_strdup(*buf);
124  return 0;
125 }
126 
127 static int contact_acl_to_str(const void *obj, const intptr_t *args, char **buf)
128 {
129  const struct ast_sip_endpoint *endpoint = obj;
130  struct ast_acl_list *acl_list;
131  struct ast_acl *first_acl;
132 
133  if (endpoint && !ast_acl_list_is_empty(acl_list=endpoint->contact_acl)) {
134  AST_LIST_LOCK(acl_list);
135  first_acl = AST_LIST_FIRST(acl_list);
136  if (ast_strlen_zero(first_acl->name)) {
137  *buf = "deny/permit";
138  } else {
139  *buf = first_acl->name;
140  }
141  AST_LIST_UNLOCK(acl_list);
142  }
143 
144  *buf = ast_strdup(*buf);
145  return 0;
146 }
147 
148 static int dtmf_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
149 {
150  struct ast_sip_endpoint *endpoint = obj;
151  int dtmf = ast_sip_str_to_dtmf(var->value);
152 
153  if (dtmf == -1) {
154  return -1;
155  }
156 
157  endpoint->dtmf = dtmf;
158  return 0;
159 }
160 
161 static int dtmf_to_str(const void *obj, const intptr_t *args, char **buf)
162 {
163  const struct ast_sip_endpoint *endpoint = obj;
164  char dtmf_str[20];
165  int result = -1;
166 
167  result = ast_sip_dtmf_to_str(endpoint->dtmf, dtmf_str, sizeof(dtmf_str));
168 
169  if (result == 0) {
170  *buf = ast_strdup(dtmf_str);
171  } else {
172  *buf = ast_strdup("none");
173  }
174  return 0;
175 }
176 
177 static int prack_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
178 {
179  struct ast_sip_endpoint *endpoint = obj;
180 
181  /* clear all */
182  endpoint->extensions.flags &= ~(PJSIP_INV_SUPPORT_100REL | PJSIP_INV_REQUIRE_100REL);
183 
184  if (ast_true(var->value)) {
185  endpoint->extensions.flags |= PJSIP_INV_SUPPORT_100REL;
186  endpoint->rel100 = AST_SIP_100REL_SUPPORTED;
187  } else if (!strcasecmp(var->value, "peer_supported")) {
188  endpoint->extensions.flags |= PJSIP_INV_SUPPORT_100REL;
189  endpoint->rel100 = AST_SIP_100REL_PEER_SUPPORTED;
190  } else if (!strcasecmp(var->value, "required")) {
191  endpoint->extensions.flags |= PJSIP_INV_REQUIRE_100REL;
192  endpoint->rel100 = AST_SIP_100REL_REQUIRED;
193  } else if (ast_false(var->value)) {
194  endpoint->rel100 = AST_SIP_100REL_UNSUPPORTED;
195  } else {
196  return -1;
197  }
198 
199  return 0;
200 }
201 
202 static int prack_to_str(const void *obj, const intptr_t *args, char **buf)
203 {
204  const struct ast_sip_endpoint *endpoint = obj;
205 
206  if (endpoint->rel100 == AST_SIP_100REL_SUPPORTED) {
207  *buf = "yes";
208  } else if (endpoint->rel100 == AST_SIP_100REL_PEER_SUPPORTED) {
209  *buf = "peer_supported";
210  } else if (endpoint->rel100 == AST_SIP_100REL_REQUIRED) {
211  *buf = "required";
212  } else {
213  *buf = "no";
214  }
215 
216  *buf = ast_strdup(*buf);
217  return 0;
218 }
219 
220 static int timers_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
221 {
222  struct ast_sip_endpoint *endpoint = obj;
223 
224  /* clear all */
225  endpoint->extensions.flags &= ~(PJSIP_INV_SUPPORT_TIMER | PJSIP_INV_REQUIRE_TIMER
226  | PJSIP_INV_ALWAYS_USE_TIMER);
227 
228  /* set only the specified flag and let pjsip normalize if needed */
229  if (ast_true(var->value)) {
230  endpoint->extensions.flags |= PJSIP_INV_SUPPORT_TIMER;
231  } else if (!strcasecmp(var->value, "required")) {
232  endpoint->extensions.flags |= PJSIP_INV_REQUIRE_TIMER;
233  } else if (!strcasecmp(var->value, "always") || !strcasecmp(var->value, "forced")) {
234  endpoint->extensions.flags |= (PJSIP_INV_SUPPORT_TIMER | PJSIP_INV_ALWAYS_USE_TIMER);
235  } else if (!ast_false(var->value)) {
236  return -1;
237  }
238 
239  return 0;
240 }
241 
242 static int timers_to_str(const void *obj, const intptr_t *args, char **buf)
243 {
244  const struct ast_sip_endpoint *endpoint = obj;
245 
246  if (endpoint->extensions.flags & PJSIP_INV_ALWAYS_USE_TIMER) {
247  *buf = "always";
248  } else if (endpoint->extensions.flags & PJSIP_INV_REQUIRE_TIMER) {
249  *buf = "required";
250  } else if (endpoint->extensions.flags & PJSIP_INV_SUPPORT_TIMER) {
251  *buf = "yes";
252  } else {
253  *buf = "no";
254  }
255 
256  *buf = ast_strdup(*buf);
257  return 0;
258 }
259 
260 static int security_mechanism_to_str(const void *obj, const intptr_t *args, char **buf)
261 {
262  const struct ast_sip_endpoint *endpoint = obj;
263 
264  return ast_sip_security_mechanisms_to_str(&endpoint->security_mechanisms, 0, buf);
265 }
266 
267 static int security_mechanism_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
268 {
269  struct ast_sip_endpoint *endpoint = obj;
270 
272 }
273 
274 static const char *security_negotiation_map[] = {
275  [AST_SIP_SECURITY_NEG_NONE] = "no",
276  [AST_SIP_SECURITY_NEG_MEDIASEC] = "mediasec",
277 };
278 
279 static int security_negotiation_to_str(const void *obj, const intptr_t *args, char **buf)
280 {
281  const struct ast_sip_endpoint *endpoint = obj;
282  if (ARRAY_IN_BOUNDS(endpoint->security_negotiation, security_negotiation_map)) {
283  *buf = ast_strdup(security_negotiation_map[endpoint->security_negotiation]);
284  }
285  return 0;
286 }
287 
288 int ast_sip_set_security_negotiation(enum ast_sip_security_negotiation *security_negotiation, const char *val) {
289  if (!strcasecmp("no", val)) {
290  *security_negotiation = AST_SIP_SECURITY_NEG_NONE;
291  } else if (!strcasecmp("mediasec", val)) {
292  *security_negotiation = AST_SIP_SECURITY_NEG_MEDIASEC;
293  } else {
294  return -1;
295  }
296  return 0;
297 }
298 
299 static int security_negotiation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
300 {
301  struct ast_sip_endpoint *endpoint = obj;
302 
303  return ast_sip_set_security_negotiation(&endpoint->security_negotiation, var->value);
304 }
305 
306 void ast_sip_auth_vector_destroy(struct ast_sip_auth_vector *auths)
307 {
308  int i;
309  size_t size;
310 
311  if (!auths) {
312  return;
313  }
314 
315  size = AST_VECTOR_SIZE(auths);
316 
317  for (i = 0; i < size; ++i) {
318  const char *name = AST_VECTOR_REMOVE_UNORDERED(auths, 0);
319  ast_free((char *) name);
320  }
321  AST_VECTOR_FREE(auths);
322 }
323 
324 int ast_sip_auth_vector_init(struct ast_sip_auth_vector *auths, const char *value)
325 {
326  char *auth_names = ast_strdupa(value);
327  char *val;
328 
329  ast_assert(auths != NULL);
330 
331  if (AST_VECTOR_SIZE(auths)) {
332  ast_sip_auth_vector_destroy(auths);
333  }
334  if (AST_VECTOR_INIT(auths, 1)) {
335  return -1;
336  }
337 
338  while ((val = ast_strip(strsep(&auth_names, ",")))) {
339  if (ast_strlen_zero(val)) {
340  continue;
341  }
342 
343  val = ast_strdup(val);
344  if (!val) {
345  goto failure;
346  }
347  if (AST_VECTOR_APPEND(auths, val)) {
348  ast_free(val);
349 
350  goto failure;
351  }
352  }
353  return 0;
354 
355 failure:
356  ast_sip_auth_vector_destroy(auths);
357  return -1;
358 }
359 
360 static int inbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
361 {
362  struct ast_sip_endpoint *endpoint = obj;
363 
364  return ast_sip_auth_vector_init(&endpoint->inbound_auths, var->value);
365 }
366 
367 static int outbound_auth_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
368 {
369  struct ast_sip_endpoint *endpoint = obj;
370 
371  return ast_sip_auth_vector_init(&endpoint->outbound_auths, var->value);
372 }
373 
374 int ast_sip_auths_to_str(const struct ast_sip_auth_vector *auths, char **buf)
375 {
376  if (!auths || !AST_VECTOR_SIZE(auths)) {
377  return 0;
378  }
379 
380  if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
381  return -1;
382  }
383 
384  /* I feel like accessing the vector's elem array directly is cheating...*/
385  ast_join_delim(*buf, MAX_OBJECT_FIELD, auths->elems, AST_VECTOR_SIZE(auths), ',');
386  return 0;
387 }
388 
389 static int inbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
390 {
391  const struct ast_sip_endpoint *endpoint = obj;
392  return ast_sip_auths_to_str(&endpoint->inbound_auths, buf);
393 }
394 
395 static int outbound_auths_to_str(const void *obj, const intptr_t *args, char **buf)
396 {
397  const struct ast_sip_endpoint *endpoint = obj;
398  return ast_sip_auths_to_str(&endpoint->outbound_auths, buf);
399 }
400 
401 /*!
402  * \internal
403  * \brief Convert identify_by method to string.
404  *
405  * \param method Method value to convert to string
406  *
407  * \return String representation.
408  */
409 static const char *sip_endpoint_identifier_type2str(enum ast_sip_endpoint_identifier_type method)
410 {
411  const char *str = "<unknown>";
412 
413  switch (method) {
414  case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME:
415  str = "username";
416  break;
417  case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME:
418  str = "auth_username";
419  break;
420  case AST_SIP_ENDPOINT_IDENTIFY_BY_IP:
421  str = "ip";
422  break;
423  case AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER:
424  str = "header";
425  break;
426  case AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI:
427  str = "request_uri";
428  break;
429  }
430  return str;
431 }
432 
433 /*!
434  * \internal
435  * \brief Convert string to an endpoint identifier token.
436  *
437  * \param str String to convert
438  *
439  * \retval enum ast_sip_endpoint_identifier_type token value on success.
440  * \retval -1 on failure.
441  */
442 static int sip_endpoint_identifier_str2type(const char *str)
443 {
444  int method;
445 
446  if (!strcasecmp(str, "username")) {
447  method = AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME;
448  } else if (!strcasecmp(str, "auth_username")) {
449  method = AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME;
450  } else if (!strcasecmp(str, "ip")) {
451  method = AST_SIP_ENDPOINT_IDENTIFY_BY_IP;
452  } else if (!strcasecmp(str, "header")) {
453  method = AST_SIP_ENDPOINT_IDENTIFY_BY_HEADER;
454  } else if (!strcasecmp(str, "request_uri")) {
455  method = AST_SIP_ENDPOINT_IDENTIFY_BY_REQUEST_URI;
456  } else {
457  method = -1;
458  }
459  return method;
460 }
461 
462 static int ident_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
463 {
464  struct ast_sip_endpoint *endpoint = obj;
465  char *idents = ast_strdupa(var->value);
466  char *val;
467  int method;
468 
469  /*
470  * If there's already something in the vector when we get here,
471  * it's the default value so we need to clean it out.
472  */
473  if (AST_VECTOR_SIZE(&endpoint->ident_method_order)) {
475  endpoint->ident_method = 0;
476  }
477 
478  while ((val = ast_strip(strsep(&idents, ",")))) {
479  if (ast_strlen_zero(val)) {
480  continue;
481  }
482 
483  method = sip_endpoint_identifier_str2type(val);
484  if (method == -1) {
485  ast_log(LOG_ERROR, "Unrecognized identification method %s specified for endpoint %s\n",
486  val, ast_sorcery_object_get_id(endpoint));
488  endpoint->ident_method = 0;
489  return -1;
490  }
491  if (endpoint->ident_method & method) {
492  /* We are already identifying by this method. No need to do it again. */
493  continue;
494  }
495 
496  endpoint->ident_method |= method;
497  AST_VECTOR_APPEND(&endpoint->ident_method_order, method);
498  }
499 
500  return 0;
501 }
502 
503 static int ident_to_str(const void *obj, const intptr_t *args, char **buf)
504 {
505  const struct ast_sip_endpoint *endpoint = obj;
506  int methods;
507  int idx;
508  int buf_used = 0;
509  int buf_size = MAX_OBJECT_FIELD;
510 
511  methods = AST_VECTOR_SIZE(&endpoint->ident_method_order);
512  if (!methods) {
513  return 0;
514  }
515 
516  *buf = ast_malloc(buf_size);
517  if (!*buf) {
518  return -1;
519  }
520 
521  for (idx = 0; idx < methods; ++idx) {
522  enum ast_sip_endpoint_identifier_type method;
523  const char *method_str;
524 
525  method = AST_VECTOR_GET(&endpoint->ident_method_order, idx);
526  method_str = sip_endpoint_identifier_type2str(method);
527 
528  /* Should never have an "<unknown>" method string */
529  ast_assert(strcmp(method_str, "<unknown>"));
530  if (!strcmp(method_str, "<unknown>")) {
531  continue;
532  }
533 
534  buf_used += snprintf(*buf + buf_used, buf_size - buf_used, "%s%s",
535  method_str, idx < methods - 1 ? "," : "");
536  if (buf_size <= buf_used) {
537  /* Need more room than available, truncating. */
538  *(*buf + (buf_size - 1)) = '\0';
539  ast_log(LOG_WARNING, "Truncated identify_by string: %s\n", *buf);
540  break;
541  }
542  }
543 
544  return 0;
545 }
546 
547 static int media_address_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
548 {
549  struct ast_sip_endpoint *endpoint = obj;
550  struct ast_sockaddr addr;
551 
552  if (ast_sockaddr_parse(&addr, var->value, 0)) {
553  /* If we're able to parse as an IP, ensure it's formatted correctly for later */
554  ast_string_field_set(endpoint, media.address, ast_sockaddr_stringify_addr_remote(&addr));
555  } else {
556  /* If we weren't able to parse it as an IP, just assume it's a hostname */
557  ast_string_field_set(endpoint, media.address, var->value);
558  }
559 
560  return 0;
561 }
562 
563 static int media_address_to_str(const void *obj, const intptr_t *args, char **buf)
564 {
565  const struct ast_sip_endpoint *endpoint = obj;
566  *buf = ast_strdup(endpoint->media.address);
567  return 0;
568 }
569 
570 static int redirect_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
571 {
572  struct ast_sip_endpoint *endpoint = obj;
573 
574  if (!strcasecmp(var->value, "user")) {
575  endpoint->redirect_method = AST_SIP_REDIRECT_USER;
576  } else if (!strcasecmp(var->value, "uri_core")) {
577  endpoint->redirect_method = AST_SIP_REDIRECT_URI_CORE;
578  } else if (!strcasecmp(var->value, "uri_pjsip")) {
579  endpoint->redirect_method = AST_SIP_REDIRECT_URI_PJSIP;
580  } else {
581  ast_log(LOG_ERROR, "Unrecognized redirect method %s specified for endpoint %s\n",
582  var->value, ast_sorcery_object_get_id(endpoint));
583  return -1;
584  }
585 
586  return 0;
587 }
588 
589 static int direct_media_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
590 {
591  struct ast_sip_endpoint *endpoint = obj;
592 
593  if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
594  endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
595  } else if (!strcasecmp(var->value, "update")) {
596  endpoint->media.direct_media.method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
597  } else {
598  ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
599  var->value, var->name, ast_sorcery_object_get_id(endpoint));
600  return -1;
601  }
602  return 0;
603 }
604 
605 static const char *id_configuration_refresh_methods[] = {
606  [AST_SIP_SESSION_REFRESH_METHOD_INVITE] = "invite",
607  [AST_SIP_SESSION_REFRESH_METHOD_UPDATE] = "update"
608 };
609 
610 static int direct_media_method_to_str(const void *obj, const intptr_t *args, char **buf)
611 {
612  const struct ast_sip_endpoint *endpoint = obj;
613  if (ARRAY_IN_BOUNDS(endpoint->id.refresh_method, id_configuration_refresh_methods)) {
614  *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
615  }
616  return 0;
617 }
618 
619 static int connected_line_method_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
620 {
621  struct ast_sip_endpoint *endpoint = obj;
622 
623  if (!strcasecmp(var->value, "invite") || !strcasecmp(var->value, "reinvite")) {
624  endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_INVITE;
625  } else if (!strcasecmp(var->value, "update")) {
626  endpoint->id.refresh_method = AST_SIP_SESSION_REFRESH_METHOD_UPDATE;
627  } else {
628  ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
629  var->value, var->name, ast_sorcery_object_get_id(endpoint));
630  return -1;
631  }
632  return 0;
633 }
634 
635 static int connected_line_method_to_str(const void *obj, const intptr_t *args, char **buf)
636 {
637  const struct ast_sip_endpoint *endpoint = obj;
638  *buf = ast_strdup(id_configuration_refresh_methods[endpoint->id.refresh_method]);
639  return 0;
640 }
641 
642 static int direct_media_glare_mitigation_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
643 {
644  struct ast_sip_endpoint *endpoint = obj;
645 
646  if (!strcasecmp(var->value, "none")) {
647  endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE;
648  } else if (!strcasecmp(var->value, "outgoing")) {
649  endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING;
650  } else if (!strcasecmp(var->value, "incoming")) {
651  endpoint->media.direct_media.glare_mitigation = AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING;
652  } else {
653  ast_log(LOG_NOTICE, "Unrecognized option value %s for %s on endpoint %s\n",
654  var->value, var->name, ast_sorcery_object_get_id(endpoint));
655  return -1;
656  }
657 
658  return 0;
659 }
660 
661 static const char *direct_media_glare_mitigation_map[] = {
662  [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_NONE] = "none",
663  [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_OUTGOING] = "outgoing",
664  [AST_SIP_DIRECT_MEDIA_GLARE_MITIGATION_INCOMING] = "incoming"
665 };
666 
667 static int direct_media_glare_mitigation_to_str(const void *obj, const intptr_t *args, char **buf)
668 {
669  const struct ast_sip_endpoint *endpoint = obj;
670  if (ARRAY_IN_BOUNDS(endpoint->media.direct_media.glare_mitigation, direct_media_glare_mitigation_map)) {
671  *buf = ast_strdup(direct_media_glare_mitigation_map[endpoint->media.direct_media.glare_mitigation]);
672  }
673 
674  return 0;
675 }
676 
677 static int caller_id_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
678 {
679  struct ast_sip_endpoint *endpoint = obj;
680  char cid_name[80] = { '\0' };
681  char cid_num[80] = { '\0' };
682 
683  ast_free(endpoint->id.self.name.str);
684  endpoint->id.self.name.str = NULL;
685  endpoint->id.self.name.valid = 0;
686  ast_free(endpoint->id.self.number.str);
687  endpoint->id.self.number.str = NULL;
688  endpoint->id.self.number.valid = 0;
689 
690  ast_callerid_split(var->value, cid_name, sizeof(cid_name), cid_num, sizeof(cid_num));
691  if (!ast_strlen_zero(cid_name)) {
692  endpoint->id.self.name.str = ast_strdup(cid_name);
693  if (!endpoint->id.self.name.str) {
694  return -1;
695  }
696  endpoint->id.self.name.valid = 1;
697  }
698  if (!ast_strlen_zero(cid_num)) {
699  endpoint->id.self.number.str = ast_strdup(cid_num);
700  if (!endpoint->id.self.number.str) {
701  return -1;
702  }
703  endpoint->id.self.number.valid = 1;
704  }
705  return 0;
706 }
707 
708 static int caller_id_to_str(const void *obj, const intptr_t *args, char **buf)
709 {
710  const struct ast_sip_endpoint *endpoint = obj;
711  const char *name = S_COR(endpoint->id.self.name.valid,
712  endpoint->id.self.name.str, NULL);
713  const char *number = S_COR(endpoint->id.self.number.valid,
714  endpoint->id.self.number.str, NULL);
715 
716  /* make sure size is at least 10 - that should cover the "<unknown>"
717  case as well as any additional formatting characters added in
718  the name and/or number case. */
719  int size = 10;
720  size += name ? strlen(name) : 0;
721  size += number ? strlen(number) : 0;
722 
723  if (!(*buf = ast_calloc(size + 1, sizeof(char)))) {
724  return -1;
725  }
726 
727  ast_callerid_merge(*buf, size + 1, name, number, NULL);
728  return 0;
729 }
730 
731 static int caller_id_privacy_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
732 {
733  struct ast_sip_endpoint *endpoint = obj;
734  int callingpres = ast_parse_caller_presentation(var->value);
735  if (callingpres == -1 && sscanf(var->value, "%d", &callingpres) != 1) {
736  return -1;
737  }
738  endpoint->id.self.number.presentation = callingpres;
739  endpoint->id.self.name.presentation = callingpres;
740  return 0;
741 }
742 
743 static int caller_id_privacy_to_str(const void *obj, const intptr_t *args, char **buf)
744 {
745  const struct ast_sip_endpoint *endpoint = obj;
746  const char *presentation = ast_named_caller_presentation(
747  endpoint->id.self.name.presentation);
748 
749  *buf = ast_strdup(presentation);
750  return 0;
751 }
752 
753 static int caller_id_tag_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
754 {
755  struct ast_sip_endpoint *endpoint = obj;
756 
757  ast_free(endpoint->id.self.tag);
758  endpoint->id.self.tag = ast_strdup(var->value);
759 
760  return endpoint->id.self.tag ? 0 : -1;
761 }
762 
763 static int caller_id_tag_to_str(const void *obj, const intptr_t *args, char **buf)
764 {
765  const struct ast_sip_endpoint *endpoint = obj;
766  *buf = ast_strdup(endpoint->id.self.tag);
767  return 0;
768 }
769 
770 static int media_encryption_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
771 {
772  struct ast_sip_endpoint *endpoint = obj;
773 
774  if (!strcasecmp("no", var->value)) {
775  endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_NONE;
776  } else if (!strcasecmp("sdes", var->value)) {
777  endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_SDES;
778  } else if (!strcasecmp("dtls", var->value)) {
779  endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
780  return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, "dtlsenable", "yes");
781  } else {
782  return -1;
783  }
784 
785  return 0;
786 }
787 
788 static const char *media_encryption_map[] = {
789  [AST_SIP_MEDIA_TRANSPORT_INVALID] = "invalid",
790  [AST_SIP_MEDIA_ENCRYPT_NONE] = "no",
791  [AST_SIP_MEDIA_ENCRYPT_SDES] = "sdes",
792  [AST_SIP_MEDIA_ENCRYPT_DTLS] = "dtls",
793 };
794 
795 static int media_encryption_to_str(const void *obj, const intptr_t *args, char **buf)
796 {
797  const struct ast_sip_endpoint *endpoint = obj;
798  if (ARRAY_IN_BOUNDS(endpoint->media.rtp.encryption, media_encryption_map)) {
799  *buf = ast_strdup(media_encryption_map[
800  endpoint->media.rtp.encryption]);
801  }
802  return 0;
803 }
804 
805 static int stir_shaken_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
806 {
807  struct ast_sip_endpoint *endpoint = obj;
808 
809  ast_log(LOG_WARNING, "Endpoint %s: Option 'stir_shaken' is no longer supported. Use 'stir_shaken_profile' instead.\n",
810  ast_sorcery_object_get_id(endpoint));
811  endpoint->stir_shaken = 0;
812 
813  return 0;
814 }
815 
816 static int stir_shaken_to_str(const void *obj, const intptr_t *args, char **buf)
817 {
818  *buf = ast_strdup("no");
819 
820  return 0;
821 }
822 
823 static int group_handler(const struct aco_option *opt,
824  struct ast_variable *var, void *obj)
825 {
826  struct ast_sip_endpoint *endpoint = obj;
827 
828  if (!strncmp(var->name, "call_group", 10)) {
829  endpoint->pickup.callgroup = ast_get_group(var->value);
830  } else if (!strncmp(var->name, "pickup_group", 12)) {
831  endpoint->pickup.pickupgroup = ast_get_group(var->value);
832  } else {
833  return -1;
834  }
835 
836  return 0;
837 }
838 
839 static int callgroup_to_str(const void *obj, const intptr_t *args, char **buf)
840 {
841  const struct ast_sip_endpoint *endpoint = obj;
842 
843  if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
844  return -1;
845  }
846 
848  return 0;
849 }
850 
851 static int pickupgroup_to_str(const void *obj, const intptr_t *args, char **buf)
852 {
853  const struct ast_sip_endpoint *endpoint = obj;
854 
855  if (!(*buf = ast_calloc(MAX_OBJECT_FIELD, sizeof(char)))) {
856  return -1;
857  }
858 
860  return 0;
861 }
862 
863 static int named_groups_handler(const struct aco_option *opt,
864  struct ast_variable *var, void *obj)
865 {
866  struct ast_sip_endpoint *endpoint = obj;
867 
868  if (!strncmp(var->name, "named_call_group", 16)) {
869  if (ast_strlen_zero(var->value)) {
870  endpoint->pickup.named_callgroups =
871  ast_unref_namedgroups(endpoint->pickup.named_callgroups);
872  } else if (!(endpoint->pickup.named_callgroups =
873  ast_get_namedgroups(var->value))) {
874  return -1;
875  }
876  } else if (!strncmp(var->name, "named_pickup_group", 18)) {
877  if (ast_strlen_zero(var->value)) {
878  endpoint->pickup.named_pickupgroups =
879  ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
880  } else if (!(endpoint->pickup.named_pickupgroups =
881  ast_get_namedgroups(var->value))) {
882  return -1;
883  }
884  } else {
885  return -1;
886  }
887 
888  return 0;
889 }
890 
891 static int named_callgroups_to_str(const void *obj, const intptr_t *args, char **buf)
892 {
893  const struct ast_sip_endpoint *endpoint = obj;
894  RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
895 
897  *buf = ast_strdup(ast_str_buffer(str));
898  return 0;
899 }
900 
901 static int named_pickupgroups_to_str(const void *obj, const intptr_t *args, char **buf)
902 {
903  const struct ast_sip_endpoint *endpoint = obj;
904  RAII_VAR(struct ast_str *, str, ast_str_create(MAX_OBJECT_FIELD), ast_free);
905 
907  *buf = ast_strdup(ast_str_buffer(str));
908  return 0;
909 }
910 
911 static int dtls_handler(const struct aco_option *opt,
912  struct ast_variable *var, void *obj)
913 {
914  struct ast_sip_endpoint *endpoint = obj;
915  char *name = ast_strdupa(var->name);
916  char *front = NULL;
917  char *back = NULL;
918  char *buf = name;
919 
920  /* strip out underscores in the name */
921  front = strtok_r(buf, "_", &back);
922  while (front) {
923  int size = strlen(front);
924  ast_copy_string(buf, front, size + 1);
925  buf += size;
926  front = strtok_r(NULL, "_", &back);
927  }
928 
929  return ast_rtp_dtls_cfg_parse(&endpoint->media.rtp.dtls_cfg, name, var->value);
930 }
931 
932 static int dtlsverify_to_str(const void *obj, const intptr_t *args, char **buf)
933 {
934  const struct ast_sip_endpoint *endpoint = obj;
935  *buf = ast_strdup(AST_YESNO(endpoint->media.rtp.dtls_cfg.verify));
936  return 0;
937 }
938 
939 static int dtlsrekey_to_str(const void *obj, const intptr_t *args, char **buf)
940 {
941  const struct ast_sip_endpoint *endpoint = obj;
942 
943  return ast_asprintf(
944  buf, "%u", endpoint->media.rtp.dtls_cfg.rekey) >=0 ? 0 : -1;
945 }
946 
947 static int dtlsautogeneratecert_to_str(const void *obj, const intptr_t *args, char **buf)
948 {
949  const struct ast_sip_endpoint *endpoint = obj;
951  return 0;
952 }
953 
954 static int dtlscertfile_to_str(const void *obj, const intptr_t *args, char **buf)
955 {
956  const struct ast_sip_endpoint *endpoint = obj;
957  *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.certfile);
958  return 0;
959 }
960 
961 static int dtlsprivatekey_to_str(const void *obj, const intptr_t *args, char **buf)
962 {
963  const struct ast_sip_endpoint *endpoint = obj;
964  *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.pvtfile);
965  return 0;
966 }
967 
968 static int dtlscipher_to_str(const void *obj, const intptr_t *args, char **buf)
969 {
970  const struct ast_sip_endpoint *endpoint = obj;
971  *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cipher);
972  return 0;
973 }
974 
975 static int dtlscafile_to_str(const void *obj, const intptr_t *args, char **buf)
976 {
977  const struct ast_sip_endpoint *endpoint = obj;
978  *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.cafile);
979  return 0;
980 }
981 
982 static int dtlscapath_to_str(const void *obj, const intptr_t *args, char **buf)
983 {
984  const struct ast_sip_endpoint *endpoint = obj;
985  *buf = ast_strdup(endpoint->media.rtp.dtls_cfg.capath);
986  return 0;
987 }
988 
989 static const char *ast_rtp_dtls_setup_map[] = {
990  [AST_RTP_DTLS_SETUP_ACTIVE] = "active",
991  [AST_RTP_DTLS_SETUP_PASSIVE] = "passive",
992  [AST_RTP_DTLS_SETUP_ACTPASS] = "actpass",
993  [AST_RTP_DTLS_SETUP_HOLDCONN] = "holdconn",
994 };
995 
996 static int dtlssetup_to_str(const void *obj, const intptr_t *args, char **buf)
997 {
998  const struct ast_sip_endpoint *endpoint = obj;
999  if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.default_setup, ast_rtp_dtls_setup_map)) {
1000  *buf = ast_strdup(ast_rtp_dtls_setup_map[endpoint->media.rtp.dtls_cfg.default_setup]);
1001  }
1002  return 0;
1003 }
1004 
1005 static const char *ast_rtp_dtls_fingerprint_map[] = {
1006  [AST_RTP_DTLS_HASH_SHA256] = "SHA-256",
1007  [AST_RTP_DTLS_HASH_SHA1] = "SHA-1",
1008 };
1009 
1010 static int dtlsfingerprint_to_str(const void *obj, const intptr_t *args, char **buf)
1011 {
1012  const struct ast_sip_endpoint *endpoint = obj;
1013  if (ARRAY_IN_BOUNDS(endpoint->media.rtp.dtls_cfg.hash, ast_rtp_dtls_fingerprint_map)) {
1014  *buf = ast_strdup(ast_rtp_dtls_fingerprint_map[endpoint->media.rtp.dtls_cfg.hash]);
1015  }
1016  return 0;
1017 }
1018 
1019 static int t38udptl_ec_handler(const struct aco_option *opt,
1020  struct ast_variable *var, void *obj)
1021 {
1022  struct ast_sip_endpoint *endpoint = obj;
1023 
1024  if (!strcmp(var->value, "none")) {
1025  endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_NONE;
1026  } else if (!strcmp(var->value, "fec")) {
1027  endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_FEC;
1028  } else if (!strcmp(var->value, "redundancy")) {
1029  endpoint->media.t38.error_correction = UDPTL_ERROR_CORRECTION_REDUNDANCY;
1030  } else {
1031  return -1;
1032  }
1033 
1034  return 0;
1035 }
1036 
1037 static const char *ast_t38_ec_modes_map[] = {
1038  [UDPTL_ERROR_CORRECTION_NONE] = "none",
1039  [UDPTL_ERROR_CORRECTION_FEC] = "fec",
1040  [UDPTL_ERROR_CORRECTION_REDUNDANCY] = "redundancy"
1041 };
1042 
1043 static int t38udptl_ec_to_str(const void *obj, const intptr_t *args, char **buf)
1044 {
1045  const struct ast_sip_endpoint *endpoint = obj;
1046  if (ARRAY_IN_BOUNDS(endpoint->media.t38.error_correction, ast_t38_ec_modes_map)) {
1047  *buf = ast_strdup(ast_t38_ec_modes_map[
1048  endpoint->media.t38.error_correction]);
1049  }
1050  return 0;
1051 }
1052 
1053 static int tos_handler(const struct aco_option *opt,
1054  struct ast_variable *var, void *obj)
1055 {
1056  struct ast_sip_endpoint *endpoint = obj;
1057  unsigned int value;
1058 
1059  if (ast_str2tos(var->value, &value)) {
1060  ast_log(LOG_ERROR, "Error configuring endpoint '%s' - Could not "
1061  "interpret '%s' value '%s'\n",
1062  ast_sorcery_object_get_id(endpoint), var->name, var->value);
1063  return -1;
1064  }
1065 
1066  if (!strcmp(var->name, "tos_audio")) {
1067  endpoint->media.tos_audio = value;
1068  } else if (!strcmp(var->name, "tos_video")) {
1069  endpoint->media.tos_video = value;
1070  } else {
1071  /* If we reach this point, someone called the tos_handler when they shouldn't have. */
1072  ast_assert(0);
1073  return -1;
1074  }
1075  return 0;
1076 }
1077 
1078 static int tos_audio_to_str(const void *obj, const intptr_t *args, char **buf)
1079 {
1080  const struct ast_sip_endpoint *endpoint = obj;
1081 
1082  if (ast_asprintf(buf, "%u", endpoint->media.tos_audio) == -1) {
1083  return -1;
1084  }
1085  return 0;
1086 }
1087 
1088 static int tos_video_to_str(const void *obj, const intptr_t *args, char **buf)
1089 {
1090  const struct ast_sip_endpoint *endpoint = obj;
1091 
1092  if (ast_asprintf(buf, "%u", endpoint->media.tos_video) == -1) {
1093  return -1;
1094  }
1095  return 0;
1096 }
1097 
1098 static int from_user_handler(const struct aco_option *opt,
1099  struct ast_variable *var, void *obj)
1100 {
1101  struct ast_sip_endpoint *endpoint = obj;
1102  /* Valid non-alphanumeric characters for URI */
1103  char *valid_uri_marks = "-._~%!$&'()*+,;=:";
1104  const char *val;
1105 
1106  for (val = var->value; *val; val++) {
1107  if (!isalpha(*val) && !isdigit(*val) && !strchr(valid_uri_marks, *val)) {
1108  ast_log(LOG_ERROR, "Error configuring endpoint '%s' - '%s' field "
1109  "contains invalid character '%c'\n",
1110  ast_sorcery_object_get_id(endpoint), var->name, *val);
1111  return -1;
1112  }
1113  }
1114 
1115  ast_string_field_set(endpoint, fromuser, var->value);
1116 
1117  return 0;
1118 }
1119 
1120 static int from_user_to_str(const void *obj, const intptr_t *args, char **buf)
1121 {
1122  const struct ast_sip_endpoint *endpoint = obj;
1123 
1124  *buf = ast_strdup(endpoint->fromuser);
1125 
1126  return 0;
1127 }
1128 
1129 static int set_var_handler(const struct aco_option *opt,
1130  struct ast_variable *var, void *obj)
1131 {
1132  struct ast_sip_endpoint *endpoint = obj;
1133  struct ast_variable *new_var;
1134  char *name;
1135  char *val;
1136 
1137  if (ast_strlen_zero(var->value)) {
1138  return 0;
1139  }
1140 
1141  name = ast_strdupa(var->value);
1142  val = strchr(name, '=');
1143 
1144  if (!val) {
1145  return -1;
1146  }
1147 
1148  *val++ = '\0';
1149 
1150  if (!(new_var = ast_variable_new(name, val, ""))) {
1151  return -1;
1152  }
1153 
1154  if (ast_variable_list_replace(&endpoint->channel_vars, new_var)) {
1155  ast_variable_list_append(&endpoint->channel_vars, new_var);
1156  }
1157 
1158  return 0;
1159 }
1160 
1161 static int set_var_to_str(const void *obj, const intptr_t *args, char **buf)
1162 {
1163  struct ast_str *str = ast_str_create(MAX_OBJECT_FIELD);
1164  const struct ast_sip_endpoint *endpoint = obj;
1165  struct ast_variable *var;
1166 
1167  for (var = endpoint->channel_vars; var; var = var->next) {
1168  ast_str_append(&str, 0, "%s=%s,", var->name, var->value);
1169  }
1170 
1171  *buf = ast_strdup(ast_str_truncate(str, -1));
1172  ast_free(str);
1173  return 0;
1174 }
1175 
1176 static int set_var_to_vl(const void *obj, struct ast_variable **fields)
1177 {
1178  const struct ast_sip_endpoint *endpoint = obj;
1179  if (endpoint->channel_vars) {
1180  *fields = ast_variables_dup(endpoint->channel_vars);
1181  }
1182  return 0;
1183 }
1184 
1185 static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1186 {
1187  struct ast_sip_endpoint *endpoint = obj;
1188 
1189  ast_free(endpoint->subscription.mwi.voicemail_extension);
1191 
1192  return endpoint->subscription.mwi.voicemail_extension ? 0 : -1;
1193 }
1194 
1195 static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf)
1196 {
1197  const struct ast_sip_endpoint *endpoint = obj;
1198 
1199  *buf = ast_strdup(endpoint->subscription.mwi.voicemail_extension);
1200 
1201  return 0;
1202 }
1203 
1204 static int contact_user_handler(const struct aco_option *opt,
1205  struct ast_variable *var, void *obj)
1206 {
1207  struct ast_sip_endpoint *endpoint = obj;
1208 
1209  ast_free(endpoint->contact_user);
1210  endpoint->contact_user = ast_strdup(var->value);
1211 
1212  return endpoint->contact_user ? 0 : -1;
1213 }
1214 
1215 static int contact_user_to_str(const void *obj, const intptr_t *args, char **buf)
1216 {
1217  const struct ast_sip_endpoint *endpoint = obj;
1218 
1219  *buf = ast_strdup(endpoint->contact_user);
1220  if (!(*buf)) {
1221  return -1;
1222  }
1223 
1224  return 0;
1225 }
1226 
1227 static int call_offer_pref_handler(const struct aco_option *opt,
1228  struct ast_variable *var, void *obj)
1229 {
1230  struct ast_sip_endpoint *endpoint = obj;
1231  struct ast_flags pref = { 0, };
1232  int outgoing = strcmp(var->name, "outgoing_call_offer_pref") == 0;
1233 
1234  int res = ast_sip_call_codec_str_to_pref(&pref, var->value, outgoing);
1235  if (res != 0) {
1236  return -1;
1237  }
1238 
1239  if (outgoing) {
1240  endpoint->media.outgoing_call_offer_pref = pref;
1241  } else {
1242  endpoint->media.incoming_call_offer_pref = pref;
1243  }
1244 
1245  return 0;
1246 }
1247 
1248 static int incoming_call_offer_pref_to_str(const void *obj, const intptr_t *args, char **buf)
1249 {
1250  const struct ast_sip_endpoint *endpoint = obj;
1251 
1252  *buf = ast_strdup(ast_sip_call_codec_pref_to_str(endpoint->media.incoming_call_offer_pref));
1253  if (!(*buf)) {
1254  return -1;
1255  }
1256 
1257  return 0;
1258 }
1259 
1260 static int outgoing_call_offer_pref_to_str(const void *obj, const intptr_t *args, char **buf)
1261 {
1262  const struct ast_sip_endpoint *endpoint = obj;
1263 
1264  *buf = ast_strdup(ast_sip_call_codec_pref_to_str(endpoint->media.outgoing_call_offer_pref));
1265  if (!(*buf)) {
1266  return -1;
1267  }
1268 
1269  return 0;
1270 }
1271 
1272 static int codec_prefs_handler(const struct aco_option *opt,
1273  struct ast_variable *var, void *obj)
1274 {
1275  struct ast_sip_endpoint *endpoint = obj;
1276  struct ast_stream_codec_negotiation_prefs *option_prefs;
1278  struct ast_str *error_message = ast_str_create(128);
1281  int res = 0;
1282 
1283  res = ast_stream_codec_prefs_parse(var->value, &prefs, &error_message);
1284  if (res < 0) {
1285  ast_log(LOG_ERROR, "Endpoint '%s': %s for option '%s'\n",
1286  ast_sorcery_object_get_id(endpoint), ast_str_buffer(error_message), var->name);
1287  ast_free(error_message);
1288  return -1;
1289  }
1290  ast_free(error_message);
1291 
1292  if (strcmp(var->name, "codec_prefs_incoming_offer") == 0) {
1293  if (prefs.operation == CODEC_NEGOTIATION_OPERATION_UNION) {
1294  ast_log(LOG_ERROR, "Endpoint '%s': Codec preference '%s' has invalid value '%s' for option: '%s'",
1295  ast_sorcery_object_get_id(endpoint),
1298  var->name);
1299  return -1;
1300  }
1301  option_prefs = &endpoint->media.codec_prefs_incoming_offer;
1302  default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
1303  default_operation = CODEC_NEGOTIATION_OPERATION_INTERSECT;
1304  } else if (strcmp(var->name, "codec_prefs_outgoing_offer") == 0) {
1305  option_prefs = &endpoint->media.codec_prefs_outgoing_offer;
1306  default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
1307  default_operation = CODEC_NEGOTIATION_OPERATION_UNION;
1308  } else if (strcmp(var->name, "codec_prefs_incoming_answer") == 0) {
1309  option_prefs = &endpoint->media.codec_prefs_incoming_answer;
1310  default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
1311  default_operation = CODEC_NEGOTIATION_OPERATION_INTERSECT;
1312  } else if (strcmp(var->name, "codec_prefs_outgoing_answer") == 0) {
1313  option_prefs = &endpoint->media.codec_prefs_outgoing_answer;
1314  default_prefer = CODEC_NEGOTIATION_PREFER_PENDING;
1315  default_operation = CODEC_NEGOTIATION_OPERATION_INTERSECT;
1316  } else {
1317  ast_log(LOG_ERROR, "Endpoint '%s': Unsupported option '%s'\n",
1318  ast_sorcery_object_get_id(endpoint),
1319  var->name);
1320  return -1;
1321  }
1322 
1323  if (prefs.prefer == CODEC_NEGOTIATION_PREFER_UNSPECIFIED) {
1324  prefs.prefer = default_prefer;
1325  }
1326 
1327  if (prefs.operation == CODEC_NEGOTIATION_OPERATION_UNSPECIFIED) {
1328  prefs.operation = default_operation;
1329  }
1330 
1331  if (prefs.keep == CODEC_NEGOTIATION_KEEP_UNSPECIFIED) {
1332  prefs.keep = CODEC_NEGOTIATION_KEEP_ALL;
1333  }
1334 
1335  if (prefs.transcode == CODEC_NEGOTIATION_TRANSCODE_UNSPECIFIED) {
1336  prefs.transcode = CODEC_NEGOTIATION_TRANSCODE_ALLOW;
1337  }
1338 
1339  /* Now that defaults have been applied as needed we apply the full codec
1340  * preference configuration to the option.
1341  */
1342  *option_prefs = prefs;
1343 
1344  return 0;
1345 }
1346 
1347 static int codec_prefs_to_str(const struct ast_stream_codec_negotiation_prefs *prefs,
1348  const void *obj, const intptr_t *args, char **buf)
1349 {
1351 
1352  if (!codecs) {
1353  return -1;
1354  }
1355 
1356  *buf = ast_strdup(ast_stream_codec_prefs_to_str(prefs, &codecs));
1357  ast_free(codecs);
1358 
1359  return 0;
1360 }
1361 
1362 static int incoming_offer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
1363 {
1364  const struct ast_sip_endpoint *endpoint = obj;
1365  return codec_prefs_to_str(&endpoint->media.codec_prefs_incoming_offer, obj, args, buf);
1366 }
1367 
1368 static int outgoing_offer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
1369 {
1370  const struct ast_sip_endpoint *endpoint = obj;
1371  return codec_prefs_to_str(&endpoint->media.codec_prefs_outgoing_offer, obj, args, buf);
1372 }
1373 
1374 static int incoming_answer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
1375 {
1376  const struct ast_sip_endpoint *endpoint = obj;
1377  return codec_prefs_to_str(&endpoint->media.codec_prefs_incoming_answer, obj, args, buf);
1378 }
1379 
1380 static int outgoing_answer_codec_prefs_to_str(const void *obj, const intptr_t *args, char **buf)
1381 {
1382  const struct ast_sip_endpoint *endpoint = obj;
1383  return codec_prefs_to_str(&endpoint->media.codec_prefs_outgoing_answer, obj, args, buf);
1384 }
1385 
1386 static void *sip_nat_hook_alloc(const char *name)
1387 {
1388  return ast_sorcery_generic_alloc(sizeof(struct ast_sip_nat_hook), NULL);
1389 }
1390 
1391 /*! \brief Destructor function for persistent endpoint information */
1392 static void persistent_endpoint_destroy(void *obj)
1393 {
1394  struct sip_persistent_endpoint *persistent = obj;
1395 
1396  ast_endpoint_shutdown(persistent->endpoint);
1397 }
1398 
1399 static int add_to_regcontext(void *obj, void *arg, int flags)
1400 {
1401  struct sip_persistent_endpoint *persistent = obj;
1402  const char *regcontext = arg;
1403 
1404  if (ast_endpoint_get_state(persistent->endpoint) == AST_ENDPOINT_ONLINE) {
1405  if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(
1406  persistent->endpoint), 1, NULL)) {
1407  ast_add_extension(regcontext, 1, ast_endpoint_get_resource(persistent->endpoint), 1, NULL, NULL,
1408  "Noop", ast_strdup(ast_endpoint_get_resource(persistent->endpoint)), ast_free_ptr, "PJSIP");
1409  }
1410  }
1411 
1412  return 0;
1413 }
1414 
1415 int ast_sip_persistent_endpoint_add_to_regcontext(const char *regcontext)
1416 {
1417  if (ast_strlen_zero(regcontext)) {
1418  return 0;
1419  }
1420 
1421  /* Make sure the regcontext exists */
1422  if (!ast_context_find_or_create(NULL, NULL, regcontext, "PJSIP")) {
1423  ast_log(LOG_ERROR, "Failed to create regcontext '%s'\n", regcontext);
1424  return -1;
1425  }
1426 
1427  /* Add any online endpoints */
1428  ao2_callback(persistent_endpoints, OBJ_NODATA, add_to_regcontext, (void *)regcontext);
1429  return 0;
1430 }
1431 
1432 int ast_sip_persistent_endpoint_update_state(const char *endpoint_name, enum ast_endpoint_state state)
1433 {
1434  struct sip_persistent_endpoint *persistent;
1435  struct ast_json *blob;
1436  char *regcontext;
1437 
1438  persistent = ao2_find(persistent_endpoints, endpoint_name, OBJ_SEARCH_KEY);
1439  if (!persistent) {
1440  return -1;
1441  }
1442 
1443  /* If there was no state change, don't publish anything. */
1444  if (ast_endpoint_get_state(persistent->endpoint) == state) {
1445  ao2_ref(persistent, -1);
1446  return 0;
1447  }
1448 
1449  regcontext = ast_sip_get_regcontext();
1450 
1451  if (state == AST_ENDPOINT_ONLINE) {
1453  blob = ast_json_pack("{s: s}", "peer_status", "Reachable");
1454 
1455  if (!ast_strlen_zero(regcontext)) {
1456  if (!ast_exists_extension(NULL, regcontext, ast_endpoint_get_resource(persistent->endpoint), 1, NULL)) {
1457  ast_add_extension(regcontext, 1, ast_endpoint_get_resource(persistent->endpoint), 1, NULL, NULL,
1458  "Noop", ast_strdup(ast_endpoint_get_resource(persistent->endpoint)), ast_free_ptr, "PJSIP");
1459  }
1460  }
1461 
1462  ast_verb(2, "Endpoint %s is now Reachable\n", ast_endpoint_get_resource(persistent->endpoint));
1463  } else {
1465  blob = ast_json_pack("{s: s}", "peer_status", "Unreachable");
1466 
1467  if (!ast_strlen_zero(regcontext)) {
1468  struct pbx_find_info q = { .stacklen = 0 };
1469 
1470  if (pbx_find_extension(NULL, NULL, &q, regcontext, ast_endpoint_get_resource(persistent->endpoint), 1, NULL, "", E_MATCH)) {
1471  ast_context_remove_extension(regcontext, ast_endpoint_get_resource(persistent->endpoint), 1, NULL);
1472  }
1473  }
1474 
1475  ast_verb(2, "Endpoint %s is now Unreachable\n", ast_endpoint_get_resource(persistent->endpoint));
1476  }
1477 
1478  ast_free(regcontext);
1479 
1481  ast_json_unref(blob);
1483 
1484  ao2_ref(persistent, -1);
1485 
1486  return 0;
1487 }
1488 
1489 void ast_sip_persistent_endpoint_publish_contact_state(const char *endpoint_name, const struct ast_sip_contact_status *contact_status)
1490 {
1491  struct sip_persistent_endpoint *persistent;
1492  struct ast_json *blob;
1493  char rtt[32];
1494 
1495  persistent = ao2_find(persistent_endpoints, endpoint_name, OBJ_SEARCH_KEY);
1496  if (!persistent) {
1497  return;
1498  }
1499 
1500  snprintf(rtt, sizeof(rtt), "%" PRId64, contact_status->rtt);
1501  blob = ast_json_pack("{s: s, s: s, s: s, s: s, s: s}",
1502  "contact_status", ast_sip_get_contact_status_label(contact_status->status),
1503  "aor", contact_status->aor,
1504  "uri", contact_status->uri,
1505  "roundtrip_usec", rtt,
1506  "endpoint_name", ast_endpoint_get_resource(persistent->endpoint));
1507  if (blob) {
1509  ast_json_unref(blob);
1510  }
1511 
1512  ao2_ref(persistent, -1);
1513 }
1514 
1515 /*! \brief Internal function which finds (or creates) persistent endpoint information */
1516 static struct ast_endpoint *persistent_endpoint_find_or_create(const struct ast_sip_endpoint *endpoint)
1517 {
1518  RAII_VAR(struct sip_persistent_endpoint *, persistent, NULL, ao2_cleanup);
1519  SCOPED_AO2LOCK(lock, persistent_endpoints);
1520 
1521  persistent = ao2_find(persistent_endpoints, ast_sorcery_object_get_id(endpoint),
1523  if (!persistent) {
1524  persistent = ao2_alloc_options(sizeof(*persistent), persistent_endpoint_destroy,
1526  if (!persistent) {
1527  return NULL;
1528  }
1529 
1530  persistent->endpoint = ast_endpoint_create("PJSIP",
1531  ast_sorcery_object_get_id(endpoint));
1532  if (!persistent->endpoint) {
1533  return NULL;
1534  }
1535 
1537 
1538  ao2_link_flags(persistent_endpoints, persistent, OBJ_NOLOCK);
1539  }
1540 
1541  ao2_ref(persistent->endpoint, +1);
1542  return persistent->endpoint;
1543 }
1544 
1545 /*! \brief Callback function for when an object is finalized */
1546 static int sip_endpoint_apply_handler(const struct ast_sorcery *sorcery, void *obj)
1547 {
1548  struct ast_sip_endpoint *endpoint = obj;
1549 
1550  if (!(endpoint->persistent = persistent_endpoint_find_or_create(endpoint))) {
1551  return -1;
1552  }
1553 
1554  if (endpoint->extensions.timer.min_se < 90) {
1555  ast_log(LOG_ERROR, "Session timer minimum expires time must be 90 or greater on endpoint '%s'\n",
1556  ast_sorcery_object_get_id(endpoint));
1557  return -1;
1558  } else if (endpoint->extensions.timer.sess_expires < endpoint->extensions.timer.min_se) {
1559  ast_log(LOG_ERROR, "Session timer expires must be greater than minimum session expires time on endpoint '%s'\n",
1560  ast_sorcery_object_get_id(endpoint));
1561  return -1;
1562  }
1563 
1564  if (ast_rtp_dtls_cfg_validate(&endpoint->media.rtp.dtls_cfg)) {
1565  return -1;
1566  }
1567 
1568  if (endpoint->preferred_codec_only) {
1569  if (endpoint->media.incoming_call_offer_pref.flags != (AST_SIP_CALL_CODEC_PREF_LOCAL | AST_SIP_CALL_CODEC_PREF_INTERSECT | AST_SIP_CALL_CODEC_PREF_ALL)) {
1570  ast_log(LOG_ERROR, "Setting both preferred_codec_only and incoming_call_offer_pref is not supported on endpoint '%s'\n",
1571  ast_sorcery_object_get_id(endpoint));
1572  return -1;
1573  }
1574  ast_clear_flag(&endpoint->media.incoming_call_offer_pref, AST_SIP_CALL_CODEC_PREF_ALL);
1575  ast_set_flag(&endpoint->media.incoming_call_offer_pref, AST_SIP_CALL_CODEC_PREF_FIRST);
1576  }
1577 
1579  if (!endpoint->media.topology) {
1580  return -1;
1581  }
1582 
1583  endpoint->media.rtcp_mux |= endpoint->media.bundle;
1584 
1585  /*
1586  * If webrtc has been enabled then enable those attributes, and default
1587  * some, that are needed in order for webrtc to work.
1588  */
1589  endpoint->media.bundle |= endpoint->media.webrtc;
1590  endpoint->media.rtcp_mux |= endpoint->media.webrtc;
1591  endpoint->media.rtp.use_avpf |= endpoint->media.webrtc;
1592  endpoint->media.rtp.ice_support |= endpoint->media.webrtc;
1593  endpoint->media.rtp.use_received_transport |= endpoint->media.webrtc;
1594 
1595  if (endpoint->media.webrtc) {
1596  endpoint->media.rtp.encryption = AST_SIP_MEDIA_ENCRYPT_DTLS;
1597  endpoint->media.rtp.dtls_cfg.enabled = 1;
1600 
1601  /* RFC8827 says: Implementations MUST NOT implement DTLS renegotiation
1602  * and MUST reject it with a "no_renegotiation" alert if offered. */
1603  if (endpoint->media.rtp.dtls_cfg.rekey) {
1604  ast_log(LOG_WARNING, "DTLS renegotiation is not supported with WebRTC. Disabling dtls_rekey.\n");
1605  endpoint->media.rtp.dtls_cfg.rekey = 0;
1606  }
1607 
1608  if (ast_strlen_zero(endpoint->media.rtp.dtls_cfg.certfile)) {
1609  /* If no certificate has been specified, try to automatically create one */
1610  endpoint->media.rtp.dtls_cfg.ephemeral_cert = 1;
1611  }
1612  }
1613 
1614  if (!ast_strlen_zero(endpoint->geoloc_incoming_call_profile) ||
1615  !ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {
1616 
1617  if (!ast_geoloc_is_loaded()) {
1618  ast_log(LOG_ERROR, "A geoloc incoming and/or outgoing call_profile was specified on endpoint '%s'"
1619  " but res_geolocation is not loaded.\n", ast_sorcery_object_get_id(endpoint));
1620  return -1;
1621  }
1622 
1623  if (!ast_strlen_zero(endpoint->geoloc_incoming_call_profile)) {
1624  struct ast_geoloc_profile *profile = ast_geoloc_get_profile(endpoint->geoloc_incoming_call_profile);
1625  if (!profile) {
1626  ast_log(LOG_ERROR, "geoloc_incoming_call_profile '%s' on endpoint '%s' doesn't exist\n",
1627  endpoint->geoloc_incoming_call_profile, ast_sorcery_object_get_id(endpoint));
1628  return -1;
1629  }
1630  ao2_cleanup(profile);
1631  }
1632 
1633  if (!ast_strlen_zero(endpoint->geoloc_outgoing_call_profile)) {
1634  struct ast_geoloc_profile *profile = ast_geoloc_get_profile(endpoint->geoloc_outgoing_call_profile);
1635  if (!profile) {
1636  ast_log(LOG_ERROR, "geoloc_outgoing_call_profile '%s' on endpoint '%s' doesn't exist\n",
1637  endpoint->geoloc_outgoing_call_profile, ast_sorcery_object_get_id(endpoint));
1638  return -1;
1639  }
1640  ao2_cleanup(profile);
1641  }
1642  }
1643 
1644  return 0;
1645 }
1646 
1647 const char *ast_sip_get_device_state(const struct ast_sip_endpoint *endpoint)
1648 {
1649  char device[MAX_OBJECT_FIELD];
1650 
1651  snprintf(device, MAX_OBJECT_FIELD, "PJSIP/%s", ast_sorcery_object_get_id(endpoint));
1652  return ast_devstate2str(ast_device_state(device));
1653 }
1654 
1655 struct ast_endpoint_snapshot *ast_sip_get_endpoint_snapshot(
1656  const struct ast_sip_endpoint *endpoint)
1657 {
1659  ast_endpoint_get_tech(endpoint->persistent),
1661 }
1662 
1663 int ast_sip_for_each_channel_snapshot(
1664  const struct ast_endpoint_snapshot *endpoint_snapshot,
1665  ao2_callback_fn on_channel_snapshot, void *arg)
1666 {
1667  int num, num_channels = endpoint_snapshot->num_channels;
1668 
1669  if (!on_channel_snapshot || !num_channels) {
1670  return 0;
1671  }
1672 
1673  for (num = 0; num < num_channels; ++num) {
1674  RAII_VAR(struct ast_channel_snapshot *, snapshot, NULL, ao2_cleanup);
1675  int res;
1676 
1677  snapshot = ast_channel_snapshot_get_latest(endpoint_snapshot->channel_ids[num]);
1678  if (!snapshot) {
1679  continue;
1680  }
1681 
1682  res = on_channel_snapshot(snapshot, arg, 0);
1683  if (res) {
1684  return -1;
1685  }
1686  }
1687  return 0;
1688 }
1689 
1690 int ast_sip_for_each_channel(
1691  const struct ast_sip_endpoint *endpoint,
1692  ao2_callback_fn on_channel_snapshot, void *arg)
1693 {
1694  RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1695  return ast_sip_for_each_channel_snapshot(endpoint_snapshot, on_channel_snapshot, arg);
1696 }
1697 
1698 static int active_channels_to_str_cb(void *object, void *arg, int flags)
1699 {
1700  const struct ast_channel_snapshot *snapshot = object;
1701  struct ast_str **buf = arg;
1702  ast_str_append(buf, 0, "%s,", snapshot->base->name);
1703  return 0;
1704 }
1705 
1706 static void active_channels_to_str(const struct ast_sip_endpoint *endpoint,
1707  struct ast_str **str)
1708 {
1709 
1710  RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot,
1711  ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
1712 
1713  if (endpoint_snapshot) {
1714  return;
1715  }
1716 
1717  ast_sip_for_each_channel_snapshot(endpoint_snapshot,
1718  active_channels_to_str_cb, str);
1719  ast_str_truncate(*str, -1);
1720 }
1721 
1722 #define AMI_DEFAULT_STR_SIZE 512
1723 
1724 struct ast_str *ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
1725 {
1726  struct ast_str *buf = ast_str_create(AMI_DEFAULT_STR_SIZE);
1727 
1728  if (!(buf)) {
1729  astman_send_error_va(ami->s, ami->m, "Unable create event "
1730  "for %s\n", event);
1731  return NULL;
1732  }
1733 
1734  ast_str_set(&buf, 0, "Event: %s\r\n", event);
1735  if (!ast_strlen_zero(ami->action_id)) {
1736  ast_str_append(&buf, 0, "ActionID: %s\r\n", ami->action_id);
1737  }
1738  return buf;
1739 }
1740 
1741 static void sip_sorcery_object_ami_set_type_name(const void *obj, struct ast_str **buf)
1742 {
1743  ast_str_append(buf, 0, "ObjectType: %s\r\n",
1745  ast_str_append(buf, 0, "ObjectName: %s\r\n",
1747 }
1748 
1749 int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
1750 {
1752  ast_sip_get_sorcery(), obj, AST_HANDLER_ONLY_STRING), ast_variables_destroy);
1753  struct ast_variable *i;
1754 
1755  if (!objset) {
1756  return -1;
1757  }
1758 
1759  sip_sorcery_object_ami_set_type_name(obj, buf);
1760 
1761  for (i = objset; i; i = i->next) {
1762  RAII_VAR(char *, camel, ast_to_camel_case(i->name), ast_free);
1763  ast_str_append(buf, 0, "%s: %s\r\n", camel, i->value);
1764  }
1765 
1766  return 0;
1767 }
1768 
1769 static int sip_endpoints_aors_ami(void *obj, void *arg, int flags)
1770 {
1771  struct ast_sip_aor *aor = obj;
1772  struct ast_str **buf = arg;
1773 
1774  ast_str_append(buf, 0, "Contacts: ");
1775  ast_sip_for_each_contact(aor, ast_sip_contact_to_str, arg);
1776  ast_str_append(buf, 0, "\r\n");
1777 
1778  return 0;
1779 }
1780 
1781 static int sip_endpoint_to_ami(const struct ast_sip_endpoint *endpoint,
1782  struct ast_str **buf)
1783 {
1784  if (ast_sip_sorcery_object_to_ami(endpoint, buf)) {
1785  return -1;
1786  }
1787 
1788  ast_str_append(buf, 0, "DeviceState: %s\r\n",
1789  ast_sip_get_device_state(endpoint));
1790 
1791  ast_str_append(buf, 0, "ActiveChannels: ");
1792  active_channels_to_str(endpoint, buf);
1793  ast_str_append(buf, 0, "\r\n");
1794 
1795  return 0;
1796 }
1797 
1798 static int format_ami_endpoint(const struct ast_sip_endpoint *endpoint,
1799  struct ast_sip_ami *ami)
1800 {
1801  RAII_VAR(struct ast_str *, buf,
1802  ast_sip_create_ami_event("EndpointDetail", ami), ast_free);
1803 
1804  if (!buf) {
1805  return -1;
1806  }
1807 
1808  sip_endpoint_to_ami(endpoint, &buf);
1809  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1810  return 0;
1811 }
1812 
1813 #define AMI_SHOW_ENDPOINTS "PJSIPShowEndpoints"
1814 #define AMI_SHOW_ENDPOINT "PJSIPShowEndpoint"
1815 
1816 static int ami_show_endpoint(struct mansession *s, const struct message *m)
1817 {
1818  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"),
1819  .count = 0, };
1820  RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
1821  const char *endpoint_name = astman_get_header(m, "Endpoint");
1822  int count = 0;
1823 
1824  if (ast_strlen_zero(endpoint_name)) {
1825  astman_send_error_va(s, m, "%s requires an endpoint name\n",
1826  AMI_SHOW_ENDPOINT);
1827  return 0;
1828  }
1829 
1830  if (!strncasecmp(endpoint_name, "pjsip/", 6)) {
1831  endpoint_name += 6;
1832  }
1833 
1834  if (!(endpoint = ast_sorcery_retrieve_by_id(
1835  ast_sip_get_sorcery(), "endpoint", endpoint_name))) {
1836  astman_send_error_va(s, m, "Unable to retrieve endpoint %s\n",
1837  endpoint_name);
1838  return 0;
1839  }
1840 
1841  astman_send_listack(s, m, "Following are Events for each object associated with the Endpoint",
1842  "start");
1843 
1844  /* the endpoint detail needs to always come first so apply as such */
1845  if (format_ami_endpoint(endpoint, &ami) ||
1846  ast_sip_format_endpoint_ami(endpoint, &ami, &count)) {
1847  astman_send_error_va(s, m, "Unable to format endpoint %s\n",
1848  endpoint_name);
1849  }
1850 
1851  astman_send_list_complete_start(s, m, "EndpointDetailComplete", ami.count + 1);
1853 
1854  return 0;
1855 }
1856 
1857 static int format_str_append_auth(const struct ast_sip_auth_vector *auths,
1858  struct ast_str **buf)
1859 {
1860  char *str = NULL;
1861  if (ast_sip_auths_to_str(auths, &str)) {
1862  return -1;
1863  }
1864  ast_str_append(buf, 0, "%s", str ? str : "");
1865  ast_free(str);
1866  return 0;
1867 }
1868 
1869 static int format_ami_endpoints(void *obj, void *arg, int flags)
1870 {
1871 
1872  struct ast_sip_endpoint *endpoint = obj;
1873  struct ast_sip_ami *ami = arg;
1874  RAII_VAR(struct ast_str *, buf,
1875  ast_sip_create_ami_event("EndpointList", ami), ast_free);
1876 
1877  if (!buf) {
1878  return CMP_STOP;
1879  }
1880 
1881  sip_sorcery_object_ami_set_type_name(endpoint, &buf);
1882  ast_str_append(&buf, 0, "Transport: %s\r\n",
1883  endpoint->transport);
1884  ast_str_append(&buf, 0, "Aor: %s\r\n",
1885  endpoint->aors);
1886 
1887  ast_str_append(&buf, 0, "Auths: ");
1888  format_str_append_auth(&endpoint->inbound_auths, &buf);
1889  ast_str_append(&buf, 0, "\r\n");
1890 
1891  ast_str_append(&buf, 0, "OutboundAuths: ");
1892  format_str_append_auth(&endpoint->outbound_auths, &buf);
1893  ast_str_append(&buf, 0, "\r\n");
1894 
1895  ast_sip_for_each_aor(endpoint->aors,
1896  sip_endpoints_aors_ami, &buf);
1897 
1898  ast_str_append(&buf, 0, "DeviceState: %s\r\n",
1899  ast_sip_get_device_state(endpoint));
1900 
1901  ast_str_append(&buf, 0, "ActiveChannels: ");
1902  active_channels_to_str(endpoint, &buf);
1903  ast_str_append(&buf, 0, "\r\n");
1904 
1905  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1906  return 0;
1907 }
1908 
1909 static int ami_show_endpoints(struct mansession *s, const struct message *m)
1910 {
1911  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1912  RAII_VAR(struct ao2_container *, endpoints, NULL, ao2_cleanup);
1913  int num;
1914 
1915  endpoints = ast_sip_get_endpoints();
1916  if (!endpoints) {
1917  astman_send_error(s, m, "Could not get endpoints\n");
1918  return 0;
1919  }
1920 
1921  if (!(num = ao2_container_count(endpoints))) {
1922  astman_send_error(s, m, "No endpoints found\n");
1923  return 0;
1924  }
1925 
1926  astman_send_listack(s, m, "A listing of Endpoints follows, presented as EndpointList events",
1927  "start");
1928 
1929  ao2_callback(endpoints, OBJ_NODATA, format_ami_endpoints, &ami);
1930 
1931  astman_send_list_complete_start(s, m, "EndpointListComplete", num);
1933  return 0;
1934 }
1935 
1936 static struct ao2_container *cli_endpoint_get_container(const char *regex)
1937 {
1938  RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
1939  struct ao2_container *s_container;
1940 
1941  container = ast_sorcery_retrieve_by_regex(sip_sorcery, "endpoint", regex);
1942  if (!container) {
1943  return NULL;
1944  }
1945 
1948  if (!s_container) {
1949  return NULL;
1950  }
1951 
1952  if (ao2_container_dup(s_container, container, 0)) {
1953  ao2_ref(s_container, -1);
1954  return NULL;
1955  }
1956 
1957  return s_container;
1958 }
1959 
1960 static int cli_endpoint_iterate(void *obj, ao2_callback_fn callback, void *args)
1961 {
1962  ao2_callback(obj, OBJ_NODATA, callback, args);
1963 
1964  return 0;
1965 }
1966 
1967 static void *cli_endpoint_retrieve_by_id(const char *id)
1968 {
1969  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "endpoint", id);
1970 }
1971 
1972 static void cli_endpoint_print_child_header(char *type, struct ast_sip_cli_context *context)
1973 {
1974  RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
1975 
1976  formatter_entry = ast_sip_lookup_cli_formatter(type);
1977  if (formatter_entry) {
1978  formatter_entry->print_header(NULL, context, 0);
1979  }
1980 }
1981 
1982 static int cli_endpoint_print_header(void *obj, void *arg, int flags)
1983 {
1984  struct ast_sip_cli_context *context = arg;
1985 
1986  ast_assert(context->output_buffer != NULL);
1987 
1988  ast_str_append(&context->output_buffer, 0,
1989  " Endpoint: <Endpoint/CID.....................................> <State.....> <Channels.>\n");
1990 
1991  if (context->recurse) {
1992  context->indent_level++;
1993  cli_endpoint_print_child_header("auth", context);
1994  cli_endpoint_print_child_header("aor", context);
1995  cli_endpoint_print_child_header("transport", context);
1996  cli_endpoint_print_child_header("identify", context);
1997  cli_endpoint_print_child_header("channel", context);
1998  context->indent_level--;
1999  }
2000 
2001  return 0;
2002 }
2003 
2004 static void cli_endpoint_print_child_body(char *type, const void *obj, struct ast_sip_cli_context *context)
2005 {
2006  RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
2007 
2008  formatter_entry = ast_sip_lookup_cli_formatter(type);
2009  if (formatter_entry) {
2010  formatter_entry->iterate((void *)obj, formatter_entry->print_body, context);
2011  }
2012 }
2013 
2014 static int cli_endpoint_print_body(void *obj, void *arg, int flags)
2015 {
2016  struct ast_sip_endpoint *endpoint = obj;
2017  RAII_VAR(struct ast_endpoint_snapshot *, endpoint_snapshot, ast_sip_get_endpoint_snapshot(endpoint), ao2_cleanup);
2018  struct ast_sip_cli_context *context = arg;
2019  const char *id = ast_sorcery_object_get_id(endpoint);
2020  char *print_name = NULL;
2021  int print_name_len;
2022  char *number = S_COR(endpoint->id.self.number.valid,
2023  endpoint->id.self.number.str, NULL);
2024  int indent;
2025  int flexwidth;
2026 
2027  ast_assert(context->output_buffer != NULL);
2028 
2029  if (number) {
2030  print_name_len = strlen(id) + strlen(number) + 2;
2031  print_name = ast_alloca(print_name_len);
2032  snprintf(print_name, print_name_len, "%s/%s", id, number);
2033  }
2034 
2035  indent = CLI_INDENT_TO_SPACES(context->indent_level);
2036  flexwidth = CLI_LAST_TABSTOP - indent - 2;
2037 
2038  ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %-12.12s %d of %.0f\n",
2039  indent, "Endpoint",
2040  flexwidth, flexwidth, print_name ? print_name : id,
2041  ast_sip_get_device_state(endpoint),
2042  endpoint_snapshot->num_channels,
2043  (double) endpoint->devicestate_busy_at ? endpoint->devicestate_busy_at :
2044  INFINITY
2045  );
2046 
2047  if (context->recurse) {
2048  context->indent_level++;
2049 
2050  context->auth_direction = "Out";
2051  cli_endpoint_print_child_body("auth", &endpoint->outbound_auths, context);
2052  context->auth_direction = "In";
2053  cli_endpoint_print_child_body("auth", &endpoint->inbound_auths, context);
2054 
2055  cli_endpoint_print_child_body("aor", endpoint->aors, context);
2056  cli_endpoint_print_child_body("transport", endpoint, context);
2057  cli_endpoint_print_child_body("identify", endpoint, context);
2058  cli_endpoint_print_child_body("channel", endpoint, context);
2059 
2060  context->indent_level--;
2061 
2062  if (context->indent_level == 0) {
2063  ast_str_append(&context->output_buffer, 0, "\n");
2064  }
2065  }
2066 
2067  if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
2068  ast_str_append(&context->output_buffer, 0, "\n");
2069  ast_sip_cli_print_sorcery_objectset(endpoint, context, 0);
2070  }
2071 
2072  return 0;
2073 }
2074 
2075 static struct ast_cli_entry cli_commands[] = {
2076  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Endpoints",
2077  .command = "pjsip list endpoints",
2078  .usage = "Usage: pjsip list endpoints [ like <pattern> ]\n"
2079  " List the configured PJSIP endpoints\n"
2080  " Optional regular expression pattern is used to filter the list.\n"),
2081  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoints",
2082  .command = "pjsip show endpoints",
2083  .usage = "Usage: pjsip show endpoints [ like <pattern> ]\n"
2084  " List(detailed) the configured PJSIP endpoints\n"
2085  " Optional regular expression pattern is used to filter the list.\n"),
2086  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Endpoint",
2087  .command = "pjsip show endpoint",
2088  .usage = "Usage: pjsip show endpoint <id>\n"
2089  " Show the configured PJSIP endpoint\n"),
2090 };
2091 
2092 struct ast_sip_cli_formatter_entry *channel_formatter;
2093 struct ast_sip_cli_formatter_entry *endpoint_formatter;
2094 
2095 static void load_all_endpoints(void)
2096 {
2097  struct ao2_container *endpoints;
2098 
2099  endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
2100  ao2_cleanup(endpoints);
2101 }
2102 
2103 static void acl_change_stasis_cb(void *data, struct stasis_subscription *sub,
2104  struct stasis_message *message)
2105 {
2106  if (stasis_message_type(message) != ast_named_acl_change_type()) {
2107  return;
2108  }
2109 
2110  ast_sorcery_force_reload_object(sip_sorcery, "endpoint");
2111 }
2112 
2113 int ast_res_pjsip_initialize_configuration(void)
2114 {
2115  if (ast_manager_register_xml(AMI_SHOW_ENDPOINTS, EVENT_FLAG_SYSTEM, ami_show_endpoints) ||
2116  ast_manager_register_xml(AMI_SHOW_ENDPOINT, EVENT_FLAG_SYSTEM, ami_show_endpoint)) {
2117  return -1;
2118  }
2119 
2120  persistent_endpoints = ao2_container_alloc_hash(AO2_ALLOC_OPT_LOCK_MUTEX, 0,
2121  PERSISTENT_BUCKETS, persistent_endpoint_hash, NULL, persistent_endpoint_cmp);
2122  if (!persistent_endpoints) {
2123  return -1;
2124  }
2125 
2126  if (!(sip_sorcery = ast_sorcery_open())) {
2127  ast_log(LOG_ERROR, "Failed to open SIP sorcery failed to open\n");
2128  return -1;
2129  }
2130 
2131  ast_sip_initialize_cli();
2132 
2133  if (ast_sip_initialize_sorcery_auth()) {
2134  ast_log(LOG_ERROR, "Failed to register SIP authentication support\n");
2135  ast_sorcery_unref(sip_sorcery);
2136  sip_sorcery = NULL;
2137  return -1;
2138  }
2139 
2140  ast_sorcery_apply_default(sip_sorcery, "endpoint", "config", "pjsip.conf,criteria=type=endpoint");
2141  ast_sorcery_apply_default(sip_sorcery, "nat_hook", "memory", NULL);
2142 
2143  if (ast_sorcery_object_register(sip_sorcery, "endpoint", ast_sip_endpoint_alloc, NULL, sip_endpoint_apply_handler)) {
2144  ast_log(LOG_ERROR, "Failed to register SIP endpoint object with sorcery\n");
2145  ast_sorcery_unref(sip_sorcery);
2146  sip_sorcery = NULL;
2147  return -1;
2148  }
2149 
2150  if (ast_sorcery_internal_object_register(sip_sorcery, "nat_hook", sip_nat_hook_alloc, NULL, NULL)) {
2151  ast_log(LOG_ERROR, "Failed to register nat_hook\n");
2152  }
2153 
2154  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "type", "", OPT_NOOP_T, 0, 0);
2155  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "context", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, context));
2156  ast_sorcery_object_field_register_alias(sip_sorcery, "endpoint", "disallow", "", OPT_CODEC_T, 0, FLDSET(struct ast_sip_endpoint, media.codecs));
2157  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow", "", OPT_CODEC_T, 1, FLDSET(struct ast_sip_endpoint, media.codecs));
2158  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtmf_mode", "rfc4733", dtmf_handler, dtmf_to_str, NULL, 0, 0);
2159  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ipv6));
2160  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_symmetric", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.symmetric));
2161  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ice_support", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.ice_support));
2162  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_ptime", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_ptime));
2163  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_rport", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.force_rport));
2164  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rewrite_contact", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, nat.rewrite_contact));
2165  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "transport", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, transport));
2166  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, outbound_proxy));
2167  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_suggest", "default", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, mohsuggest));
2168  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "100rel", "yes", prack_handler, prack_to_str, NULL, 0, 0);
2169  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "timers", "yes", timers_handler, timers_to_str, NULL, 0, 0);
2170  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));
2171  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));
2172  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "auth", "", inbound_auth_handler, inbound_auths_to_str, NULL, 0, 0);
2173  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outbound_auth", "", outbound_auth_handler, outbound_auths_to_str, NULL, 0, 0);
2174  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aors", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, aors));
2175  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_address", "", media_address_handler, media_address_to_str, NULL, 0, 0);
2176  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));
2177  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "identify_by", "username,ip", ident_handler, ident_to_str, NULL, 0, 0);
2178  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "direct_media", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.direct_media.enabled));
2179  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);
2180  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_connected_line", "yes", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_connected_line));
2181  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_connected_line", "yes", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, id.send_connected_line));
2182  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);
2183  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);
2184  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));
2185  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid", "", caller_id_handler, caller_id_to_str, NULL, 0, 0);
2186  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);
2187  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "callerid_tag", "", caller_id_tag_handler, caller_id_tag_to_str, NULL, 0, 0);
2188  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_inbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_inbound));
2189  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "trust_id_outbound", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.trust_outbound));
2190  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_pai", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_pai));
2191  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_rpid", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_rpid));
2192  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rpid_immediate", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.rpid_immediate));
2193  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_diversion", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_diversion));
2194  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_history_info", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, id.send_history_info));
2195  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.mailboxes));
2196  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0);
2197  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "aggregate_mwi", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.aggregate));
2198  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_subscribe_replaces_unsolicited", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, subscription.mwi.subscribe_replaces_unsolicited));
2199  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "media_encryption", "no", media_encryption_handler, media_encryption_to_str, NULL, 0, 0);
2200  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "use_avpf", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.use_avpf));
2201  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "force_avp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.force_avp));
2202  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));
2203  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_keepalive", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.keepalive));
2204  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.rtp.timeout));
2205  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));
2206  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "one_touch_recording", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, info.recording.enabled));
2207  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "inband_progress", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, inband_progress));
2208  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "call_group", "", group_handler, callgroup_to_str, NULL, 0, 0);
2209  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "pickup_group", "", group_handler, pickupgroup_to_str, NULL, 0, 0);
2210  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_call_group", "", named_groups_handler, named_callgroups_to_str, NULL, 0, 0);
2211  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "named_pickup_group", "", named_groups_handler, named_pickupgroups_to_str, NULL, 0, 0);
2212  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));
2213  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.enabled));
2214  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "t38_udptl_ec", "none", t38udptl_ec_handler, t38udptl_ec_to_str, NULL, 0, 0);
2215  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_maxdatagram", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.t38.maxdatagram));
2216  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, faxdetect));
2217  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "fax_detect_timeout", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, faxdetect_timeout));
2218  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_nat", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.nat));
2219  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_udptl_ipv6", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.ipv6));
2220  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "t38_bind_udptl_to_media_address", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.t38.bind_udptl_to_media_address));
2221  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "tone_zone", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, zone));
2222  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "language", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, language));
2223  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_on_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.onfeature));
2224  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "record_off_feature", "automixmon", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, info.recording.offfeature));
2225  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_transfer", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allowtransfer));
2226  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "user_eq_phone", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, usereqphone));
2227  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "moh_passthrough", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, moh_passthrough));
2228  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_owner", "-", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpowner));
2229  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sdp_session", "Asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.sdpsession));
2230  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_audio", "0", tos_handler, tos_audio_to_str, NULL, 0, 0);
2231  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "tos_video", "0", tos_handler, tos_video_to_str, NULL, 0, 0);
2232  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_audio", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_audio));
2233  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "cos_video", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.cos_video));
2234  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_subscribe", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, subscription.allow));
2235  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "sub_min_expiry", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, subscription.minexpiry));
2236  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "from_user", "", from_user_handler, from_user_to_str, NULL, 0, 0);
2237  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "from_domain", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, fromdomain));
2238  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "mwi_from_user", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, subscription.mwi.fromuser));
2239  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtp_engine", "asterisk", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, media.rtp.engine));
2240  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_verify", "no", dtls_handler, dtlsverify_to_str, NULL, 0, 0);
2241  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_rekey", "0", dtls_handler, dtlsrekey_to_str, NULL, 0, 0);
2242  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_auto_generate_cert", "no", dtls_handler, dtlsautogeneratecert_to_str, NULL, 0, 0);
2243  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cert_file", "", dtls_handler, dtlscertfile_to_str, NULL, 0, 0);
2244  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_private_key", "", dtls_handler, dtlsprivatekey_to_str, NULL, 0, 0);
2245  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_cipher", "", dtls_handler, dtlscipher_to_str, NULL, 0, 0);
2246  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_file", "", dtls_handler, dtlscafile_to_str, NULL, 0, 0);
2247  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_ca_path", "", dtls_handler, dtlscapath_to_str, NULL, 0, 0);
2248  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_setup", "", dtls_handler, dtlssetup_to_str, NULL, 0, 0);
2249  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "dtls_fingerprint", "", dtls_handler, dtlsfingerprint_to_str, NULL, 0, 0);
2250  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));
2251  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));
2252  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));
2253  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "redirect_method", "user", redirect_handler, NULL, NULL, 0, 0);
2254  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "set_var", "", set_var_handler, set_var_to_str, set_var_to_vl, 0, 0);
2255  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "message_context", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, message_context));
2256  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accountcode", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, accountcode));
2257  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "deny", "", endpoint_acl_handler, NULL, NULL, 0, 0);
2258  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "permit", "", endpoint_acl_handler, NULL, NULL, 0, 0);
2259  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "acl", "", endpoint_acl_handler, acl_to_str, NULL, 0, 0);
2260  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_deny", "", endpoint_acl_handler, NULL, NULL, 0, 0);
2261  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_permit", "", endpoint_acl_handler, NULL, NULL, 0, 0);
2262  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_acl", "", endpoint_acl_handler, contact_acl_to_str, NULL, 0, 0);
2263  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "subscribe_context", "", OPT_CHAR_ARRAY_T, 0, CHARFLDSET(struct ast_sip_endpoint, subscription.context));
2264  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "contact_user", "", contact_user_handler, contact_user_to_str, NULL, 0, 0);
2265  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "preferred_codec_only", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, preferred_codec_only));
2266  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "asymmetric_rtp_codec", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, asymmetric_rtp_codec));
2267  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "rtcp_mux", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtcp_mux));
2268  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_overlap", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_overlap));
2269  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "overlap_context", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, overlap_context));
2270  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "refer_blind_progress", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, refer_blind_progress));
2271  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "notify_early_inuse_ringing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, notify_early_inuse_ringing));
2272  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_audio_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_audio_streams));
2273  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "max_video_streams", "1", OPT_UINT_T, 0, FLDSET(struct ast_sip_endpoint, media.max_video_streams));
2274  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "bundle", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.bundle));
2275  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "webrtc", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_endpoint, media.webrtc));
2276  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "incoming_mwi_mailbox", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, incoming_mwi_mailbox));
2277  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "follow_early_media_fork", "yes", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.follow_early_media_fork));
2278  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "accept_multiple_sdp_answers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, media.rtp.accept_multiple_sdp_answers));
2279  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_q850_reason_headers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, suppress_q850_reason_headers));
2280  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));
2281  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "incoming_call_offer_pref", "local",
2282  call_offer_pref_handler, incoming_call_offer_pref_to_str, NULL, 0, 0);
2283  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "outgoing_call_offer_pref", "remote_merge",
2284  call_offer_pref_handler, outgoing_call_offer_pref_to_str, NULL, 0, 0);
2285  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "codec_prefs_incoming_offer",
2286  "prefer: pending, operation: intersect, keep: all, transcode: allow",
2287  codec_prefs_handler, incoming_offer_codec_prefs_to_str, NULL, 0, 0);
2288  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "codec_prefs_outgoing_offer",
2289  "prefer: pending, operation: union, keep: all, transcode: allow",
2290  codec_prefs_handler, outgoing_offer_codec_prefs_to_str, NULL, 0, 0);
2291  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "codec_prefs_incoming_answer",
2292  "prefer: pending, operation: intersect, keep: all",
2293  codec_prefs_handler, incoming_answer_codec_prefs_to_str, NULL, 0, 0);
2294  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "codec_prefs_outgoing_answer",
2295  "prefer: pending, operation: intersect, keep: all",
2296  codec_prefs_handler, outgoing_answer_codec_prefs_to_str, NULL, 0, 0);
2297  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint",
2298  "stir_shaken", 0, stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);
2299  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "stir_shaken_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, stir_shaken_profile));
2300  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_unauthenticated_options", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_unauthenticated_options));
2301  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_incoming_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_incoming_call_profile));
2302  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "geoloc_outgoing_call_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, geoloc_outgoing_call_profile));
2303  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_mechanisms", "", security_mechanism_handler, security_mechanism_to_str, NULL, 0, 0);
2304  ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "security_negotiation", "no", security_negotiation_handler, security_negotiation_to_str, NULL, 0, 0);
2305  ast_sorcery_object_field_register(sip_sorcery, "endpoint", "send_aoc", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, send_aoc));
2306 
2307  if (ast_sip_initialize_sorcery_transport()) {
2308  ast_log(LOG_ERROR, "Failed to register SIP transport support with sorcery\n");
2309  ast_sorcery_unref(sip_sorcery);
2310  sip_sorcery = NULL;
2311  return -1;
2312  }
2313 
2314  if (ast_sip_initialize_sorcery_location()) {
2315  ast_log(LOG_ERROR, "Failed to register SIP location support with sorcery\n");
2316  ast_sorcery_unref(sip_sorcery);
2317  sip_sorcery = NULL;
2318  return -1;
2319  }
2320 
2321  ast_sorcery_observer_add(sip_sorcery, "endpoint", &endpoint_observers);
2322 
2323  if (ast_sip_initialize_sorcery_domain_alias()) {
2324  ast_log(LOG_ERROR, "Failed to register SIP domain aliases support with sorcery\n");
2325  ast_sorcery_unref(sip_sorcery);
2326  sip_sorcery = NULL;
2327  return -1;
2328  }
2329 
2330  if (ast_sip_initialize_sorcery_global()) {
2331  ast_log(LOG_ERROR, "Failed to register SIP Global support\n");
2332  ast_sorcery_unref(sip_sorcery);
2333  sip_sorcery = NULL;
2334  return -1;
2335  }
2336 
2337  endpoint_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
2338  if (!endpoint_formatter) {
2339  ast_log(LOG_ERROR, "Unable to allocate memory for endpoint_formatter\n");
2340  ast_sorcery_unref(sip_sorcery);
2341  sip_sorcery = NULL;
2342  return -1;
2343  }
2344  endpoint_formatter->name = "endpoint";
2345  endpoint_formatter->print_header = cli_endpoint_print_header;
2346  endpoint_formatter->print_body = cli_endpoint_print_body;
2347  endpoint_formatter->get_container = cli_endpoint_get_container;
2348  endpoint_formatter->iterate = cli_endpoint_iterate;
2349  endpoint_formatter->retrieve_by_id = cli_endpoint_retrieve_by_id;
2350  endpoint_formatter->get_id = ast_sorcery_object_get_id;
2351 
2352  ast_sip_register_cli_formatter(endpoint_formatter);
2353  ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
2354 
2355  ast_sorcery_load(sip_sorcery);
2356 
2357  load_all_endpoints();
2358 
2359  acl_change_sub = stasis_subscribe(ast_security_topic(), acl_change_stasis_cb, NULL);
2362 
2363  return 0;
2364 }
2365 
2366 void ast_res_pjsip_destroy_configuration(void)
2367 {
2368  if (!sip_sorcery) {
2369  return;
2370  }
2371 
2372  acl_change_sub = stasis_unsubscribe_and_join(acl_change_sub);
2373  ast_sip_destroy_sorcery_global();
2374  ast_sip_destroy_sorcery_location();
2375  ast_sip_destroy_sorcery_auth();
2376  ast_sip_destroy_sorcery_transport();
2377  ast_sorcery_unref(sip_sorcery);
2378  sip_sorcery = NULL;
2379  ast_manager_unregister(AMI_SHOW_ENDPOINT);
2380  ast_manager_unregister(AMI_SHOW_ENDPOINTS);
2381  ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
2382  ast_sip_unregister_cli_formatter(endpoint_formatter);
2383  ast_sip_destroy_cli();
2384  ao2_cleanup(persistent_endpoints);
2385  persistent_endpoints = NULL;
2386 }
2387 
2388 int ast_res_pjsip_reload_configuration(void)
2389 {
2390  if (sip_sorcery) {
2391  ast_sorcery_reload(sip_sorcery);
2392  }
2393  return 0;
2394 }
2395 
2396 static void subscription_configuration_destroy(struct ast_sip_endpoint_subscription_configuration *subscription)
2397 {
2398  ast_string_field_free_memory(&subscription->mwi);
2399  ast_free(subscription->mwi.voicemail_extension);
2400 }
2401 
2402 static void info_configuration_destroy(struct ast_sip_endpoint_info_configuration *info)
2403 {
2405 }
2406 
2407 static void media_configuration_destroy(struct ast_sip_endpoint_media_configuration *media)
2408 {
2412 }
2413 
2414 static void endpoint_destructor(void* obj)
2415 {
2416  struct ast_sip_endpoint *endpoint = obj;
2417 
2418  ast_string_field_free_memory(endpoint);
2419 
2420  ao2_cleanup(endpoint->media.codecs);
2422  subscription_configuration_destroy(&endpoint->subscription);
2423  info_configuration_destroy(&endpoint->info);
2424  media_configuration_destroy(&endpoint->media);
2425  ast_sip_auth_vector_destroy(&endpoint->inbound_auths);
2426  ast_sip_auth_vector_destroy(&endpoint->outbound_auths);
2427  ast_party_id_free(&endpoint->id.self);
2428  endpoint->pickup.named_callgroups = ast_unref_namedgroups(endpoint->pickup.named_callgroups);
2429  endpoint->pickup.named_pickupgroups = ast_unref_namedgroups(endpoint->pickup.named_pickupgroups);
2430  ao2_cleanup(endpoint->persistent);
2432  AST_VECTOR_FREE(&endpoint->ident_method_order);
2433  ast_free(endpoint->contact_user);
2434  ast_free_acl_list(endpoint->contact_acl);
2435  ast_free_acl_list(endpoint->acl);
2436 }
2437 
2438 static int init_subscription_configuration(struct ast_sip_endpoint_subscription_configuration *subscription)
2439 {
2440  return ast_string_field_init(&subscription->mwi, 64);
2441 }
2442 
2443 static int init_info_configuration(struct ast_sip_endpoint_info_configuration *info)
2444 {
2445  return ast_string_field_init(&info->recording, 32);
2446 }
2447 
2448 static int init_media_configuration(struct ast_sip_endpoint_media_configuration *media)
2449 {
2450  return ast_string_field_init(media, 64) || ast_string_field_init(&media->rtp, 32);
2451 }
2452 
2453 void *ast_sip_endpoint_alloc(const char *name)
2454 {
2455  struct ast_sip_endpoint *endpoint = ast_sorcery_generic_alloc(sizeof(*endpoint), endpoint_destructor);
2456  if (!endpoint) {
2457  return NULL;
2458  }
2459  if (ast_string_field_init(endpoint, 64)) {
2460  ao2_cleanup(endpoint);
2461  return NULL;
2462  }
2463 
2464  if (ast_string_field_init_extended(endpoint, geoloc_incoming_call_profile) ||
2465  ast_string_field_init_extended(endpoint, geoloc_outgoing_call_profile)) {
2466  ao2_cleanup(endpoint);
2467  return NULL;
2468  }
2469  if (ast_string_field_init_extended(endpoint, overlap_context)) {
2470  ao2_cleanup(endpoint);
2471  return NULL;
2472  }
2473 
2475  ao2_cleanup(endpoint);
2476  return NULL;
2477  }
2478  if (init_subscription_configuration(&endpoint->subscription)) {
2479  ao2_cleanup(endpoint);
2480  return NULL;
2481  }
2482  if (init_info_configuration(&endpoint->info)) {
2483  ao2_cleanup(endpoint);
2484  return NULL;
2485  }
2486  if (init_media_configuration(&endpoint->media)) {
2487  ao2_cleanup(endpoint);
2488  return NULL;
2489  }
2490 
2491  ast_party_id_init(&endpoint->id.self);
2492  endpoint->id.self.tag = ast_strdup("");
2493 
2494  if (AST_VECTOR_INIT(&endpoint->ident_method_order, 1)) {
2495  return NULL;
2496  }
2497 
2498  return endpoint;
2499 }
2500 
2501 struct ao2_container *ast_sip_get_endpoints(void)
2502 {
2503  struct ao2_container *endpoints;
2504 
2505  endpoints = ast_sorcery_retrieve_by_fields(sip_sorcery, "endpoint", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
2506 
2507  return endpoints;
2508 }
2509 
2510 struct ast_sip_endpoint *ast_sip_default_outbound_endpoint(void)
2511 {
2512  RAII_VAR(char *, name, ast_sip_global_default_outbound_endpoint(), ast_free);
2513  return ast_strlen_zero(name) ? NULL : ast_sorcery_retrieve_by_id(
2514  sip_sorcery, "endpoint", name);
2515 }
2516 
2517 int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
2518 {
2519  int i;
2520 
2521  for (i = 0; i < AST_VECTOR_SIZE(auths); ++i) {
2522  /* Using AST_VECTOR_GET is safe since the vector is immutable */
2523  const char *name = AST_VECTOR_GET(auths, i);
2524  out[i] = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, name);
2525  if (!out[i]) {
2526  ast_log(LOG_NOTICE, "Couldn't find auth '%s'. Cannot authenticate\n", name);
2527  return -1;
2528  }
2529  }
2530 
2531  return 0;
2532 }
2533 
2534 void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
2535 {
2536  int i;
2537  for (i = 0; i < num_auths; ++i) {
2538  ao2_cleanup(auths[i]);
2539  }
2540 }
2541 
2542 int ast_sip_retrieve_auths_vector(const struct ast_sip_auth_vector *auth_ids,
2543  struct ast_sip_auth_objects_vector *auth_objects)
2544 {
2545  int i;
2546 
2547  for (i = 0; i < AST_VECTOR_SIZE(auth_ids); ++i) {
2548  /* Using AST_VECTOR_GET is safe since the vector is immutable */
2549  const char *name = AST_VECTOR_GET(auth_ids, i);
2550  struct ast_sip_auth *auth_object = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), SIP_SORCERY_AUTH_TYPE, name);
2551  if (!auth_object) {
2552  ast_log(LOG_WARNING, "Auth object '%s' could not be found\n", name);
2553  } else {
2554  AST_VECTOR_APPEND(auth_objects, auth_object);
2555  }
2556  }
2557 
2558  return AST_VECTOR_SIZE(auth_objects) == AST_VECTOR_SIZE(auth_ids) ? 0 : -1;
2559 }
2560 
2561 struct ast_sorcery *ast_sip_get_sorcery(void)
2562 {
2563  return sip_sorcery;
2564 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
struct ast_sip_endpoint_pickup_configuration pickup
Definition: res_pjsip.h:990
struct ast_str * output_buffer
Definition: res_pjsip_cli.h:36
struct ast_variable * next
Type for default option handler for format capabilities.
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
#define ARRAY_IN_BOUNDS(v, a)
Checks to see if value is within the bounds of the given array.
Definition: utils.h:687
#define ast_string_field_init_extended(x, field)
Initialize an extended string field.
Definition: stringfields.h:401
int presentation
Q.931 encoded presentation-indicator encoded field.
Definition: channel.h:277
const char * ast_devstate2str(enum ast_device_state devstate) attribute_pure
Convert device state to text string for output.
Definition: devicestate.c:237
int ast_rtp_dtls_cfg_parse(struct ast_rtp_dtls_cfg *dtls_cfg, const char *name, const char *value)
Parse DTLS related configuration options.
Definition: rtp_engine.c:3168
struct ast_endpoint * endpoint
Asterisk endpoint itself.
void ast_join_delim(char *s, size_t len, const char *const w[], unsigned int size, char delim)
Join an array of strings into a single string.
Definition: utils.c:2378
ast_device_state
Device States.
Definition: devicestate.h:52
enum ast_sip_dtmf_mode dtmf
Definition: res_pjsip.h:996
struct ast_sip_mwi_configuration mwi
Definition: res_pjsip.h:743
char * str
Subscriber phone number (Malloced)
Definition: channel.h:291
const char * ast_named_caller_presentation(int data)
Convert caller ID pres value to text code.
Definition: callerid.c:1382
Security Event Reporting API.
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
A contact's status.
Definition: res_pjsip.h:451
struct ast_channel_snapshot_base * base
struct ast_variable * ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery, const void *object, enum ast_sorcery_field_handler_flags flags)
Create an object set (KVP list) for an object.
Definition: sorcery.c:1511
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3310
enum ast_endpoint_state ast_endpoint_get_state(const struct ast_endpoint *endpoint)
Gets the state of the given endpoint.
unsigned int sess_expires
Definition: res_pjsip.h:702
Asterisk main include file. File version handling, generic pbx functions.
const ast_string_field fromuser
Definition: res_pjsip.h:966
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:421
A SIP address of record.
Definition: res_pjsip.h:478
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
const char * ast_stream_codec_prefs_to_str(const struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **buf)
Return a string representing the codec preferences.
Definition: stream.c:132
static char * ast_sockaddr_stringify_addr_remote(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() to return an address only.
Definition: netsock2.h:313
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:612
Endpoint configuration options for INFO packages.
Definition: res_pjsip.h:816
struct ast_flags outgoing_call_offer_pref
Definition: res_pjsip.h:935
void(* deleted)(const void *object)
Callback for when an object is deleted.
Definition: sorcery.h:340
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
int presentation
Q.931 presentation-indicator and screening-indicator encoded fields.
Definition: channel.h:295
CallerID (and other GR30) management and generation Includes code and algorithms from the Zapata libr...
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
Persistent endpoint information.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
void ast_sorcery_force_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects even if no changes determin...
Definition: sorcery.c:1457
int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *value)
Initialize security mechanism vector from string of security mechanisms.
struct ast_rtp_dtls_cfg dtls_cfg
DTLS-SRTP configuration information.
Definition: res_pjsip.h:842
struct ast_endpoint * ast_endpoint_create(const char *tech, const char *resource)
Create an endpoint struct.
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
const ast_string_field transport
Definition: res_pjsip.h:954
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
unsigned int devicestate_busy_at
Definition: res_pjsip.h:1006
struct ast_party_name name
Subscriber name.
Definition: channel.h:340
#define OBJ_KEY
Definition: astobj2.h:1151
const struct message * m
Definition: res_pjsip.h:3035
struct ast_sip_endpoint_nat_configuration nat
Definition: res_pjsip.h:984
#define ast_sorcery_object_field_register_alias(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object as an alias.
Definition: sorcery.h:971
const char * ast_endpoint_get_tech(const struct ast_endpoint *endpoint)
Gets the technology of the given endpoint.
#define AST_STREAM_MAX_CODEC_PREFS_LENGTH
Define for allocating buffer space for to_str() functions.
Definition: stream.h:307
enum ast_t38_ec_modes error_correction
Definition: res_pjsip.h:879
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3467
Endpoint subscription configuration.
Definition: res_pjsip.h:737
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
descriptor for a cli entry.
Definition: cli.h:171
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
char * contact_user
Definition: res_pjsip.h:1026
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:1693
struct ast_endpoint_snapshot * ast_endpoint_latest_snapshot(const char *tech, const char *resource)
Retrieve the most recent snapshot for the endpoint with the given name.
void * arg
Definition: res_pjsip.h:3039
AMI variable container.
Definition: res_pjsip.h:3031
char name[ACL_NAME_LENGTH]
Definition: acl.h:71
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition: astobj2.h:1327
Structure for variables, used for configurations and for channel variables.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
struct ast_sip_auth_vector outbound_auths
Definition: res_pjsip.h:994
Structure representing a snapshot of channel state.
struct ast_sip_info_recording_configuration recording
Definition: res_pjsip.h:818
struct ast_format_cap * codecs
Definition: res_pjsip.h:907
struct ast_sip_endpoint_subscription_configuration subscription
Definition: res_pjsip.h:982
Test Framework API.
Perform no matching, return all objects.
Definition: sorcery.h:123
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2464
const ast_string_field context
Definition: res_pjsip.h:952
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
#define CHARFLDSET(type, field)
A helper macro to pass the appropriate arguments to aco_option_register for OPT_CHAR_ARRAY_T.
Full structure for sorcery.
Definition: sorcery.c:230
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Definition: res_pjsip_cli.h:66
Type for a default handler that should do nothing.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
Definition: stasis.c:1077
struct stasis_message_type * ast_named_acl_change_type(void)
a stasis_message_type for changes against a named ACL or the set of all named ACLs ...
char * str
Subscriber name (Malloced)
Definition: channel.h:264
const ast_string_field address
Definition: res_pjsip.h:895
enum ast_sip_session_refresh_method method
Definition: res_pjsip.h:868
#define AST_VECTOR_REMOVE_UNORDERED(vec, idx)
Remove an element from an unordered vector by index.
Definition: vector.h:438
Definition: astman.c:222
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
Return all matching objects.
Definition: sorcery.h:120
struct ast_stream_topology * ast_stream_topology_create_from_format_cap(struct ast_format_cap *cap)
A helper function that, given a format capabilities structure, creates a topology and separates the m...
Definition: stream.c:848
void ast_endpoint_set_state(struct ast_endpoint *endpoint, enum ast_endpoint_state state)
Updates the state of the given endpoint.
Wrapper for an ast_acl linked list.
Definition: acl.h:76
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
void ast_party_id_free(struct ast_party_id *doomed)
Destroy the party id contents.
Definition: channel.c:1811
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
int ast_str2tos(const char *value, unsigned int *tos)
Convert a string to the appropriate TOS value.
Definition: acl.c:966
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
int ast_sip_security_mechanisms_to_str(const struct ast_sip_security_mechanism_vector *security_mechanisms, int add_qvalue, char **buf)
Writes the security mechanisms of an endpoint into a buffer as a string and returns the buffer...
#define ast_to_camel_case(s)
Attempts to convert the given string to camel case using an underscore as the specified delimiter...
Definition: strings.h:546
const ast_string_field uri
Definition: res_pjsip.h:457
void ast_free_ptr(void *ptr)
free() wrapper
Definition: main/astmm.c:1739
Socket address structure.
Definition: netsock2.h:97
struct ast_sip_direct_media_configuration direct_media
Definition: res_pjsip.h:903
void astman_send_error_va(struct mansession *s, const struct message *m, const char *fmt,...)
Send error in manager transaction (with va_args support)
Definition: manager.c:3394
ast_endpoint_state
Valid states for an endpoint.
Definition: endpoints.h:51
const char * ast_endpoint_get_resource(const struct ast_endpoint *endpoint)
Gets the resource name of the given endpoint.
enum ast_sip_endpoint_identifier_type ident_method
Definition: res_pjsip.h:998
unsigned int use_received_transport
Definition: res_pjsip.h:840
Media Stream API.
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
Definition: sorcery.c:1954
int ast_context_remove_extension(const char *context, const char *extension, int priority, const char *registrar)
Simply remove extension from context.
Definition: pbx.c:4948
Utility functions.
char * ast_print_group(char *buf, int buflen, ast_group_t group)
Print call and pickup groups into buffer.
Definition: channel.c:8031
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2329
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition: strings.h:786
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:3050
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
struct ast_acl_list * acl
Definition: res_pjsip.h:1020
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
struct ast_sip_security_mechanism_vector security_mechanisms
Definition: res_pjsip.h:1044
struct ast_sip_endpoint_media_configuration media
Definition: res_pjsip.h:980
Number structure.
Definition: app_followme.c:154
Type for default option handler for character array strings.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1113
Type for default option handler for bools (ast_true/ast_false)
unsigned int min_se
Definition: res_pjsip.h:700
#define ast_stream_codec_operation_to_str(value)
Safely get the name of an "operation" parameter value.
Definition: stream.h:264
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
Definition: sorcery.h:1005
struct ast_sip_identify_by_vector ident_method_order
Definition: res_pjsip.h:1000
Structure for SIP nat hook information.
Definition: res_pjsip.h:329
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
int ast_devstate_changed(enum ast_device_state state, enum ast_devstate_cache cachable, const char *fmt,...)
Tells Asterisk the State for Device is changed.
Definition: devicestate.c:510
ast_mutex_t lock
struct ast_namedgroups * named_pickupgroups
Definition: res_pjsip.h:798
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
struct ast_acl_list * contact_acl
Definition: res_pjsip.h:1022
#define AST_VECTOR_ELEM_CLEANUP_NOOP(elem)
Vector element cleanup that does nothing.
Definition: vector.h:571
Type for default option handler for unsigned integers.
int ast_variable_list_replace(struct ast_variable **head, struct ast_variable *replacement)
Replace a variable in the given list with a new value.
Definition: main/config.c:667
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
Access Control of various sorts.
static struct ao2_container * codecs
Registered codecs.
Definition: codec.c:48
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
struct ast_sip_media_rtp_configuration rtp
Definition: res_pjsip.h:901
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
Definition: strings.h:87
Use string handler only.
Definition: sorcery.h:137
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
Definition: manager.c:1785
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition: sorcery.c:2440
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
struct ast_stream_codec_negotiation_prefs codec_prefs_outgoing_answer
Definition: res_pjsip.h:943
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
struct ast_namedgroups * named_callgroups
Definition: res_pjsip.h:796
ast_stream_codec_negotiation_prefs_operation_values
The "operation" values.
Definition: stream.h:159
struct mansession * s
Definition: res_pjsip.h:3033
enum ast_rtp_dtls_hash hash
Definition: rtp_engine.h:610
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
struct ao2_container * container
Definition: res_fax.c:501
an ast_acl is a linked list node of ast_ha structs which may have names.
Definition: acl.h:67
An entity with which Asterisk communicates.
Definition: res_pjsip.h:949
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4175
enum ast_sip_session_refresh_method refresh_method
Definition: res_pjsip.h:782
#define ast_format_cap_alloc(flags)
Allocate a new ast_format_cap structure.
Definition: format_cap.h:49
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
#define MAX_OBJECT_FIELD
Maximum length of an object field name.
Definition: sorcery.h:110
Core PBX routines and definitions.
int ast_parse_caller_presentation(const char *data)
Convert caller ID text code to value (used in config file parsing)
Definition: callerid.c:1343
A snapshot of an endpoint's state.
int ast_acl_list_is_empty(struct ast_acl_list *acl_list)
Determines if an ACL is empty or if it contains entries.
Definition: acl.c:540
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2391
enum ast_sip_security_negotiation security_negotiation
Definition: res_pjsip.h:1042
enum ast_sip_contact_status_type status
Definition: res_pjsip.h:468
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
struct ast_sip_endpoint_id_configuration id
Definition: res_pjsip.h:986
enum ast_sip_session_media_encryption encryption
Definition: res_pjsip.h:846
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
int ast_stream_codec_prefs_parse(const char *pref_string, struct ast_stream_codec_negotiation_prefs *prefs, struct ast_str **error_message)
Parses a string representing the codec prefs into a ast_stream_codec_negotiation_pref structure...
Definition: stream.c:181
unsigned int enabled
Definition: rtp_engine.h:606
enum ast_rtp_dtls_setup default_setup
Definition: rtp_engine.h:608
struct ast_namedgroups * ast_get_namedgroups(const char *s)
Create an ast_namedgroups set with group names from comma separated string.
Definition: channel.c:7675
struct ast_sip_endpoint_info_configuration info
Definition: res_pjsip.h:988
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
#define ast_sorcery_internal_object_register(sorcery, type, alloc, transform, apply)
Register an internal, hidden object type.
Definition: sorcery.h:867
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
struct ast_sip_auth_vector inbound_auths
Definition: res_pjsip.h:992
Support for dynamic strings.
Definition: strings.h:623
enum ast_rtp_dtls_verify verify
Definition: rtp_engine.h:611
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
Media configuration for SIP endpoints.
Definition: res_pjsip.h:893
Interface for a sorcery object type observer.
Definition: sorcery.h:332
Type for default option handler for bools (ast_true/ast_false)
struct ast_acl_list * ast_free_acl_list(struct ast_acl_list *acl)
Free a list of ACLs.
Definition: acl.c:233
struct stasis_message_type * ast_endpoint_state_type(void)
Message type for endpoint state changes.
struct ast_sip_t38_configuration t38
Definition: res_pjsip.h:905
const char * action_id
Definition: res_pjsip.h:3037
int ast_rtp_dtls_cfg_validate(struct ast_rtp_dtls_cfg *dtls_cfg)
Validates DTLS related configuration options.
Definition: rtp_engine.c:3242
unsigned int preferred_codec_only
Definition: res_pjsip.h:1028
static struct stasis_rest_handlers endpoints
REST handler for /api-docs/endpoints.json.
struct ast_sip_timer_options timer
Definition: res_pjsip.h:715
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604
char * command
Definition: cli.h:186
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:625
enum ast_sip_direct_media_glare_mitigation glare_mitigation
Definition: res_pjsip.h:870
struct ast_stream_codec_negotiation_prefs codec_prefs_incoming_answer
Definition: res_pjsip.h:941
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Definition: stasis.c:1134
unsigned int ephemeral_cert
Definition: rtp_engine.h:617
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
void ast_party_id_init(struct ast_party_id *init)
Initialize the given party id structure.
Definition: channel.c:1757
Structure used to handle boolean flags.
Definition: utils.h:199
const char * usage
Definition: cli.h:177
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
Definition: sorcery.c:1897
void ast_endpoint_blob_publish(struct ast_endpoint *endpoint, struct stasis_message_type *type, struct ast_json *blob)
Creates and publishes a ast_endpoint_blob message.
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition: sorcery.c:1377
#define AST_YESNO(x)
return Yes or No depending on the argument.
Definition: strings.h:143
char * tag
User-set "tag".
Definition: channel.h:354
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1408
struct ast_endpoint * persistent
Definition: res_pjsip.h:1004
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680
enum ast_sip_100rel_mode rel100
Definition: res_pjsip.h:1056
static struct stasis_subscription * acl_change_sub
Definition: chan_iax2.c:328
int ast_add_extension(const char *context, int replace, const char *extension, int priority, const char *label, const char *callerid, const char *application, void *data, void(*datad)(void *), const char *registrar)
Add and extension to an extension context.
Definition: pbx.c:6928
struct ast_stream_topology * topology
Definition: res_pjsip.h:909
struct ast_channel_snapshot * ast_channel_snapshot_get_latest(const char *uniqueid)
Obtain the latest ast_channel_snapshot from the Stasis Message Bus API cache. This is an ao2 object...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
void ast_append_acl(const char *sense, const char *stuff, struct ast_acl_list **path, int *error, int *named_acl_flag)
Add a rule to an ACL struct.
Definition: acl.c:429
void ast_rtp_dtls_cfg_free(struct ast_rtp_dtls_cfg *dtls_cfg)
Free contents of a DTLS configuration structure.
Definition: rtp_engine.c:3279
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
Definition: utils.c:2216
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1023
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
struct stasis_message_type * ast_endpoint_contact_state_type(void)
Message type for endpoint contact state changes.
struct ast_sip_endpoint_extensions extensions
Definition: res_pjsip.h:978
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
#define ast_stream_codec_param_to_str(value)
Safely get the name of a preference parameter.
Definition: stream.h:244
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
struct stasis_topic * ast_security_topic(void)
A stasis_topic which publishes messages for security related issues.
ast_stream_codec_negotiation_prefs_prefer_values
The "prefer" values.
Definition: stream.h:145
Generic container type.
unsigned char valid
TRUE if the name information is valid/present.
Definition: channel.h:279
struct ast_variable * channel_vars
Definition: res_pjsip.h:1014
unsigned int stir_shaken
Definition: res_pjsip.h:1046
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
struct ast_context * ast_context_find_or_create(struct ast_context **extcontexts, struct ast_hashtab *exttable, const char *name, const char *registrar)
Register a new context or find an existing one.
Definition: pbx.c:6149
void ast_stream_topology_free(struct ast_stream_topology *topology)
Unreference and destroy a stream topology.
Definition: stream.c:743
const ast_string_field aors
Definition: res_pjsip.h:958
struct ast_flags incoming_call_offer_pref
Definition: res_pjsip.h:933
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:191
ao2_callback_fn * print_body
Definition: res_pjsip_cli.h:62
void ast_endpoint_shutdown(struct ast_endpoint *endpoint)
Shutsdown an ast_endpoint.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Definition: manager.c:3389
const char * name
Definition: res_pjsip_cli.h:58
unsigned int rekey
Definition: rtp_engine.h:607
char * ast_print_namedgroups(struct ast_str **buf, struct ast_namedgroups *groups)
Print named call groups and named pickup groups.
Definition: channel.c:8056
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
struct ast_stream_codec_negotiation_prefs codec_prefs_outgoing_offer
Definition: res_pjsip.h:939
struct ast_stream_codec_negotiation_prefs codec_prefs_incoming_offer
Definition: res_pjsip.h:937
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
enum ast_sip_session_redirect redirect_method
Definition: res_pjsip.h:1012
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
Definition: main/config.c:543
unsigned char valid
TRUE if the number information is valid/present.
Definition: channel.h:297
const ast_string_field aor
Definition: res_pjsip.h:457
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
const ast_string_field name
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Sorcery Data Access Layer API.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3431
unsigned show_details_only_level_0
Definition: res_pjsip_cli.h:46
struct ast_party_number number
Subscriber phone number.
Definition: channel.h:342