From: W.C.A. Wijngaards Date: Fri, 3 Nov 2023 16:12:44 +0000 (+0100) Subject: - fast-reload, communication sockets for information transfer. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=88a60f044c6a13166924a06a589b38636581695b;p=thirdparty%2Funbound.git - fast-reload, communication sockets for information transfer. --- diff --git a/Makefile.in b/Makefile.in index a1d98a971..2ed4d1199 100644 --- a/Makefile.in +++ b/Makefile.in @@ -962,7 +962,7 @@ fptr_wlist.lo fptr_wlist.o: $(srcdir)/util/fptr_wlist.c config.h $(srcdir)/util/ $(srcdir)/validator/val_nsec3.h $(srcdir)/validator/val_sigcrypt.h $(srcdir)/validator/val_kentry.h \ $(srcdir)/validator/val_neg.h $(srcdir)/validator/autotrust.h $(srcdir)/libunbound/libworker.h \ $(srcdir)/libunbound/context.h $(srcdir)/util/alloc.h $(srcdir)/libunbound/unbound-event.h \ - $(srcdir)/libunbound/worker.h + $(srcdir)/libunbound/worker.h $(srcdir)/daemon/remote.h locks.lo locks.o: $(srcdir)/util/locks.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h log.lo log.o: $(srcdir)/util/log.c config.h $(srcdir)/util/log.h $(srcdir)/util/locks.h $(srcdir)/sldns/sbuffer.h mini_event.lo mini_event.o: $(srcdir)/util/mini_event.c config.h $(srcdir)/util/mini_event.h $(srcdir)/util/rbtree.h \ @@ -1296,7 +1296,7 @@ remote.lo remote.o: $(srcdir)/daemon/remote.c config.h $(srcdir)/daemon/remote.h $(srcdir)/validator/val_anchor.h $(srcdir)/iterator/iterator.h $(srcdir)/services/outbound_list.h \ $(srcdir)/iterator/iter_fwd.h $(srcdir)/iterator/iter_hints.h $(srcdir)/iterator/iter_delegpt.h \ $(srcdir)/services/outside_network.h $(srcdir)/sldns/str2wire.h $(srcdir)/sldns/parseutil.h \ - $(srcdir)/sldns/wire2str.h $(srcdir)/util/locks.h + $(srcdir)/sldns/wire2str.h $(srcdir)/util/locks.h $(srcdir)/util/ub_event.h stats.lo stats.o: $(srcdir)/daemon/stats.c config.h $(srcdir)/daemon/stats.h $(srcdir)/util/timehist.h \ $(srcdir)/libunbound/unbound.h $(srcdir)/daemon/worker.h $(srcdir)/libunbound/worker.h $(srcdir)/sldns/sbuffer.h \ $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \ diff --git a/daemon/daemon.c b/daemon/daemon.c index 186ae42f2..b7d7b631b 100644 --- a/daemon/daemon.c +++ b/daemon/daemon.c @@ -842,6 +842,8 @@ daemon_cleanup(struct daemon* daemon) auth_zones_cleanup(daemon->env->auth_zones); /* key cache is cleared by module desetup during next daemon_fork() */ daemon_remote_clear(daemon->rc); + if(daemon->fast_reload_thread) + fast_reload_thread_stop(daemon->fast_reload_thread); for(i=0; inum; i++) worker_delete(daemon->workers[i]); free(daemon->workers); @@ -861,8 +863,6 @@ daemon_cleanup(struct daemon* daemon) dnsc_delete(daemon->dnscenv); daemon->dnscenv = NULL; #endif - if(daemon->fast_reload_thread) - fast_reload_thread_stop(daemon->fast_reload_thread); daemon->cfg = NULL; } diff --git a/daemon/remote.c b/daemon/remote.c index bdc4dd4f8..fdb8e1641 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -63,6 +63,7 @@ #include "util/config_file.h" #include "util/net_help.h" #include "util/module.h" +#include "util/ub_event.h" #include "services/listen_dnsport.h" #include "services/cache/rrset.h" #include "services/cache/infra.h" @@ -504,6 +505,11 @@ state_list_remove_elem(struct rc_state** list, struct comm_point* c) static void clean_point(struct daemon_remote* rc, struct rc_state* s) { + if(!s->rc) { + /* the state has been picked up and moved away */ + free(s); + return; + } state_list_remove_elem(&rc->busy_list, s->c); rc->active --; if(s->ssl) { @@ -654,11 +660,11 @@ do_reload(RES* ssl, struct worker* worker, int reuse_cache) /** do the fast_reload command */ static void -do_fast_reload(RES* ssl, struct worker* worker) +do_fast_reload(RES* ssl, struct worker* worker, struct rc_state* s) { if(!ssl_printf(ssl, "start fast_reload\n")) return; - fast_reload_thread_start(ssl, worker); + fast_reload_thread_start(ssl, worker, s); } /** do the verbosity command */ @@ -3015,7 +3021,7 @@ cmdcmp(char* p, const char* cmd, size_t len) /** execute a remote control command */ static void -execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, +execute_cmd(struct daemon_remote* rc, struct rc_state* s, RES* ssl, char* cmd, struct worker* worker) { char* p = skipwhite(cmd); @@ -3030,7 +3036,7 @@ execute_cmd(struct daemon_remote* rc, RES* ssl, char* cmd, do_reload(ssl, worker, 0); return; } else if(cmdcmp(p, "fast_reload", 11)) { - do_fast_reload(ssl, worker); + do_fast_reload(ssl, worker, s); return; } else if(cmdcmp(p, "stats_noreset", 13)) { do_stats(ssl, worker, 0); @@ -3213,7 +3219,7 @@ daemon_remote_exec(struct worker* worker) return; } verbose(VERB_ALGO, "remote exec distributed: %s", (char*)msg); - execute_cmd(NULL, NULL, (char*)msg, worker); + execute_cmd(NULL, NULL, NULL, (char*)msg, worker); free(msg); } @@ -3277,7 +3283,7 @@ handle_req(struct daemon_remote* rc, struct rc_state* s, RES* res) verbose(VERB_DETAIL, "control cmd: %s", buf); /* figure out what to do */ - execute_cmd(rc, res, buf, rc->worker); + execute_cmd(rc, s, res, buf, rc->worker); } /** handle SSL_do_handshake changes to the file descriptor to wait for later */ @@ -3374,8 +3380,8 @@ int remote_control_callback(struct comm_point* c, void* arg, int err, /** fast reload thread. the thread main function */ static void* fast_reload_thread_main(void* arg) { - struct fast_reload_thread* frio = (struct fast_reload_thread*)arg; - log_thread_set(&frio->threadnum); + struct fast_reload_thread* fast_reload_thread = (struct fast_reload_thread*)arg; + log_thread_set(&fast_reload_thread->threadnum); verbose(VERB_ALGO, "start fast reload thread"); @@ -3384,6 +3390,204 @@ static void* fast_reload_thread_main(void* arg) } #endif /* !THREADS_DISABLED */ +/** create a socketpair for bidirectional communication, false on failure */ +static int +create_socketpair(int* pair, struct ub_randstate* rand) +{ +#ifndef USE_WINSOCK + if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) { + log_err("socketpair: %s", strerror(errno)); + return 0; + } + (void)rand; +#else + struct sockaddr_in addr, baddr, accaddr, connaddr; + socklen_t baddrlen, accaddrlen, connaddrlen; + uint8_t localhost[] = {127, 0, 0, 1}; + uint8_t nonce[16], recvnonce[16]; + size_t i; + int lst; + ssize_t ret; + pair[0] = -1; + pair[1] = -1; + for(i=0; i (socklen_t)sizeof(baddr)) { + log_err("create socketpair: getsockname returned addr too big"); + sock_close(lst); + sock_close(pair[1]); + pair[1] = -1; + return 0; + } + /* the socket is blocking */ + if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) { + log_err("create socketpair: connect: %s", + sock_strerror(errno)); + sock_close(lst); + sock_close(pair[1]); + pair[1] = -1; + return 0; + } + accaddrlen = (socklen_t)sizeof(accaddr); + pair[0] = accept(lst, &accaddr, &accaddrlen); + if(pair[0] == -1) { + log_err("create socketpair: accept: %s", sock_strerror(errno)); + sock_close(lst); + sock_close(pair[1]); + pair[1] = -1; + return 0; + } + if(accaddrlen > (socklen_t)sizeof(accaddr)) { + log_err("create socketpair: accept returned addr too big"); + sock_close(lst); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + if(accaddr.sin_family != AF_INET || + memcmp(localhost, &accaddr.sin_addr, 4) != 0) { + log_err("create socketpair: accept from wrong address"); + sock_close(lst); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + connaddrlen = (socklen_t)sizeof(connaddr); + if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen) + == -1) { + log_err("create socketpair: getsockname connectedaddr: %s", + sock_strerror(errno)); + sock_close(lst); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + if(connaddrlen > (socklen_t)sizeof(connaddr)) { + log_err("create socketpair: getsockname connectedaddr returned addr too big"); + sock_close(lst); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + if(connaddr.sin_family != AF_INET || + memcmp(localhost, &connaddr.sin_addr, 4) != 0) { + log_err("create socketpair: getsockname connectedadd returned wrong address"); + sock_close(lst); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + if(accaddr.sin_port != connaddr.sin_port) { + log_err("create socketpair: accept from wrong port"); + sock_close(lst); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + sock_close(lst); + + ret = send(pair[1], nonce, sizeof(nonce), 0); + if(ret == -1) { + log_err("create socketpair: send: %s", sock_strerror(errno)); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } else if(ret != sizeof(nonce)) { + log_err("create socketpair: send was truncated"); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + + ret = recv(pair[0], recvnonce, sizeof(nonce), 0); + if(ret == -1) { + log_err("create socketpair: recv: %s", sock_strerror(errno)); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } else if(ret == 0) { + log_err("create socketpair: stream closed"); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + if(ret != sizeof(nonce)) { + log_err("create socketpair: recv did not read all nonce bytes"); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } + if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) { + log_err("create socketpair: recv wrong nonce"); + sock_close(pair[0]); + sock_close(pair[1]); + pair[0] = -1; + pair[1] = -1; + return 0; + } +#endif + return 1; +} + /** fast reload thread. setup the thread info */ static int fast_reload_thread_setup(struct worker* worker) @@ -3396,6 +3600,14 @@ fast_reload_thread_setup(struct worker* worker) /* The thread id printed in logs, numworker+1 is the dnstap thread. * This is numworkers+2. */ worker->daemon->fast_reload_thread->threadnum = numworkers+2; + worker->daemon->fast_reload_thread->commpair[0] = -1; + worker->daemon->fast_reload_thread->commpair[1] = -1; + if(!create_socketpair(worker->daemon->fast_reload_thread->commpair, + worker->daemon->rand)) { + free(worker->daemon->fast_reload_thread); + return 0; + } + worker->daemon->fast_reload_thread->worker = worker; return 1; } @@ -3405,11 +3617,44 @@ fast_reload_thread_desetup(struct fast_reload_thread* fast_reload_thread) { if(!fast_reload_thread) return; + if(fast_reload_thread->service_event && + fast_reload_thread->service_event_is_added) { + ub_event_del(fast_reload_thread->service_event); + fast_reload_thread->service_event_is_added = 0; + } + if(fast_reload_thread->service_event) + ub_event_free(fast_reload_thread->service_event); + sock_close(fast_reload_thread->commpair[0]); + sock_close(fast_reload_thread->commpair[1]); + if(fast_reload_thread->remote.ssl) { + SSL_shutdown(fast_reload_thread->remote.ssl); + SSL_free(fast_reload_thread->remote.ssl); + } + comm_point_delete(fast_reload_thread->client_cp); free(fast_reload_thread); } +void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits), + void* arg) +{ + struct fast_reload_thread* fast_reload_thread = + (struct fast_reload_thread*)arg; + (void)fast_reload_thread; +} + +int fast_reload_client_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* ATTR_UNUSED(rep)) +{ + struct fast_reload_thread* fast_reload_thread = + (struct fast_reload_thread*)arg; + (void)c; + (void)err; + (void)fast_reload_thread; + return 0; +} + void -fast_reload_thread_start(RES* ssl, struct worker* worker) +fast_reload_thread_start(RES* ssl, struct worker* worker, struct rc_state* s) { if(worker->daemon->fast_reload_thread) { log_err("fast reload thread already running"); @@ -3420,8 +3665,43 @@ fast_reload_thread_start(RES* ssl, struct worker* worker) return; return; } + worker->daemon->fast_reload_thread->remote = *ssl; worker->daemon->fast_reload_thread->started = 1; + #ifndef THREADS_DISABLED + /* Setup command listener in remote servicing thread */ + worker->daemon->fast_reload_thread->service_event = ub_event_new( + comm_base_internal(worker->base), + worker->daemon->fast_reload_thread->commpair[0], + UB_EV_READ | UB_EV_PERSIST, fast_reload_service_cb, + worker->daemon->fast_reload_thread); + if(!worker->daemon->fast_reload_thread->service_event) { + if(!ssl_printf(ssl, "error out of memory\n")) + return; + return; + } + if(ub_event_add(worker->daemon->fast_reload_thread->service_event, + NULL) != 0) { + if(!ssl_printf(ssl, "error out of memory adding service event\n")) + return; + return; + } + worker->daemon->fast_reload_thread->service_event_is_added = 1; + + /* Setup the comm point to the remote control client as an event + * on the remote servicing thread, which it already is. + * It needs a new callback to service it. */ + log_assert(s); + state_list_remove_elem(&s->rc->busy_list, s->c); + s->rc->active --; + worker->daemon->fast_reload_thread->client_cp = s->c; + worker->daemon->fast_reload_thread->client_cp->callback = + fast_reload_client_callback; + worker->daemon->fast_reload_thread->client_cp->cb_arg = + worker->daemon->fast_reload_thread; + s->rc = NULL; /* move away the rc state */ + + /* Start fast reload thread */ ub_thread_create(&worker->daemon->fast_reload_thread->tid, fast_reload_thread_main, worker->daemon->fast_reload_thread); #else diff --git a/daemon/remote.h b/daemon/remote.h index cb80d4e84..c257916a3 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -126,12 +126,26 @@ struct fast_reload_thread { /** the thread number for the dtio thread, * must be first to cast thread arg to int* in checklock code. */ int threadnum; - /** event base, for event handling */ - void* event_base; + /** communication socket pair, that sends commands */ + int commpair[2]; /** thread id, of the io thread */ ub_thread_type tid; /** if the io processing has started */ int started; + + /** the event that listens on the remote service worker to the + * commpair, it receives content from the fast reload thread. */ + void* service_event; + /** if the event that listens on the remote service worker has + * been added to the comm base. */ + int service_event_is_added; + /** the remote control connection to print output to. */ + struct remote_stream remote; + /** the worker that the service_event is added in */ + struct worker* worker; + /** the comm point for the client connection, the remote control + * client. */ + struct comm_point* client_cp; }; /** @@ -223,8 +237,12 @@ int ssl_read_line(RES* ssl, char* buf, size_t max); * Start fast reload thread * @param ssl: the RES connection to print to. * @param worker: the remote servicing worker. + * @param s: the rc_state that is servicing the remote control connection to + * the remote control client. It needs to be moved away to stay connected + * while the fast reload is running. */ -void fast_reload_thread_start(RES* ssl, struct worker* worker); +void fast_reload_thread_start(RES* ssl, struct worker* worker, + struct rc_state* s); /** * Stop fast reload thread @@ -232,4 +250,11 @@ void fast_reload_thread_start(RES* ssl, struct worker* worker); */ void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread); +/** fast reload thread commands to remote service thread event callback */ +void fast_reload_service_cb(int fd, short bits, void* arg); + +/** fast reload callback for the remote control client connection */ +int fast_reload_client_callback(struct comm_point* c, void* arg, int err, + struct comm_reply* rep); + #endif /* DAEMON_REMOTE_H */ diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 0e1c40393..412293f9a 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -1072,3 +1072,17 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), log_assert(0); } #endif + +void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), + void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + +int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(repinfo)) +{ + log_assert(0); + return 0; +} diff --git a/smallapp/worker_cb.c b/smallapp/worker_cb.c index c68981735..5987e7622 100644 --- a/smallapp/worker_cb.c +++ b/smallapp/worker_cb.c @@ -255,3 +255,17 @@ void dtio_mainfdcallback(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), log_assert(0); } #endif + +void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), + void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + +int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(repinfo)) +{ + log_assert(0); + return 0; +} diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 13970c377..45911fe29 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -1906,4 +1906,24 @@ void http2_stream_add_meshstate(struct http2_stream* ATTR_UNUSED(h2_stream), { } +void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), + void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + +void fast_reload_thread_stop( + struct fast_reload_thread* ATTR_UNUSED(fast_reload_thread)) +{ + /* nothing */ +} + +int fast_reload_client_callback(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(repinfo)) +{ + log_assert(0); + return 0; +} + /*********** End of Dummy routines ***********/ diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index 43d38dc37..2a2b89dba 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -73,6 +73,7 @@ #include "libunbound/worker.h" #include "util/tube.h" #include "util/config_file.h" +#include "daemon/remote.h" #ifdef UB_ON_WINDOWS #include "winrc/win_svc.h" #endif @@ -120,6 +121,7 @@ fptr_whitelist_comm_point_raw(comm_point_callback_type *fptr) else if(fptr == &tube_handle_write) return 1; else if(fptr == &remote_accept_callback) return 1; else if(fptr == &remote_control_callback) return 1; + else if(fptr == &fast_reload_client_callback) return 1; return 0; } @@ -180,6 +182,7 @@ fptr_whitelist_event(void (*fptr)(int, short, void *)) else if(fptr == &tube_handle_signal) return 1; else if(fptr == &comm_base_handle_slow_accept) return 1; else if(fptr == &comm_point_http_handle_callback) return 1; + else if(fptr == &fast_reload_service_cb) return 1; #ifdef USE_DNSTAP else if(fptr == &dtio_output_cb) return 1; else if(fptr == &dtio_cmd_cb) return 1;