compr.c 3.7 KB
 Daniel Salzman committed Jan 10, 2018 1 /* Copyright (C) 2018 CZ.NIC, z.s.p.o.  Jan Včelák committed Jan 15, 2014 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  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 . */ #include  Lubos Slovak committed Jul 30, 2014 18   Daniel Salzman committed Dec 10, 2015 19 #include "libknot/attribute.h"  Marek Vavrusa committed Jan 07, 2014 20 #include "libknot/packet/compr.h"  Daniel Salzman committed Nov 06, 2014 21 22 #include "libknot/errcode.h" #include "libknot/packet/pkt.h"  Daniel Salzman committed Dec 04, 2015 23 #include "contrib/tolower.h"  Lubos Slovak committed Oct 16, 2014 24   Filip Široký committed Oct 03, 2017 25 /*! \brief Helper for \ref knot_compr_put_dname, writes label(s) with size checks. */  Marek Vavrusa committed Jan 07, 2014 26 27 28 29 30 31 32 33 #define WRITE_LABEL(dst, written, label, max, len) \ if ((written) + (len) > (max)) { \ return KNOT_ESPACE; \ } else { \ memcpy((dst) + (written), (label), (len)); \ written += (len); \ }  Lubos Slovak committed Sep 24, 2014 34 _public_  Jan Včelák committed Jan 15, 2014 35 36 int knot_compr_put_dname(const knot_dname_t *dname, uint8_t *dst, uint16_t max, knot_compr_t *compr)  Marek Vavrusa committed Jan 07, 2014 37 {  Jan Včelák committed Jan 15, 2014 38 39 40  if (dname == NULL || dst == NULL) { return KNOT_EINVAL; }  Daniel Salzman committed Jul 28, 2015 41 42  /* Write uncompressible names directly (zero label dname). */  Marek Vavrusa committed Jan 07, 2014 43 44 45 46  if (compr == NULL || *dname == '\0') { return knot_dname_to_wire(dst, dname, max); }  Daniel Salzman committed Jul 28, 2015 47  /* Get number of labels (should not be a zero label dname). */  Daniel Salzman committed Jan 10, 2018 48  size_t name_labels = knot_dname_labels(dname, NULL);  Daniel Salzman committed Jul 28, 2015 49  assert(name_labels > 0);  Marek Vavrusa committed Jan 07, 2014 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68  /* 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. */  Jan Včelák committed Jan 15, 2014 69  assert(name_labels == suffix_labels);  Marek Vavrusa committed Jan 07, 2014 70 71 72 73 74 75 76 77 78  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. */  Mark Karpilovskij committed Aug 03, 2017 79  if (!knot_dname_label_is_equal(dname, suffix)) {  Marek Vavrusa committed Jan 07, 2014 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104  /* 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); }  Jan Včelák committed Aug 07, 2014 105 106 107 108  assert(dst >= compr->wire); size_t wire_pos = dst - compr->wire; assert(wire_pos < KNOT_WIRE_MAX_PKTSIZE);  Marek Vavrusa committed Jan 07, 2014 109  /* Heuristics - expect similar names are grouped together. */  Jan Včelák committed Aug 07, 2014 110 111  if (written > sizeof(uint16_t) && wire_pos + written < KNOT_WIRE_PTR_MAX) { compr->suffix.pos = wire_pos;  Marek Vavrusa committed Jan 07, 2014 112 113  compr->suffix.labels = orig_labels; }  Jan Včelák committed Nov 14, 2014 114   Marek Vavrusa committed Jan 07, 2014 115 116 117 118  return written; } #undef WRITE_LABEL