osmo-pcap-server: Write the pcap files to disk, roll them over
diff --git a/src/osmo_server_main.c b/src/osmo_server_main.c
index 54a5f00..5c1ad58 100644
--- a/src/osmo_server_main.c
+++ b/src/osmo_server_main.c
@@ -171,7 +171,6 @@
 	/* seed the PRNG */
 	srand(time(NULL));
 
-
 	signal(SIGINT, &signal_handler);
 	signal(SIGABRT, &signal_handler);
 	signal(SIGUSR1, &signal_handler);
diff --git a/src/osmo_server_network.c b/src/osmo_server_network.c
index 19e5c3c..fb08722 100644
--- a/src/osmo_server_network.c
+++ b/src/osmo_server_network.c
@@ -22,6 +22,7 @@
 
 #include <osmo-pcap/osmo_pcap_server.h>
 #include <osmo-pcap/common.h>
+#include <osmo-pcap/wireformat.h>
 
 #include <osmocom/core/socket.h>
 #include <osmocom/core/talloc.h>
@@ -30,6 +31,7 @@
 #include <sys/socket.h>
 #include <sys/types.h>
 
+#include <fcntl.h>
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
@@ -48,6 +50,96 @@
 	}
 }
 
+static void restart_pcap(struct osmo_pcap_conn *conn)
+{
+	time_t now = time(NULL);
+	struct tm *tm = localtime(&now);
+	char *filename;
+	int rc;
+
+	if (conn->local_fd >= 0) {
+		close(conn->local_fd);
+		conn->local_fd = -1;
+	}
+
+
+	filename = talloc_asprintf(conn, "%s/trace-%s-%d%.2d%.2d_%.2d%.2d%.2d.pcap",
+				   conn->server->base_path, conn->name,
+				   tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+				   tm->tm_hour, tm->tm_min, tm->tm_sec);
+	conn->local_fd = creat(filename, S_IRUSR);
+	if (conn->local_fd < 0) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to file: '%s'\n", filename);
+		return;
+	}
+
+	rc = write(conn->local_fd, &conn->file_hdr, sizeof(conn->file_hdr));
+	if (rc != sizeof(conn->file_hdr)) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to write the header: %d\n", errno);
+		close(conn->local_fd);
+		conn->local_fd = -1;
+		return;
+	}
+
+	conn->last_write = *tm;
+	talloc_free(filename);
+}
+
+static void link_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
+{
+	struct pcap_file_header *hdr;
+
+	if (data->len != sizeof(*hdr)) {
+		LOGP(DSERVER, LOGL_ERROR, "The pcap_file_header does not fit.\n");
+		close_connection(conn);
+		return;
+	}
+
+	hdr = (struct pcap_file_header *) &data->data[0];
+	if (conn->local_fd < 0) {
+		conn->file_hdr = *hdr;
+		restart_pcap(conn);
+	} else if (memcmp(&conn->file_hdr, hdr, sizeof(*hdr)) != 0) {
+		conn->file_hdr = *hdr;
+		restart_pcap(conn);
+	}
+}
+
+/*
+ * Check if we are past the limit or on a day change
+ */
+static void write_data(struct osmo_pcap_conn *conn, struct osmo_pcap_data *data)
+{
+	time_t now = time(NULL);
+	struct tm *tm = localtime(&now);
+	int rc;
+
+	if (conn->local_fd < -1) {
+		LOGP(DSERVER, LOGL_ERROR, "No file is open. close connection.\n");
+		close_connection(conn);
+		return; 
+	}
+
+	off_t cur = lseek(conn->local_fd, 0, SEEK_CUR);
+	if (cur > conn->server->max_size) {
+		LOGP(DSERVER, LOGL_NOTICE, "Rolling over file for %s\n", conn->name);
+		restart_pcap(conn);
+	} else if (conn->last_write.tm_mday != tm->tm_mday ||
+		   conn->last_write.tm_mon != tm->tm_mon ||
+		   conn->last_write.tm_year != tm->tm_year) {
+		LOGP(DSERVER, LOGL_NOTICE, "Rolling over file for %s\n", conn->name);
+		restart_pcap(conn);
+	}
+
+	conn->last_write = *tm;
+	rc = write(conn->local_fd, &data->data[0], data->len);
+	if (rc != data->len) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to write for %s\n", conn->name);
+		close_connection(conn);
+	}
+}
+
+
 void osmo_pcap_server_delete(struct osmo_pcap_conn *conn)
 {
 	close_connection(conn);
@@ -55,7 +147,6 @@
 	talloc_free(conn);
 }
 
-
 struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
 					     const char *name)
 {
@@ -81,18 +172,43 @@
 
 static int read_cb(struct osmo_fd *fd, unsigned int what)
 {
+	struct osmo_pcap_data *data;
 	struct osmo_pcap_conn *conn;
 	char buf[4096];
 	int rc;
 
 	conn = fd->data;
-	rc = read(fd->fd, buf, sizeof(buf));
-	if (rc < 0) {
+	data = (struct osmo_pcap_data *) &buf[0];
+
+	rc = read(fd->fd, buf, sizeof(*data));
+	if (rc != sizeof(*data)) {
 		LOGP(DSERVER, LOGL_ERROR, "Failed to read from %s\n", conn->name);
 		close_connection(conn);
 		return -1;
 	}
 
+	if (data->len > 2000) {
+		LOGP(DSERVER, LOGL_ERROR, "Unplausible result %u\n", data->len);
+		close_connection(conn);
+		return -1;
+	}
+
+	rc = read(fd->fd, &data->data[0], data->len);
+	if (rc != data->len) {
+		LOGP(DSERVER, LOGL_ERROR, "Two short packet %d\n", rc);
+		close_connection(conn);
+		return -1;
+	}
+
+	switch (data->type) {
+	case PKT_LINK_HDR:
+		link_data(conn, data);
+		break;
+	case PKT_LINK_DATA:
+		write_data(conn, data);
+		break;
+	}
+
 	return 0;
 }