From: Arran Cudbard-Bell Date: Thu, 5 Mar 2020 23:55:18 +0000 (-0600) Subject: misc: Add htonx and ntohx X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=aa7caef0ec57d5ce1ef29b0de1ab94426178a501;p=thirdparty%2Ffreeradius-server.git misc: Add htonx and ntohx For efficient packing and unpacking of network order integers, where the integer is of a variable size. --- diff --git a/src/lib/util/misc.h b/src/lib/util/misc.h index 34ce824e458..9680aa0ad59 100644 --- a/src/lib/util/misc.h +++ b/src/lib/util/misc.h @@ -35,6 +35,7 @@ extern "C" { #include #include #include +#include #include typedef int8_t (*fr_cmp_t)(void const *a, void const *b); @@ -167,6 +168,104 @@ static inline bool is_zero(char const *value) return true; } +/** Encode a 64bit unsigned integer as a big endian number in the fewest bytes possible + * + * @param[out] out Where to write big endian encoding of num. + * Should be at least 8 bytes. + * @param[in] num Number to encode. + * @return + * - The number of bytes written to out. + */ +static inline size_t htonx(uint8_t *out, uint64_t num) +{ + size_t ret; + + /* + * flsll isn't POSIX, but it's in at least + * Linux, FreeBSD, OpenBSD and Solaris. + * + * If we really care, implementing it + * in missing.c is trivial. + * + * This version however should compile down + * to a single CPU instruction on supported + * platforms. + */ + ret = ROUND_UP_DIV((size_t)flsll((long long)num), 8); + switch (ret) { + case 8: + out[7] = (num & 0xFF00000000000000) >> 56; + /* FALL-THROUGH */ + case 7: + out[6] = (num & 0xFF000000000000) >> 48; + /* FALL-THROUGH */ + case 6: + out[5] = (num & 0xFF0000000000) >> 40; + /* FALL-THROUGH */ + case 5: + out[4] = (num & 0xFF00000000) >> 32; + /* FALL-THROUGH */ + case 4: + out[3] = (num & 0xFF000000) >> 24; + /* FALL-THROUGH */ + case 3: + out[2] = (num & 0xFF0000) >> 16; + /* FALL-THROUGH */ + case 2: + out[1] = (num & 0xFF00) >> 8; + /* FALL-THROUGH */ + case 1: + out[0] = (num & 0xFF); + return ret; + + case 0: + out[0] = 0; + return 1; + } + + return 0; +} + +/** Convert a big endian number of variable size to a unsigned 64bit integer of native endianness + * + * @param[in] data Buffer containing the number. + * @param[in] data_len Length of number. + * @return unsigned 64bit integer. + */ +static inline uint64_t ntohx(uint8_t const *data, size_t data_len) +{ + uint64_t ret = 0; + + switch (data_len) { + case 8: + ret += ((uint64_t)data[7]) << 56; + /* FALL-THROUGH */ + case 7: + ret += ((uint64_t)data[6]) << 48; + /* FALL-THROUGH */ + case 6: + ret += ((uint64_t)data[5]) << 40; + /* FALL-THROUGH */ + case 5: + ret += ((uint64_t)data[4]) << 32; + /* FALL-THROUGH */ + case 4: + ret += ((uint64_t)data[3]) << 24; + /* FALL-THROUGH */ + case 3: + ret += ((uint64_t)data[2]) << 16; + /* FALL-THROUGH */ + case 2: + ret += ((uint64_t)data[1]) << 8; + /* FALL-THROUGH */ + case 1: + ret += data[8]; + return ret; + } + + return 0; +} + int fr_set_signal(int sig, sig_t func); int fr_unset_signal(int sig); int rad_lockfd(int fd, int lock_len);