Add experimental code for dynamic discovery (only if ENABLE_EXPERIMENTAL_DYNDISC).
[libradsec.git] / radsecproxy.c
index fa72fb2..bc3fbfe 100644 (file)
@@ -327,8 +327,13 @@ void freeserver(struct server *server, uint8_t destroymutex) {
     if (server->rbios)
        freebios(server->rbios);
     free(server->dynamiclookuparg);
-    if (server->ssl)
-       SSL_free(server->ssl);
+    if (server->ssl) {
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+        if (server->sock >= 0)
+            close(server->sock);
+#endif
+        SSL_free(server->ssl);
+    }
     if (destroymutex) {
        pthread_mutex_destroy(&server->lock);
        pthread_cond_destroy(&server->newrq_cond);
@@ -768,7 +773,12 @@ int hasdynamicserver(struct list *srvconfs) {
     struct list_node *entry;
 
     for (entry = list_first(srvconfs); entry; entry = list_next(entry))
-       if (((struct clsrvconf *)entry->data)->dynamiclookupcommand)
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+        if (((struct clsrvconf *)entry->data)->dynamiclookupcommand
+            || ((struct clsrvconf *)entry->data)->servers->in_use)
+#else
+        if (((struct clsrvconf *)entry->data)->dynamiclookupcommand)
+#endif
            return 1;
     return 0;
 }
@@ -1764,12 +1774,17 @@ void *clientwr(void *arg) {
        dynconffail = 1;
        server->dynstartup = 0;
        server->dynfailing = 1;
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+       pthread_mutex_unlock(&server->lock);
+#endif
        debug(DBG_WARN, "%s: dynamicconfig(%s) failed, sleeping %ds",
               __func__, server->conf->name, ZZZ);
        sleep(ZZZ);
        goto errexit;
     }
-
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+    pthread_mutex_unlock(&server->lock);
+#endif
     /* FIXME: Is resolving not always done by compileserverconfig(),
      * either as part of static configuration setup or by
      * dynamicconfig() above?  */
@@ -1798,6 +1813,9 @@ void *clientwr(void *arg) {
            goto errexit;
        }
        server->connectionok = 1;
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+       server->in_use = 1;
+#endif
        if (pthread_create(&clientrdth, NULL, conf->pdef->clientconnreader, (void *)server)) {
            debugerrno(errno, DBG_ERR, "clientwr: pthread_create failed");
            goto errexit;
@@ -1907,6 +1925,9 @@ void *clientwr(void *arg) {
        }
     }
 errexit:
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+    server->in_use = 0;
+#endif
     conf->servers = NULL;
     if (server->dynamiclookuparg) {
        removeserversubrealms(realms, conf);
@@ -2201,12 +2222,28 @@ struct list *createsubrealmservers(struct realm *realm, struct list *srvconfs) {
                srvconf->servers->dynstartup = 1;
                 debug(DBG_DBG, "%s: new client writer for %s",
                       __func__, srvconf->servers->conf->name);
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+               pthread_mutex_lock(&srvconf->servers->lock);
+#endif
                if (pthread_create(&clientth, NULL, clientwr, (void *)(srvconf->servers))) {
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+                    pthread_mutex_unlock(&srvconf->servers->lock);
+#endif
                    debugerrno(errno, DBG_ERR, "pthread_create failed");
                    freeserver(srvconf->servers, 1);
                    srvconf->servers = NULL;
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+                   conf = srvconf;
+                   continue;
+#endif
                } else
                    pthread_detach(clientth);
+
+#if defined ENABLE_EXPERIMENTAL_DYNDISC
+                /* If clientwr() could not find a NAPTR we have to
+                 * wait for dynfailing=1 what is set in clientwr().  */
+                pthread_mutex_lock(&srvconf->servers->lock);
+#endif
            }
            conf = srvconf;
        }
@@ -2684,13 +2721,19 @@ int mergesrvconf(struct clsrvconf *dst, struct clsrvconf *src) {
     return 1;
 }
 
-int config_hostaf(const char *block, int ipv4only, int ipv6only, int *af) {
+/** Set *AF according to IPV4ONLY and IPV6ONLY:
+    - If both are set, the function fails.
+    - If exactly one is set, *AF is set accordingly.
+    - If none is set, *AF is not affected.
+    Return 0 on success and !0 on failure.
+    In the case of an error, *AF is not affected.  */
+int config_hostaf(const char *desc, int ipv4only, int ipv6only, int *af) {
+    assert(af != NULL);
     if (ipv4only && ipv6only) {
        debug(DBG_ERR, "error in block %s, at most one of IPv4Only and "
-              "IPv6Only can be enabled", block);
+              "IPv6Only can be enabled", desc);
         return -1;
     }
-    *af = AF_UNSPEC;
     if (ipv4only)
         *af = AF_INET;
     if (ipv6only)
@@ -2702,7 +2745,7 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     struct clsrvconf *conf;
     char *conftype = NULL, *rewriteinalias = NULL;
     long int dupinterval = LONG_MIN, addttl = LONG_MIN;
-    uint8_t ipv4only, ipv6only;
+    uint8_t ipv4only = 0, ipv6only = 0;
 
     debug(DBG_DBG, "confclient_cb called for %s", block);
 
@@ -2769,6 +2812,9 @@ int confclient_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     }
 #endif
 
+    conf->hostaf = AF_UNSPEC;
+    if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
+        debugx(1, DBG_ERR, "config error: ^");
     if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
         debugx(1, DBG_ERR, "error in block %s: ^", block);
 
@@ -2877,7 +2923,7 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     struct clsrvconf *conf, *resconf;
     char *conftype = NULL, *rewriteinalias = NULL;
     long int retryinterval = LONG_MIN, retrycount = LONG_MIN, addttl = LONG_MIN;
-    uint8_t ipv4only, ipv6only;
+    uint8_t ipv4only = 0, ipv6only = 0;
 
     debug(DBG_DBG, "confserver_cb called for %s", block);
 
@@ -2947,6 +2993,9 @@ int confserver_cb(struct gconffile **cf, void *arg, char *block, char *opt, char
     free(conftype);
     conftype = NULL;
 
+    conf->hostaf = AF_UNSPEC;
+    if (config_hostaf("top level", options.ipv4only, options.ipv6only, &conf->hostaf))
+        debugx(1, DBG_ERR, "config error: ^");
     if (config_hostaf(block, ipv4only, ipv6only, &conf->hostaf))
         goto errexit;
 
@@ -3151,6 +3200,8 @@ void getmainconfig(const char *configfile) {
            "FTicksKey", CONF_STR, &fticks_key_str,
            "FTicksSyslogFacility", CONF_STR, &options.ftickssyslogfacility,
 #endif
+            "IPv4Only", CONF_BLN, &options.ipv4only,
+            "IPv6Only", CONF_BLN, &options.ipv6only,
            NULL
            ))
        debugx(1, DBG_ERR, "configuration error");