fixeria has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmocom-bb/+/35583?usp=email )


Change subject: [WIP] mobile: implement sending CSD data over UNIX socket
......................................................................

[WIP] mobile: implement sending CSD data over UNIX socket

Change-Id: Id054af7b3d9d0a41715f7981deb420f6e09bf30c
Related: OS#4396
---
M src/host/layer23/include/osmocom/bb/mobile/tch.h
M src/host/layer23/src/mobile/Makefile.am
M src/host/layer23/src/mobile/tch_data.c
A src/host/layer23/src/mobile/tch_data_sock.c
4 files changed, 284 insertions(+), 11 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmocom-bb refs/changes/83/35583/1

diff --git a/src/host/layer23/include/osmocom/bb/mobile/tch.h 
b/src/host/layer23/include/osmocom/bb/mobile/tch.h
index a31655a..c3c957a 100644
--- a/src/host/layer23/include/osmocom/bb/mobile/tch.h
+++ b/src/host/layer23/include/osmocom/bb/mobile/tch.h
@@ -13,6 +13,7 @@
                } voice;
                struct tch_data_state {
                        enum tch_data_io_handler handler;
+                       struct tch_csd_sock_state *sock;
                        struct osmo_v110_ta *v110_ta;
                        struct osmo_soft_uart *suart;
                } data;
diff --git a/src/host/layer23/src/mobile/Makefile.am 
b/src/host/layer23/src/mobile/Makefile.am
index b4e45e2..d00e45e 100644
--- a/src/host/layer23/src/mobile/Makefile.am
+++ b/src/host/layer23/src/mobile/Makefile.am
@@ -33,6 +33,7 @@
        primitives.c \
        tch.c \
        tch_data.c \
+       tch_data_sock.c \
        tch_voice.c \
        transaction.c \
        vty_interface.c \
diff --git a/src/host/layer23/src/mobile/tch_data.c 
b/src/host/layer23/src/mobile/tch_data.c
index 082c397..21ed1c2 100644
--- a/src/host/layer23/src/mobile/tch_data.c
+++ b/src/host/layer23/src/mobile/tch_data.c
@@ -72,21 +72,31 @@
        },
 };

+struct tch_csd_sock_state *tch_csd_sock_init(void *ctx, const char *sock_path);
+int tch_csd_sock_recv(struct tch_csd_sock_state *state, struct msgb *msg);
+int tch_csd_sock_send(struct tch_csd_sock_state *state, struct msgb *msg);
+void tch_csd_sock_exit(struct tch_csd_sock_state *state);
+
 static void tch_soft_uart_rx_cb(void *priv, struct msgb *msg, unsigned int 
flags)
 {
-       LOGP(DL1C, LOGL_FATAL, "%s(): [flags=0x%08x] %s\n",
+       struct tch_data_state *state = (struct tch_data_state *)priv;
+
+       LOGP(DL1C, LOGL_DEBUG, "%s(): [flags=0x%08x] %s\n",
             __func__, flags, msgb_hexdump(msg));
-       msgb_free(msg);
+
+       if (state->sock != NULL && msgb_length(msg) > 0)
+               tch_csd_sock_send(state->sock, msg);
+       else
+               msgb_free(msg);
 }

 static void tch_soft_uart_tx_cb(void *priv, struct msgb *msg)
 {
-       const char *data = "TEST\r\n";
-       size_t n_bytes;
+       struct tch_data_state *state = (struct tch_data_state *)priv;
+       int n_bytes = tch_csd_sock_recv(state->sock, msg);

-       n_bytes = OSMO_MIN(msg->data_len, strlen(data));
-       if (n_bytes > 0)
-               memcpy(msgb_put(msg, n_bytes), (void *)data, n_bytes);
+       LOGP(DL1C, LOGL_DEBUG, "%s(): [n_bytes=%u/%u] %s\n",
+            __func__, n_bytes, msg->data_len, msgb_hexdump(msg));
 }

 struct osmo_soft_uart *tch_soft_uart_alloc(struct osmocom_ms *ms)
@@ -169,7 +179,7 @@

 int tch_csd_rx_from_l1(struct osmocom_ms *ms, struct msgb *msg)
 {
-       struct tch_data_state *state = &ms->tch_state->data;
+       const struct tch_data_state *state = &ms->tch_state->data;
        const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
        const struct csd_v110_frame_desc *desc;
        ubit_t data[4 * 60];
@@ -217,7 +227,7 @@

 int tch_csd_tx_to_l1(struct osmocom_ms *ms)
 {
-       struct tch_data_state *state = &ms->tch_state->data;
+       const struct tch_data_state *state = &ms->tch_state->data;
        const struct gsm48_rr_cd *cd = &ms->rrlayer.cd_now;
        const struct csd_v110_frame_desc *desc;
        ubit_t data[60 * 4];
@@ -299,10 +309,13 @@
                        struct tch_data_state *state)
 {
        struct osmocom_ms *ms = trans->ms;
+       const struct gsm_settings *set = &ms->settings;

        switch (state->handler) {
        case TCH_DATA_IOH_UNIX_SOCK:
-               /* TODO: open listening socket */
+               state->sock = tch_csd_sock_init(ms, 
set->tch_data.unix_socket_path);
+               if (state->sock == NULL)
+                       return -ENOMEM;
                break;
        case TCH_DATA_IOH_LOOPBACK:
        case TCH_DATA_IOH_NONE:
@@ -325,6 +338,8 @@
        return 0;

 exit_free:
+       if (state->sock != NULL)
+               tch_csd_sock_exit(state->sock);
        if (state->suart != NULL)
                osmo_soft_uart_free(state->suart);
        if (state->v110_ta != NULL)
@@ -341,7 +356,8 @@

        switch (state->handler) {
        case TCH_DATA_IOH_UNIX_SOCK:
-               /* TODO: close listening socket */
+               if (state->sock != NULL)
+                       tch_csd_sock_exit(state->sock);
                break;
        default:
                break;
diff --git a/src/host/layer23/src/mobile/tch_data_sock.c 
b/src/host/layer23/src/mobile/tch_data_sock.c
new file mode 100644
index 0000000..c5cde6c
--- /dev/null
+++ b/src/host/layer23/src/mobile/tch_data_sock.c
@@ -0,0 +1,245 @@
+/*
+ * (C) 2023 by sysmocom - s.f.m.c. GmbH <i...@sysmocom.de>
+ * Author: Vadim Yanitskiy <vyanits...@sysmocom.de>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 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 General Public License for more details.
+ *
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/timer.h>
+#include <osmocom/core/msgb.h>
+#include <osmocom/core/socket.h>
+
+#include <osmocom/bb/common/logging.h>
+#include <osmocom/bb/common/osmocom_data.h>
+#include <osmocom/bb/common/ms.h>
+#include <osmocom/bb/mobile/tch.h>
+
+struct tch_csd_sock_state {
+       struct osmo_fd listen_bfd;      /* fd for listen socket */
+       struct osmo_fd conn_bfd;        /* fd for a client connection */
+       struct llist_head rxqueue;
+       struct llist_head txqueue;
+};
+
+static void tch_csd_sock_close(struct tch_csd_sock_state *state)
+{
+       struct osmo_fd *bfd = &state->conn_bfd;
+
+       LOGP(DMOB, LOGL_NOTICE, "TCH CSD sock has closed connection\n");
+
+       osmo_fd_unregister(bfd);
+       close(bfd->fd);
+       bfd->fd = -1;
+
+       /* re-enable the generation of ACCEPT for new connections */
+       osmo_fd_read_enable(&state->listen_bfd);
+
+       /* flush the queues */
+       while (!llist_empty(&state->rxqueue))
+               msgb_free(msgb_dequeue(&state->rxqueue));
+       while (!llist_empty(&state->txqueue))
+               msgb_free(msgb_dequeue(&state->txqueue));
+}
+
+static int tch_csd_sock_read(struct osmo_fd *bfd)
+{
+       struct tch_csd_sock_state *state = (struct tch_csd_sock_state 
*)bfd->data;
+       struct msgb *msg;
+       int rc;
+
+       msg = msgb_alloc(256, "tch_csd_sock_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)
+                       return 0;
+               goto close;
+       }
+
+       msgb_put(msg, rc);
+       msgb_enqueue(&state->rxqueue, msg);
+       return rc;
+
+close:
+       msgb_free(msg);
+       tch_csd_sock_close(state);
+       return -1;
+}
+
+static int tch_csd_sock_write(struct osmo_fd *bfd)
+{
+       struct tch_csd_sock_state *state = bfd->data;
+
+       while (!llist_empty(&state->txqueue)) {
+               struct msgb *msg;
+               int rc;
+
+               /* dequeue a msgb */
+               msg = msgb_dequeue(&state->txqueue);
+               osmo_fd_write_disable(bfd);
+
+               /* try to send it over the socket */
+               rc = write(bfd->fd, msgb_data(msg), msgb_length(msg));
+               if (rc == 0) {
+                       llist_add(&msg->list, &state->txqueue);
+                       goto close;
+               } else if (rc < 0) {
+                       if (errno == EAGAIN) {
+                               osmo_fd_write_enable(bfd);
+                               break;
+                       }
+                       llist_add(&msg->list, &state->txqueue);
+                       goto close;
+               }
+       }
+
+       return 0;
+
+close:
+       tch_csd_sock_close(state);
+       return -1;
+}
+
+static int tch_csd_sock_cb(struct osmo_fd *bfd, unsigned int flags)
+{
+       int rc = 0;
+
+       if (flags & OSMO_FD_READ) {
+               rc = tch_csd_sock_read(bfd);
+               if (rc < 0)
+                       return rc;
+       }
+
+       if (flags & OSMO_FD_WRITE)
+               rc = tch_csd_sock_write(bfd);
+
+       return rc;
+}
+
+static int tch_csd_sock_accept(struct osmo_fd *bfd, unsigned int flags)
+{
+       struct tch_csd_sock_state *state = (struct tch_csd_sock_state 
*)bfd->data;
+       struct osmo_fd *conn_bfd = &state->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) {
+               LOGP(DMOB, LOGL_ERROR, "Failed to accept() a new connection\n");
+               return -1;
+       }
+
+       if (conn_bfd->fd >= 0) {
+               LOGP(DMOB, LOGL_NOTICE, "TCH CSD sock already has an active 
connection\n");
+               osmo_fd_read_disable(&state->listen_bfd);
+               close(rc);
+               return 0;
+       }
+
+       osmo_fd_setup(conn_bfd, rc, OSMO_FD_READ, &tch_csd_sock_cb, state, 0);
+       if (osmo_fd_register(conn_bfd) != 0) {
+               LOGP(DMOB, LOGL_ERROR, "osmo_fd_register() failed\n");
+               close(conn_bfd->fd);
+               conn_bfd->fd = -1;
+               return -1;
+       }
+
+       LOGP(DMOB, LOGL_NOTICE, "TCH CSD sock got a connection\n");
+
+       return 0;
+}
+
+struct tch_csd_sock_state *tch_csd_sock_init(void *ctx, const char *sock_path)
+{
+       struct tch_csd_sock_state *state;
+       struct osmo_fd *bfd;
+       int rc;
+
+       state = talloc_zero(ctx, struct tch_csd_sock_state);
+       if (state == NULL)
+               return NULL;
+
+       INIT_LLIST_HEAD(&state->rxqueue);
+       INIT_LLIST_HEAD(&state->txqueue);
+       state->conn_bfd.fd = -1;
+
+       bfd = &state->listen_bfd;
+
+       rc = osmo_sock_unix_init_ofd(bfd, SOCK_SEQPACKET, 0, sock_path, 
OSMO_SOCK_F_BIND);
+       if (rc < 0) {
+               LOGP(DMOB, LOGL_ERROR, "Could not create unix socket: %s\n", 
strerror(errno));
+               talloc_free(state);
+               return NULL;
+       }
+
+       bfd->cb = &tch_csd_sock_accept;
+       bfd->data = state;
+
+       return state;
+}
+
+void tch_csd_sock_exit(struct tch_csd_sock_state *state)
+{
+       if (state->conn_bfd.fd > -1)
+               tch_csd_sock_close(state);
+       osmo_fd_unregister(&state->listen_bfd);
+       close(state->listen_bfd.fd);
+       talloc_free(state);
+}
+
+int tch_csd_sock_recv(struct tch_csd_sock_state *state, struct msgb *msg)
+{
+       unsigned int n_bytes = 0;
+
+       while (msgb_tailroom(msg) > 0) {
+               struct msgb *rmsg = msgb_dequeue(&state->rxqueue);
+               if (rmsg == NULL)
+                       break;
+               size_t len = OSMO_MIN(msgb_tailroom(msg), msgb_length(rmsg));
+               memcpy(msgb_put(msg, len), msgb_data(rmsg), len);
+               msgb_pull(rmsg, len);
+               if (msgb_length(rmsg) > 0)
+                       llist_add(&rmsg->list, &state->rxqueue);
+               else
+                       msgb_free(rmsg);
+               n_bytes += len;
+       }
+
+       return n_bytes;
+}
+
+int tch_csd_sock_send(struct tch_csd_sock_state *state, struct msgb *msg)
+{
+       msgb_enqueue(&state->txqueue, msg);
+       osmo_fd_write_enable(&state->conn_bfd);
+       return 0;
+}

--
To view, visit https://gerrit.osmocom.org/c/osmocom-bb/+/35583?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmocom-bb
Gerrit-Branch: master
Gerrit-Change-Id: Id054af7b3d9d0a41715f7981deb420f6e09bf30c
Gerrit-Change-Number: 35583
Gerrit-PatchSet: 1
Gerrit-Owner: fixeria <vyanits...@sysmocom.de>
Gerrit-MessageType: newchange

Reply via email to