Commit 8a46ce70 authored by Daniel Salzman's avatar Daniel Salzman

libknot/compr: simplify label comparison

parent 89c50775
......@@ -344,7 +344,6 @@ src/libknot/error.h
src/libknot/libknot.h
src/libknot/lookup.h
src/libknot/mm_ctx.h
src/libknot/packet/compr.c
src/libknot/packet/compr.h
src/libknot/packet/pkt.c
src/libknot/packet/pkt.h
......
......@@ -147,7 +147,6 @@ libknot_la_SOURCES = \
libknot/error.c \
libknot/db/db_lmdb.c \
libknot/db/db_trie.c \
libknot/packet/compr.c \
libknot/packet/pkt.c \
libknot/packet/rrset-wire.c \
libknot/rdataset.c \
......
......@@ -226,8 +226,8 @@ static int put_additional(knot_pkt_t *pkt, const knot_rrset_t *rr,
flags |= KNOT_PF_NOTRUNC;
}
uint16_t hint = knot_pkt_compr_hint(info, KNOT_COMPR_HINT_RDATA +
glue->ns_pos);
uint16_t hint = knot_compr_hint(info, KNOT_COMPR_HINT_RDATA +
glue->ns_pos);
knot_rrset_t rrsigs = node_rrset(glue->node, KNOT_RRTYPE_RRSIG);
for (int k = 0; k < ar_type_count; ++k) {
knot_rrset_t rrset = node_rrset(glue->node, ar_type_list[k]);
......
......@@ -726,28 +726,6 @@ bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2)
return true;
}
_public_
bool knot_dname_label_is_equal(const uint8_t *label1, const uint8_t *label2)
{
if (label1 == NULL || label2 == NULL) {
return false;
}
/* Check that they have the same length */
if (*label1 != *label2) {
return false;
}
uint8_t len = *label1;
for (uint8_t i = 1; i <= len; i++) {
if (knot_tolower(label1[i]) != knot_tolower(label2[i])) {
return false;
}
}
return true;
}
_public_
size_t knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt)
{
......
......@@ -311,18 +311,6 @@ int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);
_pure_
bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
* \brief Compares two domain name labels (case insensitive).
*
* \param label1 First label.
* \param label2 Second label.
*
* \retval true if the labels are identical
* \retval false if the labels are NOT identical
*/
_pure_
bool knot_dname_label_is_equal(const uint8_t *label1, const uint8_t *label2);
/*!
* \brief Count length of the N first labels.
*
......
/* Copyright (C) 2018 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/>.
*/
#include <assert.h>
#include "libknot/attribute.h"
#include "libknot/packet/compr.h"
#include "libknot/errcode.h"
#include "libknot/packet/pkt.h"
#include "contrib/tolower.h"
/*! \brief Helper for \ref knot_compr_put_dname, writes label(s) with size checks. */
#define WRITE_LABEL(dst, written, label, max, len) \
if ((written) + (len) > (max)) { \
return KNOT_ESPACE; \
} else { \
memcpy((dst) + (written), (label), (len)); \
written += (len); \
}
_public_
int knot_compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max,
knot_compr_t *compr)
{
if (dname == NULL || dst == NULL) {
return KNOT_EINVAL;
}
/* Write uncompressible names directly (zero label dname). */
if (compr == NULL || *dname == '\0') {
return knot_dname_to_wire(dst, dname, max);
}
/* Get number of labels (should not be a zero label dname). */
size_t name_labels = knot_dname_labels(dname, NULL);
assert(name_labels > 0);
/* Suffix must not be longer than whole name. */
const knot_dname_t *suffix = compr->wire + compr->suffix.pos;
int suffix_labels = compr->suffix.labels;
while (suffix_labels > name_labels) {
suffix = knot_wire_next_label(suffix, compr->wire);
--suffix_labels;
}
/* Suffix is shorter than name, write labels until aligned. */
uint8_t orig_labels = name_labels;
uint16_t written = 0;
while (name_labels > suffix_labels) {
WRITE_LABEL(dst, written, dname, max, (*dname + 1));
dname = knot_wire_next_label(dname, NULL);
--name_labels;
}
/* Label count is now equal. */
assert(name_labels == suffix_labels);
const knot_dname_t *match_begin = dname;
const knot_dname_t *compr_ptr = suffix;
while (dname[0] != '\0') {
/* Next labels. */
const knot_dname_t *next_dname = knot_wire_next_label(dname, NULL);
const knot_dname_t *next_suffix = knot_wire_next_label(suffix, compr->wire);
/* Two labels match, extend suffix length. */
if (!knot_dname_label_is_equal(dname, suffix)) {
/* If they don't match, write unmatched labels. */
uint16_t mismatch_len = (dname - match_begin) + (*dname + 1);
WRITE_LABEL(dst, written, match_begin, max, mismatch_len);
/* Start new potential match. */
match_begin = next_dname;
compr_ptr = next_suffix;
}
/* Jump to next labels. */
dname = next_dname;
suffix = next_suffix;
}
/* If match begins at the end of the name, write '\0' label. */
if (match_begin == dname) {
WRITE_LABEL(dst, written, dname, max, 1);
} else {
/* Match covers >0 labels, write out compression pointer. */
if (written + sizeof(uint16_t) > max) {
return KNOT_ESPACE;
}
knot_wire_put_pointer(dst + written, compr_ptr - compr->wire);
written += sizeof(uint16_t);
}
assert(dst >= compr->wire);
size_t wire_pos = dst - compr->wire;
assert(wire_pos < KNOT_WIRE_MAX_PKTSIZE);
/* Heuristics - expect similar names are grouped together. */
if (written > sizeof(uint16_t) && wire_pos + written < KNOT_WIRE_PTR_MAX) {
compr->suffix.pos = wire_pos;
compr->suffix.labels = orig_labels;
}
return written;
}
#undef WRITE_LABEL
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2018 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
......@@ -24,8 +24,8 @@
#pragma once
#include "libknot/dname.h"
#include "libknot/rrset.h"
#include <stdint.h>
#include "libknot/packet/wire.h"
/*! \brief Compression hint type. */
......@@ -75,21 +75,9 @@ typedef struct knot_compr {
} knot_compr_t;
/*!
* \brief Write compressed domain name to the destination wire.
*
* \param dname Name to be written.
* \param dst Destination wire.
* \param max Maximum number of bytes available.
* \param compr Compression context (NULL for no compression)
* \return Number of written bytes or an error.
*/
int knot_compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max,
knot_compr_t *compr);
/*! \brief Retrieve compression hint from given offset.
* \todo More detailed documentation.
* \brief Retrieve compression hint from given offset.
*/
static inline uint16_t knot_pkt_compr_hint(const knot_rrinfo_t *info, uint16_t hint_id)
static inline uint16_t knot_compr_hint(const knot_rrinfo_t *info, uint16_t hint_id)
{
if (hint_id < KNOT_COMPR_HINT_COUNT) {
return info->compress_ptr[hint_id];
......@@ -98,14 +86,15 @@ static inline uint16_t knot_pkt_compr_hint(const knot_rrinfo_t *info, uint16_t h
}
}
/*! \brief Store compression hint for given offset.
* \todo More detailed documentation.
/*!
* \brief Store compression hint for given offset.
*/
static inline void knot_pkt_compr_hint_set(knot_rrinfo_t *info, uint16_t hint_id,
uint16_t val, uint16_t len)
static inline void knot_compr_hint_set(knot_rrinfo_t *info, uint16_t hint_id,
uint16_t val, uint16_t len)
{
if ((hint_id < KNOT_COMPR_HINT_COUNT) && (val + len < KNOT_WIRE_PTR_MAX)) {
info->compress_ptr[hint_id] = val;
}
}
/*! @} */
......@@ -15,24 +15,16 @@
*/
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include "libknot/attribute.h"
#include "libknot/packet/rrset-wire.h"
#include "libknot/consts.h"
#include "libknot/descriptor.h"
#include "libknot/dname.h"
#include "libknot/packet/pkt.h"
#include "libknot/packet/wire.h"
#include "libknot/rrset.h"
#include "libknot/packet/rrset-wire.h"
#include "libknot/rrtype/naptr.h"
#include "libknot/rrtype/rrsig.h"
#include "libknot/wire.h"
#include "contrib/macros.h"
#include "contrib/tolower.h"
#include "contrib/wire_ctx.h"
#define RR_HEADER_SIZE 10
......@@ -45,6 +37,33 @@ static uint16_t dname_max(size_t wire_avail)
return MIN(wire_avail, KNOT_DNAME_MAXLEN);
}
/*!
* \brief Compares two domain name labels.
*
* \param label1 First label.
* \param label2 Second label (may be in upper-case).
*
* \retval true if the labels are identical
* \retval false if the labels are NOT identical
*/
static bool label_is_equal(const uint8_t *label1, const uint8_t *label2)
{
assert(label1 && label2);
if (*label1 != *label2) {
return false;
}
uint8_t len = *label1;
for (uint8_t i = 1; i <= len; i++) {
if (label1[i] != knot_tolower(label2[i])) {
return false;
}
}
return true;
}
/*!
* Case insensitive comparison of two dnames in wire format.
* The second name may be compressed in a supplied wire.
......@@ -58,7 +77,7 @@ static bool dname_equal_wire(const knot_dname_t *d1, const knot_dname_t *d2,
d2 = knot_wire_seek_label(d2, wire);
while (*d1 != '\0' || *d2 != '\0') {
if (!knot_dname_label_is_equal(d1, d2)) {
if (!label_is_equal(d1, d2)) {
return false;
}
d1 = knot_wire_next_label(d1, NULL);
......@@ -77,7 +96,7 @@ static uint16_t compr_get_ptr(knot_compr_t *compr, uint16_t hint)
return 0;
}
return knot_pkt_compr_hint(compr->rrinfo, hint);
return knot_compr_hint(compr->rrinfo, hint);
}
/*!
......@@ -94,7 +113,7 @@ static void compr_set_ptr(knot_compr_t *compr, uint16_t hint,
uint16_t offset = written_at - compr->wire;
knot_pkt_compr_hint_set(compr->rrinfo, hint, offset, written_size);
knot_compr_hint_set(compr->rrinfo, hint, offset, written_size);
}
/*!
......@@ -294,6 +313,105 @@ static int rdata_len(const uint8_t **src, size_t *src_avail,
/*- RRSet to wire -----------------------------------------------------------*/
/*! \brief Helper for \ref compr_put_dname, writes label(s) with size checks. */
#define WRITE_LABEL(dst, written, label, max, len) \
if ((written) + (len) > (max)) { \
return KNOT_ESPACE; \
} else { \
memcpy((dst) + (written), (label), (len)); \
written += (len); \
}
/*!
* \brief Write compressed domain name to the destination wire.
*
* \param dname Name to be written.
* \param dst Destination wire.
* \param max Maximum number of bytes available.
* \param compr Compression context (NULL for no compression)
* \return Number of written bytes or an error.
*/
static int compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max,
knot_compr_t *compr)
{
assert(dname && dst);
/* Write uncompressible names directly (zero label dname). */
if (compr == NULL || *dname == '\0') {
return knot_dname_to_wire(dst, dname, max);
}
/* Get number of labels (should not be a zero label dname). */
size_t name_labels = knot_dname_labels(dname, NULL);
assert(name_labels > 0);
/* Suffix must not be longer than whole name. */
const knot_dname_t *suffix = compr->wire + compr->suffix.pos;
int suffix_labels = compr->suffix.labels;
while (suffix_labels > name_labels) {
suffix = knot_wire_next_label(suffix, compr->wire);
--suffix_labels;
}
/* Suffix is shorter than name, write labels until aligned. */
uint8_t orig_labels = name_labels;
uint16_t written = 0;
while (name_labels > suffix_labels) {
WRITE_LABEL(dst, written, dname, max, (*dname + 1));
dname = knot_wire_next_label(dname, NULL);
--name_labels;
}
/* Label count is now equal. */
assert(name_labels == suffix_labels);
const knot_dname_t *match_begin = dname;
const knot_dname_t *compr_ptr = suffix;
while (dname[0] != '\0') {
/* Next labels. */
const knot_dname_t *next_dname = knot_wire_next_label(dname, NULL);
const knot_dname_t *next_suffix = knot_wire_next_label(suffix, compr->wire);
/* Two labels match, extend suffix length. */
if (!label_is_equal(dname, suffix)) {
/* If they don't match, write unmatched labels. */
uint16_t mismatch_len = (dname - match_begin) + (*dname + 1);
WRITE_LABEL(dst, written, match_begin, max, mismatch_len);
/* Start new potential match. */
match_begin = next_dname;
compr_ptr = next_suffix;
}
/* Jump to next labels. */
dname = next_dname;
suffix = next_suffix;
}
/* If match begins at the end of the name, write '\0' label. */
if (match_begin == dname) {
WRITE_LABEL(dst, written, dname, max, 1);
} else {
/* Match covers >0 labels, write out compression pointer. */
if (written + sizeof(uint16_t) > max) {
return KNOT_ESPACE;
}
knot_wire_put_pointer(dst + written, compr_ptr - compr->wire);
written += sizeof(uint16_t);
}
assert(dst >= compr->wire);
size_t wire_pos = dst - compr->wire;
assert(wire_pos < KNOT_WIRE_MAX_PKTSIZE);
/* Heuristics - expect similar names are grouped together. */
if (written > sizeof(uint16_t) && wire_pos + written < KNOT_WIRE_PTR_MAX) {
compr->suffix.pos = wire_pos;
compr->suffix.labels = orig_labels;
}
return written;
}
/*!
* \brief Write RR owner to wire.
*/
......@@ -346,8 +464,8 @@ static int write_owner(const knot_rrset_t *rrset, uint8_t **dst, size_t *dst_ava
compr->suffix.labels = knot_dname_labels(compr->wire + compr->suffix.pos,
compr->wire);
}
int written = knot_compr_put_dname(rrset->owner, *dst,
dname_max(*dst_avail), compr);
int written = compr_put_dname(rrset->owner, *dst,
dname_max(*dst_avail), compr);
if (written < 0) {
return written;
}
......@@ -427,8 +545,7 @@ static int compress_rdata_dname(const uint8_t **src, size_t *src_avail,
put_compr = dname_cfg->compr;
}
int written = knot_compr_put_dname(dname, *dst, dname_max(*dst_avail),
put_compr);
int written = compr_put_dname(dname, *dst, dname_max(*dst_avail), put_compr);
if (written < 0) {
return written;
}
......
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2018 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
......@@ -24,14 +24,8 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "libknot/dname.h"
#include "libknot/rrset.h"
#include "libknot/mm_ctx.h"
struct knot_compr;
#include "libknot/packet/compr.h"
/*!
* \brief Write RR Set content to a wire.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment