summaryrefslogtreecommitdiffstats
path: root/src/knot/ctl/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/knot/ctl/process.c')
-rw-r--r--src/knot/ctl/process.c128
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;
+ }
+ }
+}