modules/admin-full: rework realtime stats to start luci-bwc on demand, kill daemon after ten seconds of inactivity

This commit is contained in:
Jo-Philipp Wich 2011-09-01 22:54:29 +00:00
parent 37df666e0a
commit 8bbf59dcc6
3 changed files with 186 additions and 111 deletions

View file

@ -69,57 +69,42 @@ function action_bandwidth()
local path = luci.dispatcher.context.requestpath local path = luci.dispatcher.context.requestpath
local iface = path[#path] local iface = path[#path]
local fs = require "luci.fs" luci.http.prepare_content("application/json")
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) local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface)
if bwc then if bwc then
luci.http.write("[") luci.http.write("[")
while true do while true do
local ln = bwc:read("*l") local ln = bwc:read("*l")
if not ln then break end if not ln then break end
luci.http.write(ln) luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end end
return luci.http.write("]")
bwc:close()
end end
luci.http.status(404, "No data available")
end end
function action_load() function action_load()
local fs = require "luci.fs" luci.http.prepare_content("application/json")
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") local bwc = io.popen("luci-bwc -l 2>/dev/null")
if bwc then if bwc then
luci.http.write("[") luci.http.write("[")
while true do while true do
local ln = bwc:read("*l") local ln = bwc:read("*l")
if not ln then break end if not ln then break end
luci.http.write(ln) luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end end
return luci.http.write("]")
bwc:close()
end end
luci.http.status(404, "No data available")
end end
function action_connections() function action_connections()
local fs = require "luci.fs"
local sys = require "luci.sys" local sys = require "luci.sys"
luci.http.prepare_content("application/json") luci.http.prepare_content("application/json")
@ -127,20 +112,18 @@ function action_connections()
luci.http.write("{ connections: ") luci.http.write("{ connections: ")
luci.http.write_json(sys.net.conntrack()) 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")
local bwc = io.popen("luci-bwc -c 2>/dev/null") if bwc then
if bwc then luci.http.write(", statistics: [")
luci.http.write(", statistics: [")
while true do while true do
local ln = bwc:read("*l") local ln = bwc:read("*l")
if not ln then break end if not ln then break end
luci.http.write(ln) luci.http.write(ln)
end
luci.http.write("]")
bwc:close()
end end
luci.http.write("]")
bwc:close()
end end
luci.http.write(" }") luci.http.write(" }")

View file

@ -1,14 +0,0 @@
#!/bin/sh /etc/rc.common
START=95
STOP=95
BWC=/usr/bin/luci-bwc
start() {
$BWC -d
}
stop() {
killall ${BWC##*/}
}

View file

@ -25,6 +25,7 @@
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/mman.h> #include <sys/mman.h>
@ -33,6 +34,9 @@
#define STEP_COUNT 60 #define STEP_COUNT 60
#define STEP_TIME 1 #define STEP_TIME 1
#define TIMEOUT 10
#define PID_PATH "/var/run/luci-bwc.pid"
#define DB_PATH "/var/lib/luci-bwc" #define DB_PATH "/var/lib/luci-bwc"
#define DB_IF_FILE DB_PATH "/if/%s" #define DB_IF_FILE DB_PATH "/if/%s"
@ -90,6 +94,53 @@ static uint64_t htonll(uint64_t value)
#define ntohll htonll #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) static int init_directory(char *path)
{ {
@ -135,6 +186,11 @@ static int init_file(char *path, int esize)
return -1; 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) static int update_file(const char *path, void *entry, int esize)
{ {
int rv = -1; int rv = -1;
@ -148,8 +204,11 @@ static int update_file(const char *path, void *entry, int esize)
if ((map != NULL) && (map != MAP_FAILED)) if ((map != NULL) && (map != MAP_FAILED))
{ {
memmove(map, map + esize, esize * (STEP_COUNT-1)); if (timeof(entry) > timeof(map + esize * (STEP_COUNT-1)))
memcpy(map + esize * (STEP_COUNT-1), entry, esize); {
memmove(map, map + esize, esize * (STEP_COUNT-1));
memcpy(map + esize * (STEP_COUNT-1), entry, esize);
}
munmap(map, esize * STEP_COUNT); 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)); return update_file(path, &e, sizeof(struct load_entry));
} }
static int run_daemon(int nofork) static int run_daemon(char *progname)
{ {
FILE *info; FILE *info;
uint64_t rxb, txb, rxp, txp; uint64_t rxb, txb, rxp, txp;
@ -286,39 +345,53 @@ static int run_daemon(int nofork)
char line[1024]; char line[1024];
char ifname[16]; char ifname[16];
struct sigaction sa;
struct stat s; struct stat s;
const char *ipc = stat("/proc/net/nf_conntrack", &s) const char *ipc = stat("/proc/net/nf_conntrack", &s)
? "/proc/net/ip_conntrack" : "/proc/net/nf_conntrack"; ? "/proc/net/ip_conntrack" : "/proc/net/nf_conntrack";
if (!nofork) switch (fork())
{ {
switch (fork()) case -1:
{ perror("fork()");
case -1: return -1;
perror("fork()");
return -1;
case 0: case 0:
if (chdir("/") < 0) if (chdir("/") < 0)
{ {
perror("chdir()"); perror("chdir()");
exit(1); exit(1);
} }
close(0); close(0);
close(1); close(1);
close(2); close(2);
break; break;
default: default:
exit(0); 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 */ /* 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) if ((info = fopen("/proc/net/dev", "r")) != NULL)
{ {
while (fgets(line, sizeof(line), info)) while (fgets(line, sizeof(line), info))
@ -377,9 +450,38 @@ static int run_daemon(int nofork)
sleep(STEP_TIME); sleep(STEP_TIME);
} }
unlink(PID_PATH);
return 0;
} }
static int run_dump_ifname(const char *ifname) 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(char *progname, const char *ifname)
{ {
int i; int i;
char path[1024]; char path[1024];
@ -388,6 +490,11 @@ static int run_dump_ifname(const char *ifname)
snprintf(path, sizeof(path), DB_IF_FILE, ifname); snprintf(path, sizeof(path), DB_IF_FILE, ifname);
if (check_daemon(progname))
{
return 1;
}
if (mmap_file(path, sizeof(struct traffic_entry), &m)) if (mmap_file(path, sizeof(struct traffic_entry), &m))
{ {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); 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; return 0;
} }
static int run_dump_conns(void) static int run_dump_conns(char *progname)
{ {
int i; int i;
char path[1024]; char path[1024];
@ -423,6 +530,11 @@ static int run_dump_conns(void)
snprintf(path, sizeof(path), DB_CN_FILE); snprintf(path, sizeof(path), DB_CN_FILE);
if (check_daemon(progname))
{
return 1;
}
if (mmap_file(path, sizeof(struct conn_entry), &m)) if (mmap_file(path, sizeof(struct conn_entry), &m))
{ {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno));
@ -447,7 +559,7 @@ static int run_dump_conns(void)
return 0; return 0;
} }
static int run_dump_load(void) static int run_dump_load(char *progname)
{ {
int i; int i;
char path[1024]; char path[1024];
@ -456,6 +568,11 @@ static int run_dump_load(void)
snprintf(path, sizeof(path), DB_LD_FILE); snprintf(path, sizeof(path), DB_LD_FILE);
if (check_daemon(progname))
{
return 1;
}
if (mmap_file(path, sizeof(struct load_entry), &m)) if (mmap_file(path, sizeof(struct load_entry), &m))
{ {
fprintf(stderr, "Failed to open %s: %s\n", path, strerror(errno)); 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 main(int argc, char *argv[])
{ {
int opt; 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) switch (opt)
{ {
case 'd': case 't':
daemon = 1; timeout = atoi(optarg);
break;
case 'f':
nofork = 1;
break; break;
case 'i': case 'i':
if (optarg) if (optarg)
return run_dump_ifname(optarg); return run_dump_ifname(argv[0], optarg);
break; break;
case 'c': case 'c':
return run_dump_conns(); return run_dump_conns(argv[0]);
case 'l': case 'l':
return run_dump_load(); return run_dump_load(argv[0]);
default: default:
break; break;
} }
} }
if (daemon) fprintf(stderr,
return run_daemon(nofork); "Usage:\n"
" %s [-t timeout] -i ifname\n"
else " %s [-t timeout] -c\n"
fprintf(stderr, " %s [-t timeout] -l\n",
"Usage:\n" argv[0], argv[0], argv[0]
" %s -d [-f]\n" );
" %s -i ifname\n"
" %s -c\n"
" %s -l\n",
argv[0], argv[0], argv[0], argv[0]
);
return 1; return 1;
} }