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...)
This commit is contained in:
Matthias Schiffer 2019-11-23 21:32:15 +01:00
parent f34b302b22
commit 0f1fa243f7
No known key found for this signature in database
GPG Key ID: 16EF3F64CB201D9C
10 changed files with 649 additions and 679 deletions

View File

@ -25,7 +25,7 @@ LDFLAGS_JSONC = $(shell pkg-config --libs json-c)
respondd.so: respondd.c handle_neighbour.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 neighbours-babel: neighbours-babel.c handle_neighbour.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDLIBS) $(LDFLAGS_JSONC) -o $@ $^ $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_JSONC) $(LDFLAGS) $(LDLIBS) $(LDFLAGS_JSONC) -o $@ $^

View File

@ -26,17 +26,15 @@
#include <respondd.h> #include <respondd.h>
#include <iwinfo.h>
#include <json-c/json.h> #include <json-c/json.h>
#include <libgluonutil.h> #include <libgluonutil.h>
#include <uci.h> #include <uci.h>
#include <alloca.h>
#include <glob.h>
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -49,29 +47,15 @@
#include <sys/un.h> #include <sys/un.h>
#include <ifaddrs.h> #include <ifaddrs.h>
#include <linux/ethtool.h>
#include <linux/if_addr.h>
#include <linux/sockios.h>
#include <netdb.h> #include <netdb.h>
#include "errno.h" #include <errno.h>
#include <libbabelhelper/babelhelper.h> #include <libbabelhelper/babelhelper.h>
#include <libubox/blobmsg_json.h> #include <libubox/blobmsg_json.h>
#include "libubus.h" #include <libubus.h>
#define _STRINGIFY(s) #s
#define STRINGIFY(s) _STRINGIFY(s)
#include <stdlib.h>
#define MAX_INACTIVITY 60000
#define SOCKET_INPUT_BUFFER_SIZE 255 #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 PROTOLEN 32
#define UBUS_TIMEOUT 30000 #define UBUS_TIMEOUT 30000
@ -259,7 +243,7 @@ static void blobmsg_handle_element(struct blob_attr *attr, bool head, char **ifn
case BLOBMSG_TYPE_STRING: case BLOBMSG_TYPE_STRING:
if (!strncmp(blobmsg_name(attr), "device", 6)) { if (!strncmp(blobmsg_name(attr), "device", 6)) {
free(*ifname); free(*ifname);
*ifname = strndup(data, IFNAMELEN); *ifname = strndup(data, IF_NAMESIZE);
} else if (!strncmp(blobmsg_name(attr), "proto", 5)) { } else if (!strncmp(blobmsg_name(attr), "proto", 5)) {
free(*proto); free(*proto);
*proto = strndup(data, PROTOLEN); *proto = strndup(data, PROTOLEN);
@ -385,34 +369,40 @@ static struct json_object * respondd_provider_nodeinfo(void) {
return ret; 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"; 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]; char path[strlen(format) + strlen(ifname) + strlen(stat) + 1];
snprintf(path, sizeof(path), format, ifname, stat); snprintf(path, sizeof(path), format, ifname, stat);
if (! access(path, F_OK)) {
char *line=gluonutil_read_line(path); FILE *f = fopen(path, "r");
long long i = atoll(line); if (!f)
free(line); return NULL;
return(i);
} if (fscanf(f, "%"SCNd64, &i) == 1)
return 0; ret = json_object_new_int64(i);
fclose(f);
return ret;
} }
static struct json_object * get_traffic(void) { static struct json_object * get_traffic(void) {
char ifname[16]; const char *ifname = "br-client";
strncpy(ifname, "br-client", 16);
struct json_object *ret = NULL; struct json_object *ret = NULL;
struct json_object *rx = json_object_new_object(); struct json_object *rx = json_object_new_object();
struct json_object *tx = 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, "packets", read_number(ifname, "rx_packets"));
json_object_object_add(rx, "bytes", json_object_new_int64(getnumber(ifname, "rx_bytes"))); json_object_object_add(rx, "bytes", read_number(ifname, "rx_bytes"));
json_object_object_add(rx, "dropped", json_object_new_int64(getnumber(ifname, "rx_dropped"))); json_object_object_add(rx, "dropped", read_number(ifname, "rx_dropped"));
json_object_object_add(tx, "packets", json_object_new_int64(getnumber(ifname, "tx_packets"))); json_object_object_add(tx, "packets", read_number(ifname, "tx_packets"));
json_object_object_add(tx, "dropped", json_object_new_int64(getnumber(ifname, "tx_dropped"))); json_object_object_add(tx, "dropped", read_number(ifname, "tx_dropped"));
json_object_object_add(tx, "bytes", json_object_new_int64(getnumber(ifname, "tx_bytes"))); json_object_object_add(tx, "bytes", read_number(ifname, "tx_bytes"));
ret = json_object_new_object(); ret = json_object_new_object();
json_object_object_add(ret, "rx", rx); json_object_object_add(ret, "rx", rx);
@ -421,72 +411,6 @@ static struct json_object * get_traffic(void) {
return ret; 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) { static bool handle_route_addgw_nexthop(char **data, void *arg) {
struct json_object *obj = (struct json_object*) arg; struct json_object *obj = (struct json_object*) arg;
if (data[PREFIX] && data[FROM] && data[VIA] && data[IF]) { if (data[PREFIX] && data[FROM] && data[VIA] && data[IF]) {
@ -568,21 +492,12 @@ end:
} }
static struct json_object * get_clients(void) { 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(); struct json_object *ret = json_object_new_object();
int total = ask_l3roamd_for_client_count();
if (total >= 0) if (total >= 0)
json_object_object_add(ret, "total", json_object_new_int(total)); 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; return ret;
} }
@ -597,89 +512,6 @@ static struct json_object * respondd_provider_statistics(void) {
return ret; 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) { static struct json_object * respondd_provider_neighbours(void) {
struct json_object *ret = json_object_new_object(); 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); json_object_object_add(ret, "babel", babel);
struct json_object *wifi = get_wifi();
if (wifi)
json_object_object_add(ret, "wifi", wifi);
return ret; return ret;
} }

View File

@ -32,4 +32,4 @@ CFLAGS += $(LIBBATADV_CFLAGS)
LDLIBS += $(LIBBATADV_LDLIBS) LDLIBS += $(LIBBATADV_LDLIBS)
respondd.so: respondd.c 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

View File

@ -26,8 +26,6 @@
#include <respondd.h> #include <respondd.h>
#include <ifaddrs.h>
#include <iwinfo.h>
#include <json-c/json.h> #include <json-c/json.h>
#include <libgluonutil.h> #include <libgluonutil.h>
#include <uci.h> #include <uci.h>
@ -59,9 +57,6 @@
#include <batadv-genl.h> #include <batadv-genl.h>
#define _STRINGIFY(s) #s
#define STRINGIFY(s) _STRINGIFY(s)
#define MAX_INACTIVITY 60000 #define MAX_INACTIVITY 60000
@ -76,7 +71,7 @@ struct gw_netlink_opts {
}; };
struct clients_netlink_opts { struct clients_netlink_opts {
size_t non_wifi; size_t clients;
struct batadv_nlquery_opts query_opts; struct batadv_nlquery_opts query_opts;
}; };
@ -429,74 +424,6 @@ static struct json_object * get_traffic(void) {
return ret; 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[] = { static const enum batadv_nl_attrs clients_mandatory[] = {
BATADV_ATTR_TT_FLAGS, BATADV_ATTR_TT_FLAGS,
/* Entries without the BATADV_TT_CLIENT_NOPURGE flag do not have a /* 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]); 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; return NL_OK;
lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]); lastseen = nla_get_u32(attrs[BATADV_ATTR_LAST_SEEN_MSECS]);
if (lastseen > MAX_INACTIVITY) if (lastseen > MAX_INACTIVITY)
return NL_OK; return NL_OK;
opts->non_wifi++; opts->clients++;
return NL_OK; return NL_OK;
} }
static struct json_object * get_clients(void) { static struct json_object * get_clients(void) {
size_t wifi24 = 0, wifi5 = 0;
size_t total;
size_t wifi;
struct clients_netlink_opts opts = { struct clients_netlink_opts opts = {
.non_wifi = 0, .clients = 0,
.query_opts = { .query_opts = {
.err = 0, .err = 0,
}, },
@ -564,15 +488,10 @@ static struct json_object * get_clients(void) {
parse_clients_list_netlink_cb, NLM_F_DUMP, parse_clients_list_netlink_cb, NLM_F_DUMP,
&opts.query_opts); &opts.query_opts);
count_stations(&wifi24, &wifi5);
wifi = wifi24 + wifi5;
total = wifi + opts.non_wifi;
struct json_object *ret = json_object_new_object(); 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, "total", json_object_new_int(opts.clients));
json_object_object_add(ret, "wifi24", json_object_new_int(wifi24));
json_object_object_add(ret, "wifi5", json_object_new_int(wifi5));
return ret; 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, "tq", json_object_new_int(tq));
json_object_object_add(obj, "lastseen", json_object_new_double(lastseen / 1000.)); 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); json_object_object_add(interface, mac1, obj);
return NL_OK; return NL_OK;
@ -708,80 +627,6 @@ static struct json_object * get_batadv(void) {
return ifnames2addrs(opts.interfaces); 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) { static struct json_object * respondd_provider_neighbours(void) {
struct json_object *ret = json_object_new_object(); struct json_object *ret = json_object_new_object();
@ -789,10 +634,6 @@ static struct json_object * respondd_provider_neighbours(void) {
if (batadv) if (batadv)
json_object_object_add(ret, "batadv", 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; return ret;
} }

View File

@ -2,5 +2,7 @@ all: respondd.so
CFLAGS += -Wall CFLAGS += -Wall
respondd.so: respondd.c SOURCES = respondd.c respondd-nodeinfo.c respondd-statistics.c respondd-neighbours.c
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -D_GNU_SOURCE -o $@ $^ $(LDLIBS) -lgluonutil -lplatforminfo -luci
respondd.so: $(SOURCES) respondd-common.h
$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -shared -fPIC -fvisibility=hidden -D_GNU_SOURCE -o $@ $(SOURCES) $(LDLIBS) -lgluonutil -lplatforminfo -luci -liwinfo

View File

@ -0,0 +1,32 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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);

View File

@ -0,0 +1,130 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <iwinfo.h>
#include <json-c/json.h>
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;
}

View File

@ -0,0 +1,132 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <libplatforminfo.h>
#include <json-c/json.h>
#include <uci.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
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;
}

View File

@ -0,0 +1,309 @@
/*
Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
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 <libgluonutil.h>
#include <iwinfo.h>
#include <json-c/json.h>
#include <inttypes.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/vfs.h>
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;
}

View File

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2016, Matthias Schiffer <mschiffer@universe-factory.net> Copyright (c) 2016-2019, Matthias Schiffer <mschiffer@universe-factory.net>
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without 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. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "respondd-common.h"
#include <respondd.h> #include <respondd.h>
#include <json-c/json.h>
#include <libgluonutil.h>
#include <libplatforminfo.h>
#include <uci.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <inttypes.h>
#include <sys/vfs.h>
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[] = { const struct respondd_provider_info respondd_providers[] = {
{"nodeinfo", respondd_provider_nodeinfo}, {"nodeinfo", respondd_provider_nodeinfo},
{"statistics", respondd_provider_statistics}, {"statistics", respondd_provider_statistics},