http.c \
localip.c \
ncache.c \
+now.c \
pidfile.c \
str.c
conv.o: conv.c conv.h err.h cdefs.h
darkstat.o: darkstat.c acct.h cap.h cdefs.h config.h conv.h daylog.h \
graph_db.h db.h dns.h err.h http.h hosts_db.h addr.h localip.h ncache.h \
- pidfile.h now.h
+ now.h pidfile.h
daylog.o: daylog.c err.h cdefs.h daylog.h graph_db.h str.h now.h
db.o: db.c cdefs.h err.h hosts_db.h addr.h graph_db.h db.h
decode.o: decode.c cdefs.h decode.h addr.h err.h opt.h
html.o: html.c config.h str.h html.h opt.h
http.o: http.c cdefs.h config.h conv.h err.h graph_db.h hosts_db.h addr.h \
http.h now.h queue.h str.h stylecss.h graphjs.h
-localip.o: localip.c addr.h config.h conv.h err.h cdefs.h localip.h bsd.h
+localip.o: localip.c addr.h bsd.h config.h conv.h err.h cdefs.h localip.h \
+ now.h
ncache.o: ncache.c conv.h err.h cdefs.h ncache.h tree.h bsd.h config.h
+now.o: now.c err.h cdefs.h now.h
pidfile.o: pidfile.c err.h cdefs.h str.h pidfile.h
str.o: str.c conv.h err.h cdefs.h str.h
hs->out += sm->len;
hs->total += sm->len;
memcpy(hs->u.host.mac_addr, sm->src_mac, sizeof(sm->src_mac));
- hs->u.host.lastseen = now;
+ hs->u.host.last_seen_mono = now_mono();
}
if (!opt_want_local_only || addr_is_local(&sm->dst)) {
}
#endif
- /*
- * Once per capture poll, check our IP address. It's used in accounting
+ /* Once per capture poll, check our IP address. It's used in accounting
* for traffic graphs.
*/
localip_update(opt_interface, local_ips);
- /* FIXME: ^ this might run too often */
total = 0;
for (;;) {
AC_CHECK_HEADERS(bsd/string.h)
AC_CHECK_HEADERS(bsd/unistd.h)
+AC_SEARCH_LIBS(clock_gettime, rt)
+
AC_CONFIG_FILES([Makefile darkstat.8])
AC_OUTPUT
#include "hosts_db.h"
#include "localip.h"
#include "ncache.h"
+#include "now.h"
#include "pidfile.h"
#include <assert.h>
#include <unistd.h>
#include <pcap.h>
-#include "now.h"
-time_t now;
-
#ifndef INADDR_NONE
# define INADDR_NONE (-1) /* Solaris */
#endif
privdrop(opt_chroot_dir, opt_privdrop_user);
/* Don't need root privs for these: */
- now = time(NULL);
+ now_init();
if (daylog_fn != NULL) daylog_init(daylog_fn);
graph_init();
hosts_db_init();
struct timeval timeout;
fd_set rs, ws;
- now = time(NULL);
-
- if (export_pending) {
- if (export_fn != NULL)
- db_export(export_fn);
- export_pending = 0;
- }
-
- if (reset_pending) {
- if (export_pending)
- continue; /* export before reset */
- hosts_db_reset();
- graph_reset();
- reset_pending = 0;
- }
-
FD_ZERO(&rs);
FD_ZERO(&ws);
select_ret = select(max_fd+1, &rs, &ws, NULL,
(use_timeout) ? &timeout : NULL);
-
- if ((select_ret == 0) && (!use_timeout))
+ if (select_ret == 0 && !use_timeout)
errx(1, "select() erroneously timed out");
-
if (select_ret == -1) {
if (errno == EINTR)
continue;
else
err(1, "select()");
}
- else {
- graph_rotate();
- cap_poll(&rs);
- dns_poll();
- http_poll(&rs, &ws);
+
+ now_update();
+
+ if (export_pending) {
+ if (export_fn != NULL)
+ db_export(export_fn);
+ export_pending = 0;
}
+
+ if (reset_pending) {
+ if (export_pending)
+ continue; /* export before reset */
+ hosts_db_reset();
+ graph_reset();
+ reset_pending = 0;
+ }
+
+ graph_rotate();
+ cap_poll(&rs);
+ dns_poll();
+ http_poll(&rs, &ws);
}
verbosef("shutting down");
#define _GNU_SOURCE 1 /* for O_NOFOLLOW on Linux */
-#include <sys/types.h>
+#include "err.h"
+#include "daylog.h"
+#include "str.h"
+#include "now.h"
+
#include <assert.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
-#include "err.h"
-#include "daylog.h"
-#include "str.h"
-#include "now.h"
-
static const char *daylog_fn = NULL;
-static time_t today_time, tomorrow_time;
+static long today_real, tomorrow_real;
static uint64_t bytes_in, bytes_out, pkts_in, pkts_out;
#define DAYLOG_DATE_LEN 26 /* strlen("1900-01-01 00:00:00 +1234") + 1 */
static char datebuf[DAYLOG_DATE_LEN];
-static char *
-fmt_date(const time_t when)
-{
- time_t tmp = when;
- if (strftime(datebuf, DAYLOG_DATE_LEN,
- "%Y-%m-%d %H:%M:%S %z", localtime(&tmp) ) == 0)
+static char *fmt_date(time_t when) {
+ if (strftime(datebuf,
+ DAYLOG_DATE_LEN,
+ "%Y-%m-%d %H:%M:%S %z",
+ localtime(&when)) == 0)
errx(1, "strftime() failed in fmt_date()");
- return (datebuf);
+ return datebuf;
}
/* Given some time today, find the first second of tomorrow. */
-static time_t
-tomorrow(const time_t today)
-{
- time_t tmp = today;
+static time_t tomorrow(time_t t_before) {
+ time_t t_after;
struct tm tm, *lt;
- lt = localtime(&tmp);
+ lt = localtime(&t_before);
memcpy(&tm, lt, sizeof(tm));
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
tm.tm_mday = lt->tm_mday + 1; /* tomorrow */
- return mktime(&tm);
+ t_after = mktime(&tm);
+ assert(t_after > t_before);
+ return t_after;
}
/* Warns on error. */
}
static void daylog_emit(void) {
- daylog_write("%s|%u|%qu|%qu|%qu|%qu\n",
- fmt_date(today_time), (unsigned int)today_time,
+ daylog_write("%s|%ld|%qu|%qu|%qu|%qu\n",
+ fmt_date(today_real), (long)today_real,
bytes_in, bytes_out, pkts_in, pkts_out);
}
void daylog_init(const char *filename) {
daylog_fn = filename;
- today_time = time(NULL);
- tomorrow_time = tomorrow(today_time);
- verbosef("today is %u, tomorrow is %u",
- (unsigned int)today_time, (unsigned int)tomorrow_time);
+ today_real = now_real();
+ tomorrow_real = tomorrow(today_real);
+ verbosef("today is %ld, tomorrow is %ld",
+ (long)today_real, (long)tomorrow_real);
bytes_in = bytes_out = pkts_in = pkts_out = 0;
- daylog_write("# logging started at %s (%u)\n",
- fmt_date(today_time), (unsigned int)today_time);
+ daylog_write("# logging started at %s (%ld)\n",
+ fmt_date(today_real), (long)today_real);
}
void daylog_free(void) {
- today_time = time(NULL);
+ today_real = now_real();
daylog_emit(); /* Emit what's currently accumulated before we exit. */
- daylog_write("# logging stopped at %s (%u)\n",
- fmt_date(today_time), (unsigned int)today_time);
+ daylog_write("# logging stopped at %s (%ld)\n",
+ fmt_date(today_real), (long)today_real);
}
void daylog_acct(uint64_t amount, enum graph_dir dir) {
- if (daylog_fn == NULL) return; /* disabled */
+ if (daylog_fn == NULL)
+ return; /* daylogging disabled */
/* Check if we need to update the log. */
- if (now >= tomorrow_time) {
+ if (now_real() >= tomorrow_real) {
daylog_emit();
- today_time = now;
- tomorrow_time = tomorrow(today_time);
+ today_real = now_real();
+ tomorrow_real = tomorrow(today_real);
bytes_in = bytes_out = pkts_in = pkts_out = 0;
- verbosef("updated daylog, tomorrow = %u", (unsigned int)tomorrow_time);
+ verbosef("updated daylog, tomorrow = %ld", (long)tomorrow_real);
}
/* Accounting. */
#include <assert.h>
#include <stdlib.h>
#include <string.h> /* for memcpy() */
+#include <time.h>
#define GRAPH_WIDTH "320"
#define GRAPH_HEIGHT "200"
};
static unsigned int graph_db_size = sizeof(graph_db)/sizeof(*graph_db);
+static long start_mono, start_real, last_real;
-static time_t start_time, last_time;
-
-void
-graph_init(void)
-{
+void graph_init(void) {
unsigned int i;
for (i=0; i<graph_db_size; i++) {
graph_db[i]->in = xmalloc(sizeof(uint64_t) * graph_db[i]->num_bars);
graph_db[i]->out = xmalloc(sizeof(uint64_t) * graph_db[i]->num_bars);
}
- start_time = time(NULL);
+ start_mono = now_mono();
+ start_real = now_real();
graph_reset();
}
-static void
-zero_graph(struct graph *g)
-{
+static void zero_graph(struct graph *g) {
memset(g->in, 0, sizeof(uint64_t) * g->num_bars);
memset(g->out, 0, sizeof(uint64_t) * g->num_bars);
}
-void
-graph_reset(void)
-{
+void graph_reset(void) {
unsigned int i;
+
for (i=0; i<graph_db_size; i++)
zero_graph(graph_db[i]);
- last_time = 0;
+ last_real = 0;
}
-void
-graph_free(void)
-{
+void graph_free(void) {
unsigned int i;
+
for (i=0; i<graph_db_size; i++) {
free(graph_db[i]->in);
free(graph_db[i]->out);
}
}
-void
-graph_acct(uint64_t amount, enum graph_dir dir)
-{
+void graph_acct(uint64_t amount, enum graph_dir dir) {
unsigned int i;
for (i=0; i<graph_db_size; i++)
- switch (dir) {
- case GRAPH_IN: graph_db[i]->in[ graph_db[i]->pos ] += amount; break;
- case GRAPH_OUT: graph_db[i]->out[ graph_db[i]->pos ] += amount; break;
- default: errx(1, "unknown graph_dir in graph_acct: %d", dir);
- }
+ if (dir == GRAPH_IN) {
+ graph_db[i]->in[ graph_db[i]->pos ] += amount;
+ } else {
+ assert(dir == GRAPH_OUT);
+ graph_db[i]->out[ graph_db[i]->pos ] += amount;
+ }
}
/* Advance a graph: advance the pos, zeroing out bars as we move. */
-static void
-advance(struct graph *g, const unsigned int pos)
-{
+static void advance(struct graph *g, const unsigned int pos) {
if (g->pos == pos)
return; /* didn't need to advance */
do {
}
/* Rotate a graph: rotate all bars so that the bar at the current pos is moved
- * to the newly given pos. This is non-destructive. */
-static void
-rotate(struct graph *g, const unsigned int pos)
-{
+ * to the newly given pos.
+ */
+static void rotate(struct graph *g, const unsigned int pos) {
uint64_t *tmp;
unsigned int i, ofs;
size_t size;
g->pos = pos;
}
-static void
-graph_resync(const time_t new_time)
-{
+static void graph_resync(const long new_time) {
struct tm *tm;
/*
- * If time went backwards, we assume that real time is continuous and that
- * the time adjustment should only affect display. i.e., if we have:
+ * If real time went backwards, we assume that the time adjustment should
+ * only affect display. i.e., if we have:
*
* second 15: 12 bytes
* second 16: 345 bytes
* second 7: 345 bytes
* second 8: <-- current pos
*
- * Note that we don't make any corrections for time being stepped forward.
+ * We don't make any corrections for time being stepped forward,
+ * it's treated as though there was no traffic during that time.
+ *
* We rely on graph advancement to happen at the correct real time to
* account for, for example, bandwidth used per day.
*/
- assert(new_time < last_time);
+ assert(new_time < last_real);
tm = localtime(&new_time);
if (tm->tm_sec == 60)
rotate(&graph_hrs, tm->tm_hour);
rotate(&graph_days, tm->tm_mday - 1);
- last_time = new_time;
+ last_real = new_time;
}
-void
-graph_rotate(void)
-{
- time_t t, td;
+void graph_rotate(void) {
+ long t, td;
struct tm *tm;
unsigned int i;
- t = now;
+ t = now_real();
+ td = t - last_real;
- if (last_time == 0) {
+ if (last_real == 0) {
verbosef("first rotate");
- last_time = t;
+ last_real = t;
tm = localtime(&t);
- if (tm->tm_sec == 60)
- tm->tm_sec = 59; /* mis-handle leap seconds */
-
graph_secs.pos = tm->tm_sec;
graph_mins.pos = tm->tm_min;
graph_hrs.pos = tm->tm_hour;
return;
}
- if (t == last_time)
- return; /* superfluous rotate */
+ if (t == last_real)
+ return; /* time has not advanced a full second, don't rotate */
- if (t < last_time) {
- verbosef("time went backwards! (from %u to %u, offset is %d)",
- (unsigned int)last_time, (unsigned int)t, (int)(t - last_time));
+ if (t < last_real) {
+ verbosef("graph_db: realtime went backwards! "
+ "(from %ld to %ld, offset is %ld)",
+ last_real, t, td);
graph_resync(t);
return;
}
/* else, normal rotation */
- td = t - last_time;
- last_time = t;
+ last_real = t;
tm = localtime(&t);
- if (tm->tm_sec == 60)
- tm->tm_sec = 59; /* mis-handle leap seconds */
/* zero out graphs which have been completely rotated through */
for (i=0; i<graph_db_size; i++)
* to have validated the header of the segment, and left the file position at
* the start of the data.
*/
-int
-graph_import(const int fd)
-{
+int graph_import(const int fd) {
uint64_t last;
unsigned int i, j;
if (!read64(fd, &last)) return 0;
- last_time = (time_t)last;
+ last_real = last;
for (i=0; i<graph_db_size; i++) {
unsigned char num_bars, pos;
* Database Export: Dump hosts_db into a file provided by the caller.
* The caller is responsible for writing out the header first.
*/
-int
-graph_export(const int fd)
-{
+int graph_export(const int fd) {
unsigned int i, j;
- if (!write64(fd, (uint64_t)last_time)) return 0;
+ if (!write64(fd, (uint64_t)last_real)) return 0;
for (i=0; i<graph_db_size; i++) {
if (!write8(fd, graph_db[i]->num_bars)) return 0;
if (!write8(fd, graph_db[i]->pos)) return 0;
/* ---------------------------------------------------------------------------
* Web interface: front page!
*/
-struct str *
-html_front_page(void)
-{
+struct str *html_front_page(void) {
struct str *buf, *rf;
unsigned int i;
char start_when[100];
+ long d_real, d_mono;
buf = str_make();
html_open(buf, "Graphs", /*path_depth=*/0, /*want_graph_js=*/1);
+ d_mono = now_mono() - start_mono;
+ d_real = now_real() - start_real;
str_append(buf, "<p>\n");
str_append(buf, "<b>Running for</b> <span id=\"rf\">");
- rf = length_of_time(now - start_time);
- /* FIXME: use a more monotonic clock perhaps? */
+ rf = length_of_time(d_mono);
str_appendstr(buf, rf);
str_free(rf);
str_append(buf, "</span>");
+ if (abs(d_real - d_mono) > 1)
+ str_appendf(buf, " (real time is off by %ld sec)", d_real - d_mono);
if (strftime(start_when, sizeof(start_when),
- "%Y-%m-%d %H:%M:%S %Z%z", localtime(&start_time)) != 0)
+ "%Y-%m-%d %H:%M:%S %Z%z", localtime(&start_real)) != 0)
str_appendf(buf, "<b>, since</b> %s", start_when);
str_appendf(buf,"<b>.</b><br>\n"
/* ---------------------------------------------------------------------------
* Web interface: graphs.xml
*/
-struct str *
-xml_graphs(void)
-{
+struct str *xml_graphs(void) {
unsigned int i, j;
struct str *buf = str_make(), *rf;
str_appendf(buf, "<graphs tp=\"%qu\" tb=\"%qu\" pc=\"%u\" pd=\"%u\" rf=\"",
acct_total_packets, acct_total_bytes, cap_pkts_recv, cap_pkts_drop);
- rf = length_of_time(now - start_time);
+ rf = length_of_time(now_real() - start_real);
str_appendstr(buf, rf);
str_free(rf);
str_append(buf, "\">\n");
return (buf);
}
-/* vim:set ts=3 sw=3 tw=78 expandtab: */
+/* vim:set ts=3 sw=3 tw=80 et: */
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* memset(), strcmp() */
+#include <time.h>
#include <unistd.h>
int hosts_db_show_macs = 0;
MAKE_BUCKET(b, h, host);
h->addr = CASTKEY(struct addr);
h->dns = NULL;
- h->lastseen = 0;
+ h->last_seen_mono = 0;
memset(&h->mac_addr, 0, sizeof(h->mac_addr));
h->ports_tcp = NULL;
h->ports_udp = NULL;
b->in, b->out, b->total);
if (opt_want_lastseen) {
- time_t last_t = b->u.host.lastseen;
+ long last = b->u.host.last_seen_mono;
struct str *last_str = NULL;
- if ((now >= last_t) && (last_t > 0))
- last_str = length_of_time(now - last_t);
+ if ((now_mono() >= last) && (last > 0))
+ last_str = length_of_time(now_mono() - last);
- str_append(buf,
- " <td class=\"num\">");
+ str_append(buf, " <td class=\"num\">");
if (last_str == NULL) {
- if (last_t == 0)
+ if (last == 0)
str_append(buf, "(never)");
else
str_append(buf, "(clock error)");
str_appendstr(buf, last_str);
str_free(last_str);
}
- str_append(buf,
- "</td>");
+ str_append(buf, "</td>");
}
- str_appendf(buf,
- "</tr>\n");
+ str_appendf(buf, "</tr>\n");
/* Only resolve hosts "on demand" */
if (b->u.host.dns == NULL)
/* ---------------------------------------------------------------------------
* Web interface: detailed view of a single host.
*/
-static struct str *
-html_hosts_detail(const char *ip)
-{
+static struct str *html_hosts_detail(const char *ip) {
struct bucket *h;
struct str *buf, *ls_len;
char ls_when[100];
const char *canonical;
- time_t ls;
+ time_t last_real;
h = host_search(ip);
if (h == NULL)
"<p>\n"
"<b>Last seen:</b> ");
- ls = h->u.host.lastseen;
+ last_real = mono_to_real(h->u.host.last_seen_mono);
if (strftime(ls_when, sizeof(ls_when),
- "%Y-%m-%d %H:%M:%S %Z%z", localtime(&ls)) != 0)
+ "%Y-%m-%d %H:%M:%S %Z%z", localtime(&last_real)) != 0)
str_append(buf, ls_when);
- if (h->u.host.lastseen <= now) {
- ls_len = length_of_time(now - h->u.host.lastseen);
+ if (h->u.host.last_seen_mono <= now_mono()) {
+ ls_len = length_of_time(now_mono() - h->u.host.last_seen_mono);
str_append(buf, " (");
str_appendstr(buf, ls_len);
str_free(ls_len);
format_table(buf, h->u.host.ip_protos, 0,TOTAL,0);
html_close(buf);
- return (buf);
+ return buf;
}
/* ---------------------------------------------------------------------------
if (ver > 1) {
uint64_t t;
if (!read64(fd, &t)) return 0;
- host->u.host.lastseen = (time_t)t;
+ host->u.host.last_seen_mono = real_to_mono(t);
}
assert(sizeof(host->u.host.mac_addr) == 6);
if (!writen(fd, export_tag_host_ver3, sizeof(export_tag_host_ver3)))
return 0;
- if (!writeaddr(fd, &(b->u.host.addr))) return 0;
+ if (!writeaddr(fd, &(b->u.host.addr)))
+ return 0;
- if (!write64(fd, (uint64_t)(b->u.host.lastseen))) return 0;
+ if (!write64(fd, (uint64_t)mono_to_real(b->u.host.last_seen_mono)))
+ return 0;
assert(sizeof(b->u.host.mac_addr) == 6);
if (!writen(fd, b->u.host.mac_addr, sizeof(b->u.host.mac_addr)))
#ifndef __DARKSTAT_HOSTS_DB_H
#define __DARKSTAT_HOSTS_DB_H
-#include <sys/types.h> /* for time_t and uint64_t (esp on FreeBSD) */
+#include <sys/types.h> /* for uint64_t */
#include "addr.h"
struct addr addr;
char *dns;
uint8_t mac_addr[6];
- time_t lastseen;
+ long last_seen_mono;
struct hashtable *ports_tcp, *ports_udp, *ip_protos;
};
b = (*y)->total;
break;
case LASTSEEN:
- a = (*x)->u.host.lastseen;
- b = (*y)->u.host.lastseen;
+ a = (*x)->u.host.last_seen_mono;
+ b = (*y)->u.host.last_seen_mono;
break;
default:
errx(1, "cmp: unknown direction: %d", dir);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include <unistd.h>
#include <zlib.h>
int socket;
struct sockaddr_storage client;
- time_t last_active;
+ long last_active_mono;
enum {
RECV_REQUEST, /* receiving request */
SEND_HEADER_AND_REPLY, /* try to send header+reply together */
conn->socket = -1;
memset(&conn->client, 0, sizeof(conn->client));
- conn->last_active = now;
+ conn->last_active_mono = now_mono();
conn->request = NULL;
conn->request_length = 0;
conn->accept_gzip = 0;
* buffer is returned for convenience.
*/
#define DATE_LEN 30 /* strlen("Fri, 28 Feb 2003 00:02:08 GMT")+1 */
-static char *rfc1123_date(char *dest, const time_t when)
-{
- time_t tmp = when;
+static char *rfc1123_date(char *dest, time_t when) {
if (strftime(dest, DATE_LEN,
- "%a, %d %b %Y %H:%M:%S %Z", gmtime(&tmp) ) == 0)
+ "%a, %d %b %Y %H:%M:%S %Z", gmtime(&when) ) == 0)
errx(1, "strftime() failed [%s]", dest);
- return (dest);
+ return dest;
}
static void generate_header(struct connection *conn,
"\r\n"
,
code, text,
- rfc1123_date(date, now), server,
+ rfc1123_date(date, now_real()), server,
conn->mime_type, conn->reply_length, conn->encoding,
conn->header_extra);
conn->http_code = code;
conn->state = DONE;
return;
}
- conn->last_active = now;
+ conn->last_active_mono = now_mono();
/* append to conn->request */
conn->request = xrealloc(conn->request, conn->request_length+recvd+1);
iov[1].iov_len = conn->reply_length;
sent = writev(conn->socket, iov, 2);
- conn->last_active = now;
+ conn->last_active_mono = now_mono();
/* handle any errors (-1) or closure (0) in send() */
if (sent < 1) {
sent = send(conn->socket, conn->header + conn->header_sent,
conn->header_length - conn->header_sent, 0);
- conn->last_active = now;
+ conn->last_active_mono = now_mono();
dverbosef("poll_send_header(%d) sent %d bytes", conn->socket, (int)sent);
/* handle any errors (-1) or closure (0) in send() */
sent = send(conn->socket,
conn->reply + conn->reply_sent,
conn->reply_length - conn->reply_sent, 0);
- conn->last_active = now;
+ conn->last_active_mono = now_mono();
dverbosef("poll_send_reply(%d) sent %d: [%d-%d] of %d",
conn->socket, (int)sent,
(int)conn->reply_sent,
LIST_FOREACH_SAFE(conn, &connlist, entries, next)
{
- int idlefor = now - conn->last_active;
+ int idlefor = now_mono() - conn->last_active_mono;
/* Time out dead connections. */
if (idlefor >= idletime) {
*/
#include "addr.h"
+#include "bsd.h" /* for strlcpy */
#include "config.h" /* for HAVE_IFADDRS_H */
#include "conv.h"
#include "err.h"
#include "localip.h"
-#include "bsd.h" /* for strlcpy */
+#include "now.h"
#include <sys/socket.h>
#include <net/if.h>
struct local_ips *ips = xmalloc(sizeof(*ips));
ips->is_valid = 0;
- ips->last_update = 0;
+ ips->last_update_mono = 0;
ips->num_addrs = 0;
ips->addrs = NULL;
return ips;
return;
}
+ if (ips->last_update_mono == now_mono()) {
+ /* Too soon, bail out. */
+ return;
+ }
+ ips->last_update_mono = now_mono();
+
#ifdef HAVE_IFADDRS_H
{
struct ifaddrs *ifas, *ifa;
iface, ips->num_addrs, new_addrs);
ips->num_addrs = new_addrs;
}
- ips->last_update = time(NULL);
}
int is_localip(const struct addr * const a,
struct local_ips {
int is_valid;
- time_t last_update;
+ long last_update_mono;
int num_addrs;
struct addr *addrs;
};
--- /dev/null
+/* darkstat 3
+ * copyright (c) 2012 Emil Mikulic.
+ *
+ * now.c: a cache of the current time.
+ *
+ * Permission to use, copy, modify, and distribute this file for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "err.h"
+#include "now.h"
+
+#include <assert.h>
+#include <string.h>
+#include <time.h>
+
+static struct timespec clock_real, clock_mono;
+static int now_initialized = 0;
+
+long now_real(void) {
+ assert(now_initialized);
+ return clock_real.tv_sec;
+}
+
+long now_mono(void) {
+ assert(now_initialized);
+ return clock_mono.tv_sec;
+}
+
+static int before(const struct timespec *a, const struct timespec *b) {
+ if (a->tv_sec < b->tv_sec)
+ return 1;
+ if (a->tv_sec == b->tv_sec && a->tv_nsec < b->tv_nsec)
+ return 1;
+ return 0;
+}
+
+static void clock_update(const clockid_t clk_id,
+ struct timespec *dest,
+ const char *name) {
+ struct timespec t;
+
+ clock_gettime(clk_id, &t);
+ if (now_initialized && before(&t, dest)) {
+ verbosef("%s clock went backwards from %ld.%09ld to %ld.%09ld",
+ name,
+ (long)dest->tv_sec,
+ (long)dest->tv_nsec,
+ (long)t.tv_sec,
+ (long)t.tv_nsec);
+ }
+ memcpy(dest, &t, sizeof(t));
+}
+
+static void all_clocks_update(void) {
+ clock_update(CLOCK_REALTIME, &clock_real, "realtime");
+ clock_update(CLOCK_MONOTONIC, &clock_mono, "monotonic");
+}
+
+void now_init(void) {
+ assert(!now_initialized);
+ all_clocks_update();
+ now_initialized = 1;
+}
+
+void now_update(void) {
+ assert(now_initialized);
+ all_clocks_update();
+}
+
+long mono_to_real(const long t) {
+ assert(now_initialized);
+ return t - clock_mono.tv_sec + clock_real.tv_sec;
+}
+
+long real_to_mono(const long t) {
+ assert(now_initialized);
+ return t - clock_real.tv_sec + clock_mono.tv_sec;
+}
+
+/* vim:set ts=3 sw=3 tw=80 et: */
/* darkstat 3
* copyright (c) 2001-2006 Emil Mikulic.
*
- * now.h: a cache of the current time
- * This lets us avoid superfluous gettimeofday() syscalls.
+ * now.h: a cache of the current time.
+ *
+ * Permission to use, copy, modify, and distribute this file for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-#include <time.h>
-extern time_t now; /* updated in the event loop in darkstat.c */
+void now_init(void);
+void now_update(void); /* once per event loop (in darkstat.c) */
+
+long now_real(void);
+long now_mono(void);
+
+long mono_to_real(const long t);
+long real_to_mono(const long t);
+
+/* vim:set ts=3 sw=3 tw=80 et: */
localip.h \
ncache.c \
ncache.h \
+now.c \
now.h \
opt.h \
pidfile.c \