]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
dbuff: Add support for copying from dbuff in fr_dbuff_memcpy_in
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 13 Jul 2020 18:57:11 +0000 (11:57 -0700)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Mon, 13 Jul 2020 18:57:11 +0000 (11:57 -0700)
src/lib/util/dbuff.h
src/lib/util/value.c

index 1b360e67bb958548790071d9382aa81617644370..8d33ce7c5fec02584b3d0e9722b2022fda92746e 100644 (file)
@@ -328,31 +328,63 @@ static inline ssize_t fr_dbuff_advance(fr_dbuff_t *dbuff, size_t inlen)
 }
 #define FR_DBUFF_ADVANCE_RETURN(_dbuff, _inlen) FR_DBUFF_RETURN(fr_dbuff_advance, _dbuff, _inlen)
 
-/** Copy at most inlen bytes into the dbuff
- *
- * Use this variant when writing data to a streaming buffer where
- * partial writes will be tracked.
- *
- * @param[in] dbuff    to copy data to.
- * @param[in] in       Data to copy to dbuff.
- * @param[in] inlen    How much data we need to copy.
- * @return
- *     - 0     no data copied.
- *     - >0    the number of bytes copied to the dbuff.
- */
-static inline size_t fr_dbuff_memcpy_in_partial(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen)
+static inline ssize_t _fr_dbuff_memcpy_in(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen)
 {
        size_t freespace = fr_dbuff_remaining(dbuff);
 
        fr_assert(!dbuff->is_const);
 
-       if (inlen > freespace) inlen = freespace;
+       if (inlen > freespace) return -(inlen - freespace);
 
        memcpy(dbuff->p, in, inlen);
 
        return _fr_dbuff_advance(dbuff, inlen);
 }
 
+static inline ssize_t _fr_dbuff_memcpy_in_dbuff(fr_dbuff_t *out, fr_dbuff_t const *in, size_t inlen)
+{
+       size_t outlen;
+       fr_dbuff_t *in_m;
+
+       if (inlen == SIZE_MAX) inlen = fr_dbuff_remaining(in);
+       outlen = fr_dbuff_remaining(out);
+
+       /*
+        *      If there's too many bytes, then
+        *      return how many additional bytes
+        *      we would have needed.
+        */
+       if (inlen > outlen) return -(inlen - outlen);
+
+       (void)_fr_dbuff_memcpy_in(out, in->p, inlen);
+
+       memcpy(&in_m, &in, sizeof(in_m));       /* Stupid _Generic const issues */
+       return _fr_dbuff_advance(in_m, inlen);
+}
+
+/** Copy at inlen bytes into the dbuff
+ *
+ * If _in is a dbuff, it will be advanced by the number of bytes
+ * written to _out.
+ *
+ * @param[in] _out     to copy data to.
+ * @param[in] _in      Data to copy to dbuff.
+ * @param[in] _inlen   How much data we need to copy.
+ * @return
+ *     - 0     no data copied.
+ *     - >0    the number of bytes copied to the dbuff.
+ *     - <0    the number of bytes we would have needed
+ *             to complete the copy operation.
+ */
+#define fr_dbuff_memcpy_in(_out, _in, _inlen) \
+       _Generic((_in), \
+                uint8_t *              : _fr_dbuff_memcpy_in(_out, (uint8_t const *)(_in), _inlen), \
+                uint8_t const *        : _fr_dbuff_memcpy_in(_out, (uint8_t const *)(_in), _inlen), \
+                char *                 : _fr_dbuff_memcpy_in(_out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
+                char const *           : _fr_dbuff_memcpy_in(_out, (uint8_t const *)(_in), _inlen == SIZE_MAX ? strlen((char const *)(_in)) : _inlen), \
+                fr_dbuff_t *           : _fr_dbuff_memcpy_in_dbuff(_out, (fr_dbuff_t const *)(_in), _inlen) \
+       )
+
 /** Copy exactly n bytes into dbuff
  *
  * @param[in] dbuff    to copy data to.
@@ -363,19 +395,60 @@ static inline size_t fr_dbuff_memcpy_in_partial(fr_dbuff_t *dbuff, uint8_t const
  *     - >0    the number of bytes copied to the dbuff.
  *     - <0    the number of bytes required to complete the copy.
  */
-static inline ssize_t fr_dbuff_memcpy_in(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen)
+#define FR_DBUFF_MEMCPY_IN_RETURN(_dbuff, _in, _inlen) FR_DBUFF_RETURN(fr_dbuff_memcpy_in, _dbuff, _in, _inlen)
+
+static inline size_t _fr_dbuff_memcpy_in_partial(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen)
 {
        size_t freespace = fr_dbuff_remaining(dbuff);
 
        fr_assert(!dbuff->is_const);
 
-       if (inlen > freespace) return -(inlen - freespace);
+       if (inlen > freespace) inlen = freespace;
 
        memcpy(dbuff->p, in, inlen);
 
        return _fr_dbuff_advance(dbuff, inlen);
 }
-#define FR_DBUFF_MEMCPY_IN_RETURN(_dbuff, _in, _inlen) FR_DBUFF_RETURN(fr_dbuff_memcpy_in, _dbuff, _in, _inlen)
+
+static inline size_t _fr_dbuff_memcpy_in_dbuff_partial(fr_dbuff_t *out, fr_dbuff_t const *in, size_t inlen)
+{
+       size_t outlen;
+       fr_dbuff_t *in_m;
+
+       if (inlen == SIZE_MAX) inlen = fr_dbuff_remaining(in);
+       outlen = fr_dbuff_remaining(out);
+
+       if (inlen > outlen) inlen = outlen;
+
+       (void)_fr_dbuff_memcpy_in(out, in->p, inlen);
+
+       memcpy(&in_m, &in, sizeof(in_m));       /* Stupid _Generic const issues */
+       return _fr_dbuff_advance(in_m, inlen);
+}
+
+/** Copy at most inlen bytes into the dbuff
+ *
+ * Use this variant when writing data to a streaming buffer where
+ * partial writes will be tracked.
+ *
+ * If _in is a dbuff, it will be advanced by the number of bytes
+ * written to _out.
+ *
+ * @param[in] _out     to copy data to.
+ * @param[in] _in      Data to copy to dbuff.
+ * @param[in] _inlen   How much data we need to copy.
+ * @return
+ *     - 0     no data copied.
+ *     - >0    the number of bytes copied to the dbuff.
+ */
+#define fr_dbuff_memcpy_in_partial(_out, _in, _inlen) \
+       _Generic((_in), \
+               uint8_t *       : _fr_dbuff_memcpy_in_partial(_out, (uint8_t const *)_in, _inlen), \
+               uint8_t const * : _fr_dbuff_memcpy_in_partial(_out, (uint8_t const *)_in, _inlen), \
+               char *          : _fr_dbuff_memcpy_in_partial(_out, (uint8_t const *)_in, _inlen == SIZE_MAX ? strlen((char const *)_in) : _inlen), \
+               char const *    : _fr_dbuff_memcpy_in_partial(_out, (uint8_t const *)_in, _inlen == SIZE_MAX ? strlen((char const *)_in) : _inlen), \
+               fr_dbuff_t *    : _fr_dbuff_memcpy_in_dbuff_partial(_out, (fr_dbuff_t const *)_in, _inlen) \
+       )
 
 /** Copy a partial byte sequence into a dbuff
  *
index 74531e0397be87b5cb854e30b259ac975b558704..3187989e5512794671f3bbf7ab3ce0f71d04e018 100644 (file)
@@ -1055,7 +1055,7 @@ ssize_t fr_value_box_to_network_dbuff(size_t *need, fr_dbuff_t *dbuff, fr_value_
                        len = value->datum.length;
                }
 
-               if (value->datum.length > 0) fr_dbuff_memcpy_in(dbuff, value->datum.ptr, len);
+               if (value->datum.length > 0) fr_dbuff_memcpy_in(dbuff, (uint8_t const *)value->datum.ptr, len);
 
                return len;
        }