summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2009-04-29 15:11:56 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2009-04-29 15:11:56 (GMT)
commit5a1f674eecba607ffa328484ca34c598690ff8d2 (patch) (side-by-side diff)
tree5dcda78e8352461d2ee7fdc29c64a265024cb219
parent20d7f1d7e051c6b021a3f5d088985a74c3370b29 (diff)
downloadtagr-5a1f674eecba607ffa328484ca34c598690ff8d2.tar.gz
tagr-5a1f674eecba607ffa328484ca34c598690ff8d2.tar.bz2
Fix locking issues. Improve stream interface.
* gnulib.modules: Add c-type, c-strcase, crypto/md5, xgetdomainname, xgethostname. * src/Makefile.am (tagr_SOURCES): Add apop.c, udb.c, xhostname.c * src/graph.c (draw_graph): Rename `now' to `start'. * src/main.c (hostname, rebuild_last_option): New globals. (main): Init hostname. * src/output.c (update_output): Change semantics of the last parameter. * src/readconfig.c (cb_facility): Use c_strcasecmp. (tagr_kw): New keywords: hostname, udb-file, lock-count, lock-timeout, idle-timeout. * src/report.c: Fix locking issues. (update_monitor): Change semantics of the last parameter. (rebuild): Likewise. * src/server.c: Rewrite stream interface. * src/tagr.h (TAGR_ARG_UNUSED, TAGR_PRINTFLIKE): New macros. (lock_retry_count_option, lock_retry_timeout_option) (stream_idle_timeout, hostname): New declarations. (TAGR_UPD_FORCE, TAGR_UPD_LASTTIME): New defines. (trim_crlf, tagr_local_hostnamem tagr_auth_init, tagr_auth) (tagr_udb_name) (udb_get_passwordudb_free_password): New declarations. * TODO: Update
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--TODO9
-rw-r--r--gnulib.modules5
-rw-r--r--src/Makefile.am5
-rw-r--r--src/apop.c84
-rw-r--r--src/graph.c17
-rw-r--r--src/main.c19
-rw-r--r--src/output.c11
-rw-r--r--src/readconfig.c23
-rw-r--r--src/report.c37
-rw-r--r--src/server.c193
-rw-r--r--src/tagr.h41
-rw-r--r--src/udb.c90
-rw-r--r--src/xhostname.c56
13 files changed, 499 insertions, 91 deletions
diff --git a/TODO b/TODO
index b2edd7c..b17d5e1 100644
--- a/TODO
+++ b/TODO
@@ -1,11 +1,16 @@
-Tagr TODO list. 2009-04-28
+Tagr TODO list. 2009-04-29
Copyright (C) 2009 Sergey Poznyakoff
* Stream-based protocol
-S: +OK tagr ready
+Currently implemented are:
+
+S: +OK <msgid>
+C: AUTH name digest
+S: +OK
C: SAMPLE id 1240903636 12345 3456
S: +OK accepted
+...
C: QUIT
S: +OK bye
diff --git a/gnulib.modules b/gnulib.modules
index d4887b3..0a23f34 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -2,6 +2,9 @@
# A module name per line. Empty lines and comments are ignored.
argp
+c-ctype
+c-strcase
+crypto/md5
fprintftime
getline
gitlog-to-changelog
@@ -17,3 +20,5 @@ realloc
version-etc
xalloc
xalloc-die
+xgetdomainname
+xgethostname \ No newline at end of file
diff --git a/src/Makefile.am b/src/Makefile.am
index 0db1eb6..996c541 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,6 +17,7 @@
sbin_PROGRAMS=tagr
tagr_SOURCES=\
+ apop.c\
graph.c\
grid.c\
html.gram.y\
@@ -30,7 +31,9 @@ tagr_SOURCES=\
report.h\
server.c\
stat.c\
- tagr.h
+ tagr.h\
+ udb.c\
+ xhostname.c
noinst_HEADERS=html.gram.h
diff --git a/src/apop.c b/src/apop.c
new file mode 100644
index 0000000..ce423a5
--- a/dev/null
+++ b/src/apop.c
@@ -0,0 +1,84 @@
+/* This file is part of tagr.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <tagr.h>
+
+#include <md5.h>
+
+static char *msg_id;
+
+const char *
+tagr_auth_init ()
+{
+ asprintf (&msg_id, "<%lu.%lu@%s>",
+ (unsigned long) getpid (),
+ (unsigned long) time (NULL),
+ hostname);
+ return msg_id;
+}
+
+static int
+verify_apop (const char *password, const char *user_digest)
+{
+ int i;
+ struct md5_ctx md5context;
+ unsigned char md5digest[16];
+ char buf[sizeof (md5digest) * 2 + 1];
+ char *p;
+
+ md5_init_ctx (&md5context);
+ md5_process_bytes (msg_id, strlen (msg_id), &md5context);
+ md5_process_bytes (password, strlen (password), &md5context);
+ md5_finish_ctx (&md5context, md5digest);
+
+ for (i = 0, p = buf; i < 16; i++, p += 2)
+ sprintf (p, "%02x", md5digest[i]);
+ return strcmp (user_digest, buf);
+}
+
+int
+tagr_auth (const char *username, const char *authstr)
+{
+ int rc = 1;
+ char *password;
+
+ rc = udb_get_password (username, &password);
+ if (rc == 1)
+ {
+ logmsg (L_ERR, _("no such user `%s'"), username);
+ }
+ else if (rc == 0)
+ {
+ rc = verify_apop (password, authstr);
+ if (rc)
+ logmsg (L_ERR, _("authentication failed for `%s'"),
+ username);
+ else
+ verbose (1, _("%s authenticated"), username);
+ udb_free_password (password);
+ }
+ return rc;
+}
+
diff --git a/src/graph.c b/src/graph.c
index 1197a7d..02e0586 100644
--- a/src/graph.c
+++ b/src/graph.c
@@ -73,7 +73,7 @@ draw_vtext (gdImagePtr graph, int color, const char *text)
int
draw_graph (FILE *fp,
struct monitor *mon,
- queue_t *dataq, const struct avg_acc *avg, time_t now,
+ queue_t *dataq, const struct avg_acc *avg, time_t start,
int xstep, unsigned long xmax,
int growright,
struct grid_class *xgrid, struct grid_class *ygrid)
@@ -90,7 +90,6 @@ draw_graph (FILE *fp,
int full_ysize = graph_ysize + graph_v_margin[0] + graph_v_margin[1];
grid_t grid;
unsigned long ymax = mon->max_rate;
- time_t start;
yscale = (double) graph_ysize / ymax;
xscale = (double) graph_xsize / xmax;
@@ -143,13 +142,13 @@ draw_graph (FILE *fp,
n = queue_count (dataq);
/* Incoming traffic */
- for (i = n - 1, start = 0; i > 0; i--)
+ for (i = n - 1; i > 0; i--)
{
struct traffic_history th, tnext;
scale_sample (mon, queue_get_ptr (dataq, i), &th);
- if (start == 0)
- start = th.time;
+ if (th.time > start)
+ continue;
scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext);
if (start - tnext.time > xmax)
break;
@@ -172,13 +171,13 @@ draw_graph (FILE *fp,
/* Outgoing traffic */
gdImageSetBrush (graph, brush_out);
- for (i = n - 1, start = 0; i > 0; i--)
+ for (i = n - 1; i > 0; i--)
{
struct traffic_history th, tnext;
scale_sample (mon, queue_get_ptr (dataq, i), &th);
- if (start == 0)
- start = th.time;
+ if (th.time > start)
+ continue;
scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext);
if (start - tnext.time > xmax)
break;
@@ -245,7 +244,7 @@ draw_graph (FILE *fp,
grid_destroy (grid);
}
- grid = grid_create (xgrid, dataq, 0, xmax, &now);
+ grid = grid_create (xgrid, dataq, 0, xmax, &start);
if (grid)
{
unsigned long i;
diff --git a/src/main.c b/src/main.c
index 181e9d2..5fcb825 100644
--- a/src/main.c
+++ b/src/main.c
@@ -57,12 +57,12 @@ char *configfile = TAGR_CONFIGFILE;
char *html_template = TAGR_TEMPLATE;
char *user;
char *basedir;
-int port;
-int sockfd;
+char *hostname;
int foreground = 0;
int single_process_option = 0;
int verbose_level;
static int rebuild_option;
+static int rebuild_last_option;
static int import_option;
static int read_option;
@@ -88,6 +88,7 @@ enum {
OPT_DUMP_LEX_TRACE,
OPT_CONFIG_HELP,
OPT_READ,
+ OPT_REBUILD_LAST
};
static struct argp_option options[] = {
@@ -108,6 +109,8 @@ static struct argp_option options[] = {
N_("read statistics from given FILEs or standard input") },
{"rebuild", 'b', NULL, 0,
N_("rebuild graphs using existing statistics"), GRID+1},
+ {"rebuild-last", OPT_REBUILD_LAST, NULL, 0,
+ N_("same as --rebuild, but refer to the last stored sample"), GRID+1},
{"list", 'l', NULL, 0, N_("list contents of the rate database"), GRID+1},
{"show-defaults", OPT_SHOW_DEFAULTS, NULL, 0,
N_("Show configuration default values"), GRID+1},
@@ -276,6 +279,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
case OPT_READ:
read_option = 1;
break;
+
+ case OPT_REBUILD_LAST:
+ rebuild_option = 1;
+ rebuild_last_option = 1;
+ break;
case OPT_NO_PREPROCESSOR:
grecs_preprocessor = NULL;
@@ -668,7 +676,7 @@ main (int argc, char **argv)
save_argv = argv;
argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
argp_program_version_hook = tagr_version;
-
+
if (!isatty (2))
{
log_to_stderr = 0;
@@ -682,6 +690,8 @@ main (int argc, char **argv)
html_template = html_template_option;
if (user_option)
user = user_option;
+ if (!hostname)
+ hostname = tagr_local_hostname ();
argc -= index;
argv += index;
@@ -742,7 +752,8 @@ main (int argc, char **argv)
}
if (rebuild_option)
- rebuild (1);
+ rebuild (TAGR_UPD_FORCE
+ | (rebuild_last_option ? TAGR_UPD_LASTTIME : 0));
if (list_option)
list_db ();
diff --git a/src/output.c b/src/output.c
index 4b6e206..e2e8b92 100644
--- a/src/output.c
+++ b/src/output.c
@@ -177,7 +177,8 @@ do_update_output (struct monitor *mon, struct image_descr *dscr,
else
{
rc = draw_graph (fp, mon, queue, avg, timestamp, dscr->step,
- dscr->step*460 /* FIXME: must be queue->size * step */,
+ dscr->step*460
+ /*^ FIXME: must be queue->size * step */,
0, dscr->xgrid, dscr->ygrid);
fclose (fp);
}
@@ -236,7 +237,7 @@ format_timestamp (FILE *fp, union value v, const char *fmt, int prec)
int
update_output (struct monitor *mon, struct traffic_record *tr,
- time_t timestamp, int force_update)
+ time_t timestamp, int flags)
{
char *dirname = mkfilename (basedir, mon->dir, NULL);
int rc;
@@ -245,13 +246,17 @@ update_output (struct monitor *mon, struct traffic_record *tr,
char *tabfile = mkfilename (dirname, mon->name, ".tab");
char *htmlname;
pp_value_t *p;
-
+ int force_update = flags & TAGR_UPD_FORCE;
+
if (!force_update)
{
if (read_symtab (&tab, tabfile))
force_update = 1;
}
+ if (flags & TAGR_UPD_LASTTIME)
+ timestamp = tr->last.time;
+
rc = do_update_output (mon, &img_day,
&tr->day_hist, NULL, &tab,
timestamp, dirname, 1);
diff --git a/src/readconfig.c b/src/readconfig.c
index e75cae4..a514691 100644
--- a/src/readconfig.c
+++ b/src/readconfig.c
@@ -26,6 +26,7 @@
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
#include <obstack.h>
+#include <c-strcase.h>
#include <tagr.h>
#define ARG_UNUSED __attribute__ ((__unused__))
@@ -333,7 +334,7 @@ cb_facility (enum grecs_callback_command cmd,
str += 4;
for (i = 0; xlat_tab[i].name; i++)
- if (strcasecmp (str, xlat_tab[i].name) == 0)
+ if (c_strcasecmp (str, xlat_tab[i].name) == 0)
{
*iptr = xlat_tab[i].facility;
return 0;
@@ -455,7 +456,11 @@ static struct grecs_keyword tagr_kw[] = {
grecs_type_string, &html_template },
{ "pidfile", NULL, N_("Set pid file name"),
grecs_type_string, &pidfile },
-
+ { "hostname", NULL, N_("Set host name"),
+ grecs_type_string, &hostname },
+ { "udb-file", N_("name"), N_("Name of the user database file"),
+ grecs_type_string, &tagr_udb_name },
+
{ "server", N_("id: string"), N_("Configure server"),
grecs_type_section, NULL, 0,
cb_server, NULL, server_kw },
@@ -470,6 +475,17 @@ static struct grecs_keyword tagr_kw[] = {
{ "log", NULL, N_("Configure logging"),
grecs_type_section, NULL, 0,
NULL, NULL, log_kw },
+
+ { "lock-count", NULL,
+ N_("Set maximum number of attempts to acquire the lock on a database"),
+ grecs_type_uint, &lock_retry_count_option },
+ { "lock-timeout", N_("seconds"),
+ N_("Set the time span between the two locking attempts"),
+ grecs_type_uint, &lock_retry_timeout_option },
+
+ { "idle-timeout", N_("seconds"),
+ N_("Idle timeout for stream connections"),
+ grecs_type_uint, &stream_idle_timeout },
{ "rate-units", NULL, N_("Name of rate units"),
grecs_type_string, &rate_unit },
@@ -512,8 +528,7 @@ static struct grecs_keyword tagr_kw[] = {
grecs_type_int, color_in_max, 0, cb_color },
{ "color-out-max", NULL, N_("Not implemented") /* FIXME */,
grecs_type_int, color_out_max, 0, cb_color },
-
- /* FIXME */
+
{ NULL }
};
diff --git a/src/report.c b/src/report.c
index 71a735f..ab4cada 100644
--- a/src/report.c
+++ b/src/report.c
@@ -33,6 +33,9 @@
#include <fprintftime.h>
#include <gdbm.h>
+unsigned lock_retry_count_option = 5;
+unsigned lock_retry_timeout_option = 1;
+
static char *dbname;
static GDBM_FILE dbf;
@@ -45,13 +48,20 @@ tagr_db_report (char *str)
int
open_db (int flag)
{
- dbname = xmalloc (strlen (basedir) + 1 + sizeof (TAGR_DBNAME));
- strcpy (dbname, basedir);
- strcat (dbname, "/");
- strcat (dbname, TAGR_DBNAME);
- dbf = gdbm_open (dbname, 0,
- flag == TAGR_DB_WR ? GDBM_WRCREAT : GDBM_READER,
- TAGR_DBMODE, tagr_db_report);
+ unsigned i;
+
+ dbname = mkfilename (basedir, TAGR_DBNAME, NULL);
+
+ for (i = 0; i < lock_retry_count_option; i++)
+ {
+ dbf = gdbm_open (dbname, 0,
+ flag == TAGR_DB_WR ? GDBM_WRCREAT : GDBM_READER,
+ TAGR_DBMODE, tagr_db_report);
+ if (dbf || errno != EAGAIN)
+ break;
+ sleep (lock_retry_timeout_option);
+ }
+
if (dbf == NULL)
{
logmsg (L_ERR, _("cannot open database %s: %s"),
@@ -251,7 +261,7 @@ report (Stat *stat, time_t timestamp)
}
int
-update_monitor (datum key, time_t timestamp, int force)
+update_monitor (datum key, time_t timestamp, int flags)
{
char id[MAX_NAME_LENGTH+1];
struct traffic_record *tr = NULL;
@@ -273,8 +283,7 @@ update_monitor (datum key, time_t timestamp, int force)
_read_db (key, &tr);
if (tr)
{
- update_output (mon, tr, tr->last.time /*FIXME: must be now? */,
- force);
+ update_output (mon, tr, timestamp, flags);
free (tr);
}
@@ -282,20 +291,20 @@ update_monitor (datum key, time_t timestamp, int force)
}
void
-rebuild (int force)
+rebuild (int flags)
{
datum key;
datum content;
time_t now = time (NULL);
-
+
verbose (1, _("rebuild initiated"));
if (open_db (TAGR_DB_RD) == 0)
{
key = gdbm_firstkey (dbf);
while (key.dptr)
{
- datum nextkey = gdbm_nextkey ( dbf, key );
- update_monitor (key, now, force);
+ datum nextkey = gdbm_nextkey (dbf, key);
+ update_monitor (key, now, flags);
free (key.dptr);
key = nextkey;
}
diff --git a/src/server.c b/src/server.c
index 82aae0e..e514f37 100644
--- a/src/server.c
+++ b/src/server.c
@@ -37,8 +37,11 @@
#include <tagr.h>
#include <report.h>
#include <inttypes.h>
+#include <c-strcase.h>
#include <wordsplit.h>
+unsigned stream_idle_timeout = 10;
+
struct tagr_server
{
struct tagr_server *next;
@@ -48,7 +51,7 @@ struct tagr_server
struct grecs_sockaddr addr;
};
-struct tagr_server *server_head, *server_tail;
+static struct tagr_server *server_head, *server_tail;
struct server_class
{
@@ -194,8 +197,9 @@ subprocess (void (*fun) (void *data), void *data, int fd)
logmsg (L_ERR, _("cannot fork: %s"), strerror (errno));
else
{
- signal (SIGHUP, SIG_IGN);
- signal (SIGCHLD, SIG_IGN);
+ signal (SIGHUP, SIG_DFL);
+ signal (SIGCHLD, SIG_DFL);
+ signal (SIGALRM, SIG_DFL);
child = 1;
if (fd != -1)
close (fd);
@@ -302,7 +306,7 @@ tcp_open (struct tagr_server *srv)
return 0;
}
-static void
+void
trim_crlf (char *buf)
{
size_t len = strlen (buf);
@@ -344,75 +348,166 @@ convert_ulong (const char *str, unsigned long *pt)
return 0;
}
+static RETSIGTYPE
+sig_child_alrm (int sig)
+{
+ logmsg (L_NOTICE, _("child timed out"));
+ exit (EX_TEMPFAIL);
+}
+
+enum tagr_dialog_state
+ {
+ initial_dialog_state,
+ auth_dialog_state,
+ quit_dialog_state
+ };
+
+struct tagr_dialog
+{
+ enum tagr_dialog_state state;
+ FILE *in;
+ FILE *out;
+};
+
+#define STATEMASK(n) (1u<<(n))
+#define ANYSTATE ((unsigned)~0)
+
+struct command
+{
+ const char *name;
+ unsigned statemask;
+ int minargs;
+ int maxargs;
+ void (*handler) (struct tagr_dialog *, struct command *,
+ struct wordsplit *);
+};
+
+static void
+cmd_auth (struct tagr_dialog *dlg, struct command *cmd,
+ struct wordsplit *ws)
+{
+ if (tagr_auth (ws->ws_wordv[1], ws->ws_wordv[2]) == 0)
+ {
+ dlg->state = auth_dialog_state;
+ fprintf (dlg->out, "+OK welcome, %s\r\n", ws->ws_wordv[1]);
+ }
+ else
+ fprintf (dlg->out, "-ERR authorization failed\r\n");
+}
+
+static void
+cmd_sample (struct tagr_dialog *dlg, struct command *cmd,
+ struct wordsplit *ws)
+{
+ Stat st;
+ time_t t;
+
+ if (strlen (ws->ws_wordv[1]) > MAX_NAME_LENGTH)
+ {
+ fprintf (dlg->out, "-ERR id too long\r\n");
+ return;
+ }
+
+ strcpy (st.name, ws->ws_wordv[1]);
+ if (convert_ts (ws->ws_wordv[2], &t)
+ || convert_ulong (ws->ws_wordv[3], &st.in)
+ || convert_ulong (ws->ws_wordv[4], &st.out))
+ {
+ fprintf (dlg->out, "-ERR invalid input\r\n");
+ return;
+ }
+
+ if (open_db (TAGR_DB_WR))
+ fprintf (dlg->out, "-TEMP database not available\r\n");
+ else
+ {
+ report (&st, t);
+ close_db ();
+ fprintf (dlg->out, "+OK thank you\r\n");
+ }
+}
+
+static void
+cmd_quit (struct tagr_dialog *dlg, struct command *cmd,
+ struct wordsplit *ws)
+{
+ dlg->state = quit_dialog_state;
+ fprintf (dlg->out, "+OK bye\r\n");
+}
+
+static struct command command_tab[] = {
+ { "AUTH", STATEMASK (initial_dialog_state), 3, 3, cmd_auth },
+ { "SAMPLE", STATEMASK (auth_dialog_state), 5, 5, cmd_sample },
+ { "QUIT", ANYSTATE, 1, 1, cmd_quit },
+ { NULL }
+};
+
+static struct command *
+find_command (const char *name)
+{
+ struct command *cmd;
+
+ for (cmd = command_tab; cmd->name; cmd++)
+ if (c_strcasecmp (cmd->name, name) == 0)
+ return cmd;
+ return NULL;
+}
+
+
static void
tcp_server_loop (void *data)
{
int fd = *(int*)data;
- FILE *in = fdopen (fd, "r");
- FILE *out = fdopen (fd, "w");
+ struct tagr_dialog dlg;
size_t bufsize = 0;
char *buf = NULL;
- int quit = 0;
-
- setvbuf (in, NULL, _IOLBF, 0);
- setvbuf (out, NULL, _IOLBF, 0);
+ const char *authid;
+
+ signal (SIGALRM, sig_child_alrm);
- fprintf (out, "+OK tagr experimental stream service\r\n");
- while (!quit && getline (&buf, &bufsize, in) > 0)
+ dlg.state = initial_dialog_state;
+ dlg.in = fdopen (fd, "r");
+ dlg.out = fdopen (fd, "w");
+ setvbuf (dlg.in, NULL, _IOLBF, 0);
+ setvbuf (dlg.out, NULL, _IOLBF, 0);
+
+ authid = tagr_auth_init ();
+ fprintf (dlg.out, "+OK tagr experimental stream service %s\r\n", authid);
+ while (dlg.state != quit_dialog_state
+ && getline (&buf, &bufsize, dlg.in) > 0)
{
struct wordsplit ws;
-
+ struct command *cmd;
+
+ alarm (stream_idle_timeout);
trim_crlf (buf);
if (wordsplit (buf, &ws, WRDSF_DEFFLAGS))
{
- logmsg (L_ERR, "failed to parse input line");
- fprintf (out, "-ERR parsing failed\r\n");
+ logmsg (L_ERR, _("failed to parse input line"));
+ fprintf (dlg.out, "-ERR parsing failed\r\n");
continue;
}
if (ws.ws_wordc == 0)
- fprintf (out, "-ERR invalid input\r\n");
- else if (strcasecmp (ws.ws_wordv[0], "SAMPLE") == 0
- && ws.ws_wordc == 5)
+ fprintf (dlg.out, "-ERR invalid input\r\n");
+ else if (cmd = find_command (ws.ws_wordv[0]))
{
- Stat st;
- time_t t;
-
- if (strlen (ws.ws_wordv[1]) > MAX_NAME_LENGTH)
- fprintf (out, "-ERR id too long\r\n");
+ if (!(STATEMASK (dlg.state) & cmd->statemask))
+ fprintf (dlg.out, "-ERR wrong state\r\n");
+ else if (ws.ws_wordc < cmd->minargs
+ || (cmd->maxargs > 0 && ws.ws_wordc > cmd->maxargs))
+ fprintf (dlg.out, "-ERR invalid number of arguments\r\n");
else
- {
- strcpy (st.name, ws.ws_wordv[1]);
- if (convert_ts (ws.ws_wordv[2], &t)
- || convert_ulong (ws.ws_wordv[3], &st.in)
- || convert_ulong (ws.ws_wordv[4], &st.out))
- fprintf (out, "-ERR invalid input\r\n");
- else
- {
- if (open_db (TAGR_DB_WR))
- fprintf (out, "-ERR database not available\r\n");
- else
- {
- report (&st, t);
- close_db ();
- fprintf (out, "+OK thank you\r\n");
- }
- }
- }
- }
- else if (strcasecmp (ws.ws_wordv[0], "QUIT") == 0)
- {
- quit = 1;
- fprintf (out, "+OK bye\r\n");
+ cmd->handler (&dlg, cmd, &ws);
}
else
- fprintf (out, "-ERR invalid input\r\n");
+ fprintf (dlg.out, "-ERR invalid input\r\n");
wordsplit_free (&ws);
}
free (buf);
- fclose (in);
- fclose (out);
+ fclose (dlg.in);
+ fclose (dlg.out);
close (fd);
}
diff --git a/src/tagr.h b/src/tagr.h
index f95a249..f32b014 100644
--- a/src/tagr.h
+++ b/src/tagr.h
@@ -20,6 +20,15 @@
#include <sysexits.h>
#include <grecs.h>
+#ifndef TAGR_ARG_UNUSED
+# define TAGR_ARG_UNUSED __attribute__ ((__unused__))
+#endif
+
+#ifndef TAGR_PRINTFLIKE
+# define TAGR_PRINTFLIKE(fmt,narg) \
+ __attribute__ ((__format__ (__printf__, fmt, narg)))
+#endif
+
#define TAGR_CONFIGFILE SYSCONFDIR "/tagr.conf"
#define TAGR_TEMPLATE SYSCONFDIR "/tagr.tmpl"
#define TAGR_PIDFILE "/var/run/tagr.pid"
@@ -51,6 +60,13 @@ extern unsigned update_interval;
extern int single_process_option;
extern double cut_out_fraction;
+extern unsigned lock_retry_count_option;
+extern unsigned lock_retry_timeout_option;
+
+extern unsigned stream_idle_timeout;
+
+extern char *hostname;
+
extern char *user;
extern char *basedir;
extern char *configfile;
@@ -143,9 +159,9 @@ extern int log_print_severity;
#define L_CRIT 5
void init_syslog (char *tag);
-void logmsg (int level, const char *fmt, ...);
-void die (int code, const char *fmt, ...);
-void verbose (int level, const char *fmt, ...);
+void logmsg (int level, const char *fmt, ...) TAGR_PRINTFLIKE(2,3);
+void die (int code, const char *fmt, ...) TAGR_PRINTFLIKE(2,3);
+void verbose (int level, const char *fmt, ...) TAGR_PRINTFLIKE(2,3);
@@ -218,9 +234,13 @@ void close_db ();
void read_db (struct monitor *mon, struct traffic_record **tr);
void write_db (struct monitor *mon, struct traffic_record *tr);
void list_db (void);
-void rebuild (int force);
void tr_init (struct traffic_record *tr);
+#define TAGR_UPD_FORCE 0x0001
+#define TAGR_UPD_LASTTIME 0x0002
+
+void rebuild (int flags);
+
/* stat.c */
void update_stats (struct monitor *mon, struct traffic_sample *sample,
struct traffic_record *tr);
@@ -242,7 +262,7 @@ void scale_sample (struct monitor *mon,
const struct traffic_history *in,
struct traffic_history *out);
int update_output (struct monitor *mon, struct traffic_record *tr,
- time_t timestamp, int force);
+ time_t timestamp, int flags);
/* graph.c */
@@ -288,7 +308,18 @@ void open_servers (void);
void close_servers (void);
void server_loop (void);
+void trim_crlf (char *buf);
+
int tagr_idle (void);
+
+char *tagr_local_hostname (void);
+const char *tagr_auth_init (void);
+int tagr_auth (const char *username, const char *authstr);
+
+/* udb.c */
+extern char *tagr_udb_name;
+int udb_get_password (const char *username, char **password);
+void udb_free_password (char *pass);
diff --git a/src/udb.c b/src/udb.c
new file mode 100644
index 0000000..aad5982
--- a/dev/null
+++ b/src/udb.c
@@ -0,0 +1,90 @@
+/* This file is part of tagr.
+ Copyright (C) 2009 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <wordsplit.h>
+#include <tagr.h>
+
+char *tagr_udb_name = SYSCONFDIR "/tagr.udb";
+
+int
+udb_get_password (const char *username, char **password)
+{
+ FILE *fp;
+ size_t bufsize = 0;
+ char *buf = NULL;
+ unsigned line = 0;
+ int rc = 1;
+
+ fp = fopen (tagr_udb_name, "r");
+ if (!fp)
+ {
+ logmsg (L_ERR, _("cannot open file %s: %s"),
+ tagr_udb_name, strerror (errno));
+ return -1;
+ }
+
+ while (rc == 1 && getline (&buf, &bufsize, fp) > 0)
+ {
+ struct wordsplit ws;
+
+ line++;
+ trim_crlf (buf);
+ if (wordsplit (buf, &ws, WRDSF_DEFFLAGS))
+ {
+ logmsg (L_ERR, _("%s:%u: failed to parse input line"),
+ tagr_udb_name, line);
+ }
+ if (ws.ws_wordc == 0 || ws.ws_wordv[0][0] == '#')
+ /* next */;
+ else if (ws.ws_wordc < 2)
+ {
+ logmsg (L_WARNING, _("%s:%u: too few words on line"),
+ tagr_udb_name, line);
+ }
+ else if (ws.ws_wordc > 2)
+ {
+ logmsg (L_WARNING, _("%s:%u: too many words on line"),
+ tagr_udb_name, line);
+ }
+ else if (strcmp (ws.ws_wordv[0], username) == 0)
+ {
+ *password = xstrdup (ws.ws_wordv[1]);
+ rc = 0;
+ }
+ wordsplit_free (&ws);
+ }
+
+ free (buf);
+ fclose (fp);
+ return rc;
+}
+
+void
+udb_free_password (char *pass)
+{
+ char *p;
+ for (p = pass; *p; p++)
+ *p = 0;
+ free (pass);
+}
diff --git a/src/xhostname.c b/src/xhostname.c
new file mode 100644
index 0000000..8ffd499
--- a/dev/null
+++ b/src/xhostname.c
@@ -0,0 +1,56 @@
+/* This file is part of tagr.
+ Copyright (C) 2009 Max Bouglacoff, Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include <xalloc.h>
+#include <xgethostname.h>
+#include <xgetdomainname.h>
+
+char *
+tagr_local_hostname ()
+{
+ struct hostent *hp;
+ char *hostpart = xgethostname ();
+ char *ret;
+
+ hp = gethostbyname (hostpart);
+ if (hp)
+ ret = xstrdup (hp->h_name);
+ else
+ {
+ char *domainpart = xgetdomainname ();
+
+ if (domainpart && domainpart[0] && strcmp(domainpart, "(none)"))
+ {
+ ret = xmalloc(strlen( hostpart) + 1
+ + strlen (domainpart) + 1);
+ strcpy(ret, hostpart);
+ strcat(ret, ".");
+ strcat(ret, domainpart);
+ free (hostpart);
+ }
+ else
+ ret = hostpart;
+ free (domainpart);
+ }
+ return ret;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.