Create DNS thread

When possible we should use DNS hostnames instead of IP addresses as
logfile names.  But gethostbyaddr() can block indefinitely, so run that
command from a dedicated thread.  If it blocks, we just write to the ip
address name.

Signed-off-by: Joern Engel <joern@logfs.org>
diff --git a/Makefile b/Makefile
index 3c5c45b..985cb20 100644
--- a/Makefile
+++ b/Makefile
@@ -2,6 +2,7 @@
 VERSION=0.1.0
 
 CFLAGS += -Wall -g -O2 -DVERSION="\"$(VERSION)\""
+LDFLAGS += -lpthread
 
 cancd: cancd.o btree.o
 
diff --git a/cancd.c b/cancd.c
index 070a9db..b560ff0 100644
--- a/cancd.c
+++ b/cancd.c
@@ -32,7 +32,10 @@
 #include <getopt.h>
 #include <libgen.h>
 #include <limits.h>
+#include <netdb.h>
 #include <netinet/in.h>
+#include <pthread.h>
+#include <semaphore.h>
 #include <signal.h>
 #include <stdarg.h>
 #include <stdio.h>
@@ -41,6 +44,7 @@
 #include <syslog.h>
 #include <sys/socket.h>
 #include <sys/stat.h>
+#include <sys/time.h>
 #include <sys/types.h>
 #include <time.h>
 #include <unistd.h>
@@ -85,7 +89,10 @@
 /* What signal did we catch? */
 sig_atomic_t caught_sig = 0;
 
+
 struct btree_head32 btree;
+pthread_t dns_thread;
+sem_t dns_sem;
 
 struct source_ip {
 	const char *filename;
@@ -360,6 +367,7 @@
 		sip->filename = get_path(&addr->sin_addr);
 		err = btree_insert32(&btree, key, sip);
 		assert(!err);
+		sem_post(&dns_sem);
 	}
 	return sip;
 }
@@ -633,6 +641,41 @@
 	return 0;
 }
 
+static void dns_visitor(void *_sip, long unused, u32 ip, size_t unused2)
+{
+	struct source_ip *sip = _sip;
+	struct hostent *he;
+	const char *old, *new;
+
+	he = gethostbyaddr(&ip, 4, AF_INET);
+	if (!he)
+		return;
+	if (strcmp(he->h_name, sip->filename) == 0)
+		return;
+	new = strdup(he->h_name);
+	if (!new)
+		return;
+	old = sip->filename;
+	sip->filename = new;
+	free((void *)old);
+}
+
+void *dns_thread_func(void *_arg)
+{
+	struct timespec ts;
+	struct timeval tv;
+
+	for (;;) {
+		/* Wait for 60min or the main thread to wake us */
+		gettimeofday(&tv, NULL);
+		ts.tv_sec = tv.tv_sec + 3600;
+		ts.tv_nsec = 0;
+		sem_timedwait(&dns_sem, &ts);
+		/* Do DNS lookups for all hosts */
+		btree_visitor32(&btree, 0, dns_visitor);
+	}
+}
+
 int main(int argc, char *argv[])
 {
 	int rc;
@@ -641,21 +684,20 @@
 	rc = parse_options(argc, argv);
 	if (rc)
 		return rc;
-
 	rc = init_self();
 	if (rc)
 		goto out;
-
 	rc = open_socket();
 	if (rc)
 		goto out;
+	rc = pthread_create(&dns_thread, NULL, dns_thread_func, NULL);
+	if (rc)
+		goto out;
 
 	rc = run();
 
 	close(sock_fd);
-
 out:
 	closelog();
-
 	return rc;
 }