bindings.c 16.2 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*  Copyright (C) 2015 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

17
#include <uv.h>
18
#include <libknot/descriptor.h>
19

20 21
#include "lib/cache.h"
#include "daemon/bindings.h"
22
#include "daemon/worker.h"
23

24 25 26 27 28 29 30
/** @internal Prefix error with file:line */
static int format_error(lua_State* L, const char *err)
{
	lua_Debug d;
	lua_getstack(L, 1, &d);
	/* error message prefix */
	lua_getinfo(L, "Sln", &d);
31 32 33 34 35 36 37 38 39
	if (strncmp(d.short_src, "[", 1) != 0) {
		lua_pushstring(L, d.short_src);
		lua_pushstring(L, ":");
		lua_pushnumber(L, d.currentline);
		lua_pushstring(L, ": error: ");
		lua_concat(L, 4);
	} else {
		lua_pushstring(L, "error: ");
	}
40 41
	/* error message */
	lua_pushstring(L, err);
42
	lua_concat(L,  2);
43 44 45
	return 1;
}

46 47 48 49
/** List loaded modules */
static int mod_list(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
50
	lua_newtable(L);
51
	for (unsigned i = 0; i < engine->modules.len; ++i) {
52
		struct kr_module *module = engine->modules.at[i];
53
		lua_pushstring(L, module->name);
54
		lua_rawseti(L, -2, i + 1);
55
	}
56
	return 1;
57 58 59 60 61 62 63 64
}

/** Load module. */
static int mod_load(lua_State *L)
{
	/* Check parameters */
	int n = lua_gettop(L);
	if (n != 1 || !lua_isstring(L, 1)) {
65
		format_error(L, "expected 'load(string name)'");
66 67 68 69 70 71
		lua_error(L);
	}
	/* Load engine module */
	struct engine *engine = engine_luaget(L);
	int ret = engine_register(engine, lua_tostring(L, 1));
	if (ret != 0) {
72
		format_error(L, kr_strerror(ret));
73 74
		lua_error(L);
	}
75 76 77

	lua_pushboolean(L, 1);
	return 1;
78 79 80 81 82
}

/** Unload module. */
static int mod_unload(lua_State *L)
{
83 84 85
	/* Check parameters */
	int n = lua_gettop(L);
	if (n != 1 || !lua_isstring(L, 1)) {
Marek Vavruša's avatar
Marek Vavruša committed
86
		format_error(L, "expected 'unload(string name)'");
87 88 89 90 91 92
		lua_error(L);
	}
	/* Unload engine module */
	struct engine *engine = engine_luaget(L);
	int ret = engine_unregister(engine, lua_tostring(L, 1));
	if (ret != 0) {
93
		format_error(L, kr_strerror(ret));
94 95
		lua_error(L);
	}
96 97 98

	lua_pushboolean(L, 1);
	return 1;
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
}

int lib_modules(lua_State *L)
{
	static const luaL_Reg lib[] = {
		{ "list",   mod_list },
		{ "load",   mod_load },
		{ "unload", mod_unload },
		{ NULL, NULL }
	};

	register_lib(L, "modules", lib);
	return 1;
}

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
/** Append 'addr = {port = int, udp = bool, tcp = bool}' */
static int net_list_add(const char *key, void *val, void *ext)
{
	lua_State *L = (lua_State *)ext;
	endpoint_array_t *ep_array = val;
	lua_newtable(L);
	for (size_t i = ep_array->len; i--;) {
		struct endpoint *ep = ep_array->at[i];
		lua_pushinteger(L, ep->port);
		lua_setfield(L, -2, "port");
		lua_pushboolean(L, ep->flags & NET_UDP);
		lua_setfield(L, -2, "udp");
		lua_pushboolean(L, ep->flags & NET_TCP);
		lua_setfield(L, -2, "tcp");
	}
	lua_setfield(L, -2, key);
	return kr_ok();
}

133 134 135
/** List active endpoints. */
static int net_list(lua_State *L)
{
136 137 138 139
	struct engine *engine = engine_luaget(L);
	lua_newtable(L);
	map_walk(&engine->net.endpoints, net_list_add, L);
	return 1;
140 141
}

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
/** Listen on interface address list. */
static int net_listen_iface(lua_State *L, int port)
{
	/* Expand 'addr' key if exists */
	lua_getfield(L, 1, "addr");
	if (lua_isnil(L, -1)) {
		lua_pop(L, 1);
		lua_pushvalue(L, 1);
	}

	/* Bind to address list */
	struct engine *engine = engine_luaget(L);
	size_t count = lua_rawlen(L, -1);
	for (size_t i = 0; i < count; ++i) {
		lua_rawgeti(L, -1, i + 1);
		int ret = network_listen(&engine->net, lua_tostring(L, -1),
		                         port, NET_TCP|NET_UDP);
		if (ret != 0) {
160
			format_error(L, kr_strerror(ret));
161 162 163 164 165 166 167 168 169
			lua_error(L);
		}
		lua_pop(L, 1);
	}

	lua_pushboolean(L, true);
	return 1;
}

170 171 172
/** Listen on endpoint. */
static int net_listen(lua_State *L)
{
173 174
	/* Check parameters */
	int n = lua_gettop(L);
175 176 177 178 179 180 181 182 183
	int port = KR_DNS_PORT;
	if (n > 1 && lua_isnumber(L, 2)) {
		port = lua_tointeger(L, 2);
	}

	/* Process interface or (address, port) pair. */
	if (lua_istable(L, 1)) {
		return net_listen_iface(L, port);
	} else if (n < 1 || !lua_isstring(L, 1)) {
Marek Vavruša's avatar
Marek Vavruša committed
184
		format_error(L, "expected 'listen(string addr, number port = 53)'");
185 186 187 188 189
		lua_error(L);
	}

	/* Open resolution context cache */
	struct engine *engine = engine_luaget(L);
190 191
	int ret = network_listen(&engine->net, lua_tostring(L, 1), port, NET_TCP|NET_UDP);
	if (ret != 0) {
192
		format_error(L, kr_strerror(ret));
193 194 195 196
		lua_error(L);
	}

	lua_pushboolean(L, true);
197
	return 1;
198 199 200 201
}

/** Close endpoint. */
static int net_close(lua_State *L)
202
{
203 204 205
	/* Check parameters */
	int n = lua_gettop(L);
	if (n < 2) {
Marek Vavruša's avatar
Marek Vavruša committed
206
		format_error(L, "expected 'close(string addr, number port)'");
207 208 209 210 211 212 213 214
		lua_error(L);
	}

	/* Open resolution context cache */
	struct engine *engine = engine_luaget(L);
	int ret = network_close(&engine->net, lua_tostring(L, 1), lua_tointeger(L, 2));
	lua_pushboolean(L, ret == 0);
	return 1;
215 216
}

217
/** List available interfaces. */
218 219 220 221 222 223 224 225
static int net_interfaces(lua_State *L)
{
	/* Retrieve interface list */
	int count = 0;
	char buf[INET6_ADDRSTRLEN]; /* http://tools.ietf.org/html/rfc4291 */
	uv_interface_address_t *info = NULL;
	uv_interface_addresses(&info, &count);
	lua_newtable(L);
226
	for (int i = 0; i < count; ++i) {
227
		uv_interface_address_t iface = info[i];
228 229 230 231 232
		lua_getfield(L, -1, iface.name);
		if (lua_isnil(L, -1)) {
			lua_pop(L, 1);
			lua_newtable(L);
		}
233 234

		/* Address */
235 236 237 238 239 240
		lua_getfield(L, -1, "addr");
		if (lua_isnil(L, -1)) {
			lua_pop(L, 1);
			lua_newtable(L);
		}
		if (iface.address.address4.sin_family == AF_INET) {
241
			uv_ip4_name(&iface.address.address4, buf, sizeof(buf));
242
		} else if (iface.address.address4.sin_family == AF_INET6) {
243
			uv_ip6_name(&iface.address.address6, buf, sizeof(buf));
244 245
		} else {
			buf[0] = '\0';
246 247
		}
		lua_pushstring(L, buf);
Marek Vavruša's avatar
Marek Vavruša committed
248
		lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
249 250 251 252 253 254
		lua_setfield(L, -2, "addr");

		/* Hardware address. */
		char *p = buf;
		memset(buf, 0, sizeof(buf));
		for (unsigned k = 0; k < sizeof(iface.phys_addr); ++k) {
255 256
			sprintf(p, "%.2x:", iface.phys_addr[k] & 0xff);
			p += 3;
257
		}
258
		*(p - 1) = '\0';
259
		lua_pushstring(L, buf);
260
		lua_setfield(L, -2, "mac");
261 262

		/* Push table */
263
		lua_setfield(L, -2, iface.name);
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
	}
	uv_free_interface_addresses(info, count);

	return 1;
}

int lib_net(lua_State *L)
{
	static const luaL_Reg lib[] = {
		{ "list",       net_list },
		{ "listen",     net_listen },
		{ "close",      net_close },
		{ "interfaces", net_interfaces },
		{ NULL, NULL }
	};
	register_lib(L, "net", lib);
	return 1;
}

283 284 285 286 287 288 289 290 291
/** Return available cached backends. */
static int cache_backends(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
	storage_registry_t *registry = &engine->storage_registry;

	lua_newtable(L);
	for (unsigned i = 0; i < registry->len; ++i) {
		struct storage_api *storage = &registry->at[i];
292
		lua_pushboolean(L, storage->api() == engine->resolver.cache.api);
293 294 295 296 297
		lua_setfield(L, -2, storage->prefix);
	}
	return 1;
}

298 299 300 301
/** Return number of cached records. */
static int cache_count(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
302
	const namedb_api_t *storage = engine->resolver.cache.api;
303 304

	/* Fetch item count */
305 306
	struct kr_cache_txn txn;
	int ret = kr_cache_txn_begin(&engine->resolver.cache, &txn, NAMEDB_RDONLY);
307
	if (ret != 0) {
308
		format_error(L, kr_strerror(ret));
309 310 311
		lua_error(L);
	}

312
	lua_pushinteger(L, storage->count(&txn.t));
313 314 315 316
	kr_cache_txn_abort(&txn);
	return 1;
}

317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337
/** Return cache statistics. */
static int cache_stats(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
	struct kr_cache *cache = &engine->resolver.cache;
	lua_newtable(L);
	lua_pushnumber(L, cache->stats.hit);
	lua_setfield(L, -2, "hit");
	lua_pushnumber(L, cache->stats.miss);
	lua_setfield(L, -2, "miss");
	lua_pushnumber(L, cache->stats.insert);
	lua_setfield(L, -2, "insert");
	lua_pushnumber(L, cache->stats.delete);
	lua_setfield(L, -2, "delete");
	lua_pushnumber(L, cache->stats.txn_read);
	lua_setfield(L, -2, "txn_read");
	lua_pushnumber(L, cache->stats.txn_write);
	lua_setfield(L, -2, "txn_write");
	return 1;
}

338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
static struct storage_api *cache_select_storage(struct engine *engine, const char **conf)
{
	/* Return default backend */
	storage_registry_t *registry = &engine->storage_registry;
	if (!*conf || !strstr(*conf, "://")) {
		return &registry->at[0];
	}

	/* Find storage backend from config prefix */
	for (unsigned i = 0; i < registry->len; ++i) {
		struct storage_api *storage = &registry->at[i];
		if (strncmp(*conf, storage->prefix, strlen(storage->prefix)) == 0) {
			*conf += strlen(storage->prefix);
			return storage;
		}
	}

	return NULL;
}

358 359 360 361 362
/** Open cache */
static int cache_open(lua_State *L)
{
	/* Check parameters */
	int n = lua_gettop(L);
363
	if (n < 1 || !lua_isnumber(L, 1)) {
Marek Vavruša's avatar
Marek Vavruša committed
364
		format_error(L, "expected 'open(number max_size, string config = \"\")'");
365 366 367
		lua_error(L);
	}

368
	/* Select cache storage backend */
369
	struct engine *engine = engine_luaget(L);
370
	unsigned cache_size = lua_tonumber(L, 1);
371
	const char *conf = n > 1 ? lua_tostring(L, 2) : NULL;
372
	const char *uri = conf;
373 374 375 376 377 378 379
	struct storage_api *storage = cache_select_storage(engine, &conf);
	if (!storage) {
		format_error(L, "unsupported cache backend");
		lua_error(L);
	}

	/* Close if already open */
380
	kr_cache_close(&engine->resolver.cache);
381

382
	/* Reopen cache */
383
	void *storage_opts = storage->opts_create(conf, cache_size);
384
	int ret = kr_cache_open(&engine->resolver.cache, storage->api(), storage_opts, engine->pool);
385
	free(storage_opts);
386
	if (ret != 0) {
387
		format_error(L, "can't open cache");
388 389 390
		lua_error(L);
	}

391 392
	/* Store current configuration */
	lua_getglobal(L, "cache");
393
	lua_pushstring(L, "current_size");
394 395
	lua_pushnumber(L, cache_size);
	lua_rawset(L, -3);
396
	lua_pushstring(L, "current_storage");
397 398 399
	lua_pushstring(L, uri);
	lua_rawset(L, -3);

400 401 402 403 404 405 406
	lua_pushboolean(L, 1);
	return 1;
}

static int cache_close(lua_State *L)
{
	struct engine *engine = engine_luaget(L);
407
	kr_cache_close(&engine->resolver.cache);
408 409
	lua_pushboolean(L, 1);
	return 1;
410 411 412 413 414
}

int lib_cache(lua_State *L)
{
	static const luaL_Reg lib[] = {
415
		{ "backends", cache_backends },
416
		{ "count",  cache_count },
417
		{ "stats",  cache_stats },
418 419 420 421 422 423
		{ "open",   cache_open },
		{ "close",  cache_close },
		{ NULL, NULL }
	};

	register_lib(L, "cache", lib);
Marek Vavruša's avatar
Marek Vavruša committed
424
	return 1;
425
}
426 427 428 429 430 431 432 433 434 435

static void event_free(uv_timer_t *timer)
{
	struct worker_ctx *worker = timer->loop->data;
	lua_State *L = worker->engine->L;
	int ref = (intptr_t) timer->data;
	luaL_unref(L, LUA_REGISTRYINDEX, ref);
	free(timer);
}

436 437 438 439 440 441 442 443 444 445 446 447
static int execute_callback(lua_State *L, int argc)
{
	int ret = engine_pcall(L, argc);
	if (ret != 0) {
		fprintf(stderr, "error: %s\n", lua_tostring(L, -1));
	}
	/* Clear the stack, there may be event a/o enything returned */
	lua_settop(L, 0);
	lua_gc(L, LUA_GCCOLLECT, 0);
	return ret;
}

448 449 450 451 452 453 454 455 456
static void event_callback(uv_timer_t *timer)
{
	struct worker_ctx *worker = timer->loop->data;
	lua_State *L = worker->engine->L;

	/* Retrieve callback and execute */
	lua_rawgeti(L, LUA_REGISTRYINDEX, (intptr_t) timer->data);
	lua_rawgeti(L, -1, 1);
	lua_pushinteger(L, (intptr_t) timer->data);
457
	int ret = execute_callback(L, 1);
458 459
	/* Free callback if not recurrent or an error */
	if (ret != 0 || uv_timer_get_repeat(timer) == 0) {
460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552
		uv_close((uv_handle_t *)timer, (uv_close_cb) event_free);
	}
}

static int event_sched(lua_State *L, unsigned timeout, unsigned repeat)
{
	uv_timer_t *timer = malloc(sizeof(*timer));
	if (!timer) {
		format_error(L, "out of memory");
		lua_error(L);
	}

	/* Start timer with the reference */
	uv_loop_t *loop = uv_default_loop();
	uv_timer_init(loop, timer);
	int ret = uv_timer_start(timer, event_callback, timeout, repeat);
	if (ret != 0) {
		free(timer);
		format_error(L, "couldn't start the event");
		lua_error(L);
	}

	/* Save callback and timer in registry */
	lua_newtable(L);
	lua_pushvalue(L, 2);
	lua_rawseti(L, -2, 1);
	lua_pushlightuserdata(L, timer);
	lua_rawseti(L, -2, 2);
	int ref = luaL_ref(L, LUA_REGISTRYINDEX);

	/* Save reference to the timer */
	timer->data = (void *) (intptr_t)ref;
	lua_pushinteger(L, ref);
	return 1;
}

static int event_after(lua_State *L)
{
	/* Check parameters */
	int n = lua_gettop(L);
	if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2)) {
		format_error(L, "expected 'after(number timeout, function)'");
		lua_error(L);
	}

	return event_sched(L, lua_tonumber(L, 1), 0);
}

static int event_recurrent(lua_State *L)
{
	/* Check parameters */
	int n = lua_gettop(L);
	if (n < 2 || !lua_isnumber(L, 1) || !lua_isfunction(L, 2)) {
		format_error(L, "expected 'recurrent(number interval, function)'");
		lua_error(L);
	}
	return event_sched(L, 0, lua_tonumber(L, 1));
}

static int event_cancel(lua_State *L)
{
	int n = lua_gettop(L);
	if (n < 1 || !lua_isnumber(L, 1)) {
		format_error(L, "expected 'cancel(number event)'");
		lua_error(L);
	}

	/* Fetch event if it exists */
	lua_rawgeti(L, LUA_REGISTRYINDEX, lua_tointeger(L, 1));
	if (!lua_istable(L, -1)) {
		format_error(L, "event not exists");
		lua_error(L);
	}

	/* Close the timer */
	lua_rawgeti(L, -1, 2);
	uv_handle_t *timer = lua_touserdata(L, -1);
	uv_close(timer, (uv_close_cb) event_free);
	return 0;
}

int lib_event(lua_State *L)
{
	static const luaL_Reg lib[] = {
		{ "after",      event_after },
		{ "recurrent",  event_recurrent },
		{ "cancel",     event_cancel },
		{ NULL, NULL }
	};

	register_lib(L, "event", lib);
	return 1;
}
553 554 555 556 557 558 559 560

static inline struct worker_ctx *wrk_luaget(lua_State *L) {
	lua_getglobal(L, "__worker");
	struct worker_ctx *worker = lua_touserdata(L, -1);
	lua_pop(L, 1);
	return worker;
}

561 562 563 564 565 566 567 568 569 570 571 572 573 574
/* @internal Call the Lua callback stored in baton. */
static void resolve_callback(struct worker_ctx *worker, struct kr_request *req, void *baton)
{
	assert(worker);
	assert(req);
	assert(baton);
	lua_State *L = worker->engine->L;
	intptr_t cb_ref = (intptr_t) baton;
	lua_rawgeti(L, LUA_REGISTRYINDEX, cb_ref);
	luaL_unref(L, LUA_REGISTRYINDEX, cb_ref);
	lua_pushlightuserdata(L, req->answer);
	(void) execute_callback(L, 1);
}

575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
static int wrk_resolve(lua_State *L)
{
	struct worker_ctx *worker = wrk_luaget(L);
	if (!worker) {
		return 0;
	}
	/* Create query packet */
	knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_EDNS_MAX_UDP_PAYLOAD, NULL);
	if (!pkt) {
		lua_pushstring(L, strerror(ENOMEM));
		lua_error(L);
	}
	uint8_t dname[KNOT_DNAME_MAXLEN];
	knot_dname_from_str(dname, lua_tostring(L, 1), sizeof(dname));
	/* Check class and type */
	uint16_t rrtype = lua_tointeger(L, 2);
	if (!lua_isnumber(L, 2)) {
		lua_pushstring(L, "invalid RR type");
		lua_error(L);
	}
	uint16_t rrclass = lua_tointeger(L, 3);
	if (!lua_isnumber(L, 3)) { /* Default class is IN */
		rrclass = KNOT_CLASS_IN;
	}
	knot_pkt_put_question(pkt, dname, rrclass, rrtype);
	knot_wire_set_rd(pkt->wire);
601 602 603 604 605 606 607 608 609 610
	/* Add OPT RR */
	pkt->opt_rr = mm_alloc(&pkt->mm, sizeof(*pkt->opt_rr));
	if (!pkt->opt_rr) {
		return kr_error(ENOMEM);
	}
	int ret = knot_edns_init(pkt->opt_rr, KR_EDNS_PAYLOAD, 0, KR_EDNS_VERSION, &pkt->mm);
	if (ret != 0) {
		knot_pkt_free(&pkt);
		return 0;
	}
611
	/* Add completion callback */
612
	unsigned options = lua_tointeger(L, 4);
613 614 615 616 617 618 619 620 621
	if (lua_isfunction(L, 5)) {
		/* Store callback in registry */
		lua_pushvalue(L, 5);
		int cb = luaL_ref(L, LUA_REGISTRYINDEX);
		ret = worker_resolve(worker, pkt, options, resolve_callback, (void *) (intptr_t)cb);
	} else {
		ret = worker_resolve(worker, pkt, options, NULL, NULL);
	}
	
622
	knot_pkt_free(&pkt);
623
	lua_pushboolean(L, ret == 0);
624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
	return 1;
}

/** Return worker statistics. */
static int wrk_stats(lua_State *L)
{
	struct worker_ctx *worker = wrk_luaget(L);
	if (!worker) {
		return 0;
	}
	lua_newtable(L);
	lua_pushnumber(L, worker->stats.concurrent);
	lua_setfield(L, -2, "concurrent");
	lua_pushnumber(L, worker->stats.udp);
	lua_setfield(L, -2, "udp");
	lua_pushnumber(L, worker->stats.tcp);
	lua_setfield(L, -2, "tcp");
641 642 643 644
	lua_pushnumber(L, worker->stats.ipv6);
	lua_setfield(L, -2, "ipv6");
	lua_pushnumber(L, worker->stats.ipv4);
	lua_setfield(L, -2, "ipv4");
645 646 647 648 649 650 651 652 653 654 655 656 657
	return 1;
}

int lib_worker(lua_State *L)
{
	static const luaL_Reg lib[] = {
		{ "resolve",  wrk_resolve },
		{ "stats",    wrk_stats },
		{ NULL, NULL }
	};
	register_lib(L, "worker", lib);
	return 1;
}