aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2013-06-19 13:10:40 +0200
committerHarald Welte <laforge@gnumonks.org>2013-06-19 15:31:00 +0200
commit7083fd4389ff426ba139742a6f534f13c444fabf (patch)
tree8dcd2927b48eda90747fa5f2959799be9c85cb2c
parent96c46cff47f9dd6dc81a89e9f407284f9315c89c (diff)
rtp_proxy: add RTP_LOOPBACK mode for local loop back
This will echo back all voice received on the socket back to the same socket/subscriber. If we mark a socket as LOOPBACK at the BSC, we don't yet know a priori which source IP/port the BTS side of the socket will have, so we can only bind our local IP+port. Only once the first message from the BTS arrives at the BSC rtp_proxy, we know the source and should do a connect() to that remote address. The rtp_proxy has no idea when a call is disconnected, so the loopback mode only works for the first call, but no subsequent calls. This patch compares IP/PORT of the BTS side of the RTP flow and issues a new connect only if it is not the current remote address.
-rw-r--r--openbsc/include/openbsc/rtp_proxy.h2
-rw-r--r--openbsc/src/libtrau/rtp_proxy.c30
-rw-r--r--openbsc/src/libtrau/rtp_proxy_main.c33
3 files changed, 62 insertions, 3 deletions
diff --git a/openbsc/include/openbsc/rtp_proxy.h b/openbsc/include/openbsc/rtp_proxy.h
index 9d8d5832e..f9a55ebb0 100644
--- a/openbsc/include/openbsc/rtp_proxy.h
+++ b/openbsc/include/openbsc/rtp_proxy.h
@@ -38,6 +38,7 @@ enum rtp_rx_action {
RTP_NONE,
RTP_PROXY,
RTP_RECV_UPSTREAM,
+ RTP_LOOPBACK
};
enum rtp_tx_action {
@@ -85,6 +86,7 @@ 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_loopback(struct rtp_socket *s);
int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, uint32_t callref);
int rtp_socket_free(struct rtp_socket *rs);
int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame);
diff --git a/openbsc/src/libtrau/rtp_proxy.c b/openbsc/src/libtrau/rtp_proxy.c
index 693a57a91..f00b1656b 100644
--- a/openbsc/src/libtrau/rtp_proxy.c
+++ b/openbsc/src/libtrau/rtp_proxy.c
@@ -392,11 +392,15 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP");
struct msgb *new_msg;
struct rtp_sub_socket *other_rss;
+ struct sockaddr_in src_addr;
+ socklen_t src_addrlen;
if (!msg)
return -ENOMEM;
- rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE);
+ src_addrlen = sizeof(src_addr);
+ rc = recvfrom(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE, 0,
+ (struct sockaddr *)&src_addr, &src_addrlen);
if (rc <= 0) {
rss->bfd.when &= ~BSC_FD_READ;
return rc;
@@ -405,6 +409,20 @@ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
msgb_put(msg, rc);
switch (rs->rx_action) {
+ case RTP_LOOPBACK:
+ /* if this socket is not connected yet to a remote
+ * address, do so now */
+ if (rss->sin_local.sin_addr.s_addr != src_addr.sin_addr.s_addr ||
+ rss->sin_local.sin_port != src_addr.sin_port) {
+ LOGP(DLMUX, LOGL_INFO, "connecting loopback socket\n");
+ rc = rtp_socket_connect(rs,
+ ntohl(src_addr.sin_addr.s_addr),
+ ntohs(src_addr.sin_port));
+ }
+ /* FIXME: Do we need RTCP mangling here? */
+ msgb_enqueue(&rss->tx_queue, msg);
+ rss->bfd.when |= BSC_FD_WRITE;
+ break;
case RTP_PROXY:
if (!rs->proxy.other_sock) {
rc = -EIO;
@@ -724,6 +742,16 @@ int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other)
return 0;
}
+/*! \brief put socket into loopback mode, echong back all data
+ * \param[in] RTP socket to be put in loopback mode
+ */
+int rtp_socket_loopback(struct rtp_socket *s)
+{
+ s->rx_action = RTP_LOOPBACK;
+
+ return 0;
+}
+
/*! \brief bind RTP/RTCP socket to application, disabling proxy
* \param[in] this RTP socket
* \param[in] net gsm_network argument to trau_tx_to_mncc()
diff --git a/openbsc/src/libtrau/rtp_proxy_main.c b/openbsc/src/libtrau/rtp_proxy_main.c
index afb245364..87d6b7723 100644
--- a/openbsc/src/libtrau/rtp_proxy_main.c
+++ b/openbsc/src/libtrau/rtp_proxy_main.c
@@ -143,6 +143,29 @@ static struct vty_app_info vty_info = {
.is_config_node = bsc_vty_is_config_node,
};
+static int create_socket_loop(uint16_t port)
+{
+ struct rtp_socket *s;
+ int rc;
+
+ s = rtp_socket_create();
+ if (!s)
+ return -EIO;
+
+ rc = rtp_socket_bind_port(s, INADDR_ANY, port);
+ if (rc < 0)
+ goto err_free_s;
+
+ rc = rtp_socket_loopback(s);
+ if (rc < 0)
+ goto err_free_s;
+
+ return 0;
+err_free_s:
+ rtp_socket_free(s);
+ return -EIO;
+}
+
static int create_socket_pair(uint16_t port1, uint16_t port2)
{
struct rtp_socket *a, *b;
@@ -225,15 +248,21 @@ int main(int argc, char **argv)
osmo_init_ignore_signals();
/* hard-wire map CIC 1->33, 2->33, ... */
- for (i = 1; i <= 4; i++) {
+ for (i = 1; i <= 8; 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);
+ printf("Creating UDP port mapping (%u,%u:%u) -> (%u,%u:%u)\n",
+ 0,i,1,i,port1, port2);
rc = create_socket_pair(port1, port2);
if (rc < 0)
exit(1);
}
+ printf("Creating loopback CIC (%u,%u:%u)\n",
+ 0, 16, PORT_BY_CIC(0, 16));
+ rc = create_socket_loop(PORT_BY_CIC(0,16));
+ if (rc < 0)
+ exit(1);
if (daemonize) {
rc = osmo_daemonize();