diff --git a/hc_http.c b/hc_http.c
index 90b73be..490a957 100644
--- a/hc_http.c
+++ b/hc_http.c
@@ -46,9 +46,12 @@
#include "echttp_cors.h"
#include "echttp_static.h"
#include "houseportalclient.h"
+#include "houselog.h"
static pid_t parent;
+static long hc_known_clients[256]; // Enough to store IP v4 address.
+static long hc_known_servers[256]; // Enough to store IP v4 address.
static hc_clock_status *clock_db = 0;
static hc_nmea_status *nmea_db = 0;
@@ -63,6 +66,7 @@ static char JsonBuffer[16384];
static void hc_background (int fd, int mode) {
static time_t LastParentCheck = 0;
static time_t LastRenewal = 0;
+ static time_t LastActivityCheck = 0;
time_t now = time(0);
@@ -90,6 +94,89 @@ static void hc_background (int fd, int mode) {
LastRenewal = now;
}
}
+
+ if (ntp_db && (now >= LastActivityCheck + 5)) {
+
+
+ // Generate events for new or unsynchronized clients.
+ // We generate a local "cache" of known clients to limit the number of
+ // events generated when the clent is not synchronized. The cache key
+ // is the low 7 bits of the IP address, plus the ninth bit: this works
+ // best for me because I have two subnets, while I don't have anywhere
+ // close to 127 machines at home.
+ // This should work fine for most home networks.
+ //
+ int i;
+ for (i = 0; i < HC_NTP_DEPTH; ++i) {
+ struct hc_ntp_client *client = ntp_db->clients + i;
+
+ // Do not consider events that are empty or too old (risk of
+ // race condition)
+ //
+ if ((client->local.tv_sec < LastActivityCheck)
+ || (client->local.tv_sec == 0)) continue;
+
+ // Do not consider events that were already detected.
+ //
+ if (client->logged) continue;
+
+ if (abs(client->origin.tv_sec - client->local.tv_sec) > 600) {
+ houselog_event ("CLIENT", hc_broadcast_format (&(client->address)),
+ "ACTIVE", "NOT SYNCHRONIZED");
+ } else {
+ long adr = ntohl(client->address.sin_addr.s_addr);
+ int hash = (int) ((adr & 0x7f) | ((adr & 0x100) >> 1));
+
+ int delta =
+ ((client->origin.tv_sec - client->local.tv_sec) * 1000)
+ + ((client->origin.tv_usec - client->local.tv_usec) / 1000);
+
+ if ((hc_known_clients[hash] == adr) && (abs(delta) < 10000)) continue;
+ houselog_event ("CLIENT", hc_broadcast_format (&(client->address)),
+ "ACTIVE", "DELTA %d MS", delta);
+
+ hc_known_clients[hash] = adr;
+ }
+ client->logged = 1;
+ }
+
+ // Generate events for newly detected servers, using a similar cache
+ // as for clients to limit the rate of events when synchronized.
+ //
+ for (i = 0; i < HC_NTP_POOL; ++i) {
+ struct hc_ntp_server *server = ntp_db->pool + i;
+
+ // Do not consider events that are empty or too old (risk of
+ // race condition)
+ //
+ if ((server->local.tv_sec < LastActivityCheck)
+ || (server->local.tv_sec == 0)) continue;
+
+ // Do not consider events that were already detected.
+ //
+ if (server->logged) continue;
+
+ if (abs(server->origin.tv_sec - server->local.tv_sec) > 600) {
+ houselog_event ("SERVER", server->name, "ACTIVE",
+ "STRATUM %d, NOT SYNCHRONIZED", server->stratum);
+ } else {
+ long adr = ntohl(server->address.sin_addr.s_addr);
+ int hash = (int) ((adr & 0x7f) | ((adr & 0x100) >> 1));
+
+ int delta =
+ ((server->origin.tv_sec - server->local.tv_sec) * 1000)
+ + ((server->origin.tv_usec - server->local.tv_usec) / 1000);
+
+ if ((hc_known_servers[hash] == adr) && (abs(delta) < 10000)) continue;
+ houselog_event ("SERVER", server->name, "ACTIVE",
+ "STRATUM %d, DELTA %d MS", server->stratum, delta);
+
+ hc_known_servers[hash] = adr;
+ }
+ server->logged = 1;
+ }
+ LastActivityCheck = now;
+ }
}
static void *hc_http_attach (const char *name) {
@@ -474,6 +561,7 @@ void hc_http (int argc, const char **argv) {
houseportal_initialize (argc, argv);
use_houseportal = 1;
}
+ houselog_initialize ("ntp", argc, argv);
echttp_cors_allow_method("GET");
echttp_protect (0, hc_protect);
@@ -485,6 +573,7 @@ void hc_http (int argc, const char **argv) {
echttp_route_uri ("/ntp/server", hc_http_ntp);
echttp_static_route ("/", "/usr/local/share/house/public");
echttp_background (&hc_background);
+ houselog_event ("SERVICE", "ntp", "STARTED", "ON %s", houselog_host());
echttp_loop();
exit (0);
}
diff --git a/hc_ntp.c b/hc_ntp.c
index 3ac43df..eff3b74 100644
--- a/hc_ntp.c
+++ b/hc_ntp.c
@@ -305,6 +305,7 @@ static void hc_ntp_broadcastmsg (const ntpHeaderV3 *head,
hc_ntp_status_db->pool[sender].stratum = head->stratum;
hc_ntp_get_timestamp
(&(hc_ntp_status_db->pool[sender].origin), &(head->transmit));
+ hc_ntp_status_db->pool[sender].logged = 0;
// Elect a time source. Choose the lowest stratum available.
//
@@ -413,6 +414,7 @@ static void hc_ntp_requestmsg (const ntpHeaderV3 *head,
(&(hc_ntp_status_db->clients[hc_ntp_client_cursor].origin),
&(ntpResponse.origin));
hc_ntp_status_db->clients[hc_ntp_client_cursor].local = *receive;
+ hc_ntp_status_db->clients[hc_ntp_client_cursor].logged = 0;
}
diff --git a/hc_ntp.h b/hc_ntp.h
index d590de5..0d0f89f 100644
--- a/hc_ntp.h
+++ b/hc_ntp.h
@@ -44,6 +44,7 @@ struct hc_ntp_client {
struct sockaddr_in address;
struct timeval origin;
struct timeval local;
+ int logged;
};
struct hc_ntp_server {
@@ -52,6 +53,7 @@ struct hc_ntp_server {
short stratum;
struct sockaddr_in address;
char name[48];
+ int logged;
};
typedef struct {
diff --git a/public/events.html b/public/events.html
new file mode 100644
index 0000000..846f9c3
--- /dev/null
+++ b/public/events.html
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Time |
+ Category |
+ Name |
+ Action |
+ Description |
+
+
+
+
+
diff --git a/public/index.html b/public/index.html
index bd9e37c..58c0c79 100644
--- a/public/index.html
+++ b/public/index.html
@@ -68,6 +68,7 @@
Portal |
Clock |
+ Events |