Asterisk - The Open Source Telephony Project  GIT-master-a24979a
res_sorcery_astdb.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 /*!
20  * \file
21  *
22  * \brief Sorcery Astdb Object Wizard
23  *
24  * \author Joshua Colp <jcolp@digium.com>
25  */
26 
27 /*** MODULEINFO
28  <support_level>core</support_level>
29  ***/
30 
31 #include "asterisk.h"
32 
33 #include <regex.h>
34 
35 #include "asterisk/module.h"
36 #include "asterisk/sorcery.h"
37 #include "asterisk/astdb.h"
38 #include "asterisk/json.h"
39 
40 static void *sorcery_astdb_open(const char *data);
41 static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, void *object);
42 static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
43 static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
44 static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
45  const struct ast_variable *fields);
46 static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
47 static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len);
48 static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object);
49 static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object);
50 static void sorcery_astdb_close(void *data);
51 
53  .name = "astdb",
54  .open = sorcery_astdb_open,
55  .create = sorcery_astdb_create,
56  .retrieve_id = sorcery_astdb_retrieve_id,
57  .retrieve_fields = sorcery_astdb_retrieve_fields,
58  .retrieve_multiple = sorcery_astdb_retrieve_multiple,
59  .retrieve_regex = sorcery_astdb_retrieve_regex,
60  .retrieve_prefix = sorcery_astdb_retrieve_prefix,
61  .update = sorcery_astdb_update,
62  .delete = sorcery_astdb_delete,
63  .close = sorcery_astdb_close,
64 };
65 
66 static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, void *object)
67 {
69  RAII_VAR(char *, value, NULL, ast_json_free);
70  const char *prefix = data;
71  char family[strlen(prefix) + strlen(ast_sorcery_object_get_type(object)) + 2];
72 
73  if (!objset || !(value = ast_json_dump_string(objset))) {
74  return -1;
75  }
76 
77  snprintf(family, sizeof(family), "%s/%s", prefix, ast_sorcery_object_get_type(object));
78 
79  return ast_db_put(family, ast_sorcery_object_get_id(object), value);
80 }
81 
82 /*! \brief Internal helper function which returns a filtered objectset.
83  *
84  * The following are filtered out of the objectset:
85  * \li Fields that are not registered with sorcery.
86  *
87  * \param objectset Objectset to filter.
88  * \param sorcery The sorcery instance that is requesting an objectset.
89  * \param type The object type
90  *
91  * \return The filtered objectset
92  */
93 static struct ast_variable *sorcery_astdb_filter_objectset(struct ast_variable *objectset, const struct ast_sorcery *sorcery,
94  const char *type)
95 {
96  struct ast_variable *previous = NULL, *field = objectset;
97  struct ast_sorcery_object_type *object_type;
98 
100  if (!object_type) {
101  ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type);
102  return objectset;
103  }
104 
105  while (field) {
106  struct ast_variable *removed;
107 
108  if (ast_sorcery_is_object_field_registered(object_type, field->name)) {
109  previous = field;
110  field = field->next;
111  continue;
112  }
113 
114  ast_debug(1, "Filtering out astdb field '%s' from retrieval\n", field->name);
115 
116  if (previous) {
117  previous->next = field->next;
118  } else {
119  objectset = field->next;
120  }
121 
122  removed = field;
123  field = field->next;
124  removed->next = NULL;
125 
126  ast_variables_destroy(removed);
127  }
128 
129  ao2_cleanup(object_type);
130 
131  return objectset;
132 }
133 
134 /*! \brief Internal helper function which retrieves an object, or multiple objects, using fields for criteria */
135 static void *sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects)
136 {
137  const char *prefix = data;
138  char family[strlen(prefix) + strlen(type) + 2];
139  RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
140  struct ast_db_entry *entry;
141 
142  snprintf(family, sizeof(family), "%s/%s", prefix, type);
143 
144  if (!(entries = ast_db_gettree(family, NULL))) {
145  return NULL;
146  }
147 
148  for (entry = entries; entry; entry = entry->next) {
149  const char *key = entry->key + strlen(family) + 2;
150  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
151  struct ast_json_error error;
152  RAII_VAR(struct ast_variable *, existing, NULL, ast_variables_destroy);
153  void *object = NULL;
154 
155  if (!(json = ast_json_load_string(entry->data, &error))) {
156  return NULL;
157  }
158 
160  return NULL;
161  }
162 
163  existing = sorcery_astdb_filter_objectset(existing, sorcery, type);
164 
165  if (fields && !ast_variable_lists_match(existing, fields, 0)) {
166  continue;
167  }
168 
169  if (!(object = ast_sorcery_alloc(sorcery, type, key)) ||
170  ast_sorcery_objectset_apply(sorcery, object, existing)) {
171  ao2_cleanup(object);
172  return NULL;
173  }
174 
175  if (!objects) {
176  return object;
177  }
178 
179  ao2_link(objects, object);
180  ao2_cleanup(object);
181  }
182 
183  return NULL;
184 }
185 
186 static void *sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
187 {
188  return sorcery_astdb_retrieve_fields_common(sorcery, data, type, fields, NULL);
189 }
190 
191 static void *sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
192 {
193  const char *prefix = data;
194  char family[strlen(prefix) + strlen(type) + 2];
195  RAII_VAR(char *, value, NULL, ast_free_ptr);
196  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
197  struct ast_json_error error;
198  RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
199  void *object = NULL;
200 
201  snprintf(family, sizeof(family), "%s/%s", prefix, type);
202 
203  if (ast_db_get_allocated(family, id, &value)
204  || !(json = ast_json_load_string(value, &error))
206  || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
207  || !(object = ast_sorcery_alloc(sorcery, type, id))
208  || ast_sorcery_objectset_apply(sorcery, object, objset)) {
209  ast_debug(3, "Failed to retrieve object '%s' from astdb\n", id);
210  ao2_cleanup(object);
211  return NULL;
212  }
213 
214  return object;
215 }
216 
217 static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
218 {
219  sorcery_astdb_retrieve_fields_common(sorcery, data, type, fields, objects);
220 }
221 
222 /*!
223  * \internal
224  * \brief Convert regex prefix pattern to astDB prefix pattern if possible.
225  *
226  * \param tree astDB prefix pattern buffer to fill.
227  * \param regex Extended regular expression with the start anchor character '^'.
228  *
229  * \note Since this is a helper function, the tree buffer is
230  * assumed to always be large enough.
231  *
232  * \retval 0 on success.
233  * \retval -1 on error. regex is invalid.
234  */
235 static int make_astdb_prefix_pattern(char *tree, const char *regex)
236 {
237  const char *src;
238  char *dst;
239 
240  for (dst = tree, src = regex + 1; *src; ++src) {
241  if (*src == '\\') {
242  /* Escaped regex char. */
243  ++src;
244  if (!*src) {
245  /* Invalid regex. The caller escaped the string terminator. */
246  return -1;
247  }
248  } else if (*src == '$') {
249  if (!src[1]) {
250  /* Remove the tail anchor character. */
251  *dst = '\0';
252  return 0;
253  }
254  } else if (strchr(".?*+{[(|", *src)) {
255  /*
256  * The regex is not a simple prefix pattern.
257  *
258  * XXX With more logic, it is possible to simply
259  * use the current prefix pattern. The last character
260  * needs to be removed if possible when the current regex
261  * token is "?*{". Also the rest of the regex pattern
262  * would need to be checked for subgroup/alternation.
263  * Subgroup/alternation is too complex for a simple prefix
264  * match.
265  */
266  dst = tree;
267  break;
268  }
269  *dst++ = *src;
270  }
271  if (dst != tree) {
272  *dst++ = '%';
273  }
274  *dst = '\0';
275  return 0;
276 }
277 
278 static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
279 {
280  const char *prefix = data;
281  char family[strlen(prefix) + strlen(type) + 2];
282  char tree[strlen(regex) + 1];
283  RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
284  regex_t expression;
285  struct ast_db_entry *entry;
286 
287  snprintf(family, sizeof(family), "%s/%s", prefix, type);
288 
289  if (regex[0] == '^') {
290  /*
291  * For performance reasons, try to create an astDB prefix
292  * pattern from the regex to reduce the number of entries
293  * retrieved from astDB for regex to then match.
294  */
295  if (make_astdb_prefix_pattern(tree, regex)) {
296  return;
297  }
298  } else {
299  tree[0] = '\0';
300  }
301 
302  if (!(entries = ast_db_gettree(family, tree))
303  || regcomp(&expression, regex, REG_EXTENDED | REG_NOSUB)) {
304  return;
305  }
306 
307  for (entry = entries; entry; entry = entry->next) {
308  /* The key in the entry includes the family, so we need to strip it out for regex purposes */
309  const char *key = entry->key + strlen(family) + 2;
310  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
311  struct ast_json_error error;
312  RAII_VAR(void *, object, NULL, ao2_cleanup);
313  RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
314 
315  if (regexec(&expression, key, 0, NULL, 0)) {
316  continue;
317  } else if (!(json = ast_json_load_string(entry->data, &error))
319  || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
320  || !(object = ast_sorcery_alloc(sorcery, type, key))
321  || ast_sorcery_objectset_apply(sorcery, object, objset)) {
322  regfree(&expression);
323  return;
324  }
325 
326  ao2_link(objects, object);
327  }
328 
329  regfree(&expression);
330 }
331 
332 static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
333 {
334  const char *family_prefix = data;
335  size_t family_len = strlen(family_prefix) + strlen(type) + 1; /* +1 for slash delimiter */
336  char family[family_len + 1];
337  char tree[prefix_len + 1];
338  RAII_VAR(struct ast_db_entry *, entries, NULL, ast_db_freetree);
339  struct ast_db_entry *entry;
340 
341  snprintf(tree, sizeof(tree), "%.*s", (int) prefix_len, prefix);
342  snprintf(family, sizeof(family), "%s/%s", family_prefix, type);
343 
344  if (!(entries = ast_db_gettree_by_prefix(family, tree))) {
345  return;
346  }
347 
348  for (entry = entries; entry; entry = entry->next) {
349  /* The key in the entry includes the family, so we need to strip it out */
350  const char *key = entry->key + family_len + 2;
351  RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
352  struct ast_json_error error;
353  RAII_VAR(void *, object, NULL, ao2_cleanup);
354  RAII_VAR(struct ast_variable *, objset, NULL, ast_variables_destroy);
355 
356  if (!(json = ast_json_load_string(entry->data, &error))
358  || !(objset = sorcery_astdb_filter_objectset(objset, sorcery, type))
359  || !(object = ast_sorcery_alloc(sorcery, type, key))
360  || ast_sorcery_objectset_apply(sorcery, object, objset)) {
361  return;
362  }
363 
364  ao2_link(objects, object);
365  }
366 }
367 
368 static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object)
369 {
370  const char *prefix = data;
371  char family[strlen(prefix) + strlen(ast_sorcery_object_get_type(object)) + 2], value[2];
372 
373  snprintf(family, sizeof(family), "%s/%s", prefix, ast_sorcery_object_get_type(object));
374 
375  /* It is okay for the value to be truncated, we are only checking that it exists */
376  if (ast_db_get(family, ast_sorcery_object_get_id(object), value, sizeof(value))) {
377  return -1;
378  }
379 
380  /* The only difference between update and create is that for update the object must already exist */
381  return sorcery_astdb_create(sorcery, data, object);
382 }
383 
384 static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object)
385 {
386  const char *prefix = data;
387  char family[strlen(prefix) + strlen(ast_sorcery_object_get_type(object)) + 2];
388  char value[2];
389 
390  snprintf(family, sizeof(family), "%s/%s", prefix, ast_sorcery_object_get_type(object));
391 
392  if (ast_db_get(family, ast_sorcery_object_get_id(object), value, sizeof(value))) {
393  return -1;
394  }
395 
396  return ast_db_del(family, ast_sorcery_object_get_id(object));
397 }
398 
399 static void *sorcery_astdb_open(const char *data)
400 {
401  /* We require a prefix for family string generation, or else stuff could mix together */
402  if (ast_strlen_zero(data)) {
403  return NULL;
404  }
405 
406  return ast_strdup(data);
407 }
408 
409 static void sorcery_astdb_close(void *data)
410 {
411  ast_free(data);
412 }
413 
414 static int load_module(void)
415 {
418  }
419 
421 }
422 
423 static int unload_module(void)
424 {
426  return 0;
427 }
428 
430  .support_level = AST_MODULE_SUPPORT_CORE,
431  .load = load_module,
432  .unload = unload_module,
433  .load_pri = AST_MODPRI_REALTIME_DRIVER,
434 );
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:327
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:422
int ast_db_get(const char *family, const char *key, char *value, int valuelen)
Get key value specified by family/key.
Definition: main/db.c:412
int ast_db_del(const char *family, const char *key)
Delete entry in astdb.
Definition: main/db.c:429
struct ast_db_entry * ast_db_gettree_by_prefix(const char *family, const char *key_prefix)
Get a list of values with the given key prefix.
Definition: main/db.c:571
void ast_db_freetree(struct ast_db_entry *entry)
Free structure created by ast_db_gettree()
Definition: main/db.c:598
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:531
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
void ast_free_ptr(void *ptr)
free() wrapper
Definition: astmm.c:1739
#define ast_log
Definition: astobj2.c:42
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
static const char type[]
Definition: chan_ooh323.c:109
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static char prefix[MAX_PREFIX]
Definition: http.c:144
int ast_variable_lists_match(const struct ast_variable *left, const struct ast_variable *right, int exact_match)
Tests 2 variable lists to see if they match.
Definition: main/config.c:846
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_WARNING
Asterisk JSON abstraction layer.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
void ast_json_free(void *p)
Asterisk's custom JSON allocator. Exposed for use by unit tests.
Definition: json.c:52
#define ast_json_dump_string(root)
Encode a JSON value to a compact string.
Definition: json.h:783
@ AST_JSON_TO_AST_VARS_CODE_SUCCESS
Conversion successful.
Definition: json.h:1073
enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
Convert a ast_json list of key/value pair tuples into a ast_variable list.
Definition: json.c:797
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
Definition: json.c:546
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:317
@ AST_MODFLAG_GLOBAL_SYMBOLS
Definition: module.h:316
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:543
@ AST_MODPRI_REALTIME_DRIVER
Definition: module.h:323
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static struct ast_sorcery * sorcery
static struct ast_sorcery_wizard astdb_object_wizard
static void sorcery_astdb_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
static void * sorcery_astdb_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
static struct ast_variable * sorcery_astdb_filter_objectset(struct ast_variable *objectset, const struct ast_sorcery *sorcery, const char *type)
Internal helper function which returns a filtered objectset.
static void * sorcery_astdb_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
static int sorcery_astdb_delete(const struct ast_sorcery *sorcery, void *data, void *object)
static int sorcery_astdb_update(const struct ast_sorcery *sorcery, void *data, void *object)
static void sorcery_astdb_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
static void sorcery_astdb_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
static void sorcery_astdb_close(void *data)
static int load_module(void)
static int sorcery_astdb_create(const struct ast_sorcery *sorcery, void *data, void *object)
static int make_astdb_prefix_pattern(char *tree, const char *regex)
static void * sorcery_astdb_retrieve_fields_common(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields, struct ao2_container *objects)
Internal helper function which retrieves an object, or multiple objects, using fields for criteria.
static int unload_module(void)
static void * sorcery_astdb_open(const char *data)
#define NULL
Definition: resample.c:96
Sorcery Data Access Layer API.
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
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
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
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:2509
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:1632
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2324
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
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:2489
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Generic container type.
Definition: astdb.h:31
char * key
Definition: astdb.h:33
JSON parsing error information.
Definition: json.h:849
Abstract JSON element (object, array, string, int, ...).
Structure for registered object type.
Definition: sorcery.c:148
char name[MAX_OBJECT_TYPE]
Unique name of the object type.
Definition: sorcery.c:150
Interface for a sorcery wizard.
Definition: sorcery.h:276
const char * name
Name of the wizard.
Definition: sorcery.h:278
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Definition: search.h:40
char * key
Definition: search.h:41
char * data
Definition: search.h:42
int value
Definition: syslog.c:37
int error(const char *format,...)
Definition: utils/frame.c:999
#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:936