Change in libosmo-netif[master]: Introduce osmo_prim_srv APIs

This is merely a historical archive of years 2008-2021, before the migration to mailman3.

A maintained and still updated list archive can be found at https://lists.osmocom.org/hyperkitty/list/gerrit-log@lists.osmocom.org/.

pespin gerrit-no-reply at lists.osmocom.org
Tue Nov 30 14:01:16 UTC 2021


pespin has uploaded this change for review. ( https://gerrit.osmocom.org/c/libosmo-netif/+/26426 )


Change subject: Introduce osmo_prim_srv APIs
......................................................................

Introduce osmo_prim_srv APIs

This new module allows easy exchange of osmo_prim based data types over
IPC communication (UD socket supported only so far), by replacing the
osmo_prim_hdr struct with a serialized header when submitting/receiving
it from the IPC socket.

This patch introduces the server side of the UD socket, but the client
side can easily be introduced in the same file whenever needed.

Related: SYS#5516
Change-Id: I7cab15ac092e45a256c4f0bab11b3962df861044
---
M TODO-RELEASE
M include/osmocom/netif/Makefile.am
A include/osmocom/netif/prim.h
M src/Makefile.am
A src/prim.c
5 files changed, 432 insertions(+), 0 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/libosmo-netif refs/changes/26/26426/1

diff --git a/TODO-RELEASE b/TODO-RELEASE
index 1c9a2a6..b146231 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -8,3 +8,4 @@
 # If any interfaces have been removed or changed since the last public release: c:r:0.
 #library	what		description / commit summary line
 sctp.h          new APIs
+prim.h          new data type, APIs
diff --git a/include/osmocom/netif/Makefile.am b/include/osmocom/netif/Makefile.am
index d9d030b..92712a9 100644
--- a/include/osmocom/netif/Makefile.am
+++ b/include/osmocom/netif/Makefile.am
@@ -4,6 +4,7 @@
 		    osmux.h		\
 		    ipa.h		\
 		    ipa_unit.h		\
+		    prim.h		\
 		    rs232.h		\
 		    rtp.h		\
 		    stream.h
diff --git a/include/osmocom/netif/prim.h b/include/osmocom/netif/prim.h
new file mode 100644
index 0000000..eb2cd9e
--- /dev/null
+++ b/include/osmocom/netif/prim.h
@@ -0,0 +1,46 @@
+/* (C) 2021 by sysmocom - s.f.m.c. GmbH <info at sysmocom.de>
+ * Author: Pau Espin Pedrol <pespin at sysmocom.de>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/lienses/>.
+ *
+ */
+#pragma once
+
+#include <stdint.h>
+
+#include <osmocom/core/prim.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/linuxlist.h>
+
+struct osmo_prim_srv;
+
+/*! Must return -EBADF if the srv struct is destroyed during call. oph and
+ * related msgb is owned by srv and wll be freed after the callback returns. */
+typedef int (*osmo_prim_srv_rx_cb)(struct osmo_prim_srv *srv, struct osmo_prim_hdr *oph);
+
+struct osmo_prim_hdr *osmo_prim_pkt_alloc(unsigned int sap, unsigned int primitive,
+					  enum osmo_prim_operation operation, size_t alloc_len);
+
+struct osmo_prim_srv *osmo_prim_srv_alloc(void *ctx);
+void osmo_prim_srv_free(struct osmo_prim_srv *srv);
+bool osmo_prim_srv_connected(const struct osmo_prim_srv *srv);
+int osmo_prim_srv_set_addr(struct osmo_prim_srv *srv, const char *path);
+const char *osmo_prim_srv_get_addr(struct osmo_prim_srv *srv);
+void osmo_prim_srv_set_priv(struct osmo_prim_srv *srv, void *priv);
+void *osmo_prim_srv_get_priv(const struct osmo_prim_srv *srv);
+void osmo_prim_srv_set_log_category(struct osmo_prim_srv *srv, int log_cat);
+void osmo_prim_srv_set_rx_cb(struct osmo_prim_srv *srv, osmo_prim_srv_rx_cb rx_cb);
+int osmo_prim_srv_open(struct osmo_prim_srv *srv);
+int osmo_prim_srv_send(struct osmo_prim_srv *srv, struct msgb *msg);
diff --git a/src/Makefile.am b/src/Makefile.am
index 438b58e..5c23896 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -17,6 +17,7 @@
 			  ipa_unit.c		\
 			  jibuf.c		\
 			  osmux.c		\
+			  prim.c		\
 			  rs232.c		\
 			  rtp.c			\
 			  stream.c
diff --git a/src/prim.c b/src/prim.c
new file mode 100644
index 0000000..050fe90
--- /dev/null
+++ b/src/prim.c
@@ -0,0 +1,383 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <inttypes.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/socket.h>
+#include <osmocom/core/logging.h>
+
+#include <osmocom/netif/prim.h>
+
+struct osmo_prim_pkt_hdr {
+	uint32_t sap;    /*!< Service Access Point Identifier */
+	uint16_t primitive;    /*!< Primitive number */
+	uint16_t operation; /*! Primitive Operation (enum osmo_prim_operation) */
+} __attribute__ ((packed));
+
+/* Here we take advantage of the fact that sizeof(struct
+ * osmo_prim_pkt_hdr) <= sizeof(struct osmo_prim_hdr), so we don't need
+ * to allocate headroom when serializing later.
+ */
+osmo_static_assert(sizeof(struct osmo_prim_pkt_hdr) <= sizeof(struct osmo_prim_hdr),
+		   osmo_prim_pkt_alloc_validate_headroom);
+
+/*! Allocate a primitive of given type and its associated msgb.
+*  \param[in] sap Service Access Point
+*  \param[in] primitive Primitive Number
+*  \param[in] operation Primitive Operation (REQ/RESP/IND/CONF)
+*  \param[in] alloc_len Total length (including struct osmo_prim_hdr) to allocate for the primitive
+*  \returns Pointer to allocated prim_hdr inisde its own msgb. The osmo_prim_hdr
+*	    is pre-alocated & pre-filled.
+*/
+struct osmo_prim_hdr *osmo_prim_pkt_alloc(unsigned int sap, unsigned int primitive,
+					  enum osmo_prim_operation operation, size_t alloc_len)
+{
+	struct msgb *msg;
+	struct osmo_prim_hdr *oph;
+
+	if (alloc_len < sizeof(*oph))
+		return NULL;
+
+	msg = msgb_alloc(alloc_len, "osmo_prim_pkt_alloc");
+	oph = (struct osmo_prim_hdr *)msgb_put(msg, sizeof(*oph));
+	osmo_prim_init(oph, sap, primitive, operation, msg);
+	msg->l2h = msg->tail;
+
+	return oph;
+}
+
+/******************************
+ * osmo_prim_srv
+ ******************************/
+
+struct osmo_prim_srv {
+	void *priv;
+	char *addr;
+	int log_cat; /* Defaults to DLGLOBAL */
+	struct osmo_fd listen_bfd;	/* fd for listen socket */
+	struct osmo_fd conn_bfd;	/* fd for connection to lcr */
+	struct llist_head upqueue;	/* queue for sending messages */
+	osmo_prim_srv_rx_cb rx_cb;
+};
+
+#define LOGSRV(srv, lvl, fmt, args...) LOGP((srv)->log_cat, lvl, fmt, ## args)
+
+static void _osmo_prim_srv_close(struct osmo_prim_srv *srv)
+{
+	struct osmo_fd *bfd = &srv->conn_bfd;
+
+	close(bfd->fd);
+	bfd->fd = -1;
+	osmo_fd_unregister(bfd);
+
+	/* re-enable the generation of ACCEPT for new connections */
+	osmo_fd_read_enable(&srv->listen_bfd);
+
+	/* flush the queue */
+	while (!llist_empty(&srv->upqueue)) {
+		struct msgb *msg = msgb_dequeue(&srv->upqueue);
+		msgb_free(msg);
+	}
+}
+
+static int _osmo_prim_srv_read(struct osmo_fd *bfd)
+{
+	struct osmo_prim_srv *srv = (struct osmo_prim_srv *)bfd->data;
+	struct osmo_prim_pkt_hdr *pkth;
+	struct msgb *msg;
+	struct osmo_prim_hdr oph;
+	int rc;
+
+	msg = msgb_alloc(1600, "osmo_prim_srv_rx");
+	if (!msg)
+		return -ENOMEM;
+	rc = recv(bfd->fd, msg->tail, msgb_tailroom(msg), 0);
+	if (rc == 0)
+		goto close;
+
+	if (rc < 0) {
+		if (errno == EAGAIN) {
+			msgb_free(msg);
+			return 0;
+		}
+		goto close;
+	}
+
+	if (rc < sizeof(struct osmo_prim_pkt_hdr)) {
+		LOGSRV(srv, LOGL_ERROR, "Received %d bytes on UD Socket, but primitive hdr size "
+		     "is %zu, discarding\n", rc, sizeof(struct osmo_prim_pkt_hdr));
+		msgb_free(msg);
+		return 0;
+	}
+	pkth = (struct osmo_prim_pkt_hdr *)msgb_put(msg, rc);
+
+	/* De-serialize message: */
+	osmo_prim_init(&oph, pkth->sap, pkth->primitive, pkth->operation, msg);
+	msgb_pull(msg, sizeof(*pkth));
+
+	if (srv->rx_cb)
+		rc = srv->rx_cb(srv, &oph);
+
+	/* as we always synchronously process the message in _osmo_prim_srv_rx() and
+	 * its callbacks, we can free the message here. */
+	msgb_free(msg);
+
+	return rc;
+
+close:
+	msgb_free(msg);
+	_osmo_prim_srv_close(srv);
+	return -1;
+}
+
+static int _osmo_prim_srv_write(struct osmo_fd *bfd)
+{
+	struct osmo_prim_srv *srv = bfd->data;
+	int rc;
+
+	while (!llist_empty(&srv->upqueue)) {
+		struct msgb *msg, *msg2;
+
+		/* peek at the beginning of the queue */
+		msg = llist_entry(srv->upqueue.next, struct msgb, list);
+
+		osmo_fd_write_disable(bfd);
+
+		if (!msgb_length(msg)) {
+			LOGSRV(srv, LOGL_ERROR, "message with ZERO "
+				"bytes!\n");
+			goto dontsend;
+		}
+
+		/* try to send it over the socket */
+		rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
+		if (rc == 0)
+			goto close;
+		if (rc < 0) {
+			if (errno == EAGAIN) {
+				osmo_fd_write_enable(bfd);
+				break;
+			}
+			goto close;
+		}
+
+dontsend:
+		/* _after_ we send it, we can deueue */
+		msg2 = msgb_dequeue(&srv->upqueue);
+		assert(msg == msg2);
+		msgb_free(msg);
+	}
+	return 0;
+
+close:
+	_osmo_prim_srv_close(srv);
+
+	return -1;
+}
+
+static int _osmo_prim_srv_bfd_cb(struct osmo_fd *bfd, unsigned int flags)
+{
+	int rc = 0;
+
+	if (flags & OSMO_FD_READ)
+		rc = _osmo_prim_srv_read(bfd);
+	if (rc == -EBADF) /* socket is gone, return and don't access it */
+		return rc;
+
+	if (flags & OSMO_FD_WRITE)
+		rc = _osmo_prim_srv_write(bfd);
+
+	return rc;
+}
+
+/* accept connection coming from PCU */
+static int _osmo_prim_srv_accept(struct osmo_fd *bfd, unsigned int flags)
+{
+	struct osmo_prim_srv *srv = (struct osmo_prim_srv *)bfd->data;
+	struct osmo_fd *conn_bfd = &srv->conn_bfd;
+	struct sockaddr_un un_addr;
+	socklen_t len;
+	int rc;
+
+	len = sizeof(un_addr);
+	rc = accept(bfd->fd, (struct sockaddr *) &un_addr, &len);
+	if (rc < 0) {
+		LOGSRV(srv, LOGL_ERROR, "Failed to accept a new connection\n");
+		return -1;
+	}
+
+	if (conn_bfd->fd >= 0) {
+		LOGSRV(srv, LOGL_NOTICE, "UD Socket connects but we already have "
+		     "another active connection ?!?\n");
+		/* We already have one LLSK connected, this is all we support */
+		srv->listen_bfd.when &= ~OSMO_FD_READ;
+		close(rc);
+		return 0;
+	}
+
+	osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, _osmo_prim_srv_bfd_cb, srv, 0);
+
+	if (osmo_fd_register(conn_bfd) != 0) {
+		LOGSRV(srv, LOGL_ERROR, "Failed to register new connection fd\n");
+		close(conn_bfd->fd);
+		conn_bfd->fd = -1;
+		return -1;
+	}
+
+	LOGSRV(srv, LOGL_NOTICE, "UD socket connected\n");
+
+	return 0;
+}
+
+struct osmo_prim_srv *osmo_prim_srv_alloc(void *ctx)
+{
+	struct osmo_prim_srv *srv;
+	srv = talloc_zero(ctx, struct osmo_prim_srv);
+	if (!srv)
+		return NULL;
+
+	srv->log_cat = DLGLOBAL;
+	INIT_LLIST_HEAD(&srv->upqueue);
+	srv->conn_bfd.fd = -1;
+	srv->listen_bfd.fd = -1;
+	return srv;
+}
+
+void osmo_prim_srv_free(struct osmo_prim_srv *srv)
+{
+	struct osmo_fd *bfd, *conn_bfd;
+
+	if (!srv)
+		return;
+
+	conn_bfd = &srv->conn_bfd;
+	if (conn_bfd->fd > 0)
+		_osmo_prim_srv_close(srv);
+	bfd = &srv->listen_bfd;
+	close(bfd->fd);
+	osmo_fd_unregister(bfd);
+	talloc_free(srv);
+}
+
+bool osmo_prim_srv_connected(const struct osmo_prim_srv *srv)
+{
+	if (!srv)
+		return false;
+	if (srv->conn_bfd.fd <= 0)
+		return false;
+	return true;
+}
+int osmo_prim_srv_set_addr(struct osmo_prim_srv *srv, const char *path)
+{
+	osmo_talloc_replace_string(srv, &srv->addr, path);
+	return 0;
+}
+
+const char *osmo_prim_srv_get_addr(struct osmo_prim_srv *srv)
+{
+	return srv->addr;
+}
+
+void osmo_prim_srv_set_priv(struct osmo_prim_srv *srv, void *priv)
+{
+	srv->priv = priv;
+}
+
+void *osmo_prim_srv_get_priv(const struct osmo_prim_srv *srv)
+{
+	return srv->priv;
+}
+
+void osmo_prim_srv_set_log_category(struct osmo_prim_srv *srv, int log_cat)
+{
+	srv->log_cat = log_cat;
+}
+
+void osmo_prim_srv_set_rx_cb(struct osmo_prim_srv *srv, osmo_prim_srv_rx_cb rx_cb)
+{
+	srv->rx_cb = rx_cb;
+}
+
+int osmo_prim_srv_open(struct osmo_prim_srv *srv)
+{
+	struct osmo_fd *bfd = &srv->listen_bfd;
+	int rc;
+
+	if (!srv->addr) {
+		LOGSRV(srv, LOGL_ERROR, "Cannot open, Address not configured\n");
+		return -1;
+	}
+
+	rc = osmo_sock_unix_init(SOCK_SEQPACKET, 0, srv->addr, OSMO_SOCK_F_BIND);
+	if (rc < 0) {
+		LOGSRV(srv, LOGL_ERROR, "Could not create %s unix socket: %s\n",
+		     srv->addr, strerror(errno));
+		return -1;
+	}
+
+	osmo_fd_setup(bfd, rc, OSMO_FD_READ, _osmo_prim_srv_accept, srv, 0);
+
+	rc = osmo_fd_register(bfd);
+	if (rc < 0) {
+		LOGSRV(srv, LOGL_ERROR, "Could not register listen fd: %d\n",
+			rc);
+		close(bfd->fd);
+		bfd->fd = -1;
+		return rc;
+	}
+
+	LOGSRV(srv, LOGL_INFO, "Started listening on Lower Layer Unix Domain Socket: %s\n", srv->addr);
+
+	return 0;
+}
+
+/*! Allocate a primitive of given type and its associated msgb.
+*  \param[in] srv The osmo_prim_srv instance where message is to be sent through
+*  \param[in] msg msgb containing osmo_prim_hdr plus extra content, allocated through \ref osmo_prim_pkt_alloc()
+*  \returns zero on success, negative on error */
+int osmo_prim_srv_send(struct osmo_prim_srv *srv, struct msgb *msg)
+{
+	struct osmo_fd *conn_bfd;
+	struct osmo_prim_hdr *oph;
+	struct osmo_prim_pkt_hdr *pkth;
+	unsigned int sap;
+	unsigned int primitive;
+	enum osmo_prim_operation operation;
+
+	if (!srv) {
+		LOGSRV(srv, LOGL_INFO, "UD socket not created, dropping message\n");
+		msgb_free(msg);
+		return -EINVAL;
+	}
+	conn_bfd = &srv->conn_bfd;
+	if (conn_bfd->fd <= 0) {
+		LOGSRV(srv, LOGL_NOTICE, "UD socket not connected, dropping message\n");
+		msgb_free(msg);
+		return -EIO;
+	}
+
+	/* Serialize the oph: */
+	oph = (struct osmo_prim_hdr *)msgb_data(msg);
+	OSMO_ASSERT(oph && msgb_length(msg) >= sizeof(*oph));
+	sap = oph->sap;
+	primitive = oph->primitive;
+	operation = oph->operation;
+	msgb_pull(msg, sizeof(*oph));
+	pkth = (struct osmo_prim_pkt_hdr *)msgb_push(msg, sizeof(*pkth));
+	pkth->sap = sap;
+	pkth->primitive = primitive;
+	pkth->operation = operation;
+
+	/* Finally enqueue the msg */
+	msgb_enqueue(&srv->upqueue, msg);
+	osmo_fd_write_enable(conn_bfd);
+
+	return 0;
+}

-- 
To view, visit https://gerrit.osmocom.org/c/libosmo-netif/+/26426
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings

Gerrit-Project: libosmo-netif
Gerrit-Branch: master
Gerrit-Change-Id: I7cab15ac092e45a256c4f0bab11b3962df861044
Gerrit-Change-Number: 26426
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin at sysmocom.de>
Gerrit-MessageType: newchange
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.osmocom.org/pipermail/gerrit-log/attachments/20211130/97a0f2ae/attachment.htm>


More information about the gerrit-log mailing list