]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
misc: Add htonx and ntohx
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 5 Mar 2020 23:55:18 +0000 (17:55 -0600)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Thu, 5 Mar 2020 23:55:31 +0000 (17:55 -0600)
For efficient packing and unpacking of network order integers, where the integer is of a variable size.

src/lib/util/misc.h

index 34ce824e4581818ba7053ff783b547021f14266e..9680aa0ad595f229362da840fcf495f97e8ec8b2 100644 (file)
@@ -35,6 +35,7 @@ extern "C" {
 #include <ctype.h>
 #include <signal.h>
 #include <stdbool.h>
+#include <strings.h>
 #include <talloc.h>
 
 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);