116
static int str2rcode(const char *s, const char *filename, int lineno)
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)
120
rcode = lrad_str2int(rcode_table, s, -1);
143
rcode = lrad_str2int(rcode_table, attr, -1);
122
145
radlog(L_ERR|L_CONS,
123
146
"%s[%d] Unknown module rcode '%s'.\n",
124
filename, lineno, s);
147
filename, lineno, attr);
131
static int str2action(const char *s, const char *filename, int lineno)
133
if(!strcasecmp(s, "return"))
134
return MOD_ACTION_RETURN;
135
else if(!strcasecmp(s, "reject"))
136
return MOD_ACTION_REJECT;
137
else if (strspn(s, "0123456789")==strlen(s)) {
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);
141
161
* Don't allow priority zero, for future use.
145
"%s[%d] Invalid action '%s'.\n",
146
filename, lineno, s);
163
if (action == 0) return 0;
151
165
radlog(L_ERR|L_CONS,
152
"%s[%d] Unknown action '%s'.\n",
153
filename, lineno, s);
166
"%s[%d] Unknown action '%s'.\n",
167
filename, lineno, value);
171
c->actions[rcode] = action;
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];
229
307
static int call_modgroup(int component, modgroup *g, REQUEST *request,
232
310
int myresult = default_result;
311
int priority = 0; /* default result has lowest priority */
241
319
return default_result;
244
/* Assign the lowest possible preference to the default return code */
247
/* Loop over the children */
248
for(p = g->children; p; p = p->next) {
249
int r = RLM_MODULE_FAIL;
251
/* Call this child by recursing into modcall */
252
r = modcall(component, p, request);
255
DEBUG2("%s: action for %s is %s",
256
comp2str[component], lrad_int2str(rcode_table, r, "??"),
257
action2str(p->actions[r]));
260
/* Find an action to go with the child's result. If "return",
261
* break out of the loop so the rest of the children in the
262
* list will be skipped. */
263
if(p->actions[r] == MOD_ACTION_RETURN) {
268
/* If "reject" break out of the loop and return reject */
269
if (p->actions[r] == MOD_ACTION_REJECT) {
270
myresult = RLM_MODULE_REJECT;
274
/* Otherwise, the action is a number, the preference level of
275
* this return code. If no higher preference has been seen
276
* yet, remember this one. */
277
if(p->actions[r] >= myresultpref) {
279
myresultpref = p->actions[r];
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.
329
if(c->type==MOD_GROUP) {
330
modgroup *g = mod_callabletogroup(c);
332
DEBUG2("modcall: entering group %s for request %d",
333
c->name, request->number);
335
myresult = call_modgroup(component, g, request, myresult);
337
DEBUG2("modcall: group %s returns %s for request %d",
339
lrad_int2str(rcode_table, myresult, "??"),
342
modsingle *sp = mod_callabletosingle(c);
344
myresult = call_modsingle(component, sp, request, myresult);
346
DEBUG2(" modcall[%s]: module \"%s\" returns %s for request %d",
347
comp2str[component], c->name,
348
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");
721
/* Bail out if the module in question does not supply the wanted component */
722
static void sanity_check(int component, module_instance_t *inst,
723
const char *filename)
725
if (!inst->entry->module->methods[component]) {
727
"%s: \"%s\" modules aren't allowed in '%s' sections -- they have no such method.",
728
filename, inst->entry->module->name,
729
component_names[component]);
734
/* Parse a CONF_SECTION containing only result=action pairs */
735
static void override_actions(modcallable *c, CONF_SECTION *cs,
736
const char *filename)
740
const char *attr, *value;
741
int lineno, rcode, action;
743
for(ci=cf_item_find_next(cs, NULL); ci != NULL; ci=cf_item_find_next(cs, ci)) {
744
if(cf_item_is_section(ci)) {
746
"%s[%d] Subsection of module instance call "
747
"not allowed\n", filename,
748
cf_section_lineno(cf_itemtosection(ci)));
751
cp = cf_itemtopair(ci);
752
attr = cf_pair_attr(cp);
753
value = cf_pair_value(cp);
754
lineno = cf_pair_lineno(cp);
755
rcode = str2rcode(attr, filename, lineno);
756
action = str2action(value, filename, lineno);
757
c->actions[rcode] = action;
761
944
static modcallable *do_compile_modsingle(int component, CONF_ITEM *ci,
762
const char *filename, int grouptype,
763
const char **modname)
945
const char *filename, int grouptype,
946
const char **modname)
766
949
const char *modrefname;
771
954
if (cf_item_is_section(ci)) {
772
955
CONF_SECTION *cs = cf_itemtosection(ci);
956
const char *name2 = cf_section_name2(cs);
774
958
lineno = cf_section_lineno(cs);
775
959
modrefname = cf_section_name1(cs);
960
if (!name2) name2 = "_UnNamedGroup";
777
/* group{}, redundant{}, or append{} may appear where a
778
* single module instance was expected - in that case, we
779
* hand it off to compile_modgroup */
963
* group{}, redundant{}, or append{} may appear
964
* where a single module instance was expected.
965
* In that case, we hand it off to
780
968
if (strcmp(modrefname, "group") == 0) {
781
*modname = "UnnamedGroup";
782
970
return do_compile_modgroup(component, cs, filename,
783
GROUPTYPE_SIMPLEGROUP, grouptype);
971
GROUPTYPE_SIMPLE, grouptype);
784
972
} else if (strcmp(modrefname, "redundant") == 0) {
785
*modname = "UnnamedGroup";
786
974
return do_compile_modgroup(component, cs, filename,
787
975
GROUPTYPE_REDUNDANT, grouptype);
788
976
} else if (strcmp(modrefname, "append") == 0) {
789
*modname = "UnnamedGroup";
790
978
return do_compile_modgroup(component, cs, filename,
791
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;
794
996
CONF_PAIR *cp = cf_itemtopair(ci);
796
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
799
1017
single = rad_malloc(sizeof(*single));
800
1018
csingle = mod_singletocallable(single);
801
1019
csingle->next = NULL;
802
memcpy(csingle->actions,
803
defaultactions[component][grouptype],
804
sizeof csingle->actions);
1020
memcpy(csingle->actions, defaultactions[component][grouptype],
1021
sizeof csingle->actions);
805
1022
rad_assert(modrefname != NULL);
806
1023
csingle->name = modrefname;
807
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?
809
1032
if (cf_item_is_section(ci)) {
810
/* override default actions with what's in the CONF_SECTION */
811
override_actions(csingle, cf_itemtosection(ci), filename);
814
this = find_module_instance(modrefname);
819
sanity_check(component, this, filename);
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);
821
1076
single->modinst = this;
822
1077
*modname = this->entry->module->name;
826
1081
modcallable *compile_modsingle(int component, CONF_ITEM *ci,
827
const char *filename, const char **modname)
1082
const char *filename, const char **modname)
829
1084
modcallable *ret = do_compile_modsingle(component, ci, filename,
830
GROUPTYPE_SIMPLEGROUP,
832
1087
dump_tree(component, ret);
836
1091
static modcallable *do_compile_modgroup(int component, CONF_SECTION *cs,
837
const char *filename, int grouptype,
1092
const char *filename, int grouptype,
1093
int parentgrouptype)
844
1099
g = rad_malloc(sizeof *g);
1100
g->grouptype = grouptype;
846
1102
c = mod_grouptocallable(g);
848
1104
memcpy(c->actions, defaultactions[component][parentgrouptype],
850
c->name = cf_section_name1(cs);
851
rad_assert(c->name != NULL);
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 = "";
852
1115
c->type = MOD_GROUP;
853
1116
g->children = NULL;
855
for (ci=cf_item_find_next(cs, NULL); ci != NULL; ci=cf_item_find_next(cs, ci)) {
1118
for (ci=cf_item_find_next(cs, NULL);
1120
ci=cf_item_find_next(cs, ci)) {
856
1122
if(cf_item_is_section(ci)) {
1123
const char *junk = NULL;
858
1124
modcallable *single;
1126
CONF_SECTION *subcs = cf_itemtosection(ci);
1128
lineno = cf_section_lineno(subcs);
859
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);
861
1140
add_child(g, single);
863
1143
const char *attr, *value;
864
1144
CONF_PAIR *cp = cf_itemtopair(ci);
868
1148
value = cf_pair_value(cp);
869
1149
lineno = cf_pair_lineno(cp);
871
/* A CONF_PAIR is either a module instance with no
872
* actions specified... */
1152
* A CONF_PAIR is either a module
1153
* instance with no actions
1156
if (value[0] == 0) {
874
1157
modcallable *single;
1158
const char *junk = NULL;
877
1160
single = do_compile_modsingle(component,
878
1161
cf_pairtoitem(cp), filename,
879
1162
grouptype, &junk);
1164
radlog(L_ERR|L_CONS,
1165
"%s[%d] Failed to parse \"%s\" entry.\n",
1166
filename, lineno, attr);
1167
modcallable_free(&c);
880
1170
add_child(g, single);
882
/* ...or an action to be applied to this
885
rcode = str2rcode(attr, filename, lineno);
886
action = str2action(value, filename, lineno);
888
c->actions[rcode] = action;
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?
892
1186
return mod_grouptocallable(g);
896
1190
const char *filename)
898
1192
modcallable *ret = do_compile_modgroup(component, cs, filename,
899
GROUPTYPE_SIMPLEGROUP,
900
GROUPTYPE_SIMPLEGROUP);
901
1195
dump_tree(component, ret);
905
1199
void add_to_modcallable(modcallable **parent, modcallable *this,
906
int component, char *name)
1200
int component, char *name)
1204
rad_assert(this != NULL);
910
1206
if (*parent == NULL) {
913
1209
g = rad_malloc(sizeof *g);
1210
g->grouptype = GROUPTYPE_SIMPLE;
914
1211
c = mod_grouptocallable(g);
916
1213
memcpy(c->actions,
917
defaultactions[component][GROUPTYPE_SIMPLEGROUP],
1214
defaultactions[component][GROUPTYPE_SIMPLE],
1215
sizeof(c->actions));
919
1216
rad_assert(name != NULL);
921
1218
c->type = MOD_GROUP;