From f7eda9381febd1e1a4f6ab3d0643773878b8fe10 Mon Sep 17 00:00:00 2001 From: Jan-Philipp Litza Date: Fri, 6 May 2016 16:49:00 +0200 Subject: [PATCH] respondd modules: Use proper formatting of doubles Most doubles that are delivered via respondd have limited input precision, but are converted with up to 17 digits of precision. That can cause ugly blowups like 0.2800000000000001 in the output, which is avoided by specifying better format strings (like "%.2f" in most cases). --- .../gluon-mesh-batman-adv-core/src/respondd.c | 4 +- package/gluon-mesh-vpn-fastd/src/respondd.c | 4 +- package/gluon-node-info/src/respondd.c | 4 +- package/gluon-respondd/src/respondd.c | 17 ++- ...or-custom-format-strings-for-doubles.patch | 108 ++++++++++++++++++ 5 files changed, 130 insertions(+), 7 deletions(-) create mode 100644 patches/openwrt/0080-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch diff --git a/package/gluon-mesh-batman-adv-core/src/respondd.c b/package/gluon-mesh-batman-adv-core/src/respondd.c index f0085457..7c2ac6c7 100644 --- a/package/gluon-mesh-batman-adv-core/src/respondd.c +++ b/package/gluon-mesh-batman-adv-core/src/respondd.c @@ -501,7 +501,9 @@ static struct json_object * get_batadv(void) { struct json_object *obj = json_object_new_object(); json_object_object_add(obj, "tq", json_object_new_int(tq)); - json_object_object_add(obj, "lastseen", json_object_new_double(lastseen)); + struct json_object *jso = json_object_new_double(lastseen); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.3f", NULL); + json_object_object_add(obj, "lastseen", jso); json_object_object_add(interface, mac1, obj); } diff --git a/package/gluon-mesh-vpn-fastd/src/respondd.c b/package/gluon-mesh-vpn-fastd/src/respondd.c index 3045c77a..7354783a 100644 --- a/package/gluon-mesh-vpn-fastd/src/respondd.c +++ b/package/gluon-mesh-vpn-fastd/src/respondd.c @@ -192,7 +192,9 @@ static bool get_peer_connection(struct json_object **ret, struct json_object *co int64_t established_time = json_object_get_int64(established); *ret = json_object_new_object(); - json_object_object_add(*ret, "established", json_object_new_double(established_time/1000.0)); + struct json_object *jso = json_object_new_double(established_time/1000.0); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.3f", NULL); + json_object_object_add(*ret, "established", jso); } else { *ret = NULL; diff --git a/package/gluon-node-info/src/respondd.c b/package/gluon-node-info/src/respondd.c index dfbfd3f8..d74c69e6 100644 --- a/package/gluon-node-info/src/respondd.c +++ b/package/gluon-node-info/src/respondd.c @@ -64,7 +64,9 @@ static struct json_object * get_number(struct uci_context *ctx, struct uci_secti if (*end) return NULL; - return json_object_new_double(d); + struct json_object *jso = json_object_new_double(d); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.8f", NULL); + return jso; } static struct json_object * get_location(struct uci_context *ctx, struct uci_package *p) { diff --git a/package/gluon-respondd/src/respondd.c b/package/gluon-respondd/src/respondd.c index 85006d6f..be3c9a7a 100644 --- a/package/gluon-respondd/src/respondd.c +++ b/package/gluon-respondd/src/respondd.c @@ -107,13 +107,18 @@ static struct json_object * respondd_provider_nodeinfo(void) { static void add_uptime(struct json_object *obj) { FILE *f = fopen("/proc/uptime", "r"); + struct json_object* jso; if (!f) return; double uptime, idletime; if (fscanf(f, "%lf %lf", &uptime, &idletime) == 2) { - json_object_object_add(obj, "uptime", json_object_new_double(uptime)); - json_object_object_add(obj, "idletime", json_object_new_double(idletime)); + jso = json_object_new_double(uptime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "uptime", jso); + jso = json_object_new_double(idletime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "idletime", jso); } fclose(f); @@ -127,7 +132,9 @@ static void add_loadavg(struct json_object *obj) { double loadavg; unsigned proc_running, proc_total; if (fscanf(f, "%lf %*f %*f %u/%u", &loadavg, &proc_running, &proc_total) == 3) { - json_object_object_add(obj, "loadavg", json_object_new_double(loadavg)); + struct json_object *jso = json_object_new_double(loadavg); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "loadavg", jso); struct json_object *processes = json_object_new_object(); json_object_object_add(processes, "running", json_object_new_int(proc_running)); @@ -176,7 +183,9 @@ static struct json_object * get_rootfs_usage(void) { if (statfs("/", &s)) return NULL; - return json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); + struct json_object *jso = json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.4f", NULL); + return jso; } static struct json_object * respondd_provider_statistics(void) { diff --git a/patches/openwrt/0080-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch b/patches/openwrt/0080-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch new file mode 100644 index 00000000..690d3ebb --- /dev/null +++ b/patches/openwrt/0080-libjson-c-Add-support-for-custom-format-strings-for-doubles.patch @@ -0,0 +1,108 @@ +From: Jan-Philipp Litza +Date: Fri, 6 May 2016 16:44:29 +0200 +Subject: libjson-c: Add support for custom format strings for doubles + +diff --git a/package/libs/libjson-c/patches/002-custom-format-string.patch b/package/libs/libjson-c/patches/002-custom-format-string.patch +new file mode 100644 +index 0000000..2f454c5 +--- /dev/null ++++ b/package/libs/libjson-c/patches/002-custom-format-string.patch +@@ -0,0 +1,98 @@ ++From 21dc5dc92bd56f5f4dc2c90b9ea6bf1e1407714e Mon Sep 17 00:00:00 2001 ++From: Jan-Philipp Litza ++Date: Fri, 6 May 2016 16:12:44 +0200 ++Subject: [PATCH] Export json_object_double_to_json_string() and use custom ++ format string ++BCC: janphilipp@litza.de ++ ++--- ++ json_object.c | 12 ++++++------ ++ json_object.h | 28 ++++++++++++++++++++++++++++ ++ 2 files changed, 34 insertions(+), 6 deletions(-) ++ ++diff --git a/json_object.c b/json_object.c ++index 7d60884..46701e7 100644 ++--- a/json_object.c +++++ b/json_object.c ++@@ -55,7 +55,6 @@ static struct json_object* json_object_new(enum json_type o_type); ++ static json_object_to_json_string_fn json_object_object_to_json_string; ++ static json_object_to_json_string_fn json_object_boolean_to_json_string; ++ static json_object_to_json_string_fn json_object_int_to_json_string; ++-static json_object_to_json_string_fn json_object_double_to_json_string; ++ static json_object_to_json_string_fn json_object_string_to_json_string; ++ static json_object_to_json_string_fn json_object_array_to_json_string; ++ ++@@ -644,10 +643,10 @@ int64_t json_object_get_int64(const struct json_object *jso) ++ ++ /* json_object_double */ ++ ++-static int json_object_double_to_json_string(struct json_object* jso, ++- struct printbuf *pb, ++- int level, ++- int flags) +++int json_object_double_to_json_string(struct json_object* jso, +++ struct printbuf *pb, +++ int level, +++ int flags) ++ { ++ char buf[128], *p, *q; ++ int size; ++@@ -663,7 +662,8 @@ static int json_object_double_to_json_string(struct json_object* jso, ++ else ++ size = snprintf(buf, sizeof(buf), "-Infinity"); ++ else ++- size = snprintf(buf, sizeof(buf), "%.17g", jso->o.c_double); +++ size = snprintf(buf, sizeof(buf), +++ jso->_userdata ? (const char*) jso->_userdata : "%.17g", jso->o.c_double); ++ ++ p = strchr(buf, ','); ++ if (p) { ++diff --git a/json_object.h b/json_object.h ++index 2bce454..a89de44 100644 ++--- a/json_object.h +++++ b/json_object.h ++@@ -614,6 +614,9 @@ extern int64_t json_object_get_int64(const struct json_object *obj); ++ /* double type methods */ ++ ++ /** Create a new empty json_object of type json_type_double +++ * +++ * @see json_object_double_to_json_string() for how to set a custom format string. +++ * ++ * @param d the double ++ * @returns a json_object of type json_type_double ++ */ ++@@ -642,6 +645,31 @@ extern struct json_object* json_object_new_double(double d); ++ */ ++ extern struct json_object* json_object_new_double_s(double d, const char *ds); ++ +++ +++/** Serialize a json_object of type json_type_double to a string. +++ * +++ * This function isn't meant to be called directly. Instead, you can set a +++ * custom format string for the serialization of this double using the +++ * following call (where "%.17g" actually is the default): +++ * +++ * @code +++ * jso = json_object_new_double(d); +++ * json_object_set_serializer(jso, json_object_double_to_json_string, +++ * "%.17g", NULL); +++ * @endcode +++ * +++ * @see printf(3) man page for format strings +++ * +++ * @param jso The json_type_double object that is serialized. +++ * @param pb The destination buffer. +++ * @param level Ignored. +++ * @param flags Ignored. +++ */ +++extern int json_object_double_to_json_string(struct json_object* jso, +++ struct printbuf *pb, +++ int level, +++ int flags); +++ ++ /** Get the double floating point value of a json_object ++ * ++ * The type is coerced to a double if the passed object is not a double. ++-- ++2.7.4 ++