]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
kres: add constructor for rrsets and refactor rr2str function to use it
authorMarek Vavruša <mvavrusa@cloudflare.com>
Mon, 12 Mar 2018 04:12:39 +0000 (21:12 -0700)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Mon, 23 Apr 2018 12:34:39 +0000 (14:34 +0200)
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.

daemon/lua/kres-gen.lua
daemon/lua/kres-gen.sh
daemon/lua/kres.lua
modules/dns64/dns64.lua
tests/config/basic.test.lua

index aaca2da688e17c2bf9ef790848635f69c0f7e06e..268bac1da840f56dcca07214e07d33a691a9040c 100644 (file)
@@ -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 *);
index 0fbffaae1ee97f4b2590a80683ba973cd387243b..7a33ff4ddd7b80f5d818c2bd252ce52418af826b 100755 (executable)
@@ -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
index 9dc647f87202b95793215ab1a52ee508e10c9fee..1af5370d0f3fcdea2e17aaf66d8183d068679ed2 100644 (file)
@@ -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
index 2f14f20176df1209f01a941dad8f8ea09fcac984..6b527e956a420c275ac7a2c333c014701f713dff 100644 (file)
@@ -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)
index 1d0ea6b42d877e1b2a23c3afce4e4ce011f91b8d..7bb847533a1f073d59a0f372baac5dfd271989bf 100644 (file)
@@ -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