Asterisk - The Open Source Telephony Project GIT-master-a63eec2
Loading...
Searching...
No Matches
sorcery.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2012 - 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/*! \file
20 *
21 * \brief Sorcery Data Access Layer API
22 *
23 * \author Joshua Colp <jcolp@digium.com>
24 */
25
26/*** MODULEINFO
27 <support_level>core</support_level>
28 ***/
29
30#include "asterisk.h"
31
32#include "asterisk/logger.h"
33#include "asterisk/sorcery.h"
34#include "asterisk/astobj2.h"
35#include "asterisk/format.h"
36#include "asterisk/format_cap.h"
37#include "asterisk/strings.h"
39#include "asterisk/netsock2.h"
40#include "asterisk/module.h"
42#include "asterisk/taskpool.h"
43#include "asterisk/json.h"
44#include "asterisk/vector.h"
45#include "asterisk/cli.h"
46
47/* To prevent DEBUG_FD_LEAKS from interfering with things we undef open and close */
48#undef open
49#undef close
50
51/*! \brief Number of buckets for wizards (should be prime for performance reasons) */
52#define WIZARD_BUCKETS 7
53
54/*! \brief Number of buckets for types (should be prime for performance reasons) */
55#define TYPE_BUCKETS 53
56
57/*! \brief Number of buckets for instances (should be prime for performance reasons) */
58#define INSTANCE_BUCKETS 17
59
60/*! \brief Number of buckets for object fields (should be prime for performance reasons) */
61#define OBJECT_FIELD_BUCKETS 29
62
63#define NOTIFY_GENERIC_OBSERVERS(container, type, callback, ...) ({ \
64 struct ao2_iterator i = ao2_iterator_init(container, 0); \
65 struct type *observer; \
66 ao2_rdlock(container); \
67 while ((observer = ao2_iterator_next(&i))) { \
68 if (observer->callbacks->callback) { \
69 observer->callbacks->callback(__VA_ARGS__); \
70 } \
71 ao2_cleanup(observer); \
72 } \
73 ao2_unlock(container); \
74 ao2_iterator_cleanup(&i); \
75})
76
77#define NOTIFY_GLOBAL_OBSERVERS(container, callback, ...) \
78 NOTIFY_GENERIC_OBSERVERS(container, sorcery_global_observer, callback, __VA_ARGS__)
79
80#define NOTIFY_INSTANCE_OBSERVERS(container, callback, ...) \
81 NOTIFY_GENERIC_OBSERVERS(container, sorcery_instance_observer, callback, __VA_ARGS__)
82
83#define NOTIFY_WIZARD_OBSERVERS(container, callback, ...) \
84 NOTIFY_GENERIC_OBSERVERS(container, sorcery_wizard_observer, callback, __VA_ARGS__)
85
86/*! \brief Taskpool for observers */
87static struct ast_taskpool *taskpool;
88
89/*! \brief Structure for an internal wizard instance */
91 /*!
92 * \brief Wizard interface itself
93 * \warning Callbacks must always be declared first in this structure
94 * so an ao2_ref on &callbacks will adjust the ref count on
95 * internal_wizard.
96 */
98
99 /*! \brief Observers */
101};
102
103/*! \brief Structure for a wizard instance which operates on objects */
105 /*! \brief Wizard interface itself */
107
108 /*! \brief Unique data for the wizard */
109 void *data;
110
111 /*! \brief Wizard is acting as an object cache */
112 unsigned int caching:1;
113
114 /*! \brief Wizard is read_only */
115 unsigned int read_only:1;
116
117 /*! \brief Wizard allows others of the same type */
118 unsigned int allow_duplicates:1;
119
120 /*! \brief Wizard arguments */
121 char wizard_args[0];
122};
123
124/*! \brief Interface for a sorcery object type wizards */
125AST_VECTOR_RW(ast_sorcery_object_wizards, struct ast_sorcery_object_wizard *);
126
127/*! \brief Structure for internal sorcery object information */
129 /*! \brief Unique identifier of this object */
130 char *id;
131
132 /*! \brief Type of object */
134
135 /*! \brief Optional object destructor */
137
138 /*! \brief Extended object fields */
140
141 /*! \brief Time that the object was created */
142 struct timeval created;
143
144 /*! \brief Whether this object has dynamic contents or not */
145 unsigned int has_dynamic_contents:1;
146};
147
148/*! \brief Structure for registered object type */
150 /*! \brief Unique name of the object type */
152
153 /*! \brief Optional transformation callback */
155
156 /*! \brief Optional object set apply callback */
158
159 /*! \brief Optional object copy callback */
161
162 /*! \brief Optional object diff callback */
164
165 /*! \brief Wizard instances */
166 struct ast_sorcery_object_wizards wizards;
167
168 /*! \brief Object fields */
170
171 /*! \brief Configuration framework general information */
172 struct aco_info *info;
173
174 /*! \brief Configuration framework file information */
175 struct aco_file *file;
176
177 /*! \brief Type details */
179
180 /*! \brief Observers */
182
183 /*! \brief Serializer for observers */
185
186 /*! \brief Specifies if object type is reloadable or not */
187 unsigned int reloadable:1;
188};
189
190/*! \brief Structure for registered object type observer */
192 /*! \brief Pointer to the observer implementation */
194};
195
196/*! \brief Structure used for observer invocations */
198 /*! \brief Pointer to the object type */
200
201 /*! \brief Pointer to the object */
202 void *object;
203};
204
205/*! \brief Structure for registered object field */
207 /*! \brief Name of the field */
209
210 /*! \brief The compiled name regex if name is a regex */
211 regex_t *name_regex;
212
213 /*! \brief Callback function for translation of a single value */
215
216 /*! \brief Callback function for translation of multiple values */
218
219 /*! \brief Position of the field */
220 intptr_t args[];
221};
222
223/*! \brief Proxy object for sorcery */
226 /*! \brief The name of the module owning this sorcery instance */
227 char module_name[0];
228};
229
230/*! \brief Full structure for sorcery */
232 /*! \brief Container for known object types */
234
235 /*! \brief Observers */
237
238 /*! \brief Pointer to module_name in the associated sorcery_proxy. */
240};
241
242/*! \brief Structure for passing load/reload details */
244 /*! \brief Sorcery structure in use */
245 const struct ast_sorcery *sorcery;
246
247 /*! \brief Type of object being loaded */
248 const char *type;
249
250 /*! \brief Whether this is a reload or not */
251 unsigned int reload:1;
252
253 /*! \brief Whether this is forced or not */
254 unsigned int force:1;
255};
256
257/*! \brief Registered sorcery wizards */
258static struct ao2_container *wizards;
259
260/* The following 3 observer wrappers must name their
261 * external observer 'callbacks' and it must be
262 * the first member of the structure. Common macros
263 * and container callbacks depend on it.
264 */
265
266/*! \brief A global observer wrapper */
270
271/*! \brief An instance observer wrapper */
275
276/*! \brief A wizard observer wrapper */
280
281/*! \brief Registered global observers */
283
284/*! \brief Registered sorcery instances */
286
287/* \brief Global config flag (declared in sorcery.h) */
289
290static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
291{
292 int *field = (int *)(obj + args[0]);
293 return (ast_asprintf(buf, "%d", *field) < 0) ? -1 : 0;
294}
295
296static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
297{
298 unsigned int *field = (unsigned int *)(obj + args[0]);
299 return (ast_asprintf(buf, "%u", *field) < 0) ? -1 : 0;
300}
301
302static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
303{
304 double *field = (double *)(obj + args[0]);
305 return (ast_asprintf(buf, "%f", *field) < 0) ? -1 : 0;
306}
307
308static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
309{
310 ast_string_field *field = (const char **)(obj + args[0]);
311 return !(*buf = ast_strdup(*field)) ? -1 : 0;
312}
313
314static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
315{
316 unsigned int *field = (unsigned int *)(obj + args[0]);
317 return !(*buf = ast_strdup(*field ? "true" : "false")) ? -1 : 0;
318}
319
320static int yesno_handler_fn(const void *obj, const intptr_t *args, char **buf)
321{
322 unsigned int *field = (unsigned int *)(obj + args[0]);
323 return !(*buf = ast_strdup(*field ? "yes" : "no")) ? -1 : 0;
324}
325
326static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
327{
328 struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + args[0]);
329 return !(*buf = ast_strdup(ast_sockaddr_stringify(field))) ? -1 : 0;
330}
331
332static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
333{
334 char *field = (char *)(obj + args[0]);
335 return !(*buf = ast_strdup(field)) ? -1 : 0;
336}
337
338static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
339{
341 struct ast_format_cap **cap = (struct ast_format_cap **)(obj + args[0]);
342 return !(*buf = ast_strdup(ast_format_cap_get_names(*cap, &codec_buf)));
343}
344
346{
347 switch(type) {
348 case OPT_BOOL_T: return bool_handler_fn;
349 case OPT_YESNO_T: return yesno_handler_fn;
351 case OPT_CODEC_T: return codec_handler_fn;
352 case OPT_DOUBLE_T: return double_handler_fn;
353 case OPT_INT_T: return int_handler_fn;
356 case OPT_UINT_T: return uint_handler_fn;
357
358 default:
359 case OPT_CUSTOM_T: return NULL;
360 }
361
362 return NULL;
363}
364
365/*! \brief Hashing and comparison functions for sorcery wizards */
368
371
372/*!
373 * \internal
374 * \brief CLI command implementation for 'sorcery show settings'
375 */
376static char *cli_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
377{
378 switch (cmd) {
379 case CLI_INIT:
380 e->command = "sorcery show settings";
381 e->usage = "Usage: sorcery show settings\n"
382 " Show global configuration options\n";
383 return NULL;
384 case CLI_GENERATE:
385 return NULL;
386 }
387
388 ast_cli(a->fd, "\nSorcery global settings\n");
389 ast_cli(a->fd, "-----------------\n");
390 ast_cli(a->fd, " Update->Create fallback in backends: %s\n",
391 ast_sorcery_update_or_create_on_update_miss ? "enabled" : "disabled");
392
393 return CLI_SUCCESS;
394}
395
396
397static struct ast_cli_entry cli_commands[] = {
398 AST_CLI_DEFINE(cli_show_settings, "Show global configuration options"),
399};
400
401/*! \brief Cleanup function for graceful shutdowns */
414
415/*! \brief Compare function for sorcery instances */
417
418/*! \brief Hashing function for sorcery instances */
420
421/*!
422 * \internal
423 * \brief Parse [general] options from sorcery.conf and set globals.
424 */
425static void parse_general_options(void)
426{
427 struct ast_flags flags = { 0 };
428 struct ast_config *cfg = ast_config_load2("sorcery.conf", "sorcery", flags);
429 const struct ast_variable *var;
430
431 if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
432 return;
433 }
434
435 for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
436 if (!strcasecmp(var->name, "update_or_create_on_update_miss")) {
438 }
439 }
440
442}
443
445{
448 .auto_increment = 1,
449 .max_size = 0,
450 .idle_timeout = 60,
451 .initial_size = 1,
452 .minimum_size = 1,
453 };
455
457
458 taskpool = ast_taskpool_create("sorcery", &options);
459 if (!taskpool) {
460 return -1;
461 }
462
464 ast_sorcery_internal_wizard_hash_fn, NULL, ast_sorcery_internal_wizard_cmp_fn);
465 if (!wizards) {
466 return -1;
467 }
468
470 if (!observers) {
471 return -1;
472 }
473
475 sorcery_proxy_hash_fn, NULL, sorcery_proxy_cmp_fn);
476 if (!instances) {
477 return -1;
478 }
479
481 return -1;
482 }
483
485
486 return 0;
487}
488
490{
491 struct ast_sorcery_internal_wizard *wizard = obj;
492
493 ao2_cleanup(wizard->observers);
494}
495
496int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
497{
498 struct ast_sorcery_internal_wizard *wizard;
499 int res = -1;
500
501 ast_assert(!ast_strlen_zero(interface->name));
502
504
505 if ((wizard = ao2_find(wizards, interface->name, OBJ_KEY | OBJ_NOLOCK))) {
506 ast_log(LOG_WARNING, "Attempted to register sorcery wizard '%s' twice\n",
507 interface->name);
508 goto done;
509 }
510
511 if (!(wizard = ao2_alloc(sizeof(*wizard), sorcery_internal_wizard_destructor))) {
512 goto done;
513 }
514
515 wizard->callbacks = *interface;
516 wizard->callbacks.module = module;
517
519 if (!wizard->observers) {
520 goto done;
521 }
522
524 res = 0;
525
526 ast_verb(5, "Sorcery registered wizard '%s'\n", interface->name);
527
528 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_registered,
529 interface->name, interface);
530
531done:
532 ao2_cleanup(wizard);
534
535 return res;
536}
537
539{
540 struct ast_sorcery_internal_wizard *wizard =
541 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL;
542
543 if (wizard) {
544 NOTIFY_GLOBAL_OBSERVERS(observers, wizard_unregistering, wizard->callbacks.name, &wizard->callbacks);
545 ao2_unlink(wizards, wizard);
546 ao2_ref(wizard, -1);
547 ast_verb(5, "Sorcery unregistered wizard '%s'\n", interface->name);
548 return 0;
549 } else {
550 return -1;
551 }
552}
553
554/*! \brief Internal callback function for removing a generic observer */
555static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
556{
557 const struct sorcery_global_observer *observer = obj;
558
559 return (observer->callbacks == arg) ? CMP_MATCH : 0;
560}
561
563{
564 struct sorcery_global_observer *cb;
565
566 cb = ao2_alloc(sizeof(*cb), NULL);
567 if (!cb) {
568 return -1;
569 }
570
571 cb->callbacks = callbacks;
572 ao2_link(observers, cb);
573 ao2_ref(cb, -1);
574
575 return 0;
576}
577
583
586{
587 struct sorcery_instance_observer *cb;
588
589 cb = ao2_alloc(sizeof(*cb), NULL);
590 if (!cb) {
591 return -1;
592 }
593
594 cb->callbacks = callbacks;
596 ao2_ref(cb, -1);
597
598 return 0;
599}
600
606
609{
610 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
611 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
613
614 if (wizard) {
615 struct sorcery_wizard_observer *cb;
616
617 cb = ao2_alloc(sizeof(*cb), NULL);
618 if (!cb) {
619 return -1;
620 }
621
622 cb->callbacks = callbacks;
623 ao2_link(wizard->observers, cb);
624 ao2_ref(cb, -1);
625
626 return 0;
627 }
628
629 return -1;
630}
631
634{
635 RAII_VAR(struct ast_sorcery_internal_wizard *, wizard,
636 interface ? ao2_find(wizards, interface->name, OBJ_SEARCH_KEY) : NULL,
638
639 if (wizard) {
641 }
642}
643
644/*! \brief Destructor called when sorcery structure is destroyed */
645static void sorcery_destructor(void *obj)
646{
647 struct ast_sorcery *sorcery = obj;
648
649 if (sorcery->observers) {
651 }
654}
655
656/*! \brief Hashing function for sorcery types */
659
660static void sorcery_proxy_cb(void *weakproxy, void *data)
661{
662 ao2_unlink(instances, weakproxy);
663}
664
665struct ast_sorcery *__ast_sorcery_open(const char *module_name, const char *file, int line, const char *func)
666{
667 struct sorcery_proxy *proxy;
668 struct ast_sorcery *sorcery;
669
671
674 __PRETTY_FUNCTION__, file, line, func);
675 if (sorcery) {
677
678 return sorcery;
679 }
680
681 proxy = ao2_t_weakproxy_alloc(sizeof(*proxy) + strlen(module_name) + 1, NULL, module_name);
682 if (!proxy) {
683 goto failure_cleanup;
684 }
685 strcpy(proxy->module_name, module_name); /* Safe */
686
688 if (!sorcery) {
689 goto failure_cleanup;
690 }
691
693
694 /* We have exclusive access to proxy and sorcery, no need for locking here. */
695 if (ao2_t_weakproxy_set_object(proxy, sorcery, OBJ_NOLOCK, "weakproxy link")) {
696 goto failure_cleanup;
697 }
698
700 goto failure_cleanup;
701 }
702
704 ast_sorcery_object_type_hash_fn, NULL, ast_sorcery_object_type_cmp_fn);
705 if (!sorcery->types) {
706 goto failure_cleanup;
707 }
708
710 goto failure_cleanup;
711 }
712
714 ast_log(LOG_ERROR, "Error attempting to apply configuration %s to sorcery.\n", module_name);
715 goto failure_cleanup;
716 }
717
719 ao2_ref(proxy, -1);
720
722
724 return sorcery;
725
726failure_cleanup:
727 /* cleanup of sorcery may result in locking instances, so make sure we unlock first. */
730 ao2_cleanup(proxy);
731
732 return NULL;
733}
734
735/*! \brief Search function for sorcery instances */
740
741/*! \brief Destructor function for object types */
742static void sorcery_object_type_destructor(void *obj)
743{
744 struct ast_sorcery_object_type *object_type = obj;
745
746 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
748 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
749 AST_VECTOR_RW_FREE(&object_type->wizards);
750 ao2_cleanup(object_type->fields);
751 ao2_cleanup(object_type->observers);
752
753 if (object_type->info) {
754 aco_info_destroy(object_type->info);
755 ast_free(object_type->info);
756 }
757
758 ast_free(object_type->file);
759
761}
762
763/*! \brief Internal function which allocates an object type structure */
764static struct ast_sorcery_object_type *sorcery_object_type_alloc(const char *type, const char *module)
765{
766#define INITIAL_WIZARD_VECTOR_SIZE 5
767 struct ast_sorcery_object_type *object_type;
768 char tps_name[AST_TASKPROCESSOR_MAX_NAME + 1];
769
770 if (!(object_type = ao2_alloc(sizeof(*object_type), sorcery_object_type_destructor))) {
771 return NULL;
772 }
773
774 /* Order matters for object wizards */
775 if (AST_VECTOR_RW_INIT(&object_type->wizards, INITIAL_WIZARD_VECTOR_SIZE) != 0) {
776 ao2_ref(object_type, -1);
777 return NULL;
778 }
779
781 OBJECT_FIELD_BUCKETS, ast_sorcery_object_field_hash_fn, NULL, ast_sorcery_object_field_cmp_fn);
782 if (!object_type->fields) {
783 ao2_ref(object_type, -1);
784 return NULL;
785 }
786
788 NULL, NULL);
789 if (!object_type->observers) {
790 ao2_ref(object_type, -1);
791 return NULL;
792 }
793
794 object_type->info = ast_calloc(1,
795 sizeof(*object_type->info) + 2 * sizeof(object_type->info->files[0]));
796 if (!object_type->info) {
797 ao2_ref(object_type, -1);
798 return NULL;
799 }
800
801 object_type->file = ast_calloc(1,
802 sizeof(*object_type->file) + 2 * sizeof(object_type->file->types[0]));
803 if (!object_type->file) {
804 ao2_ref(object_type, -1);
805 return NULL;
806 }
807
808 /* Create name with seq number appended. */
809 ast_taskprocessor_build_name(tps_name, sizeof(tps_name), "sorcery/%s", type);
810
811 if (!(object_type->serializer = ast_taskpool_serializer(tps_name, taskpool))) {
812 ao2_ref(object_type, -1);
813 return NULL;
814 }
815
816 object_type->info->files[0] = object_type->file;
817 object_type->info->files[1] = NULL;
818 object_type->info->module = module;
819
820 ast_copy_string(object_type->name, type, sizeof(object_type->name));
821
822 return object_type;
823}
824
825/*! \brief Object wizard destructor */
827{
828 struct ast_sorcery_object_wizard *object_wizard = obj;
829
830 if (object_wizard->data && object_wizard->wizard->callbacks.close) {
831 object_wizard->wizard->callbacks.close(object_wizard->data);
832 }
833
834 if (object_wizard->wizard) {
835 ast_module_unref(object_wizard->wizard->callbacks.module);
836 }
837
838 ao2_cleanup(object_wizard->wizard);
839}
840
841/*! \brief Return the number of wizards mapped to an object type */
843 const char *type)
844{
846
847 if (!object_type) {
848 return -1;
849 }
850
851 return AST_VECTOR_SIZE(&object_type->wizards);
852}
853
855 const char *type, int index, struct ast_sorcery_wizard **wizard, void **data)
856{
858 struct ast_sorcery_object_wizard *owizard;
859
860 if (!object_type) {
861 return -1;
862 }
863
864 if (index < 0 || index >= AST_VECTOR_SIZE(&object_type->wizards)) {
865 return -1;
866 }
867
868 owizard = AST_VECTOR_GET(&object_type->wizards, index);
869
870 if (wizard != NULL) {
871 *wizard = &(owizard->wizard->callbacks);
872 ao2_bump(owizard->wizard);
873 } else {
874 return -1;
875 }
876
877 if (data != NULL) {
878 *data = owizard->data;
879 }
880
881 return 0;
882}
883
885 const char *object_type_name, const char *module, const char *wizard_type_name,
886 const char *wizard_args)
887{
888 RAII_VAR(struct ast_sorcery_object_type *, object_type,
889 ao2_find(sorcery->types, object_type_name, OBJ_SEARCH_KEY), ao2_cleanup);
890 int res = -1;
891 int i;
892
893 if (!object_type) {
894 return res;
895 }
896
897 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
898 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
899 struct ast_sorcery_object_wizard *wizard = AST_VECTOR_GET(&object_type->wizards, i);
900
901 if (strcmp(wizard->wizard->callbacks.name, wizard_type_name) == 0
902 && strcmp(S_OR(wizard->wizard_args, ""), S_OR(wizard_args, "")) == 0) {
903 ao2_cleanup(AST_VECTOR_REMOVE_ORDERED(&object_type->wizards, i));
904 res = 0;
905 break;
906 }
907 }
908 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
909
910 return res;
911}
912
913/*! \brief Internal function removes a wizard mapping */
915 const char *type, const char *module, const char *name)
916{
918 int res;
919
920 if (!object_type) {
921 return -1;
922 }
923
924 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
925#define WIZARD_NAME_COMPARE(a, b) (strcmp((a)->wizard->callbacks.name, (b)) == 0)
927#undef WIZARD_NAME_COMPARE
928 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
929
930 return res;
931}
932
934 const char *object_type_name, const char *module, const char *wizard_type_name,
935 const char *wizard_args, enum ast_sorcery_wizard_apply_flags flags, int position,
936 struct ast_sorcery_wizard **wizard, void **wizard_data)
937{
938 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, object_type_name, OBJ_KEY), ao2_cleanup);
939 RAII_VAR(struct ast_sorcery_internal_wizard *, internal_wizard, ao2_find(wizards, wizard_type_name, OBJ_KEY), ao2_cleanup);
940 RAII_VAR(struct ast_sorcery_object_wizard *, object_wizard, NULL, ao2_cleanup);
941 int created = 0;
942
943 object_wizard = ao2_alloc(sizeof(*object_wizard)
944 + (ast_strlen_zero(wizard_args) ? 0 : strlen(wizard_args) + 1),
946
947 if (!object_wizard) {
949 }
950
951 if (!internal_wizard
952 || internal_wizard->callbacks.module != ast_module_running_ref(internal_wizard->callbacks.module)) {
954 "Wizard '%s' could not be applied to object type '%s' as it was not found\n",
955 wizard_type_name, object_type_name);
957 }
958
959 if (!object_type) {
960 if (!(object_type = sorcery_object_type_alloc(object_type_name, module))) {
961 ast_module_unref(internal_wizard->callbacks.module);
963 }
964 created = 1;
965 }
966
967 AST_VECTOR_RW_WRLOCK(&object_type->wizards);
968 if (!created) {
969 struct ast_sorcery_object_wizard *found;
970
971#define WIZARD_COMPARE(a, b) ((a)->wizard == (b))
972 found = AST_VECTOR_GET_CMP(&object_type->wizards, internal_wizard, WIZARD_COMPARE);
973#undef WIZARD_COMPARE
974 if (found
976 ast_debug(1, "Wizard %s already applied to object type %s\n",
977 internal_wizard->callbacks.name, object_type->name);
978 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
979 ast_module_unref(internal_wizard->callbacks.module);
981 }
982 }
983
984 ast_debug(5, "Calling wizard %s open callback on object type %s\n",
985 wizard_type_name, object_type->name);
986 if (internal_wizard->callbacks.open && !(object_wizard->data = internal_wizard->callbacks.open(wizard_args))) {
987 ast_log(LOG_WARNING, "Wizard '%s' failed to open mapping for object type '%s' with data: %s\n",
988 wizard_type_name, object_type->name, S_OR(wizard_args, ""));
989 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
990 ast_module_unref(internal_wizard->callbacks.module);
992 }
993
994 object_wizard->wizard = ao2_bump(internal_wizard);
995 object_wizard->caching = !!(flags & AST_SORCERY_WIZARD_APPLY_CACHING);
996 object_wizard->read_only = !!(flags & AST_SORCERY_WIZARD_APPLY_READONLY);
997 if (wizard_args) {
998 strcpy(object_wizard->wizard_args, wizard_args); /* Safe */
999 }
1000
1001 if (position == AST_SORCERY_WIZARD_POSITION_LAST) {
1002 position = AST_VECTOR_SIZE(&object_type->wizards);
1003 }
1004
1005 if (AST_VECTOR_INSERT_AT(&object_type->wizards, position, object_wizard) != 0) {
1006 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1008 }
1009 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1010 ao2_bump(object_wizard);
1011
1012 if (created) {
1013 ao2_link(sorcery->types, object_type);
1014 }
1015
1017 sorcery->module_name, sorcery, object_type_name, &internal_wizard->callbacks, wizard_args,
1018 object_wizard->data);
1019
1020 if (wizard) {
1021 *wizard = &internal_wizard->callbacks;
1022 }
1023 if (wizard_data) {
1024 *wizard_data = object_wizard->data;
1025 }
1026
1028}
1029
1030/*! \brief Internal function which creates an object type and inserts a wizard mapping */
1032 const char *type, const char *module, const char *name,
1033 const char *data, unsigned int caching, int position)
1034{
1037 position, NULL, NULL);
1038}
1039
1040/*! \brief Internal function which creates an object type and adds a wizard mapping */
1042 const char *type, const char *module, const char *name,
1043 const char *data, unsigned int caching)
1044{
1047}
1048
1050{
1051 struct ast_flags flags = { 0 };
1052 struct ast_config *config = ast_config_load2("sorcery.conf", "sorcery", flags);
1053 struct ast_variable *mapping;
1054 int res = AST_SORCERY_APPLY_SUCCESS;
1055
1056 if (!config) {
1058 }
1059
1062 }
1063
1064 for (mapping = ast_variable_browse(config, name); mapping; mapping = mapping->next) {
1065 RAII_VAR(char *, mapping_name, ast_strdup(mapping->name), ast_free);
1066 RAII_VAR(char *, mapping_value, ast_strdup(mapping->value), ast_free);
1067 char *options = mapping_name;
1068 char *type = strsep(&options, "/");
1069 char *data = mapping_value;
1070 char *wizard = strsep(&data, ",");
1071 unsigned int caching = 0;
1072
1073 /* If no object type or wizard exists just skip, nothing we can do */
1074 if (ast_strlen_zero(type) || ast_strlen_zero(wizard)) {
1075 continue;
1076 }
1077
1078 /* If the wizard is configured as a cache treat it as such */
1079 if (!ast_strlen_zero(options) && strstr(options, "cache")) {
1080 caching = 1;
1081 }
1082
1083 /* Any error immediately causes us to stop */
1084 if (__ast_sorcery_apply_wizard_mapping(sorcery, type, module, wizard, data, caching) == AST_SORCERY_APPLY_FAIL) {
1086 break;
1087 }
1088 }
1089
1091
1092 return res;
1093}
1094
1095enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
1096{
1098
1099 /* Defaults can not be added if any existing mapping exists */
1100 if (object_type) {
1102 }
1103
1104 return __ast_sorcery_apply_wizard_mapping(sorcery, type, module, name, data, 0);
1105}
1106
1107static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
1108{
1109 return ast_sorcery_object_set_extended(obj, var->name, var->value);
1110}
1111
1112static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
1113{
1114 const struct ast_sorcery_object_details *details = obj;
1115
1116 if (details->object->extended) {
1117 *fields = ast_variables_dup(details->object->extended);
1118 } else {
1119 *fields = NULL;
1120 }
1121
1122 return 0;
1123}
1124
1126{
1127 struct ast_sorcery_object_type *object_type;
1128 int res = -1;
1129
1131 object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY | OBJ_NOLOCK);
1132 if (object_type && object_type->type.type == ACO_ITEM) {
1133 ao2_unlink_flags(sorcery->types, object_type, OBJ_NOLOCK);
1134 res = 0;
1135 }
1137
1138 /* XXX may need to add an instance unregister observer callback on success. */
1139
1140 ao2_cleanup(object_type);
1141 return res;
1142}
1143
1145{
1147
1148 if (!object_type || object_type->type.item_alloc) {
1149 return -1;
1150 }
1151
1152 object_type->type.name = object_type->name;
1153 object_type->type.type = ACO_ITEM;
1154 object_type->type.category = ".?";
1155 object_type->type.item_alloc = alloc;
1156 object_type->type.hidden = hidden;
1157
1158 object_type->reloadable = reloadable;
1159 object_type->transform = transform;
1160 object_type->apply = apply;
1161 object_type->file->types[0] = &object_type->type;
1162 object_type->file->types[1] = NULL;
1163
1164 if (aco_info_init(object_type->info)) {
1165 return -1;
1166 }
1167
1169 return -1;
1170 }
1171
1172 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, object_type_registered,
1174
1175 return 0;
1176}
1177
1178int ast_sorcery_object_set_congestion_levels(struct ast_sorcery *sorcery, const char *type, long low_water, long high_water)
1179{
1180 struct ast_sorcery_object_type *object_type;
1181 int res = -1;
1182
1183 object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
1184 if (object_type) {
1186 low_water, high_water);
1187 ao2_ref(object_type, -1);
1188 }
1189 return res;
1190}
1191
1193{
1195
1196 if (!object_type) {
1197 return;
1198 }
1199
1200 object_type->copy = copy;
1201}
1202
1204{
1206
1207 if (!object_type) {
1208 return;
1209 }
1210
1211 object_type->diff = diff;
1212}
1213
1215{
1216 struct ast_sorcery_object_field *object_field = obj;
1217
1218 if (object_field->name_regex) {
1219 regfree(object_field->name_regex);
1220 ast_free(object_field->name_regex);
1221 }
1222}
1223
1224int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
1225{
1226#define MAX_REGEX_ERROR_LEN 128
1228 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1229 int rc;
1230
1231 if (!object_type || !object_type->type.item_alloc || !config_handler
1232 || !(object_field = ao2_alloc(sizeof(*object_field), sorcery_object_field_destructor))) {
1233 return -1;
1234 }
1235
1236 ast_copy_string(object_field->name, regex, sizeof(object_field->name));
1237 object_field->multiple_handler = sorcery_handler;
1238
1239 if (!(object_field->name_regex = ast_calloc(1, sizeof(regex_t)))) {
1240 return -1;
1241 }
1242
1243 if ((rc = regcomp(object_field->name_regex, regex, REG_EXTENDED | REG_NOSUB))) {
1244 char *regerr = ast_alloca(MAX_REGEX_ERROR_LEN);
1245 regerror(rc, object_field->name_regex, regerr, MAX_REGEX_ERROR_LEN);
1246 ast_log(LOG_ERROR, "Regular expression '%s' failed to compile: %s\n", regex, regerr);
1247 return -1;
1248 }
1249
1250 ao2_link(object_type->fields, object_field);
1251 __aco_option_register(object_type->info, regex, ACO_REGEX, object_type->file->types, "", OPT_CUSTOM_T, config_handler, 0, 1, 0);
1252
1253 return 0;
1254}
1255
1256int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type,
1257 aco_option_handler config_handler, sorcery_field_handler sorcery_handler, sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, unsigned int alias, size_t argc, ...)
1258{
1260 RAII_VAR(struct ast_sorcery_object_field *, object_field, NULL, ao2_cleanup);
1261 int pos;
1262 va_list args;
1263
1264 if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
1265 return -1;
1266 }
1267
1268 if (!sorcery_handler) {
1269 sorcery_handler = sorcery_field_default_handler(opt_type);
1270 }
1271
1272 if (!(object_field = ao2_alloc(sizeof(*object_field) + argc * sizeof(object_field->args[0]), NULL))) {
1273 return -1;
1274 }
1275
1276 ast_copy_string(object_field->name, name, sizeof(object_field->name));
1277 object_field->handler = sorcery_handler;
1278 object_field->multiple_handler = multiple_handler;
1279
1280 va_start(args, argc);
1281 for (pos = 0; pos < argc; pos++) {
1282 object_field->args[pos] = va_arg(args, size_t);
1283 }
1284 va_end(args);
1285
1286 if (!alias) {
1287 ao2_link(object_type->fields, object_field);
1288 }
1289
1290 /* TODO: Improve this hack */
1291 if (!argc) {
1292 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc);
1293 } else if (argc == 1) {
1294 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1295 object_field->args[0]);
1296 } else if (argc == 2) {
1297 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1298 object_field->args[0], object_field->args[1]);
1299 } else if (argc == 3) {
1300 __aco_option_register(object_type->info, name, ACO_EXACT, object_type->file->types, default_val, opt_type, config_handler, flags, no_doc, argc,
1301 object_field->args[0], object_field->args[1], object_field->args[2]);
1302 } else {
1303 ast_assert(0); /* The hack... she does us no good for this */
1304 }
1305
1306 return 0;
1307}
1308
1309/*! \brief Retrieves whether or not the type is reloadable */
1310static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
1311{
1312 RAII_VAR(struct ast_sorcery_object_type *, object_type,
1314 return object_type && object_type->reloadable;
1315}
1316
1317static int sorcery_wizard_load(void *obj, void *arg, int flags)
1318{
1319 struct ast_sorcery_object_wizard *wizard = obj;
1320 struct sorcery_load_details *details = arg;
1321 void (*load)(void *data, const struct ast_sorcery *sorcery, const char *type);
1322
1323 if (details->reload) {
1324 if (details->force && wizard->wizard->callbacks.force_reload) {
1325 load = wizard->wizard->callbacks.force_reload;
1326 } else {
1327 load = wizard->wizard->callbacks.reload;
1328 }
1329 } else {
1330 load = wizard->wizard->callbacks.load;
1331 }
1332
1333 if (load) {
1334 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loading,
1335 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1336
1337 load(wizard->data, details->sorcery, details->type);
1338
1339 NOTIFY_WIZARD_OBSERVERS(wizard->wizard->observers, wizard_loaded,
1340 wizard->wizard->callbacks.name, &wizard->wizard->callbacks, details->type, details->reload);
1341 }
1342
1343 return 0;
1344}
1345
1346/*! \brief Destructor for observer invocation */
1348{
1349 struct sorcery_observer_invocation *invocation = obj;
1350
1351 ao2_cleanup(invocation->object_type);
1352 ao2_cleanup(invocation->object);
1353}
1354
1355/*! \brief Allocator function for observer invocation */
1357{
1358 struct sorcery_observer_invocation *invocation;
1359
1360 invocation = ao2_alloc_options(sizeof(*invocation),
1362 if (!invocation) {
1363 return NULL;
1364 }
1365
1366 ao2_ref(object_type, +1);
1367 invocation->object_type = object_type;
1368
1369 if (object) {
1370 ao2_ref(object, +1);
1371 invocation->object = object;
1372 }
1373
1374 return invocation;
1375}
1376
1377/*! \brief Internal callback function which notifies an individual observer that an object type has been loaded */
1378static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
1379{
1380 const struct ast_sorcery_object_type_observer *observer = obj;
1381
1382 if (observer->callbacks->loaded) {
1383 observer->callbacks->loaded(arg);
1384 }
1385
1386 return 0;
1387}
1388
1389/*! \brief Internal callback function which notifies observers that an object type has been loaded */
1391{
1392 struct sorcery_observer_invocation *invocation = data;
1393
1395 ao2_cleanup(invocation);
1396
1397 return 0;
1398}
1399
1400static int sorcery_object_load(void *obj, void *arg, int flags)
1401{
1402 struct ast_sorcery_object_type *type = obj;
1403 struct sorcery_load_details *details = arg;
1404
1405 if (!type->type.item_alloc) {
1406 return 0;
1407 }
1408
1409 details->type = type->name;
1410
1411 if (details->reload && !sorcery_reloadable(details->sorcery, details->type)) {
1412 ast_log(LOG_NOTICE, "Type '%s' is not reloadable, maintaining previous values\n",
1413 details->type);
1414 return 0;
1415 }
1416
1417 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loading,
1418 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1419
1420 AST_VECTOR_RW_RDLOCK(&type->wizards);
1421 AST_VECTOR_CALLBACK(&type->wizards, sorcery_wizard_load, NULL, details, 0);
1422 AST_VECTOR_RW_UNLOCK(&type->wizards);
1423
1424 NOTIFY_INSTANCE_OBSERVERS(details->sorcery->observers, object_type_loaded,
1425 details->sorcery->module_name, details->sorcery, type->name, details->reload);
1426
1427 if (ao2_container_count(type->observers)) {
1428 struct sorcery_observer_invocation *invocation;
1429
1431 if (invocation
1433 invocation)) {
1434 ao2_cleanup(invocation);
1435 }
1436 }
1437
1438 return 0;
1439}
1440
1442{
1443 struct sorcery_load_details details = {
1444 .sorcery = sorcery,
1445 .reload = 0,
1446 };
1447
1448 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1450
1452
1455}
1456
1457void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
1458{
1460 struct sorcery_load_details details = {
1461 .sorcery = sorcery,
1462 .reload = 0,
1463 };
1464
1465 if (!object_type) {
1466 return;
1467 }
1468
1469 sorcery_object_load(object_type, &details, 0);
1470}
1471
1473{
1474 struct sorcery_load_details details = {
1475 .sorcery = sorcery,
1476 .reload = 1,
1477 };
1478
1479 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1481
1483
1486
1487}
1488
1490{
1491 struct sorcery_load_details details = {
1492 .sorcery = sorcery,
1493 .reload = 1,
1494 .force = 1,
1495 };
1496
1497 NOTIFY_INSTANCE_OBSERVERS(sorcery->observers, instance_loading,
1499
1501
1504}
1505
1506void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
1507{
1509 struct sorcery_load_details details = {
1510 .sorcery = sorcery,
1511 .reload = 1,
1512 };
1513
1514 if (!object_type) {
1515 return;
1516 }
1517
1518 sorcery_object_load(object_type, &details, 0);
1519}
1520
1522{
1524 struct sorcery_load_details details = {
1525 .sorcery = sorcery,
1526 .reload = 1,
1527 .force = 1,
1528 };
1529
1530 if (!object_type) {
1531 return;
1532 }
1533
1534 sorcery_object_load(object_type, &details, 0);
1535}
1536
1538{
1539 ao2_ref(sorcery, +1);
1540}
1541
1542static struct ast_variable *get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1543{
1544 struct ast_variable *tmp = NULL;
1545 char *buf = NULL;
1546
1547 if (!object_field->handler) {
1548 return NULL;
1549 }
1550
1551 if (!(object_field->handler(object, object_field->args, &buf))) {
1552 tmp = ast_variable_new(object_field->name, S_OR(buf, ""), "");
1553 }
1554 ast_free(buf);
1555
1556 return tmp;
1557}
1558
1559static struct ast_variable *get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
1560{
1561 struct ast_variable *tmp = NULL;
1562
1563 if (!object_field->multiple_handler) {
1564 return NULL;
1565 }
1566
1567 if (object_field->multiple_handler(object, &tmp)) {
1569 tmp = NULL;
1570 }
1571
1572 return tmp;
1573}
1574
1576 const void *object, enum ast_sorcery_field_handler_flags flags)
1577{
1578 const struct ast_sorcery_object_details *details = object;
1579 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1580 struct ao2_iterator i;
1581 struct ast_sorcery_object_field *object_field;
1582 struct ast_variable *head = NULL;
1583 struct ast_variable *tail = NULL;
1584
1585 if (!object_type) {
1586 return NULL;
1587 }
1588
1589 i = ao2_iterator_init(object_type->fields, 0);
1590
1591 for (; (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1592 struct ast_variable *tmp;
1593
1594 switch (flags) {
1596 if ((tmp = get_multiple_fields_as_var_list(object, object_field)) ||
1597 (tmp = get_single_field_as_var_list(object, object_field))) {
1598 break;
1599 }
1600 continue;
1602 if ((tmp = get_single_field_as_var_list(object, object_field)) ||
1603 (tmp = get_multiple_fields_as_var_list(object, object_field))) {
1604 break;
1605 }
1606 continue;
1608 if ((tmp = get_multiple_fields_as_var_list(object, object_field))) {
1609 break;
1610 }
1611 continue;
1613 if ((tmp = get_single_field_as_var_list(object, object_field))) {
1614 break;
1615 }
1616 continue;
1617 default:
1618 continue;
1619 }
1620
1621 tail = ast_variable_list_append_hint(&head, tail, tmp);
1622 }
1623
1625
1626 return head;
1627}
1628
1629struct ast_json *ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
1630{
1631 const struct ast_sorcery_object_details *details = object;
1632 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1633 struct ao2_iterator i;
1634 struct ast_sorcery_object_field *object_field;
1635 struct ast_json *json = ast_json_object_create();
1636 int res = 0;
1637
1638 if (!object_type || !json) {
1639 ast_json_unref(json);
1640 return NULL;
1641 }
1642
1643 i = ao2_iterator_init(object_type->fields, 0);
1644
1645 for (; !res && (object_field = ao2_iterator_next(&i)); ao2_ref(object_field, -1)) {
1646 if (object_field->multiple_handler) {
1647 struct ast_variable *tmp = NULL;
1648 struct ast_variable *field;
1649
1650 if ((res = object_field->multiple_handler(object, &tmp))) {
1652 ao2_ref(object_field, -1);
1653 break;
1654 }
1655
1656 for (field = tmp; field; field = field->next) {
1657 struct ast_json *value = ast_json_string_create(field->value);
1658
1659 if (!value || ast_json_object_set(json, field->name, value)) {
1660 res = -1;
1661 break;
1662 }
1663 }
1664
1666 } else if (object_field->handler) {
1667 char *buf = NULL;
1668 struct ast_json *value = NULL;
1669
1670 if (object_field->handler(object, object_field->args, &buf)
1672 || ast_json_object_set(json, object_field->name, value)) {
1673 ast_free(buf);
1674 ast_debug(5, "Skipping field '%s' for object type '%s'\n",
1675 object_field->name, object_type->name);
1676 continue;
1677 }
1678
1679 ast_free(buf);
1680 } else {
1681 continue;
1682 }
1683 }
1684
1686
1687 /* If any error occurs we destroy the JSON object so a partial objectset is not returned */
1688 if (res) {
1689 ast_json_unref(json);
1690 json = NULL;
1691 }
1692
1693 return json;
1694}
1695
1696int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
1697{
1698 const struct ast_sorcery_object_details *details = object;
1699 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1700 RAII_VAR(struct ast_variable *, transformed, NULL, ast_variables_destroy);
1701 struct ast_variable *field;
1702 int res = 0;
1703
1704 if (!object_type) {
1705 return -1;
1706 }
1707
1708 if (object_type->transform && (transformed = object_type->transform(objectset))) {
1709 field = transformed;
1710 } else {
1711 field = objectset;
1712 }
1713
1714 for (; field; field = field->next) {
1715 if ((res = aco_process_var(&object_type->type, details->object->id, field, object))) {
1716 break;
1717 }
1718 }
1719
1720 if (!res && object_type->apply) {
1721 res = object_type->apply(sorcery, object);
1722 }
1723
1724 return res;
1725}
1726
1727int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
1728{
1729 const struct ast_variable *field;
1730 int res = 0;
1731
1732 *changes = NULL;
1733
1734 /* Unless the ast_variable list changes when examined... it can't differ from itself */
1735 if (original == modified) {
1736 return 0;
1737 }
1738
1739 for (field = modified; field; field = field->next) {
1740 const char *old_value = ast_variable_find_in_list(original, field->name);
1741
1742 if (!old_value || strcmp(old_value, field->value)) {
1743 struct ast_variable *tmp;
1744
1745 if (!(tmp = ast_variable_new(field->name, field->value, ""))) {
1746 res = -1;
1747 break;
1748 }
1749
1750 tmp->next = *changes;
1751 *changes = tmp;
1752 }
1753 }
1754
1755 /* If an error occurred do not return a partial changeset */
1756 if (res) {
1757 ast_variables_destroy(*changes);
1758 *changes = NULL;
1759 }
1760
1761 return res;
1762}
1763
1764static void sorcery_object_destructor(void *object)
1765{
1766 struct ast_sorcery_object_details *details = object;
1767
1768 if (details->object->destructor) {
1769 details->object->destructor(object);
1770 }
1771
1773 ast_free(details->object->id);
1774}
1775
1776void *ast_sorcery_lockable_alloc(size_t size, ao2_destructor_fn destructor, void *lockobj)
1777{
1778 void *object = ao2_alloc_with_lockobj(size + sizeof(struct ast_sorcery_object),
1779 sorcery_object_destructor, lockobj, "");
1780 struct ast_sorcery_object_details *details = object;
1781
1782 if (!object) {
1783 return NULL;
1784 }
1785
1786 details->object = object + size;
1787 details->object->destructor = destructor;
1788
1789 return object;
1790}
1791
1792void *ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
1793{
1794 void *object = ao2_alloc_options(size + sizeof(struct ast_sorcery_object),
1796 struct ast_sorcery_object_details *details = object;
1797
1798 if (!object) {
1799 return NULL;
1800 }
1801
1802 details->object = object + size;
1803 details->object->destructor = destructor;
1804
1805 return object;
1806}
1807
1808void *ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
1809{
1811 struct ast_sorcery_object_details *details;
1812
1813 if (!object_type || !object_type->type.item_alloc ||
1814 !(details = object_type->type.item_alloc(id))) {
1815 return NULL;
1816 }
1817
1818 if (ast_strlen_zero(id)) {
1819 char uuid[AST_UUID_STR_LEN];
1820
1822 details->object->id = ast_strdup(uuid);
1823 } else {
1824 details->object->id = ast_strdup(id);
1825 }
1826 if (!details->object->id) {
1827 ao2_ref(details, -1);
1828 return NULL;
1829 }
1830
1831 details->object->created = ast_tvnow();
1832 ast_copy_string(details->object->type, type, sizeof(details->object->type));
1833
1834 if (aco_set_defaults(&object_type->type, id, details)) {
1835 ao2_ref(details, -1);
1836 return NULL;
1837 }
1838
1839 return details;
1840}
1841
1842void *ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
1843{
1844 const struct ast_sorcery_object_details *details = object;
1845 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
1847 RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
1848 int res = 0;
1849
1850 if (!copy) {
1851 return NULL;
1852 } else if (object_type->copy) {
1853 res = object_type->copy(object, copy);
1854 } else if ((objectset = ast_sorcery_objectset_create(sorcery, object))) {
1855 res = ast_sorcery_objectset_apply(sorcery, copy, objectset);
1856 } else {
1857 /* No native copy available and could not create an objectset, this copy has failed */
1858 res = -1;
1859 }
1860
1861 if (res) {
1863 copy = NULL;
1864 }
1865
1866 return copy;
1867}
1868
1869int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
1870{
1872
1873 *changes = NULL;
1874
1875 if (strcmp(ast_sorcery_object_get_type(original), ast_sorcery_object_get_type(modified))) {
1876 return -1;
1877 }
1878
1879 if (original == modified) {
1880 return 0;
1881 } else if (!object_type->diff) {
1882 RAII_VAR(struct ast_variable *, objectset1, NULL, ast_variables_destroy);
1883 RAII_VAR(struct ast_variable *, objectset2, NULL, ast_variables_destroy);
1884
1885 objectset1 = ast_sorcery_objectset_create(sorcery, original);
1886 objectset2 = ast_sorcery_objectset_create(sorcery, modified);
1887
1888 return ast_sorcery_changeset_create(objectset1, objectset2, changes);
1889 } else {
1890 return object_type->diff(original, modified, changes);
1891 }
1892}
1893
1894/*! \brief Structure used when calling create, update, or delete */
1896 /*! \brief Pointer to the sorcery instance */
1897 const struct ast_sorcery *sorcery;
1898 /*! \brief Pointer to the object itself */
1899 void *obj;
1900};
1901
1902/*! \brief Internal function used to create an object in caching wizards */
1903static int sorcery_cache_create(void *obj, void *arg, int flags)
1904{
1905 const struct ast_sorcery_object_wizard *object_wizard = obj;
1906 const struct sorcery_details *details = arg;
1907
1908 if (!object_wizard->caching || !object_wizard->wizard->callbacks.create) {
1909 return 0;
1910 }
1911
1912 object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj);
1913
1914 return 0;
1915}
1916
1917void *ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
1918{
1919 struct ast_sorcery_object_type *object_type;
1920 void *object = NULL;
1921 int i;
1922 unsigned int cached = 0;
1923
1924 if (ast_strlen_zero(id)) {
1925 return NULL;
1926 }
1927
1928 object_type = ao2_find(sorcery->types, type, OBJ_SEARCH_KEY);
1929 if (!object_type) {
1930 return NULL;
1931 }
1932
1933 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1934 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1936 AST_VECTOR_GET(&object_type->wizards, i);
1937
1938 if (wizard->wizard->callbacks.retrieve_id &&
1939 !(object = wizard->wizard->callbacks.retrieve_id(sorcery, wizard->data, object_type->name, id))) {
1940 continue;
1941 }
1942
1943 cached = wizard->caching;
1944 break;
1945 }
1946
1947 if (!cached && object) {
1948 struct sorcery_details sdetails = {
1949 .sorcery = sorcery,
1950 .obj = object,
1951 };
1952
1953 AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, &sdetails, 0);
1954 }
1955 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
1956
1957 ao2_ref(object_type, -1);
1958 return object;
1959}
1960
1961void *ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
1962{
1964 void *object = NULL;
1965 int i;
1966 unsigned int cached = 0;
1967
1968 if (!object_type) {
1969 return NULL;
1970 }
1971
1972 /* If returning multiple objects create a container to store them in */
1973 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1975 if (!object) {
1976 return NULL;
1977 }
1978 }
1979
1980 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
1981 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
1983 AST_VECTOR_GET(&object_type->wizards, i);
1984
1985 if ((flags & AST_RETRIEVE_FLAG_MULTIPLE)) {
1986 if (wizard->wizard->callbacks.retrieve_multiple) {
1987 wizard->wizard->callbacks.retrieve_multiple(sorcery, wizard->data, object_type->name, object, fields);
1988 }
1989 } else if (fields && wizard->wizard->callbacks.retrieve_fields) {
1990 if (wizard->wizard->callbacks.retrieve_fields) {
1991 object = wizard->wizard->callbacks.retrieve_fields(sorcery, wizard->data, object_type->name, fields);
1992 }
1993 }
1994
1995 if (((flags & AST_RETRIEVE_FLAG_MULTIPLE) && (!ao2_container_count(object) || !wizard->caching)) || !object) {
1996 continue;
1997 }
1998
1999 cached = wizard->caching;
2000
2001 break;
2002 }
2003
2004 /* If we are returning a single object and it came from a non-cache source create it in any caches */
2005 if (!(flags & AST_RETRIEVE_FLAG_MULTIPLE) && !cached && object) {
2006 struct sorcery_details sdetails = {
2007 .sorcery = sorcery,
2008 .obj = object,
2009 };
2010
2011 AST_VECTOR_CALLBACK(&object_type->wizards, sorcery_cache_create, NULL, &sdetails, 0);
2012 }
2013 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2014
2015 return object;
2016}
2017
2018struct ao2_container *ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
2019{
2021 struct ao2_container *objects;
2022 int i;
2023
2024 if (!object_type) {
2025 return NULL;
2026 }
2027
2029 if (!objects) {
2030 return NULL;
2031 }
2032
2033 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2034 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2036 AST_VECTOR_GET(&object_type->wizards, i);
2037
2038 if (!wizard->wizard->callbacks.retrieve_regex) {
2039 continue;
2040 }
2041
2042 wizard->wizard->callbacks.retrieve_regex(sorcery, wizard->data, object_type->name, objects, regex);
2043
2044 if (wizard->caching && ao2_container_count(objects)) {
2045 break;
2046 }
2047 }
2048 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2049
2050 return objects;
2051}
2052
2053struct ao2_container *ast_sorcery_retrieve_by_prefix(const struct ast_sorcery *sorcery, const char *type, const char *prefix, const size_t prefix_len)
2054{
2056 struct ao2_container *objects;
2057 int i;
2058
2059 if (!object_type) {
2060 return NULL;
2061 }
2062
2064 if (!objects) {
2065 return NULL;
2066 }
2067
2068 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2069 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2071 AST_VECTOR_GET(&object_type->wizards, i);
2072
2073 if (!wizard->wizard->callbacks.retrieve_prefix) {
2074 continue;
2075 }
2076
2077 wizard->wizard->callbacks.retrieve_prefix(sorcery, wizard->data, object_type->name, objects, prefix, prefix_len);
2078
2079 if (wizard->caching && ao2_container_count(objects)) {
2080 break;
2081 }
2082 }
2083 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2084
2085 return objects;
2086}
2087
2088/*! \brief Internal function which returns if the wizard has created the object */
2089static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
2090{
2091 if (!object_wizard->wizard->callbacks.create || object_wizard->read_only) {
2092 ast_debug(5, "Sorcery wizard '%s' does not support creation\n", object_wizard->wizard->callbacks.name);
2093 return 0;
2094 }
2095
2096 if (object_wizard->wizard->callbacks.create(details->sorcery, object_wizard->data, details->obj)) {
2097 return 0;
2098 }
2099
2100 return CMP_MATCH;
2101}
2102
2103/*! \brief Internal callback function which notifies an individual observer that an object has been created */
2104static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
2105{
2106 const struct ast_sorcery_object_type_observer *observer = obj;
2107
2108 if (observer->callbacks->created) {
2109 observer->callbacks->created(arg);
2110 }
2111
2112 return 0;
2113}
2114
2115/*! \brief Internal callback function which notifies observers that an object has been created */
2117{
2118 struct sorcery_observer_invocation *invocation = data;
2119
2121 ao2_cleanup(invocation);
2122
2123 return 0;
2124}
2125
2126int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
2127{
2128 const struct ast_sorcery_object_details *details = object;
2129 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2130 struct ast_sorcery_object_wizard *object_wizard = NULL;
2131 struct ast_sorcery_object_wizard *found_wizard;
2132 int i;
2133 struct sorcery_details sdetails = {
2134 .sorcery = sorcery,
2135 .obj = object,
2136 };
2137
2138 if (!object_type) {
2139 return -1;
2140 }
2141
2142 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2143 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2144 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2145 if (!found_wizard->caching
2146 && sorcery_wizard_create(found_wizard, &sdetails) == CMP_MATCH) {
2147 object_wizard = found_wizard;
2148 }
2149 }
2150
2151 if (object_wizard) {
2152 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2153 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2154 if (found_wizard->caching) {
2155 sorcery_wizard_create(found_wizard, &sdetails);
2156 }
2157 }
2158
2159 if (ao2_container_count(object_type->observers)) {
2160 struct sorcery_observer_invocation *invocation;
2161
2162 invocation = sorcery_observer_invocation_alloc(object_type, object);
2163 if (invocation
2165 invocation)) {
2166 ao2_cleanup(invocation);
2167 }
2168 }
2169 }
2170
2172
2173 return object_wizard ? 0 : -1;
2174}
2175
2176/*! \brief Internal callback function which notifies an individual observer that an object has been updated */
2177static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
2178{
2179 const struct ast_sorcery_object_type_observer *observer = obj;
2180
2181 if (observer->callbacks->updated) {
2182 observer->callbacks->updated(arg);
2183 }
2184
2185 return 0;
2186}
2187
2188/*! \brief Internal callback function which notifies observers that an object has been updated */
2190{
2191 struct sorcery_observer_invocation *invocation = data;
2192
2194 ao2_cleanup(invocation);
2195
2196 return 0;
2197}
2198
2199/*! \brief Internal function which returns if a wizard has updated the object */
2200static int sorcery_wizard_update(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
2201{
2202 if (!object_wizard->wizard->callbacks.update || object_wizard->read_only) {
2203 ast_debug(5, "Sorcery wizard '%s' does not support updating\n", object_wizard->wizard->callbacks.name);
2204 return 0;
2205 }
2206
2207 if (object_wizard->wizard->callbacks.update(details->sorcery, object_wizard->data, details->obj)) {
2208 return 0;
2209 }
2210
2211 return CMP_MATCH;
2212}
2213
2214int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
2215{
2216 const struct ast_sorcery_object_details *details = object;
2217 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2218 struct ast_sorcery_object_wizard *object_wizard = NULL;
2219 struct ast_sorcery_object_wizard *found_wizard;
2220 int i;
2221 struct sorcery_details sdetails = {
2222 .sorcery = sorcery,
2223 .obj = object,
2224 };
2225
2226 if (!object_type) {
2227 return -1;
2228 }
2229
2230 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2231 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2232 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2233 if (!found_wizard->caching
2234 && sorcery_wizard_update(found_wizard, &sdetails) == CMP_MATCH) {
2235 object_wizard = found_wizard;
2236 }
2237 }
2238
2239 if (object_wizard) {
2240 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2241 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2242 if (found_wizard->caching) {
2243 sorcery_wizard_update(found_wizard, &sdetails);
2244 }
2245 }
2246
2247 if (ao2_container_count(object_type->observers)) {
2248 struct sorcery_observer_invocation *invocation;
2249
2250 invocation = sorcery_observer_invocation_alloc(object_type, object);
2251 if (invocation
2253 invocation)) {
2254 ao2_cleanup(invocation);
2255 }
2256 }
2257 }
2258
2260
2261 return object_wizard ? 0 : -1;
2262}
2263
2264/*! \brief Internal callback function which notifies an individual observer that an object has been deleted */
2265static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
2266{
2267 const struct ast_sorcery_object_type_observer *observer = obj;
2268
2269 if (observer->callbacks->deleted) {
2270 observer->callbacks->deleted(arg);
2271 }
2272
2273 return 0;
2274}
2275
2276/*! \brief Internal callback function which notifies observers that an object has been deleted */
2278{
2279 struct sorcery_observer_invocation *invocation = data;
2280
2282 ao2_cleanup(invocation);
2283
2284 return 0;
2285}
2286
2287/*! \brief Internal function which returns if a wizard has deleted the object */
2288static int sorcery_wizard_delete(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
2289{
2290 if (!object_wizard->wizard->callbacks.delete || object_wizard->read_only) {
2291 ast_debug(5, "Sorcery wizard '%s' does not support deletion\n", object_wizard->wizard->callbacks.name);
2292 return 0;
2293 }
2294
2295 if (object_wizard->wizard->callbacks.delete(details->sorcery, object_wizard->data, details->obj)) {
2296 return 0;
2297 }
2298
2299 return CMP_MATCH;
2300}
2301
2302int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
2303{
2304 const struct ast_sorcery_object_details *details = object;
2305 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2306 struct ast_sorcery_object_wizard *object_wizard = NULL;
2307 struct ast_sorcery_object_wizard *found_wizard;
2308 int i;
2309 struct sorcery_details sdetails = {
2310 .sorcery = sorcery,
2311 .obj = object,
2312 };
2313
2314 if (!object_type) {
2315 return -1;
2316 }
2317
2318 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2319 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2320 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2321 if (!found_wizard->caching
2322 && sorcery_wizard_delete(found_wizard, &sdetails) == CMP_MATCH) {
2323 object_wizard = found_wizard;
2324 }
2325 }
2326
2327 if (object_wizard) {
2328 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2329 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2330 if (found_wizard->caching) {
2331 sorcery_wizard_delete(found_wizard, &sdetails);
2332 }
2333 }
2334
2335 if (ao2_container_count(object_type->observers)) {
2336 struct sorcery_observer_invocation *invocation;
2337
2338 invocation = sorcery_observer_invocation_alloc(object_type, object);
2339 if (invocation
2341 invocation)) {
2342 ao2_cleanup(invocation);
2343 }
2344 }
2345 }
2346
2348
2349 return object_wizard ? 0 : -1;
2350}
2351
2352int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object)
2353{
2354 const struct ast_sorcery_object_details *details = object;
2355 RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, details->object->type, OBJ_KEY), ao2_cleanup);
2356 struct ast_sorcery_object_wizard *found_wizard;
2357 int res = 0;
2358 int i;
2359
2360 if (!object_type) {
2361 return -1;
2362 }
2363
2364 AST_VECTOR_RW_RDLOCK(&object_type->wizards);
2365 for (i = 0; i < AST_VECTOR_SIZE(&object_type->wizards); i++) {
2366 found_wizard = AST_VECTOR_GET(&object_type->wizards, i);
2367
2368 if (found_wizard->wizard->callbacks.is_stale) {
2369 res |= found_wizard->wizard->callbacks.is_stale(sorcery, found_wizard->data, object);
2370 ast_debug(5, "After calling wizard '%s', object '%s' is %s\n",
2371 found_wizard->wizard->callbacks.name,
2373 res ? "stale" : "not stale");
2374 }
2375 }
2376 AST_VECTOR_RW_UNLOCK(&object_type->wizards);
2377
2378 return res;
2379}
2380
2381const char *ast_sorcery_object_get_id(const void *object)
2382{
2383 const struct ast_sorcery_object_details *details = object;
2384 return details->object->id;
2385}
2386
2387const struct timeval ast_sorcery_object_get_created(const void *object)
2388{
2389 const struct ast_sorcery_object_details *details = object;
2390 return details->object->created;
2391}
2392
2393const char *ast_sorcery_object_get_type(const void *object)
2394{
2395 const struct ast_sorcery_object_details *details = object;
2396 return details->object->type;
2397}
2398
2399const char *ast_sorcery_object_get_extended(const void *object, const char *name)
2400{
2401 const struct ast_sorcery_object_details *details = object;
2402 struct ast_variable *field;
2403
2404 for (field = details->object->extended; field; field = field->next) {
2405 if (!strcmp(field->name + 1, name)) {
2406 return field->value;
2407 }
2408 }
2409
2410 return NULL;
2411}
2412
2413int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
2414{
2416 struct ast_variable *extended = ast_variable_new(name, value, ""), *previous = NULL;
2417 const struct ast_sorcery_object_details *details = object;
2418
2419 if (!extended) {
2420 return -1;
2421 }
2422
2423 for (field = details->object->extended; field; previous = field, field = field->next) {
2424 if (!strcmp(field->name, name)) {
2425 if (previous) {
2426 previous->next = field->next;
2427 } else {
2428 details->object->extended = field->next;
2429 }
2430 field->next = NULL;
2431 break;
2432 }
2433 }
2434
2435 extended->next = details->object->extended;
2436 details->object->extended = extended;
2437
2438 return 0;
2439}
2440
2441unsigned int ast_sorcery_object_has_dynamic_contents(const void *object)
2442{
2443 const struct ast_sorcery_object_details *details = object;
2444
2445 return details->object->has_dynamic_contents;
2446}
2447
2449{
2450 const struct ast_sorcery_object_details *details = object;
2451
2452 details->object->has_dynamic_contents = 1;
2453}
2454
2456{
2459 int res;
2460
2461 if (!object_type || !callbacks) {
2462 return -1;
2463 }
2464
2465 if (!(observer = ao2_alloc(sizeof(*observer), NULL))) {
2466 return -1;
2467 }
2468
2469 observer->callbacks = callbacks;
2470 res = 0;
2471 if (!ao2_link(object_type->observers, observer)) {
2472 res = -1;
2473 }
2474 ao2_ref(observer, -1);
2475
2476 return res;
2477}
2478
2479/*! \brief Internal callback function for removing an observer */
2480static int sorcery_observer_remove(void *obj, void *arg, int flags)
2481{
2482 const struct ast_sorcery_object_type_observer *observer = obj;
2483
2484 return (observer->callbacks == arg) ? CMP_MATCH : 0;
2485}
2486
2488{
2489 RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
2490 struct ast_sorcery_observer *cbs = (struct ast_sorcery_observer *) callbacks;/* Remove const for traversal. */
2491
2492 if (!sorcery) {
2493 return;
2494 }
2495 object_type = ao2_find(sorcery->types, type, OBJ_KEY);
2496 if (!object_type) {
2497 return;
2498 }
2499
2500 ao2_callback(object_type->observers, OBJ_NODATA | OBJ_UNLINK,
2502}
2503
2504int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
2505{
2506 const void *object_left = obj;
2507 const void *object_right = arg;
2508 const char *right_key = arg;
2509 int cmp;
2510
2511 switch (flags & OBJ_SEARCH_MASK) {
2512 case OBJ_SEARCH_OBJECT:
2513 right_key = ast_sorcery_object_get_id(object_right);
2514 /* Fall through */
2515 case OBJ_SEARCH_KEY:
2516 cmp = strcmp(ast_sorcery_object_get_id(object_left), right_key);
2517 break;
2519 cmp = strncmp(ast_sorcery_object_get_id(object_left), right_key, strlen(right_key));
2520 break;
2521 default:
2522 cmp = 0;
2523 break;
2524 }
2525 return cmp;
2526}
2527
2528int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
2529{
2530 int cmp;
2531
2532 cmp = ast_sorcery_object_id_sort(obj, arg, flags);
2533 if (cmp) {
2534 return 0;
2535 }
2536 return CMP_MATCH;
2537}
2538
2539int ast_sorcery_object_id_hash(const void *obj, int flags)
2540{
2541 const char *key;
2542
2543 switch (flags & OBJ_SEARCH_MASK) {
2544 case OBJ_SEARCH_KEY:
2545 key = obj;
2546 break;
2547 case OBJ_SEARCH_OBJECT:
2548 key = ast_sorcery_object_get_id(obj);
2549 break;
2550 default:
2551 /* Hash can only work on something with a full key. */
2552 ast_assert(0);
2553 return 0;
2554 }
2555 return ast_str_hash(key);
2556}
2557
2559 const char *type)
2560{
2562}
2563
2564static int is_registered_cb(void *obj, void *arg, int flags)
2565{
2566 struct ast_sorcery_object_field *object_field = obj;
2567 char *name = arg;
2568 int rc = 0;
2569
2570 if (object_field->name_regex
2571 && !regexec(object_field->name_regex, name, 0, NULL, 0)) {
2572 rc = CMP_MATCH;
2573 }
2574
2575 return rc;
2576}
2577
2579 const char *field_name)
2580{
2581 struct ast_sorcery_object_field *object_field;
2582 int res = 1;
2583
2584 ast_assert(object_type != NULL);
2585
2586 object_field = ao2_find(object_type->fields, field_name, OBJ_SEARCH_KEY);
2587
2588 if (!object_field) {
2589 object_field = ao2_callback(object_type->fields, 0, is_registered_cb, (char *)field_name);
2590 }
2591
2592 if (!object_field) {
2593 res = 0;
2594 }
2595
2596 ao2_cleanup(object_field);
2597 return res;
2598}
2599
2601{
2602 return sorcery->module_name;
2603}
void ast_cli_unregister_multiple(void)
Definition ael_main.c:408
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition ast_expr2f.c:605
if(!yyg->yy_init)
Definition ast_expr2f.c:854
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
int ast_register_cleanup(void(*func)(void))
Register a function to be executed before Asterisk gracefully exits.
Definition clicompat.c:19
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_free(a)
Definition astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition astmm.h:267
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
#define ast_log
Definition astobj2.c:42
int ao2_weakproxy_subscribe(void *weakproxy, ao2_weakproxy_notification_cb cb, void *data, int flags)
Request notification when weakproxy points to NULL.
Definition astobj2.c:934
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ CMP_MATCH
Definition astobj2.h:1027
#define OBJ_KEY
Definition astobj2.h:1151
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition astobj2.h:365
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition astobj2.h:363
#define ao2_wrlock(a)
Definition astobj2.h:719
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define AO2_STRING_FIELD_CMP_FN(stype, field)
Creates a compare function for a structure string field.
Definition astobj2.h:2048
#define ao2_cleanup(obj)
Definition astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
#define ao2_unlink_flags(container, obj, flags)
Remove an object from a container.
Definition astobj2.h:1600
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition astobj2.h:1554
void(* ao2_destructor_fn)(void *vdoomed)
Typedef for an object destructor.
Definition astobj2.h:358
#define ao2_alloc_with_lockobj(data_size, destructor_fn, lockobj, tag)
Allocate and initialize an object with separate locking.
Definition astobj2.h:431
#define ao2_find(container, arg, flags)
Definition astobj2.h:1736
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_t_weakproxy_alloc(data_size, destructor_fn, tag)
Definition astobj2.h:553
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_weakproxy_find(c, arg, flags, tag)
Perform an ao2_find on a container with ao2_weakproxy objects, returning the real object.
Definition astobj2.h:1748
#define ao2_lock(a)
Definition astobj2.h:717
void * __ao2_weakproxy_find(struct ao2_container *c, const void *arg, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition astobj2.h:404
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition astobj2.h:480
#define AO2_STRING_FIELD_HASH_FN(stype, field)
Creates a hash function for a structure string field.
Definition astobj2.h:2032
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition astobj2.h:1087
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition astobj2.h:1063
@ OBJ_NODATA
Definition astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition astobj2.h:1072
@ OBJ_UNLINK
Definition astobj2.h:1039
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition astobj2.h:1101
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
void * __ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result
Definition astobj2.c:768
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition astobj2.h:1303
#define ao2_t_weakproxy_set_object(weakproxy, obj, flags, tag)
Definition astobj2.h:582
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition astobj2.h:1188
static const char type[]
static const char config[]
Standard Command Line Interface.
#define CLI_SUCCESS
Definition cli.h:44
#define AST_CLI_DEFINE(fn, txt,...)
Definition cli.h:197
void ast_cli(int fd, const char *fmt,...)
Definition clicompat.c:6
@ CLI_INIT
Definition cli.h:152
@ CLI_GENERATE
Definition cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition cli.h:265
Configuration option-handling.
int(* aco_option_handler)(const struct aco_option *opt, struct ast_variable *var, void *obj)
A callback function for handling a particular option.
@ ACO_EXACT
@ ACO_REGEX
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
aco_option_type
The option types.
@ OPT_UINT_T
Type for default option handler for unsigned integers.
@ OPT_CODEC_T
Type for default option handler for format capabilities.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_CUSTOM_T
Type for a custom (user-defined) option handler.
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_SOCKADDR_T
Type for default handler for ast_sockaddrs.
@ OPT_YESNO_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_INT_T
Type for default option handler for signed integers.
@ OPT_DOUBLE_T
Type for default option handler for doubles.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
void *(* aco_type_item_alloc)(const char *category)
Allocate a configurable ao2 object.
@ ACO_ITEM
int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
Parse a single ast_variable and apply it to an object.
int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype match_type, struct aco_type **types, const char *default_val, enum aco_option_type type, aco_option_handler handler, unsigned int flags, unsigned int no_doc, size_t argc,...)
register a config option
char buf[BUFSIZE]
Definition eagi_proxy.c:66
Media Format API.
Format Capabilities API.
#define AST_FORMAT_CAP_NAMES_LEN
Definition format_cap.h:324
const char * ast_format_cap_get_names(const struct ast_format_cap *cap, struct ast_str **buf)
Get the names of codecs of a set of formats.
Definition format_cap.c:734
static const char name[]
Definition format_mp3.c:68
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int uuid(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
Definition func_uuid.c:52
static char prefix[MAX_PREFIX]
Definition http.c:144
struct ast_config * ast_config_load2(const char *filename, const char *who_asked, struct ast_flags flags)
Load a config file.
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.
#define ast_variable_new(name, value, filename)
#define CONFIG_STATUS_FILEINVALID
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition extconf.c:1287
struct ast_variable * ast_variable_list_append_hint(struct ast_variable **head, struct ast_variable *search_hint, struct ast_variable *new_var)
Appends a variable list to the end of another list.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition extconf.c:1213
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_NOTICE
#define LOG_WARNING
Asterisk JSON abstraction layer.
struct ast_json * ast_json_string_create(const char *value)
Construct a JSON string from value.
Definition json.c:278
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition json.c:73
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition json.c:399
int ast_json_object_set(struct ast_json *object, const char *key, struct ast_json *value)
Set a field in a JSON object.
Definition json.c:414
Asterisk module definitions.
#define ast_module_unref(mod)
Release a reference to the module.
Definition module.h:483
#define ast_module_running_ref(mod)
Hold a reference to the module if it is running.
Definition module.h:469
Network socket handling.
static char * ast_sockaddr_stringify(const struct ast_sockaddr *addr)
Wrapper around ast_sockaddr_stringify_fmt() with default format.
Definition netsock2.h:256
static struct ast_sorcery * sorcery
struct ast_sorcery_instance_observer observer
struct @506 callbacks
static struct @519 args
#define NULL
Definition resample.c:96
#define INSTANCE_BUCKETS
Number of buckets for instances (should be prime for performance reasons)
Definition sorcery.c:58
const char * ast_sorcery_object_get_extended(const void *object, const char *name)
Get an extended field value from a sorcery object.
Definition sorcery.c:2399
static int int_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:290
static void parse_general_options(void)
Compare function for sorcery instances.
Definition sorcery.c:425
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
static int sorcery_observer_notify_delete(void *obj, void *arg, int flags)
Internal callback function which notifies an individual observer that an object has been deleted.
Definition sorcery.c:2265
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition sorcery.c:538
static int sorcery_observers_notify_create(void *data)
Internal callback function which notifies observers that an object has been created.
Definition sorcery.c:2116
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:2487
static struct ast_cli_entry cli_commands[]
Definition sorcery.c:397
int ast_sorcery_object_fields_register(struct ast_sorcery *sorcery, const char *type, const char *regex, aco_option_handler config_handler, sorcery_fields_handler sorcery_handler)
Register a regex for multiple fields within an object.
Definition sorcery.c:1224
int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value)
Set an extended field value on a sorcery object.
Definition sorcery.c:2413
void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Remove an observer from a sorcery instance.
Definition sorcery.c:601
#define WIZARD_NAME_COMPARE(a, b)
enum ast_sorcery_apply_result __ast_sorcery_apply_default(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data)
Apply default object wizard mappings.
Definition sorcery.c:1095
static int sorcery_observer_notify_update(void *obj, void *arg, int flags)
Internal callback function which notifies an individual observer that an object has been updated.
Definition sorcery.c:2177
void ast_sorcery_load(const struct ast_sorcery *sorcery)
Inform any wizards to load persistent objects.
Definition sorcery.c:1441
void ast_sorcery_wizard_observer_remove(struct ast_sorcery_wizard *interface, const struct ast_sorcery_wizard_observer *callbacks)
Remove an observer from a sorcery wizard.
Definition sorcery.c:632
static int sorcery_cache_create(void *obj, void *arg, int flags)
Internal function used to create an object in caching wizards.
Definition sorcery.c:1903
const char * ast_sorcery_get_module(const struct ast_sorcery *sorcery)
Get the module that has opened the provided sorcery instance.
Definition sorcery.c:2600
static int chararray_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:332
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition sorcery.c:2393
int ast_sorcery_update_or_create_on_update_miss
Global control for optional update->create fallback in backends.
Definition sorcery.c:288
static int sorcery_observers_notify_delete(void *data)
Internal callback function which notifies observers that an object has been deleted.
Definition sorcery.c:2277
#define NOTIFY_GLOBAL_OBSERVERS(container, callback,...)
Definition sorcery.c:77
static void sorcery_destructor(void *obj)
Destructor called when sorcery structure is destroyed.
Definition sorcery.c:645
#define INITIAL_WIZARD_VECTOR_SIZE
#define MAX_REGEX_ERROR_LEN
void ast_sorcery_object_set_copy_handler(struct ast_sorcery *sorcery, const char *type, sorcery_copy_handler copy)
Set the copy handler for an object type.
Definition sorcery.c:1192
void ast_sorcery_object_set_has_dynamic_contents(const void *object)
Set the dynamic contents flag on a sorcery object.
Definition sorcery.c:2448
static int stringfield_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:308
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition sorcery.c:2126
static int codec_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:338
struct ast_sorcery_object_type * ast_sorcery_get_object_type(const struct ast_sorcery *sorcery, const char *type)
Get the sorcery object type given a type name.
Definition sorcery.c:2558
#define WIZARD_BUCKETS
Number of buckets for wizards (should be prime for performance reasons)
Definition sorcery.c:52
int ast_sorcery_diff(const struct ast_sorcery *sorcery, const void *original, const void *modified, struct ast_variable **changes)
Create a changeset of two objects.
Definition sorcery.c:1869
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:1917
void ast_sorcery_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects.
Definition sorcery.c:1472
int ast_sorcery_get_wizard_mapping_count(struct ast_sorcery *sorcery, const char *type)
Return the number of wizards mapped to an object type.
Definition sorcery.c:842
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:2018
int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
Register a sorcery wizard.
Definition sorcery.c:496
static void sorcery_object_type_destructor(void *obj)
Destructor function for object types.
Definition sorcery.c:742
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:2455
static int sorcery_observer_remove(void *obj, void *arg, int flags)
Internal callback function for removing an observer.
Definition sorcery.c:2480
enum ast_sorcery_apply_result __ast_sorcery_insert_wizard_mapping(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data, unsigned int caching, int position)
Internal function which creates an object type and inserts a wizard mapping.
Definition sorcery.c:1031
void ast_sorcery_force_reload(const struct ast_sorcery *sorcery)
Inform any wizards to reload persistent objects, even if no changes determined.
Definition sorcery.c:1489
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
Definition sorcery.c:1457
static struct ast_variable * get_single_field_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
Definition sorcery.c:1542
#define WIZARD_COMPARE(a, b)
static struct ast_variable * get_multiple_fields_as_var_list(const void *object, struct ast_sorcery_object_field *object_field)
Definition sorcery.c:1559
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition sorcery.c:1792
static int sorcery_wizard_load(void *obj, void *arg, int flags)
Definition sorcery.c:1317
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Definition sorcery.c:1125
static int sorcery_generic_observer_remove(void *obj, void *arg, int flags)
Internal callback function for removing a generic observer.
Definition sorcery.c:555
int __ast_sorcery_remove_wizard_mapping(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name)
Internal function removes a wizard mapping.
Definition sorcery.c:914
static void sorcery_proxy_cb(void *weakproxy, void *data)
Hashing function for sorcery types.
Definition sorcery.c:660
static int sorcery_observer_notify_loaded(void *obj, void *arg, int flags)
Internal callback function which notifies an individual observer that an object type has been loaded.
Definition sorcery.c:1378
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
static int yesno_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:320
static int bool_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:314
static struct ast_taskpool * taskpool
Taskpool for observers.
Definition sorcery.c:87
static int sorcery_extended_fields_handler(const void *obj, struct ast_variable **fields)
Definition sorcery.c:1112
unsigned int ast_sorcery_object_has_dynamic_contents(const void *object)
Get whether an object contains dynamic contents or not.
Definition sorcery.c:2441
void ast_sorcery_ref(struct ast_sorcery *sorcery)
Increase the reference count of a sorcery structure.
Definition sorcery.c:1537
static int uint_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:296
int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char *type, const char *name, const char *default_val, enum aco_option_type opt_type, aco_option_handler config_handler, sorcery_field_handler sorcery_handler, sorcery_fields_handler multiple_handler, unsigned int flags, unsigned int no_doc, unsigned int alias, size_t argc,...)
Register a field within an object.
Definition sorcery.c:1256
int ast_sorcery_wizard_observer_add(struct ast_sorcery_wizard *interface, const struct ast_sorcery_wizard_observer *callbacks)
Add an observer to a sorcery wizard.
Definition sorcery.c:607
static void sorcery_object_destructor(void *object)
Definition sorcery.c:1764
int __ast_sorcery_object_register(struct ast_sorcery *sorcery, const char *type, unsigned int hidden, unsigned int reloadable, aco_type_item_alloc alloc, sorcery_transform_handler transform, sorcery_apply_handler apply)
Register an object type.
Definition sorcery.c:1144
static int sorcery_wizard_create(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
Internal function which returns if the wizard has created the object.
Definition sorcery.c:2089
int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
Create a changeset given two object sets.
Definition sorcery.c:1727
#define NOTIFY_INSTANCE_OBSERVERS(container, callback,...)
Definition sorcery.c:80
static int sorcery_reloadable(const struct ast_sorcery *sorcery, const char *type)
Retrieves whether or not the type is reloadable.
Definition sorcery.c:1310
static char * cli_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Hashing and comparison functions for sorcery wizards.
Definition sorcery.c:376
static int sorcery_object_load(void *obj, void *arg, int flags)
Definition sorcery.c:1400
static struct ao2_container * wizards
Registered sorcery wizards.
Definition sorcery.c:258
enum ast_sorcery_apply_result __ast_sorcery_apply_config(struct ast_sorcery *sorcery, const char *name, const char *module)
Apply configured wizard mappings.
Definition sorcery.c:1049
int ast_sorcery_is_object_field_registered(const struct ast_sorcery_object_type *object_type, const char *field_name)
Determine if a particular object field has been registered with sorcery.
Definition sorcery.c:2578
static struct ao2_container * instances
Registered sorcery instances.
Definition sorcery.c:285
static int sockaddr_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:326
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition sorcery.c:1808
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
Definition sorcery.c:2504
const struct timeval ast_sorcery_object_get_created(const void *object)
Get when the sorcery object was created.
Definition sorcery.c:2387
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:1776
#define OBJECT_FIELD_BUCKETS
Number of buckets for object fields (should be prime for performance reasons)
Definition sorcery.c:61
struct ao2_container * observers
Registered global observers.
Definition sorcery.c:282
static int sorcery_observer_notify_create(void *obj, void *arg, int flags)
Internal callback function which notifies an individual observer that an object has been created.
Definition sorcery.c:2104
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition sorcery.c:2214
static int sorcery_extended_config_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Definition sorcery.c:1107
int ast_sorcery_objectset_apply(const struct ast_sorcery *sorcery, void *object, struct ast_variable *objectset)
Apply an object set (KVP list) to an object.
Definition sorcery.c:1696
int ast_sorcery_get_wizard_mapping(struct ast_sorcery *sorcery, const char *type, int index, struct ast_sorcery_wizard **wizard, void **data)
By index, return a wizard mapped to an object type.
Definition sorcery.c:854
static int sorcery_wizard_update(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
Internal function which returns if a wizard has updated the object.
Definition sorcery.c:2200
void ast_sorcery_force_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects even if no changes determin...
Definition sorcery.c:1521
static void sorcery_observer_invocation_destroy(void *obj)
Destructor for observer invocation.
Definition sorcery.c:1347
static struct sorcery_observer_invocation * sorcery_observer_invocation_alloc(struct ast_sorcery_object_type *object_type, void *object)
Allocator function for observer invocation.
Definition sorcery.c:1356
enum ast_sorcery_apply_result __ast_sorcery_apply_wizard_mapping(struct ast_sorcery *sorcery, const char *type, const char *module, const char *name, const char *data, unsigned int caching)
Internal function which creates an object type and adds a wizard mapping.
Definition sorcery.c:1041
int __ast_sorcery_object_type_remove_wizard(struct ast_sorcery *sorcery, const char *object_type_name, const char *module, const char *wizard_type_name, const char *wizard_args)
Remove an object wizard mapping.
Definition sorcery.c:884
static sorcery_field_handler sorcery_field_default_handler(enum aco_option_type type)
Definition sorcery.c:345
void ast_sorcery_global_observer_remove(const struct ast_sorcery_global_observer *callbacks)
Remove a global observer from sorcery.
Definition sorcery.c:578
static int sorcery_wizard_delete(const struct ast_sorcery_object_wizard *object_wizard, const struct sorcery_details *details)
Internal function which returns if a wizard has deleted the object.
Definition sorcery.c:2288
struct ast_json * ast_sorcery_objectset_json_create(const struct ast_sorcery *sorcery, const void *object)
Create an object set in JSON format for an object.
Definition sorcery.c:1629
static void sorcery_cleanup(void)
Cleanup function for graceful shutdowns.
Definition sorcery.c:402
int ast_sorcery_global_observer_add(const struct ast_sorcery_global_observer *callbacks)
Add a global observer to sorcery.
Definition sorcery.c:562
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition sorcery.c:1506
static int sorcery_observers_notify_update(void *data)
Internal callback function which notifies observers that an object has been updated.
Definition sorcery.c:2189
#define NOTIFY_WIZARD_OBSERVERS(container, callback,...)
Definition sorcery.c:83
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:1575
int ast_sorcery_is_stale(const struct ast_sorcery *sorcery, void *object)
Determine if a sorcery object is stale with respect to its backing datastore.
Definition sorcery.c:2352
int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Add an observer to a sorcery instance.
Definition sorcery.c:584
#define TYPE_BUCKETS
Number of buckets for types (should be prime for performance reasons)
Definition sorcery.c:55
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition sorcery.c:2539
struct ast_sorcery * __ast_sorcery_open(const char *module_name, const char *file, int line, const char *func)
Definition sorcery.c:665
static int sorcery_observers_notify_loaded(void *data)
Internal callback function which notifies observers that an object type has been loaded.
Definition sorcery.c:1390
static int is_registered_cb(void *obj, void *arg, int flags)
Definition sorcery.c:2564
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:1961
static void sorcery_object_field_destructor(void *obj)
Definition sorcery.c:1214
static int double_handler_fn(const void *obj, const intptr_t *args, char **buf)
Definition sorcery.c:302
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:1178
struct ast_sorcery * ast_sorcery_retrieve_by_module_name(const char *module_name)
Search function for sorcery instances.
Definition sorcery.c:736
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition sorcery.c:2302
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition sorcery.c:1842
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:2053
int ast_sorcery_init(void)
Initialize the sorcery API.
Definition sorcery.c:444
static struct ast_sorcery_object_type * sorcery_object_type_alloc(const char *type, const char *module)
Internal function which allocates an object type structure.
Definition sorcery.c:764
static void sorcery_object_wizard_destructor(void *obj)
Object wizard destructor.
Definition sorcery.c:826
enum ast_sorcery_apply_result __ast_sorcery_object_type_insert_wizard(struct ast_sorcery *sorcery, const char *object_type_name, const char *module, const char *wizard_type_name, const char *wizard_args, enum ast_sorcery_wizard_apply_flags flags, int position, struct ast_sorcery_wizard **wizard, void **wizard_data)
Insert an additional object wizard mapping at a specific position in the wizard list returning wizard...
Definition sorcery.c:933
static void sorcery_internal_wizard_destructor(void *obj)
Definition sorcery.c:489
void ast_sorcery_object_set_diff_handler(struct ast_sorcery *sorcery, const char *type, sorcery_diff_handler diff)
Set the diff handler for an object type.
Definition sorcery.c:1203
Sorcery Data Access Layer API.
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition sorcery.h:1137
struct ast_variable *(* sorcery_transform_handler)(struct ast_variable *set)
A callback function for performing a transformation on an object set.
Definition sorcery.h:181
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
int(* sorcery_fields_handler)(const void *obj, struct ast_variable **fields)
A callback function for translating multiple values into an ast_variable list.
Definition sorcery.h:169
int(* sorcery_apply_handler)(const struct ast_sorcery *sorcery, void *obj)
A callback function for when an object set is successfully applied to an object.
Definition sorcery.h:194
int(* sorcery_diff_handler)(const void *original, const void *modified, struct ast_variable **changes)
A callback function for generating a changeset between two objects.
Definition sorcery.h:217
int(* sorcery_copy_handler)(const void *src, void *dst)
A callback function for copying the contents of one object to another.
Definition sorcery.h:205
@ AST_SORCERY_WIZARD_POSITION_LAST
Definition sorcery.h:518
ast_sorcery_field_handler_flags
Field handler flags.
Definition sorcery.h:129
@ AST_HANDLER_PREFER_STRING
Try both handlers, string first.
Definition sorcery.h:131
@ AST_HANDLER_PREFER_LIST
Try both handlers, list first.
Definition sorcery.h:134
@ AST_HANDLER_ONLY_LIST
Use list handler only.
Definition sorcery.h:140
@ AST_HANDLER_ONLY_STRING
Use string handler only.
Definition sorcery.h:137
int(* sorcery_field_handler)(const void *obj, const intptr_t *args, char **buf)
A callback function for translating a value into a string.
Definition sorcery.h:158
#define MAX_OBJECT_FIELD
Maximum length of an object field name.
Definition sorcery.h:110
#define MAX_OBJECT_TYPE
Maximum size of an object type.
Definition sorcery.h:107
ast_sorcery_wizard_apply_flags
Wizard Apply Flags.
Definition sorcery.h:575
@ AST_SORCERY_WIZARD_APPLY_NONE
Definition sorcery.h:577
@ AST_SORCERY_WIZARD_APPLY_ALLOW_DUPLICATE
Definition sorcery.h:583
@ AST_SORCERY_WIZARD_APPLY_READONLY
Definition sorcery.h:581
@ AST_SORCERY_WIZARD_APPLY_CACHING
Definition sorcery.h:579
ast_sorcery_apply_result
Definition sorcery.h:423
@ AST_SORCERY_APPLY_SUCCESS
Definition sorcery.h:427
@ AST_SORCERY_APPLY_NO_CONFIGURATION
Definition sorcery.h:433
@ AST_SORCERY_APPLY_FAIL
Definition sorcery.h:425
@ AST_SORCERY_APPLY_DUPLICATE
Definition sorcery.h:429
@ AST_SORCERY_APPLY_DEFAULT_UNNECESSARY
Definition sorcery.h:431
const char * ast_string_field
String manipulation functions.
#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
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition strings.h:1259
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition utils.c:2235
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_alloca(init_len)
Definition strings.h:848
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
The representation of a single configuration file to be processed.
struct aco_type * types[]
struct aco_file * files[]
Type information about a category-level configurable object.
enum aco_type_t type
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
descriptor for a cli entry.
Definition cli.h:171
Structure used to handle boolean flags.
Definition utils.h:217
unsigned int flags
Definition utils.h:218
Format capabilities structure, holds formats + preference order + etc.
Definition format_cap.c:54
Abstract JSON element (object, array, string, int, ...).
Socket address structure.
Definition netsock2.h:97
Interface for the global sorcery observer.
Definition sorcery.h:220
Interface for the sorcery instance observer.
Definition sorcery.h:237
Structure for an internal wizard instance.
Definition sorcery.c:90
struct ao2_container * observers
Observers.
Definition sorcery.c:100
struct ast_sorcery_wizard callbacks
Wizard interface itself.
Definition sorcery.c:97
Structure which contains details about a sorcery object.
Definition sorcery.h:350
struct ast_sorcery_object * object
Pointer to internal sorcery object information.
Definition sorcery.h:352
Structure for registered object field.
Definition sorcery.c:206
regex_t * name_regex
The compiled name regex if name is a regex.
Definition sorcery.c:211
sorcery_field_handler handler
Callback function for translation of a single value.
Definition sorcery.c:214
sorcery_fields_handler multiple_handler
Callback function for translation of multiple values.
Definition sorcery.c:217
intptr_t args[]
Position of the field.
Definition sorcery.c:220
char name[MAX_OBJECT_FIELD]
Name of the field.
Definition sorcery.c:208
Structure for registered object type observer.
Definition sorcery.c:191
const struct ast_sorcery_observer * callbacks
Pointer to the observer implementation.
Definition sorcery.c:193
Structure for registered object type.
Definition sorcery.c:149
sorcery_copy_handler copy
Optional object copy callback.
Definition sorcery.c:160
struct aco_file * file
Configuration framework file information.
Definition sorcery.c:175
struct ast_sorcery_object_wizards wizards
Wizard instances.
Definition sorcery.c:166
sorcery_transform_handler transform
Optional transformation callback.
Definition sorcery.c:154
struct ao2_container * fields
Object fields.
Definition sorcery.c:169
char name[MAX_OBJECT_TYPE]
Unique name of the object type.
Definition sorcery.c:151
sorcery_diff_handler diff
Optional object diff callback.
Definition sorcery.c:163
sorcery_apply_handler apply
Optional object set apply callback.
Definition sorcery.c:157
struct ao2_container * observers
Observers.
Definition sorcery.c:181
struct ast_taskprocessor * serializer
Serializer for observers.
Definition sorcery.c:184
struct aco_type type
Type details.
Definition sorcery.c:178
unsigned int reloadable
Specifies if object type is reloadable or not.
Definition sorcery.c:187
struct aco_info * info
Configuration framework general information.
Definition sorcery.c:172
Structure for a wizard instance which operates on objects.
Definition sorcery.c:104
unsigned int caching
Wizard is acting as an object cache.
Definition sorcery.c:112
struct ast_sorcery_internal_wizard * wizard
Wizard interface itself.
Definition sorcery.c:106
void * data
Unique data for the wizard.
Definition sorcery.c:109
unsigned int allow_duplicates
Wizard allows others of the same type.
Definition sorcery.c:118
char wizard_args[0]
Wizard arguments.
Definition sorcery.c:121
unsigned int read_only
Wizard is read_only.
Definition sorcery.c:115
Structure for internal sorcery object information.
Definition sorcery.c:128
unsigned int has_dynamic_contents
Whether this object has dynamic contents or not.
Definition sorcery.c:145
struct timeval created
Time that the object was created.
Definition sorcery.c:142
ao2_destructor_fn destructor
Optional object destructor.
Definition sorcery.c:136
struct ast_variable * extended
Extended object fields.
Definition sorcery.c:139
char type[MAX_OBJECT_TYPE]
Type of object.
Definition sorcery.c:133
char * id
Unique identifier of this object.
Definition sorcery.c:130
Interface for a sorcery object type observer.
Definition sorcery.h:332
Interface for the sorcery wizard observer.
Definition sorcery.h:265
Interface for a sorcery wizard.
Definition sorcery.h:276
void(* close)(void *data)
Callback for closing a wizard.
Definition sorcery.h:322
void(* retrieve_multiple)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
Optional callback for retrieving multiple objects using some optional field criteria.
Definition sorcery.h:313
void *(* retrieve_fields)(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
Optional callback for retrieving an object using fields.
Definition sorcery.h:310
const char * name
Name of the wizard.
Definition sorcery.h:278
void(* load)(void *data, const struct ast_sorcery *sorcery, const char *type)
Optional callback for loading persistent objects.
Definition sorcery.h:287
void *(* retrieve_id)(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback for retrieving an object using an id.
Definition sorcery.h:296
int(* create)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for creating an object.
Definition sorcery.h:293
int(* delete)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for deleting an object.
Definition sorcery.h:319
int(* is_stale)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for whether or not the wizard believes the object is stale.
Definition sorcery.h:325
void(* retrieve_prefix)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
Optional callback for retrieving multiple objects by matching their id with a prefix.
Definition sorcery.h:302
void(* force_reload)(void *data, const struct ast_sorcery *sorcery, const char *type)
Optional callback for forcing a reload to occur, even if wizard has determined no changes.
Definition sorcery.h:328
void(* retrieve_regex)(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
Callback for retrieving multiple objects using a regex on their id.
Definition sorcery.h:299
int(* update)(const struct ast_sorcery *sorcery, void *data, void *object)
Callback for updating an object.
Definition sorcery.h:316
void(* reload)(void *data, const struct ast_sorcery *sorcery, const char *type)
Optional callback for reloading persistent objects.
Definition sorcery.h:290
Full structure for sorcery.
Definition sorcery.c:231
char * module_name
Pointer to module_name in the associated sorcery_proxy.
Definition sorcery.c:239
struct ao2_container * observers
Observers.
Definition sorcery.c:236
struct ao2_container * types
Container for known object types.
Definition sorcery.c:233
Support for dynamic strings.
Definition strings.h:623
An opaque taskpool structure.
Definition taskpool.c:62
A ast_taskprocessor structure is a singleton by name.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Structure used when calling create, update, or delete.
Definition sorcery.c:1895
void * obj
Pointer to the object itself.
Definition sorcery.c:1899
const struct ast_sorcery * sorcery
Pointer to the sorcery instance.
Definition sorcery.c:1897
A global observer wrapper.
Definition sorcery.c:267
const struct ast_sorcery_global_observer * callbacks
Definition sorcery.c:268
An instance observer wrapper.
Definition sorcery.c:272
const struct ast_sorcery_instance_observer * callbacks
Definition sorcery.c:273
Structure for passing load/reload details.
Definition sorcery.c:243
unsigned int force
Whether this is forced or not.
Definition sorcery.c:254
const char * type
Type of object being loaded.
Definition sorcery.c:248
unsigned int reload
Whether this is a reload or not.
Definition sorcery.c:251
const struct ast_sorcery * sorcery
Sorcery structure in use.
Definition sorcery.c:245
Structure used for observer invocations.
Definition sorcery.c:197
void * object
Pointer to the object.
Definition sorcery.c:202
struct ast_sorcery_object_type * object_type
Pointer to the object type.
Definition sorcery.c:199
Proxy object for sorcery.
Definition sorcery.c:224
char module_name[0]
The name of the module owning this sorcery instance.
Definition sorcery.c:227
A wizard observer wrapper.
Definition sorcery.c:277
const struct ast_sorcery_wizard_observer * callbacks
Definition sorcery.c:278
int value
Definition syslog.c:37
#define AST_TASKPOOL_OPTIONS_VERSION
Definition taskpool.h:69
struct ast_taskprocessor * ast_taskpool_serializer(const char *name, struct ast_taskpool *pool)
Serialized execution of tasks within a ast_taskpool.
Definition taskpool.c:819
void ast_taskpool_shutdown(struct ast_taskpool *pool)
Shut down a taskpool and remove the underlying taskprocessors.
Definition taskpool.c:653
struct ast_taskpool * ast_taskpool_create(const char *name, const struct ast_taskpool_options *options)
Create a new taskpool.
Definition taskpool.c:324
An API for managing task processing threads that can be shared across modules.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
int done
static struct test_options options
static struct test_val a
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159
#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:978
#define ast_assert(a)
Definition utils.h:776
#define ARRAY_LEN(a)
Definition utils.h:703
#define AST_UUID_STR_LEN
Definition uuid.h:27
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition uuid.c:141
Vector container support.
#define AST_VECTOR_REMOVE_ORDERED(vec, idx)
Remove an element from a vector by index while maintaining order.
Definition vector.h:459
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_INSERT_AT(vec, idx, elem)
Insert an element at a specific position in a vector, growing the vector if needed.
Definition vector.h:349
#define AST_VECTOR_RW_WRLOCK(vec)
Obtain write lock on vector.
Definition vector.h:898
#define AST_VECTOR_REMOVE_CMP_ORDERED(vec, value, cmp, cleanup)
Remove an element from a vector that matches the given comparison while maintaining order.
Definition vector.h:551
#define AST_VECTOR_RW_UNLOCK(vec)
Unlock vector.
Definition vector.h:908
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition vector.h:742
#define AST_VECTOR_RW_FREE(vec)
Deallocates this locked vector.
Definition vector.h:213
#define AST_VECTOR_RW(name, type)
Define a vector structure with a read/write lock.
Definition vector.h:104
#define AST_VECTOR_CALLBACK(vec, callback, default_value,...)
Execute a callback on every element in a vector returning the first matched.
Definition vector.h:776
#define AST_VECTOR_RW_RDLOCK(vec)
Obtain read lock on vector.
Definition vector.h:888
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition vector.h:873
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691
#define AST_VECTOR_RW_INIT(vec, size)
Initialize a vector with a read/write lock.
Definition vector.h:169