aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/osmo-pcap/osmo_pcap_server.h10
-rw-r--r--src/osmo_server_network.c72
2 files changed, 60 insertions, 22 deletions
diff --git a/include/osmo-pcap/osmo_pcap_server.h b/include/osmo-pcap/osmo_pcap_server.h
index a94724c..b408c47 100644
--- a/include/osmo-pcap/osmo_pcap_server.h
+++ b/include/osmo-pcap/osmo_pcap_server.h
@@ -36,6 +36,10 @@
struct osmo_pcap_server;
+
+#define STATE_INITIAL 0
+#define STATE_DATA 1
+
struct osmo_pcap_conn {
/* list of connections */
struct llist_head entry;
@@ -55,6 +59,12 @@ struct osmo_pcap_conn {
/* last time */
struct tm last_write;
+
+ /* read buffering */
+ int state;
+ int pend;
+ char buf[4096];
+ struct osmo_pcap_data *data;
};
struct osmo_pcap_server {
diff --git a/src/osmo_server_network.c b/src/osmo_server_network.c
index d1948a8..3a4ef27 100644
--- a/src/osmo_server_network.c
+++ b/src/osmo_server_network.c
@@ -167,49 +167,76 @@ struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server,
conn->rem_fd.fd = -1;
conn->local_fd = -1;
conn->server = server;
+ conn->data = (struct osmo_pcap_data *) &conn->buf[0];
llist_add_tail(&conn->entry, &server->conn);
return conn;
}
-static int read_cb(struct osmo_fd *fd, unsigned int what)
+static int read_cb_initial(struct osmo_fd *fd, struct osmo_pcap_conn *conn)
{
- struct osmo_pcap_data *data;
- struct osmo_pcap_conn *conn;
- char buf[4096];
int rc;
+ rc = read(fd->fd, conn->buf, sizeof(*conn->data));
- conn = fd->data;
- data = (struct osmo_pcap_data *) &buf[0];
-
- rc = read(fd->fd, buf, sizeof(*data));
- if (rc != sizeof(*data)) {
+ if (rc != sizeof(*conn->data)) {
LOGP(DSERVER, LOGL_ERROR, "Failed to read from %s\n", conn->name);
close_connection(conn);
return -1;
}
- data->len = ntohs(data->len);
- if (data->len > 2000) {
- LOGP(DSERVER, LOGL_ERROR, "Unplausible result %u\n", data->len);
+ conn->data->len = ntohs(conn->data->len);
+ if (conn->data->len > 2000) {
+ LOGP(DSERVER, LOGL_ERROR, "Unplausible result %u\n", conn->data->len);
close_connection(conn);
return -1;
}
- rc = read(fd->fd, &data->data[0], data->len);
- if (rc != data->len) {
+ conn->state = STATE_DATA;
+ conn->pend = conn->data->len;
+ return 0;
+}
+
+static int read_cb_data(struct osmo_fd *fd, struct osmo_pcap_conn *conn)
+{
+ int rc;
+ rc = read(fd->fd, &conn->data->data[conn->data->len - conn->pend], conn->pend);
+ if (rc <= 0) {
LOGP(DSERVER, LOGL_ERROR,
- "Too short packet. Got %d, wanted %d\n", rc, data->len);
+ "Too short packet. Got %d, wanted %d\n", rc, conn->data->len);
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;
+ conn->pend -= rc;
+ if (conn->pend < 0) {
+ LOGP(DSERVER, LOGL_ERROR,
+ "Someone got the pending read wrong: %d\n", conn->pend);
+ close_connection(conn);
+ return -1;
+ } else if (conn->pend == 0) {
+ conn->state = STATE_INITIAL;
+ switch (conn->data->type) {
+ case PKT_LINK_HDR:
+ link_data(conn, conn->data);
+ break;
+ case PKT_LINK_DATA:
+ write_data(conn, conn->data);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int read_cb(struct osmo_fd *fd, unsigned int what)
+{
+ struct osmo_pcap_conn *conn;
+
+ conn = fd->data;
+
+ if (conn->state == STATE_INITIAL) {
+ return read_cb_initial(fd, conn);
+ } else if (conn->state == STATE_DATA) {
+ return read_cb_data(fd, conn);
}
return 0;
@@ -232,6 +259,7 @@ static void new_connection(struct osmo_pcap_server *server,
client->rem_fd.data = client;
client->rem_fd.when = BSC_FD_READ;
client->rem_fd.cb = read_cb;
+ client->state = STATE_INITIAL;
}
static int accept_cb(struct osmo_fd *fd, unsigned int when)