The current json output consists of individual lines which are json
conformant, but there is no conformancy between lines. Add a new
output format, which as a whole is json conformant.
Signed-off-by: Andrew Lunn <andrew(a)lunn.ch>
---
Since v1:
Add routing algorithm to output
Add batadv-vis version to output
Update man page
Since v2:
Change cjson to jasondoc, as suggested by Nicolás Echániz
README | 44 +++++++-
vis/man/batadv-vis.8 | 45 +++++++-
vis/vis.c | 302 ++++++++++++++++++++++++++++++++++++++++++---------
vis/vis.h | 3 +-
4 files changed, 337 insertions(+), 57 deletions(-)
diff --git a/README b/README
index 50c36ad..83cdaf8 100644
--- a/README
+++ b/README
@@ -152,7 +152,7 @@ digraph {
[...]
}
-For a json formatted output, use:
+For a json line formatted output, use:
$ batadv-vis -f json
{ "primary" : "fe:f0:00:00:04:01" }
@@ -169,6 +169,48 @@ For a json formatted output, use:
{ "primary" : "fe:f0:00:00:08:01" }
[...]
+and for output where the complete document is json, use:
+
+ $ batadv-vis -f jsondoc
+{
+ "source_version" : "2013.3.0-14-gcd34783",
+ "algorithm" : 4,
+ "vis" : [
+ { "primary" : "fe:f0:00:00:04:01",
+ "neighbors" : [
+ { "router" : "fe:f0:00:00:04:01",
+ "neighbor" : "fe:f0:00:00:05:01",
+ "metric" : "1.000" },
+ { "router" : "fe:f0:00:00:04:01",
+ "neighbor" : "fe:f0:00:00:03:01",
+ "metric" : "1.008" }
+ ],
+ "clients" : [
+ "00:00:43:05:00:04",
+ "fe:f1:00:00:04:01"
+ ]
+ },
+ { "primary" : "fe:f0:00:00:02:01",
+ "neighbors" : [
+ { "router" : "fe:f0:00:00:02:01",
+ "neighbor" : "fe:f0:00:00:03:01",
+ "metric" : "1.000" },
+ { "router" : "fe:f0:00:00:02:01",
+ "neighbor" : "fe:f0:00:00:01:01",
+ "metric" : "1.016" },
+ { "router" : "fe:f0:00:00:02:01",
+ "neighbor" : "fe:f0:00:00:08:01",
+ "metric" : "1.000" }
+ ],
+ "clients" : [
+ "fe:f1:00:00:02:01",
+ "00:00:43:05:00:02"
+ ]
+ },
+ { "primary" : "fe:f0:00:00:08:01",
+[...]
+
+
License
-------
diff --git a/vis/man/batadv-vis.8 b/vis/man/batadv-vis.8
index dfa2604..807c3b1 100644
--- a/vis/man/batadv-vis.8
+++ b/vis/man/batadv-vis.8
@@ -51,7 +51,7 @@ information from batman-adv every 10 seconds and set it in alfred via unix
socket. The alfred server must run too to get this information set.
.TP
\fB\-f\fP, \fB\-\-format\fP \fIformat\fP
-Specify the output format for client mode (either "json" or "dot")
+Specify the output format for client mode (either "json", "jsondoc" or "dot")
.
.SH EXAMPLES
Start an batadv\-vis server which is fetching the information for bat0:
@@ -106,6 +106,49 @@ To get a json vis output:
[...]
.fi
.br
+
+To get output where the complete document is json:
+.br
+\fB batadv-vis -f jsondoc\fP
+.nf
+ {
+ "source_version" : "2013.3.0-14-gcd34783",
+ "algorithm" : 4,
+ "vis" : [
+ { "primary" : "fe:f0:00:00:04:01",
+ "neighbors" : [
+ { "router" : "fe:f0:00:00:04:01",
+ "neighbor" : "fe:f0:00:00:05:01",
+ "metric" : "1.000" },
+ { "router" : "fe:f0:00:00:04:01",
+ "neighbor" : "fe:f0:00:00:03:01",
+ "metric" : "1.008" }
+ ],
+ "clients" : [
+ "00:00:43:05:00:04",
+ "fe:f1:00:00:04:01"
+ ]
+ },
+ { "primary" : "fe:f0:00:00:02:01",
+ "neighbors" : [
+ { "router" : "fe:f0:00:00:02:01",
+ "neighbor" : "fe:f0:00:00:03:01",
+ "metric" : "1.000" },
+ { "router" : "fe:f0:00:00:02:01",
+ "neighbor" : "fe:f0:00:00:01:01",
+ "metric" : "1.016" },
+ { "router" : "fe:f0:00:00:02:01",
+ "neighbor" : "fe:f0:00:00:08:01",
+ "metric" : "1.000" }
+ ],
+ "clients" : [
+ "fe:f1:00:00:02:01",
+ "00:00:43:05:00:02"
+ ]
+ },
+ { "primary" : "fe:f0:00:00:08:01",
+ [...]
+
.
.SH SEE ALSO
.BR alfred (8),
diff --git a/vis/vis.c b/vis/vis.c
index ad7f530..9c7d7a9 100644
--- a/vis/vis.c
+++ b/vis/vis.c
@@ -26,6 +26,7 @@
#include <linux/if.h>
#include <netinet/in.h>
#include <signal.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
@@ -511,18 +512,254 @@ static struct vis_v1 *vis_receive_answer_packet(int sock, uint16_t *len)
return (struct vis_v1 *) data->data;
}
+static void vis_dot_preamble(void)
+{
+ printf("digraph {\n");
+}
+
+static void vis_dot_interfaces(uint8_t iface_n, struct vis_iface *ifaces)
+{
+ int i;
+
+ printf("\tsubgraph \"cluster_%s\" {\n", mac_to_str(ifaces[0].mac));
+ for (i = 0; i < iface_n; i++)
+ printf("\t\t\"%s\"%s\n", mac_to_str(ifaces[i].mac),
+ i ? " [peripheries=2]":"");
+ printf("\t}\n");
+}
+
+static void vis_dot_entries(uint8_t entries_n, struct vis_entry *vis_entries,
+ uint8_t iface_n, struct vis_iface *ifaces)
+{
+ int i;
+
+ for (i = 0; i < entries_n; i++) {
+ if (vis_entries[i].ifindex == 255) {
+ printf("\t\"%s\" ", mac_to_str(ifaces[0].mac));
+ printf("-> \"%s\" [label=\"TT\"]\n",
+ mac_to_str(vis_entries[i].mac));
+ } else {
+ if (vis_entries[i].ifindex >= iface_n) {
+ fprintf(stderr, "ERROR: bad ifindex ...\n");
+ continue;
+ }
+ if (vis_entries[i].qual == 0) {
+ fprintf(stderr, "ERROR: quality = 0?\n");
+ continue;
+ }
+ printf("\t\"%s\" ",
+ mac_to_str(ifaces[vis_entries[i].ifindex].mac));
+ printf("-> \"%s\" [label=\"%3.3f\"]\n",
+ mac_to_str(vis_entries[i].mac),
+ 255.0 / ((float)vis_entries[i].qual));
+ }
+ }
+}
+
+static void vis_dot_postamble(void)
+{
+ printf("}\n");
+}
+
+static void vis_json_preamble(void)
+{
+}
+
+static void vis_json_interfaces(uint8_t iface_n, struct vis_iface *ifaces)
+{
+ int i;
+
+ printf("{ \"primary\" : \"%s\" }\n", mac_to_str(ifaces[0].mac));
+ for (i = 1; i < iface_n; i++) {
+ printf("{ \"secondary\" : \"%s\"", mac_to_str(ifaces[i].mac));
+ printf(", \"of\" : \"%s\" }\n", mac_to_str(ifaces[0].mac));
+ }
+}
+
+static void vis_json_entries(uint8_t entries_n, struct vis_entry *vis_entries,
+ uint8_t iface_n, struct vis_iface *ifaces)
+{
+ int i;
+
+ for (i = 0; i < entries_n; i++) {
+ if (vis_entries[i].ifindex == 255) {
+ printf("{ \"router\" : \"%s\"",
+ mac_to_str(ifaces[0].mac));
+ printf(", \"gateway\" : \"%s\", \"label\" : \"TT\" }\n",
+ mac_to_str(vis_entries[i].mac));
+ } else {
+ if (vis_entries[i].ifindex >= iface_n) {
+ fprintf(stderr, "ERROR: bad ifindex ...\n");
+ continue;
+ }
+ if (vis_entries[i].qual == 0) {
+ fprintf(stderr, "ERROR: quality = 0?\n");
+ continue;
+ }
+ printf("{ \"router\" : \"%s\"",
+ mac_to_str(ifaces[vis_entries[i].ifindex].mac));
+ printf(", \"neighbor\" : \"%s\", \"label\" : \"%3.3f\" }\n",
+ mac_to_str(vis_entries[i].mac),
+ 255.0 / ((float)vis_entries[i].qual));
+ }
+ }
+}
+
+static void vis_json_postamble(void)
+{
+}
+
+static void vis_jsondoc_preamble(void)
+{
+ printf("{\n");
+ printf(" \"source_version\" : \"%s\",\n", SOURCE_VERSION);
+ printf(" \"algorithm\" : 4,\n");
+ printf(" \"vis\" : [\n");
+}
+
+static void vis_jsondoc_interfaces(uint8_t iface_n, struct vis_iface *ifaces)
+{
+ int i;
+ static bool first_interface = true;
+
+ if (first_interface)
+ first_interface = false;
+ else
+ printf(",\n");
+
+ printf(" { \"primary\" : \"%s\",\n", mac_to_str(ifaces[0].mac));
+ if (iface_n > 1) {
+ printf(" \"secondary\" : [ ");
+ for (i = 1; i < iface_n; i++) {
+ printf("\"%s\"", mac_to_str(ifaces[i].mac));
+ if ( i < iface_n - 1)
+ printf(",");
+ }
+ printf("\n ],\n");
+ }
+}
+
+static void vis_jsondoc_entries(uint8_t entries_n,
+ struct vis_entry *vis_entries,
+ uint8_t iface_n, struct vis_iface *ifaces)
+{
+ bool first_neighbor = true;
+ bool first_tt = true;
+ int i;
+
+ printf(" \"neighbors\" : [\n");
+
+ for (i = 0; i < entries_n; i++) {
+ if (vis_entries[i].ifindex == 255) {
+ continue;
+ }
+
+ if (vis_entries[i].ifindex >= iface_n) {
+ fprintf(stderr, "ERROR: bad ifindex ...\n");
+ continue;
+ }
+ if (vis_entries[i].qual == 0) {
+ fprintf(stderr, "ERROR: quality = 0?\n");
+ continue;
+ }
+
+ if (first_neighbor)
+ first_neighbor = false;
+ else
+ printf(",\n");
+
+ printf(" { \"router\" : \"%s\",\n",
+ mac_to_str(ifaces[vis_entries[i].ifindex].mac));
+ printf(" \"neighbor\" : \"%s\",\n",
+ mac_to_str(vis_entries[i].mac));
+ printf(" \"metric\" : \"%3.3f\" }",
+ 255.0 / ((float)vis_entries[i].qual));
+ }
+
+ printf("\n ],\n");
+
+ printf(" \"clients\" : [\n");
+
+ for (i = 0; i < entries_n; i++) {
+ if (vis_entries[i].ifindex == 255) {
+ if (first_tt)
+ first_tt = false;
+ else
+ printf(",\n");
+
+ printf(" \"%s\"",
+ mac_to_str(vis_entries[i].mac));
+ }
+ }
+ printf("\n ]\n");
+ printf(" }");
+}
+
+static void vis_jsondoc_postamble(void)
+{
+ printf("\n ]\n");
+ printf("}\n");
+}
+
+struct vis_print_ops
+{
+ void (*preamble)(void);
+ void (*interfaces)(uint8_t iface_n, struct vis_iface *ifaces);
+ void (*entries)(uint8_t entries_n, struct vis_entry *vis_entries,
+ uint8_t iface_n, struct vis_iface *ifaces);
+ void (*postamble)(void);
+};
+
+static const struct vis_print_ops vis_dot_ops =
+{
+ vis_dot_preamble,
+ vis_dot_interfaces,
+ vis_dot_entries,
+ vis_dot_postamble
+};
+
+static const struct vis_print_ops vis_json_ops =
+{
+ vis_json_preamble,
+ vis_json_interfaces,
+ vis_json_entries,
+ vis_json_postamble
+};
+
+static const struct vis_print_ops vis_jsondoc_ops =
+{
+ vis_jsondoc_preamble,
+ vis_jsondoc_interfaces,
+ vis_jsondoc_entries,
+ vis_jsondoc_postamble
+};
+
static int vis_read_answer(struct globals *globals)
{
+ const struct vis_print_ops *ops;
struct vis_v1 *vis_data;
uint16_t len;
struct vis_iface *ifaces;
struct vis_entry *vis_entries;
- int i;
- if (globals->vis_format == FORMAT_DOT)
- printf("digraph {\n");
+ switch (globals->vis_format) {
+ case FORMAT_DOT:
+ ops = &vis_dot_ops;
+ break;
+ case FORMAT_JSON:
+ ops = &vis_json_ops;
+ break;
+ case FORMAT_JSONDOC:
+ ops = &vis_jsondoc_ops;
+ break;
+ default:
+ return -1;
+ }
+
+ ops->preamble();
- while ((vis_data = vis_receive_answer_packet(globals->unix_sock, &len)) != NULL) {
+ while ((vis_data =
+ vis_receive_answer_packet(globals->unix_sock, &len)) != NULL) {
if (len < sizeof(*vis_data))
return -1;
@@ -536,60 +773,15 @@ static int vis_read_answer(struct globals *globals)
ifaces = vis_data->ifaces;
vis_entries = (struct vis_entry *) &ifaces[vis_data->iface_n];
- if (globals->vis_format == FORMAT_DOT) {
- printf("\tsubgraph \"cluster_%s\" {\n", mac_to_str(ifaces[0].mac));
- for (i = 0; i < vis_data->iface_n; i++)
- printf("\t\t\"%s\"%s\n", mac_to_str(ifaces[i].mac),
- i ? " [peripheries=2]":"");
- printf("\t}\n");
- } else if (globals->vis_format == FORMAT_JSON) {
- printf("{ \"primary\" : \"%s\" }\n", mac_to_str(ifaces[0].mac));
- for (i = 1; i < vis_data->iface_n; i++) {
- printf("{ \"secondary\" : \"%s\"", mac_to_str(ifaces[i].mac));
- printf(", \"of\" : \"%s\" }\n", mac_to_str(ifaces[0].mac));
- }
- }
+ ops->interfaces(vis_data->iface_n, ifaces);
if (vis_data->entries_n == 0)
continue;
- for (i = 0; i < vis_data->entries_n; i++) {
- if (vis_entries[i].ifindex == 255) {
- if (globals->vis_format == FORMAT_DOT) {
- printf("\t\"%s\" ", mac_to_str(ifaces[0].mac));
- printf("-> \"%s\" [label=\"TT\"]\n", mac_to_str(vis_entries[i].mac));
- } else if (globals->vis_format == FORMAT_JSON) {
- printf("{ \"router\" : \"%s\"", mac_to_str(ifaces[0].mac));
- printf(", \"gateway\" : \"%s\", \"label\" : \"TT\" }\n", mac_to_str(vis_entries[i].mac));
- }
- } else {
- if (vis_entries[i].ifindex >= vis_data->iface_n) {
- fprintf(stderr, "ERROR: bad ifindex ...\n");
- continue;
- }
- if (vis_entries[i].qual == 0) {
- fprintf(stderr, "ERROR: quality = 0?\n");
- continue;
- }
- if (globals->vis_format == FORMAT_DOT) {
- printf("\t\"%s\" ",
- mac_to_str(ifaces[vis_entries[i].ifindex].mac));
- printf("-> \"%s\" [label=\"%3.3f\"]\n",
- mac_to_str(vis_entries[i].mac),
- 255.0 / ((float)vis_entries[i].qual));
- } else if (globals->vis_format == FORMAT_JSON) {
- printf("{ \"router\" : \"%s\"",
- mac_to_str(ifaces[vis_entries[i].ifindex].mac));
- printf(", \"neighbor\" : \"%s\", \"label\" : \"%3.3f\" }\n",
- mac_to_str(vis_entries[i].mac),
- 255.0 / ((float)vis_entries[i].qual));
-
- }
- }
- }
+ ops->entries(vis_data->entries_n, vis_entries,
+ vis_data->iface_n, ifaces);
}
- if (globals->vis_format == FORMAT_DOT)
- printf("}\n");
+ ops->postamble();
return 0;
}
@@ -611,7 +803,7 @@ static void vis_usage(void)
printf("Usage: batadv-vis [options]\n");
printf(" -i, --interface specify the batman-adv interface configured on the system (default: bat0)\n");
printf(" -s, --server start up in server mode, which regularly updates vis data from batman-adv\n");
- printf(" -f, --format <format> specify the output format for client mode (either \"json\" or \"dot\")\n");
+ printf(" -f, --format <format> specify the output format for client mode (either \"json\", \"jsondoc\" or \"dot\")\n");
printf(" -v, --version print the version\n");
printf(" -h, --help this help\n");
printf("\n");
@@ -649,6 +841,8 @@ static struct globals *vis_init(int argc, char *argv[])
case 'f':
if (strncmp(optarg, "dot", 3) == 0)
globals->vis_format = FORMAT_DOT;
+ else if (strncmp(optarg, "jsondoc", 7) == 0)
+ globals->vis_format = FORMAT_JSONDOC;
else if (strncmp(optarg, "json", 4) == 0)
globals->vis_format = FORMAT_JSON;
else {
diff --git a/vis/vis.h b/vis/vis.h
index 6ba70c6..4ccbdad 100644
--- a/vis/vis.h
+++ b/vis/vis.h
@@ -49,7 +49,8 @@ enum opmode {
enum vis_format {
FORMAT_DOT,
- FORMAT_JSON
+ FORMAT_JSON,
+ FORMAT_JSONDOC,
};
struct vis_iface {
--
1.8.4.rc3