Add per-ip cache

Currently used for newlines and filename.

Signed-off-by: Joern Engel <joern@logfs.org>
diff --git a/cancd.c b/cancd.c
index 8c58b1c..070a9db 100644
--- a/cancd.c
+++ b/cancd.c
@@ -26,6 +26,7 @@
 #include <features.h>
 
 #include <arpa/inet.h>
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <getopt.h>
@@ -45,6 +46,7 @@
 #include <unistd.h>
 
 #include "kernel-list.h"
+#include "btree.h"
 
 #ifndef VERSION
 #define VERSION         "0.1.0"
@@ -83,6 +85,14 @@
 /* What signal did we catch? */
 sig_atomic_t caught_sig = 0;
 
+struct btree_head32 btree;
+
+struct source_ip {
+	const char *filename;
+	const char *tmpfilename;
+	int had_newline;
+};
+
 void handler(int signum)
 {
 	caught_sig = signum;
@@ -297,7 +307,7 @@
 	return 0;
 }
 
-static int write_formatted(int fd, char *buf, int count)
+static int write_formatted(int fd, struct source_ip *sip, char *buf, int count)
 {
 	const char *format = "%b %d %H:%M:%S ";
 	char *end;
@@ -305,7 +315,6 @@
 	size_t n, len, err;
 	time_t now = time(NULL);
 	struct tm *tm = localtime(&now);
-	int had_newline = 0;
 
 	/*
 	 * buf must be NUL-terminated.  We add 1 to count for the terminating
@@ -314,7 +323,7 @@
 	 */
 	count += 1;
 	while (count > 1) {
-		if (had_newline) {
+		if (sip->had_newline) {
 			n = strftime(timestr, sizeof(timestr), format, tm);
 			err = do_write(fd, timestr, n);
 			if (err)
@@ -324,7 +333,7 @@
 		if (!end) {
 			/* no newline, just write what we have */
 			do_write(fd, buf, count - 1);
-			had_newline = 0;
+			sip->had_newline = 0;
 			break;
 		}
 		len = end - buf + 1;
@@ -333,17 +342,36 @@
 			return err;
 		buf += len;
 		count -= len;
-		had_newline = 1;
+		sip->had_newline = 1;
 	}
 	return 0;
 }
 
+static struct source_ip *get_source_ip(struct sockaddr_in *addr)
+{
+	u32 key = addr->sin_addr.s_addr;
+	struct source_ip *sip;
+	int err;
+
+	sip = btree_lookup32(&btree, key);
+	if (!sip) {
+		sip = calloc(1, sizeof(*sip));
+		sip->had_newline = 1;
+		sip->filename = get_path(&addr->sin_addr);
+		err = btree_insert32(&btree, key, sip);
+		assert(!err);
+	}
+	return sip;
+}
+
 static void do_output(char *buf, int len, struct sockaddr_in *addr, socklen_t socklen)
 {
 	int fd, rc;
-	char *name, *tmp, *dir;
+	const char *name;
+	char *tmp, *dir;
+	struct source_ip *sip = get_source_ip(addr);
 
-	name = get_path(&addr->sin_addr);
+	name = sip->filename;
 	if (!name)
 		return;
 
@@ -364,10 +392,9 @@
 	if (fd < 0)
 		syslog(LOG_ERR, "Unable to open \"%s\": %s", name, strerror(errno));
 	else {
-		write_formatted(fd, buf, len);
+		write_formatted(fd, sip, buf, len);
 		close(fd);
 	}
-	free(name);
 }
 
 static int set_blocking(int blocking)
@@ -610,6 +637,7 @@
 {
 	int rc;
 
+	btree_init32(&btree);
 	rc = parse_options(argc, argv);
 	if (rc)
 		return rc;