Asterisk - The Open Source Telephony Project  18.5.0
res_sorcery_realtime.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 <[email protected]>
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 Realtime Object Wizard
23  *
24  * \author Joshua Colp <[email protected]>
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 
38 /*! \brief They key field used to store the unique identifier for the object */
39 #define UUID_FIELD "id"
40 
46 };
47 
48 struct sorcery_config {
50  char family[];
51 };
52 
53 static void *sorcery_realtime_open(const char *data);
54 static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object);
55 static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
56 static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
57 static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects,
58  const struct ast_variable *fields);
59 static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
60 static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
61  struct ao2_container *objects, const char *prefix, const size_t prefix_len);
62 static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object);
63 static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object);
64 static void sorcery_realtime_close(void *data);
65 
67  .name = "realtime",
68  .open = sorcery_realtime_open,
69  .create = sorcery_realtime_create,
70  .retrieve_id = sorcery_realtime_retrieve_id,
71  .retrieve_fields = sorcery_realtime_retrieve_fields,
72  .retrieve_multiple = sorcery_realtime_retrieve_multiple,
73  .retrieve_regex = sorcery_realtime_retrieve_regex,
74  .retrieve_prefix = sorcery_realtime_retrieve_prefix,
75  .update = sorcery_realtime_update,
76  .delete = sorcery_realtime_delete,
77  .close = sorcery_realtime_close,
78 };
79 
80 static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object)
81 {
82  struct sorcery_config *config = data;
83  RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy);
85 
86  if (!fields || !id) {
88  return -1;
89  }
90 
91  /* Place the identifier at the front for sanity sake */
92  id->next = fields;
93  fields = id;
94 
95  return (ast_store_realtime_fields(config->family, fields) <= 0) ? -1 : 0;
96 }
97 
98 /*! \brief Internal helper function which returns a filtered objectset.
99  *
100  * The following are filtered out of the objectset:
101  * \li The id field. This is returned to the caller in an out parameter.
102  * \li Fields that are not registered with sorcery.
103  *
104  * \param objectset Objectset to filter.
105  * \param[out] id The ID of the sorcery object, as found in the objectset.
106  * \param sorcery The sorcery instance that is requesting an objectset.
107  * \param type The object type
108  *
109  * \return The filtered objectset
110  */
111 static struct ast_variable *sorcery_realtime_filter_objectset(struct ast_variable *objectset, struct ast_variable **id,
112  const struct ast_sorcery *sorcery, const char *type)
113 {
114  struct ast_variable *previous = NULL, *field = objectset;
115  struct ast_sorcery_object_type *object_type;
116 
117  object_type = ast_sorcery_get_object_type(sorcery, type);
118  if (!object_type) {
119  ast_log(LOG_WARNING, "Unknown sorcery object type %s. Expect errors\n", type);
120  /* Continue since we still want to filter out the id */
121  }
122 
123  while (field) {
124  int remove_field = 0;
125  int delete_field = 0;
126 
127  if (!strcmp(field->name, UUID_FIELD)) {
128  *id = field;
129  remove_field = 1;
130  } else if (object_type &&
131  !ast_sorcery_is_object_field_registered(object_type, field->name)) {
132  ast_debug(1, "Filtering out realtime field '%s' from retrieval\n", field->name);
133  remove_field = 1;
134  delete_field = 1;
135  }
136 
137  if (remove_field) {
138  struct ast_variable *removed;
139 
140  if (previous) {
141  previous->next = field->next;
142  } else {
143  objectset = field->next;
144  }
145 
146  removed = field;
147  field = field->next;
148  removed->next = NULL;
149  if (delete_field) {
150  ast_variables_destroy(removed);
151  }
152  } else {
153  previous = field;
154  field = field->next;
155  }
156  }
157 
158  ao2_cleanup(object_type);
159 
160  return objectset;
161 }
162 
163 static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
164 {
165  struct sorcery_config *config = data;
166  RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
168  void *object = NULL;
169 
170  if (!(objectset = ast_load_realtime_fields(config->family, fields))) {
171  return NULL;
172  }
173 
174  objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);
175 
176  if (!id
177  || !(object = ast_sorcery_alloc(sorcery, type, id->value))
178  || ast_sorcery_objectset_apply(sorcery, object, objectset)) {
179  ao2_cleanup(object);
180  return NULL;
181  }
182 
183  return object;
184 }
185 
186 static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
187 {
189 
190  return sorcery_realtime_retrieve_fields(sorcery, data, type, fields);
191 }
192 
193 static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
194 {
195  struct sorcery_config *config = data;
196  RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy);
198  struct ast_category *row = NULL;
199 
200  if (!fields) {
201  char field[strlen(UUID_FIELD) + 6], value[2];
202 
203  if (config->fetch == UNQUALIFIED_FETCH_NO) {
204  return;
205  }
206  if (config->fetch == UNQUALIFIED_FETCH_ERROR) {
207  ast_log(LOG_ERROR, "Unqualified fetch prevented on %s\n", config->family);
208  return;
209  }
210  if (config->fetch == UNQUALIFIED_FETCH_WARN) {
211  ast_log(LOG_WARNING, "Unqualified fetch requested on %s\n", config->family);
212  }
213 
214  /* If no fields have been specified we want all rows, so trick realtime into doing it */
215  snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
216  snprintf(value, sizeof(value), "%%");
217 
218  if (!(all = ast_variable_new(field, value, ""))) {
219  return;
220  }
221 
222  fields = all;
223  }
224 
225  if (!(rows = ast_load_realtime_multientry_fields(config->family, fields))) {
226  return;
227  }
228 
229  while ((row = ast_category_browse_filtered(rows, NULL, row, NULL))) {
230  struct ast_variable *objectset = ast_category_detach_variables(row);
232  RAII_VAR(void *, object, NULL, ao2_cleanup);
233 
234  objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);
235 
236  if (id
237  && (object = ast_sorcery_alloc(sorcery, type, id->value))
238  && !ast_sorcery_objectset_apply(sorcery, object, objectset)) {
239  ao2_link(objects, object);
240  }
241 
242  ast_variables_destroy(objectset);
243  }
244 }
245 
246 static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
247 {
248  char field[strlen(UUID_FIELD) + 6], value[strlen(regex) + 3];
249  RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
250 
251  if (!ast_strlen_zero(regex)) {
252  /* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */
253  snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
254  if (regex[0] == '^') {
255  snprintf(value, sizeof(value), "%s%%", regex + 1);
256  } else {
257  snprintf(value, sizeof(value), "%%%s%%", regex);
258  }
259 
260  if (!(fields = ast_variable_new(field, value, ""))) {
261  return;
262  }
263  }
264 
265  sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
266 }
267 
268 static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type,
269  struct ao2_container *objects, const char *prefix, const size_t prefix_len)
270 {
271  char field[strlen(UUID_FIELD) + 6], value[prefix_len + 2];
272  RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
273 
274  if (prefix_len) {
275  snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
276  snprintf(value, sizeof(value), "%.*s%%", (int) prefix_len, prefix);
277  if (!(fields = ast_variable_new(field, value, ""))) {
278  return;
279  }
280  }
281 
282  sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
283 }
284 
285 static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object)
286 {
287  struct sorcery_config *config = data;
288  RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy);
289 
290  if (!fields) {
291  return -1;
292  }
293 
294  return (ast_update_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) < 0) ? -1 : 0;
295 }
296 
297 static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object)
298 {
299  struct sorcery_config *config = data;
300 
301  return (ast_destroy_realtime_fields(config->family, UUID_FIELD, ast_sorcery_object_get_id(object), NULL) <= 0) ? -1 : 0;
302 }
303 
304 static void *sorcery_realtime_open(const char *data)
305 {
306  struct sorcery_config *config;
307  char *tmp;
308  char *family;
309  char *option;
310 
311  /* We require a prefix for family string generation, or else stuff could mix together */
312  if (ast_strlen_zero(data)) {
313  return NULL;
314  }
315 
316  tmp = ast_strdupa(data);
317  family = strsep(&tmp, ",");
318 
319  if (!ast_realtime_is_mapping_defined(family)) {
320  return NULL;
321  }
322 
323  config = ast_calloc(1, sizeof(*config) + strlen(family) + 1);
324  if (!config) {
325  return NULL;
326  }
327 
328  strcpy(config->family, family); /* Safe */
329  config->fetch = UNQUALIFIED_FETCH_YES;
330 
331  while ((option = strsep(&tmp, ","))) {
332  char *name = strsep(&option, "=");
333  char *value = option;
334 
335  if (!strcasecmp(name, "allow_unqualified_fetch")) {
336  if (ast_strlen_zero(value) || !strcasecmp(value, "yes")) {
337  config->fetch = UNQUALIFIED_FETCH_YES;
338  } else if (!strcasecmp(value, "no")) {
339  config->fetch = UNQUALIFIED_FETCH_NO;
340  } else if (!strcasecmp(value, "warn")) {
341  config->fetch = UNQUALIFIED_FETCH_WARN;
342  } else if (!strcasecmp(value, "error")) {
343  config->fetch = UNQUALIFIED_FETCH_ERROR;
344  } else {
345  ast_log(LOG_ERROR, "Unrecognized value in %s:%s: '%s'\n", family, name, value);
346  return NULL;
347  }
348  } else {
349  ast_log(LOG_ERROR, "Unrecognized option in %s: '%s'\n", family, name);
350  return NULL;
351  }
352  }
353 
354  return config;
355 }
356 
357 static void sorcery_realtime_close(void *data)
358 {
359  ast_free(data);
360 }
361 
362 static int load_module(void)
363 {
364  if (ast_sorcery_wizard_register(&realtime_object_wizard)) {
366  }
367 
369 }
370 
371 static int unload_module(void)
372 {
373  ast_sorcery_wizard_unregister(&realtime_object_wizard);
374  return 0;
375 }
376 
378  .support_level = AST_MODULE_SUPPORT_CORE,
379  .load = load_module,
380  .unload = unload_module,
381  .load_pri = AST_MODPRI_REALTIME_DRIVER,
382 );
static int unload_module(void)
struct ast_variable * next
static const char type[]
Definition: chan_ooh323.c:109
static void sorcery_realtime_close(void *data)
Asterisk main include file. File version handling, generic pbx functions.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
char * config
Definition: conf2ael.c:66
static struct ast_sorcery_wizard realtime_object_wizard
static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object)
#define LOG_WARNING
Definition: logger.h:274
static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
static int tmp()
Definition: bt_open.c:389
Structure for variables, used for configurations and for channel variables.
struct ast_config * ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
Retrieve realtime configuration.
Definition: main/config.c:3426
static void * sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
Full structure for sorcery.
Definition: sorcery.c:230
enum unqualified_fetch fetch
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
static struct ast_variable * sorcery_realtime_filter_objectset(struct ast_variable *objectset, struct ast_variable **id, const struct ast_sorcery *sorcery, const char *type)
Internal helper function which returns a filtered objectset.
#define NULL
Definition: resample.c:96
static void * sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
int value
Definition: syslog.c:37
const char * name
Name of the wizard.
Definition: sorcery.h:278
unqualified_fetch
struct ast_category * ast_category_browse_filtered(struct ast_config *config, const char *category_name, struct ast_category *prev, const char *filter)
Browse categories with filters.
Definition: main/config.c:1335
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
static void sorcery_realtime_retrieve_prefix(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *prefix, const size_t prefix_len)
Structure for registered object type.
Definition: sorcery.c:148
#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:911
int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
Create realtime configuration.
Definition: main/config.c:3549
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object)
#define ast_variable_new(name, value, filename)
struct ao2_global_obj objects
Objects retrieved from the configuration file.
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 int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object)
Structure for storing configuration file sourced objects.
#define ast_sorcery_wizard_register(interface)
See __ast_sorcery_wizard_register()
Definition: sorcery.h:383
static void * sorcery_realtime_open(const char *data)
#define LOG_ERROR
Definition: logger.h:285
int ast_sorcery_wizard_unregister(const struct ast_sorcery_wizard *interface)
Unregister a sorcery wizard.
Definition: sorcery.c:474
static int load_module(void)
void * ast_sorcery_alloc(const struct ast_sorcery *sorcery, const char *type, const char *id)
Allocate an object.
Definition: sorcery.c:1744
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
Definition: sorcery.h:1136
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
static const char name[]
Definition: cdr_mysql.c:74
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
Definition: func_strings.c:948
struct ast_variable * ast_category_detach_variables(struct ast_category *cat)
Definition: main/config.c:1351
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_realtime_is_mapping_defined(const char *family)
Determine if a mapping exists for a given family.
Definition: main/config.c:3026
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
Interface for a sorcery wizard.
Definition: sorcery.h:276
char * strsep(char **str, const char *delims)
static struct ast_sorcery * sorcery
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ast_variable * ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
Retrieve realtime configuration.
Definition: main/config.c:3304
#define UUID_FIELD
They key field used to store the unique identifier for the object.
enum queue_result id
Definition: app_queue.c:1507
Generic container type.
int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Update realtime configuration.
Definition: main/config.c:3468
int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
Destroy realtime configuration.
Definition: main/config.c:3586
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
char name[MAX_OBJECT_TYPE]
Unique name of the object type.
Definition: sorcery.c:150
Sorcery Data Access Layer API.
static char prefix[MAX_PREFIX]
Definition: http.c:141
#define ao2_link(container, obj)
Definition: astobj2.h:1549