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) (unidiff)
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 @@
1Tagr TODO list. 2009-04-28 1Tagr TODO list. 2009-04-29
2Copyright (C) 2009 Sergey Poznyakoff 2Copyright (C) 2009 Sergey Poznyakoff
3 3
4* Stream-based protocol 4* Stream-based protocol
5 5
6S: +OK tagr ready 6Currently implemented are:
7
8S: +OK <msgid>
9C: AUTH name digest
10S: +OK
7C: SAMPLE id 1240903636 12345 3456 11C: SAMPLE id 1240903636 12345 3456
8S: +OK accepted 12S: +OK accepted
13...
9C: QUIT 14C: QUIT
10S: +OK bye 15S: +OK bye
11 16
diff --git a/gnulib.modules b/gnulib.modules
index d4887b3..0a23f34 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -2,6 +2,9 @@
2# A module name per line. Empty lines and comments are ignored. 2# A module name per line. Empty lines and comments are ignored.
3 3
4argp 4argp
5c-ctype
6c-strcase
7crypto/md5
5fprintftime 8fprintftime
6getline 9getline
7gitlog-to-changelog 10gitlog-to-changelog
@@ -17,3 +20,5 @@ realloc
17version-etc 20version-etc
18xalloc 21xalloc
19xalloc-die 22xalloc-die
23xgetdomainname
24xgethostname \ 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 @@
17sbin_PROGRAMS=tagr 17sbin_PROGRAMS=tagr
18 18
19tagr_SOURCES=\ 19tagr_SOURCES=\
20 apop.c\
20 graph.c\ 21 graph.c\
21 grid.c\ 22 grid.c\
22 html.gram.y\ 23 html.gram.y\
@@ -30,7 +31,9 @@ tagr_SOURCES=\
30 report.h\ 31 report.h\
31 server.c\ 32 server.c\
32 stat.c\ 33 stat.c\
33 tagr.h 34 tagr.h\
35 udb.c\
36 xhostname.c
34 37
35noinst_HEADERS=html.gram.h 38noinst_HEADERS=html.gram.h
36 39
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 @@
1/* This file is part of tagr.
2 Copyright (C) 2009 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20
21#include <unistd.h>
22#include <fcntl.h>
23#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <tagr.h>
27
28#include <md5.h>
29
30static char *msg_id;
31
32const char *
33tagr_auth_init ()
34{
35 asprintf (&msg_id, "<%lu.%lu@%s>",
36 (unsigned long) getpid (),
37 (unsigned long) time (NULL),
38 hostname);
39 return msg_id;
40}
41
42static int
43verify_apop (const char *password, const char *user_digest)
44{
45 int i;
46 struct md5_ctx md5context;
47 unsigned char md5digest[16];
48 char buf[sizeof (md5digest) * 2 + 1];
49 char *p;
50
51 md5_init_ctx (&md5context);
52 md5_process_bytes (msg_id, strlen (msg_id), &md5context);
53 md5_process_bytes (password, strlen (password), &md5context);
54 md5_finish_ctx (&md5context, md5digest);
55
56 for (i = 0, p = buf; i < 16; i++, p += 2)
57 sprintf (p, "%02x", md5digest[i]);
58 return strcmp (user_digest, buf);
59}
60
61int
62tagr_auth (const char *username, const char *authstr)
63{
64 int rc = 1;
65 char *password;
66
67 rc = udb_get_password (username, &password);
68 if (rc == 1)
69 {
70 logmsg (L_ERR, _("no such user `%s'"), username);
71 }
72 else if (rc == 0)
73 {
74 rc = verify_apop (password, authstr);
75 if (rc)
76 logmsg (L_ERR, _("authentication failed for `%s'"),
77 username);
78 else
79 verbose (1, _("%s authenticated"), username);
80 udb_free_password (password);
81 }
82 return rc;
83}
84
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)
73int 73int
74draw_graph (FILE *fp, 74draw_graph (FILE *fp,
75 struct monitor *mon, 75 struct monitor *mon,
76 queue_t *dataq, const struct avg_acc *avg, time_t now, 76 queue_t *dataq, const struct avg_acc *avg, time_t start,
77 int xstep, unsigned long xmax, 77 int xstep, unsigned long xmax,
78 int growright, 78 int growright,
79 struct grid_class *xgrid, struct grid_class *ygrid) 79 struct grid_class *xgrid, struct grid_class *ygrid)
@@ -90,7 +90,6 @@ draw_graph (FILE *fp,
90 int full_ysize = graph_ysize + graph_v_margin[0] + graph_v_margin[1]; 90 int full_ysize = graph_ysize + graph_v_margin[0] + graph_v_margin[1];
91 grid_t grid; 91 grid_t grid;
92 unsigned long ymax = mon->max_rate; 92 unsigned long ymax = mon->max_rate;
93 time_t start;
94 93
95 yscale = (double) graph_ysize / ymax; 94 yscale = (double) graph_ysize / ymax;
96 xscale = (double) graph_xsize / xmax; 95 xscale = (double) graph_xsize / xmax;
@@ -143,13 +142,13 @@ draw_graph (FILE *fp,
143 n = queue_count (dataq); 142 n = queue_count (dataq);
144 143
145 /* Incoming traffic */ 144 /* Incoming traffic */
146 for (i = n - 1, start = 0; i > 0; i--) 145 for (i = n - 1; i > 0; i--)
147 { 146 {
148 struct traffic_history th, tnext; 147 struct traffic_history th, tnext;
149 148
150 scale_sample (mon, queue_get_ptr (dataq, i), &th); 149 scale_sample (mon, queue_get_ptr (dataq, i), &th);
151 if (start == 0) 150 if (th.time > start)
152 start = th.time; 151 continue;
153 scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext); 152 scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext);
154 if (start - tnext.time > xmax) 153 if (start - tnext.time > xmax)
155 break; 154 break;
@@ -172,13 +171,13 @@ draw_graph (FILE *fp,
172 171
173 /* Outgoing traffic */ 172 /* Outgoing traffic */
174 gdImageSetBrush (graph, brush_out); 173 gdImageSetBrush (graph, brush_out);
175 for (i = n - 1, start = 0; i > 0; i--) 174 for (i = n - 1; i > 0; i--)
176 { 175 {
177 struct traffic_history th, tnext; 176 struct traffic_history th, tnext;
178 177
179 scale_sample (mon, queue_get_ptr (dataq, i), &th); 178 scale_sample (mon, queue_get_ptr (dataq, i), &th);
180 if (start == 0) 179 if (th.time > start)
181 start = th.time; 180 continue;
182 scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext); 181 scale_sample (mon, queue_get_ptr (dataq, i - 1), &tnext);
183 if (start - tnext.time > xmax) 182 if (start - tnext.time > xmax)
184 break; 183 break;
@@ -245,7 +244,7 @@ draw_graph (FILE *fp,
245 grid_destroy (grid); 244 grid_destroy (grid);
246 } 245 }
247 246
248 grid = grid_create (xgrid, dataq, 0, xmax, &now); 247 grid = grid_create (xgrid, dataq, 0, xmax, &start);
249 if (grid) 248 if (grid)
250 { 249 {
251 unsigned long i; 250 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;
57char *html_template = TAGR_TEMPLATE; 57char *html_template = TAGR_TEMPLATE;
58char *user; 58char *user;
59char *basedir; 59char *basedir;
60int port; 60char *hostname;
61int sockfd;
62int foreground = 0; 61int foreground = 0;
63int single_process_option = 0; 62int single_process_option = 0;
64int verbose_level; 63int verbose_level;
65static int rebuild_option; 64static int rebuild_option;
65static int rebuild_last_option;
66 66
67static int import_option; 67static int import_option;
68static int read_option; 68static int read_option;
@@ -88,6 +88,7 @@ enum {
88 OPT_DUMP_LEX_TRACE, 88 OPT_DUMP_LEX_TRACE,
89 OPT_CONFIG_HELP, 89 OPT_CONFIG_HELP,
90 OPT_READ, 90 OPT_READ,
91 OPT_REBUILD_LAST
91}; 92};
92 93
93static struct argp_option options[] = { 94static struct argp_option options[] = {
@@ -108,6 +109,8 @@ static struct argp_option options[] = {
108 N_("read statistics from given FILEs or standard input") }, 109 N_("read statistics from given FILEs or standard input") },
109 {"rebuild", 'b', NULL, 0, 110 {"rebuild", 'b', NULL, 0,
110 N_("rebuild graphs using existing statistics"), GRID+1}, 111 N_("rebuild graphs using existing statistics"), GRID+1},
112 {"rebuild-last", OPT_REBUILD_LAST, NULL, 0,
113 N_("same as --rebuild, but refer to the last stored sample"), GRID+1},
111 {"list", 'l', NULL, 0, N_("list contents of the rate database"), GRID+1}, 114 {"list", 'l', NULL, 0, N_("list contents of the rate database"), GRID+1},
112 {"show-defaults", OPT_SHOW_DEFAULTS, NULL, 0, 115 {"show-defaults", OPT_SHOW_DEFAULTS, NULL, 0,
113 N_("Show configuration default values"), GRID+1}, 116 N_("Show configuration default values"), GRID+1},
@@ -276,6 +279,11 @@ parse_opt (int key, char *arg, struct argp_state *state)
276 case OPT_READ: 279 case OPT_READ:
277 read_option = 1; 280 read_option = 1;
278 break; 281 break;
282
283 case OPT_REBUILD_LAST:
284 rebuild_option = 1;
285 rebuild_last_option = 1;
286 break;
279 287
280 case OPT_NO_PREPROCESSOR: 288 case OPT_NO_PREPROCESSOR:
281 grecs_preprocessor = NULL; 289 grecs_preprocessor = NULL;
@@ -668,7 +676,7 @@ main (int argc, char **argv)
668 save_argv = argv; 676 save_argv = argv;
669 argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; 677 argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
670 argp_program_version_hook = tagr_version; 678 argp_program_version_hook = tagr_version;
671 679
672 if (!isatty (2)) 680 if (!isatty (2))
673 { 681 {
674 log_to_stderr = 0; 682 log_to_stderr = 0;
@@ -682,6 +690,8 @@ main (int argc, char **argv)
682 html_template = html_template_option; 690 html_template = html_template_option;
683 if (user_option) 691 if (user_option)
684 user = user_option; 692 user = user_option;
693 if (!hostname)
694 hostname = tagr_local_hostname ();
685 695
686 argc -= index; 696 argc -= index;
687 argv += index; 697 argv += index;
@@ -742,7 +752,8 @@ main (int argc, char **argv)
742 } 752 }
743 753
744 if (rebuild_option) 754 if (rebuild_option)
745 rebuild (1); 755 rebuild (TAGR_UPD_FORCE
756 | (rebuild_last_option ? TAGR_UPD_LASTTIME : 0));
746 757
747 if (list_option) 758 if (list_option)
748 list_db (); 759 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,
177 else 177 else
178 { 178 {
179 rc = draw_graph (fp, mon, queue, avg, timestamp, dscr->step, 179 rc = draw_graph (fp, mon, queue, avg, timestamp, dscr->step,
180 dscr->step*460 /* FIXME: must be queue->size * step */, 180 dscr->step*460
181 /*^ FIXME: must be queue->size * step */,
181 0, dscr->xgrid, dscr->ygrid); 182 0, dscr->xgrid, dscr->ygrid);
182 fclose (fp); 183 fclose (fp);
183 } 184 }
@@ -236,7 +237,7 @@ format_timestamp (FILE *fp, union value v, const char *fmt, int prec)
236 237
237int 238int
238update_output (struct monitor *mon, struct traffic_record *tr, 239update_output (struct monitor *mon, struct traffic_record *tr,
239 time_t timestamp, int force_update) 240 time_t timestamp, int flags)
240{ 241{
241 char *dirname = mkfilename (basedir, mon->dir, NULL); 242 char *dirname = mkfilename (basedir, mon->dir, NULL);
242 int rc; 243 int rc;
@@ -245,13 +246,17 @@ update_output (struct monitor *mon, struct traffic_record *tr,
245 char *tabfile = mkfilename (dirname, mon->name, ".tab"); 246 char *tabfile = mkfilename (dirname, mon->name, ".tab");
246 char *htmlname; 247 char *htmlname;
247 pp_value_t *p; 248 pp_value_t *p;
248 249 int force_update = flags & TAGR_UPD_FORCE;
250
249 if (!force_update) 251 if (!force_update)
250 { 252 {
251 if (read_symtab (&tab, tabfile)) 253 if (read_symtab (&tab, tabfile))
252 force_update = 1; 254 force_update = 1;
253 } 255 }
254 256
257 if (flags & TAGR_UPD_LASTTIME)
258 timestamp = tr->last.time;
259
255 rc = do_update_output (mon, &img_day, 260 rc = do_update_output (mon, &img_day,
256 &tr->day_hist, NULL, &tab, 261 &tr->day_hist, NULL, &tab,
257 timestamp, dirname, 1); 262 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 @@
26#define obstack_chunk_alloc malloc 26#define obstack_chunk_alloc malloc
27#define obstack_chunk_free free 27#define obstack_chunk_free free
28#include <obstack.h> 28#include <obstack.h>
29#include <c-strcase.h>
29#include <tagr.h> 30#include <tagr.h>
30 31
31#define ARG_UNUSED __attribute__ ((__unused__)) 32#define ARG_UNUSED __attribute__ ((__unused__))
@@ -333,7 +334,7 @@ cb_facility (enum grecs_callback_command cmd,
333 str += 4; 334 str += 4;
334 335
335 for (i = 0; xlat_tab[i].name; i++) 336 for (i = 0; xlat_tab[i].name; i++)
336 if (strcasecmp (str, xlat_tab[i].name) == 0) 337 if (c_strcasecmp (str, xlat_tab[i].name) == 0)
337 { 338 {
338 *iptr = xlat_tab[i].facility; 339 *iptr = xlat_tab[i].facility;
339 return 0; 340 return 0;
@@ -455,7 +456,11 @@ static struct grecs_keyword tagr_kw[] = {
455 grecs_type_string, &html_template }, 456 grecs_type_string, &html_template },
456 { "pidfile", NULL, N_("Set pid file name"), 457 { "pidfile", NULL, N_("Set pid file name"),
457 grecs_type_string, &pidfile }, 458 grecs_type_string, &pidfile },
458 459 { "hostname", NULL, N_("Set host name"),
460 grecs_type_string, &hostname },
461 { "udb-file", N_("name"), N_("Name of the user database file"),
462 grecs_type_string, &tagr_udb_name },
463
459 { "server", N_("id: string"), N_("Configure server"), 464 { "server", N_("id: string"), N_("Configure server"),
460 grecs_type_section, NULL, 0, 465 grecs_type_section, NULL, 0,
461 cb_server, NULL, server_kw }, 466 cb_server, NULL, server_kw },
@@ -470,6 +475,17 @@ static struct grecs_keyword tagr_kw[] = {
470 { "log", NULL, N_("Configure logging"), 475 { "log", NULL, N_("Configure logging"),
471 grecs_type_section, NULL, 0, 476 grecs_type_section, NULL, 0,
472 NULL, NULL, log_kw }, 477 NULL, NULL, log_kw },
478
479 { "lock-count", NULL,
480 N_("Set maximum number of attempts to acquire the lock on a database"),
481 grecs_type_uint, &lock_retry_count_option },
482 { "lock-timeout", N_("seconds"),
483 N_("Set the time span between the two locking attempts"),
484 grecs_type_uint, &lock_retry_timeout_option },
485
486 { "idle-timeout", N_("seconds"),
487 N_("Idle timeout for stream connections"),
488 grecs_type_uint, &stream_idle_timeout },
473 489
474 { "rate-units", NULL, N_("Name of rate units"), 490 { "rate-units", NULL, N_("Name of rate units"),
475 grecs_type_string, &rate_unit }, 491 grecs_type_string, &rate_unit },
@@ -512,8 +528,7 @@ static struct grecs_keyword tagr_kw[] = {
512 grecs_type_int, color_in_max, 0, cb_color }, 528 grecs_type_int, color_in_max, 0, cb_color },
513 { "color-out-max", NULL, N_("Not implemented") /* FIXME */, 529 { "color-out-max", NULL, N_("Not implemented") /* FIXME */,
514 grecs_type_int, color_out_max, 0, cb_color }, 530 grecs_type_int, color_out_max, 0, cb_color },
515 531
516 /* FIXME */
517 { NULL } 532 { NULL }
518}; 533};
519 534
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 @@
33#include <fprintftime.h> 33#include <fprintftime.h>
34#include <gdbm.h> 34#include <gdbm.h>
35 35
36unsigned lock_retry_count_option = 5;
37unsigned lock_retry_timeout_option = 1;
38
36static char *dbname; 39static char *dbname;
37static GDBM_FILE dbf; 40static GDBM_FILE dbf;
38 41
@@ -45,13 +48,20 @@ tagr_db_report (char *str)
45int 48int
46open_db (int flag) 49open_db (int flag)
47{ 50{
48 dbname = xmalloc (strlen (basedir) + 1 + sizeof (TAGR_DBNAME)); 51 unsigned i;
49 strcpy (dbname, basedir); 52
50 strcat (dbname, "/"); 53 dbname = mkfilename (basedir, TAGR_DBNAME, NULL);
51 strcat (dbname, TAGR_DBNAME); 54
52 dbf = gdbm_open (dbname, 0, 55 for (i = 0; i < lock_retry_count_option; i++)
53 flag == TAGR_DB_WR ? GDBM_WRCREAT : GDBM_READER, 56 {
54 TAGR_DBMODE, tagr_db_report); 57 dbf = gdbm_open (dbname, 0,
58 flag == TAGR_DB_WR ? GDBM_WRCREAT : GDBM_READER,
59 TAGR_DBMODE, tagr_db_report);
60 if (dbf || errno != EAGAIN)
61 break;
62 sleep (lock_retry_timeout_option);
63 }
64
55 if (dbf == NULL) 65 if (dbf == NULL)
56 { 66 {
57 logmsg (L_ERR, _("cannot open database %s: %s"), 67 logmsg (L_ERR, _("cannot open database %s: %s"),
@@ -251,7 +261,7 @@ report (Stat *stat, time_t timestamp)
251} 261}
252 262
253int 263int
254update_monitor (datum key, time_t timestamp, int force) 264update_monitor (datum key, time_t timestamp, int flags)
255{ 265{
256 char id[MAX_NAME_LENGTH+1]; 266 char id[MAX_NAME_LENGTH+1];
257 struct traffic_record *tr = NULL; 267 struct traffic_record *tr = NULL;
@@ -273,8 +283,7 @@ update_monitor (datum key, time_t timestamp, int force)
273 _read_db (key, &tr); 283 _read_db (key, &tr);
274 if (tr) 284 if (tr)
275 { 285 {
276 update_output (mon, tr, tr->last.time /*FIXME: must be now? */, 286 update_output (mon, tr, timestamp, flags);
277 force);
278 free (tr); 287 free (tr);
279 } 288 }
280 289
@@ -282,20 +291,20 @@ update_monitor (datum key, time_t timestamp, int force)
282} 291}
283 292
284void 293void
285rebuild (int force) 294rebuild (int flags)
286{ 295{
287 datum key; 296 datum key;
288 datum content; 297 datum content;
289 time_t now = time (NULL); 298 time_t now = time (NULL);
290 299
291 verbose (1, _("rebuild initiated")); 300 verbose (1, _("rebuild initiated"));
292 if (open_db (TAGR_DB_RD) == 0) 301 if (open_db (TAGR_DB_RD) == 0)
293 { 302 {
294 key = gdbm_firstkey (dbf); 303 key = gdbm_firstkey (dbf);
295 while (key.dptr) 304 while (key.dptr)
296 { 305 {
297 datum nextkey = gdbm_nextkey ( dbf, key ); 306 datum nextkey = gdbm_nextkey (dbf, key);
298 update_monitor (key, now, force); 307 update_monitor (key, now, flags);
299 free (key.dptr); 308 free (key.dptr);
300 key = nextkey; 309 key = nextkey;
301 } 310 }
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 @@
37#include <tagr.h> 37#include <tagr.h>
38#include <report.h> 38#include <report.h>
39#include <inttypes.h> 39#include <inttypes.h>
40#include <c-strcase.h>
40#include <wordsplit.h> 41#include <wordsplit.h>
41 42
43unsigned stream_idle_timeout = 10;
44
42struct tagr_server 45struct tagr_server
43{ 46{
44 struct tagr_server *next; 47 struct tagr_server *next;
@@ -48,7 +51,7 @@ struct tagr_server
48 struct grecs_sockaddr addr; 51 struct grecs_sockaddr addr;
49}; 52};
50 53
51struct tagr_server *server_head, *server_tail; 54static struct tagr_server *server_head, *server_tail;
52 55
53struct server_class 56struct server_class
54{ 57{
@@ -194,8 +197,9 @@ subprocess (void (*fun) (void *data), void *data, int fd)
194 logmsg (L_ERR, _("cannot fork: %s"), strerror (errno)); 197 logmsg (L_ERR, _("cannot fork: %s"), strerror (errno));
195 else 198 else
196 { 199 {
197 signal (SIGHUP, SIG_IGN); 200 signal (SIGHUP, SIG_DFL);
198 signal (SIGCHLD, SIG_IGN); 201 signal (SIGCHLD, SIG_DFL);
202 signal (SIGALRM, SIG_DFL);
199 child = 1; 203 child = 1;
200 if (fd != -1) 204 if (fd != -1)
201 close (fd); 205 close (fd);
@@ -302,7 +306,7 @@ tcp_open (struct tagr_server *srv)
302 return 0; 306 return 0;
303} 307}
304 308
305static void 309void
306trim_crlf (char *buf) 310trim_crlf (char *buf)
307{ 311{
308 size_t len = strlen (buf); 312 size_t len = strlen (buf);
@@ -344,75 +348,166 @@ convert_ulong (const char *str, unsigned long *pt)
344 return 0; 348 return 0;
345} 349}
346 350
351static RETSIGTYPE
352sig_child_alrm (int sig)
353{
354 logmsg (L_NOTICE, _("child timed out"));
355 exit (EX_TEMPFAIL);
356}
357
358enum tagr_dialog_state
359 {
360 initial_dialog_state,
361 auth_dialog_state,
362 quit_dialog_state
363 };
364
365struct tagr_dialog
366{
367 enum tagr_dialog_state state;
368 FILE *in;
369 FILE *out;
370};
371
372#define STATEMASK(n) (1u<<(n))
373#define ANYSTATE ((unsigned)~0)
374
375struct command
376{
377 const char *name;
378 unsigned statemask;
379 int minargs;
380 int maxargs;
381 void (*handler) (struct tagr_dialog *, struct command *,
382 struct wordsplit *);
383};
384
385static void
386cmd_auth (struct tagr_dialog *dlg, struct command *cmd,
387 struct wordsplit *ws)
388{
389 if (tagr_auth (ws->ws_wordv[1], ws->ws_wordv[2]) == 0)
390 {
391 dlg->state = auth_dialog_state;
392 fprintf (dlg->out, "+OK welcome, %s\r\n", ws->ws_wordv[1]);
393 }
394 else
395 fprintf (dlg->out, "-ERR authorization failed\r\n");
396}
397
398static void
399cmd_sample (struct tagr_dialog *dlg, struct command *cmd,
400 struct wordsplit *ws)
401{
402 Stat st;
403 time_t t;
404
405 if (strlen (ws->ws_wordv[1]) > MAX_NAME_LENGTH)
406 {
407 fprintf (dlg->out, "-ERR id too long\r\n");
408 return;
409 }
410
411 strcpy (st.name, ws->ws_wordv[1]);
412 if (convert_ts (ws->ws_wordv[2], &t)
413 || convert_ulong (ws->ws_wordv[3], &st.in)
414 || convert_ulong (ws->ws_wordv[4], &st.out))
415 {
416 fprintf (dlg->out, "-ERR invalid input\r\n");
417 return;
418 }
419
420 if (open_db (TAGR_DB_WR))
421 fprintf (dlg->out, "-TEMP database not available\r\n");
422 else
423 {
424 report (&st, t);
425 close_db ();
426 fprintf (dlg->out, "+OK thank you\r\n");
427 }
428}
429
430static void
431cmd_quit (struct tagr_dialog *dlg, struct command *cmd,
432 struct wordsplit *ws)
433{
434 dlg->state = quit_dialog_state;
435 fprintf (dlg->out, "+OK bye\r\n");
436}
437
438static struct command command_tab[] = {
439 { "AUTH", STATEMASK (initial_dialog_state), 3, 3, cmd_auth },
440 { "SAMPLE", STATEMASK (auth_dialog_state), 5, 5, cmd_sample },
441 { "QUIT", ANYSTATE, 1, 1, cmd_quit },
442 { NULL }
443};
444
445static struct command *
446find_command (const char *name)
447{
448 struct command *cmd;
449
450 for (cmd = command_tab; cmd->name; cmd++)
451 if (c_strcasecmp (cmd->name, name) == 0)
452 return cmd;
453 return NULL;
454}
455
456
347static void 457static void
348tcp_server_loop (void *data) 458tcp_server_loop (void *data)
349{ 459{
350 int fd = *(int*)data; 460 int fd = *(int*)data;
351 FILE *in = fdopen (fd, "r"); 461 struct tagr_dialog dlg;
352 FILE *out = fdopen (fd, "w");
353 size_t bufsize = 0; 462 size_t bufsize = 0;
354 char *buf = NULL; 463 char *buf = NULL;
355 int quit = 0; 464 const char *authid;
356 465
357 setvbuf (in, NULL, _IOLBF, 0); 466 signal (SIGALRM, sig_child_alrm);
358 setvbuf (out, NULL, _IOLBF, 0);
359 467
360 fprintf (out, "+OK tagr experimental stream service\r\n"); 468 dlg.state = initial_dialog_state;
361 while (!quit && getline (&buf, &bufsize, in) > 0) 469 dlg.in = fdopen (fd, "r");
470 dlg.out = fdopen (fd, "w");
471 setvbuf (dlg.in, NULL, _IOLBF, 0);
472 setvbuf (dlg.out, NULL, _IOLBF, 0);
473
474 authid = tagr_auth_init ();
475 fprintf (dlg.out, "+OK tagr experimental stream service %s\r\n", authid);
476 while (dlg.state != quit_dialog_state
477 && getline (&buf, &bufsize, dlg.in) > 0)
362 { 478 {
363 struct wordsplit ws; 479 struct wordsplit ws;
364 480 struct command *cmd;
481
482 alarm (stream_idle_timeout);
365 trim_crlf (buf); 483 trim_crlf (buf);
366 if (wordsplit (buf, &ws, WRDSF_DEFFLAGS)) 484 if (wordsplit (buf, &ws, WRDSF_DEFFLAGS))
367 { 485 {
368 logmsg (L_ERR, "failed to parse input line"); 486 logmsg (L_ERR, _("failed to parse input line"));
369 fprintf (out, "-ERR parsing failed\r\n"); 487 fprintf (dlg.out, "-ERR parsing failed\r\n");
370 continue; 488 continue;
371 } 489 }
372 490
373 if (ws.ws_wordc == 0) 491 if (ws.ws_wordc == 0)
374 fprintf (out, "-ERR invalid input\r\n"); 492 fprintf (dlg.out, "-ERR invalid input\r\n");
375 else if (strcasecmp (ws.ws_wordv[0], "SAMPLE") == 0 493 else if (cmd = find_command (ws.ws_wordv[0]))
376 && ws.ws_wordc == 5)
377 { 494 {
378 Stat st; 495 if (!(STATEMASK (dlg.state) & cmd->statemask))
379 time_t t; 496 fprintf (dlg.out, "-ERR wrong state\r\n");
380 497 else if (ws.ws_wordc < cmd->minargs
381 if (strlen (ws.ws_wordv[1]) > MAX_NAME_LENGTH) 498 || (cmd->maxargs > 0 && ws.ws_wordc > cmd->maxargs))
382 fprintf (out, "-ERR id too long\r\n"); 499 fprintf (dlg.out, "-ERR invalid number of arguments\r\n");
383 else 500 else
384 { 501 cmd->handler (&dlg, cmd, &ws);
385 strcpy (st.name, ws.ws_wordv[1]);
386 if (convert_ts (ws.ws_wordv[2], &t)
387 || convert_ulong (ws.ws_wordv[3], &st.in)
388 || convert_ulong (ws.ws_wordv[4], &st.out))
389 fprintf (out, "-ERR invalid input\r\n");
390 else
391 {
392 if (open_db (TAGR_DB_WR))
393 fprintf (out, "-ERR database not available\r\n");
394 else
395 {
396 report (&st, t);
397 close_db ();
398 fprintf (out, "+OK thank you\r\n");
399 }
400 }
401 }
402 }
403 else if (strcasecmp (ws.ws_wordv[0], "QUIT") == 0)
404 {
405 quit = 1;
406 fprintf (out, "+OK bye\r\n");
407 } 502 }
408 else 503 else
409 fprintf (out, "-ERR invalid input\r\n"); 504 fprintf (dlg.out, "-ERR invalid input\r\n");
410 wordsplit_free (&ws); 505 wordsplit_free (&ws);
411 } 506 }
412 507
413 free (buf); 508 free (buf);
414 fclose (in); 509 fclose (dlg.in);
415 fclose (out); 510 fclose (dlg.out);
416 close (fd); 511 close (fd);
417} 512}
418 513
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 @@
20#include <sysexits.h> 20#include <sysexits.h>
21#include <grecs.h> 21#include <grecs.h>
22 22
23#ifndef TAGR_ARG_UNUSED
24# define TAGR_ARG_UNUSED __attribute__ ((__unused__))
25#endif
26
27#ifndef TAGR_PRINTFLIKE
28# define TAGR_PRINTFLIKE(fmt,narg) \
29 __attribute__ ((__format__ (__printf__, fmt, narg)))
30#endif
31
23#define TAGR_CONFIGFILE SYSCONFDIR "/tagr.conf" 32#define TAGR_CONFIGFILE SYSCONFDIR "/tagr.conf"
24#define TAGR_TEMPLATE SYSCONFDIR "/tagr.tmpl" 33#define TAGR_TEMPLATE SYSCONFDIR "/tagr.tmpl"
25#define TAGR_PIDFILE "/var/run/tagr.pid" 34#define TAGR_PIDFILE "/var/run/tagr.pid"
@@ -51,6 +60,13 @@ extern unsigned update_interval;
51extern int single_process_option; 60extern int single_process_option;
52extern double cut_out_fraction; 61extern double cut_out_fraction;
53 62
63extern unsigned lock_retry_count_option;
64extern unsigned lock_retry_timeout_option;
65
66extern unsigned stream_idle_timeout;
67
68extern char *hostname;
69
54extern char *user; 70extern char *user;
55extern char *basedir; 71extern char *basedir;
56extern char *configfile; 72extern char *configfile;
@@ -143,9 +159,9 @@ extern int log_print_severity;
143#define L_CRIT 5 159#define L_CRIT 5
144 160
145void init_syslog (char *tag); 161void init_syslog (char *tag);
146void logmsg (int level, const char *fmt, ...); 162void logmsg (int level, const char *fmt, ...) TAGR_PRINTFLIKE(2,3);
147void die (int code, const char *fmt, ...); 163void die (int code, const char *fmt, ...) TAGR_PRINTFLIKE(2,3);
148void verbose (int level, const char *fmt, ...); 164void verbose (int level, const char *fmt, ...) TAGR_PRINTFLIKE(2,3);
149 165
150 166
151 167
@@ -218,9 +234,13 @@ void close_db ();
218void read_db (struct monitor *mon, struct traffic_record **tr); 234void read_db (struct monitor *mon, struct traffic_record **tr);
219void write_db (struct monitor *mon, struct traffic_record *tr); 235void write_db (struct monitor *mon, struct traffic_record *tr);
220void list_db (void); 236void list_db (void);
221void rebuild (int force);
222void tr_init (struct traffic_record *tr); 237void tr_init (struct traffic_record *tr);
223 238
239#define TAGR_UPD_FORCE 0x0001
240#define TAGR_UPD_LASTTIME 0x0002
241
242void rebuild (int flags);
243
224/* stat.c */ 244/* stat.c */
225void update_stats (struct monitor *mon, struct traffic_sample *sample, 245void update_stats (struct monitor *mon, struct traffic_sample *sample,
226 struct traffic_record *tr); 246 struct traffic_record *tr);
@@ -242,7 +262,7 @@ void scale_sample (struct monitor *mon,
242 const struct traffic_history *in, 262 const struct traffic_history *in,
243 struct traffic_history *out); 263 struct traffic_history *out);
244int update_output (struct monitor *mon, struct traffic_record *tr, 264int update_output (struct monitor *mon, struct traffic_record *tr,
245 time_t timestamp, int force); 265 time_t timestamp, int flags);
246 266
247 267
248/* graph.c */ 268/* graph.c */
@@ -288,7 +308,18 @@ void open_servers (void);
288void close_servers (void); 308void close_servers (void);
289void server_loop (void); 309void server_loop (void);
290 310
311void trim_crlf (char *buf);
312
291int tagr_idle (void); 313int tagr_idle (void);
292 314
315
316char *tagr_local_hostname (void);
317const char *tagr_auth_init (void);
318int tagr_auth (const char *username, const char *authstr);
293 319
320
321/* udb.c */
322extern char *tagr_udb_name;
294 323
324int udb_get_password (const char *username, char **password);
325void 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 @@
1/* This file is part of tagr.
2 Copyright (C) 2009 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <unistd.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <errno.h>
24#include <string.h>
25#include <wordsplit.h>
26#include <tagr.h>
27
28char *tagr_udb_name = SYSCONFDIR "/tagr.udb";
29
30int
31udb_get_password (const char *username, char **password)
32{
33 FILE *fp;
34 size_t bufsize = 0;
35 char *buf = NULL;
36 unsigned line = 0;
37 int rc = 1;
38
39 fp = fopen (tagr_udb_name, "r");
40 if (!fp)
41 {
42 logmsg (L_ERR, _("cannot open file %s: %s"),
43 tagr_udb_name, strerror (errno));
44 return -1;
45 }
46
47 while (rc == 1 && getline (&buf, &bufsize, fp) > 0)
48 {
49 struct wordsplit ws;
50
51 line++;
52 trim_crlf (buf);
53 if (wordsplit (buf, &ws, WRDSF_DEFFLAGS))
54 {
55 logmsg (L_ERR, _("%s:%u: failed to parse input line"),
56 tagr_udb_name, line);
57 }
58 if (ws.ws_wordc == 0 || ws.ws_wordv[0][0] == '#')
59 /* next */;
60 else if (ws.ws_wordc < 2)
61 {
62 logmsg (L_WARNING, _("%s:%u: too few words on line"),
63 tagr_udb_name, line);
64 }
65 else if (ws.ws_wordc > 2)
66 {
67 logmsg (L_WARNING, _("%s:%u: too many words on line"),
68 tagr_udb_name, line);
69 }
70 else if (strcmp (ws.ws_wordv[0], username) == 0)
71 {
72 *password = xstrdup (ws.ws_wordv[1]);
73 rc = 0;
74 }
75 wordsplit_free (&ws);
76 }
77
78 free (buf);
79 fclose (fp);
80 return rc;
81}
82
83void
84udb_free_password (char *pass)
85{
86 char *p;
87 for (p = pass; *p; p++)
88 *p = 0;
89 free (pass);
90}
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 @@
1/* This file is part of tagr.
2 Copyright (C) 2009 Max Bouglacoff, Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdlib.h>
21#include <string.h>
22#include <netdb.h>
23#include <xalloc.h>
24#include <xgethostname.h>
25#include <xgetdomainname.h>
26
27char *
28tagr_local_hostname ()
29{
30 struct hostent *hp;
31 char *hostpart = xgethostname ();
32 char *ret;
33
34 hp = gethostbyname (hostpart);
35 if (hp)
36 ret = xstrdup (hp->h_name);
37 else
38 {
39 char *domainpart = xgetdomainname ();
40
41 if (domainpart && domainpart[0] && strcmp(domainpart, "(none)"))
42 {
43 ret = xmalloc(strlen( hostpart) + 1
44 + strlen (domainpart) + 1);
45 strcpy(ret, hostpart);
46 strcat(ret, ".");
47 strcat(ret, domainpart);
48 free (hostpart);
49 }
50 else
51 ret = hostpart;
52 free (domainpart);
53 }
54 return ret;
55}
56

Return to:

Send suggestions and report system problems to the System administrator.