From 6a98ba42bd3922652cf9781b07c2f3d8a0adcaee Mon Sep 17 00:00:00 2001
From: Karel Slany <karel.slany@nic.cz>
Date: Tue, 31 May 2016 14:51:41 +0200
Subject: [PATCH] Moved cookies before iterate layer.

---
 daemon/engine.c                            |   1 +
 {modules/cookies => lib/layer}/cookies.c   | 269 +------------------
 lib/lib.mk                                 |   1 +
 lib/module.c                               |   2 +
 modules/cookies/cookies.mk                 |   5 -
 modules/cookies_control/cookies_control.c  | 290 +++++++++++++++++++++
 modules/cookies_control/cookies_control.mk |   6 +
 modules/modules.mk                         |   2 +-
 8 files changed, 305 insertions(+), 271 deletions(-)
 rename {modules/cookies => lib/layer}/cookies.c (66%)
 delete mode 100644 modules/cookies/cookies.mk
 create mode 100644 modules/cookies_control/cookies_control.c
 create mode 100644 modules/cookies_control/cookies_control.mk

diff --git a/daemon/engine.c b/daemon/engine.c
index ad852ba60..4c346aab4 100644
--- a/daemon/engine.c
+++ b/daemon/engine.c
@@ -471,6 +471,7 @@ static int init_resolver(struct engine *engine)
 	}
 
 	/* Load basic modules */
+	engine_register(engine, "cookies", NULL, NULL);
 	engine_register(engine, "iterate", NULL, NULL);
 	engine_register(engine, "validate", NULL, NULL);
 	engine_register(engine, "rrcache", NULL, NULL);
diff --git a/modules/cookies/cookies.c b/lib/layer/cookies.c
similarity index 66%
rename from modules/cookies/cookies.c
rename to lib/layer/cookies.c
index 3c972db42..829ac0dff 100644
--- a/modules/cookies/cookies.c
+++ b/lib/layer/cookies.c
@@ -25,7 +25,6 @@
 #include <libknot/rrtype/opt_cookie.h> // branch dns-cookies-wip
 #include <stdlib.h>
 #include <string.h>
-#include <time.h>
 
 #include "daemon/engine.h"
 #include "lib/cookies/cache.h"
@@ -352,10 +351,9 @@ static int check_response(knot_layer_t *ctx, knot_pkt_t *pkt)
 
 	uint16_t rcode = knot_pkt_get_ext_rcode(pkt);
 	if (rcode == KNOT_RCODE_BADCOOKIE) {
-		/* TODO -- Fall back to TCP after a limited number of retries. */
-		DEBUG_MSG(NULL, "%s'n", "falling back to TCP");
+		DEBUG_MSG(NULL, "%s\n", "falling back to TCP");
 		qry->flags |= QUERY_TCP;
-		return KNOT_STATE_PRODUCE;
+		return KNOT_STATE_CONSUME;
 	}
 
 	print_packet_dflt(pkt);
@@ -363,197 +361,7 @@ static int check_response(knot_layer_t *ctx, knot_pkt_t *pkt)
 	return ctx->state;
 }
 
-/** Find storage API with given prefix. */
-static struct storage_api *find_storage_api(const storage_registry_t *registry,
-                                            const char *prefix)
-{
-	assert(registry);
-	assert(prefix);
-
-	for (unsigned i = 0; i < registry->len; ++i) {
-		struct storage_api *storage = &registry->at[i];
-		if (strcmp(storage->prefix, "lmdb://") == 0) {
-			return storage;
-		}
-	}
-
-	return NULL;
-}
-
-#define NAME_ENABLED "enabled"
-#define NAME_CLIENT_SECRET "client_secret"
-
-static bool aply_enabled(struct cookies_control *cntrl, const JsonNode *node)
-{
-	if (node->tag == JSON_BOOL) {
-		cntrl->enabled = node->bool_;
-		return true;
-	}
-
-	return false;
-}
-
-static struct secret_quantity *new_sq_str(const JsonNode *node)
-{
-	assert(node && node->tag == JSON_STRING);
-
-	size_t len = strlen(node->string_);
-
-	struct secret_quantity *sq = malloc(sizeof(*sq) + len);
-	if (!sq) {
-		return NULL;
-	}
-	sq->size = len;
-	memcpy(sq->data, node->string_, len);
-
-	return sq;
-}
-
-#define holds_char(x) ((x) >= 0 && (x) <= 255)
-
-static struct secret_quantity *new_sq_array(const JsonNode *node)
-{
-	assert(node && node->tag == JSON_ARRAY);
-
-	const JsonNode *element = NULL;
-	size_t cnt = 0;
-	json_foreach(element, node) {
-		if (element->tag != JSON_NUMBER || !holds_char(element->number_)) {
-			return NULL;
-		}
-		++cnt;
-	}
-	if (cnt == 0) {
-		return NULL;
-	}
-
-	struct secret_quantity *sq = malloc(sizeof(*sq) + cnt);
-	if (!sq) {
-		return NULL;
-	}
-
-	sq->size = cnt;
-	cnt = 0;
-	json_foreach(element, node) {
-		sq->data[cnt++] = (uint8_t) element->number_;
-	}
-
-	return sq;
-}
-
-static bool apply_client_secret(struct cookies_control *cntrl, const JsonNode *node)
-{
-	struct secret_quantity *sq = NULL;
-
-	switch (node->tag) {
-	case JSON_STRING:
-		sq = new_sq_str(node);
-		break;
-	case JSON_ARRAY:
-		sq = new_sq_array(node);
-		break;
-	default:
-		break;
-	}
-
-	if (!sq) {
-		return false;
-	}
-
-	if (sq->size == cntrl->current_cs->size &&
-	    memcmp(sq->data, cntrl->current_cs->data, sq->size) == 0) {
-		/* Ignore same values. */
-		free(sq);
-		return true;
-	}
-
-	struct secret_quantity *tmp = cntrl->recent_cs;
-	cntrl->recent_cs = cntrl->current_cs;
-	cntrl->current_cs = sq;
-
-	if (tmp && tmp != &dflt_cs) {
-		free(tmp);
-	}
-
-	return true;
-}
-
-static bool apply_configuration(struct cookies_control *cntrl, const JsonNode *node)
-{
-	assert(cntrl && node);
-
-	if (!node->key) {
-		/* All top most nodes must have names. */
-		return false;
-	}
-
-	if (strcmp(node->key, NAME_ENABLED) == 0) {
-		return aply_enabled(cntrl, node);
-	} else if (strcmp(node->key, NAME_CLIENT_SECRET) == 0) {
-		return apply_client_secret(cntrl, node);
-	}
-
-	return false;
-}
-
-static bool read_secret(JsonNode *root, struct cookies_control *cntrl)
-{
-	assert(root && cntrl);
-
-	JsonNode *array = json_mkarray();
-	if (!array) {
-		return false;
-	}
-
-	for (size_t i = 0; i < cntrl->current_cs->size; ++i) {
-		JsonNode *element = json_mknumber(cntrl->current_cs->data[i]);
-		if (!element) {
-			goto fail;
-		}
-		json_append_element(array, element);
-	}
-
-	json_append_member(root, NAME_CLIENT_SECRET, array);
-
-	return true;
-
-fail:
-	if (array) {
-		json_delete(array);
-	}
-	return false;
-}
-
-/**
- * Get/set DNS cookie related stuff.
- *
- * Input: { name: value, ... }
- * Output: current configuration
- */
-static char *cookies_config(void *env, struct kr_module *module, const char *args)
-{
-	if (args && strlen(args) > 0) {
-		JsonNode *node;
-		JsonNode *root_node = json_decode(args);
-		json_foreach (node, root_node) {
-			apply_configuration(&kr_cookies_control, node);
-		}
-		json_delete(root_node);
-	}
-
-	/* Return current configuration. */
-	char *result = NULL;
-	JsonNode *root_node = json_mkobject();
-	json_append_member(root_node, NAME_ENABLED, json_mkbool(kr_cookies_control.enabled));
-	read_secret(root_node, &kr_cookies_control);
-	result = json_encode(root_node);
-	json_delete(root_node);
-	return result;
-}
-
-/*
- * Module implementation.
- */
+/** Module implementation. */
 
 KR_EXPORT
 const knot_layer_api_t *cookies_layer(struct kr_module *module)
@@ -566,73 +374,4 @@ const knot_layer_api_t *cookies_layer(struct kr_module *module)
 	return &_layer;
 }
 
-KR_EXPORT
-int cookies_init(struct kr_module *module)
-{
-	const char *storage_prefix = "lmdb://";
-	struct engine *engine = module->data;
-	DEBUG_MSG(NULL, "initialising with engine %p\n", (void *) engine);
-
-	memset(&kr_cookies_control, 0, sizeof(kr_cookies_control));
-
-	kr_cookies_control.enabled = false;
-
-	kr_cookies_control.current_cs = &dflt_cs;
-
-	memset(&kr_cookies_control.cache, 0, sizeof(kr_cookies_control.cache));
-
-	struct storage_api *lmdb_storage_api = find_storage_api(&engine->storage_registry,
-	                                                        storage_prefix);
-	DEBUG_MSG(NULL, "found storage API %p for prefix '%s'\n",
-	          (void *) lmdb_storage_api, storage_prefix);
-
-	struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
-	opts.path = "cookies_db";
-	//opts.dbname = "cookies";
-	opts.mapsize = 1024 * 1024 * 1024;
-	opts.maxdbs = 2;
-	opts.flags.env = 0x80000 | 0x100000; /* MDB_WRITEMAP|MDB_MAPASYNC */
-
-	errno = 0;
-	int ret = kr_cache_open(&kr_cookies_control.cache,
-	                        lmdb_storage_api->api(), &opts, engine->pool);
-	DEBUG_MSG(NULL, "cache_open retval %d: %s\n", ret, kr_strerror(ret));
-
-	module->data = NULL;
-
-	return kr_ok();
-}
-
-KR_EXPORT
-int cookies_deinit(struct kr_module *module)
-{
-	kr_cookies_control.enabled = false;
-
-	if (kr_cookies_control.recent_cs &&
-	    kr_cookies_control.recent_cs != &dflt_cs) {
-		free(kr_cookies_control.recent_cs);
-	}
-	kr_cookies_control.recent_cs = NULL;
-
-	if (kr_cookies_control.current_cs &&
-	    kr_cookies_control.current_cs != &dflt_cs) {
-		free(kr_cookies_control.current_cs);
-	}
-	kr_cookies_control.current_cs = &dflt_cs;
-
-	kr_cache_close(&kr_cookies_control.cache);
-
-	return kr_ok();
-}
-
-KR_EXPORT
-struct kr_prop *cookies_props(void)
-{
-	static struct kr_prop prop_list[] = {
-	    { &cookies_config, "config", "Empty value to return current configuration.", },
-	    { NULL, NULL, NULL }
-	};
-	return prop_list;
-}
-
-KR_MODULE_EXPORT(cookies);
+KR_MODULE_EXPORT(cookies)
diff --git a/lib/lib.mk b/lib/lib.mk
index 4dafe5c8e..60dd40fe0 100644
--- a/lib/lib.mk
+++ b/lib/lib.mk
@@ -1,6 +1,7 @@
 libkres_SOURCES := \
 	contrib/fnv/hash_64a.c \
 	lib/generic/map.c      \
+	lib/layer/cookies.c    \
 	lib/layer/iterate.c    \
 	lib/layer/validate.c   \
 	lib/layer/rrcache.c    \
diff --git a/lib/module.c b/lib/module.c
index 7c7a1398d..99c96d5fe 100644
--- a/lib/module.c
+++ b/lib/module.c
@@ -24,11 +24,13 @@
 #include "lib/module.h"
 
 /* List of embedded modules */
+const knot_layer_api_t *cookies_layer(struct kr_module *module);
 const knot_layer_api_t *iterate_layer(struct kr_module *module);
 const knot_layer_api_t *validate_layer(struct kr_module *module);
 const knot_layer_api_t *rrcache_layer(struct kr_module *module);
 const knot_layer_api_t *pktcache_layer(struct kr_module *module);
 static const struct kr_module embedded_modules[] = {
+	{ "cookies",  NULL, NULL, NULL, cookies_layer, NULL, NULL, NULL },
 	{ "iterate",  NULL, NULL, NULL, iterate_layer, NULL, NULL, NULL },
 	{ "validate", NULL, NULL, NULL, validate_layer, NULL, NULL, NULL },
 	{ "rrcache",  NULL, NULL, NULL, rrcache_layer, NULL, NULL, NULL },
diff --git a/modules/cookies/cookies.mk b/modules/cookies/cookies.mk
deleted file mode 100644
index 2960154c1..000000000
--- a/modules/cookies/cookies.mk
+++ /dev/null
@@ -1,5 +0,0 @@
-cookies_CFLAGS := -fvisibility=hidden -fPIC
-cookies_SOURCES := modules/cookies/cookies.c
-cookies_DEPEND := $(libkres)
-cookies_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
-$(call make_c_module,cookies)
diff --git a/modules/cookies_control/cookies_control.c b/modules/cookies_control/cookies_control.c
new file mode 100644
index 000000000..643e27318
--- /dev/null
+++ b/modules/cookies_control/cookies_control.c
@@ -0,0 +1,290 @@
+/*  Copyright (C) 2016 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+#include <ccan/json/json.h>
+#include <libknot/db/db_lmdb.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "daemon/engine.h"
+#include "lib/cookies/control.h"
+#include "lib/layer.h"
+
+#define DEBUG_MSG(qry, fmt...) QRDEBUG(qry, "cookies_control",  fmt)
+
+/** Find storage API with given prefix. */
+static struct storage_api *find_storage_api(const storage_registry_t *registry,
+                                            const char *prefix)
+{
+	assert(registry);
+	assert(prefix);
+
+	for (unsigned i = 0; i < registry->len; ++i) {
+		struct storage_api *storage = &registry->at[i];
+		if (strcmp(storage->prefix, "lmdb://") == 0) {
+			return storage;
+		}
+	}
+
+	return NULL;
+}
+
+#define NAME_ENABLED "enabled"
+#define NAME_CLIENT_SECRET "client_secret"
+
+static bool aply_enabled(struct cookies_control *cntrl, const JsonNode *node)
+{
+	if (node->tag == JSON_BOOL) {
+		cntrl->enabled = node->bool_;
+		return true;
+	}
+
+	return false;
+}
+
+static struct secret_quantity *new_sq_str(const JsonNode *node)
+{
+	assert(node && node->tag == JSON_STRING);
+
+	size_t len = strlen(node->string_);
+
+	struct secret_quantity *sq = malloc(sizeof(*sq) + len);
+	if (!sq) {
+		return NULL;
+	}
+	sq->size = len;
+	memcpy(sq->data, node->string_, len);
+
+	return sq;
+}
+
+#define holds_char(x) ((x) >= 0 && (x) <= 255)
+
+static struct secret_quantity *new_sq_array(const JsonNode *node)
+{
+	assert(node && node->tag == JSON_ARRAY);
+
+	const JsonNode *element = NULL;
+	size_t cnt = 0;
+	json_foreach(element, node) {
+		if (element->tag != JSON_NUMBER || !holds_char(element->number_)) {
+			return NULL;
+		}
+		++cnt;
+	}
+	if (cnt == 0) {
+		return NULL;
+	}
+
+	struct secret_quantity *sq = malloc(sizeof(*sq) + cnt);
+	if (!sq) {
+		return NULL;
+	}
+
+	sq->size = cnt;
+	cnt = 0;
+	json_foreach(element, node) {
+		sq->data[cnt++] = (uint8_t) element->number_;
+	}
+
+	return sq;
+}
+
+static bool apply_client_secret(struct cookies_control *cntrl, const JsonNode *node)
+{
+	struct secret_quantity *sq = NULL;
+
+	switch (node->tag) {
+	case JSON_STRING:
+		sq = new_sq_str(node);
+		break;
+	case JSON_ARRAY:
+		sq = new_sq_array(node);
+		break;
+	default:
+		break;
+	}
+
+	if (!sq) {
+		return false;
+	}
+
+	if (sq->size == cntrl->current_cs->size &&
+	    memcmp(sq->data, cntrl->current_cs->data, sq->size) == 0) {
+		/* Ignore same values. */
+		free(sq);
+		return true;
+	}
+
+	struct secret_quantity *tmp = cntrl->recent_cs;
+	cntrl->recent_cs = cntrl->current_cs;
+	cntrl->current_cs = sq;
+
+	if (tmp && tmp != &dflt_cs) {
+		free(tmp);
+	}
+
+	return true;
+}
+
+static bool apply_configuration(struct cookies_control *cntrl, const JsonNode *node)
+{
+	assert(cntrl && node);
+
+	if (!node->key) {
+		/* All top most nodes must have names. */
+		return false;
+	}
+
+	if (strcmp(node->key, NAME_ENABLED) == 0) {
+		return aply_enabled(cntrl, node);
+	} else if (strcmp(node->key, NAME_CLIENT_SECRET) == 0) {
+		return apply_client_secret(cntrl, node);
+	}
+
+	return false;
+}
+
+static bool read_secret(JsonNode *root, struct cookies_control *cntrl)
+{
+	assert(root && cntrl);
+
+	JsonNode *array = json_mkarray();
+	if (!array) {
+		return false;
+	}
+
+	for (size_t i = 0; i < cntrl->current_cs->size; ++i) {
+		JsonNode *element = json_mknumber(cntrl->current_cs->data[i]);
+		if (!element) {
+			goto fail;
+		}
+		json_append_element(array, element);
+	}
+
+	json_append_member(root, NAME_CLIENT_SECRET, array);
+
+	return true;
+
+fail:
+	if (array) {
+		json_delete(array);
+	}
+	return false;
+}
+
+/**
+ * Get/set DNS cookie related stuff.
+ *
+ * Input: { name: value, ... }
+ * Output: current configuration
+ */
+static char *cookies_control_config(void *env, struct kr_module *module, const char *args)
+{
+	if (args && strlen(args) > 0) {
+		JsonNode *node;
+		JsonNode *root_node = json_decode(args);
+		json_foreach (node, root_node) {
+			apply_configuration(&kr_cookies_control, node);
+		}
+		json_delete(root_node);
+	}
+
+	/* Return current configuration. */
+	char *result = NULL;
+	JsonNode *root_node = json_mkobject();
+	json_append_member(root_node, NAME_ENABLED, json_mkbool(kr_cookies_control.enabled));
+	read_secret(root_node, &kr_cookies_control);
+	result = json_encode(root_node);
+	json_delete(root_node);
+	return result;
+}
+
+/*
+ * Module implementation.
+ */
+
+KR_EXPORT
+int cookies_control_init(struct kr_module *module)
+{
+	const char *storage_prefix = "lmdb://";
+	struct engine *engine = module->data;
+	DEBUG_MSG(NULL, "initialising with engine %p\n", (void *) engine);
+
+	memset(&kr_cookies_control, 0, sizeof(kr_cookies_control));
+
+	kr_cookies_control.enabled = false;
+
+	kr_cookies_control.current_cs = &dflt_cs;
+
+	memset(&kr_cookies_control.cache, 0, sizeof(kr_cookies_control.cache));
+
+	struct storage_api *lmdb_storage_api = find_storage_api(&engine->storage_registry,
+	                                                        storage_prefix);
+	DEBUG_MSG(NULL, "found storage API %p for prefix '%s'\n",
+	          (void *) lmdb_storage_api, storage_prefix);
+
+	struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
+	opts.path = "cookies_db";
+	//opts.dbname = "cookies";
+	opts.mapsize = 1024 * 1024 * 1024;
+	opts.maxdbs = 2;
+	opts.flags.env = 0x80000 | 0x100000; /* MDB_WRITEMAP|MDB_MAPASYNC */
+
+	errno = 0;
+	int ret = kr_cache_open(&kr_cookies_control.cache,
+	                        lmdb_storage_api->api(), &opts, engine->pool);
+	DEBUG_MSG(NULL, "cache_open retval %d: %s\n", ret, kr_strerror(ret));
+
+	module->data = NULL;
+
+	return kr_ok();
+}
+
+KR_EXPORT
+int cookies_control_deinit(struct kr_module *module)
+{
+	kr_cookies_control.enabled = false;
+
+	if (kr_cookies_control.recent_cs &&
+	    kr_cookies_control.recent_cs != &dflt_cs) {
+		free(kr_cookies_control.recent_cs);
+	}
+	kr_cookies_control.recent_cs = NULL;
+
+	if (kr_cookies_control.current_cs &&
+	    kr_cookies_control.current_cs != &dflt_cs) {
+		free(kr_cookies_control.current_cs);
+	}
+	kr_cookies_control.current_cs = &dflt_cs;
+
+	kr_cache_close(&kr_cookies_control.cache);
+
+	return kr_ok();
+}
+
+KR_EXPORT
+struct kr_prop *cookies_control_props(void)
+{
+	static struct kr_prop prop_list[] = {
+	    { &cookies_control_config, "config", "Empty value to return current configuration.", },
+	    { NULL, NULL, NULL }
+	};
+	return prop_list;
+}
+
+KR_MODULE_EXPORT(cookies_control);
diff --git a/modules/cookies_control/cookies_control.mk b/modules/cookies_control/cookies_control.mk
new file mode 100644
index 000000000..8ea34e622
--- /dev/null
+++ b/modules/cookies_control/cookies_control.mk
@@ -0,0 +1,6 @@
+cookies_control_CFLAGS := -fvisibility=hidden -fPIC
+cookies_control_SOURCES := \
+	modules/cookies_control/cookies_control.c
+cookies_control_DEPEND := $(libkres)
+cookies_control_LIBS := $(contrib_TARGET) $(libkres_TARGET) $(libkres_LIBS)
+$(call make_c_module,cookies_control)
diff --git a/modules/modules.mk b/modules/modules.mk
index 331f01b1d..1bac83a1f 100644
--- a/modules/modules.mk
+++ b/modules/modules.mk
@@ -1,7 +1,7 @@
 # List of built-in modules
 modules_TARGETS := hints \
                    stats \
-                   cookies
+                   cookies_control
 
 # Memcached
 ifeq ($(HAS_libmemcached),yes)
-- 
GitLab