Asterisk - The Open Source Telephony Project  21.4.1
location.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Joshua Colp <jcolp@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 #include <pjsip.h>
21 #include <pjlib.h>
22 
23 #include "asterisk/res_pjsip.h"
24 #include "asterisk/logger.h"
25 #include "asterisk/astobj2.h"
26 #include "asterisk/paths.h"
27 #include "asterisk/sorcery.h"
28 #include "asterisk/taskprocessor.h"
29 #include "include/res_pjsip_private.h"
30 #include "asterisk/res_pjsip_cli.h"
31 #include "asterisk/statsd.h"
32 #include "asterisk/named_locks.h"
33 
34 #include "asterisk/res_pjproject.h"
35 
36 static int pj_max_hostname = PJ_MAX_HOSTNAME;
37 static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
38 
39 /*! \brief Destructor for AOR */
40 static void aor_destroy(void *obj)
41 {
42  struct ast_sip_aor *aor = obj;
43 
44  ao2_cleanup(aor->permanent_contacts);
46  ast_free(aor->voicemail_extension);
47 }
48 
49 /*! \brief Allocator for AOR */
50 static void *aor_alloc(const char *name)
51 {
52  void *lock;
53  struct ast_sip_aor *aor;
54 
55  lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", name);
56  if (!lock) {
57  return NULL;
58  }
59 
60  aor = ast_sorcery_lockable_alloc(sizeof(struct ast_sip_aor), aor_destroy, lock);
61  ao2_ref(lock, -1);
62 
63  if (!aor) {
64  return NULL;
65  }
66  ast_string_field_init(aor, 128);
67 
68  return aor;
69 }
70 
71 /*! \brief Internal callback function which destroys the specified contact */
72 static int destroy_contact(void *obj, void *arg, int flags)
73 {
74  struct ast_sip_contact *contact = obj;
75 
76  ast_sip_location_delete_contact(contact);
77 
78  return CMP_MATCH;
79 }
80 
81 static void aor_deleted_observer(const void *object)
82 {
83  const struct ast_sip_aor *aor = object;
84  const char *aor_id = ast_sorcery_object_get_id(object);
85  /* Give enough space for ;@ at the end, since that is our object naming scheme */
86  size_t prefix_len = strlen(aor_id) + sizeof(";@") - 1;
87  char prefix[prefix_len + 1];
88  struct ao2_container *contacts;
89 
90  if (aor->permanent_contacts) {
91  ao2_callback(aor->permanent_contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, destroy_contact, NULL);
92  }
93 
94  sprintf(prefix, "%s;@", aor_id); /* Safe */
95  if (!(contacts = ast_sorcery_retrieve_by_prefix(ast_sip_get_sorcery(), "contact", prefix, prefix_len))) {
96  return;
97  }
98  /* Destroy any contacts that may still exist that were made for this AoR */
99  ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, destroy_contact, NULL);
100 
101  ao2_ref(contacts, -1);
102 }
103 
104 /*! \brief Observer for contacts so state can be updated on respective endpoints */
105 static const struct ast_sorcery_observer aor_observer = {
106  .deleted = aor_deleted_observer,
107 };
108 
109 
110 /*! \brief Destructor for contact */
111 static void contact_destroy(void *obj)
112 {
113  struct ast_sip_contact *contact = obj;
114 
116  ao2_cleanup(contact->endpoint);
117 }
118 
119 /*! \brief Allocator for contact */
120 static void *contact_alloc(const char *name)
121 {
122  struct ast_sip_contact *contact = ast_sorcery_generic_alloc(sizeof(*contact), contact_destroy);
123  char *id = ast_strdupa(name);
124  char *aor = id;
125  char *aor_separator = NULL;
126 
127  if (!contact) {
128  return NULL;
129  }
130 
131  if (ast_string_field_init(contact, 256)) {
132  ao2_cleanup(contact);
133  return NULL;
134  }
135 
136  /* Dynamic contacts are delimited with ";@" and static ones with "@@" */
137  if ((aor_separator = strstr(id, ";@")) || (aor_separator = strstr(id, "@@"))) {
138  *aor_separator = '\0';
139  }
140  ast_assert(aor_separator != NULL);
141 
142  ast_string_field_set(contact, aor, aor);
143 
144  return contact;
145 }
146 
147 struct ast_sip_aor *ast_sip_location_retrieve_aor(const char *aor_name)
148 {
149  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", aor_name);
150 }
151 
152 /*! \brief Internal callback function which deletes and unlinks any expired contacts */
153 static int contact_expire(void *obj, void *arg, int flags)
154 {
155  struct ast_sip_contact *contact = obj;
156 
157  /* If the contact has not yet expired it is valid */
158  if (ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) > 0) {
159  return 0;
160  }
161 
162  ast_sip_location_delete_contact(contact);
163 
164  return CMP_MATCH;
165 }
166 
167 /*! \brief Internal callback function which links static contacts into another container */
168 static int contact_link_static(void *obj, void *arg, int flags)
169 {
170  struct ao2_container *dest = arg;
171 
172  ao2_link(dest, obj);
173  return 0;
174 }
175 
176 /*! \brief Internal callback function which removes any contact which is unreachable */
177 static int contact_remove_unreachable(void *obj, void *arg, int flags)
178 {
179  struct ast_sip_contact *contact = obj;
181  int unreachable;
182 
183  status = ast_sip_get_contact_status(contact);
184  if (!status) {
185  return 0;
186  }
187 
188  unreachable = (status->status == UNAVAILABLE);
189  ao2_ref(status, -1);
190 
191  return unreachable ? CMP_MATCH : 0;
192 }
193 
194 struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact(const struct ast_sip_aor *aor)
195 {
196  return ast_sip_location_retrieve_first_aor_contact_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
197 }
198 
199 struct ast_sip_contact *ast_sip_location_retrieve_first_aor_contact_filtered(const struct ast_sip_aor *aor,
200  unsigned int flags)
201 {
202  struct ao2_container *contacts;
203  struct ast_sip_contact *contact = NULL;
204 
205  contacts = ast_sip_location_retrieve_aor_contacts_filtered(aor, flags);
206  if (contacts && ao2_container_count(contacts)) {
207  /* Get the first AOR contact in the container. */
208  contact = ao2_callback(contacts, 0, NULL, NULL);
209  }
210  ao2_cleanup(contacts);
211  return contact;
212 }
213 
214 struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor)
215 {
216  return ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
217 }
218 
219 struct ao2_container *ast_sip_location_retrieve_aor_contacts_nolock_filtered(const struct ast_sip_aor *aor,
220  unsigned int flags)
221 {
222  /* Give enough space for ;@ at the end, since that is our object naming scheme */
223  size_t prefix_len = strlen(ast_sorcery_object_get_id(aor)) + sizeof(";@") - 1;
224  char prefix[prefix_len + 1];
225  struct ao2_container *contacts;
226 
227  sprintf(prefix, "%s;@", ast_sorcery_object_get_id(aor)); /* Safe */
228  if (!(contacts = ast_sorcery_retrieve_by_prefix(ast_sip_get_sorcery(), "contact", prefix, prefix_len))) {
229  return NULL;
230  }
231 
232  /* Prune any expired contacts and delete them, we do this first because static contacts can never expire */
233  ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_expire, NULL);
234 
235  /* Add any permanent contacts from the AOR */
236  if (aor->permanent_contacts) {
237  ao2_callback(aor->permanent_contacts, OBJ_NODATA, contact_link_static, contacts);
238  }
239 
240  if (flags & AST_SIP_CONTACT_FILTER_REACHABLE) {
241  ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, contact_remove_unreachable, NULL);
242  }
243 
244  return contacts;
245 }
246 
247 struct ao2_container *ast_sip_location_retrieve_aor_contacts(const struct ast_sip_aor *aor)
248 {
249  return ast_sip_location_retrieve_aor_contacts_filtered(aor, AST_SIP_CONTACT_FILTER_DEFAULT);
250 }
251 
252 struct ao2_container *ast_sip_location_retrieve_aor_contacts_filtered(const struct ast_sip_aor *aor,
253  unsigned int flags)
254 {
255  struct ao2_container *contacts;
256 
257  /* ao2_lock / ao2_unlock do not actually write aor since it has an ao2 lockobj. */
258  ao2_lock((void*)aor);
259  contacts = ast_sip_location_retrieve_aor_contacts_nolock_filtered(aor, flags);
260  ao2_unlock((void*)aor);
261 
262  return contacts;
263 }
264 
265 
266 void ast_sip_location_retrieve_contact_and_aor_from_list(const char *aor_list, struct ast_sip_aor **aor,
267  struct ast_sip_contact **contact)
268 {
269  ast_sip_location_retrieve_contact_and_aor_from_list_filtered(aor_list, AST_SIP_CONTACT_FILTER_DEFAULT, aor, contact);
270 }
271 
272 void ast_sip_location_retrieve_contact_and_aor_from_list_filtered(const char *aor_list, unsigned int flags,
273  struct ast_sip_aor **aor, struct ast_sip_contact **contact)
274 {
275  char *aor_name;
276  char *rest;
277 
278  /* If the location is still empty we have nowhere to go */
279  if (ast_strlen_zero(aor_list) || !(rest = ast_strdupa(aor_list))) {
280  ast_log(LOG_WARNING, "Unable to determine contacts from empty aor list\n");
281  return;
282  }
283 
284  *aor = NULL;
285  *contact = NULL;
286 
287  while ((aor_name = ast_strip(strsep(&rest, ",")))) {
288  *aor = ast_sip_location_retrieve_aor(aor_name);
289 
290  if (!(*aor)) {
291  continue;
292  }
293  *contact = ast_sip_location_retrieve_first_aor_contact_filtered(*aor, flags);
294  /* If a valid contact is available use its URI for dialing */
295  if (*contact) {
296  break;
297  }
298 
299  ao2_ref(*aor, -1);
300  *aor = NULL;
301  }
302 }
303 
304 struct ast_sip_contact *ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
305 {
306  struct ast_sip_aor *aor;
307  struct ast_sip_contact *contact;
308 
309  ast_sip_location_retrieve_contact_and_aor_from_list(aor_list, &aor, &contact);
310 
311  ao2_cleanup(aor);
312 
313  return contact;
314 }
315 
316 static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags);
317 static int cli_contact_populate_container(void *obj, void *arg, int flags);
318 
319 static int gather_contacts_for_aor(void *obj, void *arg, int flags)
320 {
321  struct ao2_container *aor_contacts;
322  struct ast_sip_aor *aor = obj;
323  struct ao2_container *container = arg;
324 
325  aor_contacts = ast_sip_location_retrieve_aor_contacts(aor);
326  if (!aor_contacts) {
327  return 0;
328  }
329  ao2_callback(aor_contacts, OBJ_MULTIPLE | OBJ_NODATA, cli_contact_populate_container,
330  container);
331  ao2_ref(aor_contacts, -1);
332  return CMP_MATCH;
333 }
334 
335 struct ao2_container *ast_sip_location_retrieve_contacts_from_aor_list(const char *aor_list)
336 {
337  struct ao2_container *contacts;
338 
340  AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
341  if (!contacts) {
342  return NULL;
343  }
344 
345  ast_sip_for_each_aor(aor_list, gather_contacts_for_aor, contacts);
346 
347  return contacts;
348 }
349 
350 struct ast_sip_contact *ast_sip_location_retrieve_contact(const char *contact_name)
351 {
352  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "contact", contact_name);
353 }
354 
355 struct ast_sip_contact *ast_sip_location_create_contact(struct ast_sip_aor *aor,
356  const char *uri, struct timeval expiration_time, const char *path_info,
357  const char *user_agent, const char *via_addr, int via_port, const char *call_id,
359 {
360  struct ast_sip_contact *contact;
361  char name[MAX_OBJECT_FIELD * 2 + 3];
362  char hash[33];
363 
364  ast_md5_hash(hash, uri);
365  snprintf(name, sizeof(name), "%s;@%s", ast_sorcery_object_get_id(aor), hash);
366 
367  contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", name);
368  if (!contact) {
369  return NULL;
370  }
371 
372  ast_string_field_set(contact, uri, uri);
373  contact->expiration_time = expiration_time;
374  contact->qualify_frequency = aor->qualify_frequency;
375  contact->qualify_timeout = aor->qualify_timeout;
377  if (path_info && aor->support_path) {
378  ast_string_field_set(contact, path, path_info);
379  }
380 
381  if (!ast_strlen_zero(aor->outbound_proxy)) {
383  }
384 
385  if (!ast_strlen_zero(user_agent)) {
386  ast_string_field_set(contact, user_agent, user_agent);
387  }
388 
389  if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
390  ast_string_field_set(contact, reg_server, ast_config_AST_SYSTEM_NAME);
391  }
392 
393  if (!ast_strlen_zero(via_addr)) {
394  ast_string_field_set(contact, via_addr, via_addr);
395  }
396  contact->via_port = via_port;
397 
398  if (!ast_strlen_zero(call_id)) {
399  ast_string_field_set(contact, call_id, call_id);
400  }
401 
402  contact->endpoint = ao2_bump(endpoint);
403  if (endpoint) {
405  }
406 
407  contact->prune_on_boot = prune_on_boot;
408 
409  if (ast_sorcery_create(ast_sip_get_sorcery(), contact)) {
410  ao2_ref(contact, -1);
411  return NULL;
412  }
413  return contact;
414 }
415 
416 int ast_sip_location_add_contact_nolock(struct ast_sip_aor *aor, const char *uri,
417  struct timeval expiration_time, const char *path_info, const char *user_agent,
418  const char *via_addr, int via_port, const char *call_id,
419  struct ast_sip_endpoint *endpoint)
420 {
421  struct ast_sip_contact *contact;
422 
423  contact = ast_sip_location_create_contact(aor, uri, expiration_time, path_info,
424  user_agent, via_addr, via_port, call_id, 0, endpoint);
425  ao2_cleanup(contact);
426  return contact ? 0 : -1;
427 }
428 
429 int ast_sip_location_add_contact(struct ast_sip_aor *aor, const char *uri,
430  struct timeval expiration_time, const char *path_info, const char *user_agent,
431  const char *via_addr, int via_port, const char *call_id,
432  struct ast_sip_endpoint *endpoint)
433 {
434  int res;
435 
436  ao2_lock(aor);
437  res = ast_sip_location_add_contact_nolock(aor, uri, expiration_time, path_info, user_agent,
438  via_addr, via_port, call_id,
439  endpoint);
440  ao2_unlock(aor);
441 
442  return res;
443 }
444 
445 int ast_sip_location_update_contact(struct ast_sip_contact *contact)
446 {
447  return ast_sorcery_update(ast_sip_get_sorcery(), contact);
448 }
449 
450 int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
451 {
452  return ast_sorcery_delete(ast_sip_get_sorcery(), contact);
453 }
454 
455 static int prune_boot_contacts_cb(void *obj, void *arg, int flags)
456 {
457  struct ast_sip_contact *contact = obj;
458 
459  if (contact->prune_on_boot
460  && !strcmp(contact->reg_server, ast_config_AST_SYSTEM_NAME ?: "")) {
461  ast_verb(3, "Removed contact '%s' from AOR '%s' due to system boot\n",
462  contact->uri, contact->aor);
463  ast_sip_location_delete_contact(contact);
464  }
465 
466  return 0;
467 }
468 
469 void ast_sip_location_prune_boot_contacts(void)
470 {
471  struct ao2_container *contacts;
472 
473  contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact",
475  if (contacts) {
476  ao2_callback(contacts, 0, prune_boot_contacts_cb, NULL);
477  ao2_ref(contacts, -1);
478  }
479 }
480 
481 /*! \brief Custom handler for translating from a string timeval to actual structure */
482 static int expiration_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
483 {
484  struct ast_sip_contact *contact = obj;
485  return ast_get_timeval(var->value, &contact->expiration_time, ast_tv(0, 0), NULL);
486 }
487 
488 /*! \brief Custom handler for translating from an actual structure timeval to string */
489 static int expiration_struct2str(const void *obj, const intptr_t *args, char **buf)
490 {
491  const struct ast_sip_contact *contact = obj;
492  char secs[AST_TIME_T_LEN];
493 
494  ast_time_t_to_string(contact->expiration_time.tv_sec, secs, sizeof(secs));
495  return (ast_asprintf(buf, "%s", secs) < 0) ? -1 : 0;
496 }
497 
498 static int permanent_uri_sort_fn(const void *obj_left, const void *obj_right, int flags)
499 {
500  const struct ast_sip_contact *object_left = obj_left;
501  const struct ast_sip_contact *object_right = obj_right;
502  const char *right_key = obj_right;
503  int cmp;
504 
505  switch (flags & OBJ_SEARCH_MASK) {
506  case OBJ_SEARCH_OBJECT:
507  right_key = ast_sorcery_object_get_id(object_right);
508  /* Fall through */
509  case OBJ_SEARCH_KEY:
510  cmp = strcmp(ast_sorcery_object_get_id(object_left), right_key);
511  break;
513  /*
514  * We could also use a partial key struct containing a length
515  * so strlen() does not get called for every comparison instead.
516  */
517  cmp = strncmp(ast_sorcery_object_get_id(object_left), right_key, strlen(right_key));
518  break;
519  default:
520  /* Sort can only work on something with a full or partial key. */
521  ast_assert(0);
522  cmp = 0;
523  break;
524  }
525  return cmp;
526 }
527 
528 int ast_sip_validate_uri_length(const char *contact_uri)
529 {
530  int max_length = pj_max_hostname - 1;
531  char *contact = ast_strdupa(contact_uri);
532  char *host;
533  char *at;
534  int theres_a_port = 0;
535 
536  if (strlen(contact_uri) > pjsip_max_url_size - 1) {
537  return -1;
538  }
539 
540  contact = ast_strip_quoted(contact, "<", ">");
541 
542  if (!strncasecmp(contact, "sip:", 4)) {
543  host = contact + 4;
544  } else if (!strncasecmp(contact, "sips:", 5)) {
545  host = contact + 5;
546  } else {
547  /* Not a SIP URI */
548  return -1;
549  }
550 
551  at = strchr(contact, '@');
552  if (at) {
553  /* sip[s]:user@host */
554  host = at + 1;
555  }
556 
557  if (host[0] == '[') {
558  /* Host is an IPv6 address. Just get up to the matching bracket */
559  char *close_bracket;
560 
561  close_bracket = strchr(host, ']');
562  if (!close_bracket) {
563  return -1;
564  }
565  close_bracket++;
566  if (*close_bracket == ':') {
567  theres_a_port = 1;
568  }
569  *close_bracket = '\0';
570  } else {
571  /* uri parameters could contain ';' so trim them off first */
572  host = strsep(&host, ";?");
573  /* Host is FQDN or IPv4 address. Need to find closing delimiter */
574  if (strchr(host, ':')) {
575  theres_a_port = 1;
576  host = strsep(&host, ":");
577  }
578  }
579 
580  if (!theres_a_port) {
581  max_length -= strlen("_sips.tcp.");
582  }
583 
584  if (strlen(host) > max_length) {
585  return -1;
586  }
587 
588  return 0;
589 }
590 
591 /*! \brief Custom handler for permanent URIs */
592 static int permanent_uri_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
593 {
594  struct ast_sip_aor *aor = obj;
595  const char *aor_id = ast_sorcery_object_get_id(aor);
596  char *contacts;
597  char *contact_uri;
598 
599  if (ast_strlen_zero(var->value)) {
600  return 0;
601  }
602 
603  contacts = ast_strdupa(var->value);
604  while ((contact_uri = ast_strip(strsep(&contacts, ",")))) {
605  struct ast_sip_contact *contact;
607  char hash[33];
608  char contact_id[strlen(aor_id) + sizeof(hash) + 2];
609 
610  if (ast_strlen_zero(contact_uri)) {
611  continue;
612  }
613 
614  if (ast_sip_validate_uri_length(contact_uri)) {
615  ast_log(LOG_ERROR, "Contact uri or hostname length exceeds pjproject limit or is not a sip(s) uri: %s\n", contact_uri);
616  return -1;
617  }
618 
619  if (!aor->permanent_contacts) {
621  AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT, permanent_uri_sort_fn, NULL);
622  if (!aor->permanent_contacts) {
623  return -1;
624  }
625  }
626 
627  ast_md5_hash(hash, contact_uri);
628  snprintf(contact_id, sizeof(contact_id), "%s@@%s", aor_id, hash);
629  contact = ast_sorcery_alloc(ast_sip_get_sorcery(), "contact", contact_id);
630  if (!contact) {
631  return -1;
632  }
633 
634  ast_string_field_set(contact, uri, contact_uri);
635 
636  status = ast_res_pjsip_find_or_create_contact_status(contact);
637  if (!status) {
638  ao2_ref(contact, -1);
639  return -1;
640  }
641  ao2_ref(status, -1);
642 
643  ao2_link(aor->permanent_contacts, contact);
644  ao2_ref(contact, -1);
645  }
646 
647  return 0;
648 }
649 
650 static int contact_to_var_list(void *object, void *arg, int flags)
651 {
652  struct ast_sip_contact_wrapper *wrapper = object;
653  struct ast_variable **var = arg;
654 
655  ast_variable_list_append(&*var, ast_variable_new("contact", wrapper->contact->uri, ""));
656 
657  return 0;
658 }
659 
660 static int contacts_to_var_list(const void *obj, struct ast_variable **fields)
661 {
662  const struct ast_sip_aor *aor = obj;
663 
664  ast_sip_for_each_contact(aor, contact_to_var_list, fields);
665 
666  return 0;
667 }
668 
669 static int voicemail_extension_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
670 {
671  struct ast_sip_aor *aor = obj;
672 
673  aor->voicemail_extension = ast_strdup(var->value);
674 
675  return aor->voicemail_extension ? 0 : -1;
676 }
677 
678 static int voicemail_extension_to_str(const void *obj, const intptr_t *args, char **buf)
679 {
680  const struct ast_sip_aor *aor = obj;
681 
682  *buf = ast_strdup(aor->voicemail_extension);
683 
684  return 0;
685 }
686 
687 int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
688 {
689  char *copy;
690  char *name;
691  int res;
692 
693  if (!on_aor || ast_strlen_zero(aors)) {
694  return 0;
695  }
696 
697  copy = ast_strdupa(aors);
698  while ((name = ast_strip(strsep(&copy, ",")))) {
699  struct ast_sip_aor *aor;
700 
701  aor = ast_sip_location_retrieve_aor(name);
702  if (aor) {
703  res = on_aor(aor, arg, 0);
704  ao2_ref(aor, -1);
705  if (res) {
706  return -1;
707  }
708  }
709  }
710  return 0;
711 }
712 
713 static void contact_wrapper_destroy(void *obj)
714 {
715  struct ast_sip_contact_wrapper *wrapper = obj;
716 
717  ast_free(wrapper->aor_id);
718  ast_free(wrapper->contact_id);
719  ao2_cleanup(wrapper->contact);
720 }
721 
722 int ast_sip_for_each_contact(const struct ast_sip_aor *aor,
723  ao2_callback_fn on_contact, void *arg)
724 {
725  struct ao2_container *contacts;
726  struct ao2_iterator i;
727  int res = 0;
728  void *object = NULL;
729 
730  if (!on_contact ||
731  !(contacts = ast_sip_location_retrieve_aor_contacts(aor))) {
732  return 0;
733  }
734 
735  i = ao2_iterator_init(contacts, 0);
736  while ((object = ao2_iterator_next(&i))) {
737  RAII_VAR(struct ast_sip_contact *, contact, object, ao2_cleanup);
738  RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
739  const char *aor_id = ast_sorcery_object_get_id(aor);
740 
741  wrapper = ao2_alloc_options(sizeof(struct ast_sip_contact_wrapper),
742  contact_wrapper_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
743  if (!wrapper) {
744  res = -1;
745  break;
746  }
747  wrapper->contact_id = ast_malloc(strlen(aor_id) + strlen(contact->uri) + 2);
748  if (!wrapper->contact_id) {
749  res = -1;
750  break;
751  }
752  sprintf(wrapper->contact_id, "%s/%s", aor_id, contact->uri);
753  wrapper->aor_id = ast_strdup(aor_id);
754  if (!wrapper->aor_id) {
755  res = -1;
756  break;
757  }
758  wrapper->contact = contact;
759  ao2_bump(wrapper->contact);
760 
761  if ((res = on_contact(wrapper, arg, 0))) {
762  break;
763  }
764  }
766  ao2_ref(contacts, -1);
767  return res;
768 }
769 
770 int ast_sip_contact_to_str(void *object, void *arg, int flags)
771 {
772  struct ast_sip_contact_wrapper *wrapper = object;
773  struct ast_str **buf = arg;
774 
775  ast_str_append(buf, 0, "%s,", wrapper->contact_id);
776 
777  return 0;
778 }
779 
780 static int sip_aor_to_ami(const struct ast_sip_aor *aor, struct ast_str **buf)
781 {
782  struct ast_variable *objset;
783  struct ast_variable *i;
784 
785  objset = ast_sorcery_objectset_create2(ast_sip_get_sorcery(), aor,
787  if (!objset) {
788  return -1;
789  }
790 
791  ast_str_append(buf, 0, "ObjectType: %s\r\n",
793  ast_str_append(buf, 0, "ObjectName: %s\r\n",
795 
796  for (i = objset; i; i = i->next) {
797  char *camel = ast_to_camel_case(i->name);
798 
799  if (strcmp(camel, "Contact") == 0) {
800  ast_free(camel);
801  camel = NULL;
802  }
803  ast_str_append(buf, 0, "%s: %s\r\n", S_OR(camel, "Contacts"), i->value);
804  ast_free(camel);
805  }
806 
807  ast_variables_destroy(objset);
808  return 0;
809 }
810 
811 static int contacts_to_str(const void *obj, const intptr_t *args, char **buf)
812 {
813  const struct ast_sip_aor *aor = obj;
814  struct ast_str *str;
815 
817  if (!str) {
818  *buf = NULL;
819  return -1;
820  }
821 
822  ast_sip_for_each_contact(aor, ast_sip_contact_to_str, &str);
823  ast_str_truncate(str, -1);
824 
825  *buf = ast_strdup(ast_str_buffer(str));
826  ast_free(str);
827 
828  return *buf ? 0 : -1;
829 }
830 
831 static int format_ami_aor_handler(void *obj, void *arg, int flags)
832 {
833  struct ast_sip_aor *aor = obj;
834  struct ast_sip_ami *ami = arg;
835  const struct ast_sip_endpoint *endpoint = ami->arg;
836  struct ast_str *buf;
837  struct ao2_container *contacts;
838  int total_contacts;
839  int num_permanent;
840 
841  buf = ast_sip_create_ami_event("AorDetail", ami);
842  if (!buf) {
843  return -1;
844  }
845  contacts = ast_sip_location_retrieve_aor_contacts(aor);
846  if (!contacts) {
847  ast_free(buf);
848  return -1;
849  }
850 
851  sip_aor_to_ami(aor, &buf);
852  total_contacts = ao2_container_count(contacts);
853  num_permanent = aor->permanent_contacts ?
855 
856  ast_str_append(&buf, 0, "TotalContacts: %d\r\n", total_contacts);
857  ast_str_append(&buf, 0, "ContactsRegistered: %d\r\n",
858  total_contacts - num_permanent);
859  ast_str_append(&buf, 0, "EndpointName: %s\r\n",
860  ast_sorcery_object_get_id(endpoint));
861 
862  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
863  ami->count++;
864 
865  ast_free(buf);
866  ao2_ref(contacts, -1);
867  return 0;
868 }
869 
870 static int format_ami_endpoint_aor(const struct ast_sip_endpoint *endpoint,
871  struct ast_sip_ami *ami)
872 {
873  ami->arg = (void *)endpoint;
874  return ast_sip_for_each_aor(endpoint->aors,
875  format_ami_aor_handler, ami);
876 }
877 
878 struct ast_sip_endpoint_formatter endpoint_aor_formatter = {
879  .format_ami = format_ami_endpoint_aor
880 };
881 
882 static struct ao2_container *cli_aor_get_container(const char *regex)
883 {
884  struct ao2_container *container;
885  struct ao2_container *s_container;
886 
887  container = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "aor", regex);
888  if (!container) {
889  return NULL;
890  }
891 
892  /* Create a sorted container of aors. */
895  if (s_container
896  && ao2_container_dup(s_container, container, 0)) {
897  ao2_ref(s_container, -1);
898  s_container = NULL;
899  }
900  ao2_ref(container, -1);
901 
902  return s_container;
903 }
904 
905 static int cli_contact_populate_container(void *obj, void *arg, int flags)
906 {
907  ao2_link(arg, obj);
908 
909  return 0;
910 }
911 
912 static int cli_aor_gather_contacts(void *obj, void *arg, int flags)
913 {
914  struct ast_sip_aor *aor = obj;
915 
916  return ast_sip_for_each_contact(aor, cli_contact_populate_container, arg);
917 }
918 
919 static const char *cli_contact_get_id(const void *obj)
920 {
921  const struct ast_sip_contact_wrapper *wrapper = obj;
922  return wrapper->contact_id;
923 }
924 
925 static int cli_contact_sort(const void *obj, const void *arg, int flags)
926 {
927  const struct ast_sip_contact_wrapper *left_wrapper = obj;
928  const struct ast_sip_contact_wrapper *right_wrapper = arg;
929  const char *right_key = arg;
930  int cmp = 0;
931 
932  switch (flags & OBJ_SEARCH_MASK) {
933  case OBJ_SEARCH_OBJECT:
934  right_key = right_wrapper->contact_id;
935  /* Fall through */
936  case OBJ_SEARCH_KEY:
937  cmp = strcmp(left_wrapper->contact_id, right_key);
938  break;
940  cmp = strncmp(left_wrapper->contact_id, right_key, strlen(right_key));
941  break;
942  default:
943  cmp = 0;
944  break;
945  }
946 
947  return cmp;
948 }
949 
950 static int cli_contact_compare(void *obj, void *arg, int flags)
951 {
952  const struct ast_sip_contact_wrapper *left_wrapper = obj;
953  const struct ast_sip_contact_wrapper *right_wrapper = arg;
954  const char *right_key = arg;
955  int cmp = 0;
956 
957  switch (flags & OBJ_SEARCH_MASK) {
958  case OBJ_SEARCH_OBJECT:
959  right_key = right_wrapper->contact_id;
960  /* Fall through */
961  case OBJ_SEARCH_KEY:
962  if (strcmp(left_wrapper->contact_id, right_key) == 0) {;
963  cmp = CMP_MATCH | CMP_STOP;
964  }
965  break;
967  if (strncmp(left_wrapper->contact_id, right_key, strlen(right_key)) == 0) {
968  cmp = CMP_MATCH;
969  }
970  break;
971  default:
972  cmp = 0;
973  break;
974  }
975 
976  return cmp;
977 }
978 
979 static int cli_contact_iterate(void *container, ao2_callback_fn callback, void *args)
980 {
981  return ast_sip_for_each_contact(container, callback, args);
982 }
983 
984 static int cli_filter_contacts(void *obj, void *arg, int flags)
985 {
986  struct ast_sip_contact_wrapper *wrapper = obj;
987  regex_t *regexbuf = arg;
988 
989  if (!regexec(regexbuf, wrapper->contact_id, 0, NULL, 0)) {
990  return 0;
991  }
992 
993  return CMP_MATCH;
994 }
995 
996 static int cli_gather_contact(void *obj, void *arg, int flags)
997 {
998  struct ast_sip_contact *contact = obj;
999  RAII_VAR(struct ast_sip_contact_wrapper *, wrapper, NULL, ao2_cleanup);
1000 
1001  if (strcmp(contact->reg_server, ast_config_AST_SYSTEM_NAME ?: "")) {
1002  return 0;
1003  }
1004 
1005  wrapper = ao2_alloc_options(sizeof(struct ast_sip_contact_wrapper),
1006  contact_wrapper_destroy, AO2_ALLOC_OPT_LOCK_NOLOCK);
1007  if (!wrapper) {
1008  return -1;
1009  }
1010 
1011  wrapper->contact_id = ast_malloc(strlen(contact->aor) + strlen(contact->uri) + 2);
1012  if (!wrapper->contact_id) {
1013  return -1;
1014  }
1015  sprintf(wrapper->contact_id, "%s/%s", contact->aor, contact->uri);
1016 
1017  wrapper->aor_id = ast_strdup(contact->aor);
1018  if (!wrapper->aor_id) {
1019  return -1;
1020  }
1021 
1022  wrapper->contact = ao2_bump(contact);
1023 
1024  ao2_link(arg, wrapper);
1025 
1026  return 0;
1027 }
1028 
1029 static struct ao2_container *cli_contact_get_container(const char *regex)
1030 {
1031  RAII_VAR(struct ao2_container *, aors, NULL, ao2_cleanup);
1032  RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
1033  RAII_VAR(struct ast_variable *, var_aor, NULL, ast_variables_destroy);
1034  struct ao2_container *contacts_container;
1035  regex_t regexbuf;
1036 
1037  if (!(var_aor = ast_variable_new("contact !=", "", ""))) {
1038  return NULL;
1039  }
1040 
1041  /* Retrieving all the contacts may result in finding the same contact multiple
1042  * times. So that they don't get displayed multiple times we only allow a
1043  * single one to be placed into the container.
1044  */
1046  cli_contact_sort, cli_contact_compare);
1047  if (!contacts_container) {
1048  return NULL;
1049  }
1050 
1051  contacts = ast_sorcery_retrieve_by_regex(ast_sip_get_sorcery(), "contact", regex);
1052  if (!contacts) {
1053  ao2_ref(contacts_container, -1);
1054  return NULL;
1055  }
1056  ao2_callback(contacts, OBJ_NODATA, cli_gather_contact, contacts_container);
1057 
1058  aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
1059  "aor", AST_RETRIEVE_FLAG_MULTIPLE, var_aor);
1060  if (!aors) {
1061  ao2_ref(contacts_container, -1);
1062  return NULL;
1063  }
1064 
1065  ao2_callback(aors, OBJ_NODATA, cli_aor_gather_contacts, contacts_container);
1066 
1067  if (!ast_strlen_zero(regex)) {
1068  if (regcomp(&regexbuf, regex, REG_EXTENDED | REG_NOSUB)) {
1069  ao2_ref(contacts_container, -1);
1070  return NULL;
1071  }
1072  ao2_callback(contacts_container, OBJ_UNLINK | OBJ_MULTIPLE | OBJ_NODATA, cli_filter_contacts, &regexbuf);
1073  regfree(&regexbuf);
1074  }
1075 
1076  return contacts_container;
1077 }
1078 
1079 static void *cli_contact_retrieve_by_id(const char *id)
1080 {
1081  struct ao2_container *container;
1082  void *obj;
1083 
1084  container = cli_contact_get_container("");
1085  if (!container) {
1086  return NULL;
1087  }
1088 
1089  obj = ao2_find(container, id, OBJ_SEARCH_KEY);
1090  ao2_ref(container, -1);
1091  return obj;
1092 }
1093 
1094 static int cli_contact_print_header(void *obj, void *arg, int flags)
1095 {
1096  struct ast_sip_cli_context *context = arg;
1097  int indent = CLI_INDENT_TO_SPACES(context->indent_level);
1098  int filler = CLI_LAST_TABSTOP - indent - 23;
1099 
1100  ast_assert(context->output_buffer != NULL);
1101 
1102  ast_str_append(&context->output_buffer, 0,
1103  "%*s: <Aor/ContactUri%*.*s> <Hash....> <Status> <RTT(ms)..>\n",
1104  indent, "Contact", filler, filler, CLI_HEADER_FILLER);
1105 
1106  return 0;
1107 }
1108 
1109 static int cli_contact_print_body(void *obj, void *arg, int flags)
1110 {
1111  struct ast_sip_contact_wrapper *wrapper = obj;
1112  struct ast_sip_contact *contact = wrapper->contact;
1113  struct ast_sip_cli_context *context = arg;
1114  int indent;
1115  int flexwidth;
1116  const char *contact_id = ast_sorcery_object_get_id(contact);
1117  const char *hash_start = contact_id + strlen(contact->aor) + 2;
1119 
1120  ast_assert(contact->uri != NULL);
1121  ast_assert(context->output_buffer != NULL);
1122 
1123  status = ast_sip_get_contact_status(contact);
1124 
1125  indent = CLI_INDENT_TO_SPACES(context->indent_level);
1126  flexwidth = CLI_LAST_TABSTOP - indent - 9 - strlen(contact->aor) + 1;
1127 
1128  ast_str_append(&context->output_buffer, 0, "%*s: %s/%-*.*s %-10.10s %-7.7s %11.3f\n",
1129  indent,
1130  "Contact",
1131  contact->aor,
1132  flexwidth, flexwidth,
1133  contact->uri,
1134  hash_start,
1135  ast_sip_get_contact_short_status_label(status ? status->status : UNKNOWN),
1136  (status && (status->status == AVAILABLE)) ? ((long long) status->rtt) / 1000.0 : NAN);
1137 
1138  ao2_cleanup(status);
1139  return 0;
1140 }
1141 
1142 static int cli_aor_iterate(void *container, ao2_callback_fn callback, void *args)
1143 {
1144  const char *aor_list = container;
1145 
1146  return ast_sip_for_each_aor(aor_list, callback, args);
1147 }
1148 
1149 static void *cli_aor_retrieve_by_id(const char *id)
1150 {
1151  return ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "aor", id);
1152 }
1153 
1154 static const char *cli_aor_get_id(const void *obj)
1155 {
1156  return ast_sorcery_object_get_id(obj);
1157 }
1158 
1159 static int cli_aor_print_header(void *obj, void *arg, int flags)
1160 {
1161  struct ast_sip_cli_context *context = arg;
1162  int indent = CLI_INDENT_TO_SPACES(context->indent_level);
1163  int filler = CLI_LAST_TABSTOP - indent - 7;
1164 
1165  ast_assert(context->output_buffer != NULL);
1166 
1167  ast_str_append(&context->output_buffer, 0,
1168  "%*s: <Aor%*.*s> <MaxContact>\n",
1169  indent, "Aor", filler, filler, CLI_HEADER_FILLER);
1170 
1171  if (context->recurse) {
1172  struct ast_sip_cli_formatter_entry *formatter_entry;
1173 
1174  context->indent_level++;
1175  formatter_entry = ast_sip_lookup_cli_formatter("contact");
1176  if (formatter_entry) {
1177  formatter_entry->print_header(NULL, context, 0);
1178  ao2_ref(formatter_entry, -1);
1179  }
1180  context->indent_level--;
1181  }
1182 
1183  return 0;
1184 }
1185 
1186 static int cli_aor_print_body(void *obj, void *arg, int flags)
1187 {
1188  struct ast_sip_aor *aor = obj;
1189  struct ast_sip_cli_context *context = arg;
1190  int indent;
1191  int flexwidth;
1192 
1193  ast_assert(context->output_buffer != NULL);
1194 
1195 // context->current_aor = aor;
1196 
1197  indent = CLI_INDENT_TO_SPACES(context->indent_level);
1198  flexwidth = CLI_LAST_TABSTOP - indent - 12;
1199 
1200  ast_str_append(&context->output_buffer, 0, "%*s: %-*.*s %12u\n",
1201  indent,
1202  "Aor",
1203  flexwidth, flexwidth,
1205 
1206  if (context->recurse) {
1207  struct ast_sip_cli_formatter_entry *formatter_entry;
1208 
1209  context->indent_level++;
1210 
1211  formatter_entry = ast_sip_lookup_cli_formatter("contact");
1212  if (formatter_entry) {
1213  formatter_entry->iterate(aor, formatter_entry->print_body, context);
1214  ao2_ref(formatter_entry, -1);
1215  }
1216 
1217  context->indent_level--;
1218 
1219  if (context->indent_level == 0) {
1220  ast_str_append(&context->output_buffer, 0, "\n");
1221  }
1222  }
1223 
1224  if (context->show_details || (context->show_details_only_level_0 && context->indent_level == 0)) {
1225  ast_str_append(&context->output_buffer, 0, "\n");
1226  ast_sip_cli_print_sorcery_objectset(aor, context, 0);
1227  }
1228 
1229  return 0;
1230 }
1231 
1232 static struct ao2_container *cli_get_aors(void)
1233 {
1234  struct ao2_container *aors;
1235 
1236  aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "aor",
1238 
1239  return aors;
1240 }
1241 
1242 static int format_ami_aorlist_handler(void *obj, void *arg, int flags)
1243 {
1244  struct ast_sip_aor *aor = obj;
1245  struct ast_sip_ami *ami = arg;
1246  struct ast_str *buf;
1247 
1248  buf = ast_sip_create_ami_event("AorList", ami);
1249  if (!buf) {
1250  return -1;
1251  }
1252 
1253  sip_aor_to_ami(aor, &buf);
1254 
1255  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1256  ami->count++;
1257 
1258  ast_free(buf);
1259 
1260  return 0;
1261 }
1262 
1263 static int ami_show_aors(struct mansession *s, const struct message *m)
1264 {
1265  struct ast_sip_ami ami = { .s = s, .m = m, .action_id = astman_get_header(m, "ActionID"), };
1266  struct ao2_container *aors;
1267 
1268  aors = cli_get_aors();
1269  if (!aors) {
1270  astman_send_error(s, m, "Could not get AORs\n");
1271  return 0;
1272  }
1273 
1274  if (!ao2_container_count(aors)) {
1275  astman_send_error(s, m, "No AORs found\n");
1276  ao2_ref(aors, -1);
1277  return 0;
1278  }
1279 
1280  astman_send_listack(s, m, "A listing of AORs follows, presented as AorList events",
1281  "start");
1282 
1283  ao2_callback(aors, OBJ_NODATA, format_ami_aorlist_handler, &ami);
1284 
1285  astman_send_list_complete_start(s, m, "AorListComplete", ami.count);
1287 
1288  ao2_ref(aors, -1);
1289 
1290  return 0;
1291 }
1292 
1293 static struct ast_cli_entry cli_commands[] = {
1294  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Aors",
1295  .command = "pjsip list aors",
1296  .usage = "Usage: pjsip list aors [ like <pattern> ]\n"
1297  " List the configured PJSIP Aors\n"
1298  " Optional regular expression pattern is used to filter the list.\n"),
1299  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aors",
1300  .command = "pjsip show aors",
1301  .usage = "Usage: pjsip show aors [ like <pattern> ]\n"
1302  " Show the configured PJSIP Aors\n"
1303  " Optional regular expression pattern is used to filter the list.\n"),
1304  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Aor",
1305  .command = "pjsip show aor",
1306  .usage = "Usage: pjsip show aor <id>\n"
1307  " Show the configured PJSIP Aor\n"),
1308 
1309  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "List PJSIP Contacts",
1310  .command = "pjsip list contacts",
1311  .usage = "Usage: pjsip list contacts [ like <pattern> ]\n"
1312  " List the configured PJSIP contacts\n"
1313  " Optional regular expression pattern is used to filter the list.\n"),
1314  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contacts",
1315  .command = "pjsip show contacts",
1316  .usage = "Usage: pjsip show contacts [ like <pattern> ]\n"
1317  " Show the configured PJSIP contacts\n"
1318  " Optional regular expression pattern is used to filter the list.\n"),
1319  AST_CLI_DEFINE(ast_sip_cli_traverse_objects, "Show PJSIP Contact",
1320  .command = "pjsip show contact",
1321  .usage = "Usage: pjsip show contact\n"
1322  " Show the configured PJSIP contact\n"),
1323 };
1324 
1325 struct ast_sip_cli_formatter_entry *contact_formatter;
1326 struct ast_sip_cli_formatter_entry *aor_formatter;
1327 
1328 /*! \brief Always create a contact_status for each contact */
1329 static int contact_apply_handler(const struct ast_sorcery *sorcery, void *object)
1330 {
1332  struct ast_sip_contact *contact = object;
1333 
1334  if (ast_strlen_zero(contact->uri)) {
1335  ast_log(LOG_ERROR, "A URI on dynamic contact '%s' is empty\n",
1336  ast_sorcery_object_get_id(contact));
1337  return -1;
1338  }
1339  status = ast_res_pjsip_find_or_create_contact_status(contact);
1340  ao2_cleanup(status);
1341 
1342  return status ? 0 : -1;
1343 }
1344 
1345 static int aor_apply_outbound_proxy(void *obj, void *arg, int flags)
1346 {
1347  struct ast_sip_contact *contact = obj;
1348  struct ast_sip_aor *aor = arg;
1349 
1351 
1352  return 0;
1353 }
1354 
1355 static int aor_apply_handler(const struct ast_sorcery *sorcery, void *object)
1356 {
1357  struct ast_sip_aor *aor = object;
1358 
1359  if (!aor->permanent_contacts || ast_strlen_zero(aor->outbound_proxy)) {
1360  return 0;
1361  }
1362 
1363  ao2_callback(aor->permanent_contacts, OBJ_NODATA | OBJ_MULTIPLE, aor_apply_outbound_proxy, aor);
1364 
1365  return 0;
1366 }
1367 
1368 /*! \brief Initialize sorcery with location support */
1369 int ast_sip_initialize_sorcery_location(void)
1370 {
1371  struct ast_sorcery *sorcery = ast_sip_get_sorcery();
1372  int i;
1373 
1374  ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
1375  /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
1376  ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
1377 
1378  ast_sorcery_apply_default(sorcery, "contact", "astdb", "registrar");
1379  ast_sorcery_object_set_congestion_levels(sorcery, "contact", -1,
1381  ast_sorcery_apply_default(sorcery, "aor", "config", "pjsip.conf,criteria=type=aor");
1382 
1383  if (ast_sorcery_object_register(sorcery, "contact", contact_alloc, NULL, contact_apply_handler) ||
1384  ast_sorcery_object_register(sorcery, "aor", aor_alloc, NULL, aor_apply_handler)) {
1385  return -1;
1386  }
1387 
1388  ast_sorcery_observer_add(sorcery, "aor", &aor_observer);
1389 
1390  ast_sorcery_object_field_register(sorcery, "contact", "type", "", OPT_NOOP_T, 0, 0);
1391  ast_sorcery_object_field_register(sorcery, "contact", "uri", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, uri));
1392  ast_sorcery_object_field_register(sorcery, "contact", "path", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, path));
1393  ast_sorcery_object_field_register_custom(sorcery, "contact", "expiration_time", "", expiration_str2struct, expiration_struct2str, NULL, 0, 0);
1394  ast_sorcery_object_field_register(sorcery, "contact", "qualify_frequency", 0, OPT_UINT_T,
1395  PARSE_IN_RANGE, FLDSET(struct ast_sip_contact, qualify_frequency), 0, 86400);
1396  ast_sorcery_object_field_register(sorcery, "contact", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_contact, qualify_timeout));
1397  ast_sorcery_object_field_register(sorcery, "contact", "authenticate_qualify", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, authenticate_qualify));
1398  ast_sorcery_object_field_register(sorcery, "contact", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, outbound_proxy));
1399  ast_sorcery_object_field_register(sorcery, "contact", "user_agent", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, user_agent));
1400  ast_sorcery_object_field_register(sorcery, "contact", "endpoint", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, endpoint_name));
1401  ast_sorcery_object_field_register(sorcery, "contact", "reg_server", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, reg_server));
1402  ast_sorcery_object_field_register(sorcery, "contact", "via_addr", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, via_addr));
1403  ast_sorcery_object_field_register(sorcery, "contact", "via_port", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_contact, via_port));
1404  ast_sorcery_object_field_register(sorcery, "contact", "call_id", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_contact, call_id));
1405  ast_sorcery_object_field_register(sorcery, "contact", "prune_on_boot", "no", OPT_YESNO_T, 1, FLDSET(struct ast_sip_contact, prune_on_boot));
1406 
1407  ast_sorcery_object_field_register(sorcery, "aor", "type", "", OPT_NOOP_T, 0, 0);
1408  ast_sorcery_object_field_register(sorcery, "aor", "minimum_expiration", "60", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, minimum_expiration));
1409  ast_sorcery_object_field_register(sorcery, "aor", "maximum_expiration", "7200", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, maximum_expiration));
1410  ast_sorcery_object_field_register(sorcery, "aor", "default_expiration", "3600", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, default_expiration));
1411  ast_sorcery_object_field_register(sorcery, "aor", "qualify_frequency", 0, OPT_UINT_T, PARSE_IN_RANGE, FLDSET(struct ast_sip_aor, qualify_frequency), 0, 86400);
1412  ast_sorcery_object_field_register(sorcery, "aor", "qualify_timeout", "3.0", OPT_DOUBLE_T, 0, FLDSET(struct ast_sip_aor, qualify_timeout));
1413  ast_sorcery_object_field_register(sorcery, "aor", "authenticate_qualify", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, authenticate_qualify));
1414  ast_sorcery_object_field_register(sorcery, "aor", "max_contacts", "0", OPT_UINT_T, 0, FLDSET(struct ast_sip_aor, max_contacts));
1415  ast_sorcery_object_field_register(sorcery, "aor", "remove_existing", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_existing));
1416  ast_sorcery_object_field_register(sorcery, "aor", "remove_unavailable", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, remove_unavailable));
1417  ast_sorcery_object_field_register_custom(sorcery, "aor", "contact", "", permanent_uri_handler, contacts_to_str, contacts_to_var_list, 0, 0);
1418  ast_sorcery_object_field_register(sorcery, "aor", "mailboxes", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, mailboxes));
1419  ast_sorcery_object_field_register_custom(sorcery, "aor", "voicemail_extension", "", voicemail_extension_handler, voicemail_extension_to_str, NULL, 0, 0);
1420  ast_sorcery_object_field_register(sorcery, "aor", "outbound_proxy", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_aor, outbound_proxy));
1421  ast_sorcery_object_field_register(sorcery, "aor", "support_path", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_aor, support_path));
1422 
1423  ast_sip_register_endpoint_formatter(&endpoint_aor_formatter);
1424 
1425  contact_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1426  if (!contact_formatter) {
1427  ast_log(LOG_ERROR, "Unable to allocate memory for contact_formatter\n");
1428  return -1;
1429  }
1430  contact_formatter->name = "contact";
1431  contact_formatter->print_header = cli_contact_print_header;
1432  contact_formatter->print_body = cli_contact_print_body;
1433  contact_formatter->get_container = cli_contact_get_container;
1434  contact_formatter->iterate = cli_contact_iterate;
1435  contact_formatter->get_id = cli_contact_get_id;
1436  contact_formatter->retrieve_by_id = cli_contact_retrieve_by_id;
1437 
1438  aor_formatter = ao2_alloc(sizeof(struct ast_sip_cli_formatter_entry), NULL);
1439  if (!aor_formatter) {
1440  ast_log(LOG_ERROR, "Unable to allocate memory for aor_formatter\n");
1441  return -1;
1442  }
1443  aor_formatter->name = "aor";
1444  aor_formatter->print_header = cli_aor_print_header;
1445  aor_formatter->print_body = cli_aor_print_body;
1446  aor_formatter->get_container = cli_aor_get_container;
1447  aor_formatter->iterate = cli_aor_iterate;
1448  aor_formatter->get_id = cli_aor_get_id;
1449  aor_formatter->retrieve_by_id = cli_aor_retrieve_by_id;
1450 
1451  ast_sip_register_cli_formatter(contact_formatter);
1452  ast_sip_register_cli_formatter(aor_formatter);
1453  ast_cli_register_multiple(cli_commands, ARRAY_LEN(cli_commands));
1454 
1455  if (ast_manager_register_xml("PJSIPShowAors", EVENT_FLAG_SYSTEM, ami_show_aors)) {
1456  return -1;
1457  }
1458 
1459  /*
1460  * Reset StatsD gauges in case we didn't shut down cleanly.
1461  * Note that this must done here, as contacts will create the contact_status
1462  * object before PJSIP options handling is initialized.
1463  */
1464  for (i = 0; i <= REMOVED; i++) {
1465  ast_statsd_log_full_va("PJSIP.contacts.states.%s", AST_STATSD_GAUGE, 0, 1.0, ast_sip_get_contact_status_label(i));
1466  }
1467 
1468  return 0;
1469 }
1470 
1471 int ast_sip_destroy_sorcery_location(void)
1472 {
1473  ast_sorcery_observer_remove(ast_sip_get_sorcery(), "aor", &aor_observer);
1474  ast_cli_unregister_multiple(cli_commands, ARRAY_LEN(cli_commands));
1475  ast_sip_unregister_cli_formatter(contact_formatter);
1476  ast_sip_unregister_cli_formatter(aor_formatter);
1477  ast_manager_unregister("PJSIPShowAors");
1478 
1479  ast_sip_unregister_endpoint_formatter(&endpoint_aor_formatter);
1480 
1481  return 0;
1482 }
double qualify_timeout
Definition: res_pjsip.h:504
struct ast_str * output_buffer
Definition: res_pjsip_cli.h:36
struct ast_variable * next
struct ao2_container *(* get_container)(const char *regex)
Definition: res_pjsip_cli.h:64
int authenticate_qualify
Definition: res_pjsip.h:420
A contact's status.
Definition: res_pjsip.h:451
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
Asterisk main include file. File version handling, generic pbx functions.
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.
An entity responsible formatting endpoint information.
Definition: res_pjsip.h:3057
CLI Formatter Registry Entry.
Definition: res_pjsip_cli.h:52
void(* deleted)(const void *object)
Callback for when an object is deleted.
Definition: sorcery.h:340
const ast_string_field outbound_proxy
Definition: res_pjsip.h:414
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
const ast_string_field call_id
Definition: res_pjsip.h:414
const ast_string_field user_agent
Definition: res_pjsip.h:414
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
const ast_string_field path
Definition: res_pjsip.h:414
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch. Returns -1 on failure, zero otherwise.
Definition: time.c:152
const struct message * m
Definition: res_pjsip.h:3035
unsigned int max_contacts
Definition: res_pjsip.h:496
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
descriptor for a cli entry.
Definition: cli.h:171
const ast_string_field via_addr
Definition: res_pjsip.h:414
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
Definition: taskprocessor.h:64
#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
static struct stasis_rest_handlers mailboxes
REST handler for /api-docs/mailboxes.json.
void * arg
Definition: res_pjsip.h:3039
AMI variable container.
Definition: res_pjsip.h:3031
#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.
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
void * ast_sorcery_lockable_alloc(size_t size, ao2_destructor_fn destructor, void *lockobj)
Allocate a generic sorcery capable object with locking.
Definition: sorcery.c:1712
Full structure for sorcery.
Definition: sorcery.c:230
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 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
unsigned int qualify_frequency
Definition: res_pjsip.h:418
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
Return all matching objects.
Definition: sorcery.h:120
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:107
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
struct ao2_container * ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
Retrieve multiple objects whose id begins with the specified prefix.
Definition: sorcery.c:1989
const ast_string_field outbound_proxy
Definition: res_pjsip.h:484
const ast_string_field reg_server
Definition: res_pjsip.h:414
CLI Formatter Context passed to all formatters.
Definition: res_pjsip_cli.h:34
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
Definition: utils.c:2419
#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
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
char * voicemail_extension
Definition: res_pjsip.h:506
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
int ast_sorcery_object_set_congestion_levels(struct ast_sorcery *sorcery, const char *type, long low_water, long high_water)
Set the high and low alert water marks of the sorcery object type.
Definition: sorcery.c:1114
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_sip_endpoint * endpoint
Definition: res_pjsip.h:424
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
Type for default option handler for bools (ast_true/ast_false)
unsigned int qualify_frequency
Definition: res_pjsip.h:492
char * ast_strip_quoted(char *s, const char *beg_quotes, const char *end_quotes)
Strip leading/trailing whitespace and quotes from a string.
Definition: utils.c:1818
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2062
#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
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
const ast_string_field endpoint_name
Definition: res_pjsip.h:414
ast_mutex_t lock
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition: res_pjsip.h:515
Asterisk file paths, configured in asterisk.conf.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3475
Type for default option handler for unsigned integers.
#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
#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
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
void *(* retrieve_by_id)(const char *id)
Definition: res_pjsip_cli.h:68
struct mansession * s
Definition: res_pjsip.h:3033
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
struct ao2_container * container
Definition: res_fax.c:501
double qualify_timeout
Definition: res_pjsip.h:422
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:949
unsigned int support_path
Definition: res_pjsip.h:502
Named Locks.
#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
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_contact_status_type status
Definition: res_pjsip.h:468
struct ast_sip_contact * contact
Definition: res_pjsip.h:521
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8057
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
Support for dynamic strings.
Definition: strings.h:623
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.
Interface for a sorcery object type observer.
Definition: sorcery.h:332
Type for default option handler for bools (ast_true/ast_false)
Contact associated with an address of record.
Definition: res_pjsip.h:392
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
struct timeval expiration_time
Definition: res_pjsip.h:416
char * command
Definition: cli.h:186
Type for default option handler for doubles.
int(* format_ami)(const struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami)
Callback used to format endpoint information over AMI.
Definition: res_pjsip.h:3061
struct ao2_container * permanent_contacts
Definition: res_pjsip.h:500
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Support for logging to various files, console and syslog Configuration in file logger.conf.
An API for managing task processing threads that can be shared across modules.
const char *(* get_id)(const void *obj)
Definition: res_pjsip_cli.h:70
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
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
const ast_string_field aor
Definition: res_pjsip.h:414
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2423
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:80
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
int authenticate_qualify
Definition: res_pjsip.h:494
Type for default option handler for stringfields.
ao2_callback_fn * print_header
Definition: res_pjsip_cli.h:60
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
Generic container type.
Search option field mask.
Definition: astobj2.h:1072
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
const ast_string_field aors
Definition: res_pjsip.h:958
#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_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: utils.c:250
const ast_string_field uri
Definition: res_pjsip.h:414
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
#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
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ast_named_lock_get(lock_type, keyspace, key)
Geta named lock handle.
Definition: named_locks.h:83
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:659
Sorcery Data Access Layer API.
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2150
#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
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532