diff options
author | Harald Welte <laforge@gnumonks.org> | 2013-06-06 08:12:04 +0200 |
---|---|---|
committer | Harald Welte <laforge@gnumonks.org> | 2013-06-19 15:31:00 +0200 |
commit | 96c46cff47f9dd6dc81a89e9f407284f9315c89c (patch) | |
tree | 6d6d14a3a2f8e143a743b43bccc683e43a980605 | |
parent | b0bf1da4c87f1ab3f9367bbeea615dc86d13131c (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.h | 1 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 4 | ||||
-rw-r--r-- | openbsc/src/libtrau/Makefile.am | 7 | ||||
-rw-r--r-- | openbsc/src/libtrau/rtp_proxy.c | 36 | ||||
-rw-r--r-- | openbsc/src/libtrau/rtp_proxy_main.c | 250 |
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); + } +} |