diff options
Diffstat (limited to 'src/osmo_server_network.c')
-rw-r--r-- | src/osmo_server_network.c | 113 |
1 files changed, 112 insertions, 1 deletions
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 @@ struct osmo_pcap_conn *osmo_pcap_server_find(struct osmo_pcap_server *server, 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; } -int osmo_pcap_server_listen(struct osmo_pcap_server *server) +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) +{ + 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; +} |