/** @internal return cache, or throw lua error if not open */
static struct kr_cache * cache_assert_open(lua_State *L)
{
- struct kr_cache *cache = &the_worker->engine->resolver.cache;
+ struct kr_cache *cache = &the_resolver->cache;
if (kr_fails_assert(cache) || !kr_cache_is_open(cache))
lua_error_p(L, "no cache is open yet, use cache.open() or cache.size, etc.");
return cache;
/** Return available cached backends. */
static int cache_backends(lua_State *L)
{
- struct engine *engine = the_worker->engine;
-
lua_newtable(L);
- for (unsigned i = 0; i < engine->backends.len; ++i) {
- const struct kr_cdb_api *api = engine->backends.at[i];
- lua_pushboolean(L, api == engine->resolver.cache.api);
+ for (unsigned i = 0; i < the_engine->backends.len; ++i) {
+ const struct kr_cdb_api *api = the_engine->backends.at[i];
+ lua_pushboolean(L, api == the_resolver->cache.api);
lua_setfield(L, -2, api->name);
}
return 1;
return 1;
}
-static const struct kr_cdb_api *cache_select(struct engine *engine, const char **conf)
+static const struct kr_cdb_api *cache_select(const char **conf)
{
/* Return default backend */
if (*conf == NULL || !strstr(*conf, "://")) {
- return engine->backends.at[0];
+ return the_engine->backends.at[0];
}
/* Find storage backend from config prefix */
- for (unsigned i = 0; i < engine->backends.len; ++i) {
- const struct kr_cdb_api *api = engine->backends.at[i];
+ for (unsigned i = 0; i < the_engine->backends.len; ++i) {
+ const struct kr_cdb_api *api = the_engine->backends.at[i];
if (strncmp(*conf, api->name, strlen(api->name)) == 0) {
*conf += strlen(api->name) + strlen("://");
return api;
lua_error_p(L, "expected 'open(number max_size, string config = \"\")'");
/* Select cache storage backend */
- struct engine *engine = the_worker->engine;
-
lua_Integer csize_lua = lua_tointeger(L, 1);
if (!(csize_lua >= 8192 && csize_lua < SIZE_MAX)) { /* min. is basically arbitrary */
lua_error_p(L, "invalid cache size specified, it must be in range <8192, "
const char *conf = n > 1 ? lua_tostring(L, 2) : NULL;
const char *uri = conf;
- const struct kr_cdb_api *api = cache_select(engine, &conf);
+ const struct kr_cdb_api *api = cache_select(&conf);
if (!api)
lua_error_p(L, "unsupported cache backend");
/* Close if already open */
- kr_cache_close(&engine->resolver.cache);
+ kr_cache_close(&the_resolver->cache);
/* Reopen cache */
struct kr_cdb_opts opts = {
(conf && strlen(conf)) ? conf : ".",
cache_size
};
- int ret = kr_cache_open(&engine->resolver.cache, api, &opts, engine->pool);
+ int ret = kr_cache_open(&the_resolver->cache, api, &opts, &the_engine->pool);
if (ret != 0) {
char cwd[PATH_MAX];
get_workdir(cwd, sizeof(cwd));
}
/* Let's check_health() every five seconds to avoid keeping old cache alive
* even in case of not having any work to do. */
- ret = kr_cache_check_health(&engine->resolver.cache, 5000);
+ ret = kr_cache_check_health(&the_resolver->cache, 5000);
if (ret != 0) {
kr_log_error(CACHE, "periodic health check failed (ignored): %s\n",
kr_strerror(ret));
static int cache_close(lua_State *L)
{
- struct kr_cache *cache = &the_worker->engine->resolver.cache;
+ struct kr_cache *cache = &the_resolver->cache;
if (!kr_cache_is_open(cache)) {
return 0;
}
lua_error_maybe(L, ret);
/* Clear reputation tables */
- struct kr_context *ctx = &the_worker->engine->resolver;
- lru_reset(ctx->cache_cookie);
+ lru_reset(the_resolver->cache_cookie);
lua_pushboolean(L, true);
return 1;
}
* in NS elections again. */
static int cache_ns_tout(lua_State *L)
{
- struct kr_context *ctx = &the_worker->engine->resolver;
-
/* Check parameters */
int n = lua_gettop(L);
if (n < 1) {
- lua_pushinteger(L, ctx->cache_rtt_tout_retry_interval);
+ lua_pushinteger(L, the_resolver->cache_rtt_tout_retry_interval);
return 1;
}
STR(UINT_MAX));
}
- ctx->cache_rtt_tout_retry_interval = interval_lua;
- lua_pushinteger(L, ctx->cache_rtt_tout_retry_interval);
+ the_resolver->cache_rtt_tout_retry_interval = interval_lua;
+ lua_pushinteger(L, the_resolver->cache_rtt_tout_retry_interval);
return 1;
}
static void event_free(uv_timer_t *timer)
{
- lua_State *L = the_worker->engine->L;
+ lua_State *L = the_engine->L;
int ref = (intptr_t) timer->data;
luaL_unref(L, LUA_REGISTRYINDEX, ref);
free(timer);
static void event_callback(uv_timer_t *timer)
{
- lua_State *L = the_worker->engine->L;
+ lua_State *L = the_engine->L;
/* Retrieve callback and execute */
lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) timer->data);
static void event_fdcallback(uv_poll_t* handle, int status, int events)
{
- lua_State *L = the_worker->engine->L;
+ lua_State *L = the_engine->L;
/* Retrieve callback and execute */
lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) handle->data);
/** List loaded modules */
static int mod_list(lua_State *L)
{
- const module_array_t * const modules = &the_worker->engine->modules;
+ const module_array_t * const modules = engine_modules();
lua_newtable(L);
for (unsigned i = 0; i < modules->len; ++i) {
struct kr_module *module = modules->at[i];
const char *precedence = strtok(NULL, " ");
const char *ref = strtok(NULL, " ");
/* Load engine module */
- int ret = engine_register(the_worker->engine, name, precedence, ref);
+ int ret = engine_register(name, precedence, ref);
free(declaration);
if (ret != 0) {
if (ret == kr_error(EIDRM)) {
if (n != 1 || !lua_isstring(L, 1))
lua_error_p(L, "expected 'unload(string name)'");
/* Unload engine module */
- int ret = engine_unregister(the_worker->engine, lua_tostring(L, 1));
+ int ret = engine_unregister(lua_tostring(L, 1));
lua_error_maybe(L, ret);
lua_pushboolean(L, 1);
{
lua_newtable(L);
lua_pushinteger(L, 1);
- trie_apply_with_key(the_worker->engine->net.endpoints, net_list_add, L);
+ trie_apply_with_key(the_network->endpoints, net_list_add, L);
lua_pop(L, 1);
return 1;
}
/* Case: string, representing a single address. */
const char *str = lua_tostring(L, -1);
if (str != NULL) {
- struct network *net = &the_worker->engine->net;
const bool is_unix = str[0] == '/';
int ret = 0;
if (!flags.kind && !flags.tls) { /* normal UDP or XDP */
flags.sock_type = SOCK_DGRAM;
- ret = network_listen(net, str, port, nic_queue, flags);
+ ret = network_listen(str, port, nic_queue, flags);
}
if (!flags.kind && !flags.xdp && ret == 0) { /* common for TCP, DoT and DoH (v2) */
flags.sock_type = SOCK_STREAM;
- ret = network_listen(net, str, port, nic_queue, flags);
+ ret = network_listen(str, port, nic_queue, flags);
}
if (flags.kind) {
flags.kind = strdup(flags.kind);
flags.sock_type = SOCK_STREAM; /* TODO: allow to override this? */
- ret = network_listen(net, str, (is_unix ? 0 : port), nic_queue, flags);
+ ret = network_listen(str, (is_unix ? 0 : port), nic_queue, flags);
}
if (ret == 0) return true; /* success */
/** Allow PROXYv2 headers for IP address. */
static int net_proxy_allowed(lua_State *L)
{
- struct network *net = &the_worker->engine->net;
int n = lua_gettop(L);
int i = 1;
const char *addr;
lua_newtable(L);
i = 1;
- if (net->proxy_all4) {
+ if (the_network->proxy_all4) {
lua_pushinteger(L, i);
lua_pushstring(L, "0.0.0.0/0");
lua_settable(L, -3);
i += 1;
} else {
- net_proxy_addr_put(L, AF_INET, net->proxy_addrs4, &i);
+ net_proxy_addr_put(L, AF_INET, the_network->proxy_addrs4, &i);
}
- if (net->proxy_all6) {
+ if (the_network->proxy_all6) {
lua_pushinteger(L, i);
lua_pushstring(L, "::/0");
lua_settable(L, -3);
i += 1;
} else {
- net_proxy_addr_put(L, AF_INET6, net->proxy_addrs6, &i);
+ net_proxy_addr_put(L, AF_INET6, the_network->proxy_addrs6, &i);
}
return 1;
lua_error_p(L, "net.proxy_allowed() argument must be string or table");
/* Reset allowed proxy addresses */
- network_proxy_reset(net);
+ network_proxy_reset();
/* Add new proxy addresses */
if (lua_istable(L, 1)) {
if (!lua_isstring(L, -1))
lua_error_p(L, "net.proxy_allowed() argument may only contain strings");
addr = lua_tostring(L, -1);
- int ret = network_proxy_allow(net, addr);
+ int ret = network_proxy_allow(addr);
if (ret)
lua_error_p(L, "invalid argument");
}
} else if (lua_isstring(L, 1)) {
addr = lua_tostring(L, 1);
- int ret = network_proxy_allow(net, addr);
+ int ret = network_proxy_allow(addr);
if (ret)
lua_error_p(L, "invalid argument");
}
if (!ok)
lua_error_p(L, "expected 'close(string addr, [number port])'");
- int ret = network_close(&the_worker->engine->net, addr, port);
+ int ret = network_close(addr, port);
lua_pushboolean(L, ret == 0);
return 1;
}
/** Set UDP maximum payload size. */
static int net_bufsize(lua_State *L)
{
- struct kr_context *ctx = &the_worker->engine->resolver;
const int argc = lua_gettop(L);
if (argc == 0) {
- lua_pushinteger(L, knot_edns_get_payload(ctx->downstream_opt_rr));
- lua_pushinteger(L, knot_edns_get_payload(ctx->upstream_opt_rr));
+ lua_pushinteger(L, knot_edns_get_payload(the_resolver->downstream_opt_rr));
+ lua_pushinteger(L, knot_edns_get_payload(the_resolver->upstream_opt_rr));
return 2;
}
int bufsize = lua_tointeger(L, 1);
if (bufsize < 512 || bufsize > UINT16_MAX)
lua_error_p(L, "bufsize must be within <512, " STR(UINT16_MAX) ">");
- knot_edns_set_payload(ctx->downstream_opt_rr, (uint16_t)bufsize);
- knot_edns_set_payload(ctx->upstream_opt_rr, (uint16_t)bufsize);
+ knot_edns_set_payload(the_resolver->downstream_opt_rr, (uint16_t)bufsize);
+ knot_edns_set_payload(the_resolver->upstream_opt_rr, (uint16_t)bufsize);
} else if (argc == 2) {
int bufsize_downstream = lua_tointeger(L, 1);
int bufsize_upstream = lua_tointeger(L, 2);
|| bufsize_downstream > UINT16_MAX || bufsize_upstream > UINT16_MAX) {
lua_error_p(L, "bufsize must be within <512, " STR(UINT16_MAX) ">");
}
- knot_edns_set_payload(ctx->downstream_opt_rr, (uint16_t)bufsize_downstream);
- knot_edns_set_payload(ctx->upstream_opt_rr, (uint16_t)bufsize_upstream);
+ knot_edns_set_payload(the_resolver->downstream_opt_rr, (uint16_t)bufsize_downstream);
+ knot_edns_set_payload(the_resolver->upstream_opt_rr, (uint16_t)bufsize_upstream);
}
return 0;
}
/** Set TCP pipelining size. */
static int net_pipeline(lua_State *L)
{
- struct worker_ctx *worker = the_worker;
- if (!worker) {
+ if (!the_worker) {
return 0;
}
if (!lua_isnumber(L, 1)) {
- lua_pushinteger(L, worker->tcp_pipeline_max);
+ lua_pushinteger(L, the_worker->tcp_pipeline_max);
return 1;
}
int len = lua_tointeger(L, 1);
if (len < 0 || len > UINT16_MAX)
lua_error_p(L, "tcp_pipeline must be within <0, " STR(UINT16_MAX) ">");
- worker->tcp_pipeline_max = len;
+ the_worker->tcp_pipeline_max = len;
lua_pushinteger(L, len);
return 1;
}
static int net_tls(lua_State *L)
{
- struct network *net = &the_worker->engine->net;
- if (!net) {
+ if (kr_fails_assert(the_network)) {
return 0;
}
/* Only return current credentials. */
if (lua_gettop(L) == 0) {
/* No credentials configured yet. */
- if (!net->tls_credentials) {
+ if (!the_network->tls_credentials) {
return 0;
}
lua_newtable(L);
- lua_pushstring(L, net->tls_credentials->tls_cert);
+ lua_pushstring(L, the_network->tls_credentials->tls_cert);
lua_setfield(L, -2, "cert_file");
- lua_pushstring(L, net->tls_credentials->tls_key);
+ lua_pushstring(L, the_network->tls_credentials->tls_key);
lua_setfield(L, -2, "key_file");
return 1;
}
if ((lua_gettop(L) != 2) || !lua_isstring(L, 1) || !lua_isstring(L, 2))
lua_error_p(L, "net.tls takes two parameters: (\"cert_file\", \"key_file\")");
- int r = tls_certificate_set(net, lua_tostring(L, 1), lua_tostring(L, 2));
+ int r = tls_certificate_set(lua_tostring(L, 1), lua_tostring(L, 2));
lua_error_maybe(L, r);
lua_pushboolean(L, true);
/* TODO idea: allow starting the lua table with *multiple* IP targets,
* meaning the authentication config should be applied to each.
*/
- struct network *net = &the_worker->engine->net;
if (lua_gettop(L) == 0)
- return tls_params2lua(L, net->tls_client_params);
+ return tls_params2lua(L, the_network->tls_client_params);
/* Various basic sanity-checking. */
if (lua_gettop(L) != 1 || !lua_istable(L, 1))
lua_error_maybe(L, EINVAL);
if (!addr)
lua_error_p(L, "address '%s' could not be converted", addr_str);
tls_client_param_t **oldcfgp = tls_client_param_getptr(
- &net->tls_client_params, addr, true);
+ &the_network->tls_client_params, addr, true);
free_const(addr);
if (!oldcfgp)
lua_error_p(L, "internal error when extending tls_client_params map");
if (!addr)
lua_error_p(L, "invalid IP address");
/* Do the actual removal. */
- struct network *net = &the_worker->engine->net;
- int r = tls_client_param_remove(net->tls_client_params, addr);
+ int r = tls_client_param_remove(the_network->tls_client_params, addr);
free_const(addr);
lua_error_maybe(L, r);
lua_pushboolean(L, true);
static int net_tls_padding(lua_State *L)
{
- struct kr_context *ctx = &the_worker->engine->resolver;
-
/* Only return current padding. */
if (lua_gettop(L) == 0) {
- if (ctx->tls_padding < 0) {
+ if (the_resolver->tls_padding < 0) {
lua_pushboolean(L, true);
return 1;
- } else if (ctx->tls_padding == 0) {
+ } else if (the_resolver->tls_padding == 0) {
lua_pushboolean(L, false);
return 1;
}
- lua_pushinteger(L, ctx->tls_padding);
+ lua_pushinteger(L, the_resolver->tls_padding);
return 1;
}
if (lua_isboolean(L, 1)) {
bool x = lua_toboolean(L, 1);
if (x) {
- ctx->tls_padding = -1;
+ the_resolver->tls_padding = -1;
} else {
- ctx->tls_padding = 0;
+ the_resolver->tls_padding = 0;
}
} else if (lua_isnumber(L, 1)) {
int padding = lua_tointeger(L, 1);
if ((padding < 0) || (padding > MAX_TLS_PADDING))
lua_error_p(L, "%s", errstr);
- ctx->tls_padding = padding;
+ the_resolver->tls_padding = padding;
} else {
lua_error_p(L, "%s", errstr);
}
static int net_tls_sticket_secret_string(lua_State *L)
{
- struct network *net = &the_worker->engine->net;
-
size_t secret_len;
const char *secret;
}
}
- tls_session_ticket_ctx_destroy(net->tls_session_ticket_ctx);
- net->tls_session_ticket_ctx =
- tls_session_ticket_ctx_create(net->loop, secret, secret_len);
- if (net->tls_session_ticket_ctx == NULL) {
+ tls_session_ticket_ctx_destroy(the_network->tls_session_ticket_ctx);
+ the_network->tls_session_ticket_ctx =
+ tls_session_ticket_ctx_create(the_network->loop, secret, secret_len);
+ if (the_network->tls_session_ticket_ctx == NULL) {
lua_error_p(L,
"net.tls_sticket_secret_string - can't create session ticket context");
}
}
fclose(fp);
- struct network *net = &the_worker->engine->net;
-
- tls_session_ticket_ctx_destroy(net->tls_session_ticket_ctx);
- net->tls_session_ticket_ctx =
- tls_session_ticket_ctx_create(net->loop, secret_buf, secret_len);
- if (net->tls_session_ticket_ctx == NULL) {
+ tls_session_ticket_ctx_destroy(the_network->tls_session_ticket_ctx);
+ the_network->tls_session_ticket_ctx =
+ tls_session_ticket_ctx_create(the_network->loop, secret_buf, secret_len);
+ if (the_network->tls_session_ticket_ctx == NULL) {
lua_error_p(L,
"net.tls_sticket_secret_file - can't create session ticket context");
}
static int net_tcp_in_idle(lua_State *L)
{
- struct network *net = &the_worker->engine->net;
- return net_update_timeout(L, &net->tcp.in_idle_timeout, "net.tcp_in_idle");
+ return net_update_timeout(L, &the_network->tcp.in_idle_timeout, "net.tcp_in_idle");
}
static int net_tls_handshake_timeout(lua_State *L)
{
- struct network *net = &the_worker->engine->net;
- return net_update_timeout(L, &net->tcp.tls_handshake_timeout, "net.tls_handshake_timeout");
+ return net_update_timeout(L, &the_network->tcp.tls_handshake_timeout, "net.tls_handshake_timeout");
}
static int net_bpf_set(lua_State *L)
}
lua_pop(L, 1);
- if (network_set_bpf(&the_worker->engine->net, progfd) == 0) {
+ if (network_set_bpf(progfd) == 0) {
lua_error_p(L, "failed to attach BPF program to some networks: %s",
kr_strerror(errno));
}
#if __linux__
- network_clear_bpf(&the_worker->engine->net);
+ network_clear_bpf();
lua_pushboolean(L, 1);
return 1;
}
size_t kind_len;
const char *kind = lua_tolstring(L, 1, &kind_len);
- struct network *net = &the_worker->engine->net;
/* Unregistering */
if (param_count == 1) {
void *val;
- if (trie_del(net->endpoint_kinds, kind, kind_len, &val) == KNOT_EOK) {
+ if (trie_del(the_network->endpoint_kinds, kind, kind_len, &val) == KNOT_EOK) {
const int fun_id = (char *)val - (char *)NULL;
luaL_unref(L, LUA_REGISTRYINDEX, fun_id);
return 0;
}
const int fun_id = luaL_ref(L, LUA_REGISTRYINDEX);
/* ^^ The function is on top of the stack, incidentally. */
- void **pp = trie_get_ins(net->endpoint_kinds, kind, kind_len);
+ void **pp = trie_get_ins(the_network->endpoint_kinds, kind, kind_len);
if (!pp) lua_error_maybe(L, kr_error(ENOMEM));
if (*pp != NULL || !strcasecmp(kind, "dns") || !strcasecmp(kind, "tls"))
lua_error_p(L, "attempt to register known kind '%s'\n", kind);
/** Return worker statistics. */
static int wrk_stats(lua_State *L)
{
- struct worker_ctx *worker = the_worker;
- if (!worker) {
+ if (kr_fails_assert(the_worker)) {
return 0;
}
lua_newtable(L);
- lua_pushnumber(L, worker->stats.queries);
+ lua_pushnumber(L, the_worker->stats.queries);
lua_setfield(L, -2, "queries");
- lua_pushnumber(L, worker->stats.concurrent);
+ lua_pushnumber(L, the_worker->stats.concurrent);
lua_setfield(L, -2, "concurrent");
- lua_pushnumber(L, worker->stats.dropped);
+ lua_pushnumber(L, the_worker->stats.dropped);
lua_setfield(L, -2, "dropped");
- lua_pushnumber(L, worker->stats.timeout);
+ lua_pushnumber(L, the_worker->stats.timeout);
lua_setfield(L, -2, "timeout");
- lua_pushnumber(L, worker->stats.udp);
+ lua_pushnumber(L, the_worker->stats.udp);
lua_setfield(L, -2, "udp");
- lua_pushnumber(L, worker->stats.tcp);
+ lua_pushnumber(L, the_worker->stats.tcp);
lua_setfield(L, -2, "tcp");
- lua_pushnumber(L, worker->stats.tls);
+ lua_pushnumber(L, the_worker->stats.tls);
lua_setfield(L, -2, "tls");
- lua_pushnumber(L, worker->stats.ipv4);
+ lua_pushnumber(L, the_worker->stats.ipv4);
lua_setfield(L, -2, "ipv4");
- lua_pushnumber(L, worker->stats.ipv6);
+ lua_pushnumber(L, the_worker->stats.ipv6);
lua_setfield(L, -2, "ipv6");
- lua_pushnumber(L, worker->stats.err_udp);
+ lua_pushnumber(L, the_worker->stats.err_udp);
lua_setfield(L, -2, "err_udp");
- lua_pushnumber(L, worker->stats.err_tcp);
+ lua_pushnumber(L, the_worker->stats.err_tcp);
lua_setfield(L, -2, "err_tcp");
- lua_pushnumber(L, worker->stats.err_tls);
+ lua_pushnumber(L, the_worker->stats.err_tls);
lua_setfield(L, -2, "err_tls");
- lua_pushnumber(L, worker->stats.err_http);
+ lua_pushnumber(L, the_worker->stats.err_http);
lua_setfield(L, -2, "err_http");
/* Add subset of rusage that represents counters. */
#include "lib/dnssec/ta.h"
#include "lib/log.h"
-/* Magic defaults for the engine. */
-#ifndef LRU_RTT_SIZE
-#define LRU_RTT_SIZE 65536 /**< NS RTT cache size */
-#endif
-#ifndef LRU_REP_SIZE
-#define LRU_REP_SIZE (LRU_RTT_SIZE / 4) /**< NS reputation cache size */
-#endif
-#ifndef LRU_COOKIES_SIZE
- #if ENABLE_COOKIES
- #define LRU_COOKIES_SIZE LRU_RTT_SIZE /**< DNS cookies cache size. */
- #else
- #define LRU_COOKIES_SIZE LRU_ASSOC /* simpler than guards everywhere */
- #endif
-#endif
-
-/**@internal Maximum number of incomplete TCP connections in queue.
-* Default is from empirical testing - in our case, more isn't necessarily better.
-* See https://gitlab.nic.cz/knot/knot-resolver/-/merge_requests/968
-* */
-#ifndef TCP_BACKLOG_DEFAULT
-#define TCP_BACKLOG_DEFAULT 128
-#endif
-
/* Cleanup engine state every 5 minutes */
const size_t CLEANUP_TIMER = 5*60*1000;
*/
struct args *the_args;
+static struct engine engine = {0};
+struct engine *the_engine = NULL;
+
/** Print help and available commands. */
static int l_help(lua_State *L)
/** Quit current executable. */
static int l_quit(lua_State *L)
{
- engine_stop(the_worker->engine);
+ engine_stop();
return 0;
}
lua_error_p(L, "takes a table of string groups as parameter or nothing");
}
-char *engine_get_hostname(struct engine *engine) {
+char *engine_get_hostname(void) {
static char hostname_str[KNOT_DNAME_MAXLEN];
- if (!engine) {
- return NULL;
- }
- if (!engine->hostname) {
+ if (!the_engine->hostname) {
if (gethostname(hostname_str, sizeof(hostname_str)) != 0)
return NULL;
return hostname_str;
}
- return engine->hostname;
+ return the_engine->hostname;
}
-int engine_set_hostname(struct engine *engine, const char *hostname) {
- if (!engine || !hostname) {
+int engine_set_hostname(const char *hostname) {
+ if (!hostname) {
return kr_error(EINVAL);
}
if (!new_hostname) {
return kr_error(ENOMEM);
}
- if (engine->hostname) {
- free(engine->hostname);
+ if (the_engine->hostname) {
+ free(the_engine->hostname);
}
- engine->hostname = new_hostname;
- network_new_hostname(&engine->net, engine);
+ the_engine->hostname = new_hostname;
+ network_new_hostname();
return 0;
}
/** Return hostname. */
static int l_hostname(lua_State *L)
{
- struct engine *engine = the_worker->engine;
if (lua_gettop(L) == 0) {
- lua_pushstring(L, engine_get_hostname(engine));
+ lua_pushstring(L, engine_get_hostname());
return 1;
}
if ((lua_gettop(L) != 1) || !lua_isstring(L, 1))
lua_error_p(L, "hostname takes at most one parameter: (\"fqdn\")");
- if (engine_set_hostname(engine, lua_tostring(L, 1)) != 0)
+ if (engine_set_hostname(lua_tostring(L, 1)) != 0)
lua_error_p(L, "setting hostname failed");
- lua_pushstring(L, engine_get_hostname(engine));
+ lua_pushstring(L, engine_get_hostname());
return 1;
}
/** Load root hints from zonefile. */
static int l_hint_root_file(lua_State *L)
{
- struct kr_context *ctx = &the_worker->engine->resolver;
const char *file = lua_tostring(L, 1);
- const char *err = engine_hint_root_file(ctx, file);
+ const char *err = engine_hint_root_file(file);
if (err) {
if (!file) {
file = ROOTHINTS;
kr_zonecut_add(hints, zs->r_owner, zs->r_data, zs->r_data_length);
}
}
-const char* engine_hint_root_file(struct kr_context *ctx, const char *file)
+const char* engine_hint_root_file(const char *file)
{
if (!file) {
file = ROOTHINTS;
}
- if (strlen(file) == 0 || !ctx) {
+ if (strlen(file) == 0) {
return "invalid parameters";
}
- struct kr_zonecut *root_hints = &ctx->root_hints;
+ struct kr_zonecut *root_hints = &the_resolver->root_hints;
zs_scanner_t zs;
if (zs_init(&zs, ".", 1, 0) != 0) {
* Engine API.
*/
-static int init_resolver(struct engine *engine)
-{
- /* Note: whole *engine had been zeroed by engine_init(). */
- struct kr_context * const ctx = &engine->resolver;
- /* Default options (request flags). */
- ctx->options.REORDER_RR = true;
-
- /* Open resolution context */
- ctx->trust_anchors = trie_create(NULL);
- ctx->negative_anchors = trie_create(NULL);
- ctx->pool = engine->pool;
- ctx->modules = &engine->modules;
- ctx->cache_rtt_tout_retry_interval = KR_NS_TIMEOUT_RETRY_INTERVAL;
- /* Create OPT RR */
- ctx->downstream_opt_rr = mm_alloc(engine->pool, sizeof(knot_rrset_t));
- ctx->upstream_opt_rr = mm_alloc(engine->pool, sizeof(knot_rrset_t));
- if (!ctx->downstream_opt_rr || !ctx->upstream_opt_rr) {
- return kr_error(ENOMEM);
- }
- knot_edns_init(ctx->downstream_opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, engine->pool);
- knot_edns_init(ctx->upstream_opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, engine->pool);
- /* Use default TLS padding */
- ctx->tls_padding = -1;
- /* Empty init; filled via ./lua/postconfig.lua */
- kr_zonecut_init(&ctx->root_hints, (const uint8_t *)"", engine->pool);
- lru_create(&ctx->cache_cookie, LRU_COOKIES_SIZE, NULL, NULL);
-
- /* Load basic modules */
- engine_register(engine, "iterate", NULL, NULL);
- engine_register(engine, "validate", NULL, NULL);
- engine_register(engine, "cache", NULL, NULL);
-
- return array_push(engine->backends, kr_cdb_lmdb());
-}
-
-static int init_state(struct engine *engine)
+static int init_state(void)
{
/* Initialize Lua state */
- engine->L = luaL_newstate();
- if (engine->L == NULL) {
+ the_engine->L = luaL_newstate();
+ if (the_engine->L == NULL) {
return kr_error(ENOMEM);
}
/* Initialize used libraries. */
- luaL_openlibs(engine->L);
+ luaL_openlibs(the_engine->L);
/* Global functions */
- lua_pushcfunction(engine->L, l_help);
- lua_setglobal(engine->L, "help");
- lua_pushcfunction(engine->L, l_quit);
- lua_setglobal(engine->L, "quit");
- lua_pushcfunction(engine->L, l_hostname);
- lua_setglobal(engine->L, "hostname");
- lua_pushcfunction(engine->L, l_package_version);
- lua_setglobal(engine->L, "package_version");
- lua_pushcfunction(engine->L, l_verbose);
- lua_setglobal(engine->L, "verbose");
- lua_pushcfunction(engine->L, l_log_level);
- lua_setglobal(engine->L, "log_level");
- lua_pushcfunction(engine->L, l_log_target);
- lua_setglobal(engine->L, "log_target");
- lua_pushcfunction(engine->L, l_log_groups);
- lua_setglobal(engine->L, "log_groups");
- lua_pushcfunction(engine->L, l_setuser);
- lua_setglobal(engine->L, "user");
- lua_pushcfunction(engine->L, l_hint_root_file);
- lua_setglobal(engine->L, "_hint_root_file");
- lua_pushliteral(engine->L, libknot_SONAME);
- lua_setglobal(engine->L, "libknot_SONAME");
- lua_pushliteral(engine->L, libzscanner_SONAME);
- lua_setglobal(engine->L, "libzscanner_SONAME");
- lua_pushcfunction(engine->L, l_tojson);
- lua_setglobal(engine->L, "tojson");
- lua_pushcfunction(engine->L, l_fromjson);
- lua_setglobal(engine->L, "fromjson");
+ lua_pushcfunction(the_engine->L, l_help);
+ lua_setglobal(the_engine->L, "help");
+ lua_pushcfunction(the_engine->L, l_quit);
+ lua_setglobal(the_engine->L, "quit");
+ lua_pushcfunction(the_engine->L, l_hostname);
+ lua_setglobal(the_engine->L, "hostname");
+ lua_pushcfunction(the_engine->L, l_package_version);
+ lua_setglobal(the_engine->L, "package_version");
+ lua_pushcfunction(the_engine->L, l_verbose);
+ lua_setglobal(the_engine->L, "verbose");
+ lua_pushcfunction(the_engine->L, l_log_level);
+ lua_setglobal(the_engine->L, "log_level");
+ lua_pushcfunction(the_engine->L, l_log_target);
+ lua_setglobal(the_engine->L, "log_target");
+ lua_pushcfunction(the_engine->L, l_log_groups);
+ lua_setglobal(the_engine->L, "log_groups");
+ lua_pushcfunction(the_engine->L, l_setuser);
+ lua_setglobal(the_engine->L, "user");
+ lua_pushcfunction(the_engine->L, l_hint_root_file);
+ lua_setglobal(the_engine->L, "_hint_root_file");
+ lua_pushliteral(the_engine->L, libknot_SONAME);
+ lua_setglobal(the_engine->L, "libknot_SONAME");
+ lua_pushliteral(the_engine->L, libzscanner_SONAME);
+ lua_setglobal(the_engine->L, "libzscanner_SONAME");
+ lua_pushcfunction(the_engine->L, l_tojson);
+ lua_setglobal(the_engine->L, "tojson");
+ lua_pushcfunction(the_engine->L, l_fromjson);
+ lua_setglobal(the_engine->L, "fromjson");
/* Random number generator */
- lua_getfield(engine->L, LUA_GLOBALSINDEX, "math");
- lua_getfield(engine->L, -1, "randomseed");
- lua_remove(engine->L, -2);
+ lua_getfield(the_engine->L, LUA_GLOBALSINDEX, "math");
+ lua_getfield(the_engine->L, -1, "randomseed");
+ lua_remove(the_engine->L, -2);
lua_Number seed = kr_rand_bytes(sizeof(lua_Number));
- lua_pushnumber(engine->L, seed);
- lua_call(engine->L, 1, 0);
+ lua_pushnumber(the_engine->L, seed);
+ lua_call(the_engine->L, 1, 0);
return kr_ok();
}
* KRESD_COVERAGE_STATS environment variable.
* Do nothing if the variable is not set.
*/
-static void init_measurement(struct engine *engine)
+static void init_measurement(void)
{
const char * const statspath = getenv("KRESD_COVERAGE_STATS");
if (!statspath)
if (kr_fails_assert(ret > 0))
return;
- ret = luaL_loadstring(engine->L, snippet);
+ ret = luaL_loadstring(the_engine->L, snippet);
if (kr_fails_assert(ret == 0)) {
free(snippet);
return;
}
- lua_call(engine->L, 0, 0);
+ lua_call(the_engine->L, 0, 0);
free(snippet);
}
-int init_lua(struct engine *engine) {
- if (!engine) {
- return kr_error(EINVAL);
- }
-
+int init_lua(void) {
/* Use libdir path for including Lua scripts */
char l_paths[MAXPATHLEN] = { 0 };
#pragma GCC diagnostic push
LIBDIR, LIBEXT);
#pragma GCC diagnostic pop
- int ret = l_dobytecode(engine->L, l_paths, strlen(l_paths), "");
+ int ret = l_dobytecode(the_engine->L, l_paths, strlen(l_paths), "");
if (ret != 0) {
- lua_pop(engine->L, 1);
+ lua_pop(the_engine->L, 1);
return ret;
}
return 0;
}
-int engine_init(struct engine *engine, knot_mm_t *pool)
+int engine_init(void)
{
- if (engine == NULL) {
- return kr_error(EINVAL);
- }
-
- memset(engine, 0, sizeof(*engine));
- engine->pool = pool;
+ kr_require(!the_engine);
+ the_engine = &engine;
+ mm_ctx_mempool(&the_engine->pool, MM_DEFAULT_BLKSIZE);
/* Initialize state */
- int ret = init_state(engine);
+ int ret = init_state();
if (ret != 0) {
- engine_deinit(engine);
+ engine_deinit();
return ret;
}
- init_measurement(engine);
- /* Initialize resolver */
- ret = init_resolver(engine);
+ init_measurement();
+
+ /* Load basic modules */
+ engine_register("iterate", NULL, NULL);
+ engine_register("validate", NULL, NULL);
+ engine_register("cache", NULL, NULL);
+
+ ret = array_push(the_engine->backends, kr_cdb_lmdb());
if (ret != 0) {
- engine_deinit(engine);
+ engine_deinit();
return ret;
}
- /* Initialize network */
- network_init(&engine->net, uv_default_loop(), TCP_BACKLOG_DEFAULT);
/* Initialize lua */
- ret = init_lua(engine);
+ ret = init_lua();
if (ret != 0) {
- engine_deinit(engine);
+ engine_deinit();
return ret;
}
}
/** Unregister a (found) module */
-static void engine_unload(struct engine *engine, struct kr_module *module)
+static void engine_unload(struct kr_module *module)
{
auto_free char *name = module->name ? strdup(module->name) : NULL;
kr_module_unload(module); /* beware: lua/C mix, could be confusing */
/* Clear in Lua world, but not for embedded modules ('cache' in particular). */
if (name && !kr_module_get_embedded(name)) {
- lua_pushnil(engine->L);
- lua_setglobal(engine->L, name);
+ lua_pushnil(the_engine->L);
+ lua_setglobal(the_engine->L, name);
}
free(module);
}
-void engine_deinit(struct engine *engine)
+void engine_deinit(void)
{
- if (!engine || kr_fails_assert(engine->L))
+ if (kr_fails_assert(the_engine->L))
return;
/* Only close sockets and services; no need to clean up mempool. */
* then we can unload modules during which we still want
* e.g. the endpoint kind registry to work (inside ->net),
* and this registry deinitialization uses the lua state. */
- network_close_force(&engine->net);
- for (size_t i = 0; i < engine->modules.len; ++i) {
- engine_unload(engine, engine->modules.at[i]);
+ for (size_t i = 0; i < the_engine->modules.len; ++i) {
+ engine_unload(the_engine->modules.at[i]);
}
- kr_zonecut_deinit(&engine->resolver.root_hints);
- kr_cache_close(&engine->resolver.cache);
- /* The LRUs are currently malloc-ated and need to be freed. */
- lru_free(engine->resolver.cache_cookie);
-
- network_deinit(&engine->net);
- ffimodule_deinit(engine->L);
- lua_close(engine->L);
+ ffimodule_deinit(the_engine->L);
+ lua_close(the_engine->L);
/* Free data structures */
- array_clear(engine->modules);
- array_clear(engine->backends);
- kr_ta_clear(engine->resolver.trust_anchors);
- trie_free(engine->resolver.trust_anchors);
- kr_ta_clear(engine->resolver.negative_anchors);
- trie_free(engine->resolver.negative_anchors);
- free(engine->hostname);
+ array_clear(the_engine->modules);
+ array_clear(the_engine->backends);
+ free(the_engine->hostname);
+ mp_delete(the_engine->pool.ctx);
+
+ the_engine = NULL;
}
int engine_pcall(lua_State *L, int argc)
return engine_pcall(L, 2);
}
-int engine_load_sandbox(struct engine *engine)
+int engine_load_sandbox(void)
{
/* Init environment */
- int ret = luaL_dofile(engine->L, LIBDIR "/sandbox.lua");
+ int ret = luaL_dofile(the_engine->L, LIBDIR "/sandbox.lua");
if (ret != 0) {
- kr_log_error(SYSTEM, "error %s\n", lua_tostring(engine->L, -1));
- lua_pop(engine->L, 1);
+ kr_log_error(SYSTEM, "error %s\n", lua_tostring(the_engine->L, -1));
+ lua_pop(the_engine->L, 1);
return kr_error(ENOEXEC);
}
- ret = ffimodule_init(engine->L);
+ ret = ffimodule_init(the_engine->L);
return ret;
}
-int engine_loadconf(struct engine *engine, const char *config_path)
+int engine_loadconf(const char *config_path)
{
if (kr_fails_assert(config_path))
return kr_error(EINVAL);
get_workdir(cwd, sizeof(cwd));
kr_log_debug(SYSTEM, "loading config '%s' (workdir '%s')\n", config_path, cwd);
- int ret = luaL_dofile(engine->L, config_path);
+ int ret = luaL_dofile(the_engine->L, config_path);
if (ret != 0) {
kr_log_error(SYSTEM, "error while loading config: "
- "%s (workdir '%s')\n", lua_tostring(engine->L, -1), cwd);
- lua_pop(engine->L, 1);
+ "%s (workdir '%s')\n", lua_tostring(the_engine->L, -1), cwd);
+ lua_pop(the_engine->L, 1);
}
return ret;
}
-int engine_start(struct engine *engine)
+int engine_start(void)
{
/* Clean up stack */
- lua_settop(engine->L, 0);
+ lua_settop(the_engine->L, 0);
return kr_ok();
}
-void engine_stop(struct engine *engine)
+void engine_stop(void)
{
- if (!engine) {
- return;
- }
uv_stop(uv_default_loop());
}
return found;
}
-int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref)
+int engine_register(const char *name, const char *precedence, const char* ref)
{
- if (kr_fails_assert(engine && name))
+ if (kr_fails_assert(name))
return kr_error(EINVAL);
/* Make sure module is unloaded */
- (void) engine_unregister(engine, name);
+ (void) engine_unregister(name);
/* Find the index of referenced module. */
- module_array_t *mod_list = &engine->modules;
+ module_array_t *mod_list = &the_engine->modules;
size_t ref_pos = mod_list->len;
if (precedence && ref) {
ref_pos = module_find(mod_list, ref);
if (!module) {
return kr_error(ENOMEM);
}
- module->data = engine; /*< some outside modules may still use this value */
+ module->data = the_engine; /*< some outside modules may still use this value */
int ret = kr_module_load(module, name, LIBDIR "/kres_modules");
if (ret == 0) {
/* We have a C module, loaded and init() was called.
* Now we need to prepare the lua side. */
- lua_State *L = engine->L;
+ lua_State *L = the_engine->L;
lua_getglobal(L, "modules_create_table_for_c");
lua_pushpointer(L, module);
if (lua_isnil(L, -2)) {
} else if (ret == kr_error(ENOENT)) {
/* No luck with C module, so try to load and .init() lua module. */
- ret = ffimodule_register_lua(engine, module, name);
+ ret = ffimodule_register_lua(module, name);
if (ret != 0) {
kr_log_error(SYSTEM, "failed to load module '%s'\n", name);
}
}
if (ret != 0) {
- engine_unload(engine, module);
+ engine_unload(module);
return ret;
}
- /* Push to the right place in engine->modules */
- if (array_push(engine->modules, module) < 0) {
- engine_unload(engine, module);
+ /* Push to the right place in the_engine->modules */
+ if (array_push(the_engine->modules, module) < 0) {
+ engine_unload(module);
return kr_error(ENOMEM);
}
if (precedence) {
return kr_ok();
}
-int engine_unregister(struct engine *engine, const char *name)
+int engine_unregister(const char *name)
{
- module_array_t *mod_list = &engine->modules;
+ module_array_t *mod_list = &the_engine->modules;
size_t found = module_find(mod_list, name);
if (found < mod_list->len) {
- engine_unload(engine, mod_list->at[found]);
+ engine_unload(mod_list->at[found]);
array_del(*mod_list, found);
return kr_ok();
}
return kr_error(ENOENT);
}
+module_array_t *engine_modules(void)
+{
+ return &the_engine->modules;
+}
#include "daemon/network.h"
struct engine {
- struct kr_context resolver;
- struct network net;
module_array_t modules;
array_t(const struct kr_cdb_api *) backends;
- knot_mm_t *pool;
+ knot_mm_t pool;
char *hostname;
struct lua_State *L;
};
-int engine_init(struct engine *engine, knot_mm_t *pool);
-void engine_deinit(struct engine *engine);
+/** Pointer to the singleton engine state. NULL if not initialized. */
+KR_EXPORT extern struct engine *the_engine;
+
+/** Initializes the engine. */
+int engine_init(void);
+
+/* Deinitializes the engine. `network_unregister` should be called before
+ * this and before `network_deinit`. */
+void engine_deinit(void);
/** Perform a lua command within the sandbox.
*
/** Execute current chunk in the sandbox */
int engine_pcall(struct lua_State *L, int argc);
-int engine_load_sandbox(struct engine *engine);
-int engine_loadconf(struct engine *engine, const char *config_path);
+int engine_load_sandbox(void);
+int engine_loadconf(const char *config_path);
/** Start the lua engine and execute the config. */
-int engine_start(struct engine *engine);
-void engine_stop(struct engine *engine);
-int engine_register(struct engine *engine, const char *name, const char *precedence, const char* ref);
-int engine_unregister(struct engine *engine, const char *name);
+int engine_start(void);
+void engine_stop(void);
+int engine_register(const char *name, const char *precedence, const char* ref);
+int engine_unregister(const char *name);
+/** Gets the list of the engine's registered modules. */
+module_array_t *engine_modules(void);
/** Set/get the per engine hostname */
-char *engine_get_hostname(struct engine *engine);
-int engine_set_hostname(struct engine *engine, const char *hostname);
+char *engine_get_hostname(void);
+int engine_set_hostname(const char *hostname);
/** Load root hints from a zonefile (or config-time default if NULL).
*
* @note exported to be usable from the hints module.
*/
KR_EXPORT
-const char* engine_hint_root_file(struct kr_context *ctx, const char *file);
+const char* engine_hint_root_file(const char *file);
/* @internal Array of ip address shorthand. */
typedef array_t(char*) addr_array_t;
static int l_ffi_deinit(struct kr_module *module)
{
/* Call .deinit(), if it exists. */
- lua_State *L = the_worker->engine->L;
+ lua_State *L = the_engine->L;
lua_getglobal(L, module->name);
lua_getfield(L, -1, "deinit");
const int ret = l_ffi_modcb(L, module);
const int wrap_slot = l_ffi_wrap_slots[slot_ix];
const int cb_slot = ctx->api->cb_slots[slot_ix];
kr_require(wrap_slot > 0 && cb_slot > 0);
- lua_State *L = the_worker->engine->L;
+ lua_State *L = the_engine->L;
lua_rawgeti(L, LUA_REGISTRYINDEX, wrap_slot);
lua_rawgeti(L, LUA_REGISTRYINDEX, cb_slot);
/* We pass the content of *ctx via a global structure to avoid
#undef LAYER_REGISTER
-int ffimodule_register_lua(struct engine *engine, struct kr_module *module, const char *name)
+int ffimodule_register_lua(struct kr_module *module, const char *name)
{
/* Register module in Lua */
- lua_State *L = engine->L;
+ lua_State *L = the_engine->L;
lua_getglobal(L, "require");
lua_pushfstring(L, "kres_modules.%s", name);
if (lua_pcall(L, 1, LUA_MULTRET, 0) != 0) {
* @param name module name
* @return 0 or an error
*/
-int ffimodule_register_lua(struct engine *engine, struct kr_module *module, const char *name);
+int ffimodule_register_lua(struct kr_module *module, const char *name);
int ffimodule_init(lua_State *L);
void ffimodule_deinit(lua_State *L);
* This is magic presuming we can pull in a whole recvmmsg width in one wave.
* Linux will double this the bufsize wanted.
*/
- const int bufsize_want = 2 * sizeof( ((struct worker_ctx *)NULL)->wire_buf ) ;
+ const int bufsize_want = 2 * sizeof(the_worker->wire_buf) ;
negotiate_bufsize(uv_recv_buffer_size, handle, bufsize_want);
negotiate_bufsize(uv_send_buffer_size, handle, bufsize_want);
}
struct proxy_result proxy;
bool has_proxy = false;
if (!session_flags(s)->outgoing && proxy_header_present(data, data_len)) {
- if (!proxy_allowed(&the_worker->engine->net, comm_addr)) {
+ if (!proxy_allowed(comm_addr)) {
kr_log_debug(IO, "<= ignoring PROXYv2 UDP from disallowed address '%s'\n",
kr_straddr(comm_addr));
return;
return;
}
}
- const struct network *net = &the_worker->engine->net;
- uint64_t idle_in_timeout = net->tcp.in_idle_timeout;
+ uint64_t idle_in_timeout = the_network->tcp.in_idle_timeout;
uint64_t last_activity = session_last_activity(s);
uint64_t idle_time = kr_now() - last_activity;
if (idle_time < idle_in_timeout) {
kr_log_debug(IO, "=> closing connection to '%s'\n",
peer_str ? peer_str : "");
if (session_flags(s)->outgoing) {
- worker_del_tcp_waiting(the_worker, peer);
- worker_del_tcp_connected(the_worker, peer);
+ worker_del_tcp_waiting(peer);
+ worker_del_tcp_connected(peer);
}
session_close(s);
}
const struct sockaddr *dst_addr = NULL;
if (!session_flags(s)->outgoing && !session_flags(s)->no_proxy &&
proxy_header_present(data, data_len)) {
- if (!proxy_allowed(&the_worker->engine->net, src_addr)) {
+ if (!proxy_allowed(src_addr)) {
if (kr_log_is_debug(IO, NULL)) {
kr_log_debug(IO, "<= connection to '%s': PROXYv2 not allowed "
"for this peer, close\n",
return;
}
- struct worker_ctx *worker = the_worker;
uv_tcp_t *client = malloc(sizeof(uv_tcp_t));
if (!client) {
return;
SOCK_STREAM, AF_UNSPEC, tls, http);
if (res) {
if (res == UV_EMFILE) {
- worker->too_many_open = true;
- worker->rconcurrent_highwatermark = worker->stats.rconcurrent;
+ the_worker->too_many_open = true;
+ the_worker->rconcurrent_highwatermark = the_worker->stats.rconcurrent;
}
/* Since res isn't OK struct session wasn't allocated \ borrowed.
* We must release client handle only.
* It will re-check every half of a request time limit if the connection
* is idle and should be terminated, this is an educated guess. */
- const struct network *net = &worker->engine->net;
- uint64_t idle_in_timeout = net->tcp.in_idle_timeout;
+ uint64_t idle_in_timeout = the_network->tcp.in_idle_timeout;
uint64_t timeout = KR_CONN_RTT_MAX / 2;
if (tls) {
timeout += TLS_MAX_HANDSHAKE_TIME;
struct tls_ctx *ctx = session_tls_get_server_ctx(s);
if (!ctx) {
- ctx = tls_new(worker);
+ ctx = tls_new();
if (!ctx) {
session_close(s);
return;
/** Moving pointer to end of buffer with incomplete command. */
char *pbuf = data->buf + data->blen;
- lua_State *L = the_worker->engine->L;
+ lua_State *L = the_engine->L;
while (cmd != NULL) {
/* Last command is incomplete - save it and execute later */
if (incomplete_cmd && cmd_next == NULL) {
};
struct request_ctx {
struct kr_request req;
- struct worker_ctx *worker;
struct qr_task *task;
/* beware: hidden stub, to avoid hardcoding sockaddr lengths */
};
struct qr_task *worker_resolve_start(knot_pkt_t *, struct kr_qflags);
int zi_zone_import(const zi_config_t);
struct engine {
- struct kr_context resolver;
char _stub[];
};
struct worker_ctx {
- struct engine *engine;
char _stub[];
};
+struct kr_context *the_resolver;
struct worker_ctx *the_worker;
+struct engine *the_engine;
typedef struct {
uint8_t bitmap[32];
uint8_t length;
};
struct request_ctx {
struct kr_request req;
- struct worker_ctx *worker;
struct qr_task *task;
/* beware: hidden stub, to avoid hardcoding sockaddr lengths */
};
struct qr_task *worker_resolve_start(knot_pkt_t *, struct kr_qflags);
int zi_zone_import(const zi_config_t);
struct engine {
- struct kr_context resolver;
char _stub[];
};
struct worker_ctx {
- struct engine *engine;
char _stub[];
};
+struct kr_context *the_resolver;
struct worker_ctx *the_worker;
+struct engine *the_engine;
typedef struct {
uint8_t *params_position;
uint8_t *mandatory_position;
zi_zone_import
EOF
-echo "struct engine" | ${CDEFS} ${KRESD} types | sed '/struct network/,$ d'
+echo "struct engine" | ${CDEFS} ${KRESD} types | sed '/module_array_t/,$ d'
printf "\tchar _stub[];\n};\n"
echo "struct worker_ctx" | ${CDEFS} ${KRESD} types | sed '/uv_loop_t/,$ d'
printf "\tchar _stub[];\n};\n"
+echo "struct kr_context *the_resolver;"
echo "struct worker_ctx *the_worker;"
+echo "struct engine *the_engine;"
## libzscanner API for ./zonefile.lua
if ret ~= 1 then return nil end
return ffi.string(addr_buf, C.kr_family_len(family))
end,
- context = function () return ffi.C.the_worker.engine.resolver end,
+ context = function () return ffi.C.the_resolver end,
knot_pkt_rr = knot_pkt_rr,
}
elseif arg ~= nil then
arg_conv = tostring(arg)
end
- local ret_cstr = cb(ffi.C.the_worker.engine, kr_module, arg_conv)
+ local ret_cstr = cb(ffi.C.the_engine, kr_module, arg_conv)
if ret_cstr == nil then
return nil
end
#endif
#include <libknot/error.h>
+/**@internal Maximum number of incomplete TCP connections in queue.
+* Default is from empirical testing - in our case, more isn't necessarily better.
+* See https://gitlab.nic.cz/knot/knot-resolver/-/merge_requests/968
+* */
+#ifndef TCP_BACKLOG_DEFAULT
+#define TCP_BACKLOG_DEFAULT 128
+#endif
struct args the_args_value; /** Static allocation for the_args singleton. */
}
/** \return exit code for main() */
-static int run_worker(uv_loop_t *loop, struct engine *engine, bool leader, struct args *args)
+static int run_worker(uv_loop_t *loop, bool leader, struct args *args)
{
/* Only some kinds of stdin work with uv_pipe_t.
* Otherwise we would abort() from libuv e.g. with </dev/null */
return has_error ? EXIT_FAILURE : kr_ok();
}
-static int start_listening(struct network *net, flagged_fd_array_t *fds) {
+static int start_listening(flagged_fd_array_t *fds) {
int some_bad_ret = 0;
for (size_t i = 0; i < fds->len; ++i) {
flagged_fd_t *ffd = &fds->at[i];
- int ret = network_listen_fd(net, ffd->fd, ffd->flags);
+ int ret = network_listen_fd(ffd->fd, ffd->flags);
if (ret != 0) {
some_bad_ret = ret;
/* TODO: try logging address@port. It's not too important,
kr_crypto_init();
+ network_init(uv_default_loop(), TCP_BACKLOG_DEFAULT);
+
/* Create a server engine. */
- knot_mm_t pool;
- mm_ctx_mempool(&pool, MM_DEFAULT_BLKSIZE);
- static struct engine engine;
- ret = engine_init(&engine, &pool);
+ ret = engine_init();
if (ret != 0) {
kr_log_error(SYSTEM, "failed to initialize engine: %s\n", kr_strerror(ret));
return EXIT_FAILURE;
}
- /* Initialize the worker */
- ret = worker_init(&engine, the_args->forks);
+
+ /* Create resolver context. */
+ ret = kr_resolver_init(&the_engine->modules, &the_engine->pool);
+ if (ret != 0) {
+ kr_log_error(SYSTEM, "failed to initialize resolver: %s\n", kr_strerror(ret));
+ return EXIT_FAILURE;
+ }
+ /* Initialize the worker. */
+ ret = worker_init(the_args->forks);
if (ret != 0) {
kr_log_error(SYSTEM, "failed to initialize worker: %s\n", kr_strerror(ret));
return EXIT_FAILURE;
}
/* Start listening, in the sense of network_listen_fd(). */
- if (start_listening(&engine.net, &the_args->fds) != 0) {
+ if (start_listening(&the_args->fds) != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
}
/* Start the scripting engine */
- if (engine_load_sandbox(&engine) != 0) {
+ if (engine_load_sandbox() != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
for (i = 0; i < the_args->config.len; ++i) {
const char *config = the_args->config.at[i];
- if (engine_loadconf(&engine, config) != 0) {
+ if (engine_loadconf(config) != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
- lua_settop(engine.L, 0);
+ lua_settop(the_engine->L, 0);
}
drop_capabilities();
- if (engine_start(&engine) != 0) {
+ if (engine_start() != 0) {
ret = EXIT_FAILURE;
goto cleanup;
}
- if (network_engage_endpoints(&engine.net)) {
+ if (network_engage_endpoints()) {
ret = EXIT_FAILURE;
goto cleanup;
}
/* Run the event loop */
- ret = run_worker(loop, &engine, fork_id == 0, the_args);
+ ret = run_worker(loop, fork_id == 0, the_args);
cleanup:/* Cleanup. */
- engine_deinit(&engine);
+ network_unregister();
+
+ kr_resolver_deinit();
worker_deinit();
+ engine_deinit();
+ network_deinit();
if (loop != NULL) {
uv_loop_close(loop);
}
- mp_delete(pool.ctx);
cleanup_args:
args_deinit(the_args);
kr_crypto_cleanup();
static_assert(_Alignof(struct endpoint_key_sockaddr) <= 4, "endpoint_key must be aligned to <=4");
static_assert(_Alignof(struct endpoint_key_ifname) <= 4, "endpoint_key must be aligned to <=4");
-void network_init(struct network *net, uv_loop_t *loop, int tcp_backlog)
+static struct network the_network_value = {0};
+struct network *the_network = NULL;
+
+void network_init(uv_loop_t *loop, int tcp_backlog)
{
- if (net != NULL) {
- net->loop = loop;
- net->endpoints = trie_create(NULL);
- net->endpoint_kinds = trie_create(NULL);
- net->proxy_all4 = false;
- net->proxy_all6 = false;
- net->proxy_addrs4 = trie_create(NULL);
- net->proxy_addrs6 = trie_create(NULL);
- net->tls_client_params = NULL;
- net->tls_session_ticket_ctx = /* unsync. random, by default */
- tls_session_ticket_ctx_create(loop, NULL, 0);
- net->tcp.in_idle_timeout = 10000;
- net->tcp.tls_handshake_timeout = TLS_MAX_HANDSHAKE_TIME;
- net->tcp_backlog = tcp_backlog;
- }
+ the_network = &the_network_value;
+
+ the_network->loop = loop;
+ the_network->endpoints = trie_create(NULL);
+ the_network->endpoint_kinds = trie_create(NULL);
+ the_network->proxy_all4 = false;
+ the_network->proxy_all6 = false;
+ the_network->proxy_addrs4 = trie_create(NULL);
+ the_network->proxy_addrs6 = trie_create(NULL);
+ the_network->tls_client_params = NULL;
+ the_network->tls_session_ticket_ctx = /* unsync. random, by default */
+ tls_session_ticket_ctx_create(loop, NULL, 0);
+ the_network->tcp.in_idle_timeout = 10000;
+ the_network->tcp.tls_handshake_timeout = TLS_MAX_HANDSHAKE_TIME;
+ the_network->tcp_backlog = tcp_backlog;
}
/** Notify the registered function about endpoint getting open.
* If log_port < 1, don't log it. */
-static int endpoint_open_lua_cb(struct network *net, struct endpoint *ep,
+static int endpoint_open_lua_cb(struct endpoint *ep,
const char *log_addr)
{
const bool ok = ep->flags.kind && !ep->handle && !ep->engaged && ep->fd != -1;
if (kr_fails_assert(ok))
return kr_error(EINVAL);
/* First find callback in the endpoint registry. */
- lua_State *L = the_worker->engine->L;
- void **pp = trie_get_try(net->endpoint_kinds, ep->flags.kind,
+ lua_State *L = the_engine->L;
+ void **pp = trie_get_try(the_network->endpoint_kinds, ep->flags.kind,
strlen(ep->flags.kind));
- if (!pp && net->missing_kind_is_error) {
+ if (!pp && the_network->missing_kind_is_error) {
kr_log_error(NETWORK, "error: network socket kind '%s' not handled when opening '%s",
ep->flags.kind, log_addr);
if (ep->family != AF_UNIX)
struct endpoint *ep = &eps->at[i];
const bool match = !ep->engaged && ep->flags.kind;
if (!match) continue;
- int ret = endpoint_open_lua_cb(net, ep, log_addr);
+ int ret = endpoint_open_lua_cb(ep, log_addr);
if (ret) return ret;
}
return 0;
}
-int network_engage_endpoints(struct network *net)
+int network_engage_endpoints(void)
{
- if (net->missing_kind_is_error)
+ if (the_network->missing_kind_is_error)
return kr_ok(); /* maybe weird, but let's make it idempotent */
- net->missing_kind_is_error = true;
- int ret = trie_apply_with_key(net->endpoints, engage_endpoint_array, net);
+ the_network->missing_kind_is_error = true;
+ int ret = trie_apply_with_key(the_network->endpoints, engage_endpoint_array, the_network);
if (ret) {
- net->missing_kind_is_error = false; /* avoid the same errors when closing */
+ the_network->missing_kind_is_error = false; /* avoid the same errors when closing */
return ret;
}
return kr_ok();
}
/** Notify the registered function about endpoint about to be closed. */
-static void endpoint_close_lua_cb(struct network *net, struct endpoint *ep)
+static void endpoint_close_lua_cb(struct endpoint *ep)
{
- lua_State *L = the_worker->engine->L;
- void **pp = trie_get_try(net->endpoint_kinds, ep->flags.kind,
+ lua_State *L = the_engine->L;
+ void **pp = trie_get_try(the_network->endpoint_kinds, ep->flags.kind,
strlen(ep->flags.kind));
- if (!pp && net->missing_kind_is_error) {
+ if (!pp && the_network->missing_kind_is_error) {
kr_log_error(NETWORK, "internal error: missing kind '%s' in endpoint registry\n",
ep->flags.kind);
return;
}
}
-static void endpoint_close(struct network *net, struct endpoint *ep, bool force)
+static void endpoint_close(struct endpoint *ep, bool force)
{
const bool is_control = ep->flags.kind && strcmp(ep->flags.kind, "control") == 0;
const bool is_xdp = ep->family == AF_XDP;
kr_assert(!ep->handle);
/* Special lua-handled endpoint. */
if (ep->engaged) {
- endpoint_close_lua_cb(net, ep);
+ endpoint_close_lua_cb(ep);
}
if (ep->fd > 0) {
close(ep->fd); /* nothing to do with errors */
{
endpoint_array_t *ep_array = *val;
for (int i = 0; i < ep_array->len; ++i) {
- endpoint_close(net, &ep_array->at[i], true);
+ endpoint_close(&ep_array->at[i], true);
}
return 0;
}
return 0;
}
-void network_close_force(struct network *net)
+void network_close_force(void)
{
- if (net != NULL) {
- trie_apply(net->endpoints, close_key, net);
- trie_apply(net->endpoints, free_key, NULL);
- trie_clear(net->endpoints);
+ if (the_network != NULL) {
+ trie_apply(the_network->endpoints, close_key, the_network);
+ trie_apply(the_network->endpoints, free_key, NULL);
+ trie_clear(the_network->endpoints);
}
}
trie_it_free(it);
}
-void network_deinit(struct network *net)
+void network_unregister(void)
+{
+ network_close_force();
+ trie_apply(the_network->endpoint_kinds, kind_unregister, the_engine->L);
+}
+
+void network_deinit(void)
{
- if (net != NULL) {
- network_close_force(net);
- trie_apply(net->endpoint_kinds, kind_unregister, the_worker->engine->L);
- trie_free(net->endpoint_kinds);
- trie_free(net->endpoints);
- network_proxy_free_addr_data(net->proxy_addrs4);
- trie_free(net->proxy_addrs4);
- network_proxy_free_addr_data(net->proxy_addrs6);
- trie_free(net->proxy_addrs6);
+ trie_free(the_network->endpoint_kinds);
+ trie_free(the_network->endpoints);
+ network_proxy_free_addr_data(the_network->proxy_addrs4);
+ trie_free(the_network->proxy_addrs4);
+ network_proxy_free_addr_data(the_network->proxy_addrs6);
+ trie_free(the_network->proxy_addrs6);
- tls_credentials_free(net->tls_credentials);
- tls_client_params_free(net->tls_client_params);
- tls_session_ticket_ctx_destroy(net->tls_session_ticket_ctx);
- #ifndef NDEBUG
- memset(net, 0, sizeof(*net));
- #endif
- }
+ tls_credentials_free(the_network->tls_credentials);
+ tls_client_params_free(the_network->tls_client_params);
+ tls_session_ticket_ctx_destroy(the_network->tls_session_ticket_ctx);
+#ifndef NDEBUG
+ memset(the_network, 0, sizeof(*the_network));
+#endif
+ the_network = NULL;
}
static ssize_t endpoint_key_create(struct endpoint_key_storage *dst,
}
/** Fetch or create endpoint array and insert endpoint (shallow memcpy). */
-static int insert_endpoint(struct network *net, const char *addr_str,
+static int insert_endpoint(const char *addr_str,
const struct sockaddr *addr, struct endpoint *ep)
{
/* Fetch or insert address into map */
ssize_t keylen = endpoint_key_create(&key, addr_str, addr);
if (keylen < 0)
return keylen;
- trie_val_t *val = trie_get_ins(net->endpoints, key.bytes, keylen);
+ trie_val_t *val = trie_get_ins(the_network->endpoints, key.bytes, keylen);
endpoint_array_t *ep_array;
if (*val) {
ep_array = *val;
/** Open endpoint protocols. ep->flags were pre-set.
* \p addr_str is only used for logging or for XDP "address". */
-static int open_endpoint(struct network *net, const char *addr_str,
+static int open_endpoint(const char *addr_str,
struct endpoint *ep, const struct sockaddr *sa)
{
const bool is_control = ep->flags.kind && strcmp(ep->flags.kind, "control") == 0;
}
if (ep->flags.kind && !is_control && !is_xdp) {
/* This EP isn't to be managed internally after binding. */
- return endpoint_open_lua_cb(net, ep, addr_str);
+ return endpoint_open_lua_cb(ep, addr_str);
} else {
ep->engaged = true;
/* .engaged seems not really meaningful in this case, but... */
uv_pipe_t *ep_handle = malloc(sizeof(uv_pipe_t));
ep->handle = (uv_handle_t *)ep_handle;
ret = !ep->handle ? ENOMEM
- : io_listen_pipe(net->loop, ep_handle, ep->fd);
+ : io_listen_pipe(the_network->loop, ep_handle, ep->fd);
goto finish_ret;
}
uv_poll_t *ep_handle = malloc(sizeof(uv_poll_t));
ep->handle = (uv_handle_t *)ep_handle;
ret = !ep->handle ? ENOMEM
- : io_listen_xdp(net->loop, ep, addr_str);
+ : io_listen_xdp(the_network->loop, ep, addr_str);
#else
ret = ESOCKTNOSUPPORT;
#endif
uv_udp_t *ep_handle = malloc(sizeof(uv_udp_t));
ep->handle = (uv_handle_t *)ep_handle;
ret = !ep->handle ? ENOMEM
- : io_listen_udp(net->loop, ep_handle, ep->fd);
+ : io_listen_udp(the_network->loop, ep_handle, ep->fd);
goto finish_ret;
} /* else */
uv_tcp_t *ep_handle = malloc(sizeof(uv_tcp_t));
ep->handle = (uv_handle_t *)ep_handle;
ret = !ep->handle ? ENOMEM
- : io_listen_tcp(net->loop, ep_handle, ep->fd,
- net->tcp_backlog, ep->flags.tls, ep->flags.http);
+ : io_listen_tcp(the_network->loop, ep_handle, ep->fd,
+ the_network->tcp_backlog, ep->flags.tls, ep->flags.http);
goto finish_ret;
} /* else */
* Beware that there might be multiple matches, though that's not common.
* The matching isn't really precise in the sense that it might not find
* and endpoint that would *collide* the passed one. */
-static struct endpoint * endpoint_get(struct network *net,
- const char *addr_str,
+static struct endpoint * endpoint_get(const char *addr_str,
const struct sockaddr *sa,
endpoint_flags_t flags)
{
ssize_t keylen = endpoint_key_create(&key, addr_str, sa);
if (keylen < 0)
return NULL;
- trie_val_t *val = trie_get_try(net->endpoints, key.bytes, keylen);
+ trie_val_t *val = trie_get_try(the_network->endpoints, key.bytes, keylen);
if (!val)
return NULL;
endpoint_array_t *ep_array = *val;
/** \note pass (either sa != NULL xor ep.fd != -1) or XDP case (neither sa nor ep.fd)
* \note in XDP case addr_str is interface name
* \note ownership of ep.flags.* is taken on success. */
-static int create_endpoint(struct network *net, const char *addr_str,
+static int create_endpoint(const char *addr_str,
struct endpoint *ep, const struct sockaddr *sa)
{
- int ret = open_endpoint(net, addr_str, ep, sa);
+ int ret = open_endpoint(addr_str, ep, sa);
if (ret == 0) {
- ret = insert_endpoint(net, addr_str, sa, ep);
+ ret = insert_endpoint(addr_str, sa, ep);
}
if (ret != 0 && ep->handle) {
- endpoint_close(net, ep, false);
+ endpoint_close(ep, false);
}
return ret;
}
-int network_listen_fd(struct network *net, int fd, endpoint_flags_t flags)
+int network_listen_fd(int fd, endpoint_flags_t flags)
{
if (kr_fails_assert(!flags.xdp))
return kr_error(EINVAL);
/* always create endpoint for supervisor supplied fd
* even if addr+port is not unique */
- return create_endpoint(net, addr_str, &ep, (struct sockaddr *) &ss);
+ return create_endpoint(addr_str, &ep, (struct sockaddr *) &ss);
}
/** Try selecting XDP queue automatically. */
return -1;
}
-int network_listen(struct network *net, const char *addr, uint16_t port,
+int network_listen(const char *addr, uint16_t port,
int16_t nic_queue, endpoint_flags_t flags)
{
- if (kr_fails_assert(net != NULL && addr != 0 && nic_queue >= -1))
+ if (kr_fails_assert(the_network != NULL && addr != 0 && nic_queue >= -1))
return kr_error(EINVAL);
if (flags.xdp && nic_queue < 0) {
}
// XDP: if addr failed to parse as address, we assume it's an interface name.
- if (endpoint_get(net, addr, sa, flags)) {
+ if (endpoint_get(addr, sa, flags)) {
return kr_error(EADDRINUSE); // Already listening
}
ep.family = flags.xdp ? AF_XDP : sa->sa_family;
ep.nic_queue = nic_queue;
- int ret = create_endpoint(net, addr, &ep, sa);
+ int ret = create_endpoint(addr, &ep, sa);
// Error reporting: more precision.
if (ret == KNOT_EINVAL && !sa && flags.xdp && ENABLE_XDP) {
return ret;
}
-int network_proxy_allow(struct network *net, const char* addr)
+int network_proxy_allow(const char* addr)
{
- if (kr_fails_assert(net != NULL && addr != NULL))
+ if (kr_fails_assert(the_network != NULL && addr != NULL))
return kr_error(EINVAL);
int family = kr_straddr_family(addr);
/* Netmask is zero: allow all addresses to use PROXYv2 */
switch (family) {
case AF_INET:
- net->proxy_all4 = true;
+ the_network->proxy_all4 = true;
break;
case AF_INET6:
- net->proxy_all6 = true;
+ the_network->proxy_all6 = true;
break;
default:
kr_assert(false);
switch (family) {
case AF_INET:
addr_length = sizeof(ia.ip4);
- trie = net->proxy_addrs4;
+ trie = the_network->proxy_addrs4;
break;
case AF_INET6:
addr_length = sizeof(ia.ip6);
- trie = net->proxy_addrs6;
+ trie = the_network->proxy_addrs6;
break;
default:
kr_assert(false);
return kr_ok();
}
-void network_proxy_reset(struct network *net)
+void network_proxy_reset(void)
{
- net->proxy_all4 = false;
- network_proxy_free_addr_data(net->proxy_addrs4);
- trie_clear(net->proxy_addrs4);
- net->proxy_all6 = false;
- network_proxy_free_addr_data(net->proxy_addrs6);
- trie_clear(net->proxy_addrs6);
+ the_network->proxy_all4 = false;
+ network_proxy_free_addr_data(the_network->proxy_addrs4);
+ trie_clear(the_network->proxy_addrs4);
+ the_network->proxy_all6 = false;
+ network_proxy_free_addr_data(the_network->proxy_addrs6);
+ trie_clear(the_network->proxy_addrs6);
}
-static int endpoints_close(struct network *net,
- struct endpoint_key_storage *key, ssize_t keylen,
+static int endpoints_close(struct endpoint_key_storage *key, ssize_t keylen,
endpoint_array_t *ep_array, int port)
{
size_t i = 0;
while (i < ep_array->len) {
struct endpoint *ep = &ep_array->at[i];
if (port < 0 || ep->port == port) {
- endpoint_close(net, ep, false);
+ endpoint_close(ep, false);
array_del(*ep_array, i);
matched = true;
/* do not advance i */
typedef array_t(struct endpoint_key_with_len) endpoint_key_array_t;
struct endpoint_close_wildcard_context {
- struct network *net;
struct endpoint_key_storage *match_key;
endpoint_key_array_t del;
int ret;
return kr_ok();
endpoint_array_t *ep_array = *val;
- int ret = endpoints_close(ctx->net, key, keylen, ep_array, -1);
+ int ret = endpoints_close(key, keylen, ep_array, -1);
if (ret)
ctx->ret = ret;
return kr_ok();
}
-int network_close(struct network *net, const char *addr_str, int port)
+int network_close(const char *addr_str, int port)
{
auto_free struct sockaddr *addr = kr_straddr_socket(addr_str, port, NULL);
struct endpoint_key_storage key;
if (port < 0) {
struct endpoint_close_wildcard_context ctx = {
- .net = net,
.match_key = &key
};
array_init(ctx.del);
- trie_apply_with_key(net->endpoints, endpoints_close_wildcard, &ctx);
+ trie_apply_with_key(the_network->endpoints,
+ endpoints_close_wildcard, &ctx);
for (size_t i = 0; i < ctx.del.len; i++) {
trie_val_t val;
- trie_del(net->endpoints,
+ trie_del(the_network->endpoints,
ctx.del.at[i].key.bytes, ctx.del.at[i].keylen,
&val);
if (val) {
return ctx.ret;
}
- trie_val_t *val = trie_get_try(net->endpoints, key.bytes, keylen);
+ trie_val_t *val = trie_get_try(the_network->endpoints, key.bytes, keylen);
if (!val)
return kr_error(ENOENT);
endpoint_array_t *ep_array = *val;
- int ret = endpoints_close(net, &key, keylen, ep_array, port);
+ int ret = endpoints_close(&key, keylen, ep_array, port);
/* Collapse key if it has no endpoint. */
if (ep_array->len == 0) {
array_clear(*ep_array);
free(ep_array);
- trie_del(net->endpoints, key.bytes, keylen, NULL);
+ trie_del(the_network->endpoints, key.bytes, keylen, NULL);
}
return ret;
}
-void network_new_hostname(struct network *net, struct engine *engine)
+void network_new_hostname(void)
{
- if (net->tls_credentials &&
- net->tls_credentials->ephemeral_servicename) {
+ if (the_network->tls_credentials &&
+ the_network->tls_credentials->ephemeral_servicename) {
struct tls_credentials *newcreds;
- newcreds = tls_get_ephemeral_credentials(engine);
+ newcreds = tls_get_ephemeral_credentials();
if (newcreds) {
- tls_credentials_release(net->tls_credentials);
- net->tls_credentials = newcreds;
+ tls_credentials_release(the_network->tls_credentials);
+ the_network->tls_credentials = newcreds;
kr_log_info(TLS, "Updated ephemeral X.509 cert with new hostname\n");
} else {
kr_log_error(TLS, "Failed to update ephemeral X.509 cert with new hostname, using existing one\n");
}
#endif
-int network_set_bpf(struct network *net, int bpf_fd)
+int network_set_bpf(int bpf_fd)
{
#ifdef SO_ATTACH_BPF
- if (trie_apply(net->endpoints, set_bpf_cb, &bpf_fd) != 0) {
+ if (trie_apply(the_network->endpoints, set_bpf_cb, &bpf_fd) != 0) {
/* set_bpf_cb() has returned error. */
- network_clear_bpf(net);
+ network_clear_bpf();
return 0;
}
#else
kr_log_error(NETWORK, "SO_ATTACH_BPF socket option doesn't supported\n");
- (void)net;
(void)bpf_fd;
return 0;
#endif
}
#endif
-void network_clear_bpf(struct network *net)
+void network_clear_bpf(void)
{
#ifdef SO_DETACH_BPF
- trie_apply(net->endpoints, clear_bpf_cb, NULL);
+ trie_apply(the_network->endpoints, clear_bpf_cb, NULL);
#else
kr_log_error(NETWORK, "SO_DETACH_BPF socket option doesn't supported\n");
- (void)net;
#endif
}
int tcp_backlog;
};
-void network_init(struct network *net, uv_loop_t *loop, int tcp_backlog);
-void network_deinit(struct network *net);
+/** Pointer to the singleton network state. NULL if not initialized. */
+KR_EXPORT extern struct network *the_network;
+
+/** Initializes the network. */
+void network_init(uv_loop_t *loop, int tcp_backlog);
+
+/** Unregisters endpoints. Should be called before `network_deinit`
+ * and `engine_deinit`. */
+void network_unregister(void);
+
+/** Deinitializes the network. `network_unregister` should be called before
+ * this and before `engine_deinit`. */
+void network_deinit(void);
/** Start listening on addr#port with flags.
* \note if we did listen on that combination already,
* \note In XDP mode, addr may be also interface name, so kr_error(ENODEV)
* is returned if some nonsense is passed
*/
-int network_listen(struct network *net, const char *addr, uint16_t port,
+int network_listen(const char *addr, uint16_t port,
int16_t nic_queue, endpoint_flags_t flags);
/** Allow the specified address to send the PROXYv2 header.
* \note the address may be specified with a netmask
*/
-int network_proxy_allow(struct network *net, const char* addr);
+int network_proxy_allow(const char* addr);
/** Reset all addresses allowed to send the PROXYv2 header. No addresses will
* be allowed to send PROXYv2 headers from the point of calling this function
* until re-allowed via network_proxy_allow again.
*/
-void network_proxy_reset(struct network *net);
+void network_proxy_reset(void);
/** Start listening on an open file-descriptor.
* \note flags.sock_type isn't meaningful here.
* \note ownership of flags.* is taken on success. TODO: non-success?
*/
-int network_listen_fd(struct network *net, int fd, endpoint_flags_t flags);
+int network_listen_fd(int fd, endpoint_flags_t flags);
/** Stop listening on all endpoints with matching addr#port.
* port < 0 serves as a wild-card.
* \return kr_error(ENOENT) if nothing matched. */
-int network_close(struct network *net, const char *addr, int port);
+int network_close(const char *addr, int port);
/** Close all endpoints immediately (no waiting for UV loop). */
-void network_close_force(struct network *net);
+void network_close_force(void);
/** Enforce that all endpoints are registered from now on.
* This only does anything with struct endpoint::flags.kind != NULL. */
-int network_engage_endpoints(struct network *net);
+int network_engage_endpoints(void);
/** Returns a string representation of the specified endpoint key.
*
* The result points into key or is on static storage like for kr_straddr() */
const char *network_endpoint_key_str(const struct endpoint_key *key);
-int network_set_tls_cert(struct network *net, const char *cert);
-int network_set_tls_key(struct network *net, const char *key);
-void network_new_hostname(struct network *net, struct engine *engine);
-int network_set_bpf(struct network *net, int bpf_fd);
-void network_clear_bpf(struct network *net);
+int network_set_tls_cert(const char *cert);
+int network_set_tls_key(const char *key);
+void network_new_hostname(void);
+int network_set_bpf(int bpf_fd);
+void network_clear_bpf(void);
-/* Copyright (C) 2014-2020 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+/* Copyright (C) 2014-2022 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
-#include "daemon/proxyv2.h"
-
+#include "daemon/network.h"
#include "lib/generic/trie.h"
+#include "daemon/proxyv2.h"
+
const char PROXY2_SIGNATURE[12] = {
0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A
};
}
-bool proxy_allowed(const struct network *net, const struct sockaddr *saddr)
+bool proxy_allowed(const struct sockaddr *saddr)
{
union kr_in_addr addr;
trie_t *trie;
size_t addr_size;
switch (saddr->sa_family) {
case AF_INET:
- if (net->proxy_all4)
+ if (the_network->proxy_all4)
return true;
- trie = net->proxy_addrs4;
+ trie = the_network->proxy_addrs4;
addr_size = sizeof(addr.ip4);
addr.ip4 = ((struct sockaddr_in *) saddr)->sin_addr;
break;
case AF_INET6:
- if (net->proxy_all6)
+ if (the_network->proxy_all6)
return true;
- trie = net->proxy_addrs6;
+ trie = the_network->proxy_addrs6;
addr_size = sizeof(addr.ip6);
addr.ip6 = ((struct sockaddr_in6 *) saddr)->sin6_addr;
break;
#include <stdint.h>
#include "daemon/session.h"
-#include "daemon/network.h"
#include "lib/utils.h"
extern const char PROXY2_SIGNATURE[12];
/** Checks whether the use of PROXYv2 protocol is allowed for the specified
* address. */
-bool proxy_allowed(const struct network *net, const struct sockaddr *saddr);
+bool proxy_allowed(const struct sockaddr *saddr);
/** Parses the PROXYv2 header from buf of size nread and writes the result into
* out. The rest of the buffer is moved to free bytes of the specified session's
}
-struct tls_ctx *tls_new(struct worker_ctx *worker)
+struct tls_ctx *tls_new(void)
{
- if (kr_fails_assert(worker && worker->engine))
+ if (kr_fails_assert(the_worker && the_engine))
return NULL;
- struct network *net = &worker->engine->net;
- if (!net->tls_credentials) {
- net->tls_credentials = tls_get_ephemeral_credentials(worker->engine);
- if (!net->tls_credentials) {
+ if (!the_network->tls_credentials) {
+ the_network->tls_credentials = tls_get_ephemeral_credentials();
+ if (!the_network->tls_credentials) {
kr_log_error(TLS, "X.509 credentials are missing, and ephemeral credentials failed; no TLS\n");
return NULL;
}
kr_log_info(TLS, "Using ephemeral TLS credentials\n");
- tls_credentials_log_pins(net->tls_credentials);
+ tls_credentials_log_pins(the_network->tls_credentials);
}
time_t now = time(NULL);
- if (net->tls_credentials->valid_until != GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION) {
- if (net->tls_credentials->ephemeral_servicename) {
+ if (the_network->tls_credentials->valid_until != GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION) {
+ if (the_network->tls_credentials->ephemeral_servicename) {
/* ephemeral cert: refresh if due to expire within a week */
- if (now >= net->tls_credentials->valid_until - EPHEMERAL_CERT_EXPIRATION_SECONDS_RENEW_BEFORE) {
- struct tls_credentials *newcreds = tls_get_ephemeral_credentials(worker->engine);
+ if (now >= the_network->tls_credentials->valid_until - EPHEMERAL_CERT_EXPIRATION_SECONDS_RENEW_BEFORE) {
+ struct tls_credentials *newcreds = tls_get_ephemeral_credentials();
if (newcreds) {
- tls_credentials_release(net->tls_credentials);
- net->tls_credentials = newcreds;
+ tls_credentials_release(the_network->tls_credentials);
+ the_network->tls_credentials = newcreds;
kr_log_info(TLS, "Renewed expiring ephemeral X.509 cert\n");
} else {
kr_log_error(TLS, "Failed to renew expiring ephemeral X.509 cert, using existing one\n");
}
} else {
/* non-ephemeral cert: warn once when certificate expires */
- if (now >= net->tls_credentials->valid_until) {
+ if (now >= the_network->tls_credentials->valid_until) {
kr_log_error(TLS, "X.509 certificate has expired!\n");
- net->tls_credentials->valid_until = GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION;
+ the_network->tls_credentials->valid_until = GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION;
}
}
}
tls_free(tls);
return NULL;
}
- tls->credentials = tls_credentials_reserve(net->tls_credentials);
+ tls->credentials = tls_credentials_reserve(the_network->tls_credentials);
err = gnutls_credentials_set(tls->c.tls_session, GNUTLS_CRD_CERTIFICATE,
tls->credentials->credentials);
if (err != GNUTLS_E_SUCCESS) {
return NULL;
}
- tls->c.worker = worker;
tls->c.client_side = false;
gnutls_transport_set_pull_function(tls->c.tls_session, kres_gnutls_pull);
gnutls_transport_set_vec_push_function(tls->c.tls_session, kres_gnutls_vec_push);
gnutls_transport_set_ptr(tls->c.tls_session, tls);
- if (net->tls_session_ticket_ctx) {
- tls_session_ticket_enable(net->tls_session_ticket_ctx,
+ if (the_network->tls_session_ticket_ctx) {
+ tls_session_ticket_enable(the_network->tls_session_ticket_ctx,
tls->c.tls_session);
}
return ret;
}
-int tls_certificate_set(struct network *net, const char *tls_cert, const char *tls_key)
+int tls_certificate_set(const char *tls_cert, const char *tls_key)
{
- if (!net) {
+ if (kr_fails_assert(the_network)) {
return kr_error(EINVAL);
}
tls_credentials->valid_until = _get_end_entity_expiration(tls_credentials->credentials);
/* Exchange the x509 credentials */
- struct tls_credentials *old_credentials = net->tls_credentials;
+ struct tls_credentials *old_credentials = the_network->tls_credentials;
/* Start using the new x509_credentials */
- net->tls_credentials = tls_credentials;
- tls_credentials_log_pins(net->tls_credentials);
+ the_network->tls_credentials = tls_credentials;
+ tls_credentials_log_pins(the_network->tls_credentials);
if (old_credentials) {
err = tls_credentials_release(old_credentials);
return client_verify_certchain(ctx->c.tls_session, ctx->params->hostname);
}
-struct tls_client_ctx *tls_client_ctx_new(tls_client_param_t *entry,
- struct worker_ctx *worker)
+struct tls_client_ctx *tls_client_ctx_new(tls_client_param_t *entry)
{
struct tls_client_ctx *ctx = calloc(1, sizeof (struct tls_client_ctx));
if (!ctx) {
return NULL;
}
- ctx->c.worker = worker;
ctx->c.client_side = true;
gnutls_transport_set_pull_function(ctx->c.tls_session, kres_gnutls_pull);
struct tls_common_ctx *ctx = &client_ctx->c;
gnutls_session_set_ptr(ctx->tls_session, client_ctx);
- gnutls_handshake_set_timeout(ctx->tls_session, ctx->worker->engine->net.tcp.tls_handshake_timeout);
+ gnutls_handshake_set_timeout(ctx->tls_session, the_network->tcp.tls_handshake_timeout);
gnutls_transport_set_pull_timeout_function(ctx->tls_session, tls_pull_timeout_func);
session_tls_set_client_ctx(session, client_ctx);
ctx->handshake_cb = handshake_cb;
ssize_t consumed;
uint8_t recv_buf[16384];
tls_handshake_cb handshake_cb;
- struct worker_ctx *worker;
size_t write_queue_size;
};
};
/*! Create an empty TLS context in query context */
-struct tls_ctx* tls_new(struct worker_ctx *worker);
+struct tls_ctx* tls_new(void);
/*! Close a TLS context (call gnutls_bye()) */
void tls_close(struct tls_common_ctx *ctx);
ssize_t tls_process_input_data(struct session *s, const uint8_t *buf, ssize_t nread);
/*! Set TLS certificate and key from files. */
-int tls_certificate_set(struct network *net, const char *tls_cert, const char *tls_key);
+int tls_certificate_set(const char *tls_cert, const char *tls_key);
/*! Borrow TLS credentials for context. */
struct tls_credentials *tls_credentials_reserve(struct tls_credentials *tls_credentials);
void tls_credentials_log_pins(struct tls_credentials *tls_credentials);
/*! Generate new ephemeral TLS credentials. */
-struct tls_credentials * tls_get_ephemeral_credentials(struct engine *engine);
+struct tls_credentials * tls_get_ephemeral_credentials();
/*! Get TLS handshake state. */
tls_hs_state_t tls_get_hs_state(const struct tls_common_ctx *ctx);
/*! Allocate new client TLS context */
-struct tls_client_ctx *tls_client_ctx_new(tls_client_param_t *entry,
- struct worker_ctx *worker);
+struct tls_client_ctx *tls_client_ctx_new(tls_client_param_t *entry);
/*! Free client TLS context */
void tls_client_ctx_free(struct tls_client_ctx *ctx);
/*
* Copyright (C) 2016 American Civil Liberties Union (ACLU)
* Copyright (C) 2016-2017 CZ.NIC, z.s.p.o.
- *
+ *
* Initial Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
* SPDX-License-Identifier: GPL-3.0-or-later
*/
kr_log_error(TLS, "unable to lock lockfile " EPHEMERAL_PRIVKEY_FILENAME ".lock\n");
goto done;
}
-
+
if ((err = gnutls_x509_privkey_init (&privkey)) < 0) {
kr_log_error(TLS, "gnutls_x509_privkey_init() failed: %d (%s)\n",
err, gnutls_strerror_name(err));
return NULL;
}
-struct tls_credentials * tls_get_ephemeral_credentials(struct engine *engine)
+struct tls_credentials * tls_get_ephemeral_credentials()
{
struct tls_credentials *creds = NULL;
gnutls_x509_privkey_t privkey = NULL;
}
creds->valid_until = now + EPHEMERAL_CERT_EXPIRATION_SECONDS;
- creds->ephemeral_servicename = strdup(engine_get_hostname(engine));
+ creds->ephemeral_servicename = strdup(engine_get_hostname());
if (creds->ephemeral_servicename == NULL) {
kr_log_error(TLS, "could not get server's hostname, using '" INVALID_HOSTNAME "' instead\n");
if ((creds->ephemeral_servicename = strdup(INVALID_HOSTNAME)) == NULL) {
kr_log_error(TLS, "failed to allocate memory for ephemeral credentials\n");
goto failure;
}
- }
+ }
if ((privkey = get_ephemeral_privkey()) == NULL) {
goto failure;
}
{
struct kr_request req;
- struct worker_ctx *worker;
struct qr_task *task;
struct {
/** NULL if the request didn't come over network. */
const struct sockaddr *addr, knot_pkt_t *pkt);
static int qr_task_finalize(struct qr_task *task, int state);
static void qr_task_complete(struct qr_task *task);
-struct session* worker_find_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr *addr);
-static int worker_add_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr *addr,
- struct session *session);
-struct session* worker_find_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr *addr);
+static int worker_add_tcp_waiting(const struct sockaddr* addr, struct session *session);
static void on_tcp_connect_timeout(uv_timer_t *timer);
static void on_udp_timeout(uv_timer_t *timer);
static void subreq_finalize(struct qr_task *task, const struct sockaddr *packet_source, knot_pkt_t *pkt);
/*! @internal Create a UDP/TCP handle for an outgoing AF_INET* connection.
* socktype is SOCK_* */
-static uv_handle_t *ioreq_spawn(struct worker_ctx *worker,
- int socktype, sa_family_t family, bool has_tls,
+static uv_handle_t *ioreq_spawn(int socktype, sa_family_t family, bool has_tls,
bool has_http)
{
bool precond = (socktype == SOCK_DGRAM || socktype == SOCK_STREAM)
if (!handle) {
return NULL;
}
- int ret = io_create(worker->loop, handle, socktype, family, has_tls, has_http);
+ int ret = io_create(the_worker->loop, handle, socktype, family, has_tls, has_http);
if (ret) {
if (ret == UV_EMFILE) {
- worker->too_many_open = true;
- worker->rconcurrent_highwatermark = worker->stats.rconcurrent;
+ the_worker->too_many_open = true;
+ the_worker->rconcurrent_highwatermark = the_worker->stats.rconcurrent;
}
free(handle);
return NULL;
/* Bind to outgoing address, according to IP v4/v6. */
union kr_sockaddr *addr;
if (family == AF_INET) {
- addr = (union kr_sockaddr *)&worker->out_addr4;
+ addr = (union kr_sockaddr *)&the_worker->out_addr4;
} else {
- addr = (union kr_sockaddr *)&worker->out_addr6;
+ addr = (union kr_sockaddr *)&the_worker->out_addr6;
}
if (addr->ip.sa_family != AF_UNSPEC) {
if (kr_fails_assert(addr->ip.sa_family == family)) {
/** @endcond */
/** Get a mempool. (Recycle if possible.) */
-static inline struct mempool *pool_borrow(struct worker_ctx *worker)
+static inline struct mempool *pool_borrow(void)
{
struct mempool *mp = NULL;
- if (worker->pool_mp.len > 0) {
- mp = array_tail(worker->pool_mp);
- array_pop(worker->pool_mp);
+ if (the_worker->pool_mp.len > 0) {
+ mp = array_tail(the_worker->pool_mp);
+ array_pop(the_worker->pool_mp);
mp_poison(mp, 0);
} else { /* No mempool on the freelist, create new one */
mp = mp_new (4 * CPU_PAGE_SIZE);
}
/** Return a mempool. (Cache them up to some count.) */
-static inline void pool_release(struct worker_ctx *worker, struct mempool *mp)
+static inline void pool_release(struct mempool *mp)
{
- if (worker->pool_mp.len < MP_FREELIST_SIZE) {
+ if (the_worker->pool_mp.len < MP_FREELIST_SIZE) {
mp_flush(mp);
- array_push(worker->pool_mp, mp);
+ array_push(the_worker->pool_mp, mp);
mp_poison(mp, 1);
} else {
mp_delete(mp);
#endif
/* Helper functions for transport selection */
static inline bool is_tls_capable(struct sockaddr *address) {
- tls_client_param_t *tls_entry = tls_client_param_get(the_worker->engine->net.tls_client_params, address);
+ tls_client_param_t *tls_entry = tls_client_param_get(
+ the_network->tls_client_params, address);
return tls_entry;
}
static inline bool is_tcp_connected(struct sockaddr *address) {
- return worker_find_tcp_connected(the_worker, address);
+ return worker_find_tcp_connected(address);
}
static inline bool is_tcp_waiting(struct sockaddr *address) {
- return worker_find_tcp_waiting(the_worker, address);
+ return worker_find_tcp_waiting(address);
}
/** Create and initialize a request_ctx (on a fresh mempool).
* session and addr point to the source of the request, and they are NULL
* in case the request didn't come from network.
*/
-static struct request_ctx *request_create(struct worker_ctx *worker,
- struct session *session,
+static struct request_ctx *request_create(struct session *session,
struct io_comm_data *comm,
const uint8_t *eth_from,
const uint8_t *eth_to,
uint32_t uid)
{
knot_mm_t pool = {
- .ctx = pool_borrow(worker),
+ .ctx = pool_borrow(),
.alloc = (knot_mm_alloc_t) mp_alloc
};
/* Create request context */
struct request_ctx *ctx = mm_calloc(&pool, 1, sizeof(*ctx));
if (!ctx) {
- pool_release(worker, pool.ctx);
+ pool_release(pool.ctx);
return NULL;
}
/* TODO Relocate pool to struct request */
- ctx->worker = worker;
if (session && kr_fails_assert(session_flags(session)->outgoing == false)) {
- pool_release(worker, pool.ctx);
+ pool_release(pool.ctx);
return NULL;
}
ctx->source.session = session;
if (kr_fails_assert(!!eth_to == !!eth_from)) {
- pool_release(worker, pool.ctx);
+ pool_release(pool.ctx);
return NULL;
}
const bool is_xdp = eth_to != NULL;
if (is_xdp) {
#if ENABLE_XDP
if (kr_fails_assert(session)) {
- pool_release(worker, pool.ctx);
+ pool_release(pool.ctx);
return NULL;
}
memcpy(&ctx->source.eth_addrs[0], eth_to, sizeof(ctx->source.eth_addrs[0]));
ctx->req.alloc_wire_cb = alloc_wire_cb;
#else
kr_assert(!EINVAL);
- pool_release(worker, pool.ctx);
+ pool_release(pool.ctx);
return NULL;
#endif
}
array_init(req->selection_context.forwarding_targets);
array_reserve_mm(req->selection_context.forwarding_targets, 1, kr_memreserve, &req->pool);
- worker->stats.rconcurrent += 1;
+ the_worker->stats.rconcurrent += 1;
return ctx;
}
req->qsource.packet = pkt;
/* Start resolution */
- struct worker_ctx *worker = ctx->worker;
- struct engine *engine = worker->engine;
- kr_resolve_begin(req, &engine->resolver);
- worker->stats.queries += 1;
+ kr_resolve_begin(req, the_resolver);
+ the_worker->stats.queries += 1;
return kr_ok();
}
static void request_free(struct request_ctx *ctx)
{
- struct worker_ctx *worker = ctx->worker;
/* Dereference any Lua vars table if exists */
if (ctx->req.vars_ref != LUA_NOREF) {
- lua_State *L = worker->engine->L;
+ lua_State *L = the_engine->L;
/* Get worker variables table */
- lua_rawgeti(L, LUA_REGISTRYINDEX, worker->vars_table_ref);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, the_worker->vars_table_ref);
/* Get next free element (position 0) and store it under current reference (forming a list) */
lua_rawgeti(L, -1, 0);
lua_rawseti(L, -2, ctx->req.vars_ref);
#endif
}
/* Return mempool to ring or free it if it's full */
- pool_release(worker, ctx->req.pool.ctx);
+ pool_release(ctx->req.pool.ctx);
/* @note The 'task' is invalidated from now on. */
- worker->stats.rconcurrent -= 1;
+ the_worker->stats.rconcurrent -= 1;
}
static struct qr_task *qr_task_create(struct request_ctx *ctx)
* for UDP answers from upstream *and* from cache
* and for sending queries upstream */
uint16_t pktbuf_max = KR_EDNS_PAYLOAD;
- const knot_rrset_t *opt_our = ctx->worker->engine->resolver.upstream_opt_rr;
+ const knot_rrset_t *opt_our = the_resolver->upstream_opt_rr;
if (opt_our) {
pktbuf_max = MAX(pktbuf_max, knot_edns_get_payload(opt_our));
}
/* Make the primary reference to task. */
qr_task_ref(task);
task->creation_time = kr_now();
- ctx->worker->stats.concurrent += 1;
+ the_worker->stats.concurrent += 1;
return task;
}
if (kr_fails_assert(ctx))
return;
- struct worker_ctx *worker = ctx->worker;
-
if (ctx->task == NULL) {
request_free(ctx);
}
/* Update stats */
- worker->stats.concurrent -= 1;
+ the_worker->stats.concurrent -= 1;
}
/*@ Register new qr_task within session. */
* an in effect shrink TCP window size. To get more precise throttling,
* we would need to copy remainder of the unread buffer and reassemble
* when resuming reading. This is NYI. */
- if (session_tasklist_get_len(session) >= task->ctx->worker->tcp_pipeline_max &&
+ if (session_tasklist_get_len(session) >= the_worker->tcp_pipeline_max &&
!session_flags(session)->throttled && !session_flags(session)->closing) {
session_stop_read(session);
session_flags(session)->throttled = true;
if (session_flags(s)->outgoing || session_flags(s)->closing)
return status;
- struct worker_ctx *worker = task->ctx->worker;
if (session_flags(s)->throttled &&
- session_tasklist_get_len(s) < worker->tcp_pipeline_max/2) {
+ session_tasklist_get_len(s) < the_worker->tcp_pipeline_max/2) {
/* Start reading again if the session is throttled and
* the number of outgoing requests is below watermark. */
session_start_read(s);
worker_task_pkt_set_msgid(task, msg_id);
}
- struct worker_ctx *worker = ctx->worker;
/* Note time for upstream RTT */
task->send_time = kr_now();
task->recv_time = 0; // task structure is being reused so we have to zero this out here
if (session_flags(session)->outgoing) {
session_tasklist_add(session, task);
}
- if (worker->too_many_open &&
- worker->stats.rconcurrent <
- worker->rconcurrent_highwatermark - 10) {
- worker->too_many_open = false;
+ if (the_worker->too_many_open &&
+ the_worker->stats.rconcurrent <
+ the_worker->rconcurrent_highwatermark - 10) {
+ the_worker->too_many_open = false;
}
} else {
free(ioreq);
qr_task_unref(task);
if (ret == UV_EMFILE) {
- worker->too_many_open = true;
- worker->rconcurrent_highwatermark = worker->stats.rconcurrent;
+ the_worker->too_many_open = true;
+ the_worker->rconcurrent_highwatermark = the_worker->stats.rconcurrent;
ret = kr_error(UV_EMFILE);
}
if (session_flags(session)->has_http)
- worker->stats.err_http += 1;
+ the_worker->stats.err_http += 1;
else if (session_flags(session)->has_tls)
- worker->stats.err_tls += 1;
+ the_worker->stats.err_tls += 1;
else if (handle->type == UV_UDP)
- worker->stats.err_udp += 1;
+ the_worker->stats.err_udp += 1;
else
- worker->stats.err_tcp += 1;
+ the_worker->stats.err_tcp += 1;
}
/* Update outgoing query statistics */
if (session_flags(session)->outgoing && addr) {
if (session_flags(session)->has_tls)
- worker->stats.tls += 1;
+ the_worker->stats.tls += 1;
else if (handle->type == UV_UDP)
- worker->stats.udp += 1;
+ the_worker->stats.udp += 1;
else
- worker->stats.tcp += 1;
+ the_worker->stats.tcp += 1;
if (addr->sa_family == AF_INET6)
- worker->stats.ipv6 += 1;
+ the_worker->stats.ipv6 += 1;
else if (addr->sa_family == AF_INET)
- worker->stats.ipv4 += 1;
+ the_worker->stats.ipv4 += 1;
}
return ret;
}
if (kr_fails_assert(session_flags(session)->outgoing))
return kr_error(EINVAL);
struct sockaddr *peer = session_get_peer(session);
- int deletion_res = worker_del_tcp_waiting(the_worker, peer);
+ int deletion_res = worker_del_tcp_waiting(peer);
int ret = kr_ok();
if (status) {
}
}
- struct session *s = worker_find_tcp_connected(the_worker, peer);
+ struct session *s = worker_find_tcp_connected(peer);
ret = kr_ok();
if (deletion_res == kr_ok()) {
/* peer was in the waiting list, add to the connected list. */
* peer already is in the connected list. */
ret = kr_error(EINVAL);
} else {
- ret = worker_add_tcp_connected(the_worker, peer, session);
+ ret = worker_add_tcp_connected(peer, session);
}
} else {
/* peer wasn't in the waiting list.
/* Something went wrong.
* Either addition to the list of connected sessions
* or write to upstream failed. */
- worker_del_tcp_connected(the_worker, peer);
+ worker_del_tcp_connected(peer);
session_waitinglist_finalize(session, KR_STATE_FAIL);
session_tasklist_finalize(session, KR_STATE_FAIL);
session_close(session);
struct qr_task *t = session_waitinglist_get(session);
ret = qr_task_send(t, session, NULL, NULL);
if (ret != 0) {
- struct worker_ctx *worker = t->ctx->worker;
struct sockaddr *peer = session_get_peer(session);
session_waitinglist_finalize(session, KR_STATE_FAIL);
session_tasklist_finalize(session, KR_STATE_FAIL);
- worker_del_tcp_connected(worker, peer);
+ worker_del_tcp_connected(peer);
session_close(session);
break;
}
static void on_connect(uv_connect_t *req, int status)
{
- struct worker_ctx *worker = the_worker;
- kr_require(worker);
+ kr_require(the_worker);
uv_stream_t *handle = req->handle;
struct session *session = handle->data;
struct sockaddr *peer = session_get_peer(session);
return;
if (session_flags(session)->closing) {
- worker_del_tcp_waiting(worker, peer);
+ worker_del_tcp_waiting(peer);
kr_assert(session_is_empty(session));
return;
}
* If no, most likely this is timed out connection
* which was removed from waiting list by
* on_tcp_connect_timeout() callback. */
- struct session *s = worker_find_tcp_waiting(worker, peer);
+ struct session *s = worker_find_tcp_waiting(peer);
if (!s || s != session) {
/* session isn't on the waiting list.
* it's timed out session. */
return;
}
- s = worker_find_tcp_connected(worker, peer);
+ s = worker_find_tcp_connected(peer);
if (s) {
/* session already in the connected list.
* Something went wrong, it can be due to races when kresd has tried
kr_log_debug(WORKER, "=> connection to '%s' failed (%s), flagged as 'bad'\n",
peer_str ? peer_str : "", uv_strerror(status));
}
- worker_del_tcp_waiting(worker, peer);
+ worker_del_tcp_waiting(peer);
struct qr_task *task = session_waitinglist_get(session);
if (task && status != UV_ETIMEDOUT) {
/* Penalize upstream.
if (!session_flags(session)->has_tls) {
/* if there is a TLS, session still waiting for handshake,
* otherwise remove it from waiting list */
- if (worker_del_tcp_waiting(worker, peer) != 0) {
+ if (worker_del_tcp_waiting(peer) != 0) {
/* session isn't in list of waiting queries, *
* something gone wrong */
session_waitinglist_finalize(session, KR_STATE_FAIL);
return;
}
} else {
- worker_add_tcp_connected(worker, peer, session);
+ worker_add_tcp_connected(peer, session);
}
ret = send_waiting(session);
struct session *session = timer->data;
uv_timer_stop(timer);
- struct worker_ctx *worker = the_worker;
- kr_require(worker);
+ kr_require(the_worker);
kr_assert(session_tasklist_is_empty(session));
struct sockaddr *peer = session_get_peer(session);
- worker_del_tcp_waiting(worker, peer);
+ worker_del_tcp_waiting(peer);
struct qr_task *task = session_waitinglist_get(session);
if (!task) {
qry->server_selection.error(qry, task->transport, KR_SELECTION_TCP_CONNECT_TIMEOUT);
- worker->stats.timeout += session_waitinglist_get_len(session);
+ the_worker->stats.timeout += session_waitinglist_get_len(session);
session_waitinglist_retry(session, true);
kr_assert(session_tasklist_is_empty(session));
/* uv_cancel() doesn't support uv_connect_t request,
struct qr_task *task = session_tasklist_get_first(session);
if (!task)
return;
- struct worker_ctx *worker = task->ctx->worker;
if (task->leading && task->pending_count > 0) {
struct kr_query *qry = array_tail(task->ctx->req.rplan.pending);
}
task->timeouts += 1;
- worker->stats.timeout += 1;
+ the_worker->stats.timeout += 1;
qr_task_step(task, NULL, NULL);
}
if (kr_resolve_checkout(&ctx->req, NULL, transport, task->pktbuf) != 0) {
return ret;
}
- ret = ioreq_spawn(ctx->worker, SOCK_DGRAM, choice->sin6_family, false, false);
+ ret = ioreq_spawn(SOCK_DGRAM, choice->sin6_family, false, false);
if (!ret) {
return ret;
}
const int klen = subreq_key(key, task->pktbuf);
if (klen > 0) {
void *val_deleted;
- int ret = trie_del(task->ctx->worker->subreq_out, key, klen, &val_deleted);
+ int ret = trie_del(the_worker->subreq_out, key, klen, &val_deleted);
kr_assert(ret == KNOT_EOK && val_deleted == task);
}
/* Notify waiting tasks. */
if (klen < 0)
return;
struct qr_task **tvp = (struct qr_task **)
- trie_get_ins(task->ctx->worker->subreq_out, key, klen);
+ trie_get_ins(the_worker->subreq_out, key, klen);
if (unlikely(!tvp))
return; /*ENOMEM*/
if (kr_fails_assert(*tvp == NULL))
if (klen < 0)
return false;
struct qr_task **leader = (struct qr_task **)
- trie_get_try(task->ctx->worker->subreq_out, key, klen);
+ trie_get_try(the_worker->subreq_out, key, klen);
if (!leader /*ENOMEM*/ || !*leader)
return false;
/* Enqueue itself to leader for this subrequest. */
{
if (kr_fails_assert(session_flags(session)->outgoing && !session_flags(session)->closing))
return kr_error(EINVAL);
- struct request_ctx *ctx = task->ctx;
- struct worker_ctx *worker = ctx->worker;
/* If there are any unsent queries, send it first. */
int ret = send_waiting(session);
}
/* No unsent queries at that point. */
- if (session_tasklist_get_len(session) >= worker->tcp_pipeline_max) {
+ if (session_tasklist_get_len(session) >= the_worker->tcp_pipeline_max) {
/* Too many outstanding queries, answer with SERVFAIL, */
return kr_error(EINVAL);
}
/* Error, finalize task with SERVFAIL and
* close connection to upstream. */
session_tasklist_finalize(session, KR_STATE_FAIL);
- worker_del_tcp_connected(worker, session_get_peer(session));
+ worker_del_tcp_connected(session_get_peer(session));
session_close(session);
return kr_error(EINVAL);
}
static int tcp_task_make_connection(struct qr_task *task, const struct sockaddr *addr)
{
- struct request_ctx *ctx = task->ctx;
- struct worker_ctx *worker = ctx->worker;
-
/* Check if there must be TLS */
struct tls_client_ctx *tls_ctx = NULL;
- struct network *net = &worker->engine->net;
- tls_client_param_t *entry = tls_client_param_get(net->tls_client_params, addr);
+ tls_client_param_t *entry = tls_client_param_get(
+ the_network->tls_client_params, addr);
if (entry) {
/* Address is configured to be used with TLS.
* We need to allocate auxiliary data structure. */
- tls_ctx = tls_client_ctx_new(entry, worker);
+ tls_ctx = tls_client_ctx_new(entry);
if (!tls_ctx) {
return kr_error(EINVAL);
}
}
bool has_http = false;
bool has_tls = (tls_ctx != NULL);
- uv_handle_t *client = ioreq_spawn(worker, SOCK_STREAM, addr->sa_family, has_tls, has_http);
+ uv_handle_t *client = ioreq_spawn(SOCK_STREAM, addr->sa_family, has_tls, has_http);
if (!client) {
tls_client_ctx_free(tls_ctx);
free(conn);
/* Add address to the waiting list.
* Now it "is waiting to be connected to." */
- int ret = worker_add_tcp_waiting(worker, addr, session);
+ int ret = worker_add_tcp_waiting(addr, session);
if (ret < 0) {
free(conn);
session_close(session);
ret = session_timer_start(session, on_tcp_connect_timeout,
KR_CONN_RTT_MAX, 0);
if (ret != 0) {
- worker_del_tcp_waiting(worker, addr);
+ worker_del_tcp_waiting(addr);
free(conn);
session_close(session);
return kr_error(EINVAL);
ret = uv_tcp_connect(conn, (uv_tcp_t *)client, addr , on_connect);
if (ret != 0) {
session_timer_stop(session);
- worker_del_tcp_waiting(worker, addr);
+ worker_del_tcp_waiting(addr);
free(conn);
session_close(session);
qry->server_selection.error(qry, task->transport, KR_SELECTION_TCP_CONNECT_FAILED);
ret = session_waitinglist_push(session, task);
if (ret < 0) {
session_timer_stop(session);
- worker_del_tcp_waiting(worker, addr);
+ worker_del_tcp_waiting(addr);
free(conn);
session_close(session);
return kr_error(EINVAL);
}
int ret;
struct session* session = NULL;
- if ((session = worker_find_tcp_waiting(ctx->worker, addr)) != NULL) {
+ if ((session = worker_find_tcp_waiting(addr)) != NULL) {
/* Connection is in the list of waiting connections.
* It means that connection establishing is coming right now. */
ret = tcp_task_waiting_connection(session, task);
- } else if ((session = worker_find_tcp_connected(ctx->worker, addr)) != NULL) {
+ } else if ((session = worker_find_tcp_connected(addr)) != NULL) {
/* Connection has been already established. */
ret = tcp_task_existing_connection(session, task);
} else {
if (kr_fails_assert(ctx))
return qr_task_finalize(task, KR_STATE_FAIL);
struct kr_request *req = &ctx->req;
- struct worker_ctx *worker = ctx->worker;
- if (worker->too_many_open) {
+ if (the_worker->too_many_open) {
/* */
struct kr_rplan *rplan = &req->rplan;
- if (worker->stats.rconcurrent <
- worker->rconcurrent_highwatermark - 10) {
- worker->too_many_open = false;
+ if (the_worker->stats.rconcurrent <
+ the_worker->rconcurrent_highwatermark - 10) {
+ the_worker->too_many_open = false;
} else {
if (packet && kr_rplan_empty(rplan)) {
/* new query; TODO - make this detection more obvious */
const struct sockaddr *addr = NULL;
if (!is_outgoing) { /* request from a client */
struct request_ctx *ctx =
- request_create(the_worker, session, comm, eth_from,
+ request_create(session, comm, eth_from,
eth_to, knot_wire_get_id(pkt->wire));
if (http_ctx)
queue_pop(http_ctx->streams);
return val ? *val : NULL;
}
-int worker_add_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr* addr,
- struct session *session)
+int worker_add_tcp_connected(const struct sockaddr* addr, struct session *session)
{
- return trie_add_tcp_session(worker->tcp_connected, addr, session);
+ return trie_add_tcp_session(the_worker->tcp_connected, addr, session);
}
-int worker_del_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr* addr)
+int worker_del_tcp_connected(const struct sockaddr* addr)
{
- return trie_del_tcp_session(worker->tcp_connected, addr);
+ return trie_del_tcp_session(the_worker->tcp_connected, addr);
}
-struct session* worker_find_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr* addr)
+struct session* worker_find_tcp_connected(const struct sockaddr* addr)
{
- return trie_find_tcp_session(worker->tcp_connected, addr);
+ return trie_find_tcp_session(the_worker->tcp_connected, addr);
}
-static int worker_add_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr* addr,
+static int worker_add_tcp_waiting(const struct sockaddr* addr,
struct session *session)
{
- return trie_add_tcp_session(worker->tcp_waiting, addr, session);
+ return trie_add_tcp_session(the_worker->tcp_waiting, addr, session);
}
-int worker_del_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr* addr)
+int worker_del_tcp_waiting(const struct sockaddr* addr)
{
- return trie_del_tcp_session(worker->tcp_waiting, addr);
+ return trie_del_tcp_session(the_worker->tcp_waiting, addr);
}
-struct session* worker_find_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr* addr)
+struct session* worker_find_tcp_waiting(const struct sockaddr* addr)
{
- return trie_find_tcp_session(worker->tcp_waiting, addr);
+ return trie_find_tcp_session(the_worker->tcp_waiting, addr);
}
int worker_end_tcp(struct session *session)
struct sockaddr *peer = session_get_peer(session);
- worker_del_tcp_waiting(the_worker, peer);
- worker_del_tcp_connected(the_worker, peer);
+ worker_del_tcp_waiting(peer);
+ worker_del_tcp_connected(peer);
session_flags(session)->connected = false;
struct tls_client_ctx *tls_client_ctx = session_tls_get_client_ctx(session);
/* Add OPT RR, including wire format so modules can see both representations.
* knot_pkt_put() copies the outside; we need to duplicate the inside manually. */
- knot_rrset_t *opt = knot_rrset_copy(the_worker->engine->resolver.downstream_opt_rr, NULL);
+ knot_rrset_t *opt = knot_rrset_copy(the_resolver->downstream_opt_rr, NULL);
if (!opt) {
knot_pkt_free(pkt);
return NULL;
struct qr_task *worker_resolve_start(knot_pkt_t *query, struct kr_qflags options)
{
- struct worker_ctx *worker = the_worker;
- if (kr_fails_assert(worker && query))
+ if (kr_fails_assert(the_worker && query))
return NULL;
- struct request_ctx *ctx = request_create(worker, NULL, NULL, NULL, NULL,
- worker->next_request_uid);
+ struct request_ctx *ctx = request_create(NULL, NULL, NULL, NULL,
+ the_worker->next_request_uid);
if (!ctx)
return NULL;
return NULL;
}
- worker->next_request_uid += 1;
- if (worker->next_request_uid == 0)
- worker->next_request_uid = UINT16_MAX + 1;
+ the_worker->next_request_uid += 1;
+ if (the_worker->next_request_uid == 0)
+ the_worker->next_request_uid = UINT16_MAX + 1;
/* Set options late, as qr_task_start() -> kr_resolve_begin() rewrite it. */
kr_qflags_set(&task->ctx->req.options, options);
}
/** Reserve worker buffers. We assume worker's been zeroed. */
-static int worker_reserve(struct worker_ctx *worker, size_t ring_maxlen)
+static int worker_reserve(size_t ring_maxlen)
{
- worker->tcp_connected = trie_create(NULL);
- worker->tcp_waiting = trie_create(NULL);
- worker->subreq_out = trie_create(NULL);
+ the_worker->tcp_connected = trie_create(NULL);
+ the_worker->tcp_waiting = trie_create(NULL);
+ the_worker->subreq_out = trie_create(NULL);
- array_init(worker->pool_mp);
- if (array_reserve(worker->pool_mp, ring_maxlen)) {
+ array_init(the_worker->pool_mp);
+ if (array_reserve(the_worker->pool_mp, ring_maxlen)) {
return kr_error(ENOMEM);
}
- mm_ctx_mempool(&worker->pkt_pool, 4 * sizeof(knot_pkt_t));
+ mm_ctx_mempool(&the_worker->pkt_pool, 4 * sizeof(knot_pkt_t));
return kr_ok();
}
void worker_deinit(void)
{
- struct worker_ctx *worker = the_worker;
- if (kr_fails_assert(worker))
+ if (kr_fails_assert(the_worker))
return;
- trie_free(worker->tcp_connected);
- trie_free(worker->tcp_waiting);
- trie_free(worker->subreq_out);
- worker->subreq_out = NULL;
+ trie_free(the_worker->tcp_connected);
+ trie_free(the_worker->tcp_waiting);
+ trie_free(the_worker->subreq_out);
+ the_worker->subreq_out = NULL;
- for (int i = 0; i < worker->doh_qry_headers.len; i++)
- free((void *)worker->doh_qry_headers.at[i]);
- array_clear(worker->doh_qry_headers);
+ for (int i = 0; i < the_worker->doh_qry_headers.len; i++)
+ free((void *)the_worker->doh_qry_headers.at[i]);
+ array_clear(the_worker->doh_qry_headers);
- reclaim_mp_freelist(&worker->pool_mp);
- mp_delete(worker->pkt_pool.ctx);
- worker->pkt_pool.ctx = NULL;
+ reclaim_mp_freelist(&the_worker->pool_mp);
+ mp_delete(the_worker->pkt_pool.ctx);
+ the_worker->pkt_pool.ctx = NULL;
the_worker = NULL;
}
-int worker_init(struct engine *engine, int worker_count)
+int worker_init(void)
{
- if (kr_fails_assert(engine && engine->L && the_worker == NULL))
+ if (kr_fails_assert(the_worker == NULL))
return kr_error(EINVAL);
- kr_bindings_register(engine->L);
+ kr_bindings_register(the_engine->L); // TODO move
/* Create main worker. */
- struct worker_ctx *worker = &the_worker_value;
- memset(worker, 0, sizeof(*worker));
- worker->engine = engine;
+ the_worker = &the_worker_value;
+ memset(the_worker, 0, sizeof(*the_worker));
uv_loop_t *loop = uv_default_loop();
- worker->loop = loop;
+ the_worker->loop = loop;
- worker->count = worker_count;
+ static const int worker_count = 1;
+ the_worker->count = worker_count;
/* Register table for worker per-request variables */
- lua_newtable(engine->L);
- lua_setfield(engine->L, -2, "vars");
- lua_getfield(engine->L, -1, "vars");
- worker->vars_table_ref = luaL_ref(engine->L, LUA_REGISTRYINDEX);
- lua_pop(engine->L, 1);
+ struct lua_State *L = the_engine->L;
+ lua_newtable(L);
+ lua_setfield(L, -2, "vars");
+ lua_getfield(L, -1, "vars");
+ the_worker->vars_table_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+ lua_pop(L, 1);
- worker->tcp_pipeline_max = MAX_PIPELINED;
- worker->out_addr4.sin_family = AF_UNSPEC;
- worker->out_addr6.sin6_family = AF_UNSPEC;
+ the_worker->tcp_pipeline_max = MAX_PIPELINED;
+ the_worker->out_addr4.sin_family = AF_UNSPEC;
+ the_worker->out_addr6.sin6_family = AF_UNSPEC;
- array_init(worker->doh_qry_headers);
+ array_init(the_worker->doh_qry_headers);
- int ret = worker_reserve(worker, MP_FREELIST_SIZE);
+ int ret = worker_reserve(MP_FREELIST_SIZE);
if (ret) return ret;
- worker->next_request_uid = UINT16_MAX + 1;
+ the_worker->next_request_uid = UINT16_MAX + 1;
/* Set some worker.* fields in Lua */
- lua_getglobal(engine->L, "worker");
+ lua_getglobal(L, "worker");
pid_t pid = getpid();
auto_free char *pid_str = NULL;
const char *inst_name = getenv("SYSTEMD_INSTANCE");
if (inst_name) {
- lua_pushstring(engine->L, inst_name);
+ lua_pushstring(L, inst_name);
} else {
ret = asprintf(&pid_str, "%ld", (long)pid);
kr_assert(ret > 0);
- lua_pushstring(engine->L, pid_str);
+ lua_pushstring(L, pid_str);
}
- lua_setfield(engine->L, -2, "id");
+ lua_setfield(L, -2, "id");
- lua_pushnumber(engine->L, pid);
- lua_setfield(engine->L, -2, "pid");
- lua_pushnumber(engine->L, worker_count);
- lua_setfield(engine->L, -2, "count");
+ lua_pushnumber(L, pid);
+ lua_setfield(L, -2, "pid");
+ lua_pushnumber(L, worker_count);
+ lua_setfield(L, -2, "count");
char cwd[PATH_MAX];
get_workdir(cwd, sizeof(cwd));
- lua_pushstring(engine->L, cwd);
- lua_setfield(engine->L, -2, "cwd");
+ lua_pushstring(L, cwd);
+ lua_setfield(L, -2, "cwd");
- the_worker = worker;
loop->data = the_worker;
/* ^^^^ Now this shouldn't be used anymore, but it's hard to be 100% sure. */
return kr_ok();
/** Create and initialize the worker.
* \return error code (ENOMEM) */
-int worker_init(struct engine *engine, int worker_count);
+int worker_init();
/** Destroy the worker (free memory). */
-void worker_deinit(void);
+void worker_deinit();
/**
* Process an incoming packet (query from a client or answer from upstream).
void worker_task_timeout_inc(struct qr_task *task);
-int worker_add_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr *addr,
- struct session *session);
-int worker_del_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr *addr);
-int worker_del_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr* addr);
-struct session* worker_find_tcp_waiting(struct worker_ctx *worker,
- const struct sockaddr* addr);
-struct session* worker_find_tcp_connected(struct worker_ctx *worker,
- const struct sockaddr* addr);
+int worker_add_tcp_connected(const struct sockaddr *addr, struct session *session);
+int worker_del_tcp_connected(const struct sockaddr *addr);
+int worker_del_tcp_waiting(const struct sockaddr* addr);
+struct session* worker_find_tcp_waiting(const struct sockaddr* addr);
+struct session* worker_find_tcp_connected(const struct sockaddr* addr);
knot_pkt_t *worker_task_get_pktbuf(const struct qr_task *task);
struct request_ctx *worker_task_get_request(struct qr_task *task);
/** \details Worker state is meant to persist during the whole life of daemon. */
struct worker_ctx {
- struct engine *engine;
uv_loop_t *loop;
int count; /** unreliable, does not count systemd instance, do not use */
int vars_table_ref;
rank = KR_RANK_AUTH|KR_RANK_INSECURE;
}
- int ret = kr_cache_insert_rr(&the_worker->engine->resolver.cache, rr, rrsig,
+ int ret = kr_cache_insert_rr(&the_resolver->cache, rr, rrsig,
rank, z_import->timestamp_rr,
// Optim.: only stash NSEC* params at the apex.
origin_bailiwick == 0);
kr_timer_start(&stopwatch);
int ret = trie_apply(z_import->rrsets, zi_rrset_import, z_import);
- (void)kr_cache_commit(&the_worker->engine->resolver.cache); // RW transaction open
+ (void)kr_cache_commit(&the_resolver->cache); // RW transaction open
if (ret == 0) {
kr_log_info(PREFILL, "performance: validating and caching took %.3lf s\n",
kr_timer_elapsed(&stopwatch));
//// Initialize validator context with the DNSKEY.
if (c->downgrade)
goto zonemd;
- struct kr_context *resolver = &the_worker->engine->resolver;
const knot_rrset_t * const ds = c->ds ? c->ds :
- kr_ta_get(resolver->trust_anchors, z_import->origin);
+ kr_ta_get(the_resolver->trust_anchors, z_import->origin);
if (!ds) {
- if (!kr_ta_closest(resolver, z_import->origin, KNOT_RRTYPE_DNSKEY))
+ if (!kr_ta_closest(the_resolver, z_import->origin, KNOT_RRTYPE_DNSKEY))
goto zonemd; // our TAs say we're insecure
kr_log_error(PREFILL, "no DS found for `%s`, fail\n", zone_name_str);
ret = kr_error(ENOENT);
#define VERBOSE_MSG(qry, ...) kr_log_q((qry), RESOLVER, __VA_ARGS__)
+/** Magic defaults */
+#ifndef LRU_RTT_SIZE
+#define LRU_RTT_SIZE 65536 /**< NS RTT cache size */
+#endif
+#ifndef LRU_REP_SIZE
+#define LRU_REP_SIZE (LRU_RTT_SIZE / 4) /**< NS reputation cache size */
+#endif
+#ifndef LRU_COOKIES_SIZE
+ #if ENABLE_COOKIES
+ #define LRU_COOKIES_SIZE LRU_RTT_SIZE /**< DNS cookies cache size. */
+ #else
+ #define LRU_COOKIES_SIZE LRU_ASSOC /* simpler than guards everywhere */
+ #endif
+#endif
+
+static struct kr_context the_resolver_value = {0};
+struct kr_context *the_resolver = NULL;
+
bool kr_rank_check(uint8_t rank)
{
switch (rank & ~KR_RANK_AUTH) {
return kr_ok();
}
+int kr_resolver_init(module_array_t *modules, knot_mm_t *pool)
+{
+ the_resolver = &the_resolver_value;
+
+ /* Default options (request flags). */
+ the_resolver->options.REORDER_RR = true;
+
+ /* Open resolution context */
+ the_resolver->trust_anchors = trie_create(NULL);
+ the_resolver->negative_anchors = trie_create(NULL);
+ the_resolver->pool = pool;
+ the_resolver->modules = modules;
+ the_resolver->cache_rtt_tout_retry_interval = KR_NS_TIMEOUT_RETRY_INTERVAL;
+ /* Create OPT RR */
+ the_resolver->downstream_opt_rr = mm_alloc(pool, sizeof(knot_rrset_t));
+ the_resolver->upstream_opt_rr = mm_alloc(pool, sizeof(knot_rrset_t));
+ if (!the_resolver->downstream_opt_rr || !the_resolver->upstream_opt_rr) {
+ return kr_error(ENOMEM);
+ }
+ knot_edns_init(the_resolver->downstream_opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, pool);
+ knot_edns_init(the_resolver->upstream_opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, pool);
+ /* Use default TLS padding */
+ the_resolver->tls_padding = -1;
+ /* Empty init; filled via ./lua/postconfig.lua */
+ kr_zonecut_init(&the_resolver->root_hints, (const uint8_t *)"", pool);
+ lru_create(&the_resolver->cache_cookie, LRU_COOKIES_SIZE, NULL, NULL);
+
+ return kr_ok();
+}
+
+void kr_resolver_deinit(void)
+{
+ kr_zonecut_deinit(&the_resolver->root_hints);
+ kr_cache_close(&the_resolver->cache);
+
+ /* The LRUs are currently malloc-ated and need to be freed. */
+ lru_free(the_resolver->cache_cookie);
+
+ kr_ta_clear(the_resolver->trust_anchors);
+ trie_free(the_resolver->trust_anchors);
+ kr_ta_clear(the_resolver->negative_anchors);
+ trie_free(the_resolver->negative_anchors);
+
+ the_resolver = NULL;
+}
+
int kr_resolve_begin(struct kr_request *request, struct kr_context *ctx)
{
/* Initialize request */
knot_mm_t *pool;
};
+/** Pointer to the singleton resolver context. NULL if not initialized */
+KR_EXPORT extern struct kr_context *the_resolver;
+
+/** Initializes the resolver. */
+KR_EXPORT
+int kr_resolver_init(module_array_t *modules, knot_mm_t *pool);
+
+/** Cleans up the resolver. */
+KR_EXPORT
+void kr_resolver_deinit(void);
+
/* Kept outside, because kres-gen.lua can't handle this depth
* (and lines here were too long anyway). */
struct kr_request_qsource_flags {
if (!ka_want) {
return ctx->state;
}
- const struct network *net = &the_worker->engine->net;
- uint64_t timeout = net->tcp.in_idle_timeout / 100;
+ uint64_t timeout = the_network->tcp.in_idle_timeout / 100;
if (timeout > UINT16_MAX) {
timeout = UINT16_MAX;
}
*/
static char* hint_root(void *env, struct kr_module *module, const char *args)
{
- struct engine *engine = env;
- struct kr_context *ctx = &engine->resolver;
- struct kr_zonecut *root_hints = &ctx->root_hints;
+ struct kr_zonecut *root_hints = &the_resolver->root_hints;
/* Replace root hints if parameter is set */
if (args && args[0] != '\0') {
JsonNode *root_node = json_decode(args);
static char* hint_root_file(void *env, struct kr_module *module, const char *args)
{
- struct engine *engine = env;
- struct kr_context *ctx = &engine->resolver;
- const char *err_msg = engine_hint_root_file(ctx, args);
+ const char *err_msg = engine_hint_root_file(args);
if (err_msg) {
- luaL_error(engine->L, "error when opening '%s': %s", args, err_msg);
+ luaL_error(the_engine->L, "error when opening '%s': %s", args, err_msg);
}
return strdup(err_msg ? err_msg : "");
}
static char* nsid_name(void *env, struct kr_module *module, const char *args)
{
- struct engine *engine = env;
struct nsid_config *config = module->data;
if (args) { /* set */
/* API is not binary safe, we need to fix this one day */
uint8_t *arg_copy = (uint8_t *)strdup(args);
if (arg_copy == NULL)
- luaL_error(engine->L, "[nsid] error while allocating new NSID value\n");
+ luaL_error(the_engine->L, "[nsid] error while allocating new NSID value\n");
free(config->local_nsid);
config->local_nsid = arg_copy;
config->local_nsid_len = strlen(args);