Asterisk - The Open Source Telephony Project GIT-master-7e7a603
bucket.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Bucket File API
22 *
23 * \author Joshua Colp <jcolp@digium.com>
24 */
25
26/*** MODULEINFO
27 <use type="external">uriparser</use>
28 <support_level>core</support_level>
29 ***/
30
31/*** DOCUMENTATION
32 <configInfo name="core" language="en_US">
33 <synopsis>Bucket file API</synopsis>
34 <configFile name="bucket">
35 <configObject name="bucket">
36 <configOption name="scheme">
37 <synopsis>Scheme in use for bucket</synopsis>
38 </configOption>
39 <configOption name="created">
40 <synopsis>Time at which the bucket was created</synopsis>
41 </configOption>
42 <configOption name="modified">
43 <synopsis>Time at which the bucket was last modified</synopsis>
44 </configOption>
45 </configObject>
46 <configObject name="file">
47 <configOption name="scheme">
48 <synopsis>Scheme in use for file</synopsis>
49 </configOption>
50 <configOption name="created">
51 <synopsis>Time at which the file was created</synopsis>
52 </configOption>
53 <configOption name="modified">
54 <synopsis>Time at which the file was last modified</synopsis>
55 </configOption>
56 </configObject>
57 </configFile>
58 </configInfo>
59***/
60
61#include "asterisk.h"
62
63#ifdef HAVE_URIPARSER
64#include <uriparser/Uri.h>
65#endif
66
67#include "asterisk/logger.h"
68#include "asterisk/sorcery.h"
69#include "asterisk/bucket.h"
71#include "asterisk/astobj2.h"
72#include "asterisk/strings.h"
73#include "asterisk/json.h"
74#include "asterisk/file.h"
75#include "asterisk/module.h"
76#include "asterisk/paths.h"
77
78/*! \brief Number of buckets for the container of schemes */
79#define SCHEME_BUCKETS 53
80
81/*! \brief Number of buckets for the container of metadata in a file */
82#define METADATA_BUCKETS 53
83
84/*! \brief Sorcery instance for all bucket operations */
86
87/*! \brief Container of registered schemes */
88static struct ao2_container *schemes;
89
90/*! \brief Structure for available schemes */
92 /*! \brief Wizard for buckets */
94 /*! \brief Wizard for files */
96 /*! \brief Pointer to the file snapshot creation callback */
98 /*! \brief Pointer to the file snapshot destruction callback */
100 /*! \brief Name of the scheme */
101 char name[0];
102};
103
104/*! \brief Callback function for creating a bucket */
105static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
106{
107 struct ast_bucket *bucket = object;
108
109 return bucket->scheme_impl->bucket->create(sorcery, data, object);
110}
111
112/*! \brief Callback function for retrieving a bucket */
113static void *bucket_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
114 const char *id)
115{
116#ifdef HAVE_URIPARSER
117 UriParserStateA state;
118 UriUriA uri;
119 size_t len;
120#else
121 char *tmp = ast_strdupa(id);
122#endif
124 char *uri_scheme;
126
127#ifdef HAVE_URIPARSER
128 state.uri = &uri;
129 if (uriParseUriA(&state, id) != URI_SUCCESS ||
130 !uri.scheme.first || !uri.scheme.afterLast) {
131 uriFreeUriMembersA(&uri);
132 return NULL;
133 }
134
135 len = (uri.scheme.afterLast - uri.scheme.first) + 1;
136 uri_scheme = ast_alloca(len);
137 ast_copy_string(uri_scheme, uri.scheme.first, len);
138
139 uriFreeUriMembersA(&uri);
140#else
141 uri_scheme = tmp;
142 if (!(tmp = strchr(uri_scheme, ':'))) {
143 return NULL;
144 }
145 *tmp = '\0';
146#endif
147
148 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
149
150 if (!scheme) {
151 return NULL;
152 }
153
154 return scheme->bucket->retrieve_id(sorcery, data, type, id);
155}
156
157/*! \brief Callback function for deleting a bucket */
158static int bucket_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
159{
160 struct ast_bucket *bucket = object;
161
162 return bucket->scheme_impl->bucket->delete(sorcery, data, object);
163}
164
165/*! \brief Callback function for determining if a bucket is stale */
166static int bucket_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
167{
168 struct ast_bucket *bucket = object;
169
170 if (!bucket->scheme_impl->bucket->is_stale) {
171 return 0;
172 }
173
174 return bucket->scheme_impl->bucket->is_stale(sorcery, data, object);
175}
176
177/*! \brief Intermediary bucket wizard */
179 .name = "bucket",
180 .create = bucket_wizard_create,
181 .retrieve_id = bucket_wizard_retrieve,
182 .delete = bucket_wizard_delete,
183 .is_stale = bucket_wizard_is_stale,
184};
185
186/*! \brief Callback function for creating a bucket file */
187static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
188{
189 struct ast_bucket_file *file = object;
190
191 return file->scheme_impl->file->create(sorcery, data, object);
192}
193
194/*! \brief Callback function for retrieving a bucket file */
195static void *bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type,
196 const char *id)
197{
198#ifdef HAVE_URIPARSER
199 UriParserStateA state;
200 UriUriA uri;
201 size_t len;
202#else
203 char *tmp = ast_strdupa(id);
204#endif
205 char *uri_scheme;
208
209#ifdef HAVE_URIPARSER
210 state.uri = &uri;
211 if (uriParseUriA(&state, id) != URI_SUCCESS ||
212 !uri.scheme.first || !uri.scheme.afterLast) {
213 uriFreeUriMembersA(&uri);
214 return NULL;
215 }
216
217 len = (uri.scheme.afterLast - uri.scheme.first) + 1;
218 uri_scheme = ast_alloca(len);
219 ast_copy_string(uri_scheme, uri.scheme.first, len);
220
221 uriFreeUriMembersA(&uri);
222#else
223 uri_scheme = tmp;
224 if (!(tmp = strchr(uri_scheme, ':'))) {
225 return NULL;
226 }
227 *tmp = '\0';
228#endif
229
230 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY | OBJ_NOLOCK);
231
232 if (!scheme) {
233 return NULL;
234 }
235
236 return scheme->file->retrieve_id(sorcery, data, type, id);
237}
238
239/*! \brief Callback function for updating a bucket file */
240static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
241{
242 struct ast_bucket_file *file = object;
243
244 return file->scheme_impl->file->update(sorcery, data, object);
245}
246
247/*! \brief Callback function for deleting a bucket file */
248static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
249{
250 struct ast_bucket_file *file = object;
251
252 return file->scheme_impl->file->delete(sorcery, data, object);
253}
254
255/*! \brief Callback function for determining if a bucket is stale */
256static int bucket_file_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
257{
258 struct ast_bucket_file *file = object;
259
260 if (!file->scheme_impl->file->is_stale) {
261 return 0;
262 }
263
264 return file->scheme_impl->file->is_stale(sorcery, data, object);
265}
266
267/*! \brief Intermediary file wizard */
269 .name = "bucket_file",
271 .retrieve_id = bucket_file_wizard_retrieve,
274 .is_stale = bucket_file_wizard_is_stale,
275};
276
279 bucket_file_destroy_cb destroy_cb, struct ast_module *module)
280{
282 RAII_VAR(struct ast_bucket_scheme *, scheme, NULL, ao2_cleanup);
283
284 if (ast_strlen_zero(name) || !bucket || !file ||
285 !bucket->create || !bucket->delete || !bucket->retrieve_id ||
286 (!bucket->create && !create_cb)) {
287 return -1;
288 }
289
290 scheme = ao2_find(schemes, name, OBJ_KEY | OBJ_NOLOCK);
291 if (scheme) {
292 return -1;
293 }
294
295 scheme = ao2_alloc(sizeof(*scheme) + strlen(name) + 1, NULL);
296 if (!scheme) {
297 return -1;
298 }
299
300 strcpy(scheme->name, name);
301 scheme->bucket = bucket;
302 scheme->file = file;
303 scheme->create = create_cb;
304 scheme->destroy = destroy_cb;
305
307
308 ast_verb(5, "Registered bucket scheme '%s'\n", name);
309
311
312 return 0;
313}
314
315/*! \brief Allocator for metadata attributes */
316static struct ast_bucket_metadata *bucket_metadata_alloc(const char *name, const char *value)
317{
318 int name_len = strlen(name) + 1, value_len = strlen(value) + 1;
319 struct ast_bucket_metadata *metadata = ao2_alloc(sizeof(*metadata) + name_len + value_len, NULL);
320 char *dst;
321
322 if (!metadata) {
323 return NULL;
324 }
325
326 dst = metadata->data;
327 metadata->name = strcpy(dst, name);
328 dst += name_len;
329 metadata->value = strcpy(dst, value);
330
331 return metadata;
332}
333
334int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
335{
337
338 if (!metadata) {
339 return -1;
340 }
341
343 ao2_link(file->metadata, metadata);
344
345 return 0;
346}
347
349{
350 RAII_VAR(struct ast_bucket_metadata *, metadata, ao2_find(file->metadata, name, OBJ_UNLINK | OBJ_KEY), ao2_cleanup);
351
352 if (!metadata) {
353 return -1;
354 }
355
356 return 0;
357}
358
360{
361 return ao2_find(file->metadata, name, OBJ_KEY);
362}
363
365{
366 ao2_callback(file->metadata, 0, cb, arg);
367}
368
369
370/*! \brief Destructor for buckets */
371static void bucket_destroy(void *obj)
372{
373 struct ast_bucket *bucket = obj;
374
375 ao2_cleanup(bucket->scheme_impl);
377 ao2_cleanup(bucket->buckets);
378 ao2_cleanup(bucket->files);
379}
380
381/*! \brief Sorting function for red black tree string container */
382static int bucket_rbtree_str_sort_cmp(const void *obj_left, const void *obj_right, int flags)
383{
384 const char *str_left = obj_left;
385 const char *str_right = obj_right;
386 int cmp = 0;
387
388 switch (flags & (OBJ_POINTER | OBJ_KEY | OBJ_PARTIAL_KEY)) {
389 default:
390 case OBJ_POINTER:
391 case OBJ_KEY:
392 cmp = strcmp(str_left, str_right);
393 break;
394 case OBJ_PARTIAL_KEY:
395 cmp = strncmp(str_left, str_right, strlen(str_right));
396 break;
397 }
398 return cmp;
399}
400
401/*! \brief Allocator for buckets */
402static void *bucket_alloc(const char *name)
403{
404 RAII_VAR(struct ast_bucket *, bucket, NULL, ao2_cleanup);
405
406 bucket = ast_sorcery_generic_alloc(sizeof(*bucket), bucket_destroy);
407 if (!bucket) {
408 return NULL;
409 }
410
411 if (ast_string_field_init(bucket, 128)) {
412 return NULL;
413 }
414
417 if (!bucket->buckets) {
418 return NULL;
419 }
420
423 if (!bucket->files) {
424 return NULL;
425 }
426
427 ao2_ref(bucket, +1);
428 return bucket;
429}
430
431struct ast_bucket *ast_bucket_alloc(const char *uri)
432{
433#ifdef HAVE_URIPARSER
434 UriParserStateA state;
435 UriUriA full_uri;
436 size_t len;
437#else
438 char *tmp = ast_strdupa(uri);
439#endif
440 char *uri_scheme;
442 struct ast_bucket *bucket;
443
444 if (ast_strlen_zero(uri)) {
445 return NULL;
446 }
447
448#ifdef HAVE_URIPARSER
449 state.uri = &full_uri;
450 if (uriParseUriA(&state, uri) != URI_SUCCESS ||
451 !full_uri.scheme.first || !full_uri.scheme.afterLast ||
452 !full_uri.pathTail) {
453 uriFreeUriMembersA(&full_uri);
454 return NULL;
455 }
456
457 len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
458 uri_scheme = ast_alloca(len);
459 ast_copy_string(uri_scheme, full_uri.scheme.first, len);
460
461 uriFreeUriMembersA(&full_uri);
462#else
463 uri_scheme = tmp;
464 if (!(tmp = strchr(uri_scheme, ':'))) {
465 return NULL;
466 }
467 *tmp = '\0';
468#endif
469
470 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
471 if (!scheme) {
472 return NULL;
473 }
474
475 bucket = ast_sorcery_alloc(bucket_sorcery, "bucket", uri);
476 if (!bucket) {
477 return NULL;
478 }
479
480 ao2_ref(scheme, +1);
481 bucket->scheme_impl = scheme;
482
483 ast_string_field_set(bucket, scheme, uri_scheme);
484
485 return bucket;
486}
487
488int ast_bucket_create(struct ast_bucket *bucket)
489{
490 return ast_sorcery_create(bucket_sorcery, bucket);
491}
492
493/*!
494 * \internal
495 * \brief Sorcery object type copy handler for \c ast_bucket
496 */
497static int bucket_copy_handler(const void *src, void *dst)
498{
499 const struct ast_bucket *src_bucket = src;
500 struct ast_bucket *dst_bucket = dst;
501
502 dst_bucket->scheme_impl = ao2_bump(src_bucket->scheme_impl);
503 ast_string_field_set(dst_bucket, scheme, src_bucket->scheme);
504 dst_bucket->created = src_bucket->created;
505 dst_bucket->modified = src_bucket->modified;
506
507 return 0;
508}
509
511{
512 return ast_sorcery_copy(bucket_sorcery, bucket);
513}
514
515struct ast_bucket *ast_bucket_retrieve(const char *uri)
516{
517 if (ast_strlen_zero(uri)) {
518 return NULL;
519 }
520
521 return ast_sorcery_retrieve_by_id(bucket_sorcery, "bucket", uri);
522}
523
525{
526 return ast_sorcery_is_stale(bucket_sorcery, bucket);
527}
528
530{
532}
533
535{
537}
538
539int ast_bucket_delete(struct ast_bucket *bucket)
540{
541 return ast_sorcery_delete(bucket_sorcery, bucket);
542}
543
544struct ast_json *ast_bucket_json(const struct ast_bucket *bucket)
545{
546 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
547 struct ast_json *id, *files, *buckets;
548 struct ao2_iterator i;
549 char *uri;
550 int res = 0;
551
553 if (!json) {
554 return NULL;
555 }
556
558 if (!id) {
559 return NULL;
560 }
561
562 if (ast_json_object_set(json, "id", id)) {
563 return NULL;
564 }
565
566 buckets = ast_json_array_create();
567 if (!buckets) {
568 return NULL;
569 }
570
571 if (ast_json_object_set(json, "buckets", buckets)) {
572 return NULL;
573 }
574
575 i = ao2_iterator_init(bucket->buckets, 0);
576 for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
577 struct ast_json *bucket_uri = ast_json_string_create(uri);
578
579 if (!bucket_uri || ast_json_array_append(buckets, bucket_uri)) {
580 res = -1;
581 ao2_ref(uri, -1);
582 break;
583 }
584 }
586
587 if (res) {
588 return NULL;
589 }
590
591 files = ast_json_array_create();
592 if (!files) {
593 return NULL;
594 }
595
596 if (ast_json_object_set(json, "files", files)) {
597 return NULL;
598 }
599
600 i = ao2_iterator_init(bucket->files, 0);
601 for (; (uri = ao2_iterator_next(&i)); ao2_ref(uri, -1)) {
602 struct ast_json *file_uri = ast_json_string_create(uri);
603
604 if (!file_uri || ast_json_array_append(files, file_uri)) {
605 res = -1;
606 ao2_ref(uri, -1);
607 break;
608 }
609 }
611
612 if (res) {
613 return NULL;
614 }
615
616 ast_json_ref(json);
617 return json;
618}
619
620/*! \brief Hashing function for file metadata */
622
623/*! \brief Comparison function for file metadata */
625
626/*! \brief Destructor for bucket files */
627static void bucket_file_destroy(void *obj)
628{
629 struct ast_bucket_file *file = obj;
630
631 if (file->scheme_impl->destroy) {
632 file->scheme_impl->destroy(file);
633 }
634
635 ao2_cleanup(file->scheme_impl);
636 ao2_cleanup(file->metadata);
637}
638
639/*! \brief Allocator for bucket files */
640static void *bucket_file_alloc(const char *name)
641{
643
645 if (!file) {
646 return NULL;
647 }
648
649 if (ast_string_field_init(file, 128)) {
650 return NULL;
651 }
652
654 ast_bucket_metadata_hash_fn, NULL, ast_bucket_metadata_cmp_fn);
655 if (!file->metadata) {
656 return NULL;
657 }
658
659 ao2_ref(file, +1);
660 return file;
661}
662
664{
665#ifdef HAVE_URIPARSER
666 UriParserStateA state;
667 UriUriA full_uri;
668 size_t len;
669#else
670 char *tmp = ast_strdupa(uri);
671#endif
672 char *uri_scheme;
674 struct ast_bucket_file *file;
675
676 if (ast_strlen_zero(uri)) {
677 return NULL;
678 }
679
680#ifdef HAVE_URIPARSER
681 state.uri = &full_uri;
682 if (uriParseUriA(&state, uri) != URI_SUCCESS ||
683 !full_uri.scheme.first || !full_uri.scheme.afterLast ||
684 !full_uri.pathTail) {
685 uriFreeUriMembersA(&full_uri);
686 return NULL;
687 }
688
689 len = (full_uri.scheme.afterLast - full_uri.scheme.first) + 1;
690 uri_scheme = ast_alloca(len);
691 ast_copy_string(uri_scheme, full_uri.scheme.first, len);
692
693 uriFreeUriMembersA(&full_uri);
694#else
695 uri_scheme = tmp;
696 if (!(tmp = strchr(uri_scheme, ':'))) {
697 return NULL;
698 }
699 *tmp = '\0';
700#endif
701
702 scheme = ao2_find(schemes, uri_scheme, OBJ_KEY);
703 if (!scheme) {
704 return NULL;
705 }
706
707 file = ast_sorcery_alloc(bucket_sorcery, "file", uri);
708 if (!file) {
709 return NULL;
710 }
711
712 ao2_ref(scheme, +1);
713 file->scheme_impl = scheme;
714
715 ast_string_field_set(file, scheme, uri_scheme);
716
717 if (scheme->create && scheme->create(file)) {
718 ao2_ref(file, -1);
719 return NULL;
720 }
721
722 return file;
723}
724
726{
728}
729
730/*! \brief Copy a file, shamelessly taken from file.c */
731static int bucket_copy(const char *infile, const char *outfile)
732{
733 int ifd, ofd, len;
734 char buf[4096]; /* XXX make it larger. */
735
736 if ((ifd = open(infile, O_RDONLY)) < 0) {
737 ast_log(LOG_WARNING, "Unable to open %s in read-only mode, error: %s\n", infile, strerror(errno));
738 return -1;
739 }
740 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, AST_FILE_MODE)) < 0) {
741 ast_log(LOG_WARNING, "Unable to open %s in write-only mode, error: %s\n", outfile, strerror(errno));
742 close(ifd);
743 return -1;
744 }
745 while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
746 int res;
747 if (len < 0) {
748 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
749 break;
750 }
751 /* XXX handle partial writes */
752 res = write(ofd, buf, len);
753 if (res != len) {
754 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
755 len = -1; /* error marker */
756 break;
757 }
758 }
759 close(ifd);
760 close(ofd);
761 if (len < 0) {
762 unlink(outfile);
763 return -1; /* error */
764 }
765 return 0; /* success */
766}
767
768/*!
769 * \internal
770 * \brief Sorcery object type copy handler for \c ast_bucket_file
771 */
772static int bucket_file_copy_handler(const void *src, void *dst)
773{
774 const struct ast_bucket_file *src_file = src;
775 struct ast_bucket_file *dst_file = dst;
776
777 dst_file->scheme_impl = ao2_bump(src_file->scheme_impl);
778 ast_string_field_set(dst_file, scheme, src_file->scheme);
779 dst_file->created = src_file->created;
780 dst_file->modified = src_file->modified;
781 strcpy(dst_file->path, src_file->path); /* safe */
782
783 dst_file->metadata = ao2_container_clone(src_file->metadata, 0);
784 if (!dst_file->metadata) {
785 return -1;
786 }
787
788 return 0;
789}
790
792{
794
795 if (!copy) {
796 return NULL;
797 }
798
799 ao2_cleanup(copy->metadata);
800 copy->metadata = ao2_container_clone(file->metadata, 0);
801 if (!copy->metadata ||
802 bucket_copy(file->path, copy->path)) {
803 return NULL;
804 }
805
806 ao2_ref(copy, +1);
807 return copy;
808}
809
811{
813}
814
816{
817 if (ast_strlen_zero(uri)) {
818 return NULL;
819 }
820
821 return ast_sorcery_retrieve_by_id(bucket_sorcery, "file", uri);
822}
823
825{
827}
828
830{
832}
833
835{
837}
838
840{
842}
843
845{
847}
848
850{
851 RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
852 struct ast_json *id, *metadata;
853 struct ao2_iterator i;
854 struct ast_bucket_metadata *attribute;
855 int res = 0;
856
858 if (!json) {
859 return NULL;
860 }
861
863 if (!id) {
864 return NULL;
865 }
866
867 if (ast_json_object_set(json, "id", id)) {
868 return NULL;
869 }
870
871 metadata = ast_json_object_create();
872 if (!metadata) {
873 return NULL;
874 }
875
876 if (ast_json_object_set(json, "metadata", metadata)) {
877 return NULL;
878 }
879
880 i = ao2_iterator_init(file->metadata, 0);
881 for (; (attribute = ao2_iterator_next(&i)); ao2_ref(attribute, -1)) {
882 struct ast_json *value = ast_json_string_create(attribute->value);
883
884 if (!value || ast_json_object_set(metadata, attribute->name, value)) {
885 res = -1;
886 break;
887 }
888 }
890
891 if (res) {
892 return NULL;
893 }
894
895 ast_json_ref(json);
896 return json;
897}
898
900{
901 int fd;
902
903 snprintf(file->path, sizeof(file->path), "%s/bucket-XXXXXX", ast_config_AST_CACHE_DIR);
904
905 fd = mkstemp(file->path);
906 if (fd < 0) {
907 return -1;
908 }
909
910 close(fd);
911 return 0;
912}
913
915{
916 if (!ast_strlen_zero(file->path)) {
917 unlink(file->path);
918 }
919}
920
921/*! \brief Hashing function for scheme container */
923
924/*! \brief Comparison function for scheme container */
926
927/*! \brief Cleanup function for graceful shutdowns */
928static void bucket_cleanup(void)
929{
932
935
937}
938
939/*! \brief Custom handler for translating from a string timeval to actual structure */
940static int timeval_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
941{
942 struct timeval *field = (struct timeval *)(obj + aco_option_get_argument(opt, 0));
943 return ast_get_timeval(var->value, field, ast_tv(0, 0), NULL);
944}
945
946/*! \brief Custom handler for translating from an actual structure timeval to string */
947static int timeval_struct2str(const void *obj, const intptr_t *args, char **buf)
948{
949 struct timeval *field = (struct timeval *)(obj + args[0]);
950 return (ast_asprintf(buf, "%lu.%06lu", (unsigned long)field->tv_sec, (unsigned long)field->tv_usec) < 0) ? -1 : 0;
951}
952
953/*! \brief Initialize bucket support */
955{
957
959 ast_bucket_scheme_hash_fn, NULL, ast_bucket_scheme_cmp_fn);
960 if (!schemes) {
961 ast_log(LOG_ERROR, "Failed to create container for Bucket schemes\n");
962 return -1;
963 }
964
966 ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'bucket' intermediary\n");
967 return -1;
968 }
969
971 ast_log(LOG_ERROR, "Failed to register sorcery wizard for 'file' intermediary\n");
972 return -1;
973 }
974
975 if (!(bucket_sorcery = ast_sorcery_open())) {
976 ast_log(LOG_ERROR, "Failed to create sorcery instance for Bucket support\n");
977 return -1;
978 }
979
981 ast_log(LOG_ERROR, "Failed to apply intermediary for 'bucket' object type in Bucket sorcery\n");
982 return -1;
983 }
984
986 ast_log(LOG_ERROR, "Failed to register 'bucket' object type in Bucket sorcery\n");
987 return -1;
988 }
989
990 ast_sorcery_object_field_register(bucket_sorcery, "bucket", "scheme", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_bucket, scheme));
994
996 ast_log(LOG_ERROR, "Failed to apply intermediary for 'file' object type in Bucket sorcery\n");
997 return -1;
998 }
999
1001 ast_log(LOG_ERROR, "Failed to register 'file' object type in Bucket sorcery\n");
1002 return -1;
1003 }
1004
1009
1010 return 0;
1011}
enum queue_result id
Definition: app_queue.c:1638
ast_mutex_t lock
Definition: app_sla.c:331
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define var
Definition: ast_expr2f.c:605
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_FILE_MODE
Definition: asterisk.h:32
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
Definition: astmm.h:267
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define OBJ_KEY
Definition: astobj2.h:1151
#define OBJ_POINTER
Definition: astobj2.h:1150
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
@ AO2_ALLOC_OPT_LOCK_RWLOCK
Definition: astobj2.h:365
#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
#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
int() ao2_callback_fn(void *obj, void *arg, int flags)
Type of a generic callback function.
Definition: astobj2.h:1226
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#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_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define OBJ_PARTIAL_KEY
Definition: astobj2.h:1152
#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_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#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_container_clone(orig, flags)
Create a clone/copy of the given container.
Definition: astobj2.h:1419
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REJECT
Reject objects with duplicate keys in container.
Definition: astobj2.h:1188
static int tmp()
Definition: bt_open.c:389
static void * bucket_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback function for retrieving a bucket.
Definition: bucket.c:113
struct ast_bucket * ast_bucket_alloc(const char *uri)
Allocate a new bucket.
Definition: bucket.c:431
static int bucket_file_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for creating a bucket file.
Definition: bucket.c:187
struct ast_bucket_file * ast_bucket_file_clone(struct ast_bucket_file *file)
Clone a bucket file.
Definition: bucket.c:810
#define METADATA_BUCKETS
Number of buckets for the container of metadata in a file.
Definition: bucket.c:82
static void bucket_file_destroy(void *obj)
Hashing function for file metadata.
Definition: bucket.c:627
int ast_bucket_file_metadata_set(struct ast_bucket_file *file, const char *name, const char *value)
Set a metadata attribute on a file to a specific value.
Definition: bucket.c:334
struct ast_bucket_file * ast_bucket_file_alloc(const char *uri)
Allocate a new bucket file.
Definition: bucket.c:663
static void bucket_cleanup(void)
Hashing function for scheme container.
Definition: bucket.c:928
static int bucket_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for determining if a bucket is stale.
Definition: bucket.c:166
void ast_bucket_file_observer_remove(const struct ast_sorcery_observer *callbacks)
Remove an observer from bucket file creation and deletion.
Definition: bucket.c:834
static int bucket_file_wizard_is_stale(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for determining if a bucket is stale.
Definition: bucket.c:256
static int bucket_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for deleting a bucket.
Definition: bucket.c:158
static void * bucket_file_alloc(const char *name)
Allocator for bucket files.
Definition: bucket.c:640
static struct ast_sorcery_wizard bucket_file_wizard
Intermediary file wizard.
Definition: bucket.c:268
static struct ast_sorcery * bucket_sorcery
Sorcery instance for all bucket operations.
Definition: bucket.c:85
int ast_bucket_file_temporary_create(struct ast_bucket_file *file)
Common file snapshot creation callback for creating a temporary file.
Definition: bucket.c:899
static struct ast_sorcery_wizard bucket_wizard
Intermediary bucket wizard.
Definition: bucket.c:178
void ast_bucket_file_metadata_callback(struct ast_bucket_file *file, ao2_callback_fn cb, void *arg)
Execute a callback function on the metadata associated with a file.
Definition: bucket.c:364
int ast_bucket_create(struct ast_bucket *bucket)
Create a new bucket in backend storage.
Definition: bucket.c:488
static int bucket_file_wizard_update(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for updating a bucket file.
Definition: bucket.c:240
int ast_bucket_file_create(struct ast_bucket_file *file)
Create a new bucket file in backend storage.
Definition: bucket.c:725
static int timeval_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
Custom handler for translating from a string timeval to actual structure.
Definition: bucket.c:940
static void * bucket_file_wizard_retrieve(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
Callback function for retrieving a bucket file.
Definition: bucket.c:195
static int timeval_struct2str(const void *obj, const intptr_t *args, char **buf)
Custom handler for translating from an actual structure timeval to string.
Definition: bucket.c:947
static int bucket_copy_handler(const void *src, void *dst)
Definition: bucket.c:497
static struct ao2_container * schemes
Container of registered schemes.
Definition: bucket.c:88
int ast_bucket_file_metadata_unset(struct ast_bucket_file *file, const char *name)
Unset a specific metadata attribute on a file.
Definition: bucket.c:348
int ast_bucket_file_update(struct ast_bucket_file *file)
Update an existing bucket file in backend storage.
Definition: bucket.c:839
struct ast_bucket_metadata * ast_bucket_file_metadata_get(struct ast_bucket_file *file, const char *name)
Retrieve a metadata attribute from a file.
Definition: bucket.c:359
int ast_bucket_file_observer_add(const struct ast_sorcery_observer *callbacks)
Add an observer for bucket file creation and deletion operations.
Definition: bucket.c:829
struct ast_bucket_file * ast_bucket_file_copy(struct ast_bucket_file *file, const char *uri)
Copy a bucket file to a new URI.
Definition: bucket.c:791
int ast_bucket_is_stale(struct ast_bucket *bucket)
Retrieve whether or not the backing datastore views the bucket as stale.
Definition: bucket.c:524
static void * bucket_alloc(const char *name)
Allocator for buckets.
Definition: bucket.c:402
struct ast_bucket_file * ast_bucket_file_retrieve(const char *uri)
Retrieve a bucket file.
Definition: bucket.c:815
void ast_bucket_observer_remove(const struct ast_sorcery_observer *callbacks)
Remove an observer from bucket creation and deletion.
Definition: bucket.c:534
static int bucket_file_copy_handler(const void *src, void *dst)
Definition: bucket.c:772
int __ast_bucket_scheme_register(const char *name, struct ast_sorcery_wizard *bucket, struct ast_sorcery_wizard *file, bucket_file_create_cb create_cb, bucket_file_destroy_cb destroy_cb, struct ast_module *module)
Register support for a specific scheme.
Definition: bucket.c:277
#define SCHEME_BUCKETS
Number of buckets for the container of schemes.
Definition: bucket.c:79
static void bucket_destroy(void *obj)
Destructor for buckets.
Definition: bucket.c:371
struct ast_bucket * ast_bucket_retrieve(const char *uri)
Retrieve information about a bucket.
Definition: bucket.c:515
int ast_bucket_file_delete(struct ast_bucket_file *file)
Delete a bucket file from backend storage.
Definition: bucket.c:844
struct ast_json * ast_bucket_json(const struct ast_bucket *bucket)
Get a JSON representation of a bucket.
Definition: bucket.c:544
static struct ast_bucket_metadata * bucket_metadata_alloc(const char *name, const char *value)
Allocator for metadata attributes.
Definition: bucket.c:316
struct ast_json * ast_bucket_file_json(const struct ast_bucket_file *file)
Get a JSON representation of a bucket file.
Definition: bucket.c:849
struct ast_bucket * ast_bucket_clone(struct ast_bucket *bucket)
Clone a bucket.
Definition: bucket.c:510
void ast_bucket_file_temporary_destroy(struct ast_bucket_file *file)
Common file snapshot destruction callback for deleting a temporary file.
Definition: bucket.c:914
int ast_bucket_observer_add(const struct ast_sorcery_observer *callbacks)
Add an observer for bucket creation and deletion operations.
Definition: bucket.c:529
static int bucket_file_wizard_delete(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for deleting a bucket file.
Definition: bucket.c:248
static int bucket_copy(const char *infile, const char *outfile)
Copy a file, shamelessly taken from file.c.
Definition: bucket.c:731
static int bucket_wizard_create(const struct ast_sorcery *sorcery, void *data, void *object)
Callback function for creating a bucket.
Definition: bucket.c:105
int ast_bucket_init(void)
Initialize bucket support.
Definition: bucket.c:954
static int bucket_rbtree_str_sort_cmp(const void *obj_left, const void *obj_right, int flags)
Sorting function for red black tree string container.
Definition: bucket.c:382
int ast_bucket_file_is_stale(struct ast_bucket_file *file)
Retrieve whether or not the backing datastore views the bucket file as stale.
Definition: bucket.c:824
int ast_bucket_delete(struct ast_bucket *bucket)
Delete a bucket from backend storage.
Definition: bucket.c:539
Bucket File API.
void(* bucket_file_destroy_cb)(struct ast_bucket_file *file)
A callback function invoked when destroying a file snapshot.
Definition: bucket.h:113
int(* bucket_file_create_cb)(struct ast_bucket_file *file)
A callback function invoked when creating a file snapshot.
Definition: bucket.h:106
enum cc_state state
Definition: ccss.c:393
static const char type[]
Definition: chan_ooh323.c:109
Configuration option-handling.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
intptr_t aco_option_get_argument(const struct aco_option *option, unsigned int position)
Get the offset position for an argument within a config option.
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
Generic File Format Support. Should be included by clients of the file handling routines....
static const char name[]
Definition: format_mp3.c:68
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Support for logging to various files, console and syslog Configuration in file logger....
#define LOG_ERROR
#define ast_verb(level,...)
#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
int ast_json_array_append(struct ast_json *array, struct ast_json *value)
Append to an array.
Definition: json.c:378
struct ast_json * ast_json_object_create(void)
Create a new JSON object.
Definition: json.c:399
struct ast_json * ast_json_array_create(void)
Create a empty JSON array.
Definition: json.c:362
struct ast_json * ast_json_ref(struct ast_json *value)
Increase refcount on value.
Definition: json.c:67
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
#define SCOPED_AO2WRLOCK(varname, obj)
scoped lock specialization for ao2 write locks.
Definition: lock.h:614
#define SCOPED_AO2RDLOCK(varname, obj)
scoped lock specialization for ao2 read locks.
Definition: lock.h:609
int errno
Asterisk module definitions.
#define ast_module_shutdown_ref(mod)
Prevent unload of the module before shutdown.
Definition: module.h:464
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_CACHE_DIR
Definition: options.c:150
static struct ast_sorcery * sorcery
struct @468 callbacks
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2423
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:1128
int ast_sorcery_create(const struct ast_sorcery *sorcery, void *object)
Create and potentially persist an object using an available wizard.
Definition: sorcery.c:2062
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Definition: sorcery.h:837
int __ast_sorcery_wizard_register(const struct ast_sorcery_wizard *interface, struct ast_module *module)
Register a sorcery wizard.
Definition: sorcery.c:432
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2391
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
Definition: sorcery.h:1005
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
Definition: sorcery.c:1728
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
Definition: sorcery.h:955
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
int ast_sorcery_update(const struct ast_sorcery *sorcery, void *object)
Update an object.
Definition: sorcery.c:2150
#define ast_sorcery_apply_default(sorcery, type, name, data)
Definition: sorcery.h:476
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:1565
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
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:2288
int ast_sorcery_delete(const struct ast_sorcery *sorcery, void *object)
Delete an object.
Definition: sorcery.c:2238
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
@ AST_SORCERY_APPLY_FAIL
Definition: sorcery.h:425
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
String manipulation functions.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
int ast_get_timeval(const char *src, struct timeval *tv, struct timeval _default, int *consumed)
Parse a time (float) string.
Definition: utils.c:2419
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
Bucket file structure, contains reference to file and information about it.
Definition: bucket.h:78
struct timeval modified
When this file was last modified.
Definition: bucket.h:91
struct timeval created
When this file was created.
Definition: bucket.h:89
const ast_string_field scheme
Definition: bucket.h:87
struct ao2_container * metadata
Container of metadata attributes about file.
Definition: bucket.h:93
char path[PATH_MAX]
Local path to this file.
Definition: bucket.h:95
struct ast_bucket_scheme * scheme_impl
Scheme implementation in use.
Definition: bucket.h:82
Bucket metadata structure, AO2 key value pair.
Definition: bucket.h:47
const char * value
Value of the attribute.
Definition: bucket.h:51
const char * name
Name of the attribute.
Definition: bucket.h:49
char data[0]
Storage for the above name and value.
Definition: bucket.h:53
Structure for available schemes.
Definition: bucket.c:91
struct ast_sorcery_wizard * file
Wizard for files.
Definition: bucket.c:95
bucket_file_create_cb create
Pointer to the file snapshot creation callback.
Definition: bucket.c:97
bucket_file_destroy_cb destroy
Pointer to the file snapshot destruction callback.
Definition: bucket.c:99
struct ast_sorcery_wizard * bucket
Wizard for buckets.
Definition: bucket.c:93
char name[0]
Name of the scheme.
Definition: bucket.c:101
Bucket structure, contains other buckets and files.
Definition: bucket.h:57
struct ao2_container * buckets
Container of string URIs of buckets within this bucket.
Definition: bucket.h:72
struct timeval modified
When this bucket was last modified.
Definition: bucket.h:70
struct timeval created
When this bucket was created.
Definition: bucket.h:68
struct ao2_container * files
Container of string URIs of files within this bucket.
Definition: bucket.h:74
const ast_string_field scheme
Definition: bucket.h:66
struct ast_bucket_scheme * scheme_impl
Scheme implementation in use.
Definition: bucket.h:61
Abstract JSON element (object, array, string, int, ...).
Interface for a sorcery object type observer.
Definition: sorcery.h:332
Interface for a sorcery wizard.
Definition: sorcery.h:276
struct ast_module * module
Pointer to the Asterisk module this wizard is implemented by.
Definition: sorcery.h:281
const char * name
Name of the wizard.
Definition: sorcery.h:278
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
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.
int value
Definition: syslog.c:37
const char * args
struct timeval ast_tv(ast_time_t sec, ast_suseconds_t usec)
Returns a timeval from sec, usec.
Definition: time.h:235
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941