Asterisk - The Open Source Telephony Project  21.4.1
geoloc_config.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2022, Sangoma Technologies Corporation
5  *
6  * George Joseph <gjoseph@sangoma.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 "asterisk/module.h"
21 #include "asterisk/cli.h"
22 #define AST_API_MODULE
23 #include "geoloc_private.h"
24 
25 static struct ast_sorcery *geoloc_sorcery;
26 
27 static const char *pidf_element_names[] = {
28  "<none>",
29  "device",
30  "tuple",
31  "person"
32 };
33 
34 static const char *format_names[] = {
35  "<none>",
36  "civicAddress",
37  "GML",
38  "URI",
39 };
40 
41 static const char * precedence_names[] = {
42  "prefer_incoming",
43  "prefer_config",
44  "discard_incoming",
45  "discard_config",
46 };
47 
48 CONFIG_ENUM(location, format)
49 CONFIG_VAR_LIST(location, location_info)
50 CONFIG_VAR_LIST(location, confidence)
51 
52 static void geoloc_location_destructor(void *obj) {
53  struct ast_geoloc_location *location = obj;
54 
56  ast_variables_destroy(location->location_info);
57  ast_variables_destroy(location->confidence);
58 }
59 
60 static void *geoloc_location_alloc(const char *name)
61 {
62  struct ast_geoloc_location *location = ast_sorcery_generic_alloc(sizeof(struct ast_geoloc_location), geoloc_location_destructor);
63  if (location) {
64  ast_string_field_init(location, 128);
65  }
66 
67  return location;
68 }
69 
70 CONFIG_ENUM(profile, pidf_element)
71 CONFIG_ENUM(profile, precedence)
72 CONFIG_VAR_LIST(profile, location_refinement)
73 CONFIG_VAR_LIST(profile, location_variables)
74 CONFIG_VAR_LIST(profile, usage_rules)
75 
76 CONFIG_ENUM_HANDLER(profile, format)
77 CONFIG_ENUM_TO_STR(profile, format)
78 CONFIG_VAR_LIST(profile, location_info)
79 CONFIG_VAR_LIST(profile, confidence)
80 
81 static void geoloc_profile_destructor(void *obj) {
82  struct ast_geoloc_profile *profile = obj;
83 
85  ast_variables_destroy(profile->location_refinement);
86  ast_variables_destroy(profile->location_variables);
87  ast_variables_destroy(profile->usage_rules);
88  ast_variables_destroy(profile->location_info);
89  ast_variables_destroy(profile->confidence);
90 }
91 
92 static void *geoloc_profile_alloc(const char *name)
93 {
94  struct ast_geoloc_profile *profile = ast_sorcery_generic_alloc(sizeof(*profile),
95  geoloc_profile_destructor);
96  if (profile) {
97  ast_string_field_init(profile, 128);
98  }
99 
100  return profile;
101 }
102 
103 static enum ast_geoloc_validate_result validate_location_info(const char *id,
104  enum ast_geoloc_format format, struct ast_variable *location_info)
105 {
106  enum ast_geoloc_validate_result result;
107  const char *failed;
108  const char *uri;
109 
110  switch (format) {
111  case AST_GEOLOC_FORMAT_NONE:
112  case AST_GEOLOC_FORMAT_LAST:
113  ast_log(LOG_ERROR, "Location '%s' must have a format\n", id);
114  return -1;
115  case AST_GEOLOC_FORMAT_CIVIC_ADDRESS:
116  result = ast_geoloc_civicaddr_validate_varlist(location_info, &failed);
117  if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
118  ast_log(LOG_ERROR, "Location '%s' has invalid item '%s' in the location\n",
119  id, failed);
120  return result;
121  }
122  break;
123  case AST_GEOLOC_FORMAT_GML:
124  result = ast_geoloc_gml_validate_varlist(location_info, &failed);
125  if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
126  ast_log(LOG_ERROR, "%s for item '%s' in location '%s'\n",
127  ast_geoloc_validate_result_to_str(result), failed, id);
128  return result;
129  }
130 
131  break;
132  case AST_GEOLOC_FORMAT_URI:
133  uri = ast_variable_find_in_list(location_info, "URI");
134  if (!uri) {
135  struct ast_str *str = ast_variable_list_join(location_info, ",", "=", "\"", NULL);
136 
137  ast_log(LOG_ERROR, "Geolocation location '%s' format is set to '%s' but no 'URI' was found in location parameter '%s'\n",
138  id, format_names[AST_GEOLOC_FORMAT_URI], ast_str_buffer(str));
139  ast_free(str);
140  return AST_GEOLOC_VALIDATE_NOT_ENOUGH_VARNAMES;
141  }
142  break;
143  }
144 
145  return AST_GEOLOC_VALIDATE_SUCCESS;
146 }
147 
148 static int validate_location_source(const char *id, const char *location_source)
149 {
150  if (!ast_strlen_zero(location_source)) {
151  struct ast_sockaddr loc_source_addr;
152  int rc = ast_sockaddr_parse(&loc_source_addr, location_source, PARSE_PORT_FORBID);
153  if (rc == 1) {
154  ast_log(LOG_ERROR, "Geolocation location '%s' location_source '%s' must be a FQDN."
155  " RFC8787 expressly forbids IP addresses.\n",
156  id, location_source);
157  return -1;
158  }
159  }
160 
161  return 0;
162 }
163 
164 static int geoloc_location_apply_handler(const struct ast_sorcery *sorcery, void *obj)
165 {
166  struct ast_geoloc_location *location = obj;
167  const char *location_id = ast_sorcery_object_get_id(location);
168  enum ast_geoloc_validate_result result;
169  int rc = 0;
170 
171  if (!location->location_info) {
172  ast_log(LOG_ERROR, "Location '%s' is missing required element 'location_info'",
173  location_id);
174  return -1;
175  }
176 
177  result = validate_location_info(location_id, location->format, location->location_info);
178  if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
179  return -1;
180  }
181 
182  rc = validate_location_source(location_id, location->location_source);
183  if (rc != 0) {
184  return -1;
185  }
186 
187  return 0;
188 }
189 
190 static int geoloc_profile_apply_handler(const struct ast_sorcery *sorcery, void *obj)
191 {
192  struct ast_geoloc_profile *profile = obj;
193  struct ast_geoloc_location *location;
194  const char *id = ast_sorcery_object_get_id(profile);
195  enum ast_geoloc_validate_result result;
196  enum ast_geoloc_format format = AST_GEOLOC_FORMAT_NONE;
197  int rc = 0;
198 
199  if (!ast_strlen_zero(profile->location_reference)) {
200  if (profile->location_info ||
201  profile->format != AST_GEOLOC_FORMAT_NONE) {
202  ast_log(LOG_ERROR, "Profile '%s' can't have location_reference and location_info or format at the same time",
203  id);
204  return -1;
205  }
206  return 0;
207  }
208 
209  if (profile->location_info) {
210  result = validate_location_info(id, profile->format, profile->location_info);
211  if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
212  return -1;
213  }
214 
215  rc = validate_location_source(id, profile->location_source);
216  if (rc != 0) {
217  return -1;
218  }
219 
220  return 0;
221  }
222 
223  if (!ast_strlen_zero(profile->location_reference)) {
224  location = ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", profile->location_reference);
225  if (!location) {
226  ast_log(LOG_ERROR, "Profile '%s' has a location_reference '%s' that doesn't exist",
227  id, profile->location_reference);
228  return -1;
229  }
230  format = location->format;
231  ao2_ref(location, -1);
232  }
233 
234  if (profile->location_refinement) {
235  result = validate_location_info(id, format, profile->location_refinement);
236  if (result != AST_GEOLOC_VALIDATE_SUCCESS) {
237  return -1;
238  }
239  }
240 
241  return 0;
242 }
243 
244 struct ast_sorcery *geoloc_get_sorcery(void)
245 {
246  ast_sorcery_ref(geoloc_sorcery);
247  return geoloc_sorcery;
248 }
249 
250 static char *geoloc_config_list_locations(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
251 {
252  struct ao2_iterator iter;
253  struct ao2_container *sorted_container;
254  struct ao2_container *unsorted_container;
255  struct ast_geoloc_location *loc;
256  int using_regex = 0;
257  char *result = CLI_SUCCESS;
258  int ret = 0;
259  int count = 0;
260 
261  switch (cmd) {
262  case CLI_INIT:
263  e->command = "geoloc list locations";
264  e->usage = "Usage: geoloc list locations [ like <pattern> ]\n"
265  " List Geolocation Location Objects\n";
266  return NULL;
267  case CLI_GENERATE:
268  return NULL;
269  }
270 
271  if (a->argc != 3 && a->argc != 5) {
272  return CLI_SHOWUSAGE;
273  }
274 
275  if (a->argc == 5) {
276  if (strcasecmp(a->argv[3], "like")) {
277  return CLI_SHOWUSAGE;
278  }
279  using_regex = 1;
280  }
281 
284  if (!sorted_container) {
285  ast_cli(a->fd, "Geolocation Location Objects: Unable to allocate temporary container\n");
286  return CLI_FAILURE;
287  }
288 
289  /* Get a sorted snapshot of the scheduled tasks */
290  if (using_regex) {
291  unsorted_container = ast_sorcery_retrieve_by_regex(geoloc_sorcery, "location", a->argv[4]);
292  } else {
293  unsorted_container = ast_sorcery_retrieve_by_fields(geoloc_sorcery, "location",
295  }
296 
297  ret = ao2_container_dup(sorted_container, unsorted_container, 0);
298  ao2_ref(unsorted_container, -1);
299  if (ret != 0) {
300  ao2_ref(sorted_container, -1);
301  ast_cli(a->fd, "Geolocation Location Objects: Unable to sort temporary container\n");
302  return CLI_FAILURE;
303  }
304 
305  ast_cli(a->fd, "Geolocation Location Objects:\n\n");
306 
307  ast_cli(a->fd,
308  "<Object ID...................................> <Format.....> <Details.............>\n"
309  "===================================================================================\n");
310 
311  iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);
312  for (; (loc = ao2_iterator_next(&iter)); ao2_ref(loc, -1)) {
313  struct ast_str *str;
314 
315  ao2_lock(loc);
316  str = ast_variable_list_join(loc->location_info, ",", "=", "\"", NULL);
317  if (!str) {
318  ao2_unlock(loc);
319  ao2_ref(loc, -1);
320  ast_cli(a->fd, "Geolocation Location Objects: Unable to allocate temp string for '%s'\n",
322  result = CLI_FAILURE;
323  break;
324  }
325 
326  ast_cli(a->fd, "%-46.46s %-13s %-s\n",
328  format_names[loc->format],
329  ast_str_buffer(str));
330  ao2_unlock(loc);
331  ast_free(str);
332  count++;
333  }
334  ao2_iterator_destroy(&iter);
335  ao2_ref(sorted_container, -1);
336  ast_cli(a->fd, "\nTotal Location Objects: %d\n\n", count);
337 
338  return result;
339 }
340 
341 static char *geoloc_config_list_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
342 {
343  struct ao2_iterator iter;
344  struct ao2_container *sorted_container;
345  struct ao2_container *unsorted_container;
346  struct ast_geoloc_profile *profile;
347  int using_regex = 0;
348  char *result = CLI_SUCCESS;
349  int ret = 0;
350  int count = 0;
351 
352  switch (cmd) {
353  case CLI_INIT:
354  e->command = "geoloc list profiles";
355  e->usage = "Usage: geoloc list profiles [ like <pattern> ]\n"
356  " List Geolocation Profile Objects\n";
357  return NULL;
358  case CLI_GENERATE:
359  return NULL;
360  }
361 
362  if (a->argc != 3 && a->argc != 5) {
363  return CLI_SHOWUSAGE;
364  }
365 
366  if (a->argc == 5) {
367  if (strcasecmp(a->argv[3], "like")) {
368  return CLI_SHOWUSAGE;
369  }
370  using_regex = 1;
371  }
372 
375  if (!sorted_container) {
376  ast_cli(a->fd, "Geolocation Profile Objects: Unable to allocate temporary container\n");
377  return CLI_FAILURE;
378  }
379 
380  /* Get a sorted snapshot of the scheduled tasks */
381  if (using_regex) {
382  unsorted_container = ast_sorcery_retrieve_by_regex(geoloc_sorcery, "profile", a->argv[4]);
383  } else {
384  unsorted_container = ast_sorcery_retrieve_by_fields(geoloc_sorcery, "profile",
386  }
387 
388  ret = ao2_container_dup(sorted_container, unsorted_container, 0);
389  ao2_ref(unsorted_container, -1);
390  if (ret != 0) {
391  ao2_ref(sorted_container, -1);
392  ast_cli(a->fd, "Geolocation Profile Objects: Unable to sort temporary container\n");
393  return CLI_FAILURE;
394  }
395 
396  ast_cli(a->fd, "Geolocation Profile Objects:\n\n");
397 
398  ast_cli(a->fd,
399  "<Object ID...................................> <Profile Action> <Location Reference> \n"
400  "=====================================================================================\n");
401 
402  iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);
403  for (; (profile = ao2_iterator_next(&iter)); ao2_ref(profile, -1)) {
404  ao2_lock(profile);
405 
406  ast_cli(a->fd, "%-46.46s %-16s %-s\n",
407  ast_sorcery_object_get_id(profile),
408  precedence_names[profile->precedence],
409  profile->location_reference);
410  ao2_unlock(profile);
411  count++;
412  }
413  ao2_iterator_destroy(&iter);
414  ao2_ref(sorted_container, -1);
415  ast_cli(a->fd, "\nTotal Profile Objects: %d\n\n", count);
416 
417  return result;
418 }
419 
420 static char *geoloc_config_show_profiles(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
421 {
422  struct ao2_iterator iter;
423  struct ao2_container *sorted_container;
424  struct ao2_container *unsorted_container;
425  struct ast_geoloc_profile *profile;
426  int using_regex = 0;
427  char *result = CLI_SUCCESS;
428  int ret = 0;
429  int count = 0;
430 
431  switch (cmd) {
432  case CLI_INIT:
433  e->command = "geoloc show profiles";
434  e->usage = "Usage: geoloc show profiles [ like <pattern> ]\n"
435  " List Geolocation Profile Objects\n";
436  return NULL;
437  case CLI_GENERATE:
438  return NULL;
439  }
440 
441  if (a->argc != 3 && a->argc != 5) {
442  return CLI_SHOWUSAGE;
443  }
444 
445  if (a->argc == 5) {
446  if (strcasecmp(a->argv[3], "like")) {
447  return CLI_SHOWUSAGE;
448  }
449  using_regex = 1;
450  }
451 
452  /* Create an empty rb-tree container which always sorts its contents. */
455  if (!sorted_container) {
456  ast_cli(a->fd, "Geolocation Profile Objects: Unable to allocate temporary container\n");
457  return CLI_FAILURE;
458  }
459 
460  /* Get an unsorted list of profile parameters */
461  if (using_regex) {
462  unsorted_container = ast_sorcery_retrieve_by_regex(geoloc_sorcery, "profile", a->argv[4]);
463  } else {
464  unsorted_container = ast_sorcery_retrieve_by_fields(geoloc_sorcery, "profile",
466  }
467 
468  /* Copy the unsorted parameters into the rb-tree container which will sort them automatically. */
469  ret = ao2_container_dup(sorted_container, unsorted_container, 0);
470  ao2_ref(unsorted_container, -1);
471  if (ret != 0) {
472  ao2_ref(sorted_container, -1);
473  ast_cli(a->fd, "Geolocation Profile Objects: Unable to sort temporary container\n");
474  return CLI_FAILURE;
475  }
476 
477  ast_cli(a->fd, "Geolocation Profile Objects:\n");
478 
479  iter = ao2_iterator_init(sorted_container, AO2_ITERATOR_UNLINK);
480  for (; (profile = ao2_iterator_next(&iter)); ) {
481  struct ast_str *loc_str = NULL;
482  struct ast_str *refinement_str = NULL;
483  struct ast_str *variables_str = NULL;
484  struct ast_str *resolved_str = NULL;
485  struct ast_str *usage_rules_str = NULL;
486  struct ast_str *confidence_str = NULL;
487  struct ast_geoloc_eprofile *eprofile = ast_geoloc_eprofile_create_from_profile(profile);
488  ao2_ref(profile, -1);
489 
490  loc_str = ast_variable_list_join(eprofile->location_info, ",", "=", "\"", NULL);
491  resolved_str = ast_variable_list_join(eprofile->effective_location, ",", "=", "\"", NULL);
492 
493  refinement_str = ast_variable_list_join(eprofile->location_refinement, ",", "=", "\"", NULL);
494  variables_str = ast_variable_list_join(eprofile->location_variables, ",", "=", "\"", NULL);
495  usage_rules_str = ast_variable_list_join(eprofile->usage_rules, ",", "=", "\"", NULL);
496  confidence_str = ast_variable_list_join(eprofile->confidence, ",", "=", "\"", NULL);
497 
498  ast_cli(a->fd,"\n"
499  "id: %-s\n"
500  "profile_precedence: %-s\n"
501  "pidf_element: %-s\n"
502  "location_reference: %-s\n"
503  "location_format: %-s\n"
504  "location_info: %-s\n"
505  "location_method: %-s\n"
506  "location_source: %-s\n"
507  "location_confidence: %-s\n"
508  "location_refinement: %-s\n"
509  "location_variables: %-s\n"
510  "allow_routing_use: %-s\n"
511  "suppress_empty_elements: %-s\n"
512  "effective_location: %-s\n"
513  "usage_rules: %-s\n"
514  "notes: %-s\n",
515  eprofile->id,
516  precedence_names[eprofile->precedence],
517  pidf_element_names[eprofile->pidf_element],
518  S_OR(eprofile->location_reference, "<none>"),
519  format_names[eprofile->format],
520  S_COR(loc_str, ast_str_buffer(loc_str), "<none>"),
521  S_OR(eprofile->method, "<none>"),
522  S_OR(eprofile->location_source, "<none>"),
523  S_COR(confidence_str, ast_str_buffer(confidence_str), "<none>"),
524  S_COR(refinement_str, ast_str_buffer(refinement_str), "<none>"),
525  S_COR(variables_str, ast_str_buffer(variables_str), "<none>"),
526  S_COR(eprofile->allow_routing_use, "yes", "no"),
527  S_COR(eprofile->suppress_empty_ca_elements, "yes", "no"),
528  S_COR(resolved_str, ast_str_buffer(resolved_str), "<none>"),
529  S_COR(usage_rules_str, ast_str_buffer(usage_rules_str), "<none>"),
530  S_OR(eprofile->notes, "<none>")
531  );
532  ao2_ref(eprofile, -1);
533 
534  ast_free(loc_str);
535  ast_free(refinement_str);
536  ast_free(variables_str);
537  ast_free(resolved_str);
538  ast_free(usage_rules_str);
539  ast_free(confidence_str);
540  count++;
541  }
542  ao2_iterator_destroy(&iter);
543  ao2_ref(sorted_container, -1);
544  ast_cli(a->fd, "\nTotal Profile Objects: %d\n\n", count);
545 
546  return result;
547 }
548 
549 static char *geoloc_config_cli_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
550 {
551  char *result = CLI_SUCCESS;
552 
553  switch (cmd) {
554  case CLI_INIT:
555  e->command = "geoloc reload";
556  e->usage = "Usage: geoloc reload\n"
557  " Reload Geolocation Configuration\n";
558  return NULL;
559  case CLI_GENERATE:
560  return NULL;
561  }
562 
563  if (a->argc != 2) {
564  return CLI_SHOWUSAGE;
565  }
566 
567  geoloc_config_reload();
568  ast_cli(a->fd, "Geolocation Configuration reloaded.\n");
569 
570  return result;
571 }
572 
573 static struct ast_cli_entry geoloc_location_cli_commands[] = {
574  AST_CLI_DEFINE(geoloc_config_list_locations, "List Geolocation Location Objects"),
575  AST_CLI_DEFINE(geoloc_config_list_profiles, "List Geolocation Profile Objects"),
576  AST_CLI_DEFINE(geoloc_config_show_profiles, "Show Geolocation Profile Objects"),
577  AST_CLI_DEFINE(geoloc_config_cli_reload, "Reload Geolocation Configuration"),
578 };
579 
580 struct ast_geoloc_location * AST_OPTIONAL_API_NAME(ast_geoloc_get_location)(const char *id)
581 {
582  if (ast_strlen_zero(id)) {
583  return NULL;
584  }
585 
586  return ast_sorcery_retrieve_by_id(geoloc_sorcery, "location", id);
587 }
588 
589 struct ast_geoloc_profile * AST_OPTIONAL_API_NAME(ast_geoloc_get_profile)(const char *id)
590 {
591  if (ast_strlen_zero(id)) {
592  return NULL;
593  }
594 
595  return ast_sorcery_retrieve_by_id(geoloc_sorcery, "profile", id);
596 }
597 
598 int geoloc_config_reload(void)
599 {
600  if (geoloc_sorcery) {
601  ast_sorcery_reload(geoloc_sorcery);
602  }
604 }
605 
606 int geoloc_config_unload(void)
607 {
608  ast_cli_unregister_multiple(geoloc_location_cli_commands, ARRAY_LEN(geoloc_location_cli_commands));
609 
610  ast_sorcery_object_unregister(geoloc_sorcery, "profile");
611  ast_sorcery_object_unregister(geoloc_sorcery, "location");
612 
613  if (geoloc_sorcery) {
614  ast_sorcery_unref(geoloc_sorcery);
615  }
616  geoloc_sorcery = NULL;
617 
618  return 0;
619 }
620 
621 static int default_profile_create(const char *name)
622 {
623  int rc = 0;
624  struct ast_geoloc_profile *profile;
625  char *id = ast_alloca(strlen(name) + 3 /* <, >, NULL */);
626 
627  sprintf(id, "<%s>", name); /* Safe */
628  profile = ast_sorcery_alloc(geoloc_sorcery, "profile", id);
629  ast_assert_return(profile != NULL, 0);
630 
631  profile->precedence = ast_geoloc_precedence_str_to_enum(name);
632  profile->pidf_element = AST_PIDF_ELEMENT_DEVICE;
633  rc = ast_sorcery_create(geoloc_sorcery, profile);
634  /*
635  * We're either passing the ref to sorcery or there was an error.
636  * Either way we need to drop our reference.
637  */
638  ao2_ref(profile, -1);
639 
640  /* ast_assert_return wants a true/false */
641  return rc == 0 ? 1 : 0;
642 }
643 
644 static int geoloc_load_default_profiles(void)
645 {
646  /*
647  * If any of these fail, the module will fail to load
648  * and clean up the sorcery instance so no error cleanup
649  * is required here.
650  */
651  ast_assert_return(default_profile_create("prefer_config"), -1);
652  ast_assert_return(default_profile_create("discard_config"), -1);
653  ast_assert_return(default_profile_create("prefer_incoming"), -1);
654  ast_assert_return(default_profile_create("discard_incoming"), -1);
655 
656  return 0;
657 }
658 
659 int geoloc_config_load(void)
660 {
661  enum ast_sorcery_apply_result result;
662  int rc = 0;
663 
664  if (!(geoloc_sorcery = ast_sorcery_open())) {
665  ast_log(LOG_ERROR, "Failed to open geolocation sorcery\n");
667  }
668 
669  ast_sorcery_apply_config(geoloc_sorcery, "location");
670  result = ast_sorcery_apply_default(geoloc_sorcery, "location", "config", "geolocation.conf,criteria=type=location");
671  if (result != AST_SORCERY_APPLY_SUCCESS) {
672  ast_log(LOG_ERROR, "Failed to apply defaults for geoloc location object with sorcery\n");
674  }
675 
676  rc = ast_sorcery_object_register(geoloc_sorcery, "location", geoloc_location_alloc, NULL, geoloc_location_apply_handler);
677  if (rc != 0) {
678  ast_log(LOG_ERROR, "Failed to register geoloc location object with sorcery\n");
680  }
681 
682  ast_sorcery_object_field_register(geoloc_sorcery, "location", "type", "", OPT_NOOP_T, 0, 0);
683  ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "format", AST_GEOLOC_FORMAT_NONE,
684  location_format_handler, location_format_to_str, NULL, 0, 0);
685  ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "location_info", NULL,
686  location_location_info_handler, location_location_info_to_str, location_location_info_dup, 0, 0);
687  ast_sorcery_object_field_register_custom(geoloc_sorcery, "location", "confidence", NULL,
688  location_confidence_handler, location_confidence_to_str, location_confidence_dup, 0, 0);
689  ast_sorcery_object_field_register(geoloc_sorcery, "location", "location_source", "", OPT_STRINGFIELD_T,
690  0, STRFLDSET(struct ast_geoloc_location, location_source));
691  ast_sorcery_object_field_register(geoloc_sorcery, "location", "method", "", OPT_STRINGFIELD_T,
692  0, STRFLDSET(struct ast_geoloc_location, method));
693 
694 
695  ast_sorcery_apply_config(geoloc_sorcery, "profile");
696  /*
697  * The memory backend is used to contain the built-in profiles.
698  */
699  result = ast_sorcery_apply_wizard_mapping(geoloc_sorcery, "profile", "memory", NULL, 0);
700  if (result == AST_SORCERY_APPLY_FAIL) {
701  ast_log(LOG_ERROR, "Failed to add memory wizard mapping to geoloc profile object\n");
703  }
704 
705  result = ast_sorcery_apply_wizard_mapping(geoloc_sorcery, "profile", "config",
706  "geolocation.conf,criteria=type=profile", 0);
707  if (result == AST_SORCERY_APPLY_FAIL) {
708  ast_log(LOG_ERROR, "Failed to add memory wizard mapping to geoloc profile object\n");
710  }
711  rc = ast_sorcery_object_register(geoloc_sorcery, "profile", geoloc_profile_alloc, NULL, geoloc_profile_apply_handler);
712  if (rc != 0) {
713  ast_log(LOG_ERROR, "Failed to register geoloc profile object with sorcery\n");
715  }
716 
717  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "type", "", OPT_NOOP_T, 0, 0);
718  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "pidf_element",
719  pidf_element_names[AST_PIDF_ELEMENT_DEVICE], profile_pidf_element_handler, profile_pidf_element_to_str, NULL, 0, 0);
720  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "location_reference", "", OPT_STRINGFIELD_T,
721  0, STRFLDSET(struct ast_geoloc_profile, location_reference));
722  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "profile_precedence", "discard_incoming",
723  profile_precedence_handler, profile_precedence_to_str, NULL, 0, 0);
724  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "usage_rules", NULL,
725  profile_usage_rules_handler, profile_usage_rules_to_str, profile_usage_rules_dup, 0, 0);
726  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_info_refinement", NULL,
727  profile_location_refinement_handler, profile_location_refinement_to_str, profile_location_refinement_dup, 0, 0);
728  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_variables", NULL,
729  profile_location_variables_handler, profile_location_variables_to_str, profile_location_variables_dup, 0, 0);
730  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "notes", "", OPT_STRINGFIELD_T,
731  0, STRFLDSET(struct ast_geoloc_profile, notes));
732  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "allow_routing_use",
733  "no", OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, allow_routing_use));
734  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "suppress_empty_ca_elements",
735  "no", OPT_BOOL_T, 1, FLDSET(struct ast_geoloc_profile, suppress_empty_ca_elements));
736 
737  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "format", AST_GEOLOC_FORMAT_NONE,
738  profile_format_handler, profile_format_to_str, NULL, 0, 0);
739  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "location_info", NULL,
740  profile_location_info_handler, profile_location_info_to_str, profile_location_info_dup, 0, 0);
741  ast_sorcery_object_field_register_custom(geoloc_sorcery, "profile", "confidence", NULL,
742  profile_confidence_handler, profile_confidence_to_str, profile_confidence_dup, 0, 0);
743  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "location_source", "", OPT_STRINGFIELD_T,
744  0, STRFLDSET(struct ast_geoloc_profile, location_source));
745  ast_sorcery_object_field_register(geoloc_sorcery, "profile", "method", "", OPT_STRINGFIELD_T,
746  0, STRFLDSET(struct ast_geoloc_profile, method));
747 
748 
749  ast_sorcery_load(geoloc_sorcery);
750 
751  rc = geoloc_load_default_profiles();
752  if (rc != 0) {
753  ast_log(LOG_ERROR, "Failed to load default geoloc profiles\n");
755  }
756 
757 
758  ast_cli_register_multiple(geoloc_location_cli_commands, ARRAY_LEN(geoloc_location_cli_commands));
759 
761 }
762 
763 int AST_OPTIONAL_API_NAME(ast_geoloc_is_loaded)(void)
764 {
765  return 1;
766 }
767 
Asterisk main include file. File version handling, generic pbx functions.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define ast_sorcery_apply_wizard_mapping(sorcery, type, name, data, caching)
Apply additional object wizard mappings.
Definition: sorcery.h:510
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
Definition: netsock2.c:230
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
descriptor for a cli entry.
Definition: cli.h:171
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
Structure for variables, used for configurations and for channel variables.
Perform no matching, return all objects.
Definition: sorcery.h:123
Full structure for sorcery.
Definition: sorcery.c:230
Type for a default handler that should do nothing.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Return all matching objects.
Definition: sorcery.h:120
Socket address structure.
Definition: netsock2.h:97
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
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
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
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
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
ast_sorcery_apply_result
Definition: sorcery.h:423
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Definition: sorcery.c:1061
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#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
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
const char * ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
Gets the value of a variable from a variable list by name.
Definition: main/config.c:919
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
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.
Type for default option handler for bools (ast_true/ast_false)
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
char * command
Definition: cli.h:186
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
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
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition: sorcery.c:1377
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition: sorcery.c:1408
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Standard Command Line Interface.
struct ast_str * ast_variable_list_join(const struct ast_variable *head, const char *item_separator, const char *name_value_separator, const char *quote_char, struct ast_str **str)
Join an ast_variable list with specified separators and quoted values.
Definition: main/config.c:700
#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
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
Type for default option handler for stringfields.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define AST_OPTIONAL_API_NAME(name)
Expands to the name of the implementation function.
Definition: optional_api.h:228
Generic container type.
void ast_sorcery_ref(struct ast_sorcery *sorcery)
Increase the reference count of a sorcery structure.
Definition: sorcery.c:1473
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
Asterisk module definitions.
#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.