Sat Apr 26 2014 22:01:35

Asterisk developer's documentation


config_options.c
Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2012, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  * \brief Configuration Option-handling
00021  * \author Terry Wilson <twilson@digium.com>
00022  */
00023 
00024 /*** MODULEINFO
00025    <support_level>core</support_level>
00026  ***/
00027 
00028 #include "asterisk.h"
00029 
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 399564 $")
00031 
00032 #include <regex.h>
00033 
00034 #include "asterisk/config.h"
00035 #include "asterisk/config_options.h"
00036 #include "asterisk/stringfields.h"
00037 #include "asterisk/acl.h"
00038 #include "asterisk/frame.h"
00039 
00040 #ifdef LOW_MEMORY
00041 #define CONFIG_OPT_BUCKETS 5
00042 #else
00043 #define CONFIG_OPT_BUCKETS 53
00044 #endif /* LOW_MEMORY */
00045 
00046 /*! \brief Bits of aco_info that shouldn't be assigned outside this file
00047  * \internal
00048  */
00049 struct aco_info_internal {
00050    void *pending;              /*!< The user-defined config object awaiting application */
00051 };
00052 
00053 struct aco_type_internal {
00054    regex_t *regex;
00055    struct ao2_container *opts; /*!< The container of options registered to the aco_info */
00056 };
00057 
00058 struct aco_option {
00059    const char *name;
00060    const char *aliased_to;
00061    const char *default_val;
00062    enum aco_matchtype match_type;
00063    regex_t *name_regex;
00064    struct aco_type **obj;
00065    enum aco_option_type type;
00066    aco_option_handler handler;
00067    unsigned int flags;
00068    unsigned char deprecated:1;
00069    size_t argc;
00070    intptr_t args[0];
00071 };
00072 
00073 void *aco_pending_config(struct aco_info *info)
00074 {
00075    if (!(info && info->internal)) {
00076       ast_log(LOG_ERROR, "This may not be called without an initialized aco_info!\n");
00077       return NULL;
00078    }
00079    return info->internal->pending;
00080 }
00081 
00082 static void config_option_destroy(void *obj)
00083 {
00084    struct aco_option *opt = obj;
00085    if (opt->match_type == ACO_REGEX && opt->name_regex) {
00086       regfree(opt->name_regex);
00087       ast_free(opt->name_regex);
00088    }
00089 }
00090 
00091 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00092 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00093 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00094 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00095 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00096 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00097 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00098 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00099 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00100 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00101 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj);
00102 
00103 static aco_option_handler ast_config_option_default_handler(enum aco_option_type type)
00104 {
00105    switch(type) {
00106    case OPT_ACL_T: return acl_handler_fn;
00107    case OPT_BOOL_T: return bool_handler_fn;
00108    case OPT_BOOLFLAG_T: return boolflag_handler_fn;
00109    case OPT_CHAR_ARRAY_T: return chararray_handler_fn;
00110    case OPT_CODEC_T: return codec_handler_fn;
00111    case OPT_DOUBLE_T: return double_handler_fn;
00112    case OPT_INT_T: return int_handler_fn;
00113    case OPT_NOOP_T: return noop_handler_fn;
00114    case OPT_SOCKADDR_T: return sockaddr_handler_fn;
00115    case OPT_STRINGFIELD_T: return stringfield_handler_fn;
00116    case OPT_UINT_T: return uint_handler_fn;
00117 
00118    case OPT_CUSTOM_T: return NULL;
00119    }
00120 
00121    return NULL;
00122 }
00123 
00124 static regex_t *build_regex(const char *text)
00125 {
00126    int res;
00127    regex_t *regex;
00128 
00129    if (!(regex = ast_malloc(sizeof(*regex)))) {
00130       return NULL;
00131    }
00132 
00133    if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
00134       size_t len = regerror(res, regex, NULL, 0);
00135       char buf[len];
00136       regerror(res, regex, buf, len);
00137       ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
00138       ast_free(regex);
00139       return NULL;
00140    }
00141 
00142    return regex;
00143 }
00144 
00145 static int link_option_to_types(struct aco_type **types, struct aco_option *opt)
00146 {
00147    size_t idx = 0;
00148    struct aco_type *type;
00149 
00150    while ((type = types[idx++])) {
00151       if (!type->internal) {
00152          ast_log(LOG_ERROR, "Attempting to register option using uninitialized type\n");
00153          return -1;
00154       }
00155       if (!ao2_link(type->internal->opts, opt)) {
00156          do {
00157             ao2_unlink(types[idx]->internal->opts, opt);
00158          } while (--idx);
00159          return -1;
00160       }
00161    }
00162    /* The container(s) should hold the only ref to opt */
00163    ao2_ref(opt, -1);
00164 
00165    return 0;
00166 }
00167 
00168 int aco_option_register_deprecated(struct aco_info *info, const char *name, struct aco_type **types, const char *aliased_to)
00169 {
00170    struct aco_option *opt;
00171 
00172    if (!info || ast_strlen_zero(name) || ast_strlen_zero(aliased_to)) {
00173       return -1;
00174    }
00175 
00176    if (!(opt = ao2_alloc(sizeof(*opt), config_option_destroy))) {
00177       return -1;
00178    }
00179 
00180    opt->name = name;
00181    opt->aliased_to = aliased_to;
00182    opt->deprecated = 1;
00183    opt->match_type = ACO_EXACT;
00184 
00185    if (link_option_to_types(types, opt)) {
00186       ao2_ref(opt, -1);
00187       return -1;
00188    }
00189 
00190    return 0;
00191 }
00192 
00193 int __aco_option_register(struct aco_info *info, const char *name, enum aco_matchtype matchtype, struct aco_type **types,
00194    const char *default_val, enum aco_option_type kind, aco_option_handler handler, unsigned int flags, size_t argc, ...)
00195 {
00196    struct aco_option *opt;
00197    va_list ap;
00198    int tmp;
00199 
00200    /* Custom option types require a handler */
00201    if (!handler && kind == OPT_CUSTOM_T) {
00202       return -1;
00203    }
00204 
00205    if (!(types && types[0])) {
00206       return -1;
00207    }
00208 
00209    if (!(opt = ao2_alloc(sizeof(*opt) + argc * sizeof(opt->args[0]), config_option_destroy))) {
00210       return -1;
00211    }
00212 
00213    if (matchtype == ACO_REGEX && !(opt->name_regex = build_regex(name))) {
00214       ao2_ref(opt, -1);
00215       return -1;
00216    }
00217 
00218    va_start(ap, argc);
00219    for (tmp = 0; tmp < argc; tmp++) {
00220       opt->args[tmp] = va_arg(ap, size_t);
00221    }
00222    va_end(ap);
00223 
00224    opt->name = name;
00225    opt->match_type = matchtype;
00226    opt->default_val = default_val;
00227    opt->type = kind;
00228    opt->handler = handler;
00229    opt->flags = flags;
00230    opt->argc = argc;
00231 
00232    if (!opt->handler && !(opt->handler = ast_config_option_default_handler(opt->type))) {
00233       /* This should never happen */
00234       ast_log(LOG_ERROR, "No handler provided, and no default handler exists for type %d\n", opt->type);
00235       ao2_ref(opt, -1);
00236       return -1;
00237    };
00238 
00239    if (link_option_to_types(types, opt)) {
00240       ao2_ref(opt, -1);
00241       return -1;
00242    }
00243 
00244    return 0;
00245 }
00246 
00247 static int config_opt_hash(const void *obj, const int flags)
00248 {
00249    const struct aco_option *opt = obj;
00250    const char *name = (flags & OBJ_KEY) ? obj : opt->name;
00251    return ast_str_case_hash(name);
00252 }
00253 
00254 static int config_opt_cmp(void *obj, void *arg, int flags)
00255 {
00256    struct aco_option *opt1 = obj, *opt2 = arg;
00257    const char *name = (flags & OBJ_KEY) ? arg : opt2->name;
00258    return strcasecmp(opt1->name, name) ? 0 : CMP_MATCH | CMP_STOP;
00259 }
00260 
00261 static int find_option_cb(void *obj, void *arg, int flags)
00262 {
00263    struct aco_option *match = obj;
00264    const char *name = arg;
00265 
00266    switch (match->match_type) {
00267    case ACO_EXACT:
00268       return strcasecmp(name, match->name) ? 0 : CMP_MATCH | CMP_STOP;
00269    case ACO_REGEX:
00270       return regexec(match->name_regex, name, 0, NULL, 0) ? 0 : CMP_MATCH | CMP_STOP;
00271    }
00272    ast_log(LOG_ERROR, "Unknown match type. This should not be possible.\n");
00273    return CMP_STOP;
00274 }
00275 
00276 static struct aco_option *aco_option_find(struct aco_type *type, const char *name)
00277 {
00278    struct aco_option *opt;
00279 
00280    if (!type || !type->internal || !type->internal->opts) {
00281       ast_log(LOG_NOTICE, "Attempting to use NULL or unitialized config type\n");
00282       return NULL;
00283    }
00284 
00285    /* Try an exact match with OBJ_KEY for the common/fast case, then iterate through
00286     * all options for the regex cases */
00287    if (!(opt = ao2_callback(type->internal->opts, OBJ_KEY, find_option_cb, (void *) name))) {
00288       opt = ao2_callback(type->internal->opts, 0, find_option_cb, (void *) name);
00289    }
00290    return opt;
00291 }
00292 
00293 struct ao2_container *aco_option_container_alloc(void)
00294 {
00295    return ao2_container_alloc(CONFIG_OPT_BUCKETS, config_opt_hash, config_opt_cmp);
00296 }
00297 
00298 static struct aco_type *internal_aco_type_find(struct aco_file *file, struct ast_config *cfg, const char *category)
00299 {
00300    size_t x;
00301    struct aco_type *match;
00302    const char *val;
00303 
00304    for (x = 0, match = file->types[x]; match; match = file->types[++x]) {
00305       /* First make sure we are an object that can service this category */
00306       if (!regexec(match->internal->regex, category, 0, NULL, 0) == !match->category_match) {
00307          continue;
00308       }
00309 
00310       /* Then, see if we need to match a particular field */
00311       if (!ast_strlen_zero(match->matchfield) && (!ast_strlen_zero(match->matchvalue) || match->matchfunc)) {
00312          if (!(val = ast_variable_retrieve(cfg, category, match->matchfield))) {
00313             ast_log(LOG_ERROR, "Required match field '%s' not found\n", match->matchfield);
00314             return NULL;
00315          }
00316          if (match->matchfunc) {
00317             if (!match->matchfunc(val)) {
00318                continue;
00319             }
00320          } else if (strcasecmp(val, match->matchvalue)) {
00321             continue;
00322          }
00323       }
00324       /* If we get this far, we're a match */
00325       break;
00326    }
00327 
00328    return match;
00329 }
00330 
00331 static int is_preload(struct aco_file *file, const char *cat)
00332 {
00333    int i;
00334 
00335    if (!file->preload) {
00336       return 0;
00337    }
00338 
00339    for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
00340       if (!strcasecmp(cat, file->preload[i])) {
00341          return 1;
00342       }
00343    }
00344    return 0;
00345 }
00346 
00347 static int process_category(struct ast_config *cfg, struct aco_info *info, struct aco_file *file, const char *cat, int preload) {
00348    RAII_VAR(void *, new_item, NULL, ao2_cleanup);
00349    struct aco_type *type;
00350    /* For global types, field is the global option struct. For non-global, it is the container for items.
00351     * We do not grab a reference to these objects, as the info already holds references to them. This
00352     * pointer is just a convenience. Do not actually store it somewhere. */
00353    void **field;
00354 
00355    /* Skip preloaded categories if we aren't preloading */
00356    if (!preload && is_preload(file, cat)) {
00357       return 0;
00358    }
00359 
00360    /* Find aco_type by category, if not found it is an error */
00361    if (!(type = internal_aco_type_find(file, cfg, cat))) {
00362       ast_log(LOG_ERROR, "Could not find config type for category '%s' in '%s'\n", cat, file->filename);
00363       return -1;
00364    }
00365 
00366    field = info->internal->pending + type->item_offset;
00367    if (!*field) {
00368       ast_log(LOG_ERROR, "No object to update!\n");
00369       return -1;
00370    }
00371 
00372    if (type->type == ACO_GLOBAL && *field) {
00373       if (aco_process_category_options(type, cfg, cat, *field)) {
00374          ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
00375          return -1;
00376       }
00377    } else if (type->type == ACO_ITEM) {
00378       int new = 0;
00379       /* If we have multiple definitions of a category in a file, or can set the values from multiple
00380        * files, look up the entry if we've already added it so we can merge the values together.
00381        * Otherwise, alloc a new item. */
00382       if (*field) {
00383          if (!(new_item = type->item_find(*field, cat))) {
00384             if (!(new_item = type->item_alloc(cat))) {
00385                ast_log(LOG_ERROR, "In %s: Could not create item for %s\n", file->filename, cat);
00386                return -1;
00387             }
00388             if (aco_set_defaults(type, cat, new_item)) {
00389                ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, cat);
00390                return -1;
00391             }
00392             new = 1;
00393          }
00394       }
00395 
00396       if (type->item_pre_process && type->item_pre_process(new_item)) {
00397          ast_log(LOG_ERROR, "In %s: Preprocess callback for %s failed\n", file->filename, cat);
00398          return -1;
00399       }
00400 
00401       if (aco_process_category_options(type, cfg, cat, new_item)) {
00402          ast_log(LOG_ERROR, "In %s: Processing options for %s failed\n", file->filename, cat);
00403          return -1;
00404       }
00405 
00406       if (type->item_prelink && type->item_prelink(new_item)) {
00407          ast_log(LOG_ERROR, "In %s: Pre-link callback for %s failed\n", file->filename, cat);
00408          return -1;
00409       }
00410 
00411       if (new && !ao2_link(*field, new_item)) {
00412          ast_log(LOG_ERROR, "In %s: Linking config for %s failed\n", file->filename, cat);
00413          return -1;
00414       }
00415    }
00416    return 0;
00417 }
00418 
00419 static int apply_config(struct aco_info *info)
00420 {
00421    ao2_global_obj_replace_unref(*info->global_obj, info->internal->pending);
00422 
00423    return 0;
00424 }
00425 
00426 static enum aco_process_status internal_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
00427 {
00428    const char *cat = NULL;
00429 
00430    if (file->preload) {
00431       int i;
00432       for (i = 0; !ast_strlen_zero(file->preload[i]); i++) {
00433          if (process_category(cfg, info, file, file->preload[i], 1)) {
00434             return ACO_PROCESS_ERROR;
00435          }
00436       }
00437    }
00438 
00439    while ((cat = ast_category_browse(cfg, cat))) {
00440       if (process_category(cfg, info, file, cat, 0)) {
00441          return ACO_PROCESS_ERROR;
00442       }
00443    }
00444    return ACO_PROCESS_OK;
00445 }
00446 
00447 enum aco_process_status aco_process_ast_config(struct aco_info *info, struct aco_file *file, struct ast_config *cfg)
00448 {
00449    if (!info->internal) {
00450       ast_log(LOG_ERROR, "Attempt to process %s with uninitialized aco_info\n", file->filename);
00451       goto error;
00452    }
00453 
00454    if (!(info->internal->pending = info->snapshot_alloc())) {
00455       ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", file->filename);
00456       goto error;
00457    }
00458 
00459    if (internal_process_ast_config(info, file, cfg)) {
00460       goto error;
00461    }
00462 
00463    if (info->pre_apply_config && info->pre_apply_config()) {
00464       goto error;
00465    }
00466 
00467    if (apply_config(info)) {
00468       goto error;
00469    };
00470 
00471    ao2_cleanup(info->internal->pending);
00472    return ACO_PROCESS_OK;
00473 
00474 error:
00475    ao2_cleanup(info->internal->pending);
00476    return ACO_PROCESS_ERROR;
00477 }
00478 
00479 enum aco_process_status aco_process_config(struct aco_info *info, int reload)
00480 {
00481    struct ast_config *cfg;
00482    struct ast_flags cfg_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0, };
00483    int res = ACO_PROCESS_OK, x = 0;
00484    struct aco_file *file;
00485 
00486    if (!(info->files[0])) {
00487       ast_log(LOG_ERROR, "No filename given, cannot proceed!\n");
00488       return ACO_PROCESS_ERROR;
00489    }
00490 
00491    if (!info->internal) {
00492       ast_log(LOG_ERROR, "Attempting to process uninitialized aco_info\n");
00493       return ACO_PROCESS_ERROR;
00494    }
00495 
00496    if (!(info->internal->pending = info->snapshot_alloc())) {
00497       ast_log(LOG_ERROR, "In %s: Could not allocate temporary objects\n", info->module);
00498       return ACO_PROCESS_ERROR;
00499    }
00500 
00501    while (res != ACO_PROCESS_ERROR && (file = info->files[x++])) {
00502       const char *filename = file->filename;
00503       struct aco_type *match;
00504       int i;
00505 
00506       /* set defaults for global objects */
00507       for (i = 0, match = file->types[i]; match; match = file->types[++i]) {
00508          void **field = info->internal->pending + match->item_offset;
00509 
00510          if (match->type != ACO_GLOBAL || !*field) {
00511             continue;
00512          }
00513 
00514          if (aco_set_defaults(match, match->category, *field)) {
00515             ast_log(LOG_ERROR, "In %s: Setting defaults for %s failed\n", file->filename, match->category);
00516             res = ACO_PROCESS_ERROR;
00517             break;
00518          }
00519       }
00520 
00521       if (res == ACO_PROCESS_ERROR) {
00522          break;
00523       }
00524 
00525 try_alias:
00526       if (!(cfg = ast_config_load(filename, cfg_flags))) {
00527          if (file->alias && strcmp(file->alias, filename)) {
00528             filename = file->alias;
00529             goto try_alias;
00530          }
00531          ast_log(LOG_ERROR, "Unable to load config file '%s'\n", file->filename);
00532          res = ACO_PROCESS_ERROR;
00533          break;
00534       } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
00535          ast_debug(1, "%s was unchanged\n", file->filename);
00536          res = ACO_PROCESS_UNCHANGED;
00537          continue;
00538       } else if (cfg == CONFIG_STATUS_FILEINVALID) {
00539          ast_log(LOG_ERROR, "Contents of %s are invalid and cannot be parsed\n", file->filename);
00540          res = ACO_PROCESS_ERROR;
00541          break;
00542       } else if (cfg == CONFIG_STATUS_FILEMISSING) {
00543          if (file->alias && strcmp(file->alias, filename)) {
00544             filename = file->alias;
00545             goto try_alias;
00546          }
00547          ast_log(LOG_ERROR, "%s is missing! Cannot load %s\n", file->filename, info->module);
00548          res = ACO_PROCESS_ERROR;
00549          break;
00550       }
00551 
00552       res = internal_process_ast_config(info, file, cfg);
00553       ast_config_destroy(cfg);
00554    }
00555 
00556    if (res != ACO_PROCESS_OK) {
00557       goto end;
00558    }
00559 
00560    if (info->pre_apply_config && (info->pre_apply_config()))  {
00561       res = ACO_PROCESS_ERROR;
00562       goto end;
00563    }
00564 
00565    if (apply_config(info)) {
00566       res = ACO_PROCESS_ERROR;
00567       goto end;
00568    }
00569 
00570    if (info->post_apply_config) {
00571       info->post_apply_config();
00572    }
00573 
00574 end:
00575    ao2_cleanup(info->internal->pending);
00576    return res;
00577 }
00578 int aco_process_var(struct aco_type *type, const char *cat, struct ast_variable *var, void *obj)
00579 {
00580    RAII_VAR(struct aco_option *, opt, aco_option_find(type, var->name), ao2_cleanup);
00581    if (opt && opt->deprecated && !ast_strlen_zero(opt->aliased_to)) {
00582       const char *alias = ast_strdupa(opt->aliased_to);
00583       ast_log(LOG_WARNING, "At line %d of %s option '%s' is deprecated. Use '%s' instead\n", var->lineno, var->file, var->name, alias);
00584       ao2_ref(opt, -1);
00585       opt = aco_option_find(type, alias);
00586    }
00587 
00588    if (!opt) {
00589       ast_log(LOG_ERROR, "Could not find option suitable for category '%s' named '%s' at line %d of %s\n", cat, var->name, var->lineno, var->file);
00590       return -1;
00591    }
00592 
00593    if (!opt->handler) {
00594       /* It should be impossible for an option to not have a handler */
00595       ast_log(LOG_ERROR, "BUG! Somehow a config option for %s/%s was created with no handler!\n", cat, var->name);
00596       return -1;
00597    }
00598    if (opt->handler(opt, var, obj)) {
00599       ast_log(LOG_ERROR, "Error parsing %s=%s at line %d of %s\n", var->name, var->value, var->lineno, var->file);
00600       return -1;
00601    }
00602 
00603    return 0;
00604 }
00605 
00606 int aco_process_category_options(struct aco_type *type, struct ast_config *cfg, const char *cat, void *obj)
00607 {
00608    struct ast_variable *var;
00609 
00610    for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
00611       if (aco_process_var(type, cat, var, obj)) {
00612          return -1;
00613       }
00614    }
00615 
00616    return 0;
00617 }
00618 
00619 static void internal_type_destroy(struct aco_type *type)
00620 {
00621    /* If we've already had all our internal data cleared out,
00622     * then there's no need to proceed further
00623     */
00624    if (!type->internal) {
00625       return;
00626    }
00627 
00628    if (type->internal->regex) {
00629       regfree(type->internal->regex);
00630       ast_free(type->internal->regex);
00631    }
00632    ao2_cleanup(type->internal->opts);
00633    type->internal->opts = NULL;
00634    ast_free(type->internal);
00635    type->internal = NULL;
00636 }
00637 
00638 static void internal_file_types_destroy(struct aco_file *file)
00639 {
00640    size_t x;
00641    struct aco_type *t;
00642 
00643    for (x = 0, t = file->types[x]; t; t = file->types[++x]) {
00644       internal_type_destroy(t);
00645       t = NULL;
00646    }
00647 }
00648 
00649 static int internal_type_init(struct aco_type *type)
00650 {
00651    if (!(type->internal = ast_calloc(1, sizeof(*type->internal)))) {
00652       return -1;
00653    }
00654 
00655    if (!(type->internal->regex = build_regex(type->category))) {
00656       internal_type_destroy(type);
00657       return -1;
00658    }
00659 
00660    if (!(type->internal->opts = aco_option_container_alloc())) {
00661       internal_type_destroy(type);
00662       return -1;
00663    }
00664 
00665    return 0;
00666 }
00667 
00668 int aco_info_init(struct aco_info *info)
00669 {
00670    size_t x, y;
00671 
00672    if (!(info->internal = ast_calloc(1, sizeof(*info->internal)))) {
00673       return -1;
00674    }
00675 
00676    for (x = 0; info->files[x]; x++) {
00677       for (y = 0; info->files[x]->types[y]; y++) {
00678          if (internal_type_init(info->files[x]->types[y])) {
00679             goto error;
00680          }
00681       }
00682    }
00683 
00684    return 0;
00685 error:
00686    aco_info_destroy(info);
00687    return -1;
00688 }
00689 
00690 void aco_info_destroy(struct aco_info *info)
00691 {
00692    int x;
00693    /* It shouldn't be possible for internal->pending to be in use when this is called because
00694     * of the locks in loader.c around reloads and unloads and the fact that internal->pending
00695     * only exists while those locks are held */
00696    ast_free(info->internal);
00697    info->internal = NULL;
00698 
00699    for (x = 0; info->files[x]; x++) {
00700       internal_file_types_destroy(info->files[x]);
00701    }
00702 }
00703 
00704 int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
00705 {
00706    struct aco_option *opt;
00707    struct ao2_iterator iter;
00708 
00709    iter = ao2_iterator_init(type->internal->opts, 0);
00710 
00711    while ((opt = ao2_iterator_next(&iter))) {
00712       RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
00713 
00714       if (ast_strlen_zero(opt->default_val)) {
00715          ao2_ref(opt, -1);
00716          continue;
00717       }
00718       if (!(var = ast_variable_new(opt->name, opt->default_val, ""))) {
00719          ao2_ref(opt, -1);
00720          ao2_iterator_destroy(&iter);
00721          return -1;
00722       }
00723       if (opt->handler(opt, var, obj)) {
00724          ast_log(LOG_ERROR, "Unable to set default for %s, %s=%s\n", category, var->name, var->value);
00725          ao2_ref(opt, -1);
00726          ao2_iterator_destroy(&iter);
00727          return -1;
00728       }
00729       ao2_ref(opt, -1);
00730    }
00731    ao2_iterator_destroy(&iter);
00732 
00733    return 0;
00734 }
00735 
00736 /* Default config option handlers */
00737 
00738 /*! \brief Default option handler for signed integers
00739  * \note For a description of the opt->flags and opt->args values, see the documentation for
00740  * enum aco_option_type in config_options.h
00741  */
00742 static int int_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00743    int *field = (int *)(obj + opt->args[0]);
00744    unsigned int flags = PARSE_INT32 | opt->flags;
00745    int res = 0;
00746    if (opt->flags & PARSE_IN_RANGE) {
00747       res = opt->flags & PARSE_DEFAULT ?
00748          ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2], opt->args[3]) :
00749          ast_parse_arg(var->value, flags, field, (int) opt->args[1], (int) opt->args[2]);
00750       if (res) {
00751          if (opt->flags & PARSE_RANGE_DEFAULTS) {
00752             ast_log(LOG_WARNING, "Failed to set %s=%s. Set to  %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
00753             res = 0;
00754          } else if (opt->flags & PARSE_DEFAULT) {
00755             ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
00756             res = 0;
00757          }
00758       }
00759    } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (int) opt->args[1])) {
00760       ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %d instead due to default)\n", var->name, var->value, *field);
00761    } else {
00762       res = ast_parse_arg(var->value, flags, field);
00763    }
00764 
00765    return res;
00766 }
00767 
00768 /*! \brief Default option handler for unsigned integers
00769  * \note For a description of the opt->flags and opt->args values, see the documentation for
00770  * enum aco_option_type in config_options.h
00771  */
00772 static int uint_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00773    unsigned int *field = (unsigned int *)(obj + opt->args[0]);
00774    unsigned int flags = PARSE_INT32 | opt->flags;
00775    int res = 0;
00776    if (opt->flags & PARSE_IN_RANGE) {
00777       res = opt->flags & PARSE_DEFAULT ?
00778          ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2], opt->args[3]) :
00779          ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1], (unsigned int) opt->args[2]);
00780       if (res) {
00781          if (opt->flags & PARSE_RANGE_DEFAULTS) {
00782             ast_log(LOG_WARNING, "Failed to set %s=%s. Set to  %d instead due to range limit (%d, %d)\n", var->name, var->value, *field, (int) opt->args[1], (int) opt->args[2]);
00783             res = 0;
00784          } else if (opt->flags & PARSE_DEFAULT) {
00785             ast_log(LOG_WARNING, "Failed to set %s=%s, Set to default value %d instead.\n", var->name, var->value, *field);
00786             res = 0;
00787          }
00788       }
00789    } else if ((opt->flags & PARSE_DEFAULT) && ast_parse_arg(var->value, flags, field, (unsigned int) opt->args[1])) {
00790       ast_log(LOG_WARNING, "Attempted to set %s=%s, but set it to %u instead due to default)\n", var->name, var->value, *field);
00791    } else {
00792       res = ast_parse_arg(var->value, flags, field);
00793    }
00794 
00795    return res;
00796 }
00797 
00798 /*! \brief Default option handler for doubles
00799  * \note For a description of the opt->flags and opt->args values, see the documentation for
00800  * enum aco_option_type in config_options.h
00801  */
00802 static int double_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00803    double *field = (double *)(obj + opt->args[0]);
00804    return ast_parse_arg(var->value, PARSE_DOUBLE | opt->flags, field);
00805 }
00806 
00807 /*! \brief Default handler for ACLs
00808  * \note For a description of the opt->flags and opt->args values, see the documentation for
00809  * enum aco_option_type in config_options.h
00810  */
00811 static int acl_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00812    struct ast_ha **ha = (struct ast_ha **)(obj + opt->args[0]);
00813    int error = 0;
00814    *ha = ast_append_ha(opt->flags ? "permit" : "deny", var->value, *ha, &error);
00815    return error;
00816 }
00817 
00818 /*! \brief Default option handler for codec preferences/capabilities
00819  * \note For a description of the opt->flags and opt->args values, see the documentation for
00820  * enum aco_option_type in config_options.h
00821  */
00822 static int codec_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj) {
00823    struct ast_codec_pref *pref = (struct ast_codec_pref *)(obj + opt->args[0]);
00824    struct ast_format_cap **cap = (struct ast_format_cap **)(obj + opt->args[1]);
00825    return ast_parse_allow_disallow(pref, *cap, var->value, opt->flags);
00826 }
00827 
00828 /*! \brief Default option handler for stringfields
00829  * \note For a description of the opt->flags and opt->args values, see the documentation for
00830  * enum aco_option_type in config_options.h
00831  */
00832 static int stringfield_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00833 {
00834    ast_string_field *field = (const char **)(obj + opt->args[0]);
00835    struct ast_string_field_pool **pool = (struct ast_string_field_pool **)(obj + opt->args[1]);
00836    struct ast_string_field_mgr *mgr = (struct ast_string_field_mgr *)(obj + opt->args[2]);
00837    ast_string_field_ptr_set_by_fields(*pool, *mgr, field, var->value);
00838    return 0;
00839 }
00840 
00841 /*! \brief Default option handler for bools (ast_true/ast_false)
00842  * \note For a description of the opt->flags and opt->args values, see the documentation for
00843  * enum aco_option_type in config_options.h
00844  */
00845 static int bool_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00846 {
00847    unsigned int *field = (unsigned int *)(obj + opt->args[0]);
00848    *field = opt->flags ? ast_true(var->value) : ast_false(var->value);
00849    return 0;
00850 }
00851 
00852 /*! \brief Default option handler for bools (ast_true/ast_false) that are stored as flags
00853  * \note For a description of the opt->flags and opt->args values, see the documentation for
00854  * enum aco_option_type in config_options.h
00855  */
00856 static int boolflag_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00857 {
00858    unsigned int *flags_field = (unsigned int *)(obj + opt->args[0]);
00859    unsigned int val = opt->flags ? ast_true(var->value) : ast_false(var->value);
00860    unsigned int flag = opt->args[1];
00861    if (val) {
00862       *flags_field |= flag;
00863    } else {
00864       *flags_field &= ~flag;
00865    }
00866    return 0;
00867 }
00868 
00869 /*! \brief Default handler for ast_sockaddrs
00870  * \note For a description of the opt->flags and opt->args values, see the documentation for
00871  * enum aco_option_type in config_options.h
00872  */
00873 static int sockaddr_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00874 {
00875    struct ast_sockaddr *field = (struct ast_sockaddr *)(obj + opt->args[0]);
00876    return ast_parse_arg(var->value, PARSE_ADDR | opt->flags, field);
00877 }
00878 
00879 /*! \brief Default handler for doing noithing
00880  */
00881 static int noop_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00882 {
00883    return 0;
00884 }
00885 
00886 /*! \brief Default handler for character arrays
00887  * \note For a description of the opt->flags and opt->args values, see the documentation for
00888  * enum aco_option_type in config_options.h
00889  */
00890 static int chararray_handler_fn(const struct aco_option *opt, struct ast_variable *var, void *obj)
00891 {
00892    char *field = (char *)(obj + opt->args[0]);
00893    size_t len = opt->args[1];
00894 
00895    ast_copy_string(field, var->value, len);
00896    return 0;
00897 }