From: W.C.A. Wijngaards Date: Mon, 29 Jun 2026 14:52:20 +0000 (+0200) Subject: - auth-load-thread, poll for quit and process load transfer end. X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a1224904616390b37e49b7ad96cbb4655b557145;p=thirdparty%2Funbound.git - auth-load-thread, poll for quit and process load transfer end. --- diff --git a/services/authload.c b/services/authload.c index fdf2494e1..74c7d2ad7 100644 --- a/services/authload.c +++ b/services/authload.c @@ -51,6 +51,19 @@ #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. */ diff --git a/services/authload.h b/services/authload.h index 47fb99ced..d3f7a089f 100644 --- a/services/authload.h +++ b/services/authload.h @@ -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; diff --git a/services/authzone.c b/services/authzone.c index b5eb162b4..02bf231d8 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -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 */ diff --git a/services/authzone.h b/services/authzone.h index 7f9c11606..a49d9084c 100644 --- a/services/authzone.h +++ b/services/authzone.h @@ -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 */