From 0f1fa243f781ee5eef9ed4bc1b3c5397136ac2da Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Sat, 23 Nov 2019 21:32:15 +0100 Subject: [PATCH] Move common code from gluon-mesh-babel and -batman-adv respondd providers to gluon-respondd In addition this PR contains: - split of gluon-respondd provider into multiple source files - minor additional cleanups in gluon-mesh-babel respondd provider (untested, as the babel respondd provider already doesn't compile prior to these changes...) --- package/gluon-mesh-babel/src/Makefile | 2 +- package/gluon-mesh-babel/src/respondd.c | 230 ++----------- package/gluon-mesh-batman-adv/src/Makefile | 2 +- package/gluon-mesh-batman-adv/src/respondd.c | 175 +--------- package/gluon-respondd/src/Makefile | 6 +- package/gluon-respondd/src/respondd-common.h | 32 ++ .../gluon-respondd/src/respondd-neighbours.c | 130 ++++++++ .../gluon-respondd/src/respondd-nodeinfo.c | 132 ++++++++ .../gluon-respondd/src/respondd-statistics.c | 309 +++++++++++++++++ package/gluon-respondd/src/respondd.c | 310 +----------------- 10 files changed, 649 insertions(+), 679 deletions(-) create mode 100644 package/gluon-respondd/src/respondd-common.h create mode 100644 package/gluon-respondd/src/respondd-neighbours.c create mode 100644 package/gluon-respondd/src/respondd-nodeinfo.c create mode 100644 package/gluon-respondd/src/respondd-statistics.c diff --git a/package/gluon-mesh-babel/src/Makefile b/package/gluon-mesh-babel/src/Makefile index 98a22d5e5c..80d29fa942 100644 --- a/package/gluon-mesh-babel/src/Makefile +++ b/package/gluon-mesh-babel/src/Makefile @@ -25,7 +25,7 @@ LDFLAGS_JSONC = $(shell pkg-config --libs json-c) respondd.so: respondd.c handle_neighbour.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared $(LDFLAGS_JSONC) -o $@ $^ -lgluonutil -lblobmsg_json -lubox -lubus -liwinfo -luci + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $(LDLIBS) -shared $(LDFLAGS_JSONC) -o $@ $^ -lgluonutil -lblobmsg_json -lubox -lubus -luci neighbours-babel: neighbours-babel.c handle_neighbour.c $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDLIBS) $(LDFLAGS_JSONC) -o $@ $^ diff --git a/package/gluon-mesh-babel/src/respondd.c b/package/gluon-mesh-babel/src/respondd.c index 5251e89c6e..96195d899e 100644 --- a/package/gluon-mesh-babel/src/respondd.c +++ b/package/gluon-mesh-babel/src/respondd.c @@ -26,17 +26,15 @@ #include -#include #include #include #include -#include -#include #include #include #include #include +#include #include #include @@ -49,29 +47,15 @@ #include #include -#include -#include -#include - #include -#include "errno.h" +#include #include #include -#include "libubus.h" - -#define _STRINGIFY(s) #s -#define STRINGIFY(s) _STRINGIFY(s) -#include - -#define MAX_INACTIVITY 60000 +#include #define SOCKET_INPUT_BUFFER_SIZE 255 -#define BABEL_PORT 33123 -#define VPN_INTERFACE "mesh-vpn" -#define l3rdctl "/var/run/l3roamd.sock" -#define IFNAMELEN 32 #define PROTOLEN 32 #define UBUS_TIMEOUT 30000 @@ -257,9 +241,9 @@ static void blobmsg_handle_element(struct blob_attr *attr, bool head, char **ifn switch (blob_id(attr)) { case BLOBMSG_TYPE_STRING: - if (!strncmp(blobmsg_name(attr),"device", 6)) { + if (!strncmp(blobmsg_name(attr), "device", 6)) { free(*ifname); - *ifname = strndup(data, IFNAMELEN); + *ifname = strndup(data, IF_NAMESIZE); } else if (!strncmp(blobmsg_name(attr), "proto", 5)) { free(*proto); *proto = strndup(data, PROTOLEN); @@ -385,34 +369,40 @@ static struct json_object * respondd_provider_nodeinfo(void) { return ret; } -static uint64_t getnumber(const char *ifname, const char *stat) { +static struct json_object * read_number(const char *ifname, const char *stat) { const char *format = "/sys/class/net/%s/statistics/%s"; + + struct json_object *ret = NULL; + int64_t i; + char path[strlen(format) + strlen(ifname) + strlen(stat) + 1]; snprintf(path, sizeof(path), format, ifname, stat); - if (! access(path, F_OK)) { - char *line=gluonutil_read_line(path); - long long i = atoll(line); - free(line); - return(i); - } - return 0; + + FILE *f = fopen(path, "r"); + if (!f) + return NULL; + + if (fscanf(f, "%"SCNd64, &i) == 1) + ret = json_object_new_int64(i); + + fclose(f); + + return ret; } static struct json_object * get_traffic(void) { - char ifname[16]; - - strncpy(ifname, "br-client", 16); + const char *ifname = "br-client"; struct json_object *ret = NULL; struct json_object *rx = json_object_new_object(); struct json_object *tx = json_object_new_object(); - json_object_object_add(rx, "packets", json_object_new_int64(getnumber(ifname, "rx_packets"))); - json_object_object_add(rx, "bytes", json_object_new_int64(getnumber(ifname, "rx_bytes"))); - json_object_object_add(rx, "dropped", json_object_new_int64(getnumber(ifname, "rx_dropped"))); - json_object_object_add(tx, "packets", json_object_new_int64(getnumber(ifname, "tx_packets"))); - json_object_object_add(tx, "dropped", json_object_new_int64(getnumber(ifname, "tx_dropped"))); - json_object_object_add(tx, "bytes", json_object_new_int64(getnumber(ifname, "tx_bytes"))); + json_object_object_add(rx, "packets", read_number(ifname, "rx_packets")); + json_object_object_add(rx, "bytes", read_number(ifname, "rx_bytes")); + json_object_object_add(rx, "dropped", read_number(ifname, "rx_dropped")); + json_object_object_add(tx, "packets", read_number(ifname, "tx_packets")); + json_object_object_add(tx, "dropped", read_number(ifname, "tx_dropped")); + json_object_object_add(tx, "bytes", read_number(ifname, "tx_bytes")); ret = json_object_new_object(); json_object_object_add(ret, "rx", rx); @@ -421,72 +411,6 @@ static struct json_object * get_traffic(void) { 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++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - (*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 bool handle_route_addgw_nexthop(char **data, void *arg) { struct json_object *obj = (struct json_object*) arg; if (data[PREFIX] && data[FROM] && data[VIA] && data[IF]) { @@ -568,21 +492,12 @@ static int ask_l3roamd_for_client_count() { } static struct json_object * get_clients(void) { - size_t wifi24 = 0, wifi5 = 0; - - count_stations(&wifi24, &wifi5); - - int total = ask_l3roamd_for_client_count(); - - size_t wifi = wifi24 + wifi5; struct json_object *ret = json_object_new_object(); + int total = ask_l3roamd_for_client_count(); if (total >= 0) 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; } @@ -597,89 +512,6 @@ static struct json_object * respondd_provider_statistics(void) { return ret; } -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++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - 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) { - - struct uci_context *ctx = uci_alloc_context(); - ctx->flags &= ~UCI_FLAG_STRICT; - - struct json_object *ret = json_object_new_object(); - - struct uci_package *p; - if (uci_load(ctx, "network", &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, "interface")) - continue; - - const char *proto = uci_lookup_option_string(ctx, s, "proto"); - if (!proto || strcmp(proto, "gluon_mesh")) - continue; - - const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); - if (!ifname) - continue; - - 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); - } - -end: - uci_free_context(ctx); - return ret; -} - static struct json_object * respondd_provider_neighbours(void) { struct json_object *ret = json_object_new_object(); @@ -688,10 +520,6 @@ static struct json_object * respondd_provider_neighbours(void) { json_object_object_add(ret, "babel", babel); - struct json_object *wifi = get_wifi(); - if (wifi) - json_object_object_add(ret, "wifi", wifi); - return ret; } diff --git a/package/gluon-mesh-batman-adv/src/Makefile b/package/gluon-mesh-batman-adv/src/Makefile index 0974669b02..b40c52b15b 100644 --- a/package/gluon-mesh-batman-adv/src/Makefile +++ b/package/gluon-mesh-batman-adv/src/Makefile @@ -32,4 +32,4 @@ CFLAGS += $(LIBBATADV_CFLAGS) LDLIBS += $(LIBBATADV_LDLIBS) respondd.so: respondd.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -liwinfo -luci + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -luci diff --git a/package/gluon-mesh-batman-adv/src/respondd.c b/package/gluon-mesh-batman-adv/src/respondd.c index c2b20399f4..1df8d43f1e 100644 --- a/package/gluon-mesh-batman-adv/src/respondd.c +++ b/package/gluon-mesh-batman-adv/src/respondd.c @@ -26,8 +26,6 @@ #include -#include -#include #include #include #include @@ -59,9 +57,6 @@ #include -#define _STRINGIFY(s) #s -#define STRINGIFY(s) _STRINGIFY(s) - #define MAX_INACTIVITY 60000 @@ -76,7 +71,7 @@ struct gw_netlink_opts { }; struct clients_netlink_opts { - size_t non_wifi; + size_t clients; struct batadv_nlquery_opts query_opts; }; @@ -429,74 +424,6 @@ static struct json_object * get_traffic(void) { 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++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - (*wifi)++; - } -} - -static void count_stations(size_t *wifi24, size_t *wifi5) { - struct uci_context *ctx = uci_alloc_context(); - if (!ctx) - return; - 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 const enum batadv_nl_attrs clients_mandatory[] = { BATADV_ATTR_TT_FLAGS, /* Entries without the BATADV_TT_CLIENT_NOPURGE flag do not have a @@ -537,24 +464,21 @@ static int parse_clients_list_netlink_cb(struct nl_msg *msg, void *arg) flags = nla_get_u32(attrs[BATADV_ATTR_TT_FLAGS]); - if (flags & (BATADV_TT_CLIENT_NOPURGE | BATADV_TT_CLIENT_WIFI)) + if (flags & (BATADV_TT_CLIENT_NOPURGE)) return NL_OK; lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); if (lastseen > MAX_INACTIVITY) return NL_OK; - opts->non_wifi++; + opts->clients++; return NL_OK; } static struct json_object * get_clients(void) { - size_t wifi24 = 0, wifi5 = 0; - size_t total; - size_t wifi; struct clients_netlink_opts opts = { - .non_wifi = 0, + .clients = 0, .query_opts = { .err = 0, }, @@ -564,15 +488,10 @@ static struct json_object * get_clients(void) { parse_clients_list_netlink_cb, NLM_F_DUMP, &opts.query_opts); - count_stations(&wifi24, &wifi5); - wifi = wifi24 + wifi5; - total = wifi + opts.non_wifi; - 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)); + + json_object_object_add(ret, "total", json_object_new_int(opts.clients)); + return ret; } @@ -679,7 +598,7 @@ static int parse_orig_list_netlink_cb(struct nl_msg *msg, void *arg) json_object_object_add(obj, "tq", json_object_new_int(tq)); json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); - json_object_object_add(obj, "best", json_object_new_boolean(attrs[BATADV_ATTR_FLAG_BEST])); + json_object_object_add(obj, "best", json_object_new_boolean(!!attrs[BATADV_ATTR_FLAG_BEST])); json_object_object_add(interface, mac1, obj); return NL_OK; @@ -708,80 +627,6 @@ static struct json_object * get_batadv(void) { return ifnames2addrs(opts.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++) { - if (entry->inactive > MAX_INACTIVITY) - continue; - - 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(); @@ -789,10 +634,6 @@ static struct json_object * respondd_provider_neighbours(void) { 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; } diff --git a/package/gluon-respondd/src/Makefile b/package/gluon-respondd/src/Makefile index f26b59a218..9e1e831df9 100644 --- a/package/gluon-respondd/src/Makefile +++ b/package/gluon-respondd/src/Makefile @@ -2,5 +2,7 @@ all: respondd.so CFLAGS += -Wall -respondd.so: respondd.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -lplatforminfo -luci +SOURCES = respondd.c respondd-nodeinfo.c respondd-statistics.c respondd-neighbours.c + +respondd.so: $(SOURCES) respondd-common.h + $(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -fvisibility=hidden -D_GNU_SOURCE -o $@ $(SOURCES) $(LDLIBS) -lgluonutil -lplatforminfo -luci -liwinfo diff --git a/package/gluon-respondd/src/respondd-common.h b/package/gluon-respondd/src/respondd-common.h new file mode 100644 index 0000000000..db40cbaf31 --- /dev/null +++ b/package/gluon-respondd/src/respondd-common.h @@ -0,0 +1,32 @@ +/* + Copyright (c) 2016-2019, 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. +*/ + +#pragma once + +#define MAX_INACTIVITY 60000 + +struct json_object * respondd_provider_nodeinfo(void); +struct json_object * respondd_provider_statistics(void); +struct json_object * respondd_provider_neighbours(void); diff --git a/package/gluon-respondd/src/respondd-neighbours.c b/package/gluon-respondd/src/respondd-neighbours.c new file mode 100644 index 0000000000..2a07634f8d --- /dev/null +++ b/package/gluon-respondd/src/respondd-neighbours.c @@ -0,0 +1,130 @@ +/* + Copyright (c) 2016-2019, 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 "respondd-common.h" + +#include + +#include +#include + + +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++) { + if (entry->inactive > MAX_INACTIVITY) + continue; + + 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) { + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) + return NULL; + + ctx->flags &= ~UCI_FLAG_STRICT; + + struct json_object *ret = json_object_new_object(); + + struct uci_package *p; + if (uci_load(ctx, "network", &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, "interface")) + continue; + + const char *proto = uci_lookup_option_string(ctx, s, "proto"); + if (!proto || strcmp(proto, "gluon_mesh")) + continue; + + const char *ifname = uci_lookup_option_string(ctx, s, "ifname"); + if (!ifname) + continue; + + 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); + } + +end: + uci_free_context(ctx); + return ret; +} + +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())); + + struct json_object *wifi = get_wifi(); + if (wifi) + json_object_object_add(ret, "wifi", wifi); + + + return ret; +} diff --git a/package/gluon-respondd/src/respondd-nodeinfo.c b/package/gluon-respondd/src/respondd-nodeinfo.c new file mode 100644 index 0000000000..f70abc9a33 --- /dev/null +++ b/package/gluon-respondd/src/respondd-nodeinfo.c @@ -0,0 +1,132 @@ +/* + Copyright (c) 2016-2019, 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 "respondd-common.h" + +#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_domain_code(void) { + return gluonutil_wrap_and_free_string(gluonutil_get_domain()); +} + +static struct json_object * get_hostname(void) { + struct json_object *ret = NULL; + + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) + return NULL; + ctx->flags &= ~UCI_FLAG_STRICT; + + char section[] = "system.@system[0]"; + struct uci_ptr ptr; + if (uci_lookup_ptr(ctx, &ptr, section, true)) + goto error; + + struct uci_section *s = ptr.s; + + const char *hostname = uci_lookup_option_string(ctx, s, "pretty_hostname"); + + if (!hostname) + hostname = uci_lookup_option_string(ctx, s, "hostname"); + + ret = gluonutil_wrap_string(hostname); + +error: + uci_free_context(ctx); + + return ret; +} + +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(); + + const char *model = platforminfo_get_model(); + if (model) + json_object_object_add(hardware, "model", json_object_new_string(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()); + if (gluonutil_has_domains()) + json_object_object_add(system, "domain_code", get_domain_code()); + json_object_object_add(ret, "system", system); + + return ret; +} diff --git a/package/gluon-respondd/src/respondd-statistics.c b/package/gluon-respondd/src/respondd-statistics.c new file mode 100644 index 0000000000..634b294262 --- /dev/null +++ b/package/gluon-respondd/src/respondd-statistics.c @@ -0,0 +1,309 @@ +/* + Copyright (c) 2016-2019, 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 "respondd-common.h" + +#include + +#include +#include + +#include +#include +#include +#include + +#include + + +static void add_uptime(struct json_object *obj) { + FILE *f = fopen("/proc/uptime", "r"); + struct json_object* jso; + if (!f) + return; + + double uptime, idletime; + if (fscanf(f, "%lf %lf", &uptime, &idletime) == 2) { + jso = json_object_new_double(uptime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "uptime", jso); + jso = json_object_new_double(idletime); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "idletime", jso); + } + + fclose(f); +} + +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) { + struct json_object *jso = json_object_new_double(loadavg); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); + json_object_object_add(obj, "loadavg", jso); + + struct json_object *processes = json_object_new_object(); + json_object_object_add(processes, "running", json_object_new_int(proc_running)); + 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, "MemAvailable")) + json_object_object_add(ret, "available", 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_stat(void) { + FILE *f = fopen("/proc/stat", "r"); + if (!f) + return NULL; + + struct json_object *stat = json_object_new_object(); + struct json_object *ret = NULL; + + char *line = NULL; + size_t len = 0; + + while (getline(&line, &len, f) >= 0) { + char label[32]; + + if (sscanf(line, "%31s", label) != 1){ + goto invalid_stat_format; + } + + if (!strcmp(label, "cpu")) { + int64_t user, nice, system, idle, iowait, irq, softirq; + if (sscanf(line, "%*s %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64, + &user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7) + goto invalid_stat_format; + + struct json_object *cpu = json_object_new_object(); + + json_object_object_add(cpu, "user", json_object_new_int64(user)); + json_object_object_add(cpu, "nice", json_object_new_int64(nice)); + json_object_object_add(cpu, "system", json_object_new_int64(system)); + json_object_object_add(cpu, "idle", json_object_new_int64(idle)); + json_object_object_add(cpu, "iowait", json_object_new_int64(iowait)); + json_object_object_add(cpu, "irq", json_object_new_int64(irq)); + json_object_object_add(cpu, "softirq", json_object_new_int64(softirq)); + + json_object_object_add(stat, "cpu", cpu); + } else if (!strcmp(label, "ctxt")) { + int64_t ctxt; + if (sscanf(line, "%*s %"SCNd64, &ctxt) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "ctxt", json_object_new_int64(ctxt)); + } else if (!strcmp(label, "intr")) { + int64_t total_intr; + if (sscanf(line, "%*s %"SCNd64, &total_intr) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "intr", json_object_new_int64(total_intr)); + } else if (!strcmp(label, "softirq")) { + int64_t total_softirq; + if (sscanf(line, "%*s %"SCNd64, &total_softirq) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "softirq", json_object_new_int64(total_softirq)); + } else if (!strcmp(label, "processes")) { + int64_t processes; + if (sscanf(line, "%*s %"SCNd64, &processes) != 1) + goto invalid_stat_format; + + json_object_object_add(stat, "processes", json_object_new_int64(processes)); + } + + } + + ret = stat; + +invalid_stat_format: + if (!ret) + json_object_put(stat); + + free(line); + fclose(f); + + return ret; +} + + +static struct json_object * get_rootfs_usage(void) { + struct statfs s; + if (statfs("/", &s)) + return NULL; + + struct json_object *jso = json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); + json_object_set_serializer(jso, json_object_double_to_json_string, "%.4f", NULL); + return jso; +} + +static struct json_object * get_time(void) { + struct timespec now; + + if (clock_gettime(CLOCK_REALTIME, &now) != 0) + return NULL; + + return json_object_new_int64(now.tv_sec); +} + +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++) { + if (entry->inactive > MAX_INACTIVITY) + continue; + + (*wifi)++; + } +} + +static void count_stations(size_t *wifi24, size_t *wifi5) { + struct uci_context *ctx = uci_alloc_context(); + if (!ctx) + return; + 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 wifi24 = 0, wifi5 = 0; + + count_stations(&wifi24, &wifi5); + + struct json_object *ret = json_object_new_object(); + + json_object_object_add(ret, "wifi", json_object_new_int(wifi24 + wifi5)); + json_object_object_add(ret, "wifi24", json_object_new_int(wifi24)); + json_object_object_add(ret, "wifi5", json_object_new_int(wifi5)); + + return ret; +} + +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, "time", get_time()); + json_object_object_add(ret, "rootfs_usage", get_rootfs_usage()); + json_object_object_add(ret, "memory", get_memory()); + json_object_object_add(ret, "stat", get_stat()); + + json_object_object_add(ret, "clients", get_clients()); + + add_uptime(ret); + add_loadavg(ret); + + return ret; +} diff --git a/package/gluon-respondd/src/respondd.c b/package/gluon-respondd/src/respondd.c index 04010c6813..36188e467a 100644 --- a/package/gluon-respondd/src/respondd.c +++ b/package/gluon-respondd/src/respondd.c @@ -1,5 +1,5 @@ /* - Copyright (c) 2016, Matthias Schiffer + Copyright (c) 2016-2019, Matthias Schiffer All rights reserved. Redistribution and use in source and binary forms, with or without @@ -23,316 +23,12 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "respondd-common.h" #include -#include -#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_domain_code(void) { - return gluonutil_wrap_and_free_string(gluonutil_get_domain()); -} - -static struct json_object * get_hostname(void) { - struct json_object *ret = NULL; - - struct uci_context *ctx = uci_alloc_context(); - if (!ctx) - return NULL; - ctx->flags &= ~UCI_FLAG_STRICT; - - char section[] = "system.@system[0]"; - struct uci_ptr ptr; - if (uci_lookup_ptr(ctx, &ptr, section, true)) - goto error; - - struct uci_section *s = ptr.s; - - const char *hostname = uci_lookup_option_string(ctx, s, "pretty_hostname"); - - if (!hostname) - hostname = uci_lookup_option_string(ctx, s, "hostname"); - - ret = gluonutil_wrap_string(hostname); - -error: - uci_free_context(ctx); - - return ret; -} - -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(); - - const char *model = platforminfo_get_model(); - if (model) - json_object_object_add(hardware, "model", json_object_new_string(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()); - if (gluonutil_has_domains()) - json_object_object_add(system, "domain_code", get_domain_code()); - json_object_object_add(ret, "system", system); - - return ret; -} - - -static void add_uptime(struct json_object *obj) { - FILE *f = fopen("/proc/uptime", "r"); - struct json_object* jso; - if (!f) - return; - - double uptime, idletime; - if (fscanf(f, "%lf %lf", &uptime, &idletime) == 2) { - jso = json_object_new_double(uptime); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); - json_object_object_add(obj, "uptime", jso); - jso = json_object_new_double(idletime); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); - json_object_object_add(obj, "idletime", jso); - } - - fclose(f); -} - -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) { - struct json_object *jso = json_object_new_double(loadavg); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.2f", NULL); - json_object_object_add(obj, "loadavg", jso); - - struct json_object *processes = json_object_new_object(); - json_object_object_add(processes, "running", json_object_new_int(proc_running)); - 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, "MemAvailable")) - json_object_object_add(ret, "available", 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_stat(void) { - FILE *f = fopen("/proc/stat", "r"); - if (!f) - return NULL; - - struct json_object *stat = json_object_new_object(); - struct json_object *ret = NULL; - - char *line = NULL; - size_t len = 0; - - while (getline(&line, &len, f) >= 0) { - char label[32]; - - if (sscanf(line, "%31s", label) != 1){ - goto invalid_stat_format; - } - - if (!strcmp(label, "cpu")) { - int64_t user, nice, system, idle, iowait, irq, softirq; - if (sscanf(line, "%*s %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64" %"SCNd64, - &user, &nice, &system, &idle, &iowait, &irq, &softirq) != 7) - goto invalid_stat_format; - - struct json_object *cpu = json_object_new_object(); - - json_object_object_add(cpu, "user", json_object_new_int64(user)); - json_object_object_add(cpu, "nice", json_object_new_int64(nice)); - json_object_object_add(cpu, "system", json_object_new_int64(system)); - json_object_object_add(cpu, "idle", json_object_new_int64(idle)); - json_object_object_add(cpu, "iowait", json_object_new_int64(iowait)); - json_object_object_add(cpu, "irq", json_object_new_int64(irq)); - json_object_object_add(cpu, "softirq", json_object_new_int64(softirq)); - - json_object_object_add(stat, "cpu", cpu); - } else if (!strcmp(label, "ctxt")) { - int64_t ctxt; - if (sscanf(line, "%*s %"SCNd64, &ctxt) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "ctxt", json_object_new_int64(ctxt)); - } else if (!strcmp(label, "intr")) { - int64_t total_intr; - if (sscanf(line, "%*s %"SCNd64, &total_intr) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "intr", json_object_new_int64(total_intr)); - } else if (!strcmp(label, "softirq")) { - int64_t total_softirq; - if (sscanf(line, "%*s %"SCNd64, &total_softirq) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "softirq", json_object_new_int64(total_softirq)); - } else if (!strcmp(label, "processes")) { - int64_t processes; - if (sscanf(line, "%*s %"SCNd64, &processes) != 1) - goto invalid_stat_format; - - json_object_object_add(stat, "processes", json_object_new_int64(processes)); - } - - } - - ret = stat; - -invalid_stat_format: - if (!ret) - json_object_put(stat); - - free(line); - fclose(f); - - return ret; -} - - -static struct json_object * get_rootfs_usage(void) { - struct statfs s; - if (statfs("/", &s)) - return NULL; - - struct json_object *jso = json_object_new_double(1 - (double)s.f_bfree / s.f_blocks); - json_object_set_serializer(jso, json_object_double_to_json_string, "%.4f", NULL); - return jso; -} - -static struct json_object * get_time(void) { - struct timespec now; - - if (clock_gettime(CLOCK_REALTIME, &now) != 0) - return NULL; - - return json_object_new_int64(now.tv_sec); -} - -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 *time = get_time(); - if (time != NULL) - json_object_object_add(ret, "time", time); - - json_object_object_add(ret, "rootfs_usage", get_rootfs_usage()); - json_object_object_add(ret, "memory", get_memory()); - json_object_object_add(ret, "stat", get_stat()); - - 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; -} - +__attribute__ ((visibility ("default"))) const struct respondd_provider_info respondd_providers[] = { {"nodeinfo", respondd_provider_nodeinfo}, {"statistics", respondd_provider_statistics},