diff options
Diffstat (limited to 'src/knot/ctl/process.c')
-rw-r--r-- | src/knot/ctl/process.c | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/knot/ctl/process.c b/src/knot/ctl/process.c new file mode 100644 index 0000000..50fde21 --- /dev/null +++ b/src/knot/ctl/process.c @@ -0,0 +1,128 @@ +/* Copyright (C) 2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "knot/common/log.h" +#include "knot/ctl/commands.h" +#include "knot/ctl/process.h" +#include "libknot/error.h" +#include "contrib/string.h" + +int ctl_process(knot_ctl_t *ctl, server_t *server) +{ + if (ctl == NULL || server == NULL) { + return KNOT_EINVAL; + } + + ctl_args_t args = { + .ctl = ctl, + .type = KNOT_CTL_TYPE_END, + .server = server + }; + + // Strip redundant/unprocessed data units in the current block. + bool strip = false; + + while (true) { + // Receive data unit. + int ret = knot_ctl_receive(args.ctl, &args.type, &args.data); + if (ret != KNOT_EOK) { + log_ctl_debug("control, failed to receive (%s)", + knot_strerror(ret)); + return ret; + } + + // Decide what to do. + switch (args.type) { + case KNOT_CTL_TYPE_DATA: + // Leading data unit with a command name. + if (!strip) { + // Set to strip unprocessed data unit. + strip = true; + break; + } + // FALLTHROUGH + case KNOT_CTL_TYPE_EXTRA: + // All non-first data units should be parsed in a callback. + // Ignore if probable previous error. + continue; + case KNOT_CTL_TYPE_BLOCK: + strip = false; + continue; + case KNOT_CTL_TYPE_END: + return KNOT_EOF; + default: + assert(0); + } + + strtolower((char *)args.data[KNOT_CTL_IDX_ZONE]); + + const char *cmd_name = args.data[KNOT_CTL_IDX_CMD]; + const char *zone_name = args.data[KNOT_CTL_IDX_ZONE]; + + ctl_cmd_t cmd = ctl_str_to_cmd(cmd_name); + if (cmd == CTL_CONF_LIST) { + log_ctl_debug("control, received command '%s'", cmd_name); + } else if (cmd != CTL_NONE) { + if (zone_name != NULL) { + log_ctl_zone_str_info(zone_name, + "control, received command '%s'", cmd_name); + } else { + log_ctl_info("control, received command '%s'", cmd_name); + } + } else if (cmd_name != NULL){ + log_ctl_debug("control, invalid command '%s'", cmd_name); + continue; + } else { + log_ctl_debug("control, empty command"); + continue; + } + + // Execute the command. + int cmd_ret = ctl_exec(cmd, &args); + switch (cmd_ret) { + case KNOT_EOK: + strip = false; + case KNOT_CTL_ESTOP: + case KNOT_CTL_EZONE: + // KNOT_CTL_EZONE - don't change strip, but don't be reported + // as a ctl/communication error either. + break; + default: + log_ctl_debug("control, command '%s' (%s)", cmd_name, + knot_strerror(cmd_ret)); + break; + } + + // Finalize the answer block. + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_BLOCK, NULL); + if (ret != KNOT_EOK) { + log_ctl_debug("control, failed to reply (%s)", + knot_strerror(ret)); + } + + // Stop if required. + if (cmd_ret == KNOT_CTL_ESTOP) { + // Finalize the answer message. + ret = knot_ctl_send(ctl, KNOT_CTL_TYPE_END, NULL); + if (ret != KNOT_EOK) { + log_ctl_debug("control, failed to reply (%s)", + knot_strerror(ret)); + } + + return cmd_ret; + } + } +} |