]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add functions and macros to read values and copy bytes from dbuffs (#3709)
authorJames Jones <jejones3141@gmail.com>
Tue, 27 Oct 2020 19:07:37 +0000 (14:07 -0500)
committerGitHub <noreply@github.com>
Tue, 27 Oct 2020 19:07:37 +0000 (13:07 -0600)
src/lib/util/dbuff.h
src/lib/util/dbuff_tests.c

index 93dce277b5831df751f772400bf60dffafcccc06..97b17f936b332b6f84aac633d34677febb105f81 100644 (file)
@@ -1016,6 +1016,94 @@ size_t _fr_dbuff_move_dbuff_to_marker(fr_dbuff_marker_t *out, fr_dbuff_t *in, si
        )
 /** @} */
 
+/** @name copy data from dbuff
+ * @{
+ */
+
+static inline ssize_t _fr_dbuff_memcpy_out(uint8_t *out, fr_dbuff_t *dbuff, size_t outlen)
+{
+       FR_DBUFF_EXTEND_LOWAT_OR_RETURN(dbuff, outlen);
+
+       memcpy(out, dbuff->p, outlen);
+
+       return _fr_dbuff_set(dbuff, dbuff->p + outlen);
+}
+
+static inline ssize_t _fr_dbuff_memcpy_out_dbuff(fr_dbuff_t *out, fr_dbuff_t *in, size_t outlen)
+{
+       if (outlen > fr_dbuff_remaining(in)) outlen = fr_dbuff_remaining(in);
+
+       /*
+        *      If there's too many bytes, then
+        *      return how many additional bytes
+        *      we would have needed.
+        */
+       FR_DBUFF_EXTEND_LOWAT_OR_RETURN(out, outlen);
+
+       (void)_fr_dbuff_memcpy_out(out->p, in, outlen);
+
+       return _fr_dbuff_set(out, out->p + outlen);
+}
+
+#define FR_DBUFF_MEMCPY_OUT_RETURN(_out, _dbuff, _outlen) FR_DBUFF_RETURN(fr_dbuff_memcpy_out, _out, _dbuff, _outlen)
+
+/** Copy outlen bytes from the dbuff
+ *
+ * If _out is a dbuff, it will be advanced by the number of bytes
+ * copied from _in.
+ *
+ * If _out is a dbuff and _outlen is greater than the
+ * number of bytes available in _out, then the copy operation will
+ * be truncated, so that we don't write off the end of the buffer.
+ *
+ * @param[in] _out     to copy data to.
+ * @param[in] _in      Data to copy to dbuff.
+ * @param[in] _outlen  How much data we need to copy.
+ *                     If _out is a char * or dbuff * and SIZE_MAX
+ *                     is passed, then _inlen will be substituted
+ *                     for the length of the buffer.
+ * @return
+ *     - 0     no data copied.
+ *     - >0    the number of bytes copied.
+ *     - <0    the number of bytes we would have needed
+ *             to complete the copy operation.
+ */
+#define fr_dbuff_memcpy_out(_out, _in, _outlen) \
+       _Generic((_out), \
+                uint8_t *      : _fr_dbuff_memcpy_out((uint8_t *)(_out), _in, _outlen), \
+                int8_t *       : _fr_dbuff_memcpy_out((uint8_t *)(_out), _in, _outlen), \
+                fr_dbuff_t *   : _fr_dbuff_memcpy_out_dbuff((fr_dbuff_t *)_out, _in, _outlen) \
+       )
+
+#define FR_DBUFF_OUT_DEF(_type) \
+static inline ssize_t fr_dbuff_##_type##_out(_type##_t *num, fr_dbuff_t *dbuff) \
+{ \
+       fr_assert(num); \
+       FR_DBUFF_EXTEND_LOWAT_OR_RETURN(dbuff, sizeof(_type##_t)); \
+       *num = fr_net_to_##_type(dbuff->p); \
+       return fr_dbuff_advance(dbuff, sizeof(_type##_t)); \
+}
+
+FR_DBUFF_OUT_DEF(uint16)
+FR_DBUFF_OUT_DEF(uint32)
+FR_DBUFF_OUT_DEF(uint64)
+FR_DBUFF_OUT_DEF(int16)
+FR_DBUFF_OUT_DEF(int32)
+FR_DBUFF_OUT_DEF(int64)
+
+#define fr_dbuff_out(_value, _dbuff) \
+       _Generic((_value), \
+               uint16_t *      : fr_dbuff_uint16_out((uint16_t *)(_value), _dbuff), \
+               uint32_t *      : fr_dbuff_uint32_out((uint32_t *)(_value), _dbuff), \
+               uint64_t *      : fr_dbuff_uint64_out((uint64_t *)(_value), _dbuff), \
+               int16_t *       : fr_dbuff_int16_out((int16_t *)(_value), _dbuff), \
+               int32_t *       : fr_dbuff_int32_out((int32_t *)(_value), _dbuff), \
+               int64_t *       : fr_dbuff_int64_out((int64_t *)(_value), _dbuff) \
+       )
+#define FR_DBUFF_OUT_RETURN(_value, _dbuff) FR_DBUFF_RETURN(fr_dbuff_out, _value, _dbuff)
+
+/** @} */
+
 #ifdef __cplusplus
 }
 #endif
index 4cea048770d8dab3c6283f4a23b2ee071438f5af..84bfebaf8487105551461b961c317509e4e7c8b7 100644 (file)
@@ -313,6 +313,61 @@ static void test_dbuff_talloc_extend_multi_level(void)
        TEST_CHECK(fr_dbuff_in(&dbuff2, (uint64_t) 0x123456789abcdef0) == -8);
 }
 
+/** Test functions that read from dbuffs.
+ *
+ */
+static void test_dbuff_out(void)
+{
+       uint8_t const   buff1[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+       uint8_t         buff2[8];
+       uint8_t         buff3[8];
+       fr_dbuff_t      dbuff1;
+       fr_dbuff_t      dbuff2;
+       uint16_t        u16val = 0;
+       uint32_t        u32val = 0;
+       uint64_t        u64val = 0;
+       int16_t         i16val = 0;
+       int32_t         i32val = 0;
+       int64_t         i64val = 0;
+
+       fr_dbuff_init(&dbuff1, buff1, sizeof(buff1));
+       fr_dbuff_init(&dbuff2, buff2, sizeof(buff2));
+
+       TEST_CASE("Check dbuff reads of unsigned integers");
+       TEST_CHECK(fr_dbuff_out(&u16val, &dbuff1) == 2);
+       TEST_CHECK(u16val == 0x0123);
+       TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == 4);
+       TEST_CHECK(u32val == 0x456789ab);
+       fr_dbuff_set_to_start(&dbuff1);
+       TEST_CHECK(fr_dbuff_out(&u64val, &dbuff1) == 8);
+       TEST_CHECK(u64val == 0x0123456789abcdef);
+
+       TEST_CASE("Don't walk off the end of the buffer");
+       TEST_CHECK(fr_dbuff_out(&u32val, &dbuff1) == -4);
+
+       TEST_CASE("Check dbuff reads of signed integers");
+       fr_dbuff_set_to_start(&dbuff1);
+       TEST_CHECK(fr_dbuff_out(&i16val, &dbuff1) == 2);
+       TEST_CHECK(i16val == 0x0123);
+       TEST_CHECK(fr_dbuff_out(&i32val, &dbuff1) == 4);
+       TEST_CHECK(i32val == 0x456789ab);
+       fr_dbuff_set_to_start(&dbuff1);
+       TEST_CHECK(fr_dbuff_out(&i64val, &dbuff1) == 8);
+       TEST_CHECK(i64val == 0x0123456789abcdef);
+
+       TEST_CASE("fr_dbuff_memcpy_out");
+       fr_dbuff_set_to_start(&dbuff1);
+       memset(buff3, 0, sizeof(buff3));
+       TEST_CHECK(fr_dbuff_memcpy_out(buff3, &dbuff1, 7) == 7);
+       TEST_CHECK(memcmp(buff3, fr_dbuff_start(&dbuff1), 7) == 0 && buff3[7] == 0);
+       fr_dbuff_set_to_start(&dbuff1);
+       TEST_CHECK(fr_dbuff_memcpy_out(&dbuff2, &dbuff1, 4) == 4);
+       fr_dbuff_set_to_start(&dbuff1);
+       fr_dbuff_advance(&dbuff1, 3);
+       TEST_CHECK(fr_dbuff_memcpy_out(&dbuff2, &dbuff1, 4) == 4);
+       TEST_CHECK(memcmp(fr_dbuff_start(&dbuff2), fr_dbuff_start(&dbuff1), 4) == 0 &&
+                  memcmp(fr_dbuff_start(&dbuff2) + 4, fr_dbuff_start(&dbuff1) + 3, 4) == 0);
+}
 
 TEST_LIST = {
        /*
@@ -325,6 +380,7 @@ TEST_LIST = {
        { "fr_dbuff_move",                              test_dbuff_move },
        { "fr_dbuff_talloc_extend",                     test_dbuff_talloc_extend },
        { "fr_dbuff_talloc_extend_multi_level",         test_dbuff_talloc_extend_multi_level },
+       { "fr_dbff_out",                                test_dbuff_out },
 
 
        { NULL }