diff --git a/daemon/remote.c b/daemon/remote.c index 59cca8013..e889ca4dd 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -445,6 +445,8 @@ int ssl_print_text(SSL* ssl, const char* text) { int r; + if(!ssl) + return 0; ERR_clear_error(); if((r=SSL_write(ssl, text, (int)strlen(text))) <= 0) { if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { @@ -483,6 +485,8 @@ ssl_read_line(SSL* ssl, char* buf, size_t max) { int r; size_t len = 0; + if(!ssl) + return 0; while(len < max) { ERR_clear_error(); if((r=SSL_read(ssl, buf+len, 1)) <= 0) { @@ -1182,45 +1186,96 @@ do_flush_name(SSL* ssl, struct worker* worker, char* arg) send_ok(ssl); } +/** tell other processes to execute the command */ +void +distribute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) +{ + int i; + if(!cmd || !ssl) + return; + /* skip i=0 which is me */ + for(i=1; iworker->daemon->num; i++) { + worker_send_cmd(rc->worker->daemon->workers[i], + worker_cmd_remote); + if(!tube_write_msg(rc->worker->daemon->workers[i]->cmd, + (uint8_t*)cmd, strlen(cmd)+1, 0)) { + ssl_printf(ssl, "error could not distribute cmd\n"); + return; + } + } +} + /** execute a remote control command */ static void -execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd) +execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd, + struct worker* worker) { char* p = skipwhite(cmd); /* compare command - check longer strings first in case of substrings*/ if(strncmp(p, "stop", 4) == 0) { do_stop(ssl, rc); + return; } else if(strncmp(p, "reload", 6) == 0) { do_reload(ssl, rc); - } else if(strncmp(p, "verbosity", 9) == 0) { - do_verbosity(ssl, skipwhite(p+9)); + return; } else if(strncmp(p, "stats", 5) == 0) { do_stats(ssl, rc); - } else if(strncmp(p, "local_zone_remove", 17) == 0) { - do_zone_remove(ssl, rc->worker, skipwhite(p+17)); - } else if(strncmp(p, "local_zone", 10) == 0) { - do_zone_add(ssl, rc->worker, skipwhite(p+10)); - } else if(strncmp(p, "local_data_remove", 17) == 0) { - do_data_remove(ssl, rc->worker, skipwhite(p+17)); - } else if(strncmp(p, "local_data", 10) == 0) { - do_data_add(ssl, rc->worker, skipwhite(p+10)); + return; } else if(strncmp(p, "dump_cache", 10) == 0) { - (void)dump_cache(ssl, rc->worker); + (void)dump_cache(ssl, worker); + return; } else if(strncmp(p, "load_cache", 10) == 0) { - if(load_cache(ssl, rc->worker)) send_ok(ssl); + if(load_cache(ssl, worker)) send_ok(ssl); + return; } else if(strncmp(p, "lookup", 6) == 0) { - do_lookup(ssl, rc->worker, skipwhite(p+6)); + do_lookup(ssl, worker, skipwhite(p+6)); + return; + } + +#ifdef THREADS_DISABLED + /* other processes must execute the command as well */ + /* commands that should not be distributed, returned above. */ + if(rc) { /* only if this thread is the master (rc) thread */ + /* done before the code below, which may split the string */ + distribute_cmd(rc, ssl, cmd); + } +#endif + if(strncmp(p, "verbosity", 9) == 0) { + do_verbosity(ssl, skipwhite(p+9)); + } else if(strncmp(p, "local_zone_remove", 17) == 0) { + do_zone_remove(ssl, worker, skipwhite(p+17)); + } else if(strncmp(p, "local_zone", 10) == 0) { + do_zone_add(ssl, worker, skipwhite(p+10)); + } else if(strncmp(p, "local_data_remove", 17) == 0) { + do_data_remove(ssl, worker, skipwhite(p+17)); + } else if(strncmp(p, "local_data", 10) == 0) { + do_data_add(ssl, worker, skipwhite(p+10)); } else if(strncmp(p, "flush_zone", 10) == 0) { - do_flush_zone(ssl, rc->worker, skipwhite(p+10)); + do_flush_zone(ssl, worker, skipwhite(p+10)); } else if(strncmp(p, "flush_type", 10) == 0) { - do_flush_type(ssl, rc->worker, skipwhite(p+10)); + do_flush_type(ssl, worker, skipwhite(p+10)); } else if(strncmp(p, "flush", 5) == 0) { - do_flush_name(ssl, rc->worker, skipwhite(p+5)); + do_flush_name(ssl, worker, skipwhite(p+5)); } else { (void)ssl_printf(ssl, "error unknown command '%s'\n", p); } } +void +daemon_remote_exec(struct worker* worker) +{ + /* read the cmd string */ + uint8_t* msg = NULL; + size_t len = 0; + if(!tube_read_msg(worker->cmd, &msg, &len, 0)) { + log_err("daemon_remote_exec: tube_read_msg failed"); + return; + } + verbose(VERB_ALGO, "remote exec distributed: %s", (char*)msg); + execute_cmd(NULL, NULL, (char*)msg, worker); + free(msg); +} + /** handle remote control request */ static void handle_req(struct daemon_remote* rc, struct rc_state* s, SSL* ssl) @@ -1256,7 +1311,7 @@ handle_req(struct daemon_remote* rc, struct rc_state* s, SSL* ssl) verbose(VERB_DETAIL, "control cmd: %s", buf); /* figure out what to do */ - execute_cmd(rc, ssl, buf); + execute_cmd(rc, ssl, buf, rc->worker); } int remote_control_callback(struct comm_point* c, void* arg, int err, diff --git a/daemon/remote.h b/daemon/remote.h index ea30c803e..f47a9c62d 100644 --- a/daemon/remote.h +++ b/daemon/remote.h @@ -124,6 +124,12 @@ struct listen_port* daemon_remote_open_ports(struct config_file* cfg); int daemon_remote_open_accept(struct daemon_remote* rc, struct listen_port* ports); +/** + * Handle nonthreaded remote cmd execution. + * @param worker: this worker (the remote worker). + */ +void daemon_remote_exec(struct worker* worker); + /** handle remote control accept callbacks */ int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*); diff --git a/daemon/worker.c b/daemon/worker.c index 856b0be9a..911ad193e 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -344,6 +344,12 @@ worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg, verbose(VERB_ALGO, "got control cmd stats"); server_stats_reply(worker); break; +#ifdef THREADS_DISABLED + case worker_cmd_remote: + verbose(VERB_ALGO, "got control cmd remote"); + daemon_remote_exec(worker); + break; +#endif default: log_err("bad command %d", (int)cmd); break; diff --git a/daemon/worker.h b/daemon/worker.h index fd83b61c6..84b43980b 100644 --- a/daemon/worker.h +++ b/daemon/worker.h @@ -66,7 +66,9 @@ enum worker_commands { /** make the worker quit */ worker_cmd_quit, /** obtain statistics */ - worker_cmd_stats + worker_cmd_stats, + /** execute remote control command */ + worker_cmd_remote }; /** diff --git a/doc/Changelog b/doc/Changelog index 1be7e7132..fb882bb47 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -4,6 +4,10 @@ was using multiple processes. - iana portlist updated. - test for remote control with interprocess communication. + - created command distribution mechanism so that remote control + commands other than 'stats' work on all processes in a nonthreaded + compiled version. dump/load cache work, on the first process. + - fixup remote control local_data addition memory corruption bug. 1 December 2008: Wouter - SElinux policy files in contrib/selinux for the unbound daemon, diff --git a/services/localzone.c b/services/localzone.c index d0c7af830..354db66df 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -1233,10 +1233,11 @@ local_zones_add_RR(struct local_zones* zones, const char* rr, ldns_buffer* buf) lock_quick_unlock(&zones->lock); return 0; } + } else { + free(rr_name); } lock_rw_wrlock(&z->lock); lock_quick_unlock(&zones->lock); - free(rr_name); r = lz_enter_rr_into_zone(z, buf, rr); lock_rw_unlock(&z->lock); return r; diff --git a/testcode/fake_event.c b/testcode/fake_event.c index 3cc522ae0..47a9a271d 100644 --- a/testcode/fake_event.c +++ b/testcode/fake_event.c @@ -57,6 +57,7 @@ #include "testcode/ldns-testpkts.h" #include "util/log.h" #include +struct worker; /** Global variable: the scenario. Saved here for when event_init is done. */ static struct replay_scenario* saved_scenario = NULL; @@ -1160,4 +1161,8 @@ struct event_base* comm_base_internal(struct comm_base* ATTR_UNUSED(b)) return NULL; } +void daemon_remote_exec(struct worker* ATTR_UNUSED(worker)) +{ +} + /*********** End of Dummy routines ***********/ diff --git a/testdata/remote-threaded.tpkg b/testdata/remote-threaded.tpkg index 17947ce85..8ff01f220 100644 Binary files a/testdata/remote-threaded.tpkg and b/testdata/remote-threaded.tpkg differ