modules/admin-full: rework realtime stats to start luci-bwc on demand, kill daemon...
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 1 Sep 2011 22:54:29 +0000 (22:54 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 1 Sep 2011 22:54:29 +0000 (22:54 +0000)
modules/admin-full/luasrc/controller/admin/status.lua
modules/admin-full/root/etc/init.d/luci_bwc [deleted file]
modules/admin-full/src/luci-bwc.c

index f9bfd90..61704ff 100644 (file)
@@ -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 (executable)
index fe24607..0000000
+++ /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##*/}
-}
index 4067c57..f173d44 100644 (file)
@@ -25,6 +25,7 @@
 #include <time.h>
 #include <errno.h>
 #include <unistd.h>
+#include <signal.h>
 
 #include <sys/stat.h>
 #include <sys/mman.h>
@@ -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;
 }