From: Marek VavrusÌŒa Date: Mon, 12 Mar 2018 04:12:39 +0000 (-0700) Subject: kres: add constructor for rrsets and refactor rr2str function to use it X-Git-Tag: v2.4.0~54^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e79a17a32d9969c7a43a38f6229dd2d55c2953b6;p=thirdparty%2Fknot-resolver.git kres: add constructor for rrsets and refactor rr2str function to use it This updates the metatype to wrap knot_rrset_add_rdata and knot_rrset_init_empty in a nicer way, and adds automatic GC destructor and tests. --- diff --git a/daemon/lua/kres-gen.lua b/daemon/lua/kres-gen.lua index aaca2da68..268bac1da 100644 --- a/daemon/lua/kres-gen.lua +++ b/daemon/lua/kres-gen.lua @@ -235,6 +235,7 @@ struct kr_context { char _stub[]; }; const char *knot_strerror(int); +knot_dname_t *knot_dname_copy(const knot_dname_t *, knot_mm_t *); knot_dname_t *knot_dname_from_str(uint8_t *, const char *, size_t); _Bool knot_dname_is_equal(const knot_dname_t *, const knot_dname_t *); _Bool knot_dname_is_sub(const knot_dname_t *, const knot_dname_t *); diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh index 0fbffaae1..7a33ff4dd 100755 --- a/daemon/lua/kres-gen.sh +++ b/daemon/lua/kres-gen.sh @@ -93,6 +93,7 @@ printf "\tchar _stub[];\n};\n" # Utils knot_strerror # Domain names + knot_dname_copy knot_dname_from_str knot_dname_is_equal knot_dname_is_sub diff --git a/daemon/lua/kres.lua b/daemon/lua/kres.lua index 9dc647f87..1af5370d0 100644 --- a/daemon/lua/kres.lua +++ b/daemon/lua/kres.lua @@ -249,11 +249,26 @@ local function dname2wire(name) return ffi.string(name, knot.knot_dname_size(name)) end +-- RR sets created in Lua must have a destructor to release allocated memory +local function rrset_free(rr) + if rr._owner ~= nil then ffi.C.free(rr._owner) end + if rr.rrs.rr_count > 0 then ffi.C.free(rr.rrs.data) end +end + -- Metatype for RR set. Beware, the indexing is 0-based (rdata, get, tostring). local rrset_buflen = (64 + 1) * 1024 local rrset_buf = ffi.new('char[?]', rrset_buflen) local knot_rrset_t = ffi.typeof('knot_rrset_t') ffi.metatype( knot_rrset_t, { + -- Create a new empty RR set object with an allocated owner and a destructor + __new = function (ct, owner, rrtype, rrclass) + local rr = ffi.new(ct) + knot.knot_rrset_init_empty(rr) + rr._owner = owner and knot.knot_dname_copy(owner, nil) + rr.type = rrtype or 0 + rr.rclass = rrclass or const_class.IN + return ffi.gc(rr, rrset_free) + end, -- beware: `owner` and `rdata` are typed as a plain lua strings -- and not the real types they represent. __tostring = function(rr) return rr:txt_dump() end, @@ -300,6 +315,13 @@ ffi.metatype( knot_rrset_t, { C.free(dump[0]) return result end, + -- Add binary RDATA to the RR set + add_rdata = function (rr, rdata, rdlen, ttl) + assert(ffi.istype(knot_rrset_t, rr)) + local ret = knot.knot_rrset_add_rdata(rr, rdata, tonumber(rdlen), tonumber(ttl or 0), nil) + if ret ~= 0 then return nil, knot_strerror(ret) end + return true + end, }, }) @@ -578,15 +600,12 @@ ffi.metatype(ranked_rr_array_t, { -- Extension: append .comment if exists. local function rr2str(rr, style) -- Construct a single-RR temporary set while minimizing copying. - local rrs = knot_rrset_t() - knot.knot_rrset_init_empty(rrs) - rrs._owner = ffi.cast('knot_dname_t *', rr.owner) -- explicit cast needed here - rrs.type = rr.type - rrs.rclass = kres.class.IN - knot.knot_rrset_add_rdata(rrs, rr.rdata, #rr.rdata, rr.ttl, nil) - - local ret = rrs:txt_dump(style) - C.free(rrs.rrs.data) + local ret + do + local rrs = knot_rrset_t(rr.owner, rr.type, kres.class.IN) + rrs:add_rdata(rr.rdata, #rr.rdata, rr.ttl) + ret = rrs:txt_dump(style) + end -- Trim the newline and append comment (optionally). if ret then diff --git a/modules/dns64/dns64.lua b/modules/dns64/dns64.lua index 2f14f2017..6b527e956 100644 --- a/modules/dns64/dns64.lua +++ b/modules/dns64/dns64.lua @@ -26,11 +26,9 @@ mod.layer = { for i = 1, section.count do local orig = ffi.C.knot_pkt_rr(section, i - 1) if orig.type == kres.type.A then - local rrs = ffi.typeof('knot_rrset_t')() - ffi.C.knot_rrset_init_empty(rrs) + -- Disable GC, as this object doesn't own either owner or RDATA, it's just a reference + local rrs = ffi.gc(kres.rrset(nil, kres.type.AAAA, orig.rclass), nil) rrs._owner = ffi.cast('knot_dname_t *', orig:owner()) -- explicit cast needed here - rrs.type = kres.type.AAAA - rrs.rclass = orig.rclass for k = 1, orig.rrs.rr_count do local rdata = orig:rdata( k - 1 ) ffi.copy(addr_buf, mod.proxy, 16) diff --git a/tests/config/basic.test.lua b/tests/config/basic.test.lua index 1d0ea6b42..7bb847533 100644 --- a/tests/config/basic.test.lua +++ b/tests/config/basic.test.lua @@ -1,3 +1,5 @@ +local ffi = require('ffi') + -- test if constants work properly local function test_constants() same(kres.class.IN, 1, 'class constants work') @@ -34,6 +36,17 @@ local function test_rrset_functions() local rr_text = tostring(kres.rr2str(rr)) same(rr_text:gsub('%s+', ' '), 'com. 1 TXT "hello"', 'rrset to text works') same(kres.dname2str(todname('com.')), 'com.', 'domain name conversion works') + -- test creating rrset + rr = kres.rrset(kres.str2dname('com.'), kres.type.A, kres.class.IN) + ok(ffi.istype(kres.rrset, rr), 'created an empty RR') + same(rr:owner(), '\3com\0', 'created RR has correct owner') + same(rr.rclass, kres.class.IN, 'created RR has correct class') + same(rr.type, kres.type.A, 'created RR has correct type') + -- test adding rdata + local rdata = '\1\2\3\4' + ok(rr:add_rdata(rdata, #rdata, 66), 'adding RDATA works') + -- test conversion to text + same(rr:txt_dump(), 'com. 66 A 1.2.3.4\n', 'RR to text works') end -- test dns library packet interface