blob: e92b0742ee3e89cf125a8cc0308c5602f439764b [file] [log] [blame]
Holger Hans Peter Freyther1b0ea972010-02-21 11:11:04 +01001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
5 * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2010 by On-Waves
7 * All Rights Reserved
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 *
23 */
24
25#include <string.h>
26#include <unistd.h>
27
28#include <sys/socket.h>
29#include <arpa/inet.h>
30
31#include <openbsc/debug.h>
32#include <openbsc/mgcp.h>
33#include <openbsc/mgcp_internal.h>
34#include <openbsc/msgb.h>
35#include <openbsc/talloc.h>
36#include <openbsc/select.h>
37
38#warning "Make use of the rtp proxy code"
39
40
41enum {
42 DEST_NETWORK = 0,
43 DEST_BTS = 1,
44};
45
46enum {
47 PROTO_RTP,
48 PROTO_RTCP,
49};
50
51
52static int udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
53{
54 struct sockaddr_in out;
55 out.sin_family = AF_INET;
56 out.sin_port = port;
57 memcpy(&out.sin_addr, addr, sizeof(*addr));
58
59 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
60}
61
62/*
63 * There is data coming. We will have to figure out if it
64 * came from the BTS or the MediaGateway of the MSC. On top
65 * of that we need to figure out if it was RTP or RTCP.
66 *
67 * Currently we do not communicate with the BSC so we have
68 * no idea where the BTS is listening for RTP and need to
69 * do the classic routing trick. Wait for the first packet
70 * from the BTS and then go ahead.
71 */
72static int rtp_data_cb(struct bsc_fd *fd, unsigned int what)
73{
74 char buf[4096];
75 struct sockaddr_in addr;
76 socklen_t slen = sizeof(addr);
77 struct mgcp_endpoint *endp;
78 struct mgcp_config *cfg;
79 int rc, dest, proto;
80
81 endp = (struct mgcp_endpoint *) fd->data;
82 cfg = endp->cfg;
83
84 rc = recvfrom(fd->fd, &buf, sizeof(buf), 0,
85 (struct sockaddr *) &addr, &slen);
86 if (rc < 0) {
87 LOGP(DMGCP, LOGL_ERROR, "Failed to receive message on: 0x%x\n",
88 ENDPOINT_NUMBER(endp));
89 return -1;
90 }
91
92 /* do not forward aynthing... maybe there is a packet from the bts */
93 if (endp->ci == CI_UNUSED) {
94 LOGP(DMGCP, LOGL_ERROR, "Unknown message on endpoint: 0x%x\n", ENDPOINT_NUMBER(endp));
95 return -1;
96 }
97
98 /*
99 * Figure out where to forward it to. This code assumes that we
100 * have received the Connection Modify and know who is a legitimate
101 * partner. According to the spec we could attempt to forward even
102 * after the Create Connection but we will not as we are not really
103 * able to tell if this is legitimate.
104 */
105 #warning "Slight spec violation. With connection mode recvonly we should attempt to forward."
106 dest = memcmp(&addr.sin_addr, &endp->remote, sizeof(addr.sin_addr)) == 0 &&
107 (endp->net_rtp == addr.sin_port || endp->net_rtcp == addr.sin_port)
108 ? DEST_BTS : DEST_NETWORK;
109 proto = fd == &endp->local_rtp ? PROTO_RTP : PROTO_RTCP;
110
111 /* We have no idea who called us, maybe it is the BTS. */
112 if (dest == DEST_NETWORK && (endp->bts_rtp == 0 || cfg->forward_ip)) {
113 /* it was the BTS... */
114 if (!cfg->bts_ip || memcmp(&addr.sin_addr, &cfg->bts_in, sizeof(cfg->bts_in)) == 0) {
115 if (fd == &endp->local_rtp) {
116 endp->bts_rtp = addr.sin_port;
117 } else {
118 endp->bts_rtcp = addr.sin_port;
119 }
120
121 endp->bts = addr.sin_addr;
122 LOGP(DMGCP, LOGL_NOTICE, "Found BTS for endpoint: 0x%x on port: %d/%d\n",
123 ENDPOINT_NUMBER(endp), ntohs(endp->bts_rtp), ntohs(endp->bts_rtcp));
124 }
125 }
126
127 /* dispatch */
128 if (cfg->audio_loop)
129 dest = !dest;
130
131 if (dest == DEST_NETWORK) {
132 return udp_send(fd->fd, &endp->remote,
133 proto == PROTO_RTP ? endp->net_rtp : endp->net_rtcp,
134 buf, rc);
135 } else {
136 return udp_send(fd->fd, &endp->bts,
137 proto == PROTO_RTP ? endp->bts_rtp : endp->bts_rtcp,
138 buf, rc);
139 }
140}
141
142static int create_bind(const char *source_addr, struct bsc_fd *fd, int port)
143{
144 struct sockaddr_in addr;
145 int on = 1;
146
147 fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
148 if (fd->fd < 0) {
149 LOGP(DMGCP, LOGL_ERROR, "Failed to create UDP port.\n");
150 return -1;
151 }
152
153 setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
154 memset(&addr, 0, sizeof(addr));
155 addr.sin_family = AF_INET;
156 addr.sin_port = htons(port);
157 inet_aton(source_addr, &addr.sin_addr);
158
159 if (bind(fd->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
160 return -1;
161 }
162
163 return 0;
164}
165
166static int bind_rtp(struct mgcp_endpoint *endp)
167{
168 struct mgcp_config *cfg = endp->cfg;
169
170 if (create_bind(cfg->source_addr, &endp->local_rtp, endp->rtp_port) != 0) {
171 LOGP(DMGCP, LOGL_ERROR, "Failed to create RTP port: %s:%d on 0x%x\n",
172 cfg->source_addr, endp->rtp_port, ENDPOINT_NUMBER(endp));
173 goto cleanup0;
174 }
175
176 if (create_bind(cfg->source_addr, &endp->local_rtcp, endp->rtp_port + 1) != 0) {
177 LOGP(DMGCP, LOGL_ERROR, "Failed to create RTCP port: %s:%d on 0x%x\n",
178 cfg->source_addr, endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
179 goto cleanup1;
180 }
181
182 endp->local_rtp.cb = rtp_data_cb;
183 endp->local_rtp.data = endp;
184 endp->local_rtp.when = BSC_FD_READ;
185 if (bsc_register_fd(&endp->local_rtp) != 0) {
186 LOGP(DMGCP, LOGL_ERROR, "Failed to register RTP port %d on 0x%x\n",
187 endp->rtp_port, ENDPOINT_NUMBER(endp));
188 goto cleanup2;
189 }
190
191 endp->local_rtcp.cb = rtp_data_cb;
192 endp->local_rtcp.data = endp;
193 endp->local_rtcp.when = BSC_FD_READ;
194 if (bsc_register_fd(&endp->local_rtcp) != 0) {
195 LOGP(DMGCP, LOGL_ERROR, "Failed to register RTCP port %d on 0x%x\n",
196 endp->rtp_port + 1, ENDPOINT_NUMBER(endp));
197 goto cleanup3;
198 }
199
200 return 0;
201
202cleanup3:
203 bsc_unregister_fd(&endp->local_rtp);
204cleanup2:
205 close(endp->local_rtcp.fd);
206 endp->local_rtcp.fd = -1;
207cleanup1:
208 close(endp->local_rtp.fd);
209 endp->local_rtp.fd = -1;
210cleanup0:
211 return -1;
212}
213
214int mgcp_bind_rtp_port(struct mgcp_endpoint *endp, int rtp_port)
215{
216 endp->rtp_port = rtp_port;
217 return bind_rtp(endp);
218}