aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2010-02-21 11:11:04 +0100
committerHolger Hans Peter Freyther <zecke@selfish.org>2010-02-22 12:09:41 +0100
commit1b0ea97457e6f0c00ad34a44fe77d99668bf840c (patch)
tree3ab61b9e634d1a5a0001f1b679a051eea29f2412
parent6414a0cb223f5ec0651ff3423c7cf9f66d4e0909 (diff)
[mgcp] Move the network bits to a separate file...
This change separates the protocol from the actual network code (bind, forward data). This will allow to more easily hook up the RTP code from OpenBSC and to not use local sockets at all.
-rw-r--r--openbsc/src/Makefile.am2
-rw-r--r--openbsc/src/mgcp/mgcp_network.c218
-rw-r--r--openbsc/src/mgcp/mgcp_protocol.c190
3 files changed, 224 insertions, 186 deletions
diff --git a/openbsc/src/Makefile.am b/openbsc/src/Makefile.am
index dec635933..a73399ed7 100644
--- a/openbsc/src/Makefile.am
+++ b/openbsc/src/Makefile.am
@@ -38,7 +38,7 @@ ipaccess_config_LDADD = libbsc.a libmsc.a libbsc.a libvty.a -ldl -ldbi $(LIBCRYP
isdnsync_SOURCES = isdnsync.c
-bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_vty.c \
+bsc_mgcp_SOURCES = mgcp/mgcp_main.c mgcp/mgcp_protocol.c mgcp/mgcp_network.c mgcp/mgcp_vty.c \
msgb.c talloc.c debug.c select.c timer.c telnet_interface.c
bsc_mgcp_LDADD = libvty.a
diff --git a/openbsc/src/mgcp/mgcp_network.c b/openbsc/src/mgcp/mgcp_network.c
new file mode 100644
index 000000000..e92b0742e
--- /dev/null
+++ b/openbsc/src/mgcp/mgcp_network.c
@@ -0,0 +1,218 @@
+/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
+/* The protocol implementation */
+
+/*
+ * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * (C) 2009-2010 by On-Waves
+ * 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 <string.h>
+#include <unistd.h>
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include <openbsc/debug.h>
+#include <openbsc/mgcp.h>
+#include <openbsc/mgcp_internal.h>
+#include <openbsc/msgb.h>
+#include <openbsc/talloc.h>
+#include <openbsc/select.h>
+
+#warning "Make use of the rtp proxy code"
+
+
+enum {
+ DEST_NETWORK = 0,
+ DEST_BTS = 1,
+};
+
+enum {
+ PROTO_RTP,
+ PROTO_RTCP,
+};
+
+
+static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
+{
+ struct sockaddr_in out;
+ out.sin_family = AF_INET;
+ out.sin_port = port;
+ memcpy(&out.sin_addr, addr, sizeof(*addr));
+
+ return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
+}
+
+/*
+ * There is data coming. We will have to figure out if it
+ * came from the BTS or the MediaGateway of the MSC. On top
+ * of that we need to figure out if it was RTP or RTCP.
+ *
+ * Currently we do not communicate with the BSC so we have
+ * no idea where the BTS is listening for RTP and need to
+ * do the classic routing trick. Wait for the first packet
+ * from the BTS and then go ahead.
+ */
+static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
+{
+ char buf[4096];
+ struct sockaddr_in addr;
+ socklen_t slen = sizeof(addr);
+ struct mgcp_endpoint *endp;
+ struct mgcp_config *cfg;
+ int rc, dest, proto;
+
+ endp = (struct mgcp_endpoint *) fd->data;
+ cfg = endp->cfg;
+
+ rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
+ (struct sockaddr *) &addr, &slen);
+ if (rc < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
+ ENDPOINT_NUMBER(endp));
+ return -1;
+ }
+
+ /* do not forward aynthing... maybe there is a packet from the bts */
+ if (endp->ci == CI_UNUSED) {
+ LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
+ return -1;
+ }
+
+ /*
+ * Figure out where to forward it to. This code assumes that we
+ * have received the Connection Modify and know who is a legitimate
+ * partner. According to the spec we could attempt to forward even
+ * after the Create Connection but we will not as we are not really
+ * able to tell if this is legitimate.
+ */
+ #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
+ dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
+ (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
+ ? DEST_BTS : DEST_NETWORK;
+ proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
+
+ /* We have no idea who called us, maybe it is the BTS. */
+ if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
+ /* it was the BTS... */
+ if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
+ if (fd == &endp->local_rtp) {
+ endp->bts_rtp = addr.sin_port;
+ } else {
+ endp->bts_rtcp = addr.sin_port;
+ }
+
+ endp->bts = addr.sin_addr;
+ LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
+ ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
+ }
+ }
+
+ /* dispatch */
+ if (cfg->audio_loop)
+ dest = !dest;
+
+ if (dest == DEST_NETWORK) {
+ return udp_send(fd->fd, &endp->remote,
+ proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
+ buf, rc);
+ } else {
+ return udp_send(fd->fd, &endp->bts,
+ proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
+ buf, rc);
+ }
+}
+
+static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
+{
+ struct sockaddr_in addr;
+ int on = 1;
+
+ fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd->fd < 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n");
+ return -1;
+ }
+
+ setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ inet_aton(source_addr, &addr.sin_addr);
+
+ if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+static int bind_rtp(struct mgcp_endpoint *endp)
+{
+ struct mgcp_config *cfg = endp->cfg;
+
+ if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
+ cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
+ goto cleanup0;
+ }
+
+ if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
+ cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
+ goto cleanup1;
+ }
+
+ endp->local_rtp.cb = rtp_data_cb;
+ endp->local_rtp.data = endp;
+ endp->local_rtp.when = BSC_FD_READ;
+ if (bsc_register_fd(&endp->local_rtp) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
+ endp->rtp_port, ENDPOINT_NUMBER(endp));
+ goto cleanup2;
+ }
+
+ endp->local_rtcp.cb = rtp_data_cb;
+ endp->local_rtcp.data = endp;
+ endp->local_rtcp.when = BSC_FD_READ;
+ if (bsc_register_fd(&endp->local_rtcp) != 0) {
+ LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
+ endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
+ goto cleanup3;
+ }
+
+ return 0;
+
+cleanup3:
+ bsc_unregister_fd(&endp->local_rtp);
+cleanup2:
+ close(endp->local_rtcp.fd);
+ endp->local_rtcp.fd = -1;
+cleanup1:
+ close(endp->local_rtp.fd);
+ endp->local_rtp.fd = -1;
+cleanup0:
+ return -1;
+}
+
+int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
+{
+ endp->rtp_port = rtp_port;
+ return bind_rtp(endp);
+}
diff --git a/openbsc/src/mgcp/mgcp_protocol.c b/openbsc/src/mgcp/mgcp_protocol.c
index f7588cd38..aaa9bc582 100644
--- a/openbsc/src/mgcp/mgcp_protocol.c
+++ b/openbsc/src/mgcp/mgcp_protocol.c
@@ -30,9 +30,6 @@
#include <limits.h>
#include <unistd.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-
#include <openbsc/debug.h>
#include <openbsc/msgb.h>
#include <openbsc/talloc.h>
@@ -41,8 +38,6 @@
#include <openbsc/mgcp.h>
#include <openbsc/mgcp_internal.h>
-#warning "Make use of the rtp proxy code"
-
enum mgcp_connection_mode {
MGCP_CONN_NONE = 0,
MGCP_CONN_RECV_ONLY = 1,
@@ -50,16 +45,6 @@ enum mgcp_connection_mode {
MGCP_CONN_RECV_SEND = MGCP_CONN_RECV_ONLY | MGCP_CONN_SEND_ONLY,
};
-enum {
- DEST_NETWORK = 0,
- DEST_BTS = 1,
-};
-
-enum {
- PROTO_RTP,
- PROTO_RTCP,
-};
-
/**
* Macro for tokenizing MGCP messages and SDP in one go.
*
@@ -140,168 +125,6 @@ static unsigned int generate_transaction_id()
return abs(rand());
}
-static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
-{
- struct sockaddr_in out;
- out.sin_family = AF_INET;
- out.sin_port = port;
- memcpy(&out.sin_addr, addr, sizeof(*addr));
-
- return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
-}
-
-/*
- * There is data coming. We will have to figure out if it
- * came from the BTS or the MediaGateway of the MSC. On top
- * of that we need to figure out if it was RTP or RTCP.
- *
- * Currently we do not communicate with the BSC so we have
- * no idea where the BTS is listening for RTP and need to
- * do the classic routing trick. Wait for the first packet
- * from the BTS and then go ahead.
- */
-static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
-{
- char buf[4096];
- struct sockaddr_in addr;
- socklen_t slen = sizeof(addr);
- struct mgcp_endpoint *endp;
- struct mgcp_config *cfg;
- int rc, dest, proto;
-
- endp = (struct mgcp_endpoint *) fd->data;
- cfg = endp->cfg;
-
- rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
- (struct sockaddr *) &addr, &slen);
- if (rc < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
- ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- /* do not forward aynthing... maybe there is a packet from the bts */
- if (endp->ci == CI_UNUSED) {
- LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
- return -1;
- }
-
- /*
- * Figure out where to forward it to. This code assumes that we
- * have received the Connection Modify and know who is a legitimate
- * partner. According to the spec we could attempt to forward even
- * after the Create Connection but we will not as we are not really
- * able to tell if this is legitimate.
- */
- #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
- dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
- (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
- ? DEST_BTS : DEST_NETWORK;
- proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
-
- /* We have no idea who called us, maybe it is the BTS. */
- if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
- /* it was the BTS... */
- if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
- if (fd == &endp->local_rtp) {
- endp->bts_rtp = addr.sin_port;
- } else {
- endp->bts_rtcp = addr.sin_port;
- }
-
- endp->bts = addr.sin_addr;
- LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
- ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
- }
- }
-
- /* dispatch */
- if (cfg->audio_loop)
- dest = !dest;
-
- if (dest == DEST_NETWORK) {
- return udp_send(fd->fd, &endp->remote,
- proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
- buf, rc);
- } else {
- return udp_send(fd->fd, &endp->bts,
- proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
- buf, rc);
- }
-}
-
-static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
-{
- struct sockaddr_in addr;
- int on = 1;
-
- fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
- if (fd->fd < 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n");
- return -1;
- }
-
- setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- inet_aton(source_addr, &addr.sin_addr);
-
- if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- return -1;
- }
-
- return 0;
-}
-
-static int bind_rtp(struct mgcp_endpoint *endp)
-{
- struct mgcp_config *cfg = endp->cfg;
-
- if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
- cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
- goto cleanup0;
- }
-
- if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
- cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
- goto cleanup1;
- }
-
- endp->local_rtp.cb = rtp_data_cb;
- endp->local_rtp.data = endp;
- endp->local_rtp.when = BSC_FD_READ;
- if (bsc_register_fd(&endp->local_rtp) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
- endp->rtp_port, ENDPOINT_NUMBER(endp));
- goto cleanup2;
- }
-
- endp->local_rtcp.cb = rtp_data_cb;
- endp->local_rtcp.data = endp;
- endp->local_rtcp.when = BSC_FD_READ;
- if (bsc_register_fd(&endp->local_rtcp) != 0) {
- LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
- endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
- goto cleanup3;
- }
-
- return 0;
-
-cleanup3:
- bsc_unregister_fd(&endp->local_rtp);
-cleanup2:
- close(endp->local_rtcp.fd);
- endp->local_rtcp.fd = -1;
-cleanup1:
- close(endp->local_rtp.fd);
- endp->local_rtp.fd = -1;
-cleanup0:
- return -1;
-}
-
/*
* array of function pointers for handling various
* messages. In the future this might be binary sorted
@@ -575,6 +398,7 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
const char *trans_id;
struct mgcp_endpoint *endp;
int error_code = 500;
+ int port;
found = analyze_header(cfg, msg, data_ptrs, ARRAY_SIZE(data_ptrs), &trans_id, &endp);
if (found != 0)
@@ -618,8 +442,10 @@ static struct msgb *handle_create_con(struct mgcp_config *cfg, struct msgb *msg)
memset(&endp->remote, 0, sizeof(endp->remote));
/* bind to the port now */
- endp->rtp_port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port);
- if (!cfg->early_bind && bind_rtp(endp) != 0)
+ port = rtp_calculate_port(ENDPOINT_NUMBER(endp), cfg->rtp_base_port);
+ if (cfg->early_bind)
+ endp->rtp_port = port;
+ else if (mgcp_bind_rtp_port(endp, port) != 0)
goto error2;
/* assign a local call identifier or fail */
@@ -841,9 +667,3 @@ int mgcp_endpoints_allocate(struct mgcp_config *cfg)
return 0;
}
-
-int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
-{
- endp->rtp_port = rtp_port;
- return bind_rtp(endp);
-}