Asterisk - The Open Source Telephony Project GIT-master-3dae2cf
media_cache.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2015, Matt Jordan
5 *
6 * Matt Jordan <mjordan@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*!
20 * \file
21 * \brief An in-memory media cache
22 *
23 * \author \verbatim Matt Jordan <mjordan@digium.com> \endverbatim
24 *
25 */
26
27/*** MODULEINFO
28 <support_level>core</support_level>
29 ***/
30
31#include "asterisk.h"
32
33#include <sys/stat.h>
34#include "asterisk/config.h"
35#include "asterisk/bucket.h"
36#include "asterisk/astdb.h"
37#include "asterisk/cli.h"
38#include "asterisk/file.h"
40
41/*! The name of the AstDB family holding items in the cache. */
42#define AST_DB_FAMILY "MediaCache"
43
44/*! Length of 'MediaCache' + 2 '/' characters */
45#define AST_DB_FAMILY_LEN 12
46
47/*! Number of buckets in the ao2 container holding our media items */
48#define AO2_BUCKETS 61
49
50/*! Our one and only container holding media items */
52
53int ast_media_cache_exists(const char *uri)
54{
55 struct ast_bucket_file *bucket_file;
56
57 if (ast_strlen_zero(uri)) {
58 return 0;
59 }
60
61 bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY);
62 if (bucket_file) {
63 ao2_ref(bucket_file, -1);
64 return 1;
65 }
66
67 /* Check to see if any bucket implementation could return this item */
68 bucket_file = ast_bucket_file_retrieve(uri);
69 if (bucket_file) {
70 ao2_ref(bucket_file, -1);
71 return 1;
72 }
73
74 return 0;
75}
76
77/*!
78 * \internal
79 * \brief Sync \c bucket_file metadata to the AstDB
80 */
81static int metadata_sync_to_astdb(void *obj, void *arg, int flags)
82{
83 struct ast_bucket_metadata *metadata = obj;
84 const char *hash = arg;
85
86 ast_db_put(hash, metadata->name, metadata->value);
87
88 return 0;
89}
90
91/*!
92 * \internal
93 * \brief Sync a media cache item to the AstDB
94 * \param bucket_file The \ref ast_bucket_file media cache item to sync
95 */
96static void media_cache_item_sync_to_astdb(struct ast_bucket_file *bucket_file)
97{
98 char hash[41]; /* 40 character SHA1 hash */
99
100 ast_sha1_hash(hash, ast_sorcery_object_get_id(bucket_file));
101 if (ast_db_put(AST_DB_FAMILY, ast_sorcery_object_get_id(bucket_file), hash)) {
102 return;
103 }
104
105 ast_db_put(hash, "path", bucket_file->path);
107}
108
109/*!
110 * \internal
111 * \brief Delete a media cache item from the AstDB
112 * \param bucket_file The \ref ast_bucket_file media cache item to delete
113 */
114static void media_cache_item_del_from_astdb(struct ast_bucket_file *bucket_file)
115{
116 char *hash_value;
117
118 if (ast_db_get_allocated(AST_DB_FAMILY, ast_sorcery_object_get_id(bucket_file), &hash_value)) {
119 return;
120 }
121
122 ast_db_deltree(hash_value, NULL);
124 ast_free(hash_value);
125}
126
127/*!
128 * \internal
129 * \brief Update the name of the file backing a \c bucket_file
130 * \param bucket_file The \ref ast_bucket_file media cache item to update
131 * \param preferred_file_name The preferred name of the backing file
132 */
133static void bucket_file_update_path(struct ast_bucket_file *bucket_file,
134 const char *preferred_file_name)
135{
136 if (!ast_strlen_zero(preferred_file_name) && strcmp(bucket_file->path, preferred_file_name)) {
137 /* Use the preferred file name if available */
138 rename(bucket_file->path, preferred_file_name);
139 ast_copy_string(bucket_file->path, preferred_file_name,
140 sizeof(bucket_file->path));
141 } else if (!strchr(bucket_file->path, '.')) {
142 struct ast_bucket_metadata *ext =
143 ast_bucket_file_metadata_get(bucket_file, "ext");
144
145 if (ext) {
146 char *new_path;
147 if (ast_asprintf(&new_path, "%s%s", bucket_file->path, ext->value) != -1) {
148 rename(bucket_file->path, new_path);
149 ast_copy_string(bucket_file->path, new_path, sizeof(bucket_file->path));
150 ast_free(new_path);
151 }
152 ao2_ref(ext, -1);
153 }
154 }
155}
156
157int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name,
158 char *file_path, size_t len)
159{
160 struct ast_bucket_file *bucket_file;
161 struct ast_bucket_file *tmp_bucket_file;
162 char *ext;
163 if (ast_strlen_zero(uri)) {
164 return -1;
165 }
166
168 ast_debug(5, "Looking for media at local cache, file: %s\n", uri);
169
170 /* First, retrieve from the ao2 cache here. If we find a bucket_file
171 * matching the requested URI, ask the appropriate backend if it is
172 * stale. If not; return it.
173 */
174 bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_NOLOCK);
175 if (bucket_file) {
176 if (!ast_bucket_file_is_stale(bucket_file)
177 && ast_file_is_readable(bucket_file->path)) {
178 ast_copy_string(file_path, bucket_file->path, len);
179 if ((ext = strrchr(file_path, '.'))) {
180 *ext = '\0';
181 }
182 ao2_ref(bucket_file, -1);
183
184 ast_debug(5, "Returning media at local file: %s\n", file_path);
186 return 0;
187 }
188
189 /* Stale! Remove the item completely, as we're going to replace it next */
191 ast_bucket_file_delete(bucket_file);
192 ao2_ref(bucket_file, -1);
193 }
194 /* We unlock to retrieve the file, because it can take a long time;
195 * and we don't want to lock access to cached files while waiting
196 */
198
199 /* Either this is new or the resource is stale; do a full retrieve
200 * from the appropriate bucket_file backend
201 */
202 bucket_file = ast_bucket_file_retrieve(uri);
203 if (!bucket_file) {
204 ast_debug(2, "Failed to obtain media at '%s'\n", uri);
205 return -1;
206 }
207
208 /* we lock again, before updating cache */
210
211 /* We can have duplicated buckets here, we check if already exists
212 * before saving
213 */
214 tmp_bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_NOLOCK);
215 if (tmp_bucket_file) {
216 ao2_ref(tmp_bucket_file, -1);
217 ast_bucket_file_delete(bucket_file);
218 ao2_ref(bucket_file, -1);
220 return 0;
221 }
222
223 /* We can manipulate the 'immutable' bucket_file here, as we haven't
224 * let anyone know of its existence yet
225 */
226 bucket_file_update_path(bucket_file, preferred_file_name);
228 ast_copy_string(file_path, bucket_file->path, len);
229 if ((ext = strrchr(file_path, '.'))) {
230 *ext = '\0';
231 }
233 ao2_ref(bucket_file, -1);
234
235 ast_debug(5, "Returning media at local file: %s\n", file_path);
237
238 return 0;
239}
240
241int ast_media_cache_retrieve_metadata(const char *uri, const char *key,
242 char *value, size_t len)
243{
244 struct ast_bucket_file *bucket_file;
245 struct ast_bucket_metadata *metadata;
246
247 if (ast_strlen_zero(uri) || ast_strlen_zero(key) || !value) {
248 return -1;
249 }
250
251 bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY);
252 if (!bucket_file) {
253 return -1;
254 }
255
256 metadata = ao2_find(bucket_file->metadata, key, OBJ_SEARCH_KEY);
257 if (!metadata) {
258 ao2_ref(bucket_file, -1);
259 return -1;
260 }
261 ast_copy_string(value, metadata->value, len);
262
263 ao2_ref(metadata, -1);
264 ao2_ref(bucket_file, -1);
265 return 0;
266}
267
268int ast_media_cache_create_or_update(const char *uri, const char *file_path,
269 struct ast_variable *metadata)
270{
271 struct ast_bucket_file *bucket_file;
272 struct ast_variable *it_metadata;
273 struct stat st;
274 char tmp[128];
275 char *ext;
276 char *file_path_ptr;
277 int created = 0;
278 SCOPED_AO2LOCK(media_lock, media_cache);
279
280 if (ast_strlen_zero(file_path) || ast_strlen_zero(uri)) {
281 return -1;
282 }
283 file_path_ptr = ast_strdupa(file_path);
284
285 if (stat(file_path, &st)) {
286 ast_log(LOG_WARNING, "Unable to obtain information for file %s for URI %s\n",
287 file_path, uri);
288 return -1;
289 }
290
291 bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_NOLOCK);
292 if (bucket_file) {
293 struct ast_bucket_file *clone;
294
295 clone = ast_bucket_file_clone(bucket_file);
296 if (!clone) {
297 ao2_ref(bucket_file, -1);
298 return -1;
299 }
300
301 /* Remove the old bucket_file. We'll replace it if we succeed below. */
303 ao2_ref(bucket_file, -1);
304
305 bucket_file = clone;
306 } else {
307 bucket_file = ast_bucket_file_alloc(uri);
308 if (!bucket_file) {
309 ast_log(LOG_WARNING, "Failed to create file storage for %s and %s\n",
310 uri, file_path);
311 return -1;
312 }
313 created = 1;
314 }
315
316 strcpy(bucket_file->path, file_path);
317 bucket_file->created.tv_sec = st.st_ctime;
318 bucket_file->modified.tv_sec = st.st_mtime;
319
320 snprintf(tmp, sizeof(tmp), "%ld", (long)st.st_atime);
321 ast_bucket_file_metadata_set(bucket_file, "accessed", tmp);
322
323 snprintf(tmp, sizeof(tmp), "%jd", (intmax_t)st.st_size);
324 ast_bucket_file_metadata_set(bucket_file, "size", tmp);
325
326 ext = strrchr(file_path_ptr, '.');
327 if (ext) {
328 ast_bucket_file_metadata_set(bucket_file, "ext", ext + 1);
329 }
330
331 for (it_metadata = metadata; it_metadata; it_metadata = it_metadata->next) {
332 ast_bucket_file_metadata_set(bucket_file, it_metadata->name, it_metadata->value);
333 }
334
335 if (created && ast_bucket_file_create(bucket_file)) {
336 ast_log(LOG_WARNING, "Failed to create media for %s\n", uri);
337 ao2_ref(bucket_file, -1);
338 return -1;
339 }
341
343 ao2_ref(bucket_file, -1);
344 return 0;
345}
346
347int ast_media_cache_delete(const char *uri)
348{
349 struct ast_bucket_file *bucket_file;
350 int res;
351
352 if (ast_strlen_zero(uri)) {
353 return -1;
354 }
355
356 bucket_file = ao2_find(media_cache, uri, OBJ_SEARCH_KEY | OBJ_UNLINK);
357 if (!bucket_file) {
358 return -1;
359 }
360
361 res = ast_bucket_file_delete(bucket_file);
363
364 ao2_ref(bucket_file, -1);
365
366 return res;
367}
368
369/*!
370 * \internal
371 * \brief Remove a media cache item from the AstDB
372 * \param uri The unique URI that represents the item in the cache
373 * \param hash The hash key for the item in the AstDB
374 */
375static void media_cache_remove_from_astdb(const char *uri, const char *hash)
376{
378 ast_db_deltree(hash, NULL);
379}
380
381/*!
382 * \internal
383 * \brief Create an item in the media cache from entries in the AstDB
384 * \param uri The unique URI that represents the item in the cache
385 * \param hash The hash key for the item in the AstDB
386 * \retval 0 success
387 * \retval -1 failure
388 */
389static int media_cache_item_populate_from_astdb(const char *uri, const char *hash)
390{
391 struct ast_bucket_file *bucket_file;
392 struct ast_db_entry *db_tree;
393 struct ast_db_entry *db_entry;
394 struct stat st;
395
396 bucket_file = ast_bucket_file_alloc(uri);
397 if (!bucket_file) {
398 return -1;
399 }
400
401 db_tree = ast_db_gettree(hash, NULL);
402 for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
403 const char *key = strchr(db_entry->key + 1, '/');
404
405 if (ast_strlen_zero(key)) {
406 continue;
407 }
408 key++;
409
410 if (!strcasecmp(key, "path")) {
411 strcpy(bucket_file->path, db_entry->data);
412
413 if (stat(bucket_file->path, &st)) {
414 ast_log(LOG_WARNING, "Unable to obtain information for file %s for URI %s\n",
415 bucket_file->path, uri);
416 ao2_ref(bucket_file, -1);
417 ast_db_freetree(db_tree);
418 return -1;
419 }
420 } else {
421 ast_bucket_file_metadata_set(bucket_file, key, db_entry->data);
422 }
423 }
424 ast_db_freetree(db_tree);
425
426 if (ast_strlen_zero(bucket_file->path)) {
427 ao2_ref(bucket_file, -1);
428 ast_log(LOG_WARNING, "Failed to restore media cache item for '%s' from AstDB: no 'path' specified\n",
429 uri);
430 return -1;
431 }
432
433 ao2_link(media_cache, bucket_file);
434 ao2_ref(bucket_file, -1);
435
436 return 0;
437}
438
439/*!
440 * \internal
441 * \brief Populate the media cache from entries in the AstDB
442 */
444{
445 struct ast_db_entry *db_entry;
446 struct ast_db_entry *db_tree;
447
449 for (db_entry = db_tree; db_entry; db_entry = db_entry->next) {
451 media_cache_remove_from_astdb(db_entry->key, db_entry->data);
452 }
453 }
454 ast_db_freetree(db_tree);
455}
456
457/*!
458 * \internal
459 * \brief ao2 callback function for \ref media_cache_handle_show_all
460 */
461static int media_cache_prnt_summary(void *obj, void *arg, int flags)
462{
463#define FORMAT_ROW "%-40s\n\t%-40s\n"
464 struct ast_bucket_file *bucket_file = obj;
465 struct ast_cli_args *a = arg;
466
467 ast_cli(a->fd, FORMAT_ROW, ast_sorcery_object_get_id(bucket_file), bucket_file->path);
468
469#undef FORMAT_ROW
470 return CMP_MATCH;
471}
472
473static char *media_cache_handle_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
474{
475 switch (cmd) {
476 case CLI_INIT:
477 e->command = "media cache show all";
478 e->usage =
479 "Usage: media cache show all\n"
480 " Display a summary of all current items in the media cache.\n";
481 return NULL;
482 case CLI_GENERATE:
483 return NULL;
484 }
485
486 if (a->argc != 4) {
487 return CLI_SHOWUSAGE;
488 }
489
490 ast_cli(a->fd, "URI\n\tLocal File\n");
491 ast_cli(a->fd, "---------------\n");
493
494 return CLI_SUCCESS;
495}
496
497/*!
498 * \internal
499 * \brief CLI tab completion function for URIs
500 */
501static char *cli_complete_uri(const char *word)
502{
503 struct ast_bucket_file *bucket_file;
504 struct ao2_iterator it_media_items;
505 int wordlen = strlen(word);
506
507 it_media_items = ao2_iterator_init(media_cache, 0);
508 while ((bucket_file = ao2_iterator_next(&it_media_items))) {
509 if (!strncasecmp(word, ast_sorcery_object_get_id(bucket_file), wordlen)) {
511 }
512 ao2_ref(bucket_file, -1);
513 }
514 ao2_iterator_destroy(&it_media_items);
515
516 return NULL;
517}
518
519static char *media_cache_handle_show_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
520{
521#define FORMAT_ROW "\t%20s: %-40.40s\n"
522 struct ast_bucket_file *bucket_file;
523 struct ao2_iterator it_metadata;
524 struct ast_bucket_metadata *metadata;
525
526 switch (cmd) {
527 case CLI_INIT:
528 e->command = "media cache show";
529 e->usage =
530 "Usage: media cache show <uri>\n"
531 " Display all information about a particular item in the media cache.\n";
532 return NULL;
533 case CLI_GENERATE:
534 return a->pos == e->args ? cli_complete_uri(a->word) : NULL;
535 }
536
537 if (a->argc != 4) {
538 return CLI_SHOWUSAGE;
539 }
540
541 bucket_file = ao2_find(media_cache, a->argv[3], OBJ_SEARCH_KEY);
542 if (!bucket_file) {
543 ast_cli(a->fd, "Unable to find '%s' in the media cache\n", a->argv[3]);
544 return CLI_SUCCESS;
545 }
546
547 ast_cli(a->fd, "URI: %s\n", ast_sorcery_object_get_id(bucket_file));
548 ast_cli(a->fd, "%s\n", "----------------------------------------");
549 ast_cli(a->fd, FORMAT_ROW, "Path", bucket_file->path);
550
551 it_metadata = ao2_iterator_init(bucket_file->metadata, 0);
552 while ((metadata = ao2_iterator_next(&it_metadata))) {
553 ast_cli(a->fd, FORMAT_ROW, metadata->name, metadata->value);
554 ao2_ref(metadata, -1);
555 }
556 ao2_iterator_destroy(&it_metadata);
557
558 ao2_ref(bucket_file, -1);
559#undef FORMAT_ROW
560 return CLI_SUCCESS;
561}
562
563static char *media_cache_handle_delete_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
564{
565 switch (cmd) {
566 case CLI_INIT:
567 e->command = "media cache delete";
568 e->usage =
569 "Usage: media cache delete <uri>\n"
570 " Delete an item from the media cache.\n\n"
571 " Note that this will also remove any local storage of the media associated\n"
572 " with the URI, and will inform the backend supporting the URI scheme that\n"
573 " it should remove the item.\n";
574 return NULL;
575 case CLI_GENERATE:
576 return a->pos == e->args ? cli_complete_uri(a->word) : NULL;
577 }
578
579 if (a->argc != 4) {
580 return CLI_SHOWUSAGE;
581 }
582
583 if (ast_media_cache_delete(a->argv[3])) {
584 ast_cli(a->fd, "Unable to delete '%s'\n", a->argv[3]);
585 } else {
586 ast_cli(a->fd, "Deleted '%s' from the media cache\n", a->argv[3]);
587 }
588
589 return CLI_SUCCESS;
590}
591
592static char *media_cache_handle_refresh_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
593{
594 char file_path[PATH_MAX];
595
596 switch (cmd) {
597 case CLI_INIT:
598 e->command = "media cache refresh";
599 e->usage =
600 "Usage: media cache refresh <uri>\n"
601 " Ask for a refresh of a particular URI.\n\n"
602 " If the item does not already exist in the media cache, the item will be\n"
603 " populated from the backend supporting the URI scheme.\n";
604 return NULL;
605 case CLI_GENERATE:
606 return a->pos == e->args ? cli_complete_uri(a->word) : NULL;
607 }
608
609 if (a->argc != 4) {
610 return CLI_SHOWUSAGE;
611 }
612
613 if (ast_media_cache_retrieve(a->argv[3], NULL, file_path, sizeof(file_path))) {
614 ast_cli(a->fd, "Unable to refresh '%s'\n", a->argv[3]);
615 } else {
616 ast_cli(a->fd, "Refreshed '%s' to local storage '%s'\n", a->argv[3], file_path);
617 }
618
619 return CLI_SUCCESS;
620}
621
622static char *media_cache_handle_create_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
623{
624 switch (cmd) {
625 case CLI_INIT:
626 e->command = "media cache create";
627 e->usage =
628 "Usage: media cache create <uri> <file>\n"
629 " Create an item in the media cache by associating a local media file with\n"
630 " some URI.\n";
631 return NULL;
632 case CLI_GENERATE:
633 return NULL;
634 }
635
636 if (a->argc != 5) {
637 return CLI_SHOWUSAGE;
638 }
639
640 if (ast_media_cache_create_or_update(a->argv[3], a->argv[4], NULL)) {
641 ast_cli(a->fd, "Unable to create '%s' associated with local file '%s'\n",
642 a->argv[3], a->argv[4]);
643 } else {
644 ast_cli(a->fd, "Created '%s' for '%s' in the media cache\n",
645 a->argv[3], a->argv[4]);
646 }
647
648 return CLI_SUCCESS;
649}
650
652 AST_CLI_DEFINE(media_cache_handle_show_all, "Show all items in the media cache"),
653 AST_CLI_DEFINE(media_cache_handle_show_item, "Show a single item in the media cache"),
654 AST_CLI_DEFINE(media_cache_handle_delete_item, "Remove an item from the media cache"),
655 AST_CLI_DEFINE(media_cache_handle_refresh_item, "Refresh an item in the media cache"),
656 AST_CLI_DEFINE(media_cache_handle_create_item, "Create an item in the media cache"),
657};
658
659/*!
660 * \internal
661 * \brief Shutdown the media cache
662 */
663static void media_cache_shutdown(void)
664{
667
669}
670
672{
674
677 if (!media_cache) {
678 return -1;
679 }
680
682 return -1;
683 }
684
686
687 return 0;
688}
Persistent data storage (akin to *doze registry)
int ast_db_put(const char *family, const char *key, const char *value)
Store value addressed by family/key.
Definition: main/db.c:341
int ast_db_get_allocated(const char *family, const char *key, char **out)
Get key value specified by family/key as a heap allocated string.
Definition: main/db.c:437
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:478
struct ast_db_entry * ast_db_gettree(const char *family, const char *keytree)
Get a list of values within the astdb tree.
Definition: main/db.c:641
int ast_db_deltree(const char *family, const char *keytree)
Delete one or more entries in astdb.
Definition: main/db.c:565
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:701
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 PATH_MAX
Definition: asterisk.h:40
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#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
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#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_cleanup(obj)
Definition: astobj2.h:1934
#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
#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_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
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_MULTIPLE
Definition: astobj2.h:1049
@ 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_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
static int tmp()
Definition: bt_open.c:389
Bucket File API.
struct ast_bucket_file * ast_bucket_file_clone(struct ast_bucket_file *file)
Clone a bucket file.
Definition: bucket.c:810
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
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_file_create(struct ast_bucket_file *file)
Create a new bucket file in backend storage.
Definition: bucket.c:725
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
struct ast_bucket_file * ast_bucket_file_retrieve(const char *uri)
Retrieve a bucket file.
Definition: bucket.c:815
int ast_bucket_file_delete(struct ast_bucket_file *file)
Delete a bucket file from backend storage.
Definition: bucket.c:844
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
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2768
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
short word
Generic File Format Support. Should be included by clients of the file handling routines....
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const char * ext
Definition: http.c:150
Configuration File Parser.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
Definition: lock.h:604
static void media_cache_populate_from_astdb(void)
Definition: media_cache.c:443
static int media_cache_prnt_summary(void *obj, void *arg, int flags)
Definition: media_cache.c:461
static struct ao2_container * media_cache
Definition: media_cache.c:51
#define AST_DB_FAMILY_LEN
Definition: media_cache.c:45
static void media_cache_shutdown(void)
Definition: media_cache.c:663
#define FORMAT_ROW
int ast_media_cache_init(void)
Initialize the media cache.
Definition: media_cache.c:671
static void bucket_file_update_path(struct ast_bucket_file *bucket_file, const char *preferred_file_name)
Definition: media_cache.c:133
static struct ast_cli_entry cli_media_cache[]
Definition: media_cache.c:651
static int media_cache_item_populate_from_astdb(const char *uri, const char *hash)
Definition: media_cache.c:389
static void media_cache_item_sync_to_astdb(struct ast_bucket_file *bucket_file)
Definition: media_cache.c:96
static int metadata_sync_to_astdb(void *obj, void *arg, int flags)
Definition: media_cache.c:81
static char * media_cache_handle_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: media_cache.c:473
static char * media_cache_handle_create_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: media_cache.c:622
static char * media_cache_handle_delete_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: media_cache.c:563
int ast_media_cache_retrieve(const char *uri, const char *preferred_file_name, char *file_path, size_t len)
Retrieve an item from the cache.
Definition: media_cache.c:157
static char * cli_complete_uri(const char *word)
Definition: media_cache.c:501
static char * media_cache_handle_show_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: media_cache.c:519
int ast_media_cache_create_or_update(const char *uri, const char *file_path, struct ast_variable *metadata)
Create/update a cached media item.
Definition: media_cache.c:268
#define AO2_BUCKETS
Definition: media_cache.c:48
static char * media_cache_handle_refresh_item(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Definition: media_cache.c:592
int ast_media_cache_delete(const char *uri)
Remove an item from the media cache.
Definition: media_cache.c:347
#define AST_DB_FAMILY
Definition: media_cache.c:42
static void media_cache_item_del_from_astdb(struct ast_bucket_file *bucket_file)
Definition: media_cache.c:114
static void media_cache_remove_from_astdb(const char *uri, const char *hash)
Definition: media_cache.c:375
int ast_media_cache_exists(const char *uri)
Check if an item exists in the cache.
Definition: media_cache.c:53
int ast_media_cache_retrieve_metadata(const char *uri, const char *key, char *value, size_t len)
Retrieve metadata from an item in the cache.
Definition: media_cache.c:241
An in-memory media cache.
#define NULL
Definition: resample.c:96
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_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2464
int ast_sorcery_object_id_hash(const void *obj, int flags)
ao2 object hasher based on sorcery id.
Definition: sorcery.c:2475
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
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
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
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
descriptor for a cli entry.
Definition: cli.h:171
int args
This gets set in ast_cli_register()
Definition: cli.h:185
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Definition: astdb.h:31
struct ast_db_entry * next
Definition: astdb.h:32
char * key
Definition: astdb.h:33
char data[0]
Definition: astdb.h:34
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
int value
Definition: syslog.c:37
static struct test_val a
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
Definition: utils.c:3107
#define ARRAY_LEN(a)
Definition: utils.h:666
void ast_sha1_hash(char *output, const char *input)
Produces SHA1 hash based on input string.
Definition: utils.c:266