[PATCH] libosmo-abis[master]: add basic unixsocket support

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/.

lynxis lazus gerrit-no-reply at lists.osmocom.org
Tue Feb 21 18:57:09 UTC 2017


Hello Harald Welte, Jenkins Builder,

I'd like you to reexamine a change.  Please visit

    https://gerrit.osmocom.org/1198

to look at the new patch set (#16).

add basic unixsocket support

Allow to connect to a unix socket for communicating with LAPD.

Change-Id: Ia5723b09a5c68a0505829dc732def981e60a907a
---
M include/osmocom/abis/e1_input.h
M src/Makefile.am
M src/e1_input.c
M src/e1_input_vty.c
A src/input/unixsocket.c
A src/input/unixsocket_proto.h
6 files changed, 390 insertions(+), 3 deletions(-)


  git pull ssh://gerrit.osmocom.org:29418/libosmo-abis refs/changes/98/1198/16

diff --git a/include/osmocom/abis/e1_input.h b/include/osmocom/abis/e1_input.h
index 4c7f8a0..8501d5c 100644
--- a/include/osmocom/abis/e1_input.h
+++ b/include/osmocom/abis/e1_input.h
@@ -183,6 +183,7 @@
 	unsigned int num;
 	const char *name;
 	unsigned int port_nr;
+	char *sock_path;
 	struct rate_ctr_group *rate_ctr;
 
 	/* keepalive configuration */
@@ -303,6 +304,9 @@
 struct gsm_network;
 int ipaccess_setup(struct gsm_network *gsmnet);
 
+/* activate superchannel or deactive to use timeslots. only valid for unixsocket driver */
+void e1inp_ericsson_set_altc(struct e1inp_line *unixlinue, int superchannel);
+
 extern struct llist_head e1inp_driver_list;
 extern struct llist_head e1inp_line_list;
 
diff --git a/src/Makefile.am b/src/Makefile.am
index b24f2cf..760c1f5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,8 @@
 			 input/lapd.c \
 			 input/lapd_pcap.c \
 			 input/misdn.c \
-			 input/rs232.c
+			 input/rs232.c \
+			 input/unixsocket.c
 
 libosmotrau_la_CFLAGS = $(AM_CFLAGS) $(ORTP_CFLAGS)
 libosmotrau_la_LDFLAGS = $(AM_LDFLAGS) -version-info $(TRAU_LIBVERSION)
diff --git a/src/e1_input.c b/src/e1_input.c
index 09fea59..1e1252e 100644
--- a/src/e1_input.c
+++ b/src/e1_input.c
@@ -807,6 +807,7 @@
 void e1inp_dahdi_init(void);
 void e1inp_ipaccess_init(void);
 void e1inp_rs232_init(void);
+void e1inp_unixsocket_init(void);
 
 void e1inp_init(void)
 {
@@ -821,4 +822,5 @@
 #endif
 	e1inp_ipaccess_init();
 	e1inp_rs232_init();
+	e1inp_unixsocket_init();
 }
diff --git a/src/e1_input_vty.c b/src/e1_input_vty.c
index 5320bb3..9d69586 100644
--- a/src/e1_input_vty.c
+++ b/src/e1_input_vty.c
@@ -38,12 +38,13 @@
 
 /* CONFIG */
 
-#define E1_DRIVER_NAMES		"(misdn|misdn_lapd|dahdi|ipa)"
+#define E1_DRIVER_NAMES		"(misdn|misdn_lapd|dahdi|ipa|unixsocket)"
 #define E1_DRIVER_HELP		"mISDN supported E1 Card (kernel LAPD)\n" \
 				"mISDN supported E1 Card (userspace LAPD)\n" \
 				"DAHDI supported E1/T1/J1 Card\n" \
 				"IPA TCP/IP input\n" \
-				"HSL TCP/IP input"
+				"HSL TCP/IP input\n" \
+				"Unix socket input\n"
 
 #define E1_LINE_HELP		"Configure E1/T1/J1 Line\n" "Line Number\n"
 
@@ -84,6 +85,25 @@
 	}
 
 	line->port_nr = atoi(argv[1]);
+
+	return CMD_SUCCESS;
+}
+
+DEFUN(cfg_e1line_socket, cfg_e1_line_socket_cmd,
+	"e1_line <0-255> socket .SOCKET",
+	E1_LINE_HELP "Set socket path for unixsocket\n"
+	"socket path\n")
+{
+	struct e1inp_line *line;
+	int e1_nr = atoi(argv[0]);
+
+	line = e1inp_line_find(e1_nr);
+	if (!line) {
+		vty_out(vty, "%% Line %d doesn't exist%s", e1_nr, VTY_NEWLINE);
+		return CMD_WARNING;
+	}
+
+	line->sock_path = talloc_strdup(line, argv[1]);
 
 	return CMD_SUCCESS;
 }
@@ -363,6 +383,7 @@
 	vty_install_default(L_E1INP_NODE);
 	install_element(L_E1INP_NODE, &cfg_e1_line_driver_cmd);
 	install_element(L_E1INP_NODE, &cfg_e1_line_port_cmd);
+	install_element(L_E1INP_NODE, &cfg_e1_line_socket_cmd);
 	install_element(L_E1INP_NODE, &cfg_e1_line_name_cmd);
 	install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_cmd);
 	install_element(L_E1INP_NODE, &cfg_e1_line_keepalive_params_cmd);
diff --git a/src/input/unixsocket.c b/src/input/unixsocket.c
new file mode 100644
index 0000000..cfe4f5c
--- /dev/null
+++ b/src/input/unixsocket.c
@@ -0,0 +1,347 @@
+/* OpenBSC Abis receive lapd over a unix socket */
+
+/* (C) 2016 by sysmocom s.f.m.c. GmbH
+ *
+ * Author: Alexander Couzens <lynxis at fe80.eu>
+ * Based on other e1_input drivers.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <limits.h>
+#include <string.h>
+
+#include <osmocom/core/talloc.h>
+#include <osmocom/core/logging.h>
+#include <osmocom/core/socket.h>
+
+#include <osmocom/abis/e1_input.h>
+#include <osmocom/abis/lapd.h>
+#include <osmocom/abis/e1_input.h>
+
+#include "internal.h"
+#include "unixsocket_proto.h"
+
+void *tall_unixsocket_ctx;
+#define UNIXSOCKET_ALLOC_SIZE 1600
+#define UNIXSOCKET_SOCK_PATH_DEFAULT "/tmp/osmo_abis_line_"
+
+struct unixsocket_line {
+	struct osmo_fd fd;
+};
+
+static int unixsocket_line_update(struct e1inp_line *line);
+static int ts_want_write(struct e1inp_ts *e1i_ts);
+
+static int unixsocket_exception_cb(struct osmo_fd *bfd)
+{
+	struct e1inp_line *line = bfd->data;
+
+	LOGP(DLINP, LOGL_ERROR,
+	     "Socket connection failure, reconnecting... (line=%p, fd=%d)\n",
+	     line, bfd->fd);
+
+	/* Unregister faulty file descriptor from select loop */
+	if(osmo_fd_is_registered(bfd)) {
+		LOGP(DLINP, LOGL_DEBUG,
+		     "removing inactive socket from select loop... (line=%p, fd=%d)\n",
+		     line, bfd->fd);
+		osmo_fd_unregister(bfd);
+	}
+
+	/* Close faulty file descriptor */
+	close(bfd->fd);
+
+	unixsocket_line_update(line);
+
+	return 0;
+}
+
+static int unixsocket_read_cb(struct osmo_fd *bfd)
+{
+	struct e1inp_line *line = bfd->data;
+	struct msgb *msg = msgb_alloc(UNIXSOCKET_ALLOC_SIZE, "UNIXSOCKET TS");
+	uint8_t version;
+	uint8_t controldata;
+	int ret;
+
+	if (!msg)
+		return -ENOMEM;
+
+	ret = read(bfd->fd, msg->data, UNIXSOCKET_ALLOC_SIZE - 16);
+	if (ret == 0) {
+		unixsocket_exception_cb(bfd);
+		goto fail;
+	} else if (ret < 0) {
+		perror("read ");
+		goto fail;
+	} else if (ret < 2) {
+		/* packet must be at least 2 byte long to hold version + control/data header */
+		LOGP(DLMI, LOGL_ERROR, "received to small packet: %d < 2", ret);
+		ret = -1;
+		goto fail;
+	}
+	msgb_put(msg, ret);
+
+	LOGP(DLMI, LOGL_DEBUG, "rx msg: %s (fd=%d)\n",
+	     osmo_hexdump_nospc(msg->data, msg->len), bfd->fd);
+
+	/* check version header */
+	version = msgb_pull_u8(msg);
+	controldata = msgb_pull_u8(msg);
+
+	if (version != UNIXSOCKET_PROTO_VERSION) {
+		LOGP(DLMI, LOGL_ERROR, "received message with invalid version %d. valid: %d",
+		     ret, UNIXSOCKET_PROTO_VERSION);
+		ret = -1;
+		goto fail;
+	}
+
+	switch (controldata) {
+	case UNIXSOCKET_PROTO_DATA:
+		return e1inp_rx_ts_lapd(&line->ts[0], msg);
+	case UNIXSOCKET_PROTO_CONTROL:
+		LOGP(DLMI, LOGL_ERROR, "received (invalid) control message.");
+		ret = -1;
+		break;
+	default:
+		LOGP(DLMI, LOGL_ERROR, "received invalid message.");
+		ret = -1;
+		break;
+	}
+fail:
+	msgb_free(msg);
+	return ret;
+}
+
+static void timeout_ts1_write(void *data)
+{
+	struct e1inp_ts *e1i_ts = (struct e1inp_ts *)data;
+
+	/* trigger write of ts1, due to tx delay timer */
+	ts_want_write(e1i_ts);
+}
+
+static int unixsocket_write_cb(struct osmo_fd *bfd)
+{
+	struct e1inp_line *line = bfd->data;
+	struct e1inp_ts *e1i_ts = &line->ts[0];
+	struct msgb *msg;
+	struct e1inp_sign_link *sign_link;
+
+	bfd->when &= ~BSC_FD_WRITE;
+
+	/* get the next msg for this timeslot */
+	msg = e1inp_tx_ts(e1i_ts, &sign_link);
+	if (!msg) {
+		/* no message after tx delay timer */
+		LOGP(DLINP, LOGL_INFO,
+		     "no message available (line=%p)\n", line);
+		return 0;
+	}
+
+	/* set tx delay timer for next event */
+	e1i_ts->sign.tx_timer.cb = timeout_ts1_write;
+	e1i_ts->sign.tx_timer.data = e1i_ts;
+
+	osmo_timer_schedule(&e1i_ts->sign.tx_timer, 0, e1i_ts->sign.delay);
+
+	LOGP(DLINP, LOGL_DEBUG, "sending: %s (line=%p)\n",
+	     msgb_hexdump(msg), line);
+	lapd_transmit(e1i_ts->lapd, sign_link->tei,
+			sign_link->sapi, msg);
+
+	return 0;
+}
+
+static int unixsocket_cb(struct osmo_fd *bfd, unsigned int what)
+{
+	int ret = 0;
+
+	if (what & BSC_FD_READ)
+		ret = unixsocket_read_cb(bfd);
+	if (what & BSC_FD_WRITE)
+		ret = unixsocket_write_cb(bfd);
+
+	return ret;
+}
+
+static int ts_want_write(struct e1inp_ts *e1i_ts)
+{
+	struct unixsocket_line *line = e1i_ts->line->driver_data;
+
+	line->fd.when |= BSC_FD_WRITE;
+
+	return 0;
+}
+
+static void unixsocket_write_msg(struct msgb *msg, struct osmo_fd *bfd) {
+	int ret;
+
+	LOGP(DLMI, LOGL_DEBUG, "tx msg: %s (fd=%d)\n",
+	     osmo_hexdump_nospc(msg->data, msg->len), bfd->fd);
+
+	ret = write(bfd->fd, msg->data, msg->len);
+	msgb_free(msg);
+	if (ret == -1)
+		unixsocket_exception_cb(bfd);
+	else if (ret < 0)
+		LOGP(DLMI, LOGL_NOTICE, "%s write failed %d\n", __func__, ret);
+}
+
+/*!
+ * \brief unixsocket_write_msg lapd callback for data to unixsocket
+ * \param msg
+ * \param cbdata
+ */
+static void unixsocket_write_msg_lapd_cb(struct msgb *msg, void *cbdata)
+{
+	struct osmo_fd *bfd = cbdata;
+
+	/* data|control */
+	msgb_push_u8(msg, UNIXSOCKET_PROTO_DATA);
+	/* add version header */
+	msgb_push_u8(msg, UNIXSOCKET_PROTO_VERSION);
+
+	unixsocket_write_msg(msg, bfd);
+}
+
+static int unixsocket_line_update(struct e1inp_line *line)
+{
+	struct unixsocket_line *config;
+	char sock_path[PATH_MAX];
+	int ret = 0;
+	int i;
+
+	if (line->sock_path)
+		strcpy(sock_path, line->sock_path);
+	else
+		sprintf(sock_path, "%s%d", UNIXSOCKET_SOCK_PATH_DEFAULT,
+			line->num);
+
+	LOGP(DLINP, LOGL_NOTICE, "line update (line=%p)\n", line);
+
+	if (!line->driver_data)
+		line->driver_data = talloc_zero(line, struct unixsocket_line);
+
+	if (!line->driver_data) {
+		LOGP(DLINP, LOGL_ERROR,
+		     "OOM in line update (line=%p)\n", line);
+		return -ENOMEM;
+	}
+
+	config = line->driver_data;
+	config->fd.data = line;
+	config->fd.when = BSC_FD_READ;
+	config->fd.cb = unixsocket_cb;
+
+	/* Open unix domain socket */
+	ret = osmo_sock_unix_init(SOCK_SEQPACKET, 0, sock_path,
+				  OSMO_SOCK_F_CONNECT);
+	if (ret < 0) {
+		/* Note: We will not free the allocated driver_data memory if
+		 * opening the socket fails. The caller may want to call this
+		 * function multiple times using config->fd.data as line
+		 * parameter. Freeing now would destroy that reference. */
+		LOGP(DLINP, LOGL_ERROR,
+		     "unable to open socket: %s (line=%p, fd=%d)\n", sock_path,
+		     line, config->fd.fd);
+		return ret;
+	}
+	LOGP(DLINP, LOGL_DEBUG,
+	     "successfully opend (new) socket: %s (line=%p, fd=%d, ret=%d)\n",
+	     sock_path, line, config->fd.fd, ret);
+	config->fd.fd = ret;
+
+	/* Register socket in select loop */
+	if (osmo_fd_register(&config->fd) < 0) {
+		LOGP(DLINP, LOGL_ERROR,
+		     "error registering new socket (line=%p, fd=%d)\n",
+		     line, config->fd.fd);
+		close(config->fd.fd);
+		return -EIO;
+	}
+
+	/* Set line parameter */
+	for (i = 0; i < ARRAY_SIZE(line->ts); i++) {
+		struct e1inp_ts *e1i_ts = &line->ts[i];
+		if (!e1i_ts->lapd) {
+			e1i_ts->lapd = lapd_instance_alloc(1,
+				unixsocket_write_msg_lapd_cb, &config->fd,
+				e1inp_dlsap_up, e1i_ts, &lapd_profile_abis);
+		}
+	}
+
+	/* Ensure ericsson-superchannel is turned of when
+	 * a new connection is made */
+	e1inp_ericsson_set_altc(line, 0);
+
+	return ret;
+}
+
+struct e1inp_driver unixsocket_driver = {
+	.name = "unixsocket",
+	.want_write = ts_want_write,
+	.line_update = unixsocket_line_update,
+	.default_delay = 0,
+};
+
+void e1inp_unixsocket_init(void)
+{
+	tall_unixsocket_ctx = talloc_named_const(libosmo_abis_ctx, 1, "unixsocket");
+	e1inp_driver_register(&unixsocket_driver);
+}
+
+void e1inp_ericsson_set_altc(struct e1inp_line *unixline, int superchannel)
+{
+	struct unixsocket_line *config;
+	struct msgb *msg;
+
+	if (!unixline)
+		return;
+
+	if (unixline->driver != &unixsocket_driver) {
+		LOGP(DLMI, LOGL_NOTICE, "altc is only supported by unixsocket\n");
+		return;
+	}
+
+	config = unixline->driver_data;
+	if (!config) {
+		LOGP(DLMI, LOGL_NOTICE, "e1inp driver not yet initialized.\n");
+		return;
+	}
+
+
+	msg = msgb_alloc_headroom(200, 100, "ALTC");
+
+	/* version header */
+	msgb_put_u8(msg, UNIXSOCKET_PROTO_VERSION);
+	/* data|control */
+	msgb_put_u8(msg, UNIXSOCKET_PROTO_CONTROL);
+
+	/* magic */
+	msgb_put_u32(msg, 0x23004200);
+	msgb_put_u8(msg, superchannel ? 1 : 0);
+
+	unixsocket_write_msg(msg, &config->fd);
+}
+
diff --git a/src/input/unixsocket_proto.h b/src/input/unixsocket_proto.h
new file mode 100644
index 0000000..beba667
--- /dev/null
+++ b/src/input/unixsocket_proto.h
@@ -0,0 +1,12 @@
+
+#ifndef UNIXSOCKET_PROTO_H
+#define UNIXSOCKET_PROTO_H
+
+#define UNIXSOCKET_PROTO_VERSION 0x1
+
+enum {
+	UNIXSOCKET_PROTO_DATA = 0x0,
+	UNIXSOCKET_PROTO_CONTROL = 0x1,
+};
+
+#endif /* UNIXSOCKET_PROTO_H */

-- 
To view, visit https://gerrit.osmocom.org/1198
To unsubscribe, visit https://gerrit.osmocom.org/settings

Gerrit-MessageType: newpatchset
Gerrit-Change-Id: Ia5723b09a5c68a0505829dc732def981e60a907a
Gerrit-PatchSet: 16
Gerrit-Project: libosmo-abis
Gerrit-Branch: master
Gerrit-Owner: lynxis lazus <lynxis at fe80.eu>
Gerrit-Reviewer: Harald Welte <laforge at gnumonks.org>
Gerrit-Reviewer: Holger Freyther <holger at freyther.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier at sysmocom.de>
Gerrit-Reviewer: lynxis lazus <lynxis at fe80.eu>



More information about the gerrit-log mailing list