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
22 #include <freeradius-devel/autoconf.h>
27 #include <freeradius-devel/radiusd.h>
28 #include <freeradius-devel/rad_assert.h>
29 #include <freeradius-devel/conffile.h>
30 #include <freeradius-devel/modpriv.h>
31 #include <freeradius-devel/modules.h>
32 #include <freeradius-devel/modcall.h>
34 /* mutually-recursive static functions need a prototype up front */
35 static modcallable *do_compile_modgroup(int, CONF_SECTION *, const char *,
38 /* Actions may be a positive integer (the highest one returned in the group
39 * will be returned), or the keyword "return", represented here by
40 * MOD_ACTION_RETURN, to cause an immediate return.
41 * There's also the keyword "reject", represented here by MOD_ACTION_REJECT
42 * to cause an immediate reject. */
43 #define MOD_ACTION_RETURN (-1)
44 #define MOD_ACTION_REJECT (-2)
46 /* Here are our basic types: modcallable, modgroup, and modsingle. For an
47 * explanation of what they are all about, see ../../doc/README.failover */
49 struct modcallable *next;
51 int actions[RLM_MODULE_NUMCODES];
52 enum { MOD_SINGLE, MOD_GROUP, MOD_LOAD_BALANCE, MOD_REDUNDANT_LOAD_BALANCE } type;
55 #define GROUPTYPE_SIMPLE 0
56 #define GROUPTYPE_REDUNDANT 1
57 #define GROUPTYPE_APPEND 2
58 #define GROUPTYPE_COUNT 3
62 int grouptype; /* after mc */
63 modcallable *children;
68 module_instance_t *modinst;
72 static const LRAD_NAME_NUMBER grouptype_table[] = {
73 { "", GROUPTYPE_SIMPLE },
74 { "redundant ", GROUPTYPE_REDUNDANT },
75 { "append ", GROUPTYPE_APPEND },
79 /* Simple conversions: modsingle and modgroup are subclasses of modcallable,
80 * so we often want to go back and forth between them. */
81 static modsingle *mod_callabletosingle(modcallable *p)
83 rad_assert(p->type==MOD_SINGLE);
84 return (modsingle *)p;
86 static modgroup *mod_callabletogroup(modcallable *p)
88 rad_assert((p->type==MOD_GROUP) ||
89 (p->type==MOD_LOAD_BALANCE) ||
90 (p->type==MOD_REDUNDANT_LOAD_BALANCE));
93 static modcallable *mod_singletocallable(modsingle *p)
95 return (modcallable *)p;
97 static modcallable *mod_grouptocallable(modgroup *p)
99 return (modcallable *)p;
102 /* modgroups are grown by adding a modcallable to the end */
103 static void add_child(modgroup *g, modcallable *c)
105 modcallable **head = &g->children;
106 modcallable *node = *head;
107 modcallable **last = head;
116 rad_assert(c->next == NULL);
120 /* Here's where we recognize all of our keywords: first the rcodes, then the
122 static const LRAD_NAME_NUMBER rcode_table[] = {
123 { "reject", RLM_MODULE_REJECT },
124 { "fail", RLM_MODULE_FAIL },
125 { "ok", RLM_MODULE_OK },
126 { "handled", RLM_MODULE_HANDLED },
127 { "invalid", RLM_MODULE_INVALID },
128 { "userlock", RLM_MODULE_USERLOCK },
129 { "notfound", RLM_MODULE_NOTFOUND },
130 { "noop", RLM_MODULE_NOOP },
131 { "updated", RLM_MODULE_UPDATED },
137 * Compile action && rcode for later use.
139 static int compile_action(modcallable *c, const char *attr, const char *value,
140 const char *filename, int lineno)
144 if (!strcasecmp(value, "return"))
145 action = MOD_ACTION_RETURN;
147 else if (!strcasecmp(value, "reject"))
148 action = MOD_ACTION_REJECT;
150 else if (strspn(value, "0123456789")==strlen(value)) {
151 action = atoi(value);
154 * Don't allow priority zero, for future use.
156 if (action == 0) return 0;
159 "%s[%d] Unknown action '%s'.\n",
160 filename, lineno, value);
164 if (strcasecmp(attr, "default") != 0) {
167 rcode = lrad_str2int(rcode_table, attr, -1);
170 "%s[%d] Unknown module rcode '%s'.\n",
171 filename, lineno, attr);
174 c->actions[rcode] = action;
176 } else { /* set all unset values to the default */
179 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
180 if (!c->actions[i]) c->actions[i] = action;
188 static const char *action2str(int action)
191 if(action==MOD_ACTION_RETURN)
193 if(action==MOD_ACTION_REJECT)
195 snprintf(buf, sizeof buf, "%d", action);
200 /* Some short names for debugging output */
201 static const char * const comp2str[] = {
212 #ifdef HAVE_PTHREAD_H
214 * Lock the mutex for the module
216 static void safe_lock(module_instance_t *instance)
219 pthread_mutex_lock(instance->mutex);
223 * Unlock the mutex for the module
225 static void safe_unlock(module_instance_t *instance)
228 pthread_mutex_unlock(instance->mutex);
232 * No threads: these functions become NULL's.
234 #define safe_lock(foo)
235 #define safe_unlock(foo)
238 static int call_modsingle(int component, modsingle *sp, REQUEST *request,
241 int myresult = default_result;
243 DEBUG3(" modsingle[%s]: calling %s (%s) for request %d",
244 comp2str[component], sp->modinst->name,
245 sp->modinst->entry->name, request->number);
246 safe_lock(sp->modinst);
249 * For logging unresponsive children.
251 request->module = sp->modinst->name;
252 request->component = comp2str[component];
254 myresult = sp->modinst->entry->module->methods[component](
255 sp->modinst->insthandle, request);
257 request->module = NULL;
258 safe_unlock(sp->modinst);
259 DEBUG3(" modsingle[%s]: returned from %s (%s) for request %d",
260 comp2str[component], sp->modinst->name,
261 sp->modinst->entry->name, request->number);
268 * Helper function for call_modgroup, and call_modredundantloadbalance
270 * Returns 0 for "stop", and "1" for continue.
272 static int call_one(int component, modcallable *p, REQUEST *request,
273 int *priority, int *result)
278 * A module has taken too long to process the request,
279 * and we've been told to stop processing it.
281 if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
282 *result = RLM_MODULE_FAIL;
286 /* Call this child by recursing into modcall */
287 r = modcall(component, p, request);
290 DEBUG2("%s: action for %s is %s",
291 comp2str[component], lrad_int2str(rcode_table, r, "??"),
292 action2str(p->actions[r]));
296 * Find an action to go with the child's result. If it is
297 * "return", break out of the loop so the rest of the
298 * children in the list will be skipped.
300 if (p->actions[r] == MOD_ACTION_RETURN) {
305 /* If "reject" break out of the loop and return reject */
306 if (p->actions[r] == MOD_ACTION_REJECT) {
307 *result = RLM_MODULE_REJECT;
312 * Otherwise, the action is a number, the preference
313 * level of this return code. If no higher preference has
314 * been seen yet, remember this one
316 if (p->actions[r] >= *priority) {
318 *priority = p->actions[r];
325 static int call_modgroup(int component, modgroup *g, REQUEST *request,
328 int myresult = default_result;
329 int priority = 0; /* default result has lowest priority */
333 * Catch people who have issues.
336 DEBUG2(" WARNING! Asked to process empty group. Returning %s.", lrad_int2str(rcode_table, myresult, "??"));
337 return default_result;
340 /* Loop over the children */
341 for (p = g->children; p; p = p->next) {
342 if (!call_one(component, p, request, &priority, &myresult)) {
350 static int call_modloadbalance(int component, modgroup *g, REQUEST *request,
354 modcallable *p, *child = NULL;
357 * Catch people who have issues.
360 DEBUG2(" WARNING! Asked to process empty load-balance group. Returning %s.", lrad_int2str(rcode_table, default_result, "??"));
361 return default_result;
365 * Pick a random child.
368 /* Loop over the children */
369 for(p = g->children; p; p = p->next) {
377 * Keep track of how many load balancing servers
378 * we've gone through.
383 * See the "camel book" for why this works.
385 * If (rand(0..n) < 1), pick the current realm.
386 * We add a scale factor of 65536, to avoid
389 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
393 rad_assert(child != NULL);
395 /* Call the chosen child by recursing into modcall */
396 return modcall(component, child, request);
401 * For more than 2 modules with redundancy + load balancing
402 * across all of them, layering the "redundant" and
403 * "load-balance" groups gets too complicated. As a result, we
404 * implement a special function to do this.
406 static int call_modredundantloadbalance(int component, modgroup *g, REQUEST *request,
410 int myresult = default_result;
411 int priority = 0; /* default result has lowest priority */
412 modcallable *p, *child = NULL;
415 * Catch people who have issues.
418 DEBUG2(" WARNING! Asked to process empty redundant-load-balance group. Returning %s.", lrad_int2str(rcode_table, default_result, "??"));
419 return default_result;
423 * Pick a random child.
426 /* Loop over the children */
427 for(p = g->children; p; p = p->next) {
435 * Keep track of how many load balancing servers
436 * we've gone through.
441 * See the "camel book" for why this works.
443 * If (rand(0..n) < 1), pick the current realm.
444 * We add a scale factor of 65536, to avoid
447 if ((count * (lrad_rand() & 0xffff)) < (uint32_t) 0x10000) {
451 rad_assert(child != NULL);
454 * Call the chosen child, with fail-over to the next one
460 * Call the chosen entry. If we're done, then
463 if (!call_one(component, p, request, &priority, &myresult)) {
468 * Go to the next one, and wrap around to the beginning if
472 if (!p) p = g->children;
473 } while (p != child);
476 * And return whatever was decided.
481 int modcall(int component, modcallable *c, REQUEST *request)
486 * A module has taken too long to process the request,
487 * and we've been told to stop processing it.
489 if (request->options & RAD_REQUEST_OPTION_STOP_NOW) {
490 return RLM_MODULE_FAIL;
493 /* Choose a default return value appropriate for the component */
495 case RLM_COMPONENT_AUTZ:
496 myresult = RLM_MODULE_NOTFOUND;
498 case RLM_COMPONENT_AUTH:
499 myresult = RLM_MODULE_REJECT;
501 case RLM_COMPONENT_PREACCT:
502 myresult = RLM_MODULE_NOOP;
504 case RLM_COMPONENT_ACCT:
505 myresult = RLM_MODULE_NOOP;
507 case RLM_COMPONENT_SESS:
508 myresult = RLM_MODULE_FAIL;
510 case RLM_COMPONENT_PRE_PROXY:
511 myresult = RLM_MODULE_NOOP;
513 case RLM_COMPONENT_POST_PROXY:
514 myresult = RLM_MODULE_NOOP;
516 case RLM_COMPONENT_POST_AUTH:
517 myresult = RLM_MODULE_NOOP;
520 myresult = RLM_MODULE_FAIL;
525 DEBUG2("modcall[%s]: NULL object returns %s for request %d",
527 lrad_int2str(rcode_table, myresult, "??"),
533 case MOD_LOAD_BALANCE:
535 modgroup *g = mod_callabletogroup(c);
537 DEBUG2("modcall: entering load-balance group %s for request %d",
538 c->name, request->number);
540 myresult = call_modloadbalance(component, g, request,
543 DEBUG2("modcall: load-balance group %s returns %s for request %d",
545 lrad_int2str(rcode_table, myresult, "??"),
550 case MOD_REDUNDANT_LOAD_BALANCE:
552 modgroup *g = mod_callabletogroup(c);
554 DEBUG2("modcall: entering redundant-load-balance group %s for request %d",
555 c->name, request->number);
557 myresult = call_modredundantloadbalance(component, g, request,
560 DEBUG2("modcall: redundant-load-balance group %s returns %s for request %d",
562 lrad_int2str(rcode_table, myresult, "??"),
569 modgroup *g = mod_callabletogroup(c);
571 DEBUG2("modcall: entering group %s%s for request %d",
572 lrad_int2str(grouptype_table, g->grouptype, ""),
573 c->name, request->number);
575 myresult = call_modgroup(component, g, request,
578 DEBUG2("modcall: leaving group %s%s (returns %s) for request %d",
579 lrad_int2str(grouptype_table, g->grouptype, ""),
581 lrad_int2str(rcode_table, myresult, "??"),
588 modsingle *sp = mod_callabletosingle(c);
590 myresult = call_modsingle(component, sp, request,
593 DEBUG2(" modcall[%s]: module \"%s\" returns %s for request %d",
594 comp2str[component], c->name,
595 lrad_int2str(rcode_table, myresult, "??"),
601 radlog(L_ERR, "Internal error processing module entry");
609 /* If you suspect a bug in the parser, you'll want to use these dump
610 * functions. dump_tree should reproduce a whole tree exactly as it was found
611 * in radiusd.conf, but in long form (all actions explicitly defined) */
612 static void dump_mc(modcallable *c, int indent)
616 if(c->type==MOD_SINGLE) {
617 modsingle *single = mod_callabletosingle(c);
618 DEBUG("%.*s%s {", indent, "\t\t\t\t\t\t\t\t\t\t\t",
619 single->modinst->name);
621 modgroup *g = mod_callabletogroup(c);
623 DEBUG("%.*sgroup {", indent, "\t\t\t\t\t\t\t\t\t\t\t");
624 for(p = g->children;p;p = p->next)
625 dump_mc(p, indent+1);
628 for(i = 0; i<RLM_MODULE_NUMCODES; ++i) {
629 DEBUG("%.*s%s = %s", indent+1, "\t\t\t\t\t\t\t\t\t\t\t",
630 lrad_int2str(rcode_table, i, "??"),
631 action2str(c->actions[i]));
634 DEBUG("%.*s}", indent, "\t\t\t\t\t\t\t\t\t\t\t");
637 static void dump_tree(int comp, modcallable *c)
639 DEBUG("[%s]", comp2str[comp]);
643 static void dump_tree(int comp UNUSED, modcallable *c UNUSED)
649 /* These are the default actions. For each component, the group{} block
650 * behaves like the code from the old module_*() function. redundant{} and
651 * append{} are based on my guesses of what they will be used for. --Pac. */
653 defaultactions[RLM_COMPONENT_COUNT][GROUPTYPE_COUNT][RLM_MODULE_NUMCODES] =
659 MOD_ACTION_RETURN, /* reject */
661 MOD_ACTION_RETURN, /* ok */
662 MOD_ACTION_RETURN, /* handled */
664 MOD_ACTION_RETURN, /* userlock */
665 MOD_ACTION_RETURN, /* notfound */
671 MOD_ACTION_RETURN, /* reject */
673 MOD_ACTION_RETURN, /* ok */
674 MOD_ACTION_RETURN, /* handled */
675 MOD_ACTION_RETURN, /* invalid */
676 MOD_ACTION_RETURN, /* userlock */
677 MOD_ACTION_RETURN, /* notfound */
678 MOD_ACTION_RETURN, /* noop */
679 MOD_ACTION_RETURN /* updated */
683 MOD_ACTION_RETURN, /* reject */
685 MOD_ACTION_RETURN, /* ok */
686 MOD_ACTION_RETURN, /* handled */
687 MOD_ACTION_RETURN, /* invalid */
688 MOD_ACTION_RETURN, /* userlock */
690 MOD_ACTION_RETURN, /* noop */
691 MOD_ACTION_RETURN /* updated */
698 MOD_ACTION_RETURN, /* reject */
699 MOD_ACTION_RETURN, /* fail */
701 MOD_ACTION_RETURN, /* handled */
702 MOD_ACTION_RETURN, /* invalid */
703 MOD_ACTION_RETURN, /* userlock */
710 MOD_ACTION_RETURN, /* reject */
712 MOD_ACTION_RETURN, /* ok */
713 MOD_ACTION_RETURN, /* handled */
714 MOD_ACTION_RETURN, /* invalid */
715 MOD_ACTION_RETURN, /* userlock */
716 MOD_ACTION_RETURN, /* notfound */
717 MOD_ACTION_RETURN, /* noop */
718 MOD_ACTION_RETURN /* updated */
722 MOD_ACTION_RETURN, /* reject */
724 MOD_ACTION_RETURN, /* ok */
725 MOD_ACTION_RETURN, /* handled */
726 MOD_ACTION_RETURN, /* invalid */
727 MOD_ACTION_RETURN, /* userlock */
729 MOD_ACTION_RETURN, /* noop */
730 MOD_ACTION_RETURN /* updated */
737 MOD_ACTION_RETURN, /* reject */
738 MOD_ACTION_RETURN, /* fail */
740 MOD_ACTION_RETURN, /* handled */
741 MOD_ACTION_RETURN, /* invalid */
742 MOD_ACTION_RETURN, /* userlock */
743 MOD_ACTION_RETURN, /* notfound */
749 MOD_ACTION_RETURN, /* reject */
751 MOD_ACTION_RETURN, /* ok */
752 MOD_ACTION_RETURN, /* handled */
753 MOD_ACTION_RETURN, /* invalid */
754 MOD_ACTION_RETURN, /* userlock */
755 MOD_ACTION_RETURN, /* notfound */
756 MOD_ACTION_RETURN, /* noop */
757 MOD_ACTION_RETURN /* updated */
761 MOD_ACTION_RETURN, /* reject */
763 MOD_ACTION_RETURN, /* ok */
764 MOD_ACTION_RETURN, /* handled */
765 MOD_ACTION_RETURN, /* invalid */
766 MOD_ACTION_RETURN, /* userlock */
768 MOD_ACTION_RETURN, /* noop */
769 MOD_ACTION_RETURN /* updated */
776 MOD_ACTION_RETURN, /* reject */
777 MOD_ACTION_RETURN, /* fail */
779 MOD_ACTION_RETURN, /* handled */
780 MOD_ACTION_RETURN, /* invalid */
781 MOD_ACTION_RETURN, /* userlock */
782 MOD_ACTION_RETURN, /* notfound */
790 MOD_ACTION_RETURN, /* ok */
791 MOD_ACTION_RETURN, /* handled */
800 MOD_ACTION_RETURN, /* reject */
802 MOD_ACTION_RETURN, /* ok */
803 MOD_ACTION_RETURN, /* handled */
804 MOD_ACTION_RETURN, /* invalid */
805 MOD_ACTION_RETURN, /* userlock */
807 MOD_ACTION_RETURN, /* noop */
808 MOD_ACTION_RETURN /* updated */
815 MOD_ACTION_RETURN, /* reject */
817 MOD_ACTION_RETURN, /* ok */
818 MOD_ACTION_RETURN, /* handled */
819 MOD_ACTION_RETURN, /* invalid */
820 MOD_ACTION_RETURN, /* userlock */
821 MOD_ACTION_RETURN, /* notfound */
822 MOD_ACTION_RETURN, /* noop */
823 MOD_ACTION_RETURN /* updated */
827 MOD_ACTION_RETURN, /* reject */
829 MOD_ACTION_RETURN, /* ok */
830 MOD_ACTION_RETURN, /* handled */
831 MOD_ACTION_RETURN, /* invalid */
832 MOD_ACTION_RETURN, /* userlock */
833 MOD_ACTION_RETURN, /* notfound */
834 MOD_ACTION_RETURN, /* noop */
835 MOD_ACTION_RETURN /* updated */
839 MOD_ACTION_RETURN, /* reject */
841 MOD_ACTION_RETURN, /* ok */
842 MOD_ACTION_RETURN, /* handled */
843 MOD_ACTION_RETURN, /* invalid */
844 MOD_ACTION_RETURN, /* userlock */
845 MOD_ACTION_RETURN, /* notfound */
846 MOD_ACTION_RETURN, /* noop */
847 MOD_ACTION_RETURN /* updated */
854 MOD_ACTION_RETURN, /* reject */
855 MOD_ACTION_RETURN, /* fail */
857 MOD_ACTION_RETURN, /* handled */
858 MOD_ACTION_RETURN, /* invalid */
859 MOD_ACTION_RETURN, /* userlock */
866 MOD_ACTION_RETURN, /* reject */
868 MOD_ACTION_RETURN, /* ok */
869 MOD_ACTION_RETURN, /* handled */
870 MOD_ACTION_RETURN, /* invalid */
871 MOD_ACTION_RETURN, /* userlock */
872 MOD_ACTION_RETURN, /* notfound */
873 MOD_ACTION_RETURN, /* noop */
874 MOD_ACTION_RETURN /* updated */
878 MOD_ACTION_RETURN, /* reject */
880 MOD_ACTION_RETURN, /* ok */
881 MOD_ACTION_RETURN, /* handled */
882 MOD_ACTION_RETURN, /* invalid */
883 MOD_ACTION_RETURN, /* userlock */
885 MOD_ACTION_RETURN, /* noop */
886 MOD_ACTION_RETURN /* updated */
893 MOD_ACTION_RETURN, /* reject */
894 MOD_ACTION_RETURN, /* fail */
896 MOD_ACTION_RETURN, /* handled */
897 MOD_ACTION_RETURN, /* invalid */
898 MOD_ACTION_RETURN, /* userlock */
905 MOD_ACTION_RETURN, /* reject */
907 MOD_ACTION_RETURN, /* ok */
908 MOD_ACTION_RETURN, /* handled */
909 MOD_ACTION_RETURN, /* invalid */
910 MOD_ACTION_RETURN, /* userlock */
911 MOD_ACTION_RETURN, /* notfound */
912 MOD_ACTION_RETURN, /* noop */
913 MOD_ACTION_RETURN /* updated */
917 MOD_ACTION_RETURN, /* reject */
919 MOD_ACTION_RETURN, /* ok */
920 MOD_ACTION_RETURN, /* handled */
921 MOD_ACTION_RETURN, /* invalid */
922 MOD_ACTION_RETURN, /* userlock */
924 MOD_ACTION_RETURN, /* noop */
925 MOD_ACTION_RETURN /* updated */
932 MOD_ACTION_RETURN, /* reject */
933 MOD_ACTION_RETURN, /* fail */
935 MOD_ACTION_RETURN, /* handled */
936 MOD_ACTION_RETURN, /* invalid */
937 MOD_ACTION_RETURN, /* userlock */
944 MOD_ACTION_RETURN, /* reject */
946 MOD_ACTION_RETURN, /* ok */
947 MOD_ACTION_RETURN, /* handled */
948 MOD_ACTION_RETURN, /* invalid */
949 MOD_ACTION_RETURN, /* userlock */
950 MOD_ACTION_RETURN, /* notfound */
951 MOD_ACTION_RETURN, /* noop */
952 MOD_ACTION_RETURN /* updated */
956 MOD_ACTION_RETURN, /* reject */
958 MOD_ACTION_RETURN, /* ok */
959 MOD_ACTION_RETURN, /* handled */
960 MOD_ACTION_RETURN, /* invalid */
961 MOD_ACTION_RETURN, /* userlock */
963 MOD_ACTION_RETURN, /* noop */
964 MOD_ACTION_RETURN /* updated */
971 * Compile one entry of a module call.
973 static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
974 const char *filename, int grouptype,
975 const char **modname)
978 const char *modrefname;
980 modcallable *csingle;
981 module_instance_t *this;
983 if (cf_item_is_section(ci)) {
984 CONF_SECTION *cs = cf_itemtosection(ci);
985 const char *name2 = cf_section_name2(cs);
987 lineno = cf_section_lineno(cs);
988 modrefname = cf_section_name1(cs);
989 if (!name2) name2 = "_UnNamedGroup";
992 * group{}, redundant{}, or append{} may appear
993 * where a single module instance was expected.
994 * In that case, we hand it off to
997 if (strcmp(modrefname, "group") == 0) {
999 return do_compile_modgroup(component, cs, filename,
1000 GROUPTYPE_SIMPLE, grouptype);
1001 } else if (strcmp(modrefname, "redundant") == 0) {
1003 return do_compile_modgroup(component, cs, filename,
1004 GROUPTYPE_REDUNDANT, grouptype);
1005 } else if (strcmp(modrefname, "append") == 0) {
1007 return do_compile_modgroup(component, cs, filename,
1008 GROUPTYPE_APPEND, grouptype);
1009 } else if (strcmp(modrefname, "load-balance") == 0) {
1011 csingle= do_compile_modgroup(component, cs, filename,
1012 GROUPTYPE_SIMPLE, grouptype);
1013 if (!csingle) return NULL;
1014 csingle->type = MOD_LOAD_BALANCE;
1016 } else if (strcmp(modrefname, "redundant-load-balance") == 0) {
1018 csingle= do_compile_modgroup(component, cs, filename,
1019 GROUPTYPE_REDUNDANT, grouptype);
1020 if (!csingle) return NULL;
1021 csingle->type = MOD_REDUNDANT_LOAD_BALANCE;
1025 * Else it's a module reference, with updated return
1029 CONF_PAIR *cp = cf_itemtopair(ci);
1030 lineno = cf_pair_lineno(cp);
1031 modrefname = cf_pair_attr(cp);
1035 * See if the module is a virtual one. If so, return that,
1036 * rather than doing anything here.
1038 this = find_module_instance(cf_section_find("modules"), modrefname);
1040 CONF_SECTION *cs, *subcs;
1043 * Then, look for it in the "instantiate" section.
1045 if (((subcs = cf_section_find(NULL)) != NULL) &&
1046 ((cs = cf_section_sub_find_name2(subcs, "instantiate", NULL)) != NULL)) {
1047 subcs = cf_section_sub_find_name2(cs, NULL, modrefname);
1050 * As it's sole configuration, the
1051 * virtual module takes a section which
1054 return do_compile_modsingle(component,
1055 cf_sectiontoitem(subcs),
1064 radlog(L_ERR|L_CONS, "%s[%d] Unknown module \"%s\".", filename,
1065 lineno, modrefname);
1070 * We know it's all OK, allocate the structures, and fill
1073 single = rad_malloc(sizeof(*single));
1074 csingle = mod_singletocallable(single);
1075 csingle->next = NULL;
1076 memcpy(csingle->actions, defaultactions[component][grouptype],
1077 sizeof csingle->actions);
1078 rad_assert(modrefname != NULL);
1079 csingle->name = modrefname;
1080 csingle->type = MOD_SINGLE;
1083 * Singles can override the actions, virtual modules cannot.
1085 * FIXME: We may want to re-visit how to do this...
1086 * maybe a csingle as a ref?
1088 if (cf_item_is_section(ci)) {
1089 CONF_SECTION *cs = cf_itemtosection(ci);
1091 const char *attr, *value;
1093 for (ci=cf_item_find_next(cs, NULL);
1095 ci=cf_item_find_next(cs, ci)) {
1097 if (cf_item_is_section(ci)) {
1098 radlog(L_ERR|L_CONS,
1099 "%s[%d] Subsection of module instance call "
1100 "not allowed\n", filename,
1101 cf_section_lineno(cf_itemtosection(ci)));
1102 modcallable_free(&csingle);
1106 cp = cf_itemtopair(ci);
1107 attr = cf_pair_attr(cp);
1108 value = cf_pair_value(cp);
1109 lineno = cf_pair_lineno(cp);
1111 if (!compile_action(csingle, attr, value, filename,
1113 modcallable_free(&csingle);
1120 * Bail out if the module in question does not supply the
1123 if (!this->entry->module->methods[component]) {
1124 radlog(L_ERR|L_CONS,
1125 "%s[%d]: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
1126 filename, lineno, this->entry->module->name,
1127 comp2str[component]);
1128 modcallable_free(&csingle);
1132 single->modinst = this;
1133 *modname = this->entry->module->name;
1137 modcallable *compile_modsingle(int component, CONF_ITEM *ci,
1138 const char *filename, const char **modname)
1140 modcallable *ret = do_compile_modsingle(component, ci, filename,
1143 dump_tree(component, ret);
1149 * Internal compile group code.
1151 static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
1152 const char *filename, int grouptype,
1153 int parentgrouptype)
1160 g = rad_malloc(sizeof(*g));
1161 g->grouptype = grouptype;
1163 c = mod_grouptocallable(g);
1165 memset(c->actions, 0, sizeof(c->actions));
1168 * Remember the name for printing, etc.
1170 * FIXME: We may also want to put the names into a
1171 * rbtree, so that groups can reference each other...
1173 c->name = cf_section_name2(cs);
1174 if (!c->name) c->name = "";
1175 c->type = MOD_GROUP;
1179 * Loop over the children of this group.
1181 for (ci=cf_item_find_next(cs, NULL);
1183 ci=cf_item_find_next(cs, ci)) {
1186 * Sections are references to other groups, or
1187 * to modules with updated return codes.
1189 if (cf_item_is_section(ci)) {
1190 const char *junk = NULL;
1191 modcallable *single;
1193 CONF_SECTION *subcs = cf_itemtosection(ci);
1195 lineno = cf_section_lineno(subcs);
1197 single = do_compile_modsingle(component, ci, filename,
1200 radlog(L_ERR|L_CONS,
1201 "%s[%d] Failed to parse \"%s\" subsection.\n",
1203 cf_section_name1(subcs));
1204 modcallable_free(&c);
1207 add_child(g, single);
1210 const char *attr, *value;
1211 CONF_PAIR *cp = cf_itemtopair(ci);
1214 attr = cf_pair_attr(cp);
1215 value = cf_pair_value(cp);
1216 lineno = cf_pair_lineno(cp);
1219 * A CONF_PAIR is either a module
1220 * instance with no actions
1223 if (value[0] == 0) {
1224 modcallable *single;
1225 const char *junk = NULL;
1227 single = do_compile_modsingle(component,
1228 cf_pairtoitem(cp), filename,
1231 radlog(L_ERR|L_CONS,
1232 "%s[%d] Failed to parse \"%s\" entry.\n",
1233 filename, lineno, attr);
1234 modcallable_free(&c);
1237 add_child(g, single);
1240 * Or a module instance with action.
1242 } else if (!compile_action(c, attr, value, filename,
1244 modcallable_free(&c);
1246 } /* else it worked */
1251 * Set the default actions, if they haven't already been
1254 for (i = 0; i < RLM_MODULE_NUMCODES; i++) {
1255 if (!c->actions[i]) {
1256 c->actions[i] = defaultactions[component][parentgrouptype][i];
1261 * FIXME: If there are no children, return NULL?
1263 return mod_grouptocallable(g);
1266 modcallable *compile_modgroup(int component, CONF_SECTION *cs,
1267 const char *filename)
1269 modcallable *ret = do_compile_modgroup(component, cs, filename,
1272 dump_tree(component, ret);
1276 void add_to_modcallable(modcallable **parent, modcallable *this,
1277 int component, const char *name)
1281 rad_assert(this != NULL);
1283 if (*parent == NULL) {
1286 g = rad_malloc(sizeof *g);
1287 g->grouptype = GROUPTYPE_SIMPLE;
1288 c = mod_grouptocallable(g);
1291 defaultactions[component][GROUPTYPE_SIMPLE],
1292 sizeof(c->actions));
1293 rad_assert(name != NULL);
1295 c->type = MOD_GROUP;
1298 *parent = mod_grouptocallable(g);
1300 g = mod_callabletogroup(*parent);
1306 void modcallable_free(modcallable **pc)
1308 modcallable *c, *loop, *next;
1310 if(c->type==MOD_GROUP) {
1311 for(loop = mod_callabletogroup(c)->children;
1315 modcallable_free(&loop);