+#ifdef WITH_COA
+static const FR_NAME_NUMBER home_server_types[] = {
+ { "auth", HOME_TYPE_AUTH },
+ { "auth+acct", HOME_TYPE_AUTH },
+ { "acct", HOME_TYPE_ACCT },
+ { "coa", HOME_TYPE_COA },
+ { NULL, 0 }
+};
+
+static int pool_peek_type(CONF_SECTION *config, CONF_SECTION *cs)
+{
+ int home;
+ const char *name, *type;
+ CONF_PAIR *cp;
+ CONF_SECTION *server_cs;
+
+ cp = cf_pair_find(cs, "home_server");
+ if (!cp) {
+ cf_log_err(cf_sectiontoitem(cs), "Pool does not contain a \"home_server\" entry");
+ return HOME_TYPE_INVALID;
+ }
+
+ name = cf_pair_value(cp);
+ if (!name) {
+ cf_log_err(cf_pairtoitem(cp), "home_server entry does not reference a home server");
+ return HOME_TYPE_INVALID;
+ }
+
+ server_cs = cf_section_sub_find_name2(config, "home_server", name);
+ if (!server_cs) {
+ cf_log_err(cf_pairtoitem(cp), "home_server \"%s\" does not exist", name);
+ return HOME_TYPE_INVALID;
+ }
+
+ cp = cf_pair_find(server_cs, "type");
+ if (!cp) {
+ cf_log_err(cf_sectiontoitem(server_cs), "home_server %s does not contain a \"type\" entry", name);
+ return HOME_TYPE_INVALID;
+ }
+
+ type = cf_pair_value(cp);
+ if (!type) {
+ cf_log_err(cf_sectiontoitem(server_cs), "home_server %s contains an empty \"type\" entry", name);
+ return HOME_TYPE_INVALID;
+ }
+
+ home = fr_str2int(home_server_types, type, HOME_TYPE_INVALID);
+ if (home == HOME_TYPE_INVALID) {
+ cf_log_err(cf_sectiontoitem(server_cs), "home_server %s contains an invalid \"type\" entry of value \"%s\"", name, type);
+ return HOME_TYPE_INVALID;
+ }
+
+ return home; /* 'cause we miss it so much */
+}
+#endif
+
+int realms_init(CONF_SECTION *config)
+{
+ CONF_SECTION *cs;
+ realm_config_t *rc, *old_rc;
+
+ if (realms_byname) return 1;
+
+ realms_byname = rbtree_create(realm_name_cmp, free, 0);
+ if (!realms_byname) {
+ realms_free();
+ return 0;
+ }
+
+#ifdef WITH_PROXY
+ home_servers_byaddr = rbtree_create(home_server_addr_cmp, free, 0);
+ if (!home_servers_byaddr) {
+ realms_free();
+ return 0;
+ }
+
+ home_servers_byname = rbtree_create(home_server_name_cmp, NULL, 0);
+ if (!home_servers_byname) {
+ realms_free();
+ return 0;
+ }
+
+#ifdef WITH_STATS
+ home_servers_bynumber = rbtree_create(home_server_number_cmp, NULL, 0);
+ if (!home_servers_bynumber) {
+ realms_free();
+ return 0;
+ }
+#endif
+
+ home_pools_byname = rbtree_create(home_pool_name_cmp, NULL, 0);
+ if (!home_pools_byname) {
+ realms_free();
+ return 0;
+ }
+#endif
+
+ rc = rad_malloc(sizeof(*rc));
+ memset(rc, 0, sizeof(*rc));
+ rc->cs = config;
+
+#ifdef WITH_PROXY
+ cs = cf_subsection_find_next(config, NULL, "proxy");
+ if (cs) {
+ cf_section_parse(cs, rc, proxy_config);
+ } else {
+ rc->dead_time = DEAD_TIME;
+ rc->retry_count = RETRY_COUNT;
+ rc->retry_delay = RETRY_DELAY;
+ rc->fallback = 0;
+ rc->wake_all_if_all_dead= 0;
+ }
+#endif
+
+ for (cs = cf_subsection_find_next(config, NULL, "realm");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "realm")) {
+ if (!realm_add(rc, cs)) {
+ free(rc);
+ realms_free();
+ return 0;
+ }
+ }
+
+#ifdef WITH_COA
+ /*
+ * CoA pools aren't tied to realms.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "home_server_pool");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "home_server_pool")) {
+ int type;
+
+ /*
+ * Pool was already loaded.
+ */
+ if (cf_data_find(cs, "home_server_pool")) continue;
+
+ type = pool_peek_type(config, cs);
+ if (type == HOME_TYPE_INVALID) return 0;
+
+ if (!server_pool_add(rc, cs, type, TRUE)) {
+ return 0;
+ }
+ }
+
+ /*
+ * CoA home servers aren't tied to realms.
+ */
+ for (cs = cf_subsection_find_next(config, NULL, "home_server");
+ cs != NULL;
+ cs = cf_subsection_find_next(config, cs, "home_server")) {
+ /*
+ * Server was already loaded.
+ */
+ if (cf_data_find(cs, "home_server")) continue;
+
+ if (!home_server_add(rc, cs, HOME_TYPE_COA)) {
+ return 0;
+ }
+ }
+#endif
+
+
+#ifdef WITH_PROXY
+ xlat_register("home_server", xlat_home_server, NULL);
+ xlat_register("home_server_pool", xlat_server_pool, NULL);
+#endif
+
+ /*
+ * Swap pointers atomically.
+ */
+ old_rc = realm_config;
+ realm_config = rc;
+ free(old_rc);
+
+ return 1;
+}
+
+/*
+ * Find a realm where "name" might be the regex.
+ */
+REALM *realm_find2(const char *name)
+{
+ REALM myrealm;
+ REALM *realm;
+
+ if (!name) name = "NULL";
+
+ myrealm.name = name;
+ realm = rbtree_finddata(realms_byname, &myrealm);
+ if (realm) return realm;
+
+#ifdef HAVE_REGEX_H
+ if (realms_regex) {
+ realm_regex_t *this;
+
+ for (this = realms_regex; this != NULL; this = this->next) {
+ if (strcmp(this->realm->name, name) == 0) {
+ return this->realm;
+ }
+ }
+ }
+#endif
+
+ /*
+ * Couldn't find a realm. Look for DEFAULT.
+ */
+ myrealm.name = "DEFAULT";
+ return rbtree_finddata(realms_byname, &myrealm);
+}
+