<p>laforge has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-iuh/+/16370">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: SABP server<br><br>Change-Id: Iff1d33c7482ff767aa5446a8ccfe9086fee57365<br>---<br>M src/sabp_common.c<br>A src/sabp_server.c<br>A src/sabp_server.h<br>3 files changed, 365 insertions(+), 4 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-iuh refs/changes/70/16370/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/src/sabp_common.c b/src/sabp_common.c</span><br><span>index cdb0e32..75c89ef 100644</span><br><span>--- a/src/sabp_common.c</span><br><span>+++ b/src/sabp_common.c</span><br><span>@@ -1,6 +1,6 @@</span><br><span> /* common SABP code */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-/* (C) 2015 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2019 by Harald Welte <laforge@gnumonks.org></span><br><span>  * All Rights Reserved</span><br><span>  *</span><br><span>  * This program is free software; you can redistribute it and/or modify</span><br><span>@@ -19,6 +19,11 @@</span><br><span>  */</span><br><span> </span><br><span> #include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdlib.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span> </span><br><span> #include <osmocom/core/msgb.h></span><br><span> </span><br><span>@@ -73,14 +78,17 @@</span><br><span>       { 0, NULL }</span><br><span> };</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-static struct msgb *sabp_msgb_alloc(void)</span><br><span style="color: hsl(120, 100%, 40%);">+struct msgb *osmo_sabp_msgb_alloc(void *ctx, const char *name)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return msgb_alloc_headroom(1024+512, 512, "SABP Tx");</span><br><span style="color: hsl(120, 100%, 40%);">+       /* make the messages rather large as the cell lists can be long! */</span><br><span style="color: hsl(120, 100%, 40%);">+   return msgb_alloc_headroom_c(ctx, 65535, 16, name);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+extern void *tall_msgb_ctx;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> static struct msgb *_sabp_gen_msg(SABP_SABP_PDU_t *pdu)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     struct msgb *msg = sabp_msgb_alloc();</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *msg = osmo_sabp_msgb_alloc(tall_msgb_ctx, __func__);</span><br><span>    asn_enc_rval_t rval;</span><br><span> </span><br><span>     if (!msg)</span><br><span>@@ -213,3 +221,144 @@</span><br><span> {</span><br><span>       _sabp_DSABP = log_area;</span><br><span> }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/***********************************************************************</span><br><span style="color: hsl(120, 100%, 40%);">+ * Message Reception</span><br><span style="color: hsl(120, 100%, 40%);">+ ***********************************************************************/</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* SABP was specified as ASN.1 APER encoded messages *directly* inside a TCP</span><br><span style="color: hsl(120, 100%, 40%);">+ * stream, without any intermediate framing layer.  As TCP doesn't preserve</span><br><span style="color: hsl(120, 100%, 40%);">+ * message boundaries, and SABP messages are variable length, we need to</span><br><span style="color: hsl(120, 100%, 40%);">+ * actually parse the message up to the point of the APER-internal length</span><br><span style="color: hsl(120, 100%, 40%);">+ * determinant (which itself is variable-length encoded). */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Three bytes for TriggeringMessage, procedureCode and Criticality */</span><br><span style="color: hsl(120, 100%, 40%);">+#define SABP_HDR_LEN   3</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! parse a single APER length determinant.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] in input data as received from peer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] in_len length of 'in'</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] len_len Length of the current length determinant in octets</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns parsed length or -EAGAIN if more data is needed, or -EIO in case of parse error */</span><br><span style="color: hsl(120, 100%, 40%);">+static int parse_aper_len_det(const uint8_t *in, unsigned int in_len, unsigned int *len_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    /* Variable-length Length encoding according to X.961 Section 9.1 NOTE 2 */</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (in[0] & 0xC0) {</span><br><span style="color: hsl(120, 100%, 40%);">+   case 0x00:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* total length is encoded in this octet */</span><br><span style="color: hsl(120, 100%, 40%);">+           *len_len = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+         return in[0];</span><br><span style="color: hsl(120, 100%, 40%);">+ case 0x80:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* total length (up to 16k) encoded in two octets */</span><br><span style="color: hsl(120, 100%, 40%);">+          *len_len = 2;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (in_len < 2)</span><br><span style="color: hsl(120, 100%, 40%);">+                    return -EAGAIN; /* we need one more byte */</span><br><span style="color: hsl(120, 100%, 40%);">+           return ((in[0] & 0x3F) << 8) | in[1];</span><br><span style="color: hsl(120, 100%, 40%);">+       case 0xC0:</span><br><span style="color: hsl(120, 100%, 40%);">+            /* total length not known, encoded in chunks; first chunk length now known */</span><br><span style="color: hsl(120, 100%, 40%);">+         *len_len = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+         return (in[0] & 0x3f) * 16384;</span><br><span style="color: hsl(120, 100%, 40%);">+            /* we must read the chunk and then look at the variable-length encoded length</span><br><span style="color: hsl(120, 100%, 40%);">+          * of the next chunk */</span><br><span style="color: hsl(120, 100%, 40%);">+       default:</span><br><span style="color: hsl(120, 100%, 40%);">+              return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* msg->l1h points to first byte of current length determinant */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MSGB_LEN_NEEDED(msg) (msg)->cb[0]      /* total length of msgb needed (as known so far) */</span><br><span style="color: hsl(120, 100%, 40%);">+#define MSGB_APER_STATE(msg) (msg)->cb[1]       /* '1' if we're expecting another length determinant */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Read one SABP message from socket fd or store part if still not fully received.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] ctx talloc context from which to allocate new msgb.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] fd The fd for the socket to read from.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] rmsg internally allocated msgb containing a fully received SABP message.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[inout] tmp_msg internally allocated msgb caching data for not yet fully received message.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ *  Function is designed just like ipa_msg_recv_buffered()</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_sabp_recv_buffered(void *ctx, int fd, struct msgb **rmsg, struct msgb **tmp_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct msgb *msg = tmp_msg ? *tmp_msg : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int len_len;</span><br><span style="color: hsl(120, 100%, 40%);">+ bool first_call = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           msg = osmo_sabp_msgb_alloc(ctx, __func__);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (!msg)</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -ENOMEM;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!msgb_l1(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* new msgb; we expect first length determinant after 3 bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+              msg->l1h = msgb_data(msg) + SABP_HDR_LEN;</span><br><span style="color: hsl(120, 100%, 40%);">+          MSGB_LEN_NEEDED(msg) = SABP_HDR_LEN + 1; /* 1 == minimum length of length-field */</span><br><span style="color: hsl(120, 100%, 40%);">+            first_call = true;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* attempt to receive missing/needed amount of bytes */</span><br><span style="color: hsl(120, 100%, 40%);">+       rc = recv(fd, msg->tail, MSGB_LEN_NEEDED(msg)-msgb_length(msg), 0);</span><br><span style="color: hsl(120, 100%, 40%);">+        if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+          goto discard_msg; /* dead socket */</span><br><span style="color: hsl(120, 100%, 40%);">+   else if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+         if (errno == EAGAIN || errno == EINTR)</span><br><span style="color: hsl(120, 100%, 40%);">+                        rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               else {</span><br><span style="color: hsl(120, 100%, 40%);">+                        rc = -errno;</span><br><span style="color: hsl(120, 100%, 40%);">+                  goto discard_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     msgb_put(msg, rc);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* check if we have received sufficient amount of data */</span><br><span style="color: hsl(120, 100%, 40%);">+     if (msgb_length(msg) < MSGB_LEN_NEEDED(msg)) {</span><br><span style="color: hsl(120, 100%, 40%);">+             if (msg->len == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = -EAGAIN;</span><br><span style="color: hsl(120, 100%, 40%);">+                 goto discard_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (!tmp_msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       rc = -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+                    goto discard_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span style="color: hsl(120, 100%, 40%);">+             *tmp_msg = msg;</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EAGAIN;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (!first_call && MSGB_APER_STATE(msg) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+               /* we have read all needed bytes by now, and hence can return successfully */</span><br><span style="color: hsl(120, 100%, 40%);">+         return msgb_length(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* below code is only executed on first call/iteration, or if last length-det was chunked */</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(first_call || MSGB_APER_STATE(msg) == 1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       OSMO_ASSERT(msg->l1h < msg->tail);</span><br><span style="color: hsl(120, 100%, 40%);">+   rc = parse_aper_len_det(msgb_l1(msg), msgb_l1len(msg), &len_len);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (rc == -EIO) {</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EIO;</span><br><span style="color: hsl(120, 100%, 40%);">+  } else if (rc == -EAGAIN) {</span><br><span style="color: hsl(120, 100%, 40%);">+           /* need (typically 1 byte) more data */</span><br><span style="color: hsl(120, 100%, 40%);">+               OSMO_ASSERT(len_len > 1);</span><br><span style="color: hsl(120, 100%, 40%);">+          MSGB_LEN_NEEDED(msg) += len_len-1;</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EAGAIN;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else if (rc >= 16384) {</span><br><span style="color: hsl(120, 100%, 40%);">+          /* read up to next length determinant */</span><br><span style="color: hsl(120, 100%, 40%);">+              MSGB_LEN_NEEDED(msg) += len_len-1 + rc + 1 /* new length determinant */;</span><br><span style="color: hsl(120, 100%, 40%);">+              msg->l1h += (len_len-1) + rc; /* start of next length determinant */</span><br><span style="color: hsl(120, 100%, 40%);">+               MSGB_APER_STATE(msg) = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+             return -EAGAIN;</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              /* full length is known now */</span><br><span style="color: hsl(120, 100%, 40%);">+                MSGB_LEN_NEEDED(msg) += len_len-1 + rc;</span><br><span style="color: hsl(120, 100%, 40%);">+               return -EAGAIN;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+discard_msg:</span><br><span style="color: hsl(120, 100%, 40%);">+     if (tmp_msg)</span><br><span style="color: hsl(120, 100%, 40%);">+          *tmp_msg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      msgb_free(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+       return rc;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/sabp_server.c b/src/sabp_server.c</span><br><span>new file mode 100644</span><br><span>index 0000000..6d67a5e</span><br><span>--- /dev/null</span><br><span>+++ b/src/sabp_server.c</span><br><span>@@ -0,0 +1,171 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/* (C) 2019 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: AGPL-3.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU Affero General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 3 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU Affero General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU Affero General Public License</span><br><span style="color: hsl(120, 100%, 40%);">+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/types.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <sys/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/talloc.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/select.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/socket.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/msgb.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/logging.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/stream.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "sabp_server.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int sabp_cbc_read_cb(struct osmo_stream_srv *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_stream_srv_link *link = osmo_stream_srv_get_master(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+ struct osmo_sabp_server_client *client = osmo_stream_srv_get_data(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+      struct osmo_sabp_server *srv = osmo_stream_srv_link_get_data(link);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_fd *ofd = osmo_stream_srv_get_ofd(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+  struct msgb *msg = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+      int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPSC(client, LOGL_DEBUG, "read_cb rx_msg=%p\n", client->rx_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* message de-segmentation */</span><br><span style="color: hsl(120, 100%, 40%);">+ rc = osmo_sabp_recv_buffered(conn, ofd->fd, &msg, &client->rx_msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              if (rc == -EAGAIN || rc == -EINTR) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  /* more data needs to be read */</span><br><span style="color: hsl(120, 100%, 40%);">+                      return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (rc == -EPIPE || rc == -ECONNRESET) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       /* lost connection with server */</span><br><span style="color: hsl(120, 100%, 40%);">+             } else if (rc == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                 /* connection closed with server */</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+             /* destroy connection */</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_stream_srv_destroy(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+                return -EBADF;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     OSMO_ASSERT(msg);</span><br><span style="color: hsl(120, 100%, 40%);">+     LOGPSC(client, LOGL_DEBUG, "Received SABP %s\n", msgb_hexdump(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+        /* decode + dispatch message */</span><br><span style="color: hsl(120, 100%, 40%);">+       decoded =...;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (decoded) {</span><br><span style="color: hsl(120, 100%, 40%);">+                LOGPSC(client, LOGL_INFO, "Received SABP %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                     get_value_string(FIXME));</span><br><span style="color: hsl(120, 100%, 40%);">+             srv->rx_cb(client, decoded);</span><br><span style="color: hsl(120, 100%, 40%);">+       } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGPSC(client, LOGL_ERROR, "Unable to decode %s\n", msgb_hexdump(msg));</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int sabp_server_closed_cb(struct osmo_stream_srv *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_sabp_server_client *client = osmo_stream_srv_get_data(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+      LOGSC(client, LOGL_INFO, "connection closed\n");</span><br><span style="color: hsl(120, 100%, 40%);">+    llist_del(&client->list);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_fsm_inst_term(client->fi, OSMO_FSM_TERM_REQUEST, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+       talloc_free(client);</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int sabp_server_accept_cb(struct omso_stream_srv_link *link, int fd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_sabp_server *srv = osmo_stream_srv_link_get_data(link);</span><br><span style="color: hsl(120, 100%, 40%);">+   struct osmo_sabp_server_client *client = talloc_zero(srv, struct osmo_sabp_server_client);</span><br><span style="color: hsl(120, 100%, 40%);">+    char remote_ip[INET6_ADDRSTRLEN], portbuf[6];</span><br><span style="color: hsl(120, 100%, 40%);">+ int remote_port;</span><br><span style="color: hsl(120, 100%, 40%);">+      OSMO_ASSERT(client);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        remote_ip[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+  portbuf[0] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_sock_get_ip_and_port(fd, remote_ip, sizeof(remote_ip), portbuf, sizeof(portbuf), false);</span><br><span style="color: hsl(120, 100%, 40%);">+ remote_port = atoi(portbuf);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        client->conn = osmo_stream_srv_create(link, lnk, fd, sabp_server_read_cb,</span><br><span style="color: hsl(120, 100%, 40%);">+                                          sabp_srever_closed_cb, client);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!client->conn) {</span><br><span style="color: hsl(120, 100%, 40%);">+               LOGP(DSABP, LOGL_ERROR, "Unable to create stream server for %s:%d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       remote_ip, remote_port);</span><br><span style="color: hsl(120, 100%, 40%);">+              talloc_free(client);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     client->fi = osmo_fsm_inst_alloc(&sabp_server_fsm, client, client, LOGL_DEBUG, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!client->fi) {</span><br><span style="color: hsl(120, 100%, 40%);">+         LOGPSC(client, LOGL_ERROR, "Unable to allocate FSM\n");</span><br><span style="color: hsl(120, 100%, 40%);">+             osmo_stream_srv_destroy(client->conn);</span><br><span style="color: hsl(120, 100%, 40%);">+             talloc_free(client);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     llist_add_tail(&client->lits, &srv->clients);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* TODO: Match client to peer? */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGPSC(client, LOGL_INFO, "New SABP client connection\n");</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_fsm_inst_dispatch(client->fi, SABP_SRV_E_CMD_RESET, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#if 0</span><br><span style="color: hsl(120, 100%, 40%);">+void sabp_server_client_tx(struct osmo_sabp_cbc_client *client, struct SABP_SABP_PDU_t *sabp)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       struct msgb *msg = _sabp_gen_msg(pdu);</span><br><span style="color: hsl(120, 100%, 40%);">+        LOGPSC(client, LOGL_INFO, "Transmitting %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              get_value_string(</span><br><span style="color: hsl(120, 100%, 40%);">+     if (!msg) {</span><br><span style="color: hsl(120, 100%, 40%);">+           LOGPSC(client, LOGL_ERROR, "Failed to encode SABP %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                    get_value_string());</span><br><span style="color: hsl(120, 100%, 40%);">+          ASN_STRUCT_FREE(sabp);</span><br><span style="color: hsl(120, 100%, 40%);">+                return;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     ASN_STRUCT_FREE(sabp);</span><br><span style="color: hsl(120, 100%, 40%);">+        osmo_stream_srv_send(client->conn, msg);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void sabp_server_client_close(struct osmo_sabp_server_client *client)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    osmo_stream_srv_destroy(client->conn);</span><br><span style="color: hsl(120, 100%, 40%);">+     /* FIXME: do we need to unlink/free the client? */</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sabp_server *sabp_server_create(void *ctx, const char *bind_ip, int bind_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     int (*rx_cb)(struct osmo_sabp_server_client *client,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       struct SABP_PDU *dec))</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    struct osmo_sabp_server *srv = talloc_zero(ctx, struct osmo_sabp_server);</span><br><span style="color: hsl(120, 100%, 40%);">+     int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     if (bind_port == -1)</span><br><span style="color: hsl(120, 100%, 40%);">+          bind_port = SABP_TCP_PORT;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  OSMO_ASSERT(srv);</span><br><span style="color: hsl(120, 100%, 40%);">+     srv->rx_cb = rx_cbp;</span><br><span style="color: hsl(120, 100%, 40%);">+       INIT_LLIST_HEAD(&srv->clients);</span><br><span style="color: hsl(120, 100%, 40%);">+        srv->link = osmo_stream_srv_link_create(srv);</span><br><span style="color: hsl(120, 100%, 40%);">+      osmo_stream_srv_link_set_data(srv->link, srv);</span><br><span style="color: hsl(120, 100%, 40%);">+     osmo_stream_srv_link_set_nodelay(srv->link, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_stream_srv_link_set_port(srv->link, bind_port);</span><br><span style="color: hsl(120, 100%, 40%);">+       if (bind_ip)</span><br><span style="color: hsl(120, 100%, 40%);">+          osmo_stream_srv_link_set_addr(srv->link, bind_ip);</span><br><span style="color: hsl(120, 100%, 40%);">+ osmo_stream_srv_link_set_accept_cb(srv->link, sabp_server_accept_cb);</span><br><span style="color: hsl(120, 100%, 40%);">+      rc = osmo_stream_serv_link_open(srv->link);</span><br><span style="color: hsl(120, 100%, 40%);">+        OSMO_ASSERT(rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ LOGP(DSABP, LOGL_NOTICE, "Listening for SABP at %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+              osmo_stream_srv_link_get_sockname(srv->link));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return srv;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/src/sabp_server.h b/src/sabp_server.h</span><br><span>new file mode 100644</span><br><span>index 0000000..5cb0fb2</span><br><span>--- /dev/null</span><br><span>+++ b/src/sabp_server.h</span><br><span>@@ -0,0 +1,41 @@</span><br><span style="color: hsl(120, 100%, 40%);">+#pragma once</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/linuxlist.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/netif/stream.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define LOGPSC(client, level, fmt, args...) \</span><br><span style="color: hsl(120, 100%, 40%);">+   LOGP(DSABP, level, "%s: " fmt, sabp_server_client_name(client), ## args)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sabp_server_client;</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_fsm_inst;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* a SABP server */</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sabp_sever {</span><br><span style="color: hsl(120, 100%, 40%);">+ /* libosmo-netif stream server */</span><br><span style="color: hsl(120, 100%, 40%);">+     struct osmo_stream_srv_link *link;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* clients connected to this server */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct llist_head clients;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* receive call-back; called for every received message */</span><br><span style="color: hsl(120, 100%, 40%);">+    int (*rx_cb)(struct osmo_sabp_server_client *client, struct SABP_SABP_PDU *dec);</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sabp_server_client {</span><br><span style="color: hsl(120, 100%, 40%);">+      /* entry in osmo_cbsp_cbc.clients */</span><br><span style="color: hsl(120, 100%, 40%);">+  struct llist_head list;</span><br><span style="color: hsl(120, 100%, 40%);">+       /* stream server connection for this client */</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_stream_srv *conn;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* partially received CBSP message (rx completion pending) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct msgb *rx_msg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   void *peer;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *sabp_server_client_name(const struct osmo_sabp_server_client *client);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+void sabp_server_client_close(struct osmo_sabp_server_client *client);</span><br><span style="color: hsl(120, 100%, 40%);">+struct osmo_sabp_server *sabp_server_create(void *ctx, const char *bind_ip, int bind_port,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       int (*rx_cb)(struct osmo_sabp_server_client *client,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                       struct SABP_SABP_PDU *dec));</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-iuh/+/16370">change 16370</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-iuh/+/16370"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-iuh </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: Iff1d33c7482ff767aa5446a8ccfe9086fee57365 </div>
<div style="display:none"> Gerrit-Change-Number: 16370 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: laforge <laforge@osmocom.org> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>