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,
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,
},
})
-- 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
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)
+local ffi = require('ffi')
+
-- test if constants work properly
local function test_constants()
same(kres.class.IN, 1, 'class constants work')
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