From 8be372a590151b6d4f4dc7f37571e8acf5bf9944 Mon Sep 17 00:00:00 2001
From: Nils Schneider <nils@nilsschneider.net>
Date: Wed, 2 Sep 2015 16:22:12 +0200
Subject: [PATCH] gluon-status-page-api: rewrite stations in C

---
 package/gluon-status-page-api/Makefile        |  1 +
 .../status-page/www/cgi-bin/dyn/stations      | 52 -----------
 package/gluon-status-page-api/src/Makefile    |  7 +-
 package/gluon-status-page-api/src/stations.c  | 88 +++++++++++++++++++
 4 files changed, 95 insertions(+), 53 deletions(-)
 delete mode 100755 package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
 create mode 100755 package/gluon-status-page-api/src/stations.c

diff --git a/package/gluon-status-page-api/Makefile b/package/gluon-status-page-api/Makefile
index 863bbc397..91a7095a7 100644
--- a/package/gluon-status-page-api/Makefile
+++ b/package/gluon-status-page-api/Makefile
@@ -23,6 +23,7 @@ endef
 define Package/gluon-status-page-api/install
 	$(INSTALL_DIR) $(1)/lib/gluon/status-page/www/cgi-bin/dyn
 	$(INSTALL_BIN) $(PKG_BUILD_DIR)/neighbours-batadv $(1)/lib/gluon/status-page/www/cgi-bin/dyn/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/stations $(1)/lib/gluon/status-page/www/cgi-bin/dyn/
 	$(CP) ./files/* $(1)/
 endef
 
diff --git a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations b/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
deleted file mode 100755
index 637de6499..000000000
--- a/package/gluon-status-page-api/files/lib/gluon/status-page/www/cgi-bin/dyn/stations
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/lua
-
-util = require 'luci.util'
-json = require 'luci.jsonc'
-nixio = require 'nixio'
-iwinfo = require 'iwinfo'
-
-function badrequest()
-  io.write("Status: 400 Bad Request\n\n")
-  os.exit(1)
-end
-
-function get_stations(iw, ifname)
-  local stations = {}
-
-  for k, v in pairs(iw.assoclist(ifname)) do
-    stations[k:lower()] = {signal = v.signal, noise = v.noise, inactive = v.inactive}
-  end
-
-  return stations
-end
-
-local ifname = os.getenv("QUERY_STRING")
-
-if ifname == nil then badrequest() end
-
-local list = util.exec('batctl if')
-local found = false
-for _, line in ipairs(util.split(list)) do
-  if ifname == line:match('^(.-):') then
-    found = true
-    break
-  end
-end
-
-if found == false then badrequest() end
-
-local wifitype = iwinfo.type(ifname)
-
-if wifitype == nil then badrequest() end
-
-local iw = iwinfo[wifitype]
-
-io.write("Access-Control-Allow-Origin: *\n")
-io.write("Content-type: text/event-stream\n\n")
-
-while true do
-  local stations = json.stringify(get_stations(iw, ifname))
-  io.write("data: " .. stations .. "\n\n")
-  io.flush()
-  nixio.nanosleep(0, 150e6)
-end
diff --git a/package/gluon-status-page-api/src/Makefile b/package/gluon-status-page-api/src/Makefile
index 499bb55b0..f0bee9757 100644
--- a/package/gluon-status-page-api/src/Makefile
+++ b/package/gluon-status-page-api/src/Makefile
@@ -1,7 +1,12 @@
+CFLAGS += -std=c99 -D_BSD_SOURCE
+
 CFLAGS += $(shell pkg-config --cflags json-c)
 LDFLAGS += $(shell pkg-config --libs json-c)
 
-all: neighbours-batadv
+all: neighbours-batadv stations
 
 neighbours-batadv: neighbours-batadv.c
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS)
+
+stations: stations.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) -liwinfo
diff --git a/package/gluon-status-page-api/src/stations.c b/package/gluon-status-page-api/src/stations.c
new file mode 100755
index 000000000..9cae36803
--- /dev/null
+++ b/package/gluon-status-page-api/src/stations.c
@@ -0,0 +1,88 @@
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <json-c/json.h>
+#include <iwinfo.h>
+#include <net/if.h>
+
+#define STR(x) #x
+#define XSTR(x) STR(x)
+
+#define BATIF_PREFIX "/sys/class/net/bat0/lower_"
+
+static struct json_object *get_stations(const struct iwinfo_ops *iw, const char *ifname) {
+  int len;
+  char buf[IWINFO_BUFSIZE];
+  struct json_object *stations = json_object_new_object();
+
+  if (iw->assoclist(ifname, buf, &len) == -1)
+    return stations;
+
+  // This is just: for entry in assoclist(ifname)
+  for (struct iwinfo_assoclist_entry *entry = (struct iwinfo_assoclist_entry *)buf;
+      (char*)(entry+1) <= buf + len; entry++) {
+    struct json_object *station = json_object_new_object();
+
+    json_object_object_add(station, "signal", json_object_new_int(entry->signal));
+    json_object_object_add(station, "noise", json_object_new_int(entry->noise));
+    json_object_object_add(station, "inactive", json_object_new_int(entry->inactive));
+
+    char macstr[18];
+
+    snprintf(macstr, sizeof(macstr), "%02x:%02x:%02x:%02x:%02x:%02x",
+        entry->mac[0], entry->mac[1], entry->mac[2],
+        entry->mac[3], entry->mac[4], entry->mac[5]);
+
+    json_object_object_add(stations, macstr, station);
+  }
+
+  return stations;
+}
+
+static void badrequest() {
+  printf("Status: 400 Bad Request\n\n");
+  exit(1);
+}
+
+bool interface_is_valid(const char *ifname) {
+  if (strlen(ifname) > IF_NAMESIZE)
+    return false;
+
+  if (strchr(ifname, '/') != NULL)
+    return false;
+
+  char *path = alloca(1 + strlen(BATIF_PREFIX) + strlen(ifname));
+  sprintf(path, "%s%s", BATIF_PREFIX, ifname);
+
+  return access(path, F_OK) == 0;
+}
+
+int main(void) {
+  char *ifname = getenv("QUERY_STRING");
+
+  if (ifname == NULL)
+    badrequest();
+
+  if (!interface_is_valid(ifname))
+    badrequest();
+
+  const struct iwinfo_ops *iw = iwinfo_backend(ifname);
+
+  if (iw == NULL)
+    badrequest();
+
+  printf("Access-Control-Allow-Origin: *\n");
+  printf("Content-type: text/event-stream\n\n");
+
+  while (true) {
+    struct json_object *obj;
+    obj = get_stations(iw, ifname);
+    printf("data: %s\n\n", json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN));
+    fflush(stdout);
+    json_object_put(obj);
+    usleep(150000);
+  }
+
+  return 0;
+}
-- 
GitLab