From fd3cfa822b54252c533b8f75d2ee335673717740 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marek=20Vavru=C5=A1a?= <marek.vavrusa@nic.cz>
Date: Fri, 8 Aug 2014 13:53:10 +0200
Subject: [PATCH] daemon: simple resolver daemon implementation

---
 Makefile.am          |  2 +-
 configure.ac         |  1 +
 daemon/Makefile.am   | 17 +++++++++
 daemon/layer/query.c | 84 ++++++++++++++++++++++++++++++++++++++++++++
 daemon/layer/query.h | 22 ++++++++++++
 daemon/main.c        | 34 ++++++++++++++++++
 daemon/worker.c      | 77 ++++++++++++++++++++++++++++++++++++++++
 daemon/worker.h      | 31 ++++++++++++++++
 knot-resolver.files  |  7 +++-
 9 files changed, 273 insertions(+), 2 deletions(-)
 create mode 100644 daemon/Makefile.am
 create mode 100644 daemon/layer/query.c
 create mode 100644 daemon/layer/query.h
 create mode 100644 daemon/main.c
 create mode 100644 daemon/worker.c
 create mode 100644 daemon/worker.h

diff --git a/Makefile.am b/Makefile.am
index 790e539c2..cff123807 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,2 +1,2 @@
 ACLOCAL_AMFLAGS = -I m4
-SUBDIRS = lib tests
+SUBDIRS = lib tests daemon
diff --git a/configure.ac b/configure.ac
index 691cfbef0..915d183b1 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,7 @@ AC_SEARCH_LIBS([knot_rrset_clear], [knot])
 # Config files
 AC_CONFIG_FILES([Makefile
 		 lib/Makefile
+		 daemon/Makefile
 		 tests/Makefile
 		 ])
 
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
new file mode 100644
index 000000000..5544b0f3e
--- /dev/null
+++ b/daemon/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = \
+	-include $(top_builddir)/config.h \
+	-I$(top_srcdir)/lib
+
+sbin_PROGRAMS = kresolved 
+
+kresolved_SOURCES =					\
+	layer/query.h					\
+	layer/query.c					\
+	worker.h						\
+	worker.c						\
+	main.c
+
+# sbin programs
+kresolved_LDADD = $(top_builddir)/lib/libknotresolve.la \
+					$(KNOT_LIBS) \
+					$(libuv_LIBS)
diff --git a/daemon/layer/query.c b/daemon/layer/query.c
new file mode 100644
index 000000000..c39fd41e3
--- /dev/null
+++ b/daemon/layer/query.c
@@ -0,0 +1,84 @@
+/* Copyright 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#include "daemon/layer/query.h"
+#include "lib/resolve.h"
+
+/* State-less single resolution iteration step, not needed. */
+static int reset(knot_process_t *ctx)  { return NS_PROC_MORE; }
+static int finish(knot_process_t *ctx) { return NS_PROC_NOOP; }
+static int begin(knot_process_t *ctx, void *module_param)
+{
+	ctx->data = module_param;
+	return NS_PROC_MORE;
+}
+
+static int input_query(knot_pkt_t *pkt, knot_process_t *ctx)
+{
+	assert(pkt && ctx);
+	struct layer_param *param = ctx->data;
+
+	/* Check if at least header is parsed. */
+	if (pkt->parsed < pkt->size) {
+		knot_pkt_free(&pkt);
+		return NS_PROC_FAIL;
+	}
+
+	/* Accept only queries. */
+	if (knot_wire_get_qr(pkt->wire)) {
+		knot_pkt_free(&pkt);
+		return NS_PROC_NOOP; /* Ignore. */
+	}
+
+	/* Prepare for query processing. */
+	int ret = kr_resolve(param->ctx, param->result,
+	                     knot_pkt_qname(pkt),
+	                     knot_pkt_qclass(pkt),
+	                     knot_pkt_qtype(pkt));
+
+	/* Set correct message ID. */
+	knot_pkt_t *answer = param->result->ans;
+	knot_wire_set_id(answer->wire, knot_wire_get_id(pkt->wire));
+
+	/* Free query and finish. */
+	knot_pkt_free(&pkt);
+
+	if (ret != 0) {
+		return NS_PROC_FAIL;
+	} else {
+		return NS_PROC_DONE;
+	}
+}
+
+static int output(knot_pkt_t *pkt, knot_process_t *ctx)
+{
+	/* \note Output is returned indirectly via resolution result. */
+	return NS_PROC_NOOP;
+}
+
+/*! \brief Module implementation. */
+static const knot_process_module_t LAYER_QUERY_MODULE = {
+	&begin,
+	&reset,
+	&finish,
+	&input_query,
+	&output,
+	&knot_process_noop  /* No error processing. */
+};
+
+const knot_process_module_t *layer_query_module(void)
+{
+	return &LAYER_QUERY_MODULE;
+}
diff --git a/daemon/layer/query.h b/daemon/layer/query.h
new file mode 100644
index 000000000..4f6c6e17b
--- /dev/null
+++ b/daemon/layer/query.h
@@ -0,0 +1,22 @@
+/* Copyright 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#pragma once
+
+#include "lib/layer.h"
+
+/* Processing module implementation. */
+const knot_process_module_t *layer_query_module(void);
+#define LAYER_QUERY layer_query_module()
diff --git a/daemon/main.c b/daemon/main.c
new file mode 100644
index 000000000..cc133b331
--- /dev/null
+++ b/daemon/main.c
@@ -0,0 +1,34 @@
+#include <uv.h>
+#include "lib/resolve.h"
+#include "worker.h"
+
+int main(void)
+{
+	mm_ctx_t mm;
+	mm_ctx_init(&mm);
+
+	uv_loop_t *loop = uv_default_loop();
+
+	/* Bind to sockets. */
+	/* TODO: list of sockets, configurable loops. */
+	uv_udp_t udp_sock;
+	memset(&udp_sock, 0, sizeof(uv_udp_t));
+	struct sockaddr_in anyaddr;
+	uv_ip4_addr("0.0.0.0", 3535, &anyaddr);
+	uv_udp_init(loop, &udp_sock);
+	uv_udp_bind(&udp_sock, (struct sockaddr *)&anyaddr, 0);
+
+	/* Start a worker. */
+	struct worker_ctx worker;
+	worker_init(&worker, &mm);
+	worker_start(&udp_sock, &worker);
+
+	/* Run the event loop. */
+	int ret = uv_run(loop, UV_RUN_DEFAULT);
+
+	/* Cleanup. */
+	worker_stop(&udp_sock);
+	worker_deinit(&worker);
+
+	return ret;
+}
diff --git a/daemon/worker.c b/daemon/worker.c
new file mode 100644
index 000000000..3cda2f2af
--- /dev/null
+++ b/daemon/worker.c
@@ -0,0 +1,77 @@
+#include <uv.h>
+
+#include <libknot/packet/pkt.h>
+#include <libknot/packet/net.h>
+
+#include "daemon/worker.h"
+#include "daemon/layer/query.h"
+
+static void worker_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf)
+{
+	struct worker_ctx *worker = handle->data;
+	buf->base = mm_alloc(worker->pool, suggested_size);
+	buf->len = suggested_size;
+}
+
+static void worker_send(uv_udp_t *handle, knot_pkt_t *answer, const struct sockaddr *addr)
+{
+	uv_buf_t sendbuf = uv_buf_init((char *)answer->wire, answer->size);
+	uv_udp_try_send(handle, &sendbuf, 1, addr);
+}
+
+static void worker_recv(uv_udp_t *handle, ssize_t nread, const uv_buf_t *buf,
+                        const struct sockaddr *addr, unsigned flags)
+{
+	struct worker_ctx *ctx = handle->data;
+	assert(ctx->pool);
+
+	if (nread < KNOT_WIRE_HEADER_SIZE) {
+		return;
+	}
+
+	struct kr_result result;
+
+	/* Create query processing context. */
+	struct layer_param param;
+	param.ctx = &ctx->resolve;
+	param.result = &result;
+
+	/* Process query packet. */
+	knot_process_t proc = {0};
+	memcpy(&proc.mm, ctx->pool, sizeof(mm_ctx_t));
+	knot_process_begin(&proc, &param, LAYER_QUERY);
+	int state = knot_process_in((uint8_t *)buf->base, nread, &proc);
+	if (state & (NS_PROC_DONE|NS_PROC_FAIL)) {
+		worker_send(handle, result.ans, addr);
+	}
+
+	/* Cleanup. */
+	knot_process_finish(&proc);
+	kr_result_deinit(&result);
+	kr_context_reset(&ctx->resolve);
+}
+
+void worker_init(struct worker_ctx *worker, mm_ctx_t *mm)
+{
+	memset(worker, 0, sizeof(struct worker_ctx));
+	worker->pool = mm;
+
+	kr_context_init(&worker->resolve, mm);
+}
+
+void worker_deinit(struct worker_ctx *worker)
+{
+	kr_context_deinit(&worker->resolve);
+}
+
+void worker_start(uv_udp_t *handle, struct worker_ctx *worker)
+{
+
+	handle->data = worker;
+	uv_udp_recv_start(handle, &worker_alloc, &worker_recv);
+}
+
+void worker_stop(uv_udp_t *handle)
+{
+	uv_udp_recv_stop(handle);
+}
diff --git a/daemon/worker.h b/daemon/worker.h
new file mode 100644
index 000000000..7312a6eda
--- /dev/null
+++ b/daemon/worker.h
@@ -0,0 +1,31 @@
+/* Copyright 2014 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+#pragma once
+
+#include <uv.h>
+
+#include <libknot/mempattern.h>
+#include "lib/resolve.h"
+
+struct worker_ctx {
+	struct kr_context resolve;
+	mm_ctx_t *pool;
+};
+
+void worker_init(struct worker_ctx *worker, mm_ctx_t *mm);
+void worker_deinit(struct worker_ctx *worker);
+void worker_start(uv_udp_t *req, struct worker_ctx *worker);
+void worker_stop(uv_udp_t *req);
diff --git a/knot-resolver.files b/knot-resolver.files
index df843b883..cfde92e6f 100644
--- a/knot-resolver.files
+++ b/knot-resolver.files
@@ -1,3 +1,8 @@
+daemon/layer/query.c
+daemon/layer/query.h
+daemon/main.c
+daemon/worker.c
+daemon/worker.h
 include/kgetdns.h
 lib/layer/iterate.c
 lib/layer/iterate.h
@@ -5,8 +10,8 @@ lib/layer/static.c
 lib/layer/static.h
 lib/context.c
 lib/context.h
+lib/layer.h
 lib/resolve.c
 lib/resolve.h
 tests/context.c
 tests/resolve.c
-lib/layer.h
-- 
GitLab