osmo-pcap-server: Accept the client connection from a given host

We now read from a given system.
diff --git a/src/osmo_server_network.c b/src/osmo_server_network.c
index 6562829..19e5c3c 100644
--- a/src/osmo_server_network.c
+++ b/src/osmo_server_network.c
@@ -23,12 +23,34 @@
 #include <osmo-pcap/osmo_pcap_server.h>
 #include <osmo-pcap/common.h>
 
+#include <osmocom/core/socket.h>
 #include <osmocom/core/talloc.h>
 
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include <errno.h>
 #include <string.h>
+#include <unistd.h>
+
+static void close_connection(struct osmo_pcap_conn *conn)
+{
+	if (conn->rem_fd.fd != -1) {
+		close(conn->rem_fd.fd);
+		conn->rem_fd.fd = -1;
+		osmo_fd_unregister(&conn->rem_fd);
+	}
+
+	if (conn->local_fd != -1) {
+		close(conn->local_fd);
+		conn->local_fd = -1;
+	}
+}
 
 void osmo_pcap_server_delete(struct osmo_pcap_conn *conn)
 {
+	close_connection(conn);
 	llist_del(&conn->entry);
 	talloc_free(conn);
 }
@@ -50,11 +72,100 @@
 		return NULL;
 	}
 
+	conn->name = talloc_strdup(conn, name);
+	conn->rem_fd.fd = -1;
+	conn->server = server;
 	llist_add_tail(&conn->entry, &server->conn);
 	return conn;
 }
 
+static int read_cb(struct osmo_fd *fd, unsigned int what)
+{
+	struct osmo_pcap_conn *conn;
+	char buf[4096];
+	int rc;
+
+	conn = fd->data;
+	rc = read(fd->fd, buf, sizeof(buf));
+	if (rc < 0) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to read from %s\n", conn->name);
+		close_connection(conn);
+		return -1;
+	}
+
+	return 0;
+}
+
+static void new_connection(struct osmo_pcap_server *server,
+			   struct osmo_pcap_conn *client, int new_fd)
+{
+	close_connection(client);
+
+	memset(&client->file_hdr, 0, sizeof(client->file_hdr));
+	client->rem_fd.fd = new_fd;
+	if (osmo_fd_register(&client->rem_fd) != 0) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to register fd.\n");
+		client->rem_fd.fd = -1;
+		close(new_fd);
+		return;
+	}
+
+	client->rem_fd.data = client;
+	client->rem_fd.when = BSC_FD_READ;
+	client->rem_fd.cb = read_cb;
+}
+
+static int accept_cb(struct osmo_fd *fd, unsigned int when)
+{
+	struct osmo_pcap_conn *conn;
+	struct osmo_pcap_server *server;
+	struct sockaddr_in addr;
+	socklen_t size = sizeof(addr);
+	int new_fd;
+
+	new_fd = accept(fd->fd, (struct sockaddr *) &addr, &size);
+	if (new_fd < 0) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to accept socket: %d\n", errno);
+		return -1;
+	}
+
+	server = fd->data;
+	llist_for_each_entry(conn, &server->conn, entry) {
+		if (conn->remote_addr.s_addr == addr.sin_addr.s_addr) {
+			LOGP(DSERVER, LOGL_NOTICE,
+			     "New connection from %s\n", conn->name);
+			new_connection(server, conn, new_fd);
+			return 0;
+		}
+	}
+
+	LOGP(DSERVER, LOGL_ERROR,
+	     "Failed to find client for %s\n", inet_ntoa(addr.sin_addr));
+	close(new_fd);
+	return -1;
+}
+
 int osmo_pcap_server_listen(struct osmo_pcap_server *server)
 {
-	return -1;
+	int fd;
+
+	fd = osmo_sock_init(AF_INET, SOCK_STREAM, IPPROTO_TCP,
+			    server->addr, server->port, 1);
+	if (fd < 0) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to create the server socket.\n");
+		return -1;
+	}
+
+	server->listen_fd.fd = fd;
+	server->listen_fd.when = BSC_FD_READ;
+	server->listen_fd.cb = accept_cb;
+	server->listen_fd.data = server;
+
+	if (osmo_fd_register(&server->listen_fd) != 0) {
+		LOGP(DSERVER, LOGL_ERROR, "Failed to register the socket.\n");
+		close(fd);
+		return -1;
+	}
+
+	return 0;
 }
diff --git a/src/osmo_server_vty.c b/src/osmo_server_vty.c
index 5d7d23d..2a40ef3 100644
--- a/src/osmo_server_vty.c
+++ b/src/osmo_server_vty.c
@@ -107,7 +107,8 @@
 	}
 
 	talloc_free(conn->remote_host);
-	conn->remote_host = talloc_strdup(pcap_server, argv[0]);
+	conn->remote_host = talloc_strdup(pcap_server, argv[1]);
+	inet_aton(argv[1], &conn->remote_addr);
 
 	return CMD_SUCCESS;
 }