6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000 The FreeRADIUS server project
27 #include "rad_assert.h"
33 /* mutually-recursive static functions need a prototype up front */
34 static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,
37 /* Actions may be a positive integer (the highest one returned in the group
38 * will be returned), or the keyword "return", represented here by
39 * MOD_ACTION_RETURN, to cause an immediate return.
40 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
41 * to cause an immediate reject. */
42 #define MOD_ACTION_RETURN (-1)
43 #define MOD_ACTION_REJECT (-2)
45 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
46 * explanation of what they are all about, see ../../doc/README.failover */
48 struct modcallable *next;
50 int actions[RLM_MODULE_NUMCODES];
51 enum { MOD_SINGLE, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE } type;
54 #define GROUPTYPE_SIMPLE 0
55 #define GROUPTYPE_REDUNDANT 1
56 #define GROUPTYPE_APPEND 2
57 #define GROUPTYPE_COUNT 3
62 modcallable *children;
67 module_instance_t *modinst;
71 static const LRAD_NAME_NUMBER grouptype_table[] = {
72 { "", GROUPTYPE_SIMPLE },
73 { "redundant ", GROUPTYPE_REDUNDANT },
74 { "append ", GROUPTYPE_APPEND },
78 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
79 * so we often want to go back and forth between them. */
80 static modsingle *mod_callabletosingle(modcallable *p)
82 rad_assert(p->type==MOD_SINGLE);
83 return (modsingle *)p;
85 static modgroup *mod_callabletogroup(modcallable *p)
87 rad_assert((p->type==MOD_GROUP) ||
88 (p->type==MOD_LOAD_BALANCE) ||
89 (p->type==MOD_REDUNDANT_LOAD_BALANCE));
92 static modcallable *mod_singletocallable(modsingle *p)
94 return (modcallable *)p;
96 static modcallable *mod_grouptocallable(modgroup *p)
98 return (modcallable *)p;
101 /* modgroups are grown by adding a modcallable to the end */
102 static void add_child(modgroup *g, modcallable *c)
104 modcallable **head = &g->children;
105 modcallable *node = *head;
106 modcallable **last = head;
115 rad_assert(c->next == NULL);
119 /* Here's where we recognize all of our keywords: first the rcodes, then the
121 static const LRAD_NAME_NUMBER rcode_table[] = {
122 { "reject", RLM_MODULE_REJECT },
123 { "fail", RLM_MODULE_FAIL },
124 { "ok", RLM_MODULE_OK },
125 { "handled", RLM_MODULE_HANDLED },
126 { "invalid", RLM_MODULE_INVALID },
127 { "userlock", RLM_MODULE_USERLOCK },
128 { "notfound", RLM_MODULE_NOTFOUND },
129 { "noop", RLM_MODULE_NOOP },
130 { "updated", RLM_MODULE_UPDATED },
136 * Compile action && rcode for later use.
138 static int compile_action(modcallable *c, const char *attr, const char *value,
139 const char *filename, int lineno)
143 rcode = lrad_str2int(rcode_table, attr, -1);
146 "%s[%d] Unknown module rcode '%s'.\n",
147 filename, lineno, attr);
151 if (!strcasecmp(value, "return"))
152 action = MOD_ACTION_RETURN;
154 else if (!strcasecmp(value, "reject"))
155 action = MOD_ACTION_REJECT;
157 else if (strspn(value, "0123456789")==strlen(value)) {
158 action = atoi(value);
161 * Don't allow priority zero, for future use.
163 if (action == 0) return 0;
166 "%s[%d] Unknown action '%s'.\n",
167 filename, lineno, value);
171 c->actions[rcode] = action;
177 static const char *action2str(int action)
180 if(action==MOD_ACTION_RETURN)
182 if(action==MOD_ACTION_REJECT)
184 snprintf(buf, sizeof buf, "%d", action);
189 /* Some short names for debugging output */
190 static const char *comp2str[] = {
201 #ifdef HAVE_PTHREAD_H
203 * Lock the mutex for the module
205 static void safe_lock(module_instance_t *instance)
208 pthread_mutex_lock(instance->mutex);
212 * Unlock the mutex for the module
214 static void safe_unlock(module_instance_t *instance)
217 pthread_mutex_unlock(instance->mutex);
221 * No threads: these functions become NULL's.
223 #define safe_lock(foo)
224 #define safe_unlock(foo)
227 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
230 int myresult = default_result;
232 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
233 comp2str[component], sp->modinst->name,
234 sp->modinst->entry->name, request->number);
235 safe_lock(sp->modinst);
236 myresult = sp->modinst->entry->module->methods[component](
237 sp->modinst->insthandle, request);
238 safe_unlock(sp->modinst);
239 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
240 comp2str[component], sp->modinst->name,
241 sp->modinst->entry->name, request->number);
248 * Helper function for call_modgroup, and call_modredundantloadbalance
250 * Returns 0 for "stop", and "1" for continue.
252 static int call_one(int component, modcallable *p, REQUEST *request,
253 int *priority, int *result)
257 #ifdef RAD_REQUEST_OPTION_STOP_NOW
259 * A module has taken too long to process the request,
260 * and we've been told to stop processing it.
262 if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
263 *result = RLM_MODULE_FAIL;
268 /* Call this child by recursing into modcall */
269 r = modcall(component, p, request);
272 DEBUG2("%s: action for %s is %s",
273 comp2str[component], lrad_int2str(rcode_table, r, "??"),
274 action2str(p->actions[r]));
278 * Find an action to go with the child's result. If it is
279 * "return", break out of the loop so the rest of the
280 * children in the list will be skipped.
282 if (p->actions[r] == MOD_ACTION_RETURN) {
287 /* If "reject" break out of the loop and return reject */
288 if (p->actions[r] == MOD_ACTION_REJECT) {
289 *result = RLM_MODULE_REJECT;
294 * Otherwise, the action is a number, the preference
295 * level of this return code. If no higher preference has
296 * been seen yet, remember this one
298 if (p->actions[r] >= *priority) {
300 *priority = p->actions[r];
307 static int call_modgroup(int component, modgroup *g, REQUEST *request,
310 int myresult = default_result;
311 int priority = 0; /* default result has lowest priority */
315 * Catch people who have issues.
318 DEBUG2(" WARNING! Asked to process empty group. Returning %s.", lrad_int2str(rcode_table, myresult, "??"));
319 return default_result;
322 /* Loop over the children */
323 for (p = g->children; p; p = p->next) {
324 if (!call_one(component, p, request, &priority, &myresult)) {
332 static int call_modloadbalance(int component, modgroup *g, REQUEST *request,
336 modcallable *p, *child = NULL;
339 * Catch people who have issues.
342 DEBUG2(" WARNING! Asked to process empty load-balance group. Returning %s.", lrad_int2str(rcode_table, default_result, "??"));
343 return default_result;
347 * Pick a random child.
350 /* Loop over the children */
351 for(p = g->children; p; p = p->next) {
359 * Keep track of how many load balancing servers
360 * we've gone through.
365 * See the "camel book" for why this works.
367 * If (rand(0..n) < 1), pick the current realm.
368 * We add a scale factor of 65536, to avoid
371 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
375 rad_assert(child != NULL);
377 /* Call the chosen child by recursing into modcall */
378 return modcall(component, child, request);
383 * For more than 2 modules with redundancy + load balancing
384 * across all of them, layering the "redundant" and
385 * "load-balance" groups gets too complicated. As a result, we
386 * implement a special function to do this.
388 static int call_modredundantloadbalance(int component, modgroup *g, REQUEST *request,
392 int myresult = default_result;
393 int priority = 0; /* default result has lowest priority */
394 modcallable *p, *child = NULL;
397 * Catch people who have issues.
400 DEBUG2(" WARNING! Asked to process empty redundant-load-balance group. Returning %s.", lrad_int2str(rcode_table, default_result, "??"));
401 return default_result;
405 * Pick a random child.
408 /* Loop over the children */
409 for(p = g->children; p; p = p->next) {
417 * Keep track of how many load balancing servers
418 * we've gone through.
423 * See the "camel book" for why this works.
425 * If (rand(0..n) < 1), pick the current realm.
426 * We add a scale factor of 65536, to avoid
429 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
433 rad_assert(child != NULL);
436 * Call the chosen child, with fail-over to the next one
442 * Call the chosen entry. If we're done, then
445 if (!call_one(component, p, request, &priority, &myresult)) {
450 * Go to the next one, and wrap around to the beginning if
454 if (!p) p = g->children;
455 } while (p != child);
458 * And return whatever was decided.
463 int modcall(int component, modcallable *c, REQUEST *request)
467 /* Choose a default return value appropriate for the component */
469 case RLM_COMPONENT_AUTZ:
470 myresult = RLM_MODULE_NOTFOUND;
472 case RLM_COMPONENT_AUTH:
473 myresult = RLM_MODULE_REJECT;
475 case RLM_COMPONENT_PREACCT:
476 myresult = RLM_MODULE_NOOP;
478 case RLM_COMPONENT_ACCT:
479 myresult = RLM_MODULE_NOOP;
481 case RLM_COMPONENT_SESS:
482 myresult = RLM_MODULE_FAIL;
484 case RLM_COMPONENT_PRE_PROXY:
485 myresult = RLM_MODULE_NOOP;
487 case RLM_COMPONENT_POST_PROXY:
488 myresult = RLM_MODULE_NOOP;
490 case RLM_COMPONENT_POST_AUTH:
491 myresult = RLM_MODULE_NOOP;
494 myresult = RLM_MODULE_FAIL;
499 DEBUG2("modcall[%s]: NULL object returns %s for request %d",
501 lrad_int2str(rcode_table, myresult, "??"),
507 case MOD_LOAD_BALANCE:
509 modgroup *g = mod_callabletogroup(c);
511 DEBUG2("modcall: entering load-balance group %s for request %d",
512 c->name, request->number);
514 myresult = call_modloadbalance(component, g, request,
517 DEBUG2("modcall: load-balance group %s returns %s for request %d",
519 lrad_int2str(rcode_table, myresult, "??"),
524 case MOD_REDUNDANT_LOAD_BALANCE:
526 modgroup *g = mod_callabletogroup(c);
528 DEBUG2("modcall: entering redundant-load-balance group %s for request %d",
529 c->name, request->number);
531 myresult = call_modredundantloadbalance(component, g, request,
534 DEBUG2("modcall: redundant-load-balance group %s returns %s for request %d",
536 lrad_int2str(rcode_table, myresult, "??"),
543 modgroup *g = mod_callabletogroup(c);
545 DEBUG2("modcall: entering group %s%s for request %d",
546 lrad_int2str(grouptype_table, g->grouptype, ""),
547 c->name, request->number);
549 myresult = call_modgroup(component, g, request,
552 DEBUG2("modcall: leaving group %s%s (returns %s) for request %d",
553 lrad_int2str(grouptype_table, g->grouptype, ""),
555 lrad_int2str(rcode_table, myresult, "??"),
562 modsingle *sp = mod_callabletosingle(c);
564 myresult = call_modsingle(component, sp, request,
567 DEBUG2(" modcall[%s]: module \"%s\" returns %s for request %d",
568 comp2str[component], c->name,
569 lrad_int2str(rcode_table, myresult, "??"),
575 radlog(L_ERR, "Internal error processing module entry");
583 /* If you suspect a bug in the parser, you'll want to use these dump
584 * functions. dump_tree should reproduce a whole tree exactly as it was found
585 * in radiusd.conf, but in long form (all actions explicitly defined) */
586 static void dump_mc(modcallable *c, int indent)
590 if(c->type==MOD_SINGLE) {
591 modsingle *single = mod_callabletosingle(c);
592 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
593 single->modinst->name);
595 modgroup *g = mod_callabletogroup(c);
597 DEBUG("%.*sgroup {", indent, "\t\t\t\t\t\t\t\t\t\t\t");
598 for(p = g->children;p;p = p->next)
599 dump_mc(p, indent+1);
602 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
603 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
604 lrad_int2str(rcode_table, i, "??"),
605 action2str(c->actions[i]));
608 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
611 static void dump_tree(int comp, modcallable *c)
613 DEBUG("[%s]", comp2str[comp]);
617 static void dump_tree(int comp UNUSED, modcallable *c UNUSED)
623 /* These are the default actions. For each component, the group{} block
624 * behaves like the code from the old module_*() function. redundant{} and
625 * append{} are based on my guesses of what they will be used for. --Pac. */
627 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
633 MOD_ACTION_RETURN, /* reject */
635 MOD_ACTION_RETURN, /* ok */
636 MOD_ACTION_RETURN, /* handled */
638 MOD_ACTION_RETURN, /* userlock */
639 MOD_ACTION_RETURN, /* notfound */
645 MOD_ACTION_RETURN, /* reject */
647 MOD_ACTION_RETURN, /* ok */
648 MOD_ACTION_RETURN, /* handled */
649 MOD_ACTION_RETURN, /* invalid */
650 MOD_ACTION_RETURN, /* userlock */
651 MOD_ACTION_RETURN, /* notfound */
652 MOD_ACTION_RETURN, /* noop */
653 MOD_ACTION_RETURN /* updated */
657 MOD_ACTION_RETURN, /* reject */
659 MOD_ACTION_RETURN, /* ok */
660 MOD_ACTION_RETURN, /* handled */
661 MOD_ACTION_RETURN, /* invalid */
662 MOD_ACTION_RETURN, /* userlock */
664 MOD_ACTION_RETURN, /* noop */
665 MOD_ACTION_RETURN /* updated */
672 MOD_ACTION_RETURN, /* reject */
673 MOD_ACTION_RETURN, /* fail */
675 MOD_ACTION_RETURN, /* handled */
676 MOD_ACTION_RETURN, /* invalid */
677 MOD_ACTION_RETURN, /* userlock */
684 MOD_ACTION_RETURN, /* reject */
686 MOD_ACTION_RETURN, /* ok */
687 MOD_ACTION_RETURN, /* handled */
688 MOD_ACTION_RETURN, /* invalid */
689 MOD_ACTION_RETURN, /* userlock */
690 MOD_ACTION_RETURN, /* notfound */
691 MOD_ACTION_RETURN, /* noop */
692 MOD_ACTION_RETURN /* updated */
696 MOD_ACTION_RETURN, /* reject */
698 MOD_ACTION_RETURN, /* ok */
699 MOD_ACTION_RETURN, /* handled */
700 MOD_ACTION_RETURN, /* invalid */
701 MOD_ACTION_RETURN, /* userlock */
703 MOD_ACTION_RETURN, /* noop */
704 MOD_ACTION_RETURN /* updated */
711 MOD_ACTION_RETURN, /* reject */
712 MOD_ACTION_RETURN, /* fail */
714 MOD_ACTION_RETURN, /* handled */
715 MOD_ACTION_RETURN, /* invalid */
716 MOD_ACTION_RETURN, /* userlock */
717 MOD_ACTION_RETURN, /* notfound */
723 MOD_ACTION_RETURN, /* reject */
725 MOD_ACTION_RETURN, /* ok */
726 MOD_ACTION_RETURN, /* handled */
727 MOD_ACTION_RETURN, /* invalid */
728 MOD_ACTION_RETURN, /* userlock */
729 MOD_ACTION_RETURN, /* notfound */
730 MOD_ACTION_RETURN, /* noop */
731 MOD_ACTION_RETURN /* updated */
735 MOD_ACTION_RETURN, /* reject */
737 MOD_ACTION_RETURN, /* ok */
738 MOD_ACTION_RETURN, /* handled */
739 MOD_ACTION_RETURN, /* invalid */
740 MOD_ACTION_RETURN, /* userlock */
742 MOD_ACTION_RETURN, /* noop */
743 MOD_ACTION_RETURN /* updated */
750 MOD_ACTION_RETURN, /* reject */
751 MOD_ACTION_RETURN, /* fail */
753 MOD_ACTION_RETURN, /* handled */
754 MOD_ACTION_RETURN, /* invalid */
755 MOD_ACTION_RETURN, /* userlock */
756 MOD_ACTION_RETURN, /* notfound */
764 MOD_ACTION_RETURN, /* ok */
765 MOD_ACTION_RETURN, /* handled */
774 MOD_ACTION_RETURN, /* reject */
776 MOD_ACTION_RETURN, /* ok */
777 MOD_ACTION_RETURN, /* handled */
778 MOD_ACTION_RETURN, /* invalid */
779 MOD_ACTION_RETURN, /* userlock */
781 MOD_ACTION_RETURN, /* noop */
782 MOD_ACTION_RETURN /* updated */
789 MOD_ACTION_RETURN, /* reject */
791 MOD_ACTION_RETURN, /* ok */
792 MOD_ACTION_RETURN, /* handled */
793 MOD_ACTION_RETURN, /* invalid */
794 MOD_ACTION_RETURN, /* userlock */
795 MOD_ACTION_RETURN, /* notfound */
796 MOD_ACTION_RETURN, /* noop */
797 MOD_ACTION_RETURN /* updated */
801 MOD_ACTION_RETURN, /* reject */
803 MOD_ACTION_RETURN, /* ok */
804 MOD_ACTION_RETURN, /* handled */
805 MOD_ACTION_RETURN, /* invalid */
806 MOD_ACTION_RETURN, /* userlock */
807 MOD_ACTION_RETURN, /* notfound */
808 MOD_ACTION_RETURN, /* noop */
809 MOD_ACTION_RETURN /* updated */
813 MOD_ACTION_RETURN, /* reject */
815 MOD_ACTION_RETURN, /* ok */
816 MOD_ACTION_RETURN, /* handled */
817 MOD_ACTION_RETURN, /* invalid */
818 MOD_ACTION_RETURN, /* userlock */
819 MOD_ACTION_RETURN, /* notfound */
820 MOD_ACTION_RETURN, /* noop */
821 MOD_ACTION_RETURN /* updated */
828 MOD_ACTION_RETURN, /* reject */
829 MOD_ACTION_RETURN, /* fail */
831 MOD_ACTION_RETURN, /* handled */
832 MOD_ACTION_RETURN, /* invalid */
833 MOD_ACTION_RETURN, /* userlock */
840 MOD_ACTION_RETURN, /* reject */
842 MOD_ACTION_RETURN, /* ok */
843 MOD_ACTION_RETURN, /* handled */
844 MOD_ACTION_RETURN, /* invalid */
845 MOD_ACTION_RETURN, /* userlock */
846 MOD_ACTION_RETURN, /* notfound */
847 MOD_ACTION_RETURN, /* noop */
848 MOD_ACTION_RETURN /* updated */
852 MOD_ACTION_RETURN, /* reject */
854 MOD_ACTION_RETURN, /* ok */
855 MOD_ACTION_RETURN, /* handled */
856 MOD_ACTION_RETURN, /* invalid */
857 MOD_ACTION_RETURN, /* userlock */
859 MOD_ACTION_RETURN, /* noop */
860 MOD_ACTION_RETURN /* updated */
867 MOD_ACTION_RETURN, /* reject */
868 MOD_ACTION_RETURN, /* fail */
870 MOD_ACTION_RETURN, /* handled */
871 MOD_ACTION_RETURN, /* invalid */
872 MOD_ACTION_RETURN, /* userlock */
879 MOD_ACTION_RETURN, /* reject */
881 MOD_ACTION_RETURN, /* ok */
882 MOD_ACTION_RETURN, /* handled */
883 MOD_ACTION_RETURN, /* invalid */
884 MOD_ACTION_RETURN, /* userlock */
885 MOD_ACTION_RETURN, /* notfound */
886 MOD_ACTION_RETURN, /* noop */
887 MOD_ACTION_RETURN /* updated */
891 MOD_ACTION_RETURN, /* reject */
893 MOD_ACTION_RETURN, /* ok */
894 MOD_ACTION_RETURN, /* handled */
895 MOD_ACTION_RETURN, /* invalid */
896 MOD_ACTION_RETURN, /* userlock */
898 MOD_ACTION_RETURN, /* noop */
899 MOD_ACTION_RETURN /* updated */
906 MOD_ACTION_RETURN, /* reject */
907 MOD_ACTION_RETURN, /* fail */
909 MOD_ACTION_RETURN, /* handled */
910 MOD_ACTION_RETURN, /* invalid */
911 MOD_ACTION_RETURN, /* userlock */
918 MOD_ACTION_RETURN, /* reject */
920 MOD_ACTION_RETURN, /* ok */
921 MOD_ACTION_RETURN, /* handled */
922 MOD_ACTION_RETURN, /* invalid */
923 MOD_ACTION_RETURN, /* userlock */
924 MOD_ACTION_RETURN, /* notfound */
925 MOD_ACTION_RETURN, /* noop */
926 MOD_ACTION_RETURN /* updated */
930 MOD_ACTION_RETURN, /* reject */
932 MOD_ACTION_RETURN, /* ok */
933 MOD_ACTION_RETURN, /* handled */
934 MOD_ACTION_RETURN, /* invalid */
935 MOD_ACTION_RETURN, /* userlock */
937 MOD_ACTION_RETURN, /* noop */
938 MOD_ACTION_RETURN /* updated */
944 static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
945 const char *filename, int grouptype,
946 const char **modname)
949 const char *modrefname;
951 modcallable *csingle;
952 module_instance_t *this;
954 if (cf_item_is_section(ci)) {
955 CONF_SECTION *cs = cf_itemtosection(ci);
956 const char *name2 = cf_section_name2(cs);
958 lineno = cf_section_lineno(cs);
959 modrefname = cf_section_name1(cs);
960 if (!name2) name2 = "_UnNamedGroup";
963 * group{}, redundant{}, or append{} may appear
964 * where a single module instance was expected.
965 * In that case, we hand it off to
968 if (strcmp(modrefname, "group") == 0) {
970 return do_compile_modgroup(component, cs, filename,
971 GROUPTYPE_SIMPLE, grouptype);
972 } else if (strcmp(modrefname, "redundant") == 0) {
974 return do_compile_modgroup(component, cs, filename,
975 GROUPTYPE_REDUNDANT, grouptype);
976 } else if (strcmp(modrefname, "append") == 0) {
978 return do_compile_modgroup(component, cs, filename,
979 GROUPTYPE_APPEND, grouptype);
980 } else if (strcmp(modrefname, "load-balance") == 0) {
982 csingle= do_compile_modgroup(component, cs, filename,
983 GROUPTYPE_SIMPLE, grouptype);
984 if (!csingle) return NULL;
985 csingle->type = MOD_LOAD_BALANCE;
987 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
989 csingle= do_compile_modgroup(component, cs, filename,
990 GROUPTYPE_REDUNDANT, grouptype);
991 if (!csingle) return NULL;
992 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
996 CONF_PAIR *cp = cf_itemtopair(ci);
997 lineno = cf_pair_lineno(cp);
998 modrefname = cf_pair_attr(cp);
1002 * FIXME: See if the module is a virtual one. If so,
1003 * return that, rather than doing anything here.
1005 this = find_module_instance(modrefname);
1008 radlog(L_ERR|L_CONS, "%s[%d] Unknown module \"%s\".", filename,
1009 lineno, modrefname);
1014 * We know it's all OK, allocate the structures, and fill
1017 single = rad_malloc(sizeof(*single));
1018 csingle = mod_singletocallable(single);
1019 csingle->next = NULL;
1020 memcpy(csingle->actions, defaultactions[component][grouptype],
1021 sizeof csingle->actions);
1022 rad_assert(modrefname != NULL);
1023 csingle->name = modrefname;
1024 csingle->type = MOD_SINGLE;
1027 * Singles can override the actions, virtual modules cannot.
1029 * FIXME: We may want to re-visit how to do this...
1030 * maybe a csingle as a ref?
1032 if (cf_item_is_section(ci)) {
1033 CONF_SECTION *cs = cf_itemtosection(ci);
1035 const char *attr, *value;
1037 for (ci=cf_item_find_next(cs, NULL);
1039 ci=cf_item_find_next(cs, ci)) {
1041 if (cf_item_is_section(ci)) {
1042 radlog(L_ERR|L_CONS,
1043 "%s[%d] Subsection of module instance call "
1044 "not allowed\n", filename,
1045 cf_section_lineno(cf_itemtosection(ci)));
1046 modcallable_free(&csingle);
1050 cp = cf_itemtopair(ci);
1051 attr = cf_pair_attr(cp);
1052 value = cf_pair_value(cp);
1053 lineno = cf_pair_lineno(cp);
1055 if (!compile_action(csingle, attr, value, filename,
1057 modcallable_free(&csingle);
1064 * Bail out if the module in question does not supply the
1067 if (!this->entry->module->methods[component]) {
1068 radlog(L_ERR|L_CONS,
1069 "%s: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1070 filename, this->entry->module->name,
1071 component_names[component]);
1072 modcallable_free(&csingle);
1076 single->modinst = this;
1077 *modname = this->entry->module->name;
1081 modcallable *compile_modsingle(int component, CONF_ITEM *ci,
1082 const char *filename, const char **modname)
1084 modcallable *ret = do_compile_modsingle(component, ci, filename,
1087 dump_tree(component, ret);
1091 static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
1092 const char *filename, int grouptype,
1093 int parentgrouptype)
1099 g = rad_malloc(sizeof *g);
1100 g->grouptype = grouptype;
1102 c = mod_grouptocallable(g);
1104 memcpy(c->actions, defaultactions[component][parentgrouptype],
1105 sizeof(c->actions));
1108 * Remember the name for printing, etc.
1110 * FIXME: We may also want to put the names into a
1111 * rbtree, so that groups can reference each other...
1113 c->name = cf_section_name2(cs);
1114 if (!c->name) c->name = "";
1115 c->type = MOD_GROUP;
1118 for (ci=cf_item_find_next(cs, NULL);
1120 ci=cf_item_find_next(cs, ci)) {
1122 if(cf_item_is_section(ci)) {
1123 const char *junk = NULL;
1124 modcallable *single;
1126 CONF_SECTION *subcs = cf_itemtosection(ci);
1128 lineno = cf_section_lineno(subcs);
1130 single = do_compile_modsingle(component, ci, filename,
1133 radlog(L_ERR|L_CONS,
1134 "%s[%d] Failed to parse \"%s\" subsection.\n",
1136 cf_section_name1(subcs));
1137 modcallable_free(&c);
1140 add_child(g, single);
1143 const char *attr, *value;
1144 CONF_PAIR *cp = cf_itemtopair(ci);
1147 attr = cf_pair_attr(cp);
1148 value = cf_pair_value(cp);
1149 lineno = cf_pair_lineno(cp);
1152 * A CONF_PAIR is either a module
1153 * instance with no actions
1156 if (value[0] == 0) {
1157 modcallable *single;
1158 const char *junk = NULL;
1160 single = do_compile_modsingle(component,
1161 cf_pairtoitem(cp), filename,
1164 radlog(L_ERR|L_CONS,
1165 "%s[%d] Failed to parse \"%s\" entry.\n",
1166 filename, lineno, attr);
1167 modcallable_free(&c);
1170 add_child(g, single);
1173 * Or a module instance with action.
1175 } else if (!compile_action(c, attr, value, filename,
1177 modcallable_free(&c);
1179 } /* else it worked */
1184 * FIXME: If there are no children, return NULL?
1186 return mod_grouptocallable(g);
1189 modcallable *compile_modgroup(int component, CONF_SECTION *cs,
1190 const char *filename)
1192 modcallable *ret = do_compile_modgroup(component, cs, filename,
1195 dump_tree(component, ret);
1199 void add_to_modcallable(modcallable **parent, modcallable *this,
1200 int component, char *name)
1204 rad_assert(this != NULL);
1206 if (*parent == NULL) {
1209 g = rad_malloc(sizeof *g);
1210 g->grouptype = GROUPTYPE_SIMPLE;
1211 c = mod_grouptocallable(g);
1214 defaultactions[component][GROUPTYPE_SIMPLE],
1215 sizeof(c->actions));
1216 rad_assert(name != NULL);
1218 c->type = MOD_GROUP;
1221 *parent = mod_grouptocallable(g);
1223 g = mod_callabletogroup(*parent);
1229 void modcallable_free(modcallable **pc)
1231 modcallable *c, *loop, *next;
1233 if(c->type==MOD_GROUP) {
1234 for(loop = mod_callabletogroup(c)->children;
1238 modcallable_free(&loop);