aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo_server_network.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/osmo_server_network.c')
-rw-r--r--src/osmo_server_network.c122
1 files changed, 119 insertions, 3 deletions
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 close_connection(struct osmo_pcap_conn *conn)
}
}
+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 @@ void osmo_pcap_server_delete(struct osmo_pcap_conn *conn)
talloc_free(conn);
}
-
struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
const char *name)
{
@@ -81,18 +172,43 @@ struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
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;
}