aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2013-06-06 08:12:04 +0200
committerHarald Welte <laforge@gnumonks.org>2013-06-19 15:31:00 +0200
commit96c46cff47f9dd6dc81a89e9f407284f9315c89c (patch)
tree6d6d14a3a2f8e143a743b43bccc683e43a980605
parentb0bf1da4c87f1ab3f9367bbeea615dc86d13131c (diff)
initial version of a stand-alone RTP proxy
The idea is to use this initially for local CIC loopback at the BSC, but hopefully later also remove the RTP stream handling from the osmo-nitb binary altogether.
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h1
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c4
-rw-r--r--openbsc/src/libtrau/Makefile.am7
-rw-r--r--openbsc/src/libtrau/rtp_proxy.c36
-rw-r--r--openbsc/src/libtrau/rtp_proxy_main.c250
5 files changed, 291 insertions, 7 deletions
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index 26cac0df4..9d8d5832e 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -82,6 +82,7 @@ struct rtp_socket {
struct rtp_socket *rtp_socket_create(void);
int rtp_socket_bind(struct rtp_socket *rs, uint32_t ip);
+int rtp_socket_bind_port(struct rtp_socket *rs, uint32_t ip, uint16_t port);
int rtp_socket_connect(struct rtp_socket *rs, uint32_t ip, uint16_t port);
int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other);
int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, uint32_t callref);
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index cd31f6974..436d29556 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -1466,6 +1466,10 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,
if (!lchan->abis_ip.rtp_socket)
return -EIO;
+ rc = rtp_socket_bind(lchan->abis_ip.rtp_socket, INADDR_ANY);
+ if (rc < 0)
+ return -EIO;
+
rc = rtp_socket_connect(lchan->abis_ip.rtp_socket,
lchan->abis_ip.bound_ip,
lchan->abis_ip.bound_port);
diff --git a/openbsc/src/libtrau/Makefile.am b/openbsc/src/libtrau/Makefile.am
index 0c8cf17b5..871e02f64 100644
--- a/openbsc/src/libtrau/Makefile.am
+++ b/openbsc/src/libtrau/Makefile.am
@@ -5,3 +5,10 @@ AM_LDFLAGS = $(LIBOSMOCORE_LIBS) $(LIBOSMOGSM_LIBS) $(LIBOSMOABIS_LIBS) $(COVERA
noinst_LIBRARIES = libtrau.a
libtrau_a_SOURCES = rtp_proxy.c trau_mux.c trau_upqueue.c
+
+bin_PROGRAMS = osmo-rtpproxy
+
+osmo_rtpproxy_SOURCES = rtp_proxy_main.c
+osmo_rtpproxy_LDADD = libtrau.a ../libcommon/libcommon.a
+osmo_rtpproxy_CFLAGS = $(AM_CFLAGS) $(LIBOSMOVTY_CFLAGS)
+osmo_rtpproxy_LDFLAGS = $(AM_LDFLAGS) $(LIBOSMOVTY_LIBS)
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index 0074b4a04..693a57a91 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -563,15 +563,8 @@ struct rtp_socket *rtp_socket_create(void)
goto out_rtcp_socket;
DEBUGPC(DLMUX, "success\n");
-
- rc = rtp_socket_bind(rs, INADDR_ANY);
- if (rc < 0)
- goto out_rtcp_bfd;
-
return rs;
-out_rtcp_bfd:
- osmo_fd_unregister(&rs->rtcp.bfd);
out_rtcp_socket:
close(rs->rtcp.bfd.fd);
out_rtp_bfd:
@@ -644,6 +637,35 @@ int rtp_socket_bind(struct rtp_socket *rs, uint32_t ip)
return ntohs(rs->rtp.sin_local.sin_port);
}
+int rtp_socket_bind_port(struct rtp_socket *rs, uint32_t ip, uint16_t port)
+{
+ int rc = -EIO;
+ struct in_addr ia;
+
+ ia.s_addr = htonl(ip);
+ DEBUGP(DLMUX, "rtp_socket_bind_port(rs=%p, IP=%s): ", rs,
+ inet_ntoa(ia));
+
+ /* try to bind to a consecutive pair of ports */
+ rc = rtp_sub_socket_bind(&rs->rtp, ip, port);
+ if (rc < 0) {
+ DEBUGPC(DLMUX, "failed\n");
+ return rc;
+ }
+
+ rc = rtp_sub_socket_bind(&rs->rtcp, ip, port+1);
+ if (rc < 0) {
+ DEBUGPC(DLMUX, "failed\n");
+ return rc;
+ }
+
+ ia.s_addr = rs->rtp.sin_local.sin_addr.s_addr;
+ DEBUGPC(DLMUX, "BOUND_IP=%s, BOUND_PORT=%u\n",
+ inet_ntoa(ia), ntohs(rs->rtp.sin_local.sin_port));
+
+ return 0;
+}
+
static int rtp_sub_socket_connect(struct rtp_sub_socket *rss,
uint32_t ip, uint16_t port)
{
diff --git a/openbsc/src/libtrau/rtp_proxy_main.c b/openbsc/src/libtrau/rtp_proxy_main.c
new file mode 100644
index 000000000..afb245364
--- /dev/null
+++ b/openbsc/src/libtrau/rtp_proxy_main.c
@@ -0,0 +1,250 @@
+/* A hackish minimal TRAU and RTP multiplexing */
+
+/* (C) 2013 by Harald Welte <laforge@gnumonks.org>
+ * 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/licenses/>.
+ *
+ */
+
+#include <unistd.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include <osmocom/core/application.h>
+#include <osmocom/core/select.h>
+#include <osmocom/core/talloc.h>
+#include <osmocom/abis/abis.h>
+#include <osmocom/abis/e1_input.h>
+#include <osmocom/vty/telnet_interface.h>
+#include <osmocom/vty/logging.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/signal.h>
+#include <openbsc/vty.h>
+#include <openbsc/rtp_proxy.h>
+
+#include "../../bscconfig.h"
+
+static const char *config_file = "osmo-rtp_proxy.cfg";
+extern const char *openbsc_copyright;
+static int daemonize = 0;
+
+static void print_usage()
+{
+ printf("Usage: osmo-rtp_proxy\n");
+}
+
+static void print_help()
+{
+ printf(" Some useful help...\n");
+ printf(" -h --help this text\n");
+ printf(" -D --daemonize Fork the process into a background daemon\n");
+ printf(" -c --config-file filename The config file to use.\n");
+ printf(" -V --version. Print the version of OpenBSC.\n");
+}
+
+static void handle_options(int argc, char **argv)
+{
+ while (1) {
+ int option_index = 0, c;
+ static struct option long_options[] = {
+ {"help", 0, 0, 'h'},
+ {"debug", 1, 0, 'd'},
+ {"daemonize", 0, 0, 'D'},
+ {"config-file", 1, 0, 'c'},
+ {"version", 0, 0, 'V' },
+ {0, 0, 0, 0}
+ };
+
+ c = getopt_long(argc, argv, "hd:DVc:",
+ long_options, &option_index);
+ if (c == -1)
+ break;
+
+ switch (c) {
+ case 'h':
+ print_usage();
+ print_help();
+ exit(0);
+ case 'd':
+ log_parse_category_mask(osmo_stderr_target, optarg);
+ break;
+ case 'D':
+ daemonize = 1;
+ break;
+ case 'c':
+ config_file = strdup(optarg);
+ break;
+ case 'V':
+ print_version(1);
+ exit(0);
+ break;
+ default:
+ /* ignore */
+ break;
+ }
+ }
+}
+
+static void signal_handler(int signal)
+{
+ fprintf(stdout, "signal %u received\n", signal);
+
+ switch (signal) {
+ case SIGINT:
+ osmo_signal_dispatch(SS_L_GLOBAL, S_L_GLOBAL_SHUTDOWN, NULL);
+ sleep(3);
+ exit(0);
+ break;
+ case SIGABRT:
+ /* in case of abort, we want to obtain a talloc report
+ * and then return to the caller, who will abort the process */
+ case SIGUSR1:
+ talloc_report_full(tall_bsc_ctx, stderr);
+ break;
+ case SIGUSR2:
+ break;
+ default:
+ break;
+ }
+}
+
+void gsm_net_update_ctype(struct gsm_network *network)
+{
+}
+
+extern enum node_type bsc_vty_go_parent(struct vty *vty);
+
+static struct vty_app_info vty_info = {
+ .name = "OsmoRTP",
+ .version = PACKAGE_VERSION,
+ .go_parent_cb = bsc_vty_go_parent,
+ .is_config_node = bsc_vty_is_config_node,
+};
+
+static int create_socket_pair(uint16_t port1, uint16_t port2)
+{
+ struct rtp_socket *a, *b;
+ uint32_t localhost = 0x7f000001;
+ int rc;
+
+ a = rtp_socket_create();
+ if (!a)
+ return -EIO;
+
+ b = rtp_socket_create();
+ if (!a)
+ goto err_free_a;
+
+ rc = rtp_socket_bind_port(a, INADDR_ANY, port1);
+ if (rc < 0)
+ goto err_free;
+
+ rc = rtp_socket_bind_port(b, INADDR_ANY, port2);
+ if (rc < 0)
+ goto err_free;
+
+ rc = rtp_socket_connect(a, localhost, port2);
+ if (rc < 0)
+ goto err_free;
+
+ rtp_socket_connect(b, localhost, port1);
+ if (rc < 0)
+ goto err_free;
+
+ rc = rtp_socket_proxy(a, b);
+ if (rc < 0)
+ goto err_free;
+
+ return 0;
+
+err_free:
+ rtp_socket_free(b);
+err_free_a:
+ rtp_socket_free(a);
+
+ return -EIO;
+}
+
+
+#define PORT_BY_CIC(mux, x) (4000 + ((mux)*32)+((x)*2))
+
+int main(int argc, char **argv)
+{
+ int rc, i;
+ struct gsm_network dummy_network;
+
+ vty_info.copyright = openbsc_copyright;
+
+ tall_bsc_ctx = talloc_named_const(NULL, 1, "osmortp");
+
+ libosmo_abis_init(tall_bsc_ctx);
+ osmo_init_logging(&log_info);
+
+ /* This needs to precede handle_options() */
+ vty_init(&vty_info);
+ logging_vty_add_cmds(&log_info);
+
+ /* parse options */
+ handle_options(argc, argv);
+
+ /* FIXME: parse config file */
+
+ rc = telnet_init(tall_bsc_ctx, &dummy_network, 4239);
+ if (rc < 0)
+ return rc;
+
+ /* seed the PRNG */
+ srand(time(NULL));
+
+ signal(SIGINT, &signal_handler);
+ signal(SIGABRT, &signal_handler);
+ signal(SIGUSR1, &signal_handler);
+ signal(SIGUSR2, &signal_handler);
+ osmo_init_ignore_signals();
+
+ /* hard-wire map CIC 1->33, 2->33, ... */
+ for (i = 1; i <= 4; i++) {
+ uint16_t port1, port2;
+ port1 = PORT_BY_CIC(0, i);
+ port2 = PORT_BY_CIC(1, i);
+ printf("Creating UDP port mapping %u -> %u\n", port1, port2);
+ rc = create_socket_pair(port1, port2);
+ if (rc < 0)
+ exit(1);
+ }
+
+ if (daemonize) {
+ rc = osmo_daemonize();
+ if (rc < 0) {
+ perror("Error during daemonize");
+ exit(1);
+ }
+ }
+
+ while (1) {
+ log_reset_context();
+ osmo_select_main(0);
+ }
+}