]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add fr_dbuff_move() and tests (#3675)
authorJames Jones <jejones3141@gmail.com>
Thu, 8 Oct 2020 14:57:45 +0000 (09:57 -0500)
committerGitHub <noreply@github.com>
Thu, 8 Oct 2020 14:57:45 +0000 (09:57 -0500)
src/lib/util/dbuff.c [new file with mode: 0644]
src/lib/util/dbuff.h
src/lib/util/dbuff_tests.c
src/lib/util/libfreeradius-util.mk

diff --git a/src/lib/util/dbuff.c b/src/lib/util/dbuff.c
new file mode 100644 (file)
index 0000000..fcc29a2
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *   This library is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU Lesser General Public
+ *   License as published by the Free Software Foundation; either
+ *   version 2.1 of the License, or (at your option) any later version.
+ *
+ *   This library 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
+ *   Lesser General Public License for more details.
+ *
+ *   You should have received a copy of the GNU Lesser General Public
+ *   License along with this library; if not, write to the Free Software
+ *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+ /** A generic data buffer structure for encoding and decoding
+ *
+ * Because doing manual length checks is error prone and a waste of everyone's time.
+ *
+ * @file src/lib/util/dbuff.c
+ *
+ * @copyright 2020 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
+ */
+
+RCSID("$Id:")
+
+#include <freeradius-devel/util/dbuff.h>
+
+#if defined(__clang_analyzer__) || !defined(NDEBUG)
+#  define CHECK_DBUFF_INIT(_sbuff)     if (!(_sbuff)->extend && (unlikely(!(_sbuff)->buff) || unlikely(!(_sbuff)->start) || unlikely(!(_sbuff)->end) || unlikely(!(_sbuff)->p))) return 0;
+#else
+#  define CHECK_DBUFF_INIT(_sbuff)
+#endif
+
+/** start/end flavored mem{cpy,move} wrapper with sanity checks
+ */
+static inline CC_HINT(always_inline) ssize_t safecpy(uint8_t *o_start, uint8_t *o_end,
+                                                    uint8_t const *i_start, uint8_t const *i_end)
+{
+       ssize_t diff;
+       size_t  i_len = i_end - i_start;
+
+       if (unlikely((o_end < o_start) || (i_end < i_start))) return 0; /* sanity check */
+
+       diff = (o_end - o_start) - (i_len);
+       if (diff < 0) return diff;
+
+       if ((i_start > o_end) || (i_end < o_start)) {                   /* no-overlap */
+               memcpy(o_start,  i_start, i_len);
+       } else {                                                        /* overlap */
+               memmove(o_start, i_start, i_len);
+       }
+
+       return (i_len);
+}
+
+/** Move data from one dbuff to another
+ *
+ * @note Do not call this function directly; use #fr_dbuff_move
+ *
+ * Both in and out will be advanced by
+ * min {len, fr_dbuff_remaining(out), fr_dbuff_remaining(in)}; eventually,
+ * we'll attempt to extend dbuffs where possible and needed to make len bytes
+ * available in both in and out.
+ *
+ * @param[in] out      dbuff to copy data to.
+ * @param[in] in       dbuff to copy data from.
+ * @param[in] len      Maximum number of bytes to copy.
+ * @return The amount of data copied.
+ */
+size_t _fr_dbuff_move_dbuff_to_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t len)
+{
+       size_t o_remaining = fr_dbuff_remaining(out);
+       size_t i_remaining = fr_dbuff_remaining(in);
+       size_t to_copy = len;
+       if (to_copy > o_remaining) to_copy = o_remaining;
+       if (to_copy > i_remaining) to_copy = i_remaining;
+       safecpy(fr_dbuff_current(out), fr_dbuff_end(out), fr_dbuff_current(in), fr_dbuff_current(in) + to_copy);
+       return fr_dbuff_advance(out, fr_dbuff_advance(in, to_copy));
+}
+
+/** Move data from a marker to a dbuff
+ *
+ * @note Do not call this function directly; use #fr_dbuff_move
+ *
+ * Both in and out will be advanced by
+ * min {len, fr_dbuff_remaining(out), fr_dbuff_marker_remaining(in)}; eventually,
+ * we'll attempt to extend dbuffs where possible and needed to make len bytes
+ * available in both in and out.
+ *
+ * @param[in] out      dbuff to copy data to.
+ * @param[in] in       marker to copy data from.
+ * @param[in] len      Maximum number of bytes to copy.
+ * @return The amount of data copied.
+ */
+size_t _fr_dbuff_move_marker_to_dbuff(fr_dbuff_t *out, fr_dbuff_marker_t *in, size_t len)
+{
+       size_t o_remaining = fr_dbuff_remaining(out);
+       size_t i_remaining = fr_dbuff_marker_remaining(in);
+       size_t to_copy = len;
+       if (to_copy > o_remaining) to_copy = o_remaining;
+       if (to_copy > i_remaining) to_copy = i_remaining;
+       safecpy(fr_dbuff_current(out), fr_dbuff_end(out), fr_dbuff_marker_current(in),
+               fr_dbuff_marker_current(in) + to_copy);
+       return fr_dbuff_advance(out, fr_dbuff_marker_advance(in, to_copy));
+}
+
+/** Move data from one marker to another
+ *
+ * @note Do not call this function directly; use #fr_dbuff_move
+ *
+ * Both in and out will be advanced by
+ * min {len, fr_dbuff_marker_remaining(out), fr_dbuff_marker_remaining(in)}; eventually,
+ * we'll attempt to extend dbuffs where possible and needed to make len bytes
+ * available in both in and out.
+ *
+ * @param[in] out      dbuff to copy data to.
+ * @param[in] in       marker to copy data from.
+ * @param[in] len      Maximum number of bytes to copy.
+ * @return The amount of data copied.
+ */
+size_t _fr_dbuff_move_marker_to_marker(fr_dbuff_marker_t *out, fr_dbuff_marker_t *in, size_t len)
+{
+       size_t o_remaining = fr_dbuff_marker_remaining(out);
+       size_t i_remaining = fr_dbuff_marker_remaining(in);
+       size_t to_copy = len;
+       if (to_copy > o_remaining) to_copy = o_remaining;
+       if (to_copy > i_remaining) to_copy = i_remaining;
+       safecpy(fr_dbuff_marker_current(out), fr_dbuff_marker_end(out), fr_dbuff_marker_current(in),
+               fr_dbuff_marker_current(in) + to_copy);
+       return fr_dbuff_marker_advance(out, fr_dbuff_marker_advance(in, to_copy));
+}
+
+/** Move data from a dbuff to a marker
+ *
+ * @note Do not call this function directly; use #fr_dbuff_move
+ *
+ * Both in and out will be advanced by
+ * min {len, fr_dbuff_marker_remaining(out), fr_dbuff_marker_remaining(in)}; eventually,
+ * we'll attempt to extend dbuffs where possible and needed to make len bytes
+ * available in both in and out.
+ *
+ * @param[in] out      dbuff to copy data to.
+ * @param[in] in       marker to copy data from.
+ * @param[in] len      Maximum number of bytes to copy.
+ * @return The amount of data copied.
+ */
+size_t _fr_dbuff_move_dbuff_to_marker(fr_dbuff_marker_t *out, fr_dbuff_t *in, size_t len)
+{
+       size_t o_remaining = fr_dbuff_marker_remaining(out);
+       size_t i_remaining = fr_dbuff_remaining(in);
+       size_t to_copy = len;
+       if (to_copy > o_remaining) to_copy = o_remaining;
+       if (to_copy > i_remaining) to_copy = i_remaining;
+       safecpy(fr_dbuff_marker_current(out), fr_dbuff_marker_end(out), fr_dbuff_current(in),
+               fr_dbuff_current(in) + to_copy);
+       return fr_dbuff_marker_advance(out, fr_dbuff_advance(in, to_copy));
+}
index 9e0df708cd23b1d5e2dcd571fbf79554b74acaf3..e8fb540f7f7dff5d1b369647c9a4bbe61f8d0574 100644 (file)
@@ -530,6 +530,14 @@ static inline size_t fr_dbuff_marker_used(fr_dbuff_marker_t *m)
 {
        return m->p - m->parent->start;
 }
+
+/* what is the end of the buffer (determined from marker)
+ *
+ */
+static inline uint8_t *fr_dbuff_marker_end(fr_dbuff_marker_t *m)
+{
+       return m->parent->end;
+}
 /** @} */
 
 /** @name copy data to dbuff
@@ -766,6 +774,39 @@ static inline ssize_t fr_dbuff_uint64v_in(fr_dbuff_t *dbuff, uint64_t num)
 
        return fr_dbuff_memcpy_in(dbuff, ((uint8_t *)&num) + (sizeof(uint64_t) - ret), ret);
 }
+
+size_t _fr_dbuff_move_dbuff_to_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t len);
+
+size_t _fr_dbuff_move_marker_to_dbuff(fr_dbuff_t *out, fr_dbuff_marker_t *in, size_t len);
+
+size_t _fr_dbuff_move_marker_to_marker(fr_dbuff_marker_t *out, fr_dbuff_marker_t *in, size_t len);
+
+size_t _fr_dbuff_move_dbuff_to_marker(fr_dbuff_marker_t *out, fr_dbuff_t *in, size_t len);
+
+/** Copy in as many bytes as possible from one dbuff or marker to another
+ *
+ * @param[in] out      to copy into.
+ * @param[in] in       to copy from.
+ * @param[in] len      The maximum length to copy.
+ * @return Number of bytes to copy.
+ */
+#define fr_dbuff_move(_out, _in, _len) \
+       _Generic((_out), \
+               fr_dbuff_t *            : \
+                       _Generic((_in), \
+                               fr_dbuff_t *            : _fr_dbuff_move_dbuff_to_dbuff((fr_dbuff_t *)_out, \
+                                                                                       (fr_dbuff_t *)_in, _len), \
+                               fr_dbuff_marker_t *     : _fr_dbuff_move_marker_to_dbuff((fr_dbuff_t *)_out, \
+                                                                                       (fr_dbuff_marker_t *)_in, _len) \
+                       ), \
+              fr_dbuff_marker_t *      : \
+                       _Generic((_in), \
+                               fr_dbuff_t *            : _fr_dbuff_move_dbuff_to_marker((fr_dbuff_marker_t *)_out, \
+                                                                                        (fr_dbuff_t *)_in, _len), \
+                               fr_dbuff_marker_t *     : _fr_dbuff_move_marker_to_marker((fr_dbuff_marker_t *)_out, \
+                                                                                         (fr_dbuff_marker_t *)_in, _len) \
+                       ) \
+       )
 /** @} */
 
 #ifdef __cplusplus
index 5a2c6b13aa7b2e65a081924bab9be4a43a6df83e..50fe77fc11dcd3cc2dfc87da3567ed61369b34b6 100644 (file)
@@ -219,6 +219,47 @@ static void test_dbuff_net_encode(void)
        TEST_CHECK(fr_dbuff_in(&dbuff, u64val) == -(ssize_t)(sizeof(uint64_t) - sizeof(uint32_t)));
 }
 
+static void test_dbuff_move(void)
+{
+       uint8_t                 buff1[26], buff2[26], buff3[10];
+       fr_dbuff_t              dbuff1, dbuff2, dbuff3;
+       fr_dbuff_marker_t       marker1, marker2;
+
+       memcpy(buff1, "abcdefghijklmnopqrstuvwxyz", sizeof(buff1));
+       memcpy(buff2, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", sizeof(buff2));
+       memcpy(buff3, "0123456789", sizeof(buff3));
+       fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
+       fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
+       fr_dbuff_init(&dbuff3, buff3, sizeof(buff3));
+       fr_dbuff_marker(&marker1, &dbuff1);
+       fr_dbuff_marker(&marker2, &dbuff2);
+
+       TEST_CASE("move dbuff to dbuff");
+       TEST_CHECK(fr_dbuff_move(&dbuff1, &dbuff2, 13) == 13);
+       TEST_CHECK(fr_dbuff_used(&dbuff1) == 13);
+       TEST_CHECK(fr_dbuff_used(&dbuff2) == 13);
+       TEST_CHECK(memcmp(dbuff1.start, "ABCDEFGHIJKLMnopqrstuvwxyz", 26) == 0);
+
+       TEST_CASE("move dbuff to marker");
+       fr_dbuff_marker_advance(&marker2, 4);
+       TEST_CHECK(fr_dbuff_move(&marker2, &dbuff3, 10) == 10);
+       TEST_CHECK(fr_dbuff_marker_used(&marker2) == 14);
+       TEST_CHECK(memcmp(dbuff2.start, "ABCD0123456789OPQRSTUVWXYZ", 26) == 0);
+
+       TEST_CASE("move marker to dbuff");
+       fr_dbuff_marker_advance(&marker1, 7);
+       TEST_CHECK(fr_dbuff_move(&dbuff1, &marker1, 6) == 6);
+       TEST_CHECK(fr_dbuff_used(&dbuff1) == 19);
+       TEST_CHECK(fr_dbuff_marker_used(&marker1) == 13);
+       TEST_CHECK(memcmp(dbuff1.start, "ABCDEFGHIJKLMHIJKLMtuvwxyz", 26) == 0);
+
+       TEST_CASE("move marker to marker");
+       TEST_CHECK(fr_dbuff_move(&marker2, &marker1, 8) == 8);
+       TEST_CHECK(fr_dbuff_marker_used(&marker1) == 21);
+       TEST_CHECK(fr_dbuff_marker_used(&marker2) == 22);
+       TEST_CHECK(memcmp(dbuff2.start, "ABCD0123456789HIJKLMtuWXYZ", 26) == 0);
+}
+
 
 TEST_LIST = {
        /*
@@ -228,6 +269,7 @@ TEST_LIST = {
        { "fr_dbuff_init_no_parent",                    test_dbuff_init_no_parent },
        { "fr_dbuff_max",                               test_dbuff_max },
        { "fr_dbuff_in",                        test_dbuff_net_encode },
+       { "fr_dbuff_move",                              test_dbuff_move },
 
        { NULL }
 };
index c557b6d23924c21bd65e9813d4dbce32be5d7429..f471aa95b5367d29187ca79330b411c6849f4b82 100644 (file)
@@ -10,6 +10,7 @@ SOURCES               := \
                   base64.c \
                   cap.c \
                   cursor.c \
+                  dbuff.c \
                   debug.c \
                   dict_print.c \
                   dict_tokenize.c \