From 9004028cb47d360360c9fdcc2fea52822998a75f Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Tue, 2 Feb 2016 06:38:03 +0100 Subject: [PATCH] Convert gluon-announce Lua code to C modules, rename to gluon-respondd gluon-announced and gluon-announce are merged to gluon-respondd. --- modules | 2 +- package/gluon-alfred/Makefile | 2 +- package/gluon-announce/Makefile | 32 - .../files/lib/gluon/announce/neighbours.cache | 1 - .../lib/gluon/announce/neighbours.d/node_id | 1 - .../files/lib/gluon/announce/nodeinfo.cache | 1 - .../gluon/announce/nodeinfo.d/hardware/model | 1 - .../gluon/announce/nodeinfo.d/hardware/nproc | 14 - .../lib/gluon/announce/nodeinfo.d/hostname | 1 - .../lib/gluon/announce/nodeinfo.d/network/mac | 1 - .../lib/gluon/announce/nodeinfo.d/node_id | 1 - .../announce/nodeinfo.d/software/firmware | 4 - .../announce/nodeinfo.d/system/site_code | 1 - .../files/lib/gluon/announce/statistics.cache | 1 - .../lib/gluon/announce/statistics.d/idletime | 1 - .../lib/gluon/announce/statistics.d/loadavg | 1 - .../lib/gluon/announce/statistics.d/memory | 13 - .../lib/gluon/announce/statistics.d/node_id | 1 - .../lib/gluon/announce/statistics.d/processes | 3 - .../gluon/announce/statistics.d/rootfs_usage | 4 - .../lib/gluon/announce/statistics.d/uptime | 1 - .../files/usr/lib/lua/gluon/announce.lua | 68 -- package/gluon-announced/Makefile | 32 - .../files/usr/lib/lua/gluon/announced.lua | 71 -- package/gluon-autoupdater/Makefile | 13 +- .../announce/nodeinfo.d/software/autoupdater | 7 - package/gluon-autoupdater/src/Makefile | 6 + package/gluon-autoupdater/src/respondd.c | 79 +++ package/gluon-core/Makefile | 2 +- .../nodeinfo.d/software/batman-adv/compat | 1 - .../lib/gluon/mesh-batman-adv-core/compat | 1 + .../nodeinfo.d/software/batman-adv/compat | 1 - .../lib/gluon/mesh-batman-adv-core/compat | 1 + package/gluon-mesh-batman-adv-core/Makefile | 13 +- .../lib/gluon/announce/neighbours.d/batadv | 39 -- .../lib/gluon/announce/neighbours.d/wifi | 40 -- .../announce/nodeinfo.d/network/addresses | 15 - .../nodeinfo.d/network/mesh/bat0/interfaces | 56 -- .../nodeinfo.d/network/mesh_interfaces | 13 - .../nodeinfo.d/software/batman-adv/version | 1 - .../lib/gluon/announce/statistics.d/clients | 55 -- .../lib/gluon/announce/statistics.d/gateway | 12 - .../lib/gluon/announce/statistics.d/traffic | 14 - .../gluon-mesh-batman-adv-core/src/Makefile | 6 + .../gluon-mesh-batman-adv-core/src/respondd.c | 604 ++++++++++++++++++ package/gluon-mesh-vpn-fastd/Makefile | 17 +- .../gluon/announce/nodeinfo.d/software/fastd | 5 - .../lib/gluon/announce/statistics.d/mesh_vpn | 70 -- package/gluon-mesh-vpn-fastd/src/Makefile | 6 + package/gluon-mesh-vpn-fastd/src/respondd.c | 305 +++++++++ package/gluon-node-info/Makefile | 17 +- .../lib/gluon/announce/nodeinfo.d/location | 7 - .../files/lib/gluon/announce/nodeinfo.d/owner | 4 - .../lib/gluon/announce/nodeinfo.d/system/role | 4 - package/gluon-node-info/src/Makefile | 6 + package/gluon-node-info/src/respondd.c | 144 +++++ package/gluon-respondd/Makefile | 29 + .../etc/hotplug.d/iface/10-gluon-respondd} | 9 +- .../files/lib/gluon/respondd/neighbours.cache | 1 + .../files/lib/gluon/respondd/nodeinfo.cache | 1 + .../files/lib/gluon/respondd/statistics.cache | 1 + .../lib/gluon/upgrade/400-respondd-firewall} | 8 +- package/gluon-respondd/src/Makefile | 6 + package/gluon-respondd/src/respondd.c | 209 ++++++ package/gluon-status-page-api/Makefile | 7 +- .../announce/nodeinfo.d/software/status-page | 1 - package/gluon-status-page-api/src/Makefile | 13 +- package/gluon-status-page-api/src/respondd.c | 47 ++ 68 files changed, 1502 insertions(+), 652 deletions(-) delete mode 100644 package/gluon-announce/Makefile delete mode 100644 package/gluon-announce/files/lib/gluon/announce/neighbours.cache delete mode 100644 package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.cache delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware delete mode 100644 package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.cache delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/memory delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/processes delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage delete mode 100644 package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime delete mode 100644 package/gluon-announce/files/usr/lib/lua/gluon/announce.lua delete mode 100644 package/gluon-announced/Makefile delete mode 100644 package/gluon-announced/files/usr/lib/lua/gluon/announced.lua delete mode 100644 package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater create mode 100644 package/gluon-autoupdater/src/Makefile create mode 100644 package/gluon-autoupdater/src/respondd.c delete mode 100644 package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat create mode 100644 package/gluon-mesh-batman-adv-14/files/lib/gluon/mesh-batman-adv-core/compat delete mode 100644 package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat create mode 100644 package/gluon-mesh-batman-adv-15/files/lib/gluon/mesh-batman-adv-core/compat delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway delete mode 100644 package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic create mode 100644 package/gluon-mesh-batman-adv-core/src/Makefile create mode 100644 package/gluon-mesh-batman-adv-core/src/respondd.c delete mode 100644 package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd delete mode 100644 package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn create mode 100644 package/gluon-mesh-vpn-fastd/src/Makefile create mode 100644 package/gluon-mesh-vpn-fastd/src/respondd.c delete mode 100644 package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location delete mode 100644 package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner delete mode 100644 package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role create mode 100644 package/gluon-node-info/src/Makefile create mode 100644 package/gluon-node-info/src/respondd.c create mode 100644 package/gluon-respondd/Makefile rename package/{gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced => gluon-respondd/files/etc/hotplug.d/iface/10-gluon-respondd} (79%) create mode 100644 package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache create mode 100644 package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache create mode 100644 package/gluon-respondd/files/lib/gluon/respondd/statistics.cache rename package/{gluon-announced/files/lib/gluon/upgrade/400-announced-firewall => gluon-respondd/files/lib/gluon/upgrade/400-respondd-firewall} (54%) create mode 100644 package/gluon-respondd/src/Makefile create mode 100644 package/gluon-respondd/src/respondd.c delete mode 100644 package/gluon-status-page-api/files/lib/gluon/announce/nodeinfo.d/software/status-page create mode 100644 package/gluon-status-page-api/src/respondd.c diff --git a/modules b/modules index 6c9a9f62..ad6d44b5 100644 --- a/modules +++ b/modules @@ -8,7 +8,7 @@ PACKAGES_OPENWRT_COMMIT=f8a70fc188673d0ae8739b0a3095f7f61335fc10 PACKAGES_OPENWRT_BRANCH=for-15.05 PACKAGES_GLUON_REPO=git://github.com/freifunk-gluon/packages.git -PACKAGES_GLUON_COMMIT=bdb56bba02168a7fdd7c8bbf380ae59a4febac7c +PACKAGES_GLUON_COMMIT=fd06c7d67da69713f0361dadab16393c26cb609b PACKAGES_ROUTING_REPO=git://github.com/openwrt-routing/packages.git PACKAGES_ROUTING_COMMIT=ae65d4fe027592652376f8dbd3ff2ef37f5a84bc diff --git a/package/gluon-alfred/Makefile b/package/gluon-alfred/Makefile index 54881c70..ca3ae327 100644 --- a/package/gluon-alfred/Makefile +++ b/package/gluon-alfred/Makefile @@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/package.mk define Package/gluon-alfred SECTION:=gluon CATEGORY:=Gluon - DEPENDS:=+gluon-core +gluon-announced +gluon-neighbour-info +micrond +alfred + DEPENDS:=+gluon-core +gluon-respondd +gluon-neighbour-info +micrond +alfred TITLE:=Configure alfred endef diff --git a/package/gluon-announce/Makefile b/package/gluon-announce/Makefile deleted file mode 100644 index d2742cf7..00000000 --- a/package/gluon-announce/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=gluon-announce -PKG_VERSION:=1 -PKG_RELEASE:=1 - -PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) - -include $(INCLUDE_DIR)/package.mk - -define Package/gluon-announce - SECTION:=gluon - CATEGORY:=Gluon - DEPENDS:=+gluon-core +luci-lib-jsonc +lua-ethtool-stats - TITLE:=Lua scripts announcing various information -endef - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile -endef - -define Package/gluon-announce/install - $(CP) ./files/* $(1)/ -endef - -$(eval $(call BuildPackage,gluon-announce)) diff --git a/package/gluon-announce/files/lib/gluon/announce/neighbours.cache b/package/gluon-announce/files/lib/gluon/announce/neighbours.cache deleted file mode 100644 index f599e28b..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/neighbours.cache +++ /dev/null @@ -1 +0,0 @@ -10 diff --git a/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id b/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id deleted file mode 100644 index 66303f4c..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/neighbours.d/node_id +++ /dev/null @@ -1 +0,0 @@ -return require('gluon.util').node_id() diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.cache b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.cache deleted file mode 100644 index 697cb3a2..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.cache +++ /dev/null @@ -1 +0,0 @@ -300 diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model deleted file mode 100644 index aee3cd81..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/model +++ /dev/null @@ -1 +0,0 @@ -return require('platform_info').get_model() diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc deleted file mode 100644 index fc94bd5b..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hardware/nproc +++ /dev/null @@ -1,14 +0,0 @@ -local n = 0 - -local cpus = util.readline(io.open('/sys/devices/system/cpu/online')) - -for entry in cpus:gmatch('([^,]+)') do - local x, y = entry:match('(%d+)-(%d+)') - if x then - n = n + tonumber(y) - tonumber(x) + 1 - else - n = n + 1 - end -end - -return n diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname deleted file mode 100644 index 7d4f0521..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/hostname +++ /dev/null @@ -1 +0,0 @@ -return uci:get_first('system', 'system', 'hostname') diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac deleted file mode 100644 index 049eea58..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/network/mac +++ /dev/null @@ -1 +0,0 @@ -return require('gluon.sysconfig').primary_mac diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id deleted file mode 100644 index 66303f4c..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/node_id +++ /dev/null @@ -1 +0,0 @@ -return require('gluon.util').node_id() diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware deleted file mode 100644 index 53f6fbaf..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/software/firmware +++ /dev/null @@ -1,4 +0,0 @@ -return { - base = 'gluon-' .. util.readline(io.open('/lib/gluon/gluon-version')), - release = util.readline(io.open('/lib/gluon/release')), -} diff --git a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code b/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code deleted file mode 100644 index fa7d9e80..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/nodeinfo.d/system/site_code +++ /dev/null @@ -1 +0,0 @@ -return require('gluon.site_config').site_code diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.cache b/package/gluon-announce/files/lib/gluon/announce/statistics.cache deleted file mode 100644 index 7ed6ff82..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.cache +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime b/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime deleted file mode 100644 index 61258820..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/idletime +++ /dev/null @@ -1 +0,0 @@ -return tonumber(util.readline(io.open('/proc/uptime')):match('^[^ ]+ ([^ ]+)')) diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg b/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg deleted file mode 100644 index 3548ac7a..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/loadavg +++ /dev/null @@ -1 +0,0 @@ -return tonumber(util.readline(io.open('/proc/loadavg')):match('^([^ ]+) ')) diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory b/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory deleted file mode 100644 index 2e880346..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/memory +++ /dev/null @@ -1,13 +0,0 @@ -local data = io.open('/proc/meminfo'):read('*a') - -local fields = {} -for k, v in data:gmatch('([^\n:]+):%s*(%d+) kB') do - fields[k] = tonumber(v) -end - -return { - total = fields.MemTotal, - free = fields.MemFree, - buffers = fields.Buffers, - cached = fields.Cached, -} diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id b/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id deleted file mode 100644 index 66303f4c..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/node_id +++ /dev/null @@ -1 +0,0 @@ -return require('gluon.util').node_id() diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes b/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes deleted file mode 100644 index 30f09790..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/processes +++ /dev/null @@ -1,3 +0,0 @@ -local running, total = util.readline(io.open('/proc/loadavg')):match('^[^ ]+ [^ ]+ [^ ]+ (%d+)/(%d+)') - -return { running = tonumber(running), total = tonumber(total) } diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage b/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage deleted file mode 100644 index 8426e9e1..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/rootfs_usage +++ /dev/null @@ -1,4 +0,0 @@ -local fs = require "nixio.fs" - -local st = fs.statvfs("/") -return 1 - st.bfree / st.blocks diff --git a/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime b/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime deleted file mode 100644 index 509d1470..00000000 --- a/package/gluon-announce/files/lib/gluon/announce/statistics.d/uptime +++ /dev/null @@ -1 +0,0 @@ -return tonumber(util.readline(io.open('/proc/uptime')):match('^([^ ]+) ')) diff --git a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua b/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua deleted file mode 100644 index 0e336ad5..00000000 --- a/package/gluon-announce/files/usr/lib/lua/gluon/announce.lua +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/lua - -module('gluon.announce', package.seeall) - -fs = require 'nixio.fs' -util = require 'gluon.util' -model_uci = require 'luci.model.uci' - - -local collect_dir - -local function collect_entry(entry) - if fs.stat(entry, 'type') == 'dir' then - return collect_dir(entry) - else - return loadfile(entry) - end -end - -function collect_dir(dir) - local fns = {} - - for entry in fs.dir(dir) do - if entry:sub(1, 1) ~= '.' then - collectgarbage() - local fn, err = collect_entry(dir .. '/' .. entry) - - if fn then - fns[entry] = fn - else - io.stderr:write(err, '\n') - end - end - end - - return function () - local ret = { [{}] = true } - - for k, v in pairs(fns) do - collectgarbage() - local ok, val = pcall(setfenv(v, _M)) - - if ok then - ret[k] = val - else - io.stderr:write(val, '\n') - end - end - - collectgarbage() - - return ret - end -end - -function collect(dir) - local f = collect_dir(dir) - - return function () - _M.uci = model_uci.cursor() - ret = f() - _M.uci = nil - - collectgarbage() - - return ret - end -end diff --git a/package/gluon-announced/Makefile b/package/gluon-announced/Makefile deleted file mode 100644 index d5b06dce..00000000 --- a/package/gluon-announced/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=gluon-announced -PKG_VERSION:=2 -PKG_RELEASE:=1 - -PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) - -include $(INCLUDE_DIR)/package.mk - -define Package/gluon-announced - SECTION:=gluon - CATEGORY:=Gluon - TITLE:=Provides node information to the network - DEPENDS:=+gluon-announce +respondd +lua-deflate -endef - -define Build/Prepare - mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile -endef - -define Package/gluon-announced/install - $(CP) ./files/* $(1)/ -endef - -$(eval $(call BuildPackage,gluon-announced)) diff --git a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua b/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua deleted file mode 100644 index 2dfe005c..00000000 --- a/package/gluon-announced/files/usr/lib/lua/gluon/announced.lua +++ /dev/null @@ -1,71 +0,0 @@ -local announce = require 'gluon.announce' -local deflate = require 'deflate' -local json = require 'luci.jsonc' -local util = require 'luci.util' -local nixio = require 'nixio' -local fs = require 'nixio.fs' - -local memoize = {} - -nixio.chdir('/lib/gluon/announce/') - -for dir in fs.glob('*.d') do - local name = dir:sub(1, -3) - memoize[name] = { - collect = announce.collect(dir), - -- tonumber will return 0 for invalid inputs - cache_time = tonumber(util.trim(fs.readfile(name .. '.cache') or '')) - } -end - -local function collect(type, timestamp) - local c = memoize[type] - if not c then - return nil - end - - if c.cache_timeout and timestamp < c.cache_timeout then - return c.cache - else - local ret = c.collect() - - if c.cache_time then - c.cache = ret - c.cache_timeout = timestamp + c.cache_time - end - - return ret - end -end - -module('gluon.announced', package.seeall) - -function handle_request(query, timestamp) - collectgarbage() - - local m = query:match('^GET ([a-z ]+)$') - local ret - if m then - local data = {} - - for q in m:gmatch('([a-z]+)') do - local ok, val = pcall(collect, q, timestamp) - if ok then - data[q] = val - end - end - - if next(data) then - ret = deflate.compress(json.stringify(data)) - end - elseif query:match('^[a-z]+$') then - local ok, data = pcall(collect, query, timestamp) - if ok then - ret = json.stringify(data) - end - end - - collectgarbage() - - return ret -end diff --git a/package/gluon-autoupdater/Makefile b/package/gluon-autoupdater/Makefile index f4885ee0..40120fa9 100644 --- a/package/gluon-autoupdater/Makefile +++ b/package/gluon-autoupdater/Makefile @@ -5,29 +5,28 @@ PKG_VERSION:=4 PKG_RELEASE:=$(GLUON_BRANCH) PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd include $(GLUONDIR)/include/package.mk define Package/gluon-autoupdater SECTION:=gluon CATEGORY:=Gluon - DEPENDS:=+gluon-core +micrond +autoupdater + DEPENDS:=+gluon-core +libgluonutil +micrond +autoupdater TITLE:=Automatically update firmware endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Package/gluon-autoupdater/install $(CP) ./files/* $(1)/ + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/autoupdater.so + if [ '$(GLUON_BRANCH)' ]; then \ $(INSTALL_DIR) $(1)/lib/gluon/autoupdater; \ echo '$(GLUON_BRANCH)' > $(1)/lib/gluon/autoupdater/default_branch; \ diff --git a/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater b/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater deleted file mode 100644 index 75a67578..00000000 --- a/package/gluon-autoupdater/files/lib/gluon/announce/nodeinfo.d/software/autoupdater +++ /dev/null @@ -1,7 +0,0 @@ -local autoupdater = uci:get_all('autoupdater', 'settings') -if autoupdater then - return { - branch = autoupdater['branch'], - enabled = uci:get_bool('autoupdater', 'settings', 'enabled'), - } -end diff --git a/package/gluon-autoupdater/src/Makefile b/package/gluon-autoupdater/src/Makefile new file mode 100644 index 00000000..3ddc8a58 --- /dev/null +++ b/package/gluon-autoupdater/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-autoupdater/src/respondd.c b/package/gluon-autoupdater/src/respondd.c new file mode 100644 index 00000000..66b7a928 --- /dev/null +++ b/package/gluon-autoupdater/src/respondd.c @@ -0,0 +1,79 @@ +/* + Copyright (c) 2016, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include + +#include + +#include + + +static struct json_object * get_autoupdater(void) { + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (uci_load(ctx, "autoupdater", &p)) + goto error; + + struct uci_section *s = uci_lookup_section(ctx, p, "settings"); + if (!s) + goto error; + + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "branch", gluonutil_wrap_string(uci_lookup_option_string(ctx, s, "branch"))); + + const char *enabled = uci_lookup_option_string(ctx, s, "enabled"); + json_object_object_add(ret, "enabled", json_object_new_boolean(enabled && !strcmp(enabled, "1"))); + + uci_free_context(ctx); + + return ret; + + error: + uci_free_context(ctx); + return NULL; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *software = json_object_new_object(); + json_object_object_add(software, "autoupdater", get_autoupdater()); + json_object_object_add(ret, "software", software); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {} +}; diff --git a/package/gluon-core/Makefile b/package/gluon-core/Makefile index ecd6fbe3..de54283b 100644 --- a/package/gluon-core/Makefile +++ b/package/gluon-core/Makefile @@ -12,7 +12,7 @@ define Package/gluon-core SECTION:=gluon CATEGORY:=Gluon TITLE:=Base files of Gluon - DEPENDS:=+gluon-site +lua-platform-info +luci-base +luci-lib-jsonc +odhcp6c +firewall + DEPENDS:=+gluon-site +libgluonutil +lua-platform-info +luci-base +luci-lib-jsonc +odhcp6c +firewall endef diff --git a/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat b/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat deleted file mode 100644 index 84137237..00000000 --- a/package/gluon-mesh-batman-adv-14/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat +++ /dev/null @@ -1 +0,0 @@ -return 14 diff --git a/package/gluon-mesh-batman-adv-14/files/lib/gluon/mesh-batman-adv-core/compat b/package/gluon-mesh-batman-adv-14/files/lib/gluon/mesh-batman-adv-core/compat new file mode 100644 index 00000000..8351c193 --- /dev/null +++ b/package/gluon-mesh-batman-adv-14/files/lib/gluon/mesh-batman-adv-core/compat @@ -0,0 +1 @@ +14 diff --git a/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat b/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat deleted file mode 100644 index d44224b3..00000000 --- a/package/gluon-mesh-batman-adv-15/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/compat +++ /dev/null @@ -1 +0,0 @@ -return 15 diff --git a/package/gluon-mesh-batman-adv-15/files/lib/gluon/mesh-batman-adv-core/compat b/package/gluon-mesh-batman-adv-15/files/lib/gluon/mesh-batman-adv-core/compat new file mode 100644 index 00000000..60d3b2f4 --- /dev/null +++ b/package/gluon-mesh-batman-adv-15/files/lib/gluon/mesh-batman-adv-core/compat @@ -0,0 +1 @@ +15 diff --git a/package/gluon-mesh-batman-adv-core/Makefile b/package/gluon-mesh-batman-adv-core/Makefile index cb7426f2..365ccbca 100644 --- a/package/gluon-mesh-batman-adv-core/Makefile +++ b/package/gluon-mesh-batman-adv-core/Makefile @@ -4,6 +4,7 @@ PKG_NAME:=gluon-mesh-batman-adv-core PKG_VERSION:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd include $(GLUONDIR)/include/package.mk @@ -11,21 +12,19 @@ define Package/gluon-mesh-batman-adv-core SECTION:=gluon CATEGORY:=Gluon TITLE:=Support for batman-adv meshing (core) - DEPENDS:=+gluon-core +gluon-client-bridge +firewall +libiwinfo-lua +batman-adv-visdata + DEPENDS:=+gluon-core +libgluonutil +gluon-client-bridge +firewall +libiwinfo +batman-adv-visdata endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Package/gluon-mesh-batman-adv-core/install $(CP) ./files/* $(1)/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/mesh-batman-adv-core.so endef define Package/gluon-mesh-batman-adv-core/postinst diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv deleted file mode 100644 index fa953037..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/batadv +++ /dev/null @@ -1,39 +0,0 @@ -local ifname_address_cache = {} - -function ifname2address(ifname) - local ifaddress - if ifname_address_cache[ifname] ~= nil then - ifaddress = ifname_address_cache[ifname] - else - ifaddress = util.readline(io.open("/sys/class/net/" .. ifname .. "/address")) - ifname_address_cache[ifname] = ifaddress - end - - return ifaddress -end - -function batadv() - local interfaces = {} - local list = io.lines("/tmp/batman-adv-visdata/bat0/originators") - for line in list do - local mac1, lastseen, tq, mac2, ifname = - line:match("^([0-9a-f:]+) +(%d+%.%d+)s +%( *(%d+)%) +([0-9a-f:]+) +%[ *(.-)%]") - - if mac1 ~= nil and mac1 == mac2 then - ifaddress = ifname2address(ifname) - if interfaces[ifaddress] == nil then - interfaces[ifaddress] = { neighbours = { [{}] = true } } - end - - interfaces[ifaddress].neighbours[mac1] = { tq = tonumber(tq) - , lastseen = tonumber(lastseen) - } - end - end - - if next(interfaces) then - return interfaces - end -end - -return batadv() diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi deleted file mode 100644 index 4f2b0ce2..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/neighbours.d/wifi +++ /dev/null @@ -1,40 +0,0 @@ -local batman_adv = require 'gluon.batman_adv' -local iwinfo = require 'iwinfo' - -function neighbours(iface) - local stations = {} - for k, v in pairs(iface.iw.assoclist(iface.ifname)) do - stations[k:lower()] = { signal = v.signal - , noise = v.noise - , inactive = v.inactive - } - end - - if next(stations) then - return stations - end -end - -function interfaces() - local interfaces = {} - for ifname in batman_adv.interfaces('bat0') do - pcall(function() - local address = util.readline(io.open('/sys/class/net/' .. ifname .. '/address')) - local wifitype = iwinfo.type(ifname) - if wifitype ~= nil then - interfaces[address] = { ifname = ifname, iw = iwinfo[wifitype] } - end - end) - end - - return interfaces -end - -local wifi = {} -for address, iface in pairs(interfaces()) do - wifi[address] = { [{}] = true, neighbours = neighbours(iface) } -end - -if next(wifi) then - return wifi -end diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses deleted file mode 100644 index aa513b1c..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/addresses +++ /dev/null @@ -1,15 +0,0 @@ -local ip = require 'luci.ip' -local bit = require 'nixio'.bit - -local addresses = {} - -for line in io.lines('/proc/net/if_inet6') do - local matches = { line:match('^' .. string.rep('(%x%x%x%x)', 8) .. string.rep(' %x%x', 3) .. ' (%x%x)%s+([^%s]+)$') } - -- exclude wrong interfaces and deprecated as well as tentative addresses - -- (see /include/uapi/linux/if_addr.h in linux source for flags) - if matches[10] == 'br-client' and bit.band(tonumber(matches[9], 16), 0x60) == 0 then - table.insert(addresses, ip.IPv6(string.format('%s:%s:%s:%s:%s:%s:%s:%s', unpack(matches))):string():lower()) - end -end - -return addresses diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces deleted file mode 100644 index 6f63af2f..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh/bat0/interfaces +++ /dev/null @@ -1,56 +0,0 @@ -local batman_adv = require 'gluon.batman_adv' - -local wireless = {} -local tunnel = {} -local other = {} - -local function get_address(t, ifname) - pcall( - function() - table.insert(t, util.readline(io.open('/sys/class/net/' .. ifname .. '/address'))) - end - ) -end - -local function file_exists(filename) - local f = io.open(filename) - if f == nil then - return false - else - f:close() - return true - end -end - -local function is_wireless(ifname) - return file_exists('/sys/class/net/' .. ifname .. '/wireless') -end - -local function is_tuntap(ifname) - return file_exists('/sys/class/net/' .. ifname .. '/tun_flags') -end - -local function nil_table(t) - if next(t) ~= nil then - return t - else - return nil - end -end - -for ifname in batman_adv.interfaces('bat0') do - if is_wireless(ifname) then - get_address(wireless, ifname) - elseif is_tuntap(ifname) then - get_address(tunnel, ifname) - else - get_address(other, ifname) - end -end - -return { - wireless = nil_table(wireless), - tunnel = nil_table(tunnel), - other = nil_table(other), - [{}] = true -} diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces deleted file mode 100644 index 0d66d603..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/network/mesh_interfaces +++ /dev/null @@ -1,13 +0,0 @@ -local batman_adv = require 'gluon.batman_adv' - -local interfaces = {} - -for ifname in batman_adv.interfaces('bat0') do - pcall( - function() - table.insert(interfaces, util.readline(io.open('/sys/class/net/' .. ifname .. '/address'))) - end - ) -end - -return interfaces diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version deleted file mode 100644 index e0f556cf..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/nodeinfo.d/software/batman-adv/version +++ /dev/null @@ -1 +0,0 @@ -return util.readline(io.open('/sys/module/batman_adv/version')) diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients deleted file mode 100644 index 8e4506e9..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/clients +++ /dev/null @@ -1,55 +0,0 @@ -local iwinfo = require 'iwinfo' - -local counts = { total = 0 - , wifi = 0 - , wifi24 = 0 - , wifi5 = 0 - } - -local list = io.lines("/sys/kernel/debug/batman_adv/bat0/transtable_local") -local clients = {} -for line in list do - local mac, _, flags, lastseen = line:match("^ %* ([0-9a-f:]+) *(.- )%[(.-)%] +(%d+%.%d+)") - if mac then - if not flags:match('P') then - counts.total = counts.total + 1 - clients[mac:lower()] = true - - if flags:match('W') then - counts.wifi = counts.wifi +1 - end - end - end -end - -function count_iface_stations(iface) - local wifitype = iwinfo.type(iface) - if wifitype == nil then - return - end - - local freq = iwinfo[wifitype].frequency(iface) - local key - if freq >= 2400 and freq < 2500 then - key = "wifi24" - elseif freq >= 5000 and freq < 6000 then - key = "wifi5" - else - return - end - - for k, v in pairs(iwinfo[wifitype].assoclist(iface)) do - if clients[k:lower()] then - counts[key] = counts[key] + 1 - end - end -end - -local ifaces = {} -uci:foreach("wireless", "wifi-iface", function(s) - if s.network == "client" and s.mode == "ap" then - count_iface_stations(s.ifname) - end -end) - -return counts diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway deleted file mode 100644 index b1909cf6..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/gateway +++ /dev/null @@ -1,12 +0,0 @@ -local gateway = '' - -for line in io.lines('/sys/kernel/debug/batman_adv/bat0/gateways') do - if line:sub(1, 3) == '=> ' then - gateway = line:sub(4, 20) - break - end -end - -if gateway ~= '' then - return gateway -end diff --git a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic b/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic deleted file mode 100644 index 01f6b4ab..00000000 --- a/package/gluon-mesh-batman-adv-core/files/lib/gluon/announce/statistics.d/traffic +++ /dev/null @@ -1,14 +0,0 @@ -local ethtool = require 'ethtool_stats' - -local fields = ethtool.interface_stats('bat0') - -local traffic = {} -for _, class in ipairs({'rx', 'tx', 'forward', 'mgmt_rx', 'mgmt_tx'}) do - traffic[class] = { - bytes = fields[class .. '_bytes'], - packets = fields[class], - } -end -traffic['tx']['dropped'] = fields['tx_dropped'] - -return traffic diff --git a/package/gluon-mesh-batman-adv-core/src/Makefile b/package/gluon-mesh-batman-adv-core/src/Makefile new file mode 100644 index 00000000..84d9d48e --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -liwinfo -luci diff --git a/package/gluon-mesh-batman-adv-core/src/respondd.c b/package/gluon-mesh-batman-adv-core/src/respondd.c new file mode 100644 index 00000000..cc1c59cc --- /dev/null +++ b/package/gluon-mesh-batman-adv-core/src/respondd.c @@ -0,0 +1,604 @@ +/* + Copyright (c) 2016, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + + + +#define _STRINGIFY(s) #s +#define STRINGIFY(s) _STRINGIFY(s) + + +static struct json_object * get_addresses(void) { + FILE *f = fopen("/proc/net/if_inet6", "r"); + if (!f) + return NULL; + + char *line = NULL; + size_t len = 0; + + struct json_object *ret = json_object_new_array(); + + while (getline(&line, &len, f) >= 0) { + /* IF_NAMESIZE would be enough, but adding 1 here is simpler than subtracting 1 in the format string */ + char ifname[IF_NAMESIZE+1]; + unsigned int flags; + struct in6_addr addr; + char buf[INET6_ADDRSTRLEN]; + + if (sscanf(line, + "%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8 + "%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8"%2"SCNx8 + " %*2x %*2x %*2x %2x %"STRINGIFY(IF_NAMESIZE)"s", + &addr.s6_addr[0], &addr.s6_addr[1], &addr.s6_addr[2], &addr.s6_addr[3], + &addr.s6_addr[4], &addr.s6_addr[5], &addr.s6_addr[6], &addr.s6_addr[7], + &addr.s6_addr[8], &addr.s6_addr[9], &addr.s6_addr[10], &addr.s6_addr[11], + &addr.s6_addr[12], &addr.s6_addr[13], &addr.s6_addr[14], &addr.s6_addr[15], + &flags, ifname) != 18) + continue; + + if (strcmp(ifname, "br-client")) + continue; + + if (flags & (IFA_F_TENTATIVE|IFA_F_DEPRECATED)) + continue; + + inet_ntop(AF_INET6, &addr, buf, sizeof(buf)); + + json_object_array_add(ret, json_object_new_string(buf)); + } + + fclose(f); + free(line); + + return ret; +} + +static void add_if_not_empty(struct json_object *obj, const char *key, struct json_object *val) { + if (json_object_array_length(val)) + json_object_object_add(obj, key, val); + else + json_object_put(val); +} + +static bool interface_file_exists(const char *ifname, const char *name) { + const char *format = "/sys/class/net/%s/%s"; + char path[strlen(format) + strlen(ifname) + strlen(name)]; + snprintf(path, sizeof(path), format, ifname, name); + + return !access(path, F_OK); +} + +static void mesh_add_subif(const char *ifname, struct json_object *wireless, + struct json_object *tunnel, struct json_object *other) { + struct json_object *address = gluonutil_wrap_and_free_string(gluonutil_get_interface_address(ifname)); + + if (interface_file_exists(ifname, "wireless")) + json_object_array_add(wireless, address); + else if (interface_file_exists(ifname, "tun_flags")) + json_object_array_add(tunnel, address); + else + json_object_array_add(other, address); + +} + +static struct json_object * get_mesh_subifs(const char *ifname) { + struct json_object *wireless = json_object_new_array(); + struct json_object *tunnel = json_object_new_array(); + struct json_object *other = json_object_new_array(); + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + strlen(ifname) - 1]; + snprintf(pattern, sizeof(pattern), format, ifname); + + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { + size_t i; + for (i = 0; i < lower.gl_pathc; i++) { + mesh_add_subif(lower.gl_pathv[i] + pattern_len - 1, + wireless, tunnel, other); + } + + globfree(&lower); + } + + struct json_object *ret = json_object_new_object(); + add_if_not_empty(ret, "wireless", wireless); + add_if_not_empty(ret, "tunnel", tunnel); + add_if_not_empty(ret, "other", other); + return ret; +} + +static struct json_object * get_mesh(void) { + struct json_object *ret = json_object_new_object(); + struct json_object *bat0_interfaces = json_object_new_object(); + json_object_object_add(bat0_interfaces, "interfaces", get_mesh_subifs("bat0")); + json_object_object_add(ret, "bat0", bat0_interfaces); + return ret; +} + +static struct json_object * get_batman_adv_compat(void) { + FILE *f = fopen("/lib/gluon/mesh-batman-adv-core/compat", "r"); + if (!f) + return NULL; + + struct json_object *ret = NULL; + + int compat; + if (fscanf(f, "%i", &compat) == 1) + ret = json_object_new_int(compat); + + fclose(f); + + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *network = json_object_new_object(); + json_object_object_add(network, "addresses", get_addresses()); + json_object_object_add(network, "mesh", get_mesh()); + json_object_object_add(ret, "network", network); + + struct json_object *software = json_object_new_object(); + struct json_object *software_batman_adv = json_object_new_object(); + json_object_object_add(software_batman_adv, "version", gluonutil_wrap_and_free_string(gluonutil_read_line("/sys/module/batman_adv/version"))); + json_object_object_add(software_batman_adv, "compat", get_batman_adv_compat()); + json_object_object_add(software, "batman-adv", software_batman_adv); + json_object_object_add(ret, "software", software); + + return ret; +} + + +static void add_gateway(struct json_object *obj) { + FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/gateways", "r"); + if (!f) + return; + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char addr[18]; + + if (sscanf(line, "=> %17[0-9a-fA-F:]", addr) != 1) + continue; + + json_object_object_add(obj, "gateway", json_object_new_string(addr)); + break; + } + + free(line); + fclose(f); +} + +static inline bool ethtool_ioctl(int fd, struct ifreq *ifr, void *data) { + ifr->ifr_data = data; + + return (ioctl(fd, SIOCETHTOOL, ifr) >= 0); +} + +static uint32_t ethtool_get_stats_length(int fd, struct ifreq *ifr) { + const size_t sset_info_len = sizeof(struct ethtool_sset_info) + sizeof(uint32_t); + struct ethtool_sset_info *sset_info = alloca(sset_info_len); + memset(sset_info, 0, sset_info_len); + + sset_info->cmd = ETHTOOL_GSSET_INFO; + sset_info->sset_mask = 1ull << ETH_SS_STATS; + + if (!ethtool_ioctl(fd, ifr, sset_info)) + return 0; + + return sset_info->sset_mask ? sset_info->data[0] : 0; +} + +static struct ethtool_gstrings * ethtool_get_stats_strings(int fd, struct ifreq *ifr) { + uint32_t n_stats = ethtool_get_stats_length(fd, ifr); + + if (!n_stats) + return NULL; + + struct ethtool_gstrings *strings = calloc(1, sizeof(*strings) + n_stats * ETH_GSTRING_LEN); + + strings->cmd = ETHTOOL_GSTRINGS; + strings->string_set = ETH_SS_STATS; + strings->len = n_stats; + + if (!ethtool_ioctl(fd, ifr, strings)) { + free(strings); + return NULL; + } + + return strings; +} + + +static struct json_object * get_traffic(void) { + struct ethtool_gstrings *strings = NULL; + struct ethtool_stats *stats = NULL; + + struct ifreq ifr = {}; + strncpy(ifr.ifr_name, "bat0", IF_NAMESIZE); + + struct json_object *ret = NULL; + + int fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd < 0) + return NULL; + + strings = ethtool_get_stats_strings(fd, &ifr); + if (!strings) + goto out; + + stats = calloc(1, sizeof(struct ethtool_stats) + strings->len * sizeof(uint64_t)); + stats->cmd = ETHTOOL_GSTATS; + stats->n_stats = strings->len; + + if (!ethtool_ioctl(fd, &ifr, stats)) + goto out; + + struct json_object *rx = json_object_new_object(); + struct json_object *tx = json_object_new_object(); + struct json_object *forward = json_object_new_object(); + struct json_object *mgmt_rx = json_object_new_object(); + struct json_object *mgmt_tx = json_object_new_object(); + + size_t i; + for (i = 0; i < strings->len; i++) { + if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx", ETH_GSTRING_LEN)) + json_object_object_add(rx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "rx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(rx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx", ETH_GSTRING_LEN)) + json_object_object_add(tx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_dropped", ETH_GSTRING_LEN)) + json_object_object_add(tx, "dropped", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "tx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(tx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward", ETH_GSTRING_LEN)) + json_object_object_add(forward, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "forward_bytes", ETH_GSTRING_LEN)) + json_object_object_add(forward, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_rx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_rx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_rx, "bytes", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_tx, "packets", json_object_new_int64(stats->data[i])); + else if (!strncmp((const char*)&strings->data[i * ETH_GSTRING_LEN], "mgmt_tx_bytes", ETH_GSTRING_LEN)) + json_object_object_add(mgmt_tx, "bytes", json_object_new_int64(stats->data[i])); + } + + ret = json_object_new_object(); + json_object_object_add(ret, "rx", rx); + json_object_object_add(ret, "tx", tx); + json_object_object_add(ret, "forward", forward); + json_object_object_add(ret, "mgmt_rx", mgmt_rx); + json_object_object_add(ret, "mgmt_tx", mgmt_tx); + + out: + free(stats); + free(strings); + close(fd); + return ret; +} + +static void count_iface_stations(size_t *wifi24, size_t *wifi5, const char *ifname) { + const struct iwinfo_ops *iw = iwinfo_backend(ifname); + if (!iw) + return; + + int freq; + if (iw->frequency(ifname, &freq) < 0) + return; + + size_t *wifi; + if (freq >= 2400 && freq < 2500) + wifi = wifi24; + else if (freq >= 5000 && freq < 6000) + wifi = wifi5; + else + return; + + int len; + char buf[IWINFO_BUFSIZE]; + if (iw->assoclist(ifname, buf, &len) < 0) + return; + + struct iwinfo_assoclist_entry *entry; + for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) + (*wifi)++; +} + +static void count_stations(size_t *wifi24, size_t *wifi5) { + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + + struct uci_package *p; + if (uci_load(ctx, "wireless", &p)) + goto end; + + + struct uci_element *e; + uci_foreach_element(&p->sections, e) { + struct uci_section *s = uci_to_section(e); + if (strcmp(s->type, "wifi-iface")) + continue; + + const char *network = uci_lookup_option_string(ctx, s, "network"); + if (!network || strcmp(network, "client")) + continue; + + const char *mode = uci_lookup_option_string(ctx, s, "mode"); + if (!mode || strcmp(mode, "ap")) + continue; + + const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); + if (!ifname) + continue; + + count_iface_stations(wifi24, wifi5, ifname); + } + + end: + uci_free_context(ctx); +} + +static struct json_object * get_clients(void) { + size_t total = 0, wifi = 0, wifi24 = 0, wifi5 = 0; + + FILE *f = fopen("/sys/kernel/debug/batman_adv/bat0/transtable_local", "r"); + if (!f) + return NULL; + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char addr[18], flags[16]; + + if (sscanf(line, " * %17[0-9a-fA-F:] [%15[^]]]", addr, flags) != 2) + continue; + + if (strchr(flags, 'P')) + continue; + + total++; + + if (strchr(flags, 'W')) + wifi++; + } + + free(line); + fclose(f); + + count_stations(&wifi24, &wifi5); + + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "total", json_object_new_int(total)); + json_object_object_add(ret, "wifi", json_object_new_int(wifi)); + json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); + json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); + return ret; +} + + +static struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "clients", get_clients()); + json_object_object_add(ret, "traffic", get_traffic()); + + add_gateway(ret); + + return ret; +} + + +static struct json_object * ifnames2addrs(struct json_object *interfaces) { + struct json_object *ret = json_object_new_object(); + + json_object_object_foreach(interfaces, ifname, interface) { + char *ifaddr = gluonutil_get_interface_address(ifname); + if (!ifaddr) + continue; + + struct json_object *obj = json_object_new_object(); + json_object_object_add(obj, "neighbours", json_object_get(interface)); + json_object_object_add(ret, ifaddr, obj); + + free(ifaddr); + } + + json_object_put(interfaces); + + return ret; +} + +static struct json_object * get_batadv(void) { + FILE *f = fopen("/tmp/batman-adv-visdata/bat0/originators", "r"); + if (!f) + return NULL; + + char *line = NULL; + size_t len = 0; + + struct json_object *interfaces = json_object_new_object(); + + while (getline(&line, &len, f) >= 0) { + char mac1[18], mac2[18]; + /* IF_NAMESIZE would be enough, but adding 1 here is simpler than subtracting 1 in the format string */ + char ifname[IF_NAMESIZE+1]; + double lastseen; + int tq; + + if (sscanf(line, + "%17[0-9a-fA-F:] %lfs ( %i ) %17[0-9a-fA-F:] [ %"STRINGIFY(IF_NAMESIZE)"[^]] ]", + mac1, &lastseen, &tq, mac2, ifname) != 5) + continue; + + if (strcmp(mac1, mac2)) + continue; + + struct json_object *interface; + if (!json_object_object_get_ex(interfaces, ifname, &interface)) { + interface = json_object_new_object(); + json_object_object_add(interfaces, ifname, interface); + } + + 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)); + json_object_object_add(interface, mac1, obj); + } + + fclose(f); + free(line); + + return ifnames2addrs(interfaces); +} + +static struct json_object * get_wifi_neighbours(const char *ifname) { + const struct iwinfo_ops *iw = iwinfo_backend(ifname); + if (!iw) + return NULL; + + int len; + char buf[IWINFO_BUFSIZE]; + if (iw->assoclist(ifname, buf, &len) < 0) + return NULL; + + struct json_object *neighbours = json_object_new_object(); + + struct iwinfo_assoclist_entry *entry; + for (entry = (struct iwinfo_assoclist_entry *)buf; (char*)(entry+1) <= buf + len; entry++) { + struct json_object *obj = json_object_new_object(); + + json_object_object_add(obj, "signal", json_object_new_int(entry->signal)); + json_object_object_add(obj, "noise", json_object_new_int(entry->noise)); + json_object_object_add(obj, "inactive", json_object_new_int(entry->inactive)); + + char mac[18]; + snprintf(mac, sizeof(mac), "%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(neighbours, mac, obj); + } + + struct json_object *ret = json_object_new_object(); + + if (json_object_object_length(neighbours)) + json_object_object_add(ret, "neighbours", neighbours); + else + json_object_put(neighbours); + + return ret; +} + +static struct json_object * get_wifi(void) { + const char *mesh = "bat0"; + + struct json_object *ret = json_object_new_object(); + + const char *format = "/sys/class/net/%s/lower_*"; + char pattern[strlen(format) + strlen(mesh)]; + snprintf(pattern, sizeof(pattern), format, mesh); + + size_t pattern_len = strlen(pattern); + + glob_t lower; + if (!glob(pattern, GLOB_NOSORT, NULL, &lower)) { + size_t i; + for (i = 0; i < lower.gl_pathc; i++) { + const char *ifname = lower.gl_pathv[i] + pattern_len - 1; + char *ifaddr = gluonutil_get_interface_address(ifname); + if (!ifaddr) + continue; + + struct json_object *neighbours = get_wifi_neighbours(ifname); + if (neighbours) + json_object_object_add(ret, ifaddr, neighbours); + + free(ifaddr); + } + + globfree(&lower); + } + + return ret; +} + +static struct json_object * respondd_provider_neighbours(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *batadv = get_batadv(); + if (batadv) + json_object_object_add(ret, "batadv", batadv); + + struct json_object *wifi = get_wifi(); + if (wifi) + json_object_object_add(ret, "wifi", wifi); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {"statistics", respondd_provider_statistics}, + {"neighbours", respondd_provider_neighbours}, + {} +}; diff --git a/package/gluon-mesh-vpn-fastd/Makefile b/package/gluon-mesh-vpn-fastd/Makefile index 4fdd608b..0875e485 100644 --- a/package/gluon-mesh-vpn-fastd/Makefile +++ b/package/gluon-mesh-vpn-fastd/Makefile @@ -4,6 +4,7 @@ PKG_NAME:=gluon-mesh-vpn-fastd PKG_VERSION:=3 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd include $(GLUONDIR)/include/package.mk @@ -11,25 +12,19 @@ define Package/gluon-mesh-vpn-fastd SECTION:=gluon CATEGORY:=Gluon TITLE:=Support for connecting batman-adv meshes via fastd - DEPENDS:=+gluon-core gluon-mesh-batman-adv +gluon-wan-dnsmasq +fastd +iptables-mod-extra +simple-tc -endef - -define Package/gluon-mesh-vpn-fastd/description - Gluon community wifi mesh firmware framework: fastd support + DEPENDS:=+gluon-core +libgluonutil gluon-mesh-batman-adv +gluon-wan-dnsmasq +fastd +iptables-mod-extra +simple-tc endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Package/gluon-mesh-vpn-fastd/install $(CP) ./files/* $(1)/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/mesh-vpn-fastd.so endef define Package/gluon-mesh-vpn-fastd/postinst diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd deleted file mode 100644 index 2c412eb8..00000000 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/nodeinfo.d/software/fastd +++ /dev/null @@ -1,5 +0,0 @@ -local ret = { - enabled = uci:get('fastd', 'mesh_vpn') and (uci:get('fastd', 'mesh_vpn', 'enabled') == nil or uci:get_bool('fastd', 'mesh_vpn', 'enabled')), - version = util.readline(io.popen('exec fastd -v')):match('^[^%s]+%s+(.+)'), -} -return ret diff --git a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn b/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn deleted file mode 100644 index f4e8f221..00000000 --- a/package/gluon-mesh-vpn-fastd/files/lib/gluon/announce/statistics.d/mesh_vpn +++ /dev/null @@ -1,70 +0,0 @@ -local json = require 'luci.jsonc' -local ltn12 = require 'luci.ltn12' -local nixio = require 'nixio' -local site = require 'gluon.site_config' - -local fastd_sock = nixio.socket('unix', 'stream') -local socket_path = uci:get('fastd', 'mesh_vpn', 'status_socket') - -if not fastd_sock:connect(socket_path) then - return nil -end - -local decoder = json.new() -ltn12.pump.all(ltn12.source.file(fastd_sock), decoder:sink()) - -local status = decoder:get() - - -local peer_groups - -local function peer_connection(config) - local peer = status.peers[config.key] - if peer then - if peer.connection then - return { - established = peer.connection.established/1000 - } - else - return function()end -- nil - end - end -end - -local function peer_group(config) - local ret = {} - - if config.peers then - local peers = {} - - for peername, peerconfig in pairs(config.peers) do - peers[peername] = peer_connection(peerconfig) - end - - if next(peers) then - ret.peers = peers - end - end - - ret.groups = peer_groups(config.groups) - - if next(ret) then - return ret - end -end - -function peer_groups(groups) - if groups then - local ret = {} - - for name, group in pairs(groups) do - ret[name] = peer_group(group) - end - - if next(ret) then - return ret - end - end -end - -return peer_group(site.fastd_mesh_vpn) diff --git a/package/gluon-mesh-vpn-fastd/src/Makefile b/package/gluon-mesh-vpn-fastd/src/Makefile new file mode 100644 index 00000000..3ddc8a58 --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-mesh-vpn-fastd/src/respondd.c b/package/gluon-mesh-vpn-fastd/src/respondd.c new file mode 100644 index 00000000..3045c77a --- /dev/null +++ b/package/gluon-mesh-vpn-fastd/src/respondd.c @@ -0,0 +1,305 @@ +/* + Copyright (c) 2016, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + + +static struct json_object * get_peer_groups(struct json_object *groups, struct json_object *peers); + +static struct json_object * get_fastd_version(void) { + FILE *f = popen("exec fastd -v", "r"); + if (!f) + return NULL; + + char *line = NULL; + size_t len = 0; + + ssize_t r = getline(&line, &len, f); + + pclose(f); + + if (r >= 0) { + len = strlen(line); /* The len given by getline is the buffer size, not the string length */ + + if (len && line[len-1] == '\n') + line[len-1] = 0; + } + else { + free(line); + line = NULL; + } + + const char *version = line; + if (strncmp(version, "fastd ", 6) == 0) + version += 6; + + struct json_object *ret = gluonutil_wrap_string(version); + free(line); + return ret; +} + +static struct json_object * get_fastd(void) { + bool enabled = false; + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (uci_load(ctx, "fastd", &p)) + goto disabled; + + struct uci_section *s = uci_lookup_section(ctx, p, "mesh_vpn"); + if (!s) + goto disabled; + + const char *enabled_str = uci_lookup_option_string(ctx, s, "enabled"); + if (!enabled_str || !strcmp(enabled_str, "1")) + enabled = true; + + disabled: + + uci_free_context(ctx); + + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "version", get_fastd_version()); + json_object_object_add(ret, "enabled", json_object_new_boolean(enabled)); + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *software = json_object_new_object(); + json_object_object_add(software, "fastd", get_fastd()); + json_object_object_add(ret, "software", software); + + return ret; +} + + +static const char * get_status_socket(struct uci_context *ctx, struct uci_section *s) { + return uci_lookup_option_string(ctx, s, "status_socket"); +} + +static struct json_object * read_status(struct uci_context *ctx, struct uci_section *s) { + const char *path = get_status_socket(ctx, s); + + size_t addrlen = strlen(path); + + /* Allocate enough space for arbitrary-length paths */ + char addrbuf[offsetof(struct sockaddr_un, sun_path) + addrlen + 1]; + memset(addrbuf, 0, sizeof(addrbuf)); + + struct sockaddr_un *addr = (struct sockaddr_un *)addrbuf; + addr->sun_family = AF_UNIX; + memcpy(addr->sun_path, path, addrlen+1); + + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + return NULL; + + if (connect(fd, (struct sockaddr*)addr, sizeof(addrbuf)) < 0) { + close(fd); + return NULL; + } + + struct json_object *ret = NULL; + struct json_tokener *tok = json_tokener_new(); + + do { + char buf[1024]; + size_t len = read(fd, buf, sizeof(buf)); + if (len <= 0) + break; + + ret = json_tokener_parse_ex(tok, buf, len); + } while (!ret && json_tokener_get_error(tok) == json_tokener_continue); + + json_tokener_free(tok); + close(fd); + return ret; +} + +static struct json_object * get_status(void) { + struct json_object *ret = NULL; + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (!uci_load(ctx, "fastd", &p)) { + struct uci_section *s = uci_lookup_section(ctx, p, "mesh_vpn"); + + if (s) + ret = read_status(ctx, s); + } + + uci_free_context(ctx); + + return ret; +} + +static bool get_peer_connection(struct json_object **ret, struct json_object *config, struct json_object *peers) { + struct json_object *key_object; + if (!json_object_object_get_ex(config, "key", &key_object)) + return false; + + const char *key = json_object_get_string(key_object); + if (!key) + return false; + + struct json_object *peer, *connection, *established; + if (!json_object_object_get_ex(peers, key, &peer) || + !json_object_object_get_ex(peer, "connection", &connection)) + return false; + + if (json_object_object_get_ex(connection, "established", &established)) { + 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)); + } + else { + *ret = NULL; + } + + return true; +} + +static struct json_object * get_peer_group(struct json_object *config, struct json_object *peers) { + struct json_object *ret = json_object_new_object(); + + struct json_object *config_peers; + if (json_object_object_get_ex(config, "peers", &config_peers) && + json_object_is_type(config_peers, json_type_object)) { + struct json_object *ret_peers = json_object_new_object(); + + json_object_object_foreach(config_peers, peername, peerconfig) { + struct json_object *obj; + if (get_peer_connection(&obj, peerconfig, peers)) + json_object_object_add(ret_peers, peername, obj); + } + + if (json_object_object_length(ret_peers)) + json_object_object_add(ret, "peers", ret_peers); + else + json_object_put(ret_peers); + } + + struct json_object *config_groups; + if (json_object_object_get_ex(config, "groups", &config_groups)) { + struct json_object *obj = get_peer_groups(config_groups, peers); + if (obj) + json_object_object_add(ret, "groups", obj); + } + + + if (!json_object_object_length(ret)) { + json_object_put(ret); + return NULL; + } + + return ret; +} + +static struct json_object * get_peer_groups(struct json_object *groups, struct json_object *peers) { + if (!json_object_is_type(groups, json_type_object)) + return NULL; + + struct json_object *ret = json_object_new_object(); + + json_object_object_foreach(groups, name, group) { + struct json_object *g = get_peer_group(group, peers); + if (g) + json_object_object_add(ret, name, g); + } + + if (!json_object_object_length(ret)) { + json_object_put(ret); + return NULL; + } + + return ret; +} + +static struct json_object * get_mesh_vpn(void) { + struct json_object *ret = NULL; + struct json_object *status = NULL; + struct json_object *site = NULL; + + status = get_status(); + if (!status) + goto end; + + struct json_object *peers; + if (!json_object_object_get_ex(status, "peers", &peers)) + goto end; + + site = gluonutil_load_site_config(); + if (!site) + goto end; + + struct json_object *fastd_mesh_vpn; + if (!json_object_object_get_ex(site, "fastd_mesh_vpn", &fastd_mesh_vpn)) + goto end; + + ret = get_peer_group(fastd_mesh_vpn, peers); + + end: + json_object_put(site); + json_object_put(status); + + return ret; +} + +static struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *mesh_vpn = get_mesh_vpn(); + if (mesh_vpn) + json_object_object_add(ret, "mesh_vpn", mesh_vpn); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {"statistics", respondd_provider_statistics}, + {} +}; diff --git a/package/gluon-node-info/Makefile b/package/gluon-node-info/Makefile index 0fe8a8dd..a5ac8ddc 100644 --- a/package/gluon-node-info/Makefile +++ b/package/gluon-node-info/Makefile @@ -5,6 +5,7 @@ PKG_VERSION:=1 PKG_RELEASE:=1 PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd include $(GLUONDIR)/include/package.mk @@ -12,25 +13,19 @@ define Package/gluon-node-info SECTION:=gluon CATEGORY:=Gluon TITLE:=Add /etc/config/gluon-node-info to uci - DEPENDS:=+gluon-core -endef - -define Package/gluon-node-info/description - This packages creates /etc/config/gluon-node-info. + DEPENDS:=+gluon-core +libgluonutil endef define Build/Prepare mkdir -p $(PKG_BUILD_DIR) -endef - -define Build/Configure -endef - -define Build/Compile + $(CP) ./src/* $(PKG_BUILD_DIR)/ endef define Package/gluon-node-info/install $(CP) ./files/* $(1)/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/node-info.so endef define Package/gluon-node-info/postinst diff --git a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location deleted file mode 100644 index 72bf8878..00000000 --- a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/location +++ /dev/null @@ -1,7 +0,0 @@ -if uci:get_first('gluon-node-info', 'location', 'share_location', false) then - return { - latitude = tonumber(uci:get_first('gluon-node-info', 'location', 'latitude')), - longitude = tonumber(uci:get_first('gluon-node-info', 'location', 'longitude')), - altitude = tonumber(uci:get_first('gluon-node-info', 'location', 'altitude')), - } -end diff --git a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner deleted file mode 100644 index 8a2a611d..00000000 --- a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/owner +++ /dev/null @@ -1,4 +0,0 @@ -local contact = uci:get_first('gluon-node-info', 'owner', 'contact', '') -if contact ~= '' then - return { contact = contact } -end diff --git a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role b/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role deleted file mode 100644 index 38de47d7..00000000 --- a/package/gluon-node-info/files/lib/gluon/announce/nodeinfo.d/system/role +++ /dev/null @@ -1,4 +0,0 @@ -local role = uci:get_first('gluon-node-info', 'system', 'role', '') -if role ~= '' then - return role -end diff --git a/package/gluon-node-info/src/Makefile b/package/gluon-node-info/src/Makefile new file mode 100644 index 00000000..3ddc8a58 --- /dev/null +++ b/package/gluon-node-info/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-node-info/src/respondd.c b/package/gluon-node-info/src/respondd.c new file mode 100644 index 00000000..dfbfd3f8 --- /dev/null +++ b/package/gluon-node-info/src/respondd.c @@ -0,0 +1,144 @@ +/* + Copyright (c) 2016, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include + +#include + +#include +#include + + +static struct uci_section * get_first_section(struct uci_package *p, const char *type) { + struct uci_element *e; + uci_foreach_element(&p->sections, e) { + struct uci_section *s = uci_to_section(e); + if (!strcmp(s->type, type)) + return s; + } + + return NULL; +} + +static const char * get_first_option(struct uci_context *ctx, struct uci_package *p, const char *type, const char *option) { + struct uci_section *s = get_first_section(p, type); + if (s) + return uci_lookup_option_string(ctx, s, option); + else + return NULL; +} + +static struct json_object * get_number(struct uci_context *ctx, struct uci_section *s, const char *name) { + const char *val = uci_lookup_option_string(ctx, s, name); + if (!val || !*val) + return NULL; + + char *end; + double d = strtod(val, &end); + if (*end) + return NULL; + + return json_object_new_double(d); +} + +static struct json_object * get_location(struct uci_context *ctx, struct uci_package *p) { + struct uci_section *s = get_first_section(p, "location"); + if (!s) + return NULL; + + const char *share = uci_lookup_option_string(ctx, s, "share_location"); + if (!share || strcmp(share, "1")) + return NULL; + + struct json_object *ret = json_object_new_object(); + + struct json_object *latitude = get_number(ctx, s, "latitude"); + if (latitude) + json_object_object_add(ret, "latitude", latitude); + + struct json_object *longitude = get_number(ctx, s, "longitude"); + if (longitude) + json_object_object_add(ret, "longitude", longitude); + + struct json_object *altitude = get_number(ctx, s, "altitude"); + if (altitude) + json_object_object_add(ret, "altitude", altitude); + + return ret; +} + +static struct json_object * get_owner(struct uci_context *ctx, struct uci_package *p) { + const char *contact = get_first_option(ctx, p, "owner", "contact"); + if (!contact || !*contact) + return NULL; + + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "contact", gluonutil_wrap_string(contact)); + return ret; +} + +static struct json_object * get_system(struct uci_context *ctx, struct uci_package *p) { + struct json_object *ret = json_object_new_object(); + + const char *role = get_first_option(ctx, p, "system", "role"); + if (role && *role) + json_object_object_add(ret, "role", gluonutil_wrap_string(role)); + + return ret; +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct uci_context *ctx = uci_alloc_context(); + ctx->flags &= ~UCI_FLAG_STRICT; + + struct uci_package *p; + if (!uci_load(ctx, "gluon-node-info", &p)) { + struct json_object *location = get_location(ctx, p); + if (location) + json_object_object_add(ret, "location", location); + + struct json_object *owner = get_owner(ctx, p); + if (owner) + json_object_object_add(ret, "owner", owner); + + json_object_object_add(ret, "system", get_system(ctx, p)); + } + + uci_free_context(ctx); + + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {} +}; diff --git a/package/gluon-respondd/Makefile b/package/gluon-respondd/Makefile new file mode 100644 index 00000000..df9f257e --- /dev/null +++ b/package/gluon-respondd/Makefile @@ -0,0 +1,29 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-respondd +PKG_VERSION:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-respondd + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Provides node information to the network + DEPENDS:=+gluon-core +libplatforminfo +libgluonutil +respondd +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +define Package/gluon-respondd/install + $(CP) ./files/* $(1)/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/respondd.so +endef + +$(eval $(call BuildPackage,gluon-respondd)) diff --git a/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced b/package/gluon-respondd/files/etc/hotplug.d/iface/10-gluon-respondd similarity index 79% rename from package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced rename to package/gluon-respondd/files/etc/hotplug.d/iface/10-gluon-respondd index a1e2c45f..c8594a1b 100644 --- a/package/gluon-announced/files/etc/hotplug.d/iface/10-gluon-announced +++ b/package/gluon-respondd/files/etc/hotplug.d/iface/10-gluon-respondd @@ -3,7 +3,7 @@ . /usr/share/libubox/jshn.sh . /lib/functions/service.sh -DEVLIST=/var/run/gluon-announced.devs +DEVLIST=/var/run/gluon-respondd.devs DAEMON=/usr/bin/respondd ifname_to_dev () { @@ -13,7 +13,7 @@ ifname_to_dev () { echo "$dev" } -restart_announced () { +restart_respondd () { SERVICE_USE_PID=1 SERVICE_WRITE_PID=1 SERVICE_DAEMONIZE=1 @@ -21,7 +21,7 @@ restart_announced () { DEVS=$(cat $DEVLIST | while read dev iface; do echo -n " -i $dev"; done) service_stop $DAEMON - service_start $DAEMON -g ff02::2:1001 -p 1001 -c 'return require("gluon.announced").handle_request' $DEVS + service_start $DAEMON -g ff02::2:1001 -p 1001 -d /lib/gluon/respondd $DEVS } case "$ACTION" in @@ -38,8 +38,7 @@ case "$ACTION" in echo "$DEVS" | sort -u > $DEVLIST - restart_announced + restart_respondd ;; esac - diff --git a/package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache b/package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache new file mode 100644 index 00000000..5caff40c --- /dev/null +++ b/package/gluon-respondd/files/lib/gluon/respondd/neighbours.cache @@ -0,0 +1 @@ +10000 diff --git a/package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache b/package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache new file mode 100644 index 00000000..67f9d558 --- /dev/null +++ b/package/gluon-respondd/files/lib/gluon/respondd/nodeinfo.cache @@ -0,0 +1 @@ +300000 diff --git a/package/gluon-respondd/files/lib/gluon/respondd/statistics.cache b/package/gluon-respondd/files/lib/gluon/respondd/statistics.cache new file mode 100644 index 00000000..e9c02dad --- /dev/null +++ b/package/gluon-respondd/files/lib/gluon/respondd/statistics.cache @@ -0,0 +1 @@ +5000 diff --git a/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall b/package/gluon-respondd/files/lib/gluon/upgrade/400-respondd-firewall similarity index 54% rename from package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall rename to package/gluon-respondd/files/lib/gluon/upgrade/400-respondd-firewall index 77acb1b9..65c5d8e3 100755 --- a/package/gluon-announced/files/lib/gluon/upgrade/400-announced-firewall +++ b/package/gluon-respondd/files/lib/gluon/upgrade/400-respondd-firewall @@ -2,10 +2,12 @@ local uci = require('luci.model.uci').cursor() --- Allow announced port on WAN to allow resolving neighbours over mesh-on-wan -uci:section('firewall', 'rule', 'wan_announced', +uci:delete('firewall', 'wan_announced') + +-- Allow respondd port on WAN to allow resolving neighbours over mesh-on-wan +uci:section('firewall', 'rule', 'wan_respondd', { - name = 'wan_announced', + name = 'wan_respondd', src = 'wan', src_ip = 'fe80::/64', dest_port = '1001', diff --git a/package/gluon-respondd/src/Makefile b/package/gluon-respondd/src/Makefile new file mode 100644 index 00000000..eddbe260 --- /dev/null +++ b/package/gluon-respondd/src/Makefile @@ -0,0 +1,6 @@ +all: respondd.so + +CFLAGS += -Wall + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -lplatforminfo diff --git a/package/gluon-respondd/src/respondd.c b/package/gluon-respondd/src/respondd.c new file mode 100644 index 00000000..85006d6f --- /dev/null +++ b/package/gluon-respondd/src/respondd.c @@ -0,0 +1,209 @@ +/* + Copyright (c) 2016, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + + +static struct json_object * gluon_version(void) { + char *version = gluonutil_read_line("/lib/gluon/gluon-version"); + if (!version) + return NULL; + + char full_version[6 + strlen(version) + 1]; + snprintf(full_version, sizeof(full_version), "gluon-%s", version); + + free(version); + + + return json_object_new_string(full_version); +} + +static struct json_object * get_site_code(void) { + struct json_object *site = gluonutil_load_site_config(); + if (!site) + return NULL; + + struct json_object *ret = NULL; + json_object_object_get_ex(site, "site_code", &ret); + if (ret) + json_object_get(ret); + + json_object_put(site); + return ret; +} + +static struct json_object * get_hostname(void) { + struct utsname utsname; + + if (uname(&utsname)) + return NULL; + + return gluonutil_wrap_string(utsname.nodename); +} + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + json_object_object_add(ret, "hostname", get_hostname()); + + struct json_object *hardware = json_object_new_object(); + json_object_object_add(hardware, "model", json_object_new_string(platforminfo_get_model())); + json_object_object_add(hardware, "nproc", json_object_new_int(sysconf(_SC_NPROCESSORS_ONLN))); + json_object_object_add(ret, "hardware", hardware); + + struct json_object *network = json_object_new_object(); + json_object_object_add(network, "mac", gluonutil_wrap_and_free_string(gluonutil_get_sysconfig("primary_mac"))); + json_object_object_add(ret, "network", network); + + struct json_object *software = json_object_new_object(); + struct json_object *software_firmware = json_object_new_object(); + json_object_object_add(software_firmware, "base", gluon_version()); + json_object_object_add(software_firmware, "release", gluonutil_wrap_and_free_string(gluonutil_read_line("/lib/gluon/release"))); + json_object_object_add(software, "firmware", software_firmware); + json_object_object_add(ret, "software", software); + + struct json_object *system = json_object_new_object(); + json_object_object_add(system, "site_code", get_site_code()); + json_object_object_add(ret, "system", system); + + return ret; +} + + +static void add_uptime(struct json_object *obj) { + FILE *f = fopen("/proc/uptime", "r"); + 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)); + } + + fclose(f); +} + +static void add_loadavg(struct json_object *obj) { + FILE *f = fopen("/proc/loadavg", "r"); + if (!f) + return; + + 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 *processes = json_object_new_object(); + json_object_object_add(processes, "running", json_object_new_int(proc_running)); + json_object_object_add(processes, "total", json_object_new_int(proc_total)); + json_object_object_add(obj, "processes", processes); + } + + fclose(f); +} + +static struct json_object * get_memory(void) { + FILE *f = fopen("/proc/meminfo", "r"); + if (!f) + return NULL; + + struct json_object *ret = json_object_new_object(); + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char label[32]; + unsigned value; + + if (sscanf(line, "%31[^:]: %u", label, &value) != 2) + continue; + + if (!strcmp(label, "MemTotal")) + json_object_object_add(ret, "total", json_object_new_int(value)); + else if (!strcmp(label, "MemFree")) + json_object_object_add(ret, "free", json_object_new_int(value)); + else if (!strcmp(label, "Buffers")) + json_object_object_add(ret, "buffers", json_object_new_int(value)); + else if (!strcmp(label, "Cached")) + json_object_object_add(ret, "cached", json_object_new_int(value)); + } + + free(line); + fclose(f); + + return ret; +} + +static struct json_object * get_rootfs_usage(void) { + struct statfs s; + if (statfs("/", &s)) + return NULL; + + return json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); +} + +static struct json_object * respondd_provider_statistics(void) { + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + + json_object_object_add(ret, "rootfs_usage", get_rootfs_usage()); + json_object_object_add(ret, "memory", get_memory()); + + add_uptime(ret); + add_loadavg(ret); + + return ret; +} + + +static struct json_object * respondd_provider_neighbours(void) { + struct json_object *ret = json_object_new_object(); + json_object_object_add(ret, "node_id", gluonutil_wrap_and_free_string(gluonutil_get_node_id())); + return ret; +} + + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {"statistics", respondd_provider_statistics}, + {"neighbours", respondd_provider_neighbours}, + {} +}; diff --git a/package/gluon-status-page-api/Makefile b/package/gluon-status-page-api/Makefile index 5b806331..17abab29 100644 --- a/package/gluon-status-page-api/Makefile +++ b/package/gluon-status-page-api/Makefile @@ -5,6 +5,7 @@ PKG_VERSION:=1 PKG_RELEASE:=1 PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME) +PKG_BUILD_DEPENDS := respondd include $(INCLUDE_DIR)/package.mk @@ -12,7 +13,7 @@ define Package/gluon-status-page-api SECTION:=gluon CATEGORY:=Gluon TITLE:=API for gluon-status-page - DEPENDS:=+gluon-core +uhttpd +sse-multiplex +batman-adv-visdata +gluon-neighbour-info +gluon-announced +libiwinfo +libjson-c + DEPENDS:=+gluon-core +uhttpd +sse-multiplex +batman-adv-visdata +gluon-neighbour-info +gluon-respondd +libiwinfo +libjson-c endef define Build/Prepare @@ -24,6 +25,10 @@ define Package/gluon-status-page-api/install $(INSTALL_DIR) $(1)/lib/gluon/status-page/providers $(INSTALL_BIN) $(PKG_BUILD_DIR)/neighbours-batadv $(1)/lib/gluon/status-page/providers/ $(INSTALL_BIN) $(PKG_BUILD_DIR)/stations $(1)/lib/gluon/status-page/providers/ + + $(INSTALL_DIR) $(1)/lib/gluon/respondd + $(CP) $(PKG_BUILD_DIR)/respondd.so $(1)/lib/gluon/respondd/status-page-api.so + $(CP) ./files/* $(1)/ endef diff --git a/package/gluon-status-page-api/files/lib/gluon/announce/nodeinfo.d/software/status-page b/package/gluon-status-page-api/files/lib/gluon/announce/nodeinfo.d/software/status-page deleted file mode 100644 index 20e865f3..00000000 --- a/package/gluon-status-page-api/files/lib/gluon/announce/nodeinfo.d/software/status-page +++ /dev/null @@ -1 +0,0 @@ -return { api = 1 } diff --git a/package/gluon-status-page-api/src/Makefile b/package/gluon-status-page-api/src/Makefile index f0bee975..81b48b6d 100644 --- a/package/gluon-status-page-api/src/Makefile +++ b/package/gluon-status-page-api/src/Makefile @@ -1,12 +1,15 @@ CFLAGS += -std=c99 -D_BSD_SOURCE -CFLAGS += $(shell pkg-config --cflags json-c) -LDFLAGS += $(shell pkg-config --libs json-c) +CFLAGS_JSONC = $(shell pkg-config --cflags json-c) +LDFLAGS_JSONC = $(shell pkg-config --libs json-c) -all: neighbours-batadv stations +all: neighbours-batadv stations respondd.so neighbours-batadv: neighbours-batadv.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDFLAGS_JSONC) -Wall -o $@ $^ $(LDLIBS) stations: stations.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -Wall -o $@ $^ $(LDLIBS) -liwinfo + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDFLAGS_JSONC) -Wall -o $@ $^ $(LDLIBS) -liwinfo + +respondd.so: respondd.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -o $@ $^ $(LDLIBS) diff --git a/package/gluon-status-page-api/src/respondd.c b/package/gluon-status-page-api/src/respondd.c new file mode 100644 index 00000000..f6a0e51e --- /dev/null +++ b/package/gluon-status-page-api/src/respondd.c @@ -0,0 +1,47 @@ +/* + Copyright (c) 2016, Matthias Schiffer + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + + +#include + +#include + + +static struct json_object * respondd_provider_nodeinfo(void) { + struct json_object *ret = json_object_new_object(); + + struct json_object *software = json_object_new_object(); + struct json_object *software_status_page = json_object_new_object(); + json_object_object_add(software_status_page, "api", json_object_new_int(1)); + json_object_object_add(software, "status-page", software_status_page); + json_object_object_add(ret, "software", software); + + return ret; +} + +const struct respondd_provider_info respondd_providers[] = { + {"nodeinfo", respondd_provider_nodeinfo}, + {} +};