From 8bbf59dcc6bd33a2353d56da5390c3c869c57c3a Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Thu, 1 Sep 2011 22:54:29 +0000 Subject: [PATCH] modules/admin-full: rework realtime stats to start luci-bwc on demand, kill daemon after ten seconds of inactivity --- .../luasrc/controller/admin/status.lua | 85 +++----- modules/admin-full/root/etc/init.d/luci_bwc | 14 -- modules/admin-full/src/luci-bwc.c | 206 +++++++++++++----- 3 files changed, 190 insertions(+), 115 deletions(-) delete mode 100755 modules/admin-full/root/etc/init.d/luci_bwc diff --git a/modules/admin-full/luasrc/controller/admin/status.lua b/modules/admin-full/luasrc/controller/admin/status.lua index f9bfd908d6..61704ff55b 100644 --- a/modules/admin-full/luasrc/controller/admin/status.lua +++ b/modules/admin-full/luasrc/controller/admin/status.lua @@ -69,57 +69,42 @@ function action_bandwidth() local path = luci.dispatcher.context.requestpath local iface = path[#path] - local fs = require "luci.fs" - if fs.access("/var/lib/luci-bwc/if/%s" % iface) then - luci.http.prepare_content("application/json") - - local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface) - if bwc then - luci.http.write("[") - - while true do - local ln = bwc:read("*l") - if not ln then break end - luci.http.write(ln) - end - - luci.http.write("]") - bwc:close() + luci.http.prepare_content("application/json") + + local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface) + if bwc then + luci.http.write("[") + + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) end - return + luci.http.write("]") + bwc:close() end - - luci.http.status(404, "No data available") end function action_load() - local fs = require "luci.fs" - if fs.access("/var/lib/luci-bwc/load") then - luci.http.prepare_content("application/json") - - local bwc = io.popen("luci-bwc -l 2>/dev/null") - if bwc then - luci.http.write("[") - - while true do - local ln = bwc:read("*l") - if not ln then break end - luci.http.write(ln) - end - - luci.http.write("]") - bwc:close() + luci.http.prepare_content("application/json") + + local bwc = io.popen("luci-bwc -l 2>/dev/null") + if bwc then + luci.http.write("[") + + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) end - return + luci.http.write("]") + bwc:close() end - - luci.http.status(404, "No data available") end function action_connections() - local fs = require "luci.fs" local sys = require "luci.sys" luci.http.prepare_content("application/json") @@ -127,20 +112,18 @@ function action_connections() luci.http.write("{ connections: ") luci.http.write_json(sys.net.conntrack()) - if fs.access("/var/lib/luci-bwc/connections") then - local bwc = io.popen("luci-bwc -c 2>/dev/null") - if bwc then - luci.http.write(", statistics: [") + local bwc = io.popen("luci-bwc -c 2>/dev/null") + if bwc then + luci.http.write(", statistics: [") - while true do - local ln = bwc:read("*l") - if not ln then break end - luci.http.write(ln) - end - - luci.http.write("]") - bwc:close() + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) end + + luci.http.write("]") + bwc:close() end luci.http.write(" }") diff --git a/modules/admin-full/root/etc/init.d/luci_bwc b/modules/admin-full/root/etc/init.d/luci_bwc deleted file mode 100755 index fe246073f0..0000000000 --- a/modules/admin-full/root/etc/init.d/luci_bwc +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh /etc/rc.common - -START=95 -STOP=95 - -BWC=/usr/bin/luci-bwc - -start() { - $BWC -d -} - -stop() { - killall ${BWC##*/} -} diff --git a/modules/admin-full/src/luci-bwc.c b/modules/admin-full/src/luci-bwc.c index 4067c577af..f173d44e0f 100644 --- a/modules/admin-full/src/luci-bwc.c +++ b/modules/admin-full/src/luci-bwc.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,9 @@ #define STEP_COUNT 60 #define STEP_TIME 1 +#define TIMEOUT 10 + +#define PID_PATH "/var/run/luci-bwc.pid" #define DB_PATH "/var/lib/luci-bwc" #define DB_IF_FILE DB_PATH "/if/%s" @@ -90,6 +94,53 @@ static uint64_t htonll(uint64_t value) #define ntohll htonll +static int readpid(void) +{ + int fd; + int pid = -1; + char buf[9] = { 0 }; + + if ((fd = open(PID_PATH, O_RDONLY)) > -1) + { + if (read(fd, buf, sizeof(buf))) + { + buf[8] = 0; + pid = atoi(buf); + } + + close(fd); + } + + return pid; +} + +static int writepid(void) +{ + int fd; + int wlen; + char buf[9] = { 0 }; + + if ((fd = open(PID_PATH, O_WRONLY | O_CREAT | O_TRUNC, 0600)) > -1) + { + wlen = snprintf(buf, sizeof(buf), "%i", getpid()); + write(fd, buf, wlen); + close(fd); + + return 0; + } + + return -1; +} + +static int timeout = TIMEOUT; +static int countdown = -1; + +static void reset_countdown(int sig) +{ + countdown = timeout; + +} + static int init_directory(char *path) { @@ -135,6 +186,11 @@ static int init_file(char *path, int esize) return -1; } +static inline uint64_t timeof(void *entry) +{ + return ((struct traffic_entry *)entry)->time; +} + static int update_file(const char *path, void *entry, int esize) { int rv = -1; @@ -148,8 +204,11 @@ static int update_file(const char *path, void *entry, int esize) if ((map != NULL) && (map != MAP_FAILED)) { - memmove(map, map + esize, esize * (STEP_COUNT-1)); - memcpy(map + esize * (STEP_COUNT-1), entry, esize); + if (timeof(entry) > timeof(map + esize * (STEP_COUNT-1))) + { + memmove(map, map + esize, esize * (STEP_COUNT-1)); + memcpy(map + esize * (STEP_COUNT-1), entry, esize); + } munmap(map, esize * STEP_COUNT); @@ -277,7 +336,7 @@ static int update_ldstat(uint16_t load1, uint16_t load5, uint16_t load15) return update_file(path, &e, sizeof(struct load_entry)); } -static int run_daemon(int nofork) +static int run_daemon(char *progname) { FILE *info; uint64_t rxb, txb, rxp, txp; @@ -286,39 +345,53 @@ static int run_daemon(int nofork) char line[1024]; char ifname[16]; + struct sigaction sa; + struct stat s; const char *ipc = stat("/proc/net/nf_conntrack", &s) ? "/proc/net/ip_conntrack" : "/proc/net/nf_conntrack"; - if (!nofork) + switch (fork()) { - switch (fork()) - { - case -1: - perror("fork()"); - return -1; + case -1: + perror("fork()"); + return -1; - case 0: - if (chdir("/") < 0) - { - perror("chdir()"); - exit(1); - } + case 0: + if (chdir("/") < 0) + { + perror("chdir()"); + exit(1); + } - close(0); - close(1); - close(2); - break; + close(0); + close(1); + close(2); + break; - default: - exit(0); - } + default: + return 0; } + /* setup USR1 signal handler to reset timer */ + sa.sa_handler = reset_countdown; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + sigaction(SIGUSR1, &sa, NULL); + + /* write pid */ + if (writepid()) + { + fprintf(stderr, "Failed to write pid file: %s\n", strerror(errno)); + return 1; + } /* go */ - while (1) + for (reset_countdown(0); countdown >= 0; countdown--) { + /* alter progname for ps, top */ + sprintf(progname, "luci-bwc %d", countdown); + if ((info = fopen("/proc/net/dev", "r")) != NULL) { while (fgets(line, sizeof(line), info)) @@ -377,9 +450,38 @@ static int run_daemon(int nofork) sleep(STEP_TIME); } + + unlink(PID_PATH); + + return 0; +} + +static int check_daemon(char *progname) +{ + int pid; + + if ((pid = readpid()) < 0 || kill(pid, 0) < 0) + { + /* daemon ping failed, try to start it up */ + if (run_daemon(progname)) + { + fprintf(stderr, + "Failed to ping daemon and unable to start it up: %s\n", + strerror(errno)); + + return 1; + } + } + else if (kill(pid, SIGUSR1)) + { + fprintf(stderr, "Failed to send signal: %s\n", strerror(errno)); + return 1; + } + + return 0; } -static int run_dump_ifname(const char *ifname) +static int run_dump_ifname(char *progname, const char *ifname) { int i; char path[1024]; @@ -388,6 +490,11 @@ static int run_dump_ifname(const char *ifname) snprintf(path, sizeof(path), DB_IF_FILE, ifname); + if (check_daemon(progname)) + { + return 1; + } + if (mmap_file(path, sizeof(struct traffic_entry), &m)) { fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); @@ -414,7 +521,7 @@ static int run_dump_ifname(const char *ifname) return 0; } -static int run_dump_conns(void) +static int run_dump_conns(char *progname) { int i; char path[1024]; @@ -423,6 +530,11 @@ static int run_dump_conns(void) snprintf(path, sizeof(path), DB_CN_FILE); + if (check_daemon(progname)) + { + return 1; + } + if (mmap_file(path, sizeof(struct conn_entry), &m)) { fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); @@ -447,7 +559,7 @@ static int run_dump_conns(void) return 0; } -static int run_dump_load(void) +static int run_dump_load(char *progname) { int i; char path[1024]; @@ -456,6 +568,11 @@ static int run_dump_load(void) snprintf(path, sizeof(path), DB_LD_FILE); + if (check_daemon(progname)) + { + return 1; + } + if (mmap_file(path, sizeof(struct load_entry), &m)) { fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); @@ -484,49 +601,38 @@ static int run_dump_load(void) int main(int argc, char *argv[]) { int opt; - int daemon = 0; - int nofork = 0; - while ((opt = getopt(argc, argv, "dfi:cl")) > -1) + while ((opt = getopt(argc, argv, "t:i:cl")) > -1) { switch (opt) { - case 'd': - daemon = 1; - break; - - case 'f': - nofork = 1; + case 't': + timeout = atoi(optarg); break; case 'i': if (optarg) - return run_dump_ifname(optarg); + return run_dump_ifname(argv[0], optarg); break; case 'c': - return run_dump_conns(); + return run_dump_conns(argv[0]); case 'l': - return run_dump_load(); + return run_dump_load(argv[0]); default: break; } } - if (daemon) - return run_daemon(nofork); - - else - fprintf(stderr, - "Usage:\n" - " %s -d [-f]\n" - " %s -i ifname\n" - " %s -c\n" - " %s -l\n", - argv[0], argv[0], argv[0], argv[0] - ); + fprintf(stderr, + "Usage:\n" + " %s [-t timeout] -i ifname\n" + " %s [-t timeout] -c\n" + " %s [-t timeout] -l\n", + argv[0], argv[0], argv[0] + ); return 1; } -- 2.30.2