]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- auth-load-thread, poll for quit and process load transfer end.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Mon, 29 Jun 2026 14:52:20 +0000 (16:52 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Mon, 29 Jun 2026 14:52:20 +0000 (16:52 +0200)
services/authload.c
services/authload.h
services/authzone.c
services/authzone.h

index fdf2494e152e1a4c80b4c8800e0516dfc27cbefa..74c7d2ad7d72562e3d8b7b531a620914ff9fd54b 100644 (file)
 #include "util/log.h"
 #include "util/ub_event.h"
 
+/** Auth load notification to string, for descriptive purposes. */
+static const char*
+auth_load_notification_to_string(enum auth_load_notification_type status)
+{
+       switch(status) {
+       case auth_load_notification_exit:
+               return "auth_load_notification_exit";
+       default:
+               break;
+       }
+       return "unknown_auth_load_notification_value";
+}
+
 /** delete chunks */
 static void
 auth_chunk_list_delete(struct auth_chunk* first)
@@ -149,7 +162,58 @@ auth_load_task_create_xfr(struct auth_xfer* xfr, struct worker* worker)
 static int
 auth_load_thread_poll_for_quit(struct auth_load_thread* thr)
 {
-       (void)thr;
+       int inevent, loopexit = 0;
+       uint8_t cmd;
+       ssize_t ret;
+
+       if(thr->need_to_quit)
+               return 1;
+       /* Is there data? */
+       if(!sock_poll_timeout(thr->commpair[1], 0, 1, 0, &inevent)) {
+               log_err("auth_load_thread_poll_for_quit: poll failed");
+               return 0;
+       }
+       if(!inevent)
+               return 0;
+
+       /* Read the data */
+       while(1) {
+               if(++loopexit > 200) {
+                       log_err("auth_load_thread_poll_for_quit: recv loops %s",
+                               sock_strerror(errno));
+                       return 0;
+               }
+               ret = recv(thr->commpair[1], ((char*)&cmd), sizeof(cmd), 0);
+               if(ret == -1) {
+                       if(
+#ifndef USE_WINSOCK
+                               errno == EINTR || errno == EAGAIN
+#  ifdef EWOULDBLOCK
+                               || errno == EWOULDBLOCK
+#  endif
+#else
+                               WSAGetLastError() == WSAEINTR ||
+                               WSAGetLastError() == WSAEINPROGRESS ||
+                               WSAGetLastError() == WSAEWOULDBLOCK
+#endif
+                               )
+                               continue; /* Try again. */
+                       log_err("auth_load_thread_poll_for_quit: recv: %s",
+                               sock_strerror(errno));
+                       return 0;
+               } else if(ret == 0) {
+                       log_err("auth_load_thread_poll_for_quit: recv: EOF");
+                       return 0;
+               }
+               break;
+       }
+       if(cmd == auth_load_notification_exit) {
+               thr->need_to_quit = 1;
+               verbose(VERB_ALGO, "auth load: exit notification received");
+               return 1;
+       }
+       log_err("auth_load_thread_poll_for_quit: unknown notification status "
+               "received: %d %s", cmd, auth_load_notification_to_string(cmd));
        return 0;
 }
 
@@ -298,6 +362,8 @@ worker_auth_load_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits),
        uint8_t recv_item;
        ssize_t ret;
        struct auth_xfer* xfr;
+       struct module_env* env;
+       int ixfr_fail;
 
        log_assert(thr->commpair[0] >= 0);
        ret = recv(thr->commpair[0], &recv_item, 1, 0);
@@ -316,7 +382,7 @@ worker_auth_load_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits),
                        return; /* Continue later. */
 #ifdef USE_WINSOCK
                if(WSAGetLastError() == WSAEWOULDBLOCK) {
-                       ub_winsock_tcp_wouldblock(fr->service_event,
+                       ub_winsock_tcp_wouldblock(thr->service_event,
                                UB_EV_READ);
                        return; /* Continue later. */
                }
@@ -347,8 +413,10 @@ worker_auth_load_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits),
        }
        lock_basic_lock(&xfr->lock);
        lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
+       env = &thr->task->worker->env;
+       ixfr_fail = thr->task->ixfr_fail;
        auth_load_thread_delete(thr);
-       xfr_process_load_end_transfer(xfr, recv_item);
+       xfr_process_load_end_transfer(xfr, env, recv_item, ixfr_fail);
 }
 
 /** Attach worker to the auth load thread. */
index 47fb99cedb7c9baa5f8bf50fb207bd20cab6c980..d3f7a089fe9bc4ecd864689e604982f7b3f08d6b 100644 (file)
@@ -49,6 +49,14 @@ struct auth_xfer;
 struct module_env;
 struct auth_load_task;
 
+/**
+ * The types of notifications that the auth load thread sends around.
+ */
+enum auth_load_notification_type {
+       /** This is sent to make the auth load thread perform exit */
+       auth_load_notification_exit
+};
+
 /**
  * The auth load thread. The thread runs to load authority zone information
  * and RPZ information into memory. It loads into a copy. Then that is swapped
@@ -124,6 +132,9 @@ struct auth_load_task {
        /** Set if the transfer is an IXFR but we detected an AXFR contents */
        int on_ixfr_is_axfr;
 
+       /** Set if the ixfr failed. (So that there can be backoff to AXFR). */
+       int ixfr_fail;
+
        /** current serial (from SOA), if we have no zone, 0
         * This is for checking the IXFR result. */
        uint32_t serial;
index b5eb162b46b0ee82c86f7f8d298ccb46212737ad..02bf231d80d8161c956ef62b67dd7ada93e72189 100644 (file)
@@ -6277,6 +6277,57 @@ xfer_link_data(sldns_buffer* pkt, struct auth_xfer* xfr)
        return 1;
 }
 
+/** task transfer, process the failure to process the zone transfer.
+ * It continues with the task transfer, possibly. */
+static void
+xfr_process_transfer_failed(struct auth_xfer* xfr, struct module_env* env,
+       int ixfr_fail)
+{
+       /* processing failed */
+       if(ixfr_fail) {
+               xfr->task_transfer->ixfr_fail = 1;
+       } else {
+               xfr_transfer_nextmaster(xfr);
+       }
+       xfr_transfer_nexttarget_or_end(xfr, env);
+}
+
+/** task transfer, process the success to process the zone transfer.
+ * It continues with the task probe, possibly, due to notify. Or nextprobe. */
+static void
+xfr_process_transfer_success(struct auth_xfer* xfr, struct module_env* env)
+{
+       /* we fetched the zone, move to wait task */
+       xfr_transfer_disown(xfr);
+
+       if(xfr->notify_received && (!xfr->notify_has_serial ||
+               (xfr->notify_has_serial &&
+               xfr_serial_means_update(xfr, xfr->notify_serial)))) {
+               uint32_t sr = xfr->notify_serial;
+               int has_sr = xfr->notify_has_serial;
+               /* we received a notify while probe/transfer was
+                * in progress.  start a new probe and transfer */
+               xfr->notify_received = 0;
+               xfr->notify_has_serial = 0;
+               xfr->notify_serial = 0;
+               if(!xfr_start_probe(xfr, env, NULL)) {
+                       /* if we couldn't start it, already in
+                        * progress; restore notify serial,
+                        * while xfr still locked */
+                       xfr->notify_received = 1;
+                       xfr->notify_has_serial = has_sr;
+                       xfr->notify_serial = sr;
+                       lock_basic_unlock(&xfr->lock);
+               }
+               return;
+       } else {
+               /* pick up the nextprobe task and wait (normail wait time) */
+               if(xfr->task_nextprobe->worker == NULL)
+                       xfr_set_timeout(xfr, env, 0, 0);
+       }
+       lock_basic_unlock(&xfr->lock);
+}
+
 /** task transfer.  the list of data is complete. process it and if failed
  * move to next master, if succeeded, end the task transfer */
 static void
@@ -6288,66 +6339,31 @@ process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env)
                if(auth_load_add_task_xfr(xfr, env->worker)) {
                        /* Task is created, wait for it to be done. The worker
                         * is signalled with the result. */
+                       /* When it is done, the xfr_process_load_end_transfer
+                        * routine is called. */
                        return;
                }
        } else if(xfr_process_chunk_list(xfr, env, &ixfr_fail)) {
                /* it worked! */
                auth_chunks_delete(xfr->task_transfer);
-
-               /* we fetched the zone, move to wait task */
-               xfr_transfer_disown(xfr);
-
-               if(xfr->notify_received && (!xfr->notify_has_serial ||
-                       (xfr->notify_has_serial && 
-                       xfr_serial_means_update(xfr, xfr->notify_serial)))) {
-                       uint32_t sr = xfr->notify_serial;
-                       int has_sr = xfr->notify_has_serial;
-                       /* we received a notify while probe/transfer was
-                        * in progress.  start a new probe and transfer */
-                       xfr->notify_received = 0;
-                       xfr->notify_has_serial = 0;
-                       xfr->notify_serial = 0;
-                       if(!xfr_start_probe(xfr, env, NULL)) {
-                               /* if we couldn't start it, already in
-                                * progress; restore notify serial,
-                                * while xfr still locked */
-                               xfr->notify_received = 1;
-                               xfr->notify_has_serial = has_sr;
-                               xfr->notify_serial = sr;
-                               lock_basic_unlock(&xfr->lock);
-                       }
-                       return;
-               } else {
-                       /* pick up the nextprobe task and wait (normail wait time) */
-                       if(xfr->task_nextprobe->worker == NULL)
-                               xfr_set_timeout(xfr, env, 0, 0);
-               }
-               lock_basic_unlock(&xfr->lock);
+               xfr_process_transfer_success(xfr, env);
                return;
        }
-       /* processing failed */
        /* when done, delete data from list */
        auth_chunks_delete(xfr->task_transfer);
-       if(ixfr_fail) {
-               xfr->task_transfer->ixfr_fail = 1;
-       } else {
-               xfr_transfer_nextmaster(xfr);
-       }
-       xfr_transfer_nexttarget_or_end(xfr, env);
+       xfr_process_transfer_failed(xfr, env, ixfr_fail);
 }
 
-void xfr_process_load_end_transfer(struct auth_xfer* xfr, uint8_t status)
+void xfr_process_load_end_transfer(struct auth_xfer* xfr,
+       struct module_env* env, uint8_t status, int ixfr_fail)
 {
        if(status) {
                /* it worked! */
-               /* we fetched the zone, move to wait task */
-               xfr_transfer_disown(xfr);
-
-               lock_basic_unlock(&xfr->lock);
+               xfr_process_transfer_success(xfr, env);
                return;
        }
        /* The transfer failed */
-       lock_basic_unlock(&xfr->lock);
+       xfr_process_transfer_failed(xfr, env, ixfr_fail);
 }
 
 /** callback for the task_transfer timer */
index 7f9c116068e1080bd7b82d8dac9644a1b9590fc9..a49d9084cc0d168f75aca5177958556fc0f6e18c 100644 (file)
@@ -858,6 +858,7 @@ int chunkline_count_parens(struct sldns_buffer* buf, size_t start);
 void auth_zone_clear_data(struct auth_zone* z);
 
 /** Handle the end of an auth load task. */
-void xfr_process_load_end_transfer(struct auth_xfer* xfr, uint8_t status);
+void xfr_process_load_end_transfer(struct auth_xfer* xfr,
+       struct module_env* env, uint8_t status, int ixfr_fail);
 
 #endif /* SERVICES_AUTHZONE_H */