Updated cf_section_sub_find_name2 to be a little smarter, and to
authoraland <aland>
Tue, 24 May 2005 19:04:35 +0000 (19:04 +0000)
committeraland <aland>
Tue, 24 May 2005 19:04:35 +0000 (19:04 +0000)
better support modules.c & modcall.c, which try to look modules
up by name1 or name2.

New function cf_data_find & cf_data_add, where other code can add
named data to be "associated" with a particular configuration section.

Updated modules.c so that the module_instance_t structure is stored
via cf_data_add(), rather than in a static pointer.  This means
that it now gets automagically free'd when the configuration
section gets freed, which simplifies out lives.

It also means that the whole "reread conf files" may become easier,
as we can now read a new configuration file, do a 'diff' with the
old one, and potentially move the module instance data from the
old to the new, and therefore NOT shutdown & restart all of the
modules on a HUP.

src/include/conffile.h
src/include/modpriv.h
src/main/conffile.c
src/main/modcall.c
src/main/modules.c

index 77b1abe..0dc2e10 100644 (file)
@@ -17,6 +17,7 @@
 typedef struct conf_item CONF_ITEM;
 typedef struct conf_pair CONF_PAIR;
 typedef struct conf_part CONF_SECTION;
+typedef struct conf_data CONF_DATA;
 
 /*
  *  Instead of putting the information into a configuration structure,
@@ -60,6 +61,9 @@ CONF_SECTION  *cf_section_sub_find(const CONF_SECTION *, const char *name);
 CONF_SECTION   *cf_section_sub_find_name2(const CONF_SECTION *, const char *name1, const char *name2);
 char           *cf_section_value_find(const CONF_SECTION *, const char *attr);
 
+void *cf_data_find(CONF_SECTION *, const char *);
+int cf_data_add(CONF_SECTION *, const char *, void *, void (*)(void *));
+
 char *cf_pair_attr(CONF_PAIR *pair);
 char *cf_pair_value(CONF_PAIR *pair);
 const char *cf_section_name1(const CONF_SECTION *);
index 0aef7ff..2342f65 100644 (file)
@@ -31,4 +31,4 @@ typedef struct module_instance_t {
 #endif
 } module_instance_t;
 
-module_instance_t *find_module_instance(const char *instname);
+module_instance_t *find_module_instance(CONF_SECTION *, const char *instname);
index 780231b..e0c8ed7 100644 (file)
@@ -55,8 +55,10 @@ static const char rcsid[] =
 "$Id$";
 
 typedef enum conf_type {
+       CONF_ITEM_INVALID = 0,
        CONF_ITEM_PAIR,
-       CONF_ITEM_SECTION
+       CONF_ITEM_SECTION,
+       CONF_ITEM_DATA
 } CONF_ITEM_TYPE;
 
 struct conf_item {
@@ -81,6 +83,18 @@ struct conf_part {
        rbtree_t        *name2_tree; /* for sections of the same name2 */
 };
 
+
+/*
+ *     Internal data that is associated with a configuration section,
+ *     so that we don't have to track it separately.
+ */
+struct conf_data {
+       CONF_ITEM  item;
+       const char *name;
+       void       *data;       /* user data */
+       void       (*free)(void *); /* free user data function */
+};
+
 /*
  *     Isolate the scary casts in these tiny provably-safe functions
  */
@@ -111,6 +125,20 @@ CONF_ITEM *cf_sectiontoitem(CONF_SECTION *cs)
        return (CONF_ITEM *)cs;
 }
 
+static CONF_DATA *cf_itemtodata(CONF_ITEM *ci)
+{
+       if (ci == NULL)
+               return NULL;
+       rad_assert(ci->type == CONF_ITEM_DATA);
+       return (CONF_DATA *)ci;
+}
+static CONF_ITEM *cf_datatoitem(CONF_DATA *cd)
+{
+       if (cd == NULL)
+               return NULL;
+       return (CONF_ITEM *)cd;
+}
+
 /*
  *     Create a new CONF_PAIR
  */
@@ -151,6 +179,20 @@ void cf_pair_free(CONF_PAIR **cp)
 }
 
 
+static void cf_data_free(CONF_DATA **cd)
+{
+       if (!cd || !*cd) return;
+
+       free((*cd)->name);
+       if (!(*cd)->free) {
+               free((*cd)->data);
+       } else {
+               ((*cd)->free)((*cd)->data);
+       }
+
+       *cd = NULL;
+}
+
 /*
  *     rbtree callback function
  */
@@ -204,12 +246,29 @@ void cf_section_free(CONF_SECTION **cs)
 
        for (ci = (*cs)->children; ci; ci = next) {
                next = ci->next;
-               if (ci->type==CONF_ITEM_PAIR) {
-                       CONF_PAIR *pair = cf_itemtopair(ci);
-                       cf_pair_free(&pair);
-               } else {
-                       CONF_SECTION *section = cf_itemtosection(ci);
-                       cf_section_free(&section);
+
+               switch (ci->type) {
+               case CONF_ITEM_PAIR: {
+                               CONF_PAIR *pair = cf_itemtopair(ci);
+                               cf_pair_free(&pair);
+                       }
+                       break;
+
+               case CONF_ITEM_SECTION: {
+                               
+                               CONF_SECTION *section = cf_itemtosection(ci);
+                               cf_section_free(&section);
+                       }
+                       break;
+
+               case CONF_ITEM_DATA: {
+                               CONF_DATA *data = cf_itemtodata(ci);
+                               cf_data_free(&data);
+                       }
+                       break;
+
+               default:        /* should really be an error. */
+                       break;
                }
        }
 
@@ -297,45 +356,54 @@ static void cf_item_add(CONF_SECTION *cs, CONF_ITEM *ci_new)
         *      For fast lookups.
         */
        while (ci_new) {
-               if (ci_new->type == CONF_ITEM_PAIR) {
-                       rbtree_insert(cs->pair_tree, ci_new);
-                       
-               } else if (ci_new->type == CONF_ITEM_SECTION) {
-                       const CONF_SECTION *cs_new = cf_itemtosection(ci_new);
-
-                       if (!cs->section_tree) {
-                               cs->section_tree = rbtree_create(section_cmp, NULL, 0);
-                               /* ignore any errors */
-                       }
-                       
-                       if (cs->section_tree) {
-                               rbtree_insert(cs->section_tree, cs_new);
-                       }
-                       
-                       /*
-                        *      Two names: find the named instance.
-                        */
-                       if (cs_new->name2) {
-                               CONF_SECTION *old_cs;
+               switch (ci_new->type) {
+                       case CONF_ITEM_PAIR:
+                               rbtree_insert(cs->pair_tree, ci_new);
+                               break;
                                
-                               /*
-                                *      Find the FIRST CONF_SECTION having the
-                                *      given name1, and create a new tree
-                                *      under it.
-                                */
-                               old_cs = rbtree_finddata(cs->section_tree, cs_new);
-                               if (!old_cs) return; /* this is a bad error! */
+                       case CONF_ITEM_SECTION: {
+                               const CONF_SECTION *cs_new = cf_itemtosection(ci_new);
                                
-                               if (!old_cs->name2_tree) {
-                                       old_cs->name2_tree = rbtree_create(name2_cmp,
-                                                                          NULL, 0);
+                               if (!cs->section_tree) {
+                                       cs->section_tree = rbtree_create(section_cmp, NULL, 0);
+                                       /* ignore any errors */
                                }
-                               if (old_cs->name2_tree) {
-                                       rbtree_insert(old_cs->name2_tree, cs_new);
+                               
+                               if (cs->section_tree) {
+                                       rbtree_insert(cs->section_tree, cs_new);
                                }
-                       } /* had a name2 */
-               } /* was a section */
+                               
+                               /*
+                                *      Two names: find the named instance.
+                                */
+                               if (cs_new->name2) {
+                                       CONF_SECTION *old_cs;
+                                       
+                                       /*
+                                        *      Find the FIRST
+                                        *      CONF_SECTION having
+                                        *      the given name1, and
+                                        *      create a new tree
+                                        *      under it.
+                                        */
+                                       old_cs = rbtree_finddata(cs->section_tree, cs_new);
+                                       if (!old_cs) return; /* this is a bad error! */
+                                       
+                                       if (!old_cs->name2_tree) {
+                                               old_cs->name2_tree = rbtree_create(name2_cmp,
+                                                                                  NULL, 0);
+                                       }
+                                       if (old_cs->name2_tree) {
+                                               rbtree_insert(old_cs->name2_tree, cs_new);
+                                       }
+                               } /* had a name2 */
+                               break;
+                       } /* was a section */
 
+                       default: /* FIXME: assert & error! */
+                               break;
+
+               } /* switch over conf types */
                ci_new = ci_new->next;
        } /* loop over ci_new */
 }
@@ -1233,7 +1301,7 @@ CONF_SECTION *cf_section_sub_find(const CONF_SECTION *cs, const char *name)
 
 
 /*
- * Find a CONF_SECTION with both names.
+ *     Find a CONF_SECTION with both names.
  */
 CONF_SECTION *cf_section_sub_find_name2(const CONF_SECTION *cs,
                                        const char *name1, const char *name2)
@@ -1244,7 +1312,7 @@ CONF_SECTION *cf_section_sub_find_name2(const CONF_SECTION *cs,
 
        if (!cs) cs = mainconfig.config;
 
-       if (cs->section_tree) {
+       if (name1 && (cs->section_tree)) {
                CONF_SECTION mycs, *master_cs;
                
                mycs.name1 = name1;
@@ -1266,6 +1334,15 @@ CONF_SECTION *cf_section_sub_find_name2(const CONF_SECTION *cs,
                        continue;
 
                subcs = cf_itemtosection(ci);
+               if (!name1) {
+                       if (!subcs->name2) {
+                               if (strcmp(subcs->name1, name2) == 0) break;
+                       } else {
+                               if (strcmp(subcs->name2, name2) == 0) break;
+                       }
+                       continue; /* don't do the string comparisons below */
+               }
+
                if ((strcmp(subcs->name1, name1) == 0) &&
                    (subcs->name2 != NULL) &&
                    (strcmp(subcs->name2, name2) == 0))
@@ -1343,6 +1420,82 @@ int cf_item_is_section(CONF_ITEM *item)
 }
 
 
+static CONF_DATA *cf_data_alloc(CONF_SECTION *parent, const char *name,
+                               void *data, void (*data_free)(void *))
+{
+       CONF_DATA *cd;
+
+       cd = rad_malloc(sizeof(*cd));
+       memset(cd, 0, sizeof(*cd));
+
+       cd->item.type = CONF_ITEM_DATA;
+       cd->item.parent = parent;
+       cd->name = strdup(name);
+       cd->data = data;
+       cd->free = data_free;
+
+       return cd;
+}
+
+
+/*
+ *     Find data from a particular section.
+ */
+void *cf_data_find(CONF_SECTION *cs, const char *name)
+{
+       CONF_ITEM *ci;
+
+       if (!cs || !name) return NULL;
+
+       for (ci = cs->children; ci != NULL; ci = ci->next) {
+               CONF_DATA *cd;
+
+               /*
+                *      Data is always inserted at the front of the
+                *      list.
+                */
+               if (ci->type != CONF_ITEM_DATA) return NULL;
+
+               cd = cf_itemtodata(ci);
+               if (strcmp(name, cd->name) == 0) return cd->data;
+       }
+
+       return NULL;
+}
+
+
+/*
+ *     Add named data to a configuration section.
+ */
+int cf_data_add(CONF_SECTION *cs, const char *name,
+               void *data, void (*data_free)(void *))
+{
+       CONF_ITEM *ci;
+       CONF_DATA *cd;
+
+       if (!cs || !name || !data) return -1;
+
+       /*
+        *      Already exists.  Can't add it.
+        */
+       if (cf_data_find(cs, name) != NULL) return -1;
+
+       ci = cs->children;
+
+       cd = cf_data_alloc(cs, name, data, data_free);
+
+       /*
+        *      Insert at the TOP of the list.
+        */
+       ci = cf_datatoitem(cd);
+
+       ci->next = cs->children;
+       cs->children = ci;
+
+       return 0;
+}
+
+
 #if 0
 /*
  * JMG dump_config tries to dump the config structure in a readable format
@@ -1360,12 +1513,15 @@ static int dump_config_section(CONF_SECTION *cs, int indent)
         * so I had to get creative. --Pac. */
 
        for (ci = cs->children; ci; ci = ci->next) {
-               if (ci->type == CONF_ITEM_PAIR) {
+               switch (ci->type) {
+               case CONF_ITEM_PAIR:
                        cp=cf_itemtopair(ci);
                        DEBUG("%.*s%s = %s",
                                indent, "\t\t\t\t\t\t\t\t\t\t\t",
                                cp->attr, cp->value);
-               } else {
+                       break;
+
+               case CONF_ITEM_SECTION:
                        scs=cf_itemtosection(ci);
                        DEBUG("%.*s%s %s%s{",
                                indent, "\t\t\t\t\t\t\t\t\t\t\t",
@@ -1375,6 +1531,10 @@ static int dump_config_section(CONF_SECTION *cs, int indent)
                        dump_config_section(scs, indent+1);
                        DEBUG("%.*s}",
                                indent, "\t\t\t\t\t\t\t\t\t\t\t");
+                       break;
+
+               default:        /* FIXME: Do more! */
+                       break;
                }
        }
 
index d0f55e9..6dac112 100644 (file)
@@ -1025,28 +1025,16 @@ static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
         *      See if the module is a virtual one.  If so, return that,
         *      rather than doing anything here.
         */
-       this = find_module_instance(modrefname);
+       this = find_module_instance(cf_section_find("modules"), modrefname);
        if (!this) {
                CONF_SECTION *cs, *subcs;
 
                /*
-                *      Then, look for a named "modules virtual {" section.
+                *      Then, look for it in the "instantiate" section.
                 */
                if (((subcs = cf_section_find(NULL)) != NULL) &&
                    ((cs = cf_section_sub_find_name2(subcs, "instantiate", NULL)) != NULL)) {
-                       const char *name1, *name2;
-
-                       name1 = name2 = NULL;
-                       for (subcs = cf_subsection_find_next(cs, NULL, NULL);
-                            subcs != NULL;
-                            subcs=cf_subsection_find_next(cs, subcs, NULL)) {
-                               name1 = cf_section_name1(subcs);
-                               name2 = cf_section_name2(subcs);
-                               if ((name2 && (strcmp(name2, modrefname) == 0)) ||
-                                   (!name2 && (strcmp(name1, modrefname) == 0))) {
-                                       break;
-                               }
-                       }
+                       subcs = cf_section_sub_find_name2(cs, NULL, modrefname);
                        if (subcs) {
                                /*
                                 *      As it's sole configuration, the
index ac4da5d..b71ab51 100644 (file)
@@ -43,11 +43,6 @@ static const char rcsid[] = "$Id$";
  */
 static module_list_t *module_list = NULL;
 
-/*
- *     Internal list of each module instance.
- */
-static module_instance_t *module_instance_list = NULL;
-
 typedef struct indexed_modcallable {
        struct indexed_modcallable *next;
        int idx;
@@ -110,32 +105,28 @@ static void indexed_modcallable_free(indexed_modcallable **cf)
        *cf = NULL;
 }
 
-static void instance_list_free(module_instance_t **i)
+/*
+ *     Free a module instance.
+ */
+static void module_instance_free(module_instance_t *this)
 {
-       module_instance_t       *c, *next;
-
-       c = *i;
-       while (c) {
-               next = c->next;
-               if(c->entry->module->detach)
-                       (c->entry->module->detach)(c->insthandle);
+       if (this->entry->module->detach)
+               (this->entry->module->detach)(this->insthandle);
 #ifdef HAVE_PTHREAD_H
-               if (c->mutex) {
-                       /*
-                        *      FIXME
-                        *      The mutex MIGHT be locked...
-                        *      we'll check for that later, I guess.
-                        */
-                       pthread_mutex_destroy(c->mutex);
-                       free(c->mutex);
-               }
-#endif
-               free(c);
-               c = next;
+       if (this->mutex) {
+               /*
+                *      FIXME
+                *      The mutex MIGHT be locked...
+                *      we'll check for that later, I guess.
+                */
+               pthread_mutex_destroy(this->mutex);
+               free(this->mutex);
        }
-       *i = NULL;
+#endif
+       free(this);
 }
 
+
 /*
  *     Remove all of the modules.
  */
@@ -151,8 +142,6 @@ int detach_modules(void)
                indexed_modcallable_free(&components[i]);
        }
 
-       instance_list_free(&module_instance_list);
-
        ml = module_list;
        while (ml) {
                next = ml->next;
@@ -249,44 +238,15 @@ static module_list_t *linkto_module(const char *module_name,
 /*
  *     Find a module instance.
  */
-module_instance_t *find_module_instance(const char *instname)
+module_instance_t *find_module_instance(CONF_SECTION *modules,
+                                       const char *instname)
 {
-       CONF_SECTION *cs, *inst_cs;
+       CONF_SECTION *cs;
        const char *name1, *name2;
-       module_instance_t *node, **last;
+       module_instance_t *node;
        char module_name[256];
 
-       /*
-        *      Look through the global module instance list for the
-        *      named module.
-        */
-       last = &module_instance_list;
-       for (node = module_instance_list; node != NULL; node = node->next) {
-               /*
-                *      Found the named instance.  Return it.
-                */
-               if (strcmp(node->name, instname) == 0)
-                       return node;
-
-               /*
-                *      Keep a pointer to the last entry to update...
-                */
-               last = &node->next;
-       }
-
-       /*
-        *      Instance doesn't exist yet. Try to find the
-        *      corresponding configuration section and create it.
-        */
-
-       /*
-        *      Look for the 'modules' configuration section.
-        */
-       cs = cf_section_find("modules");
-       if (cs == NULL) {
-               radlog(L_ERR|L_CONS, "ERROR: Cannot find a 'modules' section in the configuration file.\n");
-               return NULL;
-       }
+       if (!modules) return NULL;
 
        /*
         *      Module instances are declared in the modules{} block
@@ -294,22 +254,22 @@ module_instance_t *find_module_instance(const char *instname)
         *      name2 from the config section, or name1 if there was
         *      no name2.
         */
-       name1 = name2 = NULL;
-       for(inst_cs=cf_subsection_find_next(cs, NULL, NULL);
-           inst_cs != NULL;
-           inst_cs=cf_subsection_find_next(cs, inst_cs, NULL)) {
-               name1 = cf_section_name1(inst_cs);
-               name2 = cf_section_name2(inst_cs);
-               if ( (name2 && !strcmp(name2, instname)) ||
-                    (!name2 && !strcmp(name1, instname)) )
-                       break;
-       }
-       if (inst_cs == NULL) {
+       cs = cf_section_sub_find_name2(modules, NULL, instname);
+       if (cs == NULL) {
                radlog(L_ERR|L_CONS, "ERROR: Cannot find a configuration entry for module \"%s\".\n", instname);
                return NULL;
        }
 
        /*
+        *      If there's already module instance, return it.
+        */
+       node = cf_data_find(cs, "instance");
+       if (node) return node;
+
+       name1 = cf_section_name1(cs);
+       name2 = cf_section_name2(cs);
+
+       /*
         *      Found the configuration entry.
         */
        node = rad_malloc(sizeof(*node));
@@ -323,7 +283,7 @@ module_instance_t *find_module_instance(const char *instname)
        snprintf(module_name, sizeof(module_name), "rlm_%s", name1);
 
        node->entry = linkto_module(module_name, mainconfig.radiusd_conf,
-                                   cf_section_lineno(inst_cs));
+                                   cf_section_lineno(cs));
        if (!node->entry) {
                free(node);
                /* linkto_module logs any errors */
@@ -334,11 +294,10 @@ module_instance_t *find_module_instance(const char *instname)
         *      Call the module's instantiation routine.
         */
        if ((node->entry->module->instantiate) &&
-           ((node->entry->module->instantiate)(inst_cs,
-                       &node->insthandle) < 0)) {
+           ((node->entry->module->instantiate)(cs, &node->insthandle) < 0)) {
                radlog(L_ERR|L_CONS,
                                "%s[%d]: %s: Module instantiation failed.\n",
-                      mainconfig.radiusd_conf, cf_section_lineno(inst_cs),
+                      mainconfig.radiusd_conf, cf_section_lineno(cs),
                       instname);
                free(node);
                return NULL;
@@ -370,7 +329,7 @@ module_instance_t *find_module_instance(const char *instname)
        }
 
 #endif
-       *last = node;
+       cf_data_add(cs, "instance", node, module_instance_free);
 
        DEBUG("Module: Instantiated %s (%s) ", name1, node->name);
 
@@ -524,7 +483,7 @@ static int load_component_section(CONF_SECTION *cs, int comp,
        int idx;
        indexed_modcallable *subcomp;
        const char *modname;
-       char *visiblename;
+       const char *visiblename;
 
        /*
         *      Loop over the entries in the named section.
@@ -639,7 +598,7 @@ static int load_component_section(CONF_SECTION *cs, int comp,
 int setup_modules(void)
 {
        int             comp;
-       CONF_SECTION    *cs;
+       CONF_SECTION    *cs, *modules;
        int             do_component[RLM_COMPONENT_COUNT];
        rad_listen_t    *listener;
 
@@ -844,6 +803,15 @@ int setup_modules(void)
        } /* over the sections which can have redundent sub-sections */
 
        /*
+        *      Remember where the modules were stored.
+        */
+       modules = cf_section_find("modules");
+       if (!modules) {
+               radlog(L_ERR, "Cannot find a \"modules\" section in the configuration file!");
+               return -1;
+       }
+
+       /*
         *  Look for the 'instantiate' section, which tells us
         *  the instantiation order of the modules, and also allows
         *  us to load modules with no authorize/authenticate/etc.
@@ -873,7 +841,7 @@ int setup_modules(void)
 
                        cp = cf_itemtopair(ci);
                        name = cf_pair_attr(cp);
-                       module = find_module_instance(name);
+                       module = find_module_instance(modules, name);
                        if (!module) {
                                return -1;
                        }