]> git.ipfire.org Git - thirdparty/lldpd.git/commitdiff
lldpcli: Add support for JSON-C
authorMichel Stam <m.stam@fugro.nl>
Fri, 18 Jul 2014 15:00:32 +0000 (17:00 +0200)
committerMichel Stam <m.stam@fugro.nl>
Mon, 21 Jul 2014 15:11:10 +0000 (17:11 +0200)
OpenWRT is shipped with the JSON-C library, which is used for
several other packages. Having a separate JSON library (Jansson)
doing the exact same thing is wasting flash space.

configure.ac
m4/jansson.m4
m4/json-c.m4 [new file with mode: 0644]
src/client/Makefile.am
src/client/jansson_writer.c [moved from src/client/json_writer.c with 93% similarity]
src/client/jsonc_writer.c [new file with mode: 0644]
src/client/lldpcli.c
src/client/writer.h

index 059fdbe51be76c1d709ce0bde8f67603f4f17202..b29a5033a3e2f2e42fdcf59b96149857d5cf2b99 100644 (file)
@@ -191,10 +191,12 @@ fi
 AC_ARG_WITH([json],
   AS_HELP_STRING(
     [--with-json],
-    [Enable JSON output via Jansson @<:@default=no@:>@]
+    [Enable JSON output via janson,json-c,no @<:@default=no@:>@]
   ))
-if test x"$with_json" = x"yes"; then
+if test x"$with_json" = x"jansson"; then
    lldp_CHECK_JANSSON
+elif test x"$with_json" = x"json-c"; then
+   lldp_CHECK_JSONC
 fi
 
 # Seccomp
@@ -256,7 +258,9 @@ lldp_ARG_ENABLE([oldies], [compatibility with Linux kernel older than 2.6.18], [
 AM_CONDITIONAL([HAVE_CHECK], [test x"$have_check" = x"yes"])
 AM_CONDITIONAL([USE_SNMP], [test x"$with_snmp" = x"yes"])
 AM_CONDITIONAL([USE_XML], [test x"$with_xml" = x"yes"])
-AM_CONDITIONAL([USE_JSON], [test x"$with_json" = x"yes"])
+AM_CONDITIONAL([USE_JSON], [test x"$with_json" = x"json-c" || test -x"$with_json" = x"jansson"])
+AM_CONDITIONAL([USE_JANSSON], [test x"$with_json" = x"jansson"])
+AM_CONDITIONAL([USE_JSONC], [test x"$with_json" = x"json-c"])
 AM_CONDITIONAL([USE_SECCOMP], [test x"$with_seccomp" = x"yes"])
 AC_OUTPUT
 
index ca936d44add9674c327043de8974bb2c27c8fbb4..770de2ad9844c5b7c2b796393332694ddec0301e 100644 (file)
@@ -9,4 +9,5 @@ AC_DEFUN([lldp_CHECK_JANSSON], [
    AC_SUBST([JANSSON_LIBS])
    AC_SUBST([JANSSON_CFLAGS])
    AC_DEFINE_UNQUOTED([USE_JSON], 1, [Define to indicate to enable JSON support])
+   AC_DEFINE_UNQUOTED([USE_JANSSON], 1, [Define to indicate to enable JSON support through jansson])
 ])
diff --git a/m4/json-c.m4 b/m4/json-c.m4
new file mode 100644 (file)
index 0000000..cfab01e
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# lldp_CHECK_JSONC
+#
+
+AC_DEFUN([lldp_CHECK_JSONC], [
+   PKG_CHECK_MODULES([JSONC], [json-c >= 0], [],
+      [AC_MSG_ERROR([*** unable to find json-c])])
+
+   AC_SUBST([JSONC_LIBS])
+   AC_SUBST([JSONC_CFLAGS])
+   AC_DEFINE_UNQUOTED([USE_JSON], 1, [Define to indicate to enable JSON support])
+   AC_DEFINE_UNQUOTED([USE_JSONC], 1, [Define to indicate to enable JSON via json-c support])
+])
index 4370d85b7e2d827c82f6fc5571f961817a23a241..af747ea40ec6af9f8415b97ca786b5408808f993 100644 (file)
@@ -28,8 +28,14 @@ lldpcli_CFLAGS  += @XML2_CFLAGS@
 lldpcli_LDADD   += @XML2_LIBS@
 endif
 
-if USE_JSON
-lldpcli_SOURCES += json_writer.c
+if USE_JANSSON
+lldpcli_SOURCES += jansson_writer.c
 lldpcli_CFLAGS  += @JANSSON_CFLAGS@
 lldpcli_LDADD   += @JANSSON_LIBS@
 endif
+
+if USE_JSONC
+lldpcli_SOURCES += jsonc_writer.c
+lldpcli_CFLAGS  += @JSONC_CFLAGS@
+lldpcli_LDADD   += @JSONC_LIBS@
+endif
similarity index 93%
rename from src/client/json_writer.c
rename to src/client/jansson_writer.c
index bf914a633c61c2e3d797b91202f5c09dc9a0ee32..3ddfc8eede413e392f4e61ca94f9560eaf33cbad 100644 (file)
@@ -68,7 +68,7 @@ struct json_element {
 TAILQ_HEAD(json_writer_private, json_element);
 
 static void
-json_start(struct writer *w, const char *tag, const char *descr)
+jansson_start(struct writer *w, const char *tag, const char *descr)
 {
        struct json_writer_private *p = w->priv;
        struct json_element *current = TAILQ_LAST(p, json_writer_private);
@@ -91,7 +91,7 @@ json_start(struct writer *w, const char *tag, const char *descr)
 }
 
 static void
-json_attr(struct writer *w, const char *tag,
+jansson_attr(struct writer *w, const char *tag,
     const char *descr, const char *value)
 {
        struct json_writer_private *p = w->priv;
@@ -107,7 +107,7 @@ json_attr(struct writer *w, const char *tag,
 }
 
 static void
-json_data(struct writer *w, const char *data)
+jansson_data(struct writer *w, const char *data)
 {
        struct json_writer_private *p = w->priv;
        struct json_element *current = TAILQ_LAST(p, json_writer_private);
@@ -115,7 +115,7 @@ json_data(struct writer *w, const char *data)
 }
 
 static void
-json_end(struct writer *w)
+jansson_end(struct writer *w)
 {
        struct json_writer_private *p = w->priv;
        struct json_element *current = TAILQ_LAST(p, json_writer_private);
@@ -132,7 +132,7 @@ json_end(struct writer *w)
  * `name` key outside (inside a new object). This is a recursive function. We
  * think the depth will be limited. */
 static json_t*
-json_cleanup(json_t *el)
+jansson_cleanup(json_t *el)
 {
        json_t *new;
        if (el == NULL) return NULL;
@@ -187,7 +187,7 @@ json_cleanup(json_t *el)
 }
 
 static void
-json_finish(struct writer *w)
+jansson_finish(struct writer *w)
 {
        struct json_writer_private *p = w->priv;
        if (TAILQ_EMPTY(p)) {
@@ -212,7 +212,7 @@ json_finish(struct writer *w)
 }
 
 struct writer*
-json_init(FILE *fh)
+jansson_init(FILE *fh)
 {
        struct writer *result;
        struct json_writer_private *priv;
@@ -231,11 +231,11 @@ json_init(FILE *fh)
        if (result == NULL) fatal(NULL, NULL);
 
        result->priv   = priv;
-       result->start  = json_start;
-       result->attr   = json_attr;
-       result->data   = json_data;
-       result->end    = json_end;
-       result->finish = json_finish;
+       result->start  = jansson_start;
+       result->attr   = jansson_attr;
+       result->data   = jansson_data;
+       result->end    = jansson_end;
+       result->finish = jansson_finish;
 
        return result;
 }
diff --git a/src/client/jsonc_writer.c b/src/client/jsonc_writer.c
new file mode 100644 (file)
index 0000000..da780a3
--- /dev/null
@@ -0,0 +1,176 @@
+/* -*- mode: c; c-file-style: "openbsd" -*- */
+/*
+ * Copyright (c) 2014 Michel Stam <michel@reverze.net>,
+ *  Vincent Bernat <bernat@luffy.cx>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <json-c/json.h>
+#include <sys/queue.h>
+
+#include "writer.h"
+#include "../compat/compat.h"
+#include "../log.h"
+
+/*
+ * { lldp:
+ *    { interface: [
+
+ * { chassis:
+ *   { id: { type: "mac", value: "60:eb:69:ce:6e:a0" },
+ *     name: "guybrush",
+ *     descr: "Debian GNU/Linux 7.0 (wheezy)",
+ *     capability: [{type: "bridge", enabled: true}, {type: "router", enabled: false}] },
+*  <interface label="Interface" name="port2" via="LLDP" rid="1" age="0 day, 00:00:09">
+*   <chassis label="Chassis">
+*    <id label="ChassisID" type="mac">60:eb:69:ce:6e:a0</id>
+*    <name label="SysName">guybrush.luffy.cx</name>
+*    <descr label="SysDescr">Debian GNU/Linux 7.0 (wheezy) Linux 3.5-trunk-amd64 #1 SMP Debian 3.5.5-1~experimental.1 x86_64</descr>
+*    <mgmt-ip label="MgmtIP">192.168.116.3</mgmt-ip>
+*    <capability label="Capability" type="Bridge" enabled="off"/>
+*    <capability label="Capability" type="Router" enabled="off"/>
+*    <capability label="Capability" type="Wlan" enabled="on"/>
+*   </chassis>
+*   <port label="Port">
+*    <id label="PortID" type="mac">fe:86:6f:b6:1e:db</id>
+*    <descr label="PortDescr">port1</descr>
+*    <auto-negotiation label="PMD autoneg" supported="no" enabled="no">
+*     <current label="MAU oper type">10GigBaseR - R PCS/PMA, unknown PMD.</current>
+*    </auto-negotiation>
+*   </port>
+*  </interface>
+* </lldp>
+*/
+
+/* This list is used as a queue. The queue does not hold reference to the json_t
+ * element except the first one. */
+struct json_element {
+       TAILQ_ENTRY(json_element) next;
+       json_object *el;
+};
+TAILQ_HEAD(json_writer_private, json_element);
+
+static void
+jsonc_start(struct writer *w, const char *tag, const char *descr)
+{
+       struct json_writer_private *p = w->priv;
+       struct json_element *current = TAILQ_LAST(p, json_writer_private);
+       struct json_element *new;
+       json_object *exist = NULL;
+
+    if (!json_object_object_get_ex(current->el, tag, &exist)) {
+               exist = json_object_new_array();
+               json_object_object_add(current->el, tag, exist);
+    }
+
+       /* Queue the new element. */
+       new = malloc(sizeof(*new));
+       if (new == NULL) fatal(NULL, NULL);
+       new->el = json_object_new_object();
+       json_object_array_add(exist, new->el);
+       TAILQ_INSERT_TAIL(p, new, next);
+}
+
+static void
+jsonc_attr(struct writer *w, const char *tag,
+    const char *descr, const char *value)
+{
+       struct json_writer_private *p = w->priv;
+       struct json_element *current = TAILQ_LAST(p, json_writer_private);
+       json_object *jvalue;
+       if (!strcmp(value, "yes") || !strcmp(value, "on"))
+               jvalue = json_object_new_boolean(1);
+       else if (!strcmp(value, "no") || !strcmp(value, "off"))
+               jvalue = json_object_new_boolean(0);
+       else
+               jvalue = json_object_new_string(value);
+       json_object_object_add(current->el, tag, jvalue);
+}
+
+static void
+jsonc_data(struct writer *w, const char *data)
+{
+       struct json_writer_private *p = w->priv;
+       struct json_element *current = TAILQ_LAST(p, json_writer_private);
+       json_object_object_add(current->el, "value", json_object_new_string(data));
+}
+
+static void
+jsonc_end(struct writer *w)
+{
+       struct json_writer_private *p = w->priv;
+       struct json_element *current = TAILQ_LAST(p, json_writer_private);
+       if (current == NULL) {
+               log_warnx("lldpctl", "unbalanced tags");
+               return;
+       }
+       TAILQ_REMOVE(p, current, next);
+       free(current);
+}
+
+static void
+jsonc_finish(struct writer *w)
+{
+       struct json_writer_private *p = w->priv;
+       if (TAILQ_EMPTY(p)) {
+               log_warnx("lldpctl", "nothing to output");
+       } else if (TAILQ_NEXT(TAILQ_FIRST(p), next) != NULL) {
+               log_warnx("lldpctl", "unbalanced tags");
+               /* memory will leak... */
+       } else {
+               struct json_element *first = TAILQ_FIRST(p);
+               fprintf(stdout, "%s", json_object_to_json_string(first->el));
+               json_object_put(first->el);
+               TAILQ_REMOVE(p, first, next);
+               free(first);
+       }
+       free(p);
+       free(w);
+}
+
+struct writer*
+jsonc_init(FILE *fh)
+{
+       struct writer *result;
+       struct json_writer_private *priv;
+       struct json_element *root;
+
+       priv = malloc(sizeof(*priv));
+       root = malloc(sizeof(*root));
+       if (priv == NULL || root == NULL) fatal(NULL, NULL);
+       TAILQ_INIT(priv);
+       TAILQ_INSERT_TAIL(priv, root, next);
+       root->el = json_object_new_object();
+       if (root->el == NULL)
+               fatalx("cannot create JSON root object");
+
+       result = malloc(sizeof(*result));
+       if (result == NULL) fatal(NULL, NULL);
+
+       result->priv   = priv;
+       result->start  = jsonc_start;
+       result->attr   = jsonc_attr;
+       result->data   = jsonc_data;
+       result->end    = jsonc_end;
+       result->finish = jsonc_finish;
+
+       return result;
+}
index 964c6bbe712302bd2696da3aba0bd37015b0d726..689ef4263e7744569b5a3501bead54ef269e8e60 100644 (file)
@@ -271,8 +271,11 @@ cmd_exec(lldpctl_conn_t *conn, const char *fmt, int argc, const char **argv)
 #ifdef USE_XML
        else if (strcmp(fmt, "xml")      == 0) w = xml_init(stdout);
 #endif
-#ifdef USE_JSON
-       else if (strcmp(fmt, "json")     == 0) w = json_init(stdout);
+#ifdef USE_JANSSON
+       else if (strcmp(fmt, "json")     == 0) w = jansson_init(stdout);
+#endif
+#ifdef USE_JSONC
+       else if (strcmp(fmt, "json")     == 0) w = jsonc_init(stdout);
 #endif
        else w = txt_init(stdout);
 
index f4a4759234ca2d0a9aced3c59f2ec4e8b82873e6..ea2d4cfff9bde473976fd96ef03810f21401172d 100644 (file)
@@ -41,8 +41,11 @@ extern struct writer * kv_init( FILE * );
 #ifdef USE_XML
 extern struct writer * xml_init( FILE * );
 #endif
-#ifdef USE_JSON
-extern struct writer * json_init( FILE * );
+#ifdef USE_JANSSON
+extern struct writer * jansson_init( FILE * );
+#endif
+#ifdef USE_JSONC
+extern struct writer * jsonc_init( FILE * );
 #endif
 
 #endif /* _WRITER_H */