From: James Jones Date: Tue, 27 Oct 2020 19:07:37 +0000 (-0500) Subject: Add functions and macros to read values and copy bytes from dbuffs (#3709) X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=34d2012e5b59346e5a0511010e09de0e64a5e29b;p=thirdparty%2Ffreeradius-server.git Add functions and macros to read values and copy bytes from dbuffs (#3709) --- diff --git a/src/lib/util/dbuff.h b/src/lib/util/dbuff.h index 93dce277b58..97b17f936b3 100644 --- a/src/lib/util/dbuff.h +++ b/src/lib/util/dbuff.h @@ -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 diff --git a/src/lib/util/dbuff_tests.c b/src/lib/util/dbuff_tests.c index 4cea048770d..84bfebaf848 100644 --- a/src/lib/util/dbuff_tests.c +++ b/src/lib/util/dbuff_tests.c @@ -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 }