From 93d65ed6503b32865b5453238c159e603bb37cb8 Mon Sep 17 00:00:00 2001
From: lns <matzeton@googlemail.com>
Date: Mon, 8 Aug 2022 18:16:18 +0200
Subject: Support serialization of double-precision floating-point numbers.
 Fixes #1702.

Signed-off-by: lns <matzeton@googlemail.com>
Signed-off-by: Toni Uhlig <matzeton@googlemail.com>
---
 src/include/ndpi_api.h.in   |  32 ++++++++++++
 src/include/ndpi_typedefs.h |   1 +
 src/lib/Makefile.in         |   2 +-
 src/lib/ndpi_serializer.c   | 121 ++++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 151 insertions(+), 5 deletions(-)

(limited to 'src')

diff --git a/src/include/ndpi_api.h.in b/src/include/ndpi_api.h.in
index 2e8690203..3a81cceb3 100644
--- a/src/include/ndpi_api.h.in
+++ b/src/include/ndpi_api.h.in
@@ -1229,6 +1229,16 @@ extern "C" {
    */
   int ndpi_serialize_uint32_float(ndpi_serializer *serializer, u_int32_t key, float value, const char *format /* e.f. "%.2f" */);
 
+  /**
+   * Serialize a 32-bit unsigned int key and a double value
+   * @param serializer The serializer handle
+   * @param key The field name or ID
+   * @param value The field value
+   * @param format The double value format
+   * @return 0 on success, a negative number otherwise
+   */
+  int ndpi_serialize_uint32_double(ndpi_serializer *serializer, u_int32_t key, double value, const char *format /* e.f. "%.2f" */);
+
   /**
    * Serialize a 32-bit unsigned int key and a string value
    * @param serializer The serializer handle
@@ -1395,6 +1405,17 @@ extern "C" {
    */
   int ndpi_serialize_binary_float(ndpi_serializer *_serializer, const char *key, u_int16_t klen, float value, const char *format /* e.f. "%.2f" */);
 
+  /**
+   * Serialize an unterminated string key and a double value
+   * @param serializer The serializer handle
+   * @param key The field name or ID
+   * @param klen The key length
+   * @param value The field value
+   * @param format The double format
+   * @return 0 on success, a negative number otherwise
+   */
+  int ndpi_serialize_binary_double(ndpi_serializer *_serializer, const char *key, u_int16_t klen, double value, const char *format /* e.f. "%.2f" */);
+
   /**
    * Serialize a string key and a a float value
    * @param serializer The serializer handle
@@ -1405,6 +1426,16 @@ extern "C" {
    */
   int ndpi_serialize_string_float(ndpi_serializer *serializer, const char *key, float value, const char *format /* e.f. "%.2f" */);
 
+  /**
+   * Serialize a string key and a a double value
+   * @param serializer The serializer handle
+   * @param key The field name or ID
+   * @param value The field value
+   * @param format The double format
+   * @return 0 on success, a negative number otherwise
+   */
+  int ndpi_serialize_string_double(ndpi_serializer *serializer, const char *key, double value, const char *format /* e.f. "%.2f" */);
+
   /**
    * Serialize an unterminated string key and a boolean value (JSON/CSV only, not supported by TLV)
    * @param serializer The serializer handle
@@ -1586,6 +1617,7 @@ extern "C" {
   int ndpi_deserialize_value_int32(ndpi_deserializer *deserializer, int32_t *value);
   int ndpi_deserialize_value_int64(ndpi_deserializer *deserializer, int64_t *value);
   int ndpi_deserialize_value_float(ndpi_deserializer *deserializer, float *value);
+  int ndpi_deserialize_value_double(ndpi_deserializer *deserializer, double *value);
   int ndpi_deserialize_value_string(ndpi_deserializer *deserializer, ndpi_string *value);
 
   int ndpi_deserialize_clone_item(ndpi_deserializer *deserializer, ndpi_serializer *serializer);
diff --git a/src/include/ndpi_typedefs.h b/src/include/ndpi_typedefs.h
index 502c7fe12..377ed0e2e 100644
--- a/src/include/ndpi_typedefs.h
+++ b/src/include/ndpi_typedefs.h
@@ -1618,6 +1618,7 @@ typedef enum {
   ndpi_serialization_int32,
   ndpi_serialization_int64,
   ndpi_serialization_float,
+  ndpi_serialization_double,
   ndpi_serialization_string,
   ndpi_serialization_start_of_block,
   ndpi_serialization_end_of_block,
diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in
index 201c49420..b6db5330e 100644
--- a/src/lib/Makefile.in
+++ b/src/lib/Makefile.in
@@ -61,7 +61,7 @@ $(NDPI_LIB_STATIC): $(OBJECTS)
 	   $(RANLIB) $@      
 
 $(NDPI_LIB_SHARED): $(OBJECTS)
-	$(CC) -shared -fPIC $(SONAME_FLAG) -o $@ $(LDFLAGS) $(OBJECTS) $(LIBS)
+	$(CC) -shared -fPIC $(CFLAGS) $(SONAME_FLAG) -o $@ $(LDFLAGS) $(OBJECTS) $(LIBS)
 	ln -fs $(NDPI_LIB_SHARED) $(NDPI_LIB_SHARED_BASE)
 	ln -fs $(NDPI_LIB_SHARED) $(NDPI_LIB_SHARED_BASE).$(NDPI_VERSION_MAJOR)
 
diff --git a/src/lib/ndpi_serializer.c b/src/lib/ndpi_serializer.c
index 7843ace60..e51a168d0 100644
--- a/src/lib/ndpi_serializer.c
+++ b/src/lib/ndpi_serializer.c
@@ -492,6 +492,15 @@ static inline void ndpi_serialize_single_float(ndpi_private_serializer *serializ
 
 /* ********************************** */
 
+/* TODO: fix portability across platforms */
+static inline void ndpi_serialize_single_double(ndpi_private_serializer *serializer,
+                           double s) {
+  memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], &s, sizeof(s));
+  serializer->status.buffer.size_used += sizeof(double);
+}
+
+/* ********************************** */
+
 static inline void ndpi_serialize_single_string(ndpi_private_serializer *serializer,
 						const char *s, u_int16_t slen) {
   u_int16_t l = htons(slen);
@@ -571,6 +580,14 @@ static inline void ndpi_deserialize_single_float(ndpi_private_deserializer *dese
 
 /* ********************************** */
 
+/* TODO: fix portability across platforms */
+static inline void ndpi_deserialize_single_double(ndpi_private_deserializer *deserializer,
+                         u_int32_t offset, double *s) {
+  *s = *(double*)&deserializer->buffer.data[offset];
+}
+
+/* ********************************** */
+
 static inline void ndpi_deserialize_single_string(ndpi_private_deserializer *deserializer,
 						  u_int32_t offset, ndpi_string *v) {
   v->str_len = ntohs(*((u_int16_t *) &deserializer->buffer.data[offset]));
@@ -1633,6 +1650,62 @@ int ndpi_serialize_binary_float(ndpi_serializer *_serializer,
 
 /* ********************************** */
 
+int ndpi_serialize_binary_double(ndpi_serializer *_serializer,
+                    const char *key,
+                    u_int16_t klen,
+                    double value,
+                    const char *format /* e.f. "%.2f" */) {
+  ndpi_private_serializer *serializer = (ndpi_private_serializer*)_serializer;
+  u_int32_t buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
+  u_int32_t needed;
+
+  needed =
+    sizeof(u_int8_t) /* type */ +
+    sizeof(u_int16_t) /* key len */ +
+    klen /* key */ +
+    sizeof(double);
+
+  if(serializer->fmt == ndpi_serialization_format_json)
+    needed += 32 + klen;
+
+  if(buff_diff < needed) {
+    if(ndpi_extend_serializer_buffer(&serializer->buffer, needed - buff_diff) < 0)
+      return(-1);
+    buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
+  }
+
+  if(serializer->fmt == ndpi_serialization_format_json) {
+    ndpi_serialize_json_pre(_serializer);
+
+    if (!(serializer->status.flags & NDPI_SERIALIZER_STATUS_LIST)) {
+      serializer->status.buffer.size_used += ndpi_json_string_escape(key, klen,
+        (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
+      serializer->buffer.data[serializer->status.buffer.size_used] = ':';
+      serializer->status.buffer.size_used++;
+      buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
+    }
+
+    serializer->status.buffer.size_used += ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
+
+    ndpi_serialize_json_post(_serializer);
+  } else if(serializer->fmt == ndpi_serialization_format_csv) {
+    if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
+    ndpi_serialize_csv_pre(serializer);
+    buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
+    serializer->status.buffer.size_used += ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, format, value);
+  } else {
+    serializer->buffer.data[serializer->status.buffer.size_used++] = (ndpi_serialization_string << 4) | ndpi_serialization_double;
+
+    ndpi_serialize_single_string(serializer, key, klen);
+    ndpi_serialize_single_double(serializer, value);
+  }
+
+  serializer->status.flags |= NDPI_SERIALIZER_STATUS_NOT_EMPTY;
+  return(0);
+}
+
+/* ********************************** */
+
 int ndpi_serialize_string_float(ndpi_serializer *_serializer,
 				const char *key,
 				float value,
@@ -1642,6 +1715,16 @@ int ndpi_serialize_string_float(ndpi_serializer *_serializer,
 
 /* ********************************** */
 
+int ndpi_serialize_string_double(ndpi_serializer *_serializer,
+                const char *key,
+                double value,
+                const char *format /* e.f. "%.2f" */)
+{
+  return(ndpi_serialize_binary_double(_serializer, key, strlen(key), value, format));
+}
+
+/* ********************************** */
+
 /* Key is a <string, len> pair, value is a raw value */
 static int ndpi_serialize_binary_raw(ndpi_serializer *_serializer,
 					const char *key,
@@ -1684,7 +1767,6 @@ static int ndpi_serialize_binary_raw(ndpi_serializer *_serializer,
       serializer->status.buffer.size_used += ndpi_json_string_escape(value, vlen,
         (char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff);
     else {
-      //serializer->status.buffer.size_used += ndpi_snprintf((char *) &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, value, vlen);
       memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], value, vlen);
       serializer->status.buffer.size_used += vlen;
     }
@@ -1694,9 +1776,6 @@ static int ndpi_serialize_binary_raw(ndpi_serializer *_serializer,
     if (ndpi_serializer_header_string(serializer, key, klen) < 0) return(-1);
     ndpi_serialize_csv_pre(serializer);
     buff_diff = serializer->buffer.size - serializer->status.buffer.size_used;
-
-    //serializer->status.buffer.size_used += ndpi_snprintf((char *)
-    //  &serializer->buffer.data[serializer->status.buffer.size_used], buff_diff, "%s", value);
     memcpy(&serializer->buffer.data[serializer->status.buffer.size_used], value, vlen);
     serializer->status.buffer.size_used += vlen;
 
@@ -2210,6 +2289,9 @@ static inline int ndpi_deserialize_get_single_size(ndpi_private_deserializer *de
   case ndpi_serialization_float:
     size = sizeof(float);
     break;
+  case ndpi_serialization_double:
+    size = sizeof(double);
+    break;
   case ndpi_serialization_string:
   case ndpi_serialization_start_of_block:
   case ndpi_serialization_start_of_list:
@@ -2528,6 +2610,37 @@ int ndpi_deserialize_value_float(ndpi_deserializer *_deserializer,
 
 /* ********************************** */
 
+int ndpi_deserialize_value_double(ndpi_deserializer *_deserializer,
+                 double *value) {
+  ndpi_private_deserializer *deserializer = (ndpi_private_deserializer*)_deserializer;
+  ndpi_serialization_type kt, et;
+  u_int32_t buff_diff = deserializer->buffer.size - deserializer->status.buffer.size_used;
+  u_int16_t expected;
+  int size;
+
+  expected = sizeof(u_int8_t) /* type */;
+  if(buff_diff < expected) return(-2);
+
+  kt = ndpi_deserialize_get_key_subtype(deserializer);
+  size = ndpi_deserialize_get_single_size(deserializer, kt, deserializer->status.buffer.size_used + expected);
+  if(size < 0) return(-2);
+
+  expected += size;
+
+  et = ndpi_deserialize_get_value_subtype(deserializer);
+  size = ndpi_deserialize_get_single_size(deserializer, et, deserializer->status.buffer.size_used + expected);
+  if(size < 0) return(-2);
+
+  if(et != ndpi_serialization_double)
+    return(-1);
+
+  ndpi_deserialize_single_double(deserializer, deserializer->status.buffer.size_used + expected, value);
+
+  return(0);
+}
+
+/* ********************************** */
+
 /* Return the string value for the current element */
 int ndpi_deserialize_value_string(ndpi_deserializer *_deserializer,
 				  ndpi_string *value) {
-- 
cgit v1.2.3