diff mbox

[05/10] gtphub: populate API impl from test prog

Message ID 1444227508-26608-6-git-send-email-nhofmeyr@sysmocom.de
State Superseded
Headers show

Commit Message

Neels Hofmeyr Oct. 7, 2015, 2:18 p.m. UTC
Sponsored-by: On-Waves ehi
---
 openbsc/src/gprs/gtphub.c      | 209 ++++++++++++++++++++++++++++++++++++++++-
 openbsc/src/gprs/gtphub_main.c | 183 +++++++++++-------------------------
 2 files changed, 261 insertions(+), 131 deletions(-)

Comments

Holger Freyther Oct. 8, 2015, 9:05 a.m. UTC | #1
> On 07 Oct 2015, at 16:18, Neels Hofmeyr <nhofmeyr@sysmocom.de> wrote:
> 
> +/* TODO move this to osmocom/core/linuxlist.h ? */
> +#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
> +#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry)

Why the null check? I mean

struct *foo = llist_first(list);
if (!foo)
	return

vs.

if (llist_empty(list))
	return;
struct *foo = llist_first(list);

has no difference?


> +int servers_read_cb(struct osmo_fd *servers_ofd, unsigned int what)
> +{
> +	unsigned int port_idx = servers_ofd->priv_nr;
> +	OSMO_ASSERT(port_idx < GTPH_PORT_N);
> +	LOG("reading from servers socket (%s)\n", gtphub_port_idx_names[port_idx]);
> +	if (!(what & BSC_FD_READ))
> +		return 0;
> +
> +	struct gtphub *hub = servers_ofd->data;
> +
> +	/* TODO this will not be hardcoded. */
> +	struct gtphub_peer *client = llist_first(&hub->to_clients[port_idx].peers,
> +						 struct gtphub_peer, entry);

interesting that you are the first to use the llist in this way. As you will track
multiple peers the need for a llist_first will vanish?
Neels Hofmeyr Oct. 8, 2015, 11:58 a.m. UTC | #2
On Thu, Oct 08, 2015 at 11:05:21AM +0200, Holger Freyther wrote:
> > +#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
> > +#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry)
> 
> Why the null check? I mean
> 
> struct *foo = llist_first(list);
> if (!foo)
> 	return
> 
> vs.
> 
> if (llist_empty(list))
> 	return;
> struct *foo = llist_first(list);
> 
> has no difference?

Almost. All it does is make sure I don't forget the emptiness check,
really... a NULL dereference will more reliably result in a segfault than
dereferencing a list item struct from an llist_head. But anyway: ...

> > +	/* TODO this will not be hardcoded. */
> > +	struct gtphub_peer *client = llist_first(&hub->to_clients[port_idx].peers,
> > +						 struct gtphub_peer, entry);
> 
> interesting that you are the first to use the llist in this way. As you will track
> multiple peers the need for a llist_first will vanish?

... Indeed.

~Neels
diff mbox

Patch

diff --git a/openbsc/src/gprs/gtphub.c b/openbsc/src/gprs/gtphub.c
index ffe0d4a..a8bd276 100644
--- a/openbsc/src/gprs/gtphub.c
+++ b/openbsc/src/gprs/gtphub.c
@@ -20,26 +20,231 @@ 
  */
 
 #include <string.h>
+#include <errno.h>
+#include <netinet/in.h>
 
 #include <openbsc/gtphub.h>
 #include <openbsc/debug.h>
 
 #include <osmocom/core/utils.h>
 #include <osmocom/core/logging.h>
+#include <osmocom/core/socket.h>
 
 void *osmo_gtphub_ctx;
 
 #define LOGERR(fmt, args...) \
 	LOGP(DGTPHUB, LOGL_ERROR, fmt, ##args)
 
+#define LOG(fmt, args...) \
+	LOGP(DGTPHUB, LOGL_NOTICE, fmt, ##args)
+
+/* TODO move this to osmocom/core/select.h ? */
+typedef int (*osmo_fd_cb_t)(struct osmo_fd *fd, unsigned int what);
+
+/* TODO move this to osmocom/core/linuxlist.h ? */
+#define __llist_first(head) (((head)->next == (head)) ? NULL : (head)->next)
+#define llist_first(head, type, entry) llist_entry(__llist_first(head), type, entry)
+
+
+/* general */
+
+const char* const gtphub_port_idx_names[GTPH_PORT_N] = {
+	"CTRL",
+	"USER",
+};
+
+
+/* gtphub */
+
 void gtphub_zero(struct gtphub *hub)
 {
 	memset(hub, '\0', sizeof(*hub));
 }
 
+static int gtphub_sock_init(struct osmo_fd *ofd,
+			    const struct gtphub_cfg_addr *addr,
+			    osmo_fd_cb_t cb,
+			    void *data,
+			    int ofd_id)
+{
+	ofd->when = BSC_FD_READ;
+	ofd->cb = cb;
+	ofd->data = data;
+	ofd->priv_nr = ofd_id;
+
+	int rc;
+	rc = osmo_sock_init_ofd(ofd,
+				AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+				addr->addr_str, addr->port,
+				OSMO_SOCK_F_BIND);
+	if (rc < 1) {
+		LOGERR("Cannot bind to %s port %d (rc %d)\n",
+		       addr->addr_str, (int)addr->port, rc);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int gtphub_gtp_bind_init(struct gtphub_bind *b,
+				const struct gtphub_cfg_bind *cfg,
+				osmo_fd_cb_t cb, void *cb_data,
+				unsigned int ofd_id)
+{
+	memset(b, '\0', sizeof(*b));
+
+	INIT_LLIST_HEAD(&b->peers);
+
+	if (gtphub_sock_init(&b->ofd, &cfg->bind, cb, cb_data, ofd_id) != 0)
+		return -1;
+	return 0;
+}
+
+/* Recv datagram from from->fd, optionally write sender's address to *from_addr
+ * and *from_addr_len, parse datagram as GTP, and forward on to to->fd using
+ * *to_addr. to_addr may be NULL, if an address is set on to->fd. */
+static int gtp_relay(struct osmo_fd *from,
+		     struct sockaddr_storage *from_addr,
+		     socklen_t *from_addr_len,
+		     struct osmo_fd *to,
+		     struct sockaddr_storage *to_addr,
+		     socklen_t to_addr_len)
+{
+	static uint8_t buf[4096];
+
+	/* recvfrom requires the available length to be set in *from_addr_len. */
+	if (from_addr_len && from_addr)
+		*from_addr_len = sizeof(*from_addr);
+
+	errno = 0;
+	ssize_t received = recvfrom(from->fd, buf, sizeof(buf), 0,
+				    (struct sockaddr*)from_addr, from_addr_len);
+
+	if (received <= 0) {
+		if (errno != EAGAIN)
+			LOGERR("error: %s\n", strerror(errno));
+		return -errno;
+	}
+
+	if (from_addr) {
+		LOG("from %s\n", osmo_hexdump((uint8_t*)from_addr, *from_addr_len));
+	}
+
+	if (received <= 0) {
+		LOGERR("error: %s\n", strerror(errno));
+		return -EINVAL;
+	}
+
+	/* insert magic here */
+
+	errno = 0;
+	ssize_t sent = sendto(to->fd, buf, received, 0,
+			      (struct sockaddr*)to_addr, to_addr_len);
+
+	if (to_addr) {
+		LOG("to %s\n", osmo_hexdump((uint8_t*)to_addr, to_addr_len));
+	}
+
+	if (sent == -1) {
+		LOGERR("error: %s\n", strerror(errno));
+		return -EINVAL;
+	}
+
+	if (sent != received)
+		LOGERR("sent(%d) != received(%d)\n", (int)sent, (int)received);
+	else
+		LOG("%d b ok\n", (int)sent);
+
+	return 0;
+}
+
+int servers_read_cb(struct osmo_fd *servers_ofd, unsigned int what)
+{
+	unsigned int port_idx = servers_ofd->priv_nr;
+	OSMO_ASSERT(port_idx < GTPH_PORT_N);
+	LOG("reading from servers socket (%s)\n", gtphub_port_idx_names[port_idx]);
+	if (!(what & BSC_FD_READ))
+		return 0;
+
+	struct gtphub *hub = servers_ofd->data;
+
+	/* TODO this will not be hardcoded. */
+	struct gtphub_peer *client = llist_first(&hub->to_clients[port_idx].peers,
+						 struct gtphub_peer, entry);
+	if (!client) {
+		LOGERR("no client");
+		return 0;
+	}
+
+	return gtp_relay(servers_ofd, NULL, NULL,
+			 &hub->to_clients[port_idx].ofd,
+			 &client->addr.a, client->addr.l);
+}
+
+int clients_read_cb(struct osmo_fd *clients_ofd, unsigned int what)
+{
+	unsigned int port_idx = clients_ofd->priv_nr;
+	OSMO_ASSERT(port_idx < GTPH_PORT_N);
+	LOG("reading from clients socket (%s)\n", gtphub_port_idx_names[port_idx]);
+
+	if (!(what & BSC_FD_READ))
+		return 0;
+
+	struct gtphub *hub = clients_ofd->data;
+
+	/* TODO this will not be hardcoded. */
+	/* so far just remembering the last client */
+	struct gtphub_peer *server = llist_first(&hub->to_servers[port_idx].peers,
+						 struct gtphub_peer, entry);
+	if (!server) {
+		LOGERR("no server to send to\n");
+		return 0;
+	}
+
+	struct gtphub_peer *client = llist_first(&hub->to_clients[port_idx].peers,
+						 struct gtphub_peer, entry);
+	if (!client)
+		client = gtphub_peer_new(&hub->to_clients[port_idx]);
+
+	return gtp_relay(clients_ofd, &client->addr.a, &client->addr.l,
+			 &hub->to_servers[port_idx].ofd,
+			 &server->addr.a, server->addr.l);
+}
+
 int gtphub_init(struct gtphub *hub, struct gtphub_cfg *cfg)
 {
-	LOGERR("%s not implemented\n", __func__);
-	return -1;
+	gtphub_zero(hub);
+
+	int port_id;
+	for (port_id = 0; port_id < GTPH_PORT_N; port_id++) {
+		int rc;
+		rc = gtphub_gtp_bind_init(&hub->to_servers[port_id],
+					  &cfg->to_servers[port_id],
+					  servers_read_cb, hub, port_id);
+		if (rc < 0)
+			return rc;
+
+		rc = gtphub_gtp_bind_init(&hub->to_clients[port_id],
+					  &cfg->to_clients[port_id],
+					  clients_read_cb, hub, port_id);
+		if (rc < 0)
+			return rc;
+
+		/* ... */
+	}
+	return 0;
+}
+
+struct gtphub_peer *gtphub_peer_new(struct gtphub_bind *bind)
+{
+	struct gtphub_peer *n = talloc_zero(osmo_gtphub_ctx, struct gtphub_peer);
+	llist_add(&n->entry, &bind->peers);
+	return n;
+}
+
+void gtphub_peer_del(struct gtphub_peer *peer)
+{
+	llist_del(&peer->entry);
+	talloc_free(peer);
 }
 
diff --git a/openbsc/src/gprs/gtphub_main.c b/openbsc/src/gprs/gtphub_main.c
index f8bcd59..104cbfd 100644
--- a/openbsc/src/gprs/gtphub_main.c
+++ b/openbsc/src/gprs/gtphub_main.c
@@ -20,27 +20,17 @@ 
  */
 
 #include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <errno.h>
 
-#include <sys/socket.h>
-#include <netinet/in.h>
-
 #define _GNU_SOURCE
 #include <getopt.h>
 
 #include <osmocom/core/application.h>
-#include <osmocom/core/utils.h>
-#include <osmocom/core/socket.h>
-#include <osmocom/core/select.h>
 #include <osmocom/core/logging.h>
+#include <osmocom/core/utils.h>
 
 #include <openbsc/debug.h>
-
-#include <gtp.h>
-
-#include <unistd.h>
+#include <openbsc/gtphub.h>
 
 #define LOGERR(fmt, args...) \
 	LOGP(DGTPHUB, LOGL_ERROR, fmt, ##args)
@@ -112,7 +102,6 @@  int osmo_sockaddr_init(struct sockaddr_storage *addr, socklen_t *addr_len,
 }
 
 
-void *tall_bsc_ctx;
 
 const char *gtphub_copyright =
 	"Copyright (C) 2015 sysmocom s.m.f.c GmbH <info@sysmocom.de>\r\n"
@@ -141,141 +130,77 @@  static const struct log_info gtphub_log_info = {
 	.num_cat = ARRAY_SIZE(gtphub_categories),
 };
 
-/* Recv datagram from from->fd, optionally write sender's address to *from_addr
- * and *from_addr_len, parse datagram as GTP, and forward on to to->fd using
- * *to_addr. to_addr may be NULL, if an address is set on to->fd. */
-int gtp_relay(struct osmo_fd *from, struct sockaddr_storage *from_addr, socklen_t *from_addr_len,
-	      struct osmo_fd *to, struct sockaddr_storage *to_addr, socklen_t to_addr_len)
+void log_cfg(struct gtphub_cfg *cfg)
 {
-	static uint8_t buf[4096];
-
-	errno = 0;
-	ssize_t received = recvfrom(from->fd, buf, sizeof(buf), 0,
-				    (struct sockaddr*)from_addr, from_addr_len);
-
-	if (received <= 0) {
-		if (errno != EAGAIN)
-			LOGERR("error: %s\n", strerror(errno));
-		return -errno;
-	}
-
-	if (from_addr) {
-		LOG("from %s\n", osmo_hexdump((uint8_t*)from_addr, *from_addr_len));
-	}
-
-	if (received <= 0) {
-		LOGERR("error: %s\n", strerror(errno));
-		return -EINVAL;
-	}
-
-	/* insert magic here */
-
-	errno = 0;
-	ssize_t sent = sendto(to->fd, buf, received, 0,
-			      (struct sockaddr*)to_addr, to_addr_len);
-
-	if (to_addr) {
-		LOG("to %s\n", osmo_hexdump((uint8_t*)to_addr, to_addr_len));
-	}
-
-	if (sent == -1) {
-		LOGERR("error: %s\n", strerror(errno));
-		return -EINVAL;
-	}
-
-	if (sent != received)
-		LOGERR("sent(%d) != received(%d)\n", (int)sent, (int)received);
-	else
-		LOG("%d b ok\n", (int)sent);
-
-	return 0;
+	struct gtphub_cfg_addr *a;
+	a = &cfg->to_clients[GTPH_PORT_CONTROL].bind;
+	LOG("Clients bind, Control:    %s port %d\n",
+	    a->addr_str, a->port);
+	a = &cfg->to_clients[GTPH_PORT_USER].bind;
+	LOG("Clients bind, User:       %s port %d\n",
+	    a->addr_str, a->port);
+	a = &cfg->to_servers[GTPH_PORT_CONTROL].bind;
+	LOG("GTP server bind, Control: %s port %d\n",
+	    a->addr_str, a->port);
+	a = &cfg->to_servers[GTPH_PORT_USER].bind;
+	LOG("GTP server bind, User:    %s port %d\n",
+	    a->addr_str, a->port);
 }
 
-struct sockaddr_storage last_client_addr;
-socklen_t last_client_addr_len;
-struct sockaddr_storage server_addr;
-socklen_t server_addr_len;
-
-int clients_read_cb(struct osmo_fd *clients_ofd, unsigned int what)
+int main(int argc, char **argv)
 {
-	LOG("reading from clients socket\n");
-	struct osmo_fd *server_ofd = clients_ofd->data;
+	osmo_gtphub_ctx = talloc_named_const(NULL, 0, "osmo_gtphub");
 
-	if (!(what & BSC_FD_READ))
-		return 0;
-
-	last_client_addr_len = sizeof(last_client_addr);
-	return gtp_relay(clients_ofd, &last_client_addr, &last_client_addr_len,
-			 server_ofd, &server_addr, server_addr_len);
-}
-
-int server_read_cb(struct osmo_fd *server_ofd, unsigned int what)
-{
-	LOG("reading from server socket\n");
-	struct osmo_fd *clients_ofd = server_ofd->data;
+	osmo_init_logging(&gtphub_log_info);
 
-	if (!(what & BSC_FD_READ))
-		return 0;
+	int rc;
 
-	return gtp_relay(server_ofd, NULL, NULL,
-			 clients_ofd, &last_client_addr, last_client_addr_len);
-}
+	struct gtphub_cfg _cfg = {
+	.to_clients = {
+		{ .bind = {
+				.addr_str = "127.0.0.3",
+				.port = 2123,
+			  } },
+		{ .bind = {
+				.addr_str = "127.0.0.3",
+				.port = 2152,
+			  } },
+	},
+	.to_servers = {
+		{ .bind = {
+				.addr_str = "127.0.0.4",
+				.port = 2123,
+			  } },
+		{ .bind = {
+				.addr_str = "127.0.0.4",
+				.port = 2152,
+			  } },
+	},
+	};
 
-int main(int argc, char **argv)
-{
-	osmo_init_logging(&gtphub_log_info);
+	struct gtphub_cfg *cfg = &_cfg;
 
-	int rc;
+	struct gtphub _hub;
+	struct gtphub *hub = &_hub;
 
-	/* Which local interface to use to listen for GTP clients */
-	const char* clients_addr_str = "127.0.0.3";
-	uint16_t clients_port = 2123;
+	if (gtphub_init(hub, cfg) != 0)
+		return -1;
 
+	/* TODO this will not be configured, gtphub will have to find the
+	 * servers from incoming GTP PDUs. */
 	/* Where the GTP server sits that we're relaying for */
 	const char* server_addr_str = "127.0.0.2";
 	uint16_t server_port = 2123;
-
-	/* Which local interface to use to listen for the GTP server's
-	 * responses */
-	const char* server_rx_addr_str = "127.0.0.4";
-	uint16_t server_rx_port = 2123;
-
-	rc = osmo_sockaddr_init(&server_addr, &server_addr_len,
-				AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, server_addr_str, server_port);
+	struct gtphub_peer *test_server = gtphub_peer_new(&hub->to_servers[GTPH_PORT_CONTROL]);
+	rc = osmo_sockaddr_init(&test_server->addr.a, &test_server->addr.l,
+				AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP,
+				server_addr_str, server_port);
 	if (rc != 0) {
 		LOGERR("Cannot resolve '%s port %d'\n", server_addr_str, server_port);
 		exit(-1);
 	}
 
-	struct osmo_fd clients_ofd;
-	struct osmo_fd server_ofd;
-
-	memset(&clients_ofd, 0, sizeof(clients_ofd));
-	clients_ofd.when = BSC_FD_READ;
-	clients_ofd.cb = clients_read_cb;
-	clients_ofd.data = &server_ofd;
-
-	rc = osmo_sock_init_ofd(&clients_ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, clients_addr_str, clients_port, OSMO_SOCK_F_BIND);
-	if (rc < 1) {
-		LOGERR("Cannot bind to %s port %d\n", clients_addr_str, clients_port);
-		exit(-1);
-	}
-
-	memset(&server_ofd, 0, sizeof(server_ofd));
-	server_ofd.when = BSC_FD_READ;
-	server_ofd.cb = server_read_cb;
-	server_ofd.data = &clients_ofd;
-
-	rc = osmo_sock_init_ofd(&server_ofd, AF_UNSPEC, SOCK_DGRAM, IPPROTO_UDP, server_rx_addr_str, server_rx_port, OSMO_SOCK_F_BIND);
-	if (rc < 1) {
-		LOGERR("Cannot bind to %s port %d\n", server_rx_addr_str, server_rx_port);
-		exit(-1);
-	}
-
-	LOG("GTP server connection: %s port %d <--> %s port %d\n",
-	    server_rx_addr_str, (int)server_rx_port,
-	    server_addr_str, (int)server_port);
-	LOG("Listening for clients on %s port %d.\n", clients_addr_str, clients_port);
+	log_cfg(cfg);
 
 	int daemonize = 0;