blob: f7eb8b8353746fe09c7ea1e25f51b5e2e9c3b94a [file] [log] [blame]
Harald Welteead7a7b2009-07-28 00:01:58 +02001/* RTP proxy handling for ip.access nanoBTS */
2
3/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 */
21
22#include <errno.h>
23#include <unistd.h>
24#include <sys/socket.h>
25#include <netinet/in.h>
26
27#include <openbsc/talloc.h>
28#include <openbsc/gsm_data.h>
29#include <openbsc/msgb.h>
30#include <openbsc/select.h>
31#include <openbsc/rtp_proxy.h>
32
33static LLIST_HEAD(rtp_sockets);
34
35enum rtp_bfd_priv {
36 RTP_PRIV_NONE,
37 RTP_PRIV_RTP,
38 RTP_PRIV_RTCP
39};
40
41#define RTP_ALLOC_SIZE 1500
42
43/* read from incoming RTP/RTCP socket */
44static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
45{
46 int rc;
47 struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP");
48 struct rtp_sub_socket *other_rss;
49
50 if (!msg)
51 return -ENOMEM;
52
53 rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE);
54 if (rc <= 0) {
55 rss->bfd.when &= ~BSC_FD_READ;
56 return rc;
57 }
58
59 msgb_put(msg, rc);
60
61 switch (rs->rx_action) {
62 case RTP_PROXY:
63 if (rss->bfd.priv_nr == RTP_PRIV_RTP)
64 other_rss = &rs->proxy.other_sock->rtp;
65 else if (rss->bfd.priv_nr == RTP_PRIV_RTCP)
66 other_rss = &rs->proxy.other_sock->rtcp;
67 else {
68 msgb_free(msg);
69 return -EINVAL;
70 }
71 msgb_enqueue(&other_rss->tx_queue, msg);
72 other_rss->bfd.when |= BSC_FD_WRITE;
73 break;
74 /* FIXME: other cases */
75 }
76
77 return rc;
78}
79
80/* write from tx_queue to RTP/RTCP socket */
81static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss)
82{
83 struct msgb *msg;
84 int written;
85
86 msg = msgb_dequeue(&rss->tx_queue);
87 if (!msg) {
88 rss->bfd.when &= ~BSC_FD_WRITE;
89 return 0;
90 }
91
92 written = write(rss->bfd.fd, msg->data, msg->len);
93 if (written < msg->len) {
94 perror("short write");
95 msgb_free(msg);
96 return -EIO;
97 }
98
99 msgb_free(msg);
100
101 return 0;
102}
103
104
105/* callback for the select.c:bfd_* layer */
106static int rtp_bfd_cb(struct bsc_fd *bfd, unsigned int flags)
107{
108 struct rtp_socket *rs = bfd->data;
109 struct rtp_sub_socket *rss;
110
111 switch (bfd->priv_nr) {
112 case RTP_PRIV_RTP:
113 rss = &rs->rtp;
114 break;
115 case RTP_PRIV_RTCP:
116 rss = &rs->rtcp;
117 break;
118 default:
119 return -EINVAL;
120 }
121
122 if (flags & BSC_FD_READ)
123 rtp_socket_read(rs, rss);
124
125 if (flags & BSC_FD_WRITE)
126 rtp_socket_write(rs, rss);
127
128 return 0;
129}
130
131static void init_rss(struct rtp_sub_socket *rss,
132 struct rtp_socket *rs, int fd, int priv_nr)
133{
134 /* initialize bfd */
135 rss->bfd.fd = fd;
136 rss->bfd.data = rs;
137 rss->bfd.priv_nr = priv_nr;
138 rss->bfd.cb = rtp_bfd_cb;
139}
140
141struct rtp_socket *rtp_socket_create(void)
142{
143 int rc;
144 struct rtp_socket *rs;
145
146 rs = talloc_zero(tall_bsc_ctx, struct rtp_socket);
147 if (!rs)
148 return NULL;
149
150 INIT_LLIST_HEAD(&rs->rtp.tx_queue);
151 INIT_LLIST_HEAD(&rs->rtcp.tx_queue);
152
153 rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
154 if (rc < 0)
155 goto out_free;
156
157 init_rss(&rs->rtp, rs, rc, RTP_PRIV_RTP);
158 rc = bsc_register_fd(&rs->rtp.bfd);
159 if (rc < 0)
160 goto out_rtp_socket;
161
162 rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
163 if (rc < 0)
164 goto out_rtp_bfd;
165
166 init_rss(&rs->rtcp, rs, rc, RTP_PRIV_RTCP);
167 rc = bsc_register_fd(&rs->rtcp.bfd);
168 if (rc < 0)
169 goto out_rtcp_socket;
170
171 return rs;
172
173out_rtcp_socket:
174 close(rs->rtcp.bfd.fd);
175out_rtp_bfd:
176 bsc_unregister_fd(&rs->rtp.bfd);
177out_rtp_socket:
178 close(rs->rtp.bfd.fd);
179out_free:
180 talloc_free(rs);
181 return NULL;
182}
183
184static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, u_int32_t ip,
185 u_int16_t port)
186{
187 rss->sin_local.sin_family = AF_INET;
188 rss->sin_local.sin_addr.s_addr = htonl(ip);
189 rss->sin_local.sin_port = htons(port);
190 rss->bfd.when |= BSC_FD_READ;
191
192 return bind(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
193 sizeof(rss->sin_local));
194}
195
196#define RTP_PORT_BASE 30000
197static u_int16_t next_udp_port = RTP_PORT_BASE;
198
199/* bind a RTP socket to a local address */
200int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip)
201{
202 int rc;
203
204 /* try to bind to a consecutive pair of ports */
205 for (next_udp_port; next_udp_port < 0xffff; next_udp_port += 2) {
206 rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port);
207 if (rc != 0)
208 continue;
209
210 rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1);
211 if (rc == 0)
212 break;
213 }
214 if (rc < 0)
215 return rc;
216
217 return ntohs(rs->rtp.sin_local.sin_port);
218}
219
220static int rtp_sub_socket_connect(struct rtp_sub_socket *rss,
221 u_int32_t ip, u_int16_t port)
222{
223 rss->sin_remote.sin_family = AF_INET;
224 rss->sin_remote.sin_addr.s_addr = htonl(ip);
225 rss->sin_remote.sin_port = htons(port);
226
227 return connect(rss->bfd.fd, (struct sockaddr *) &rss->sin_remote,
228 sizeof(rss->sin_remote));
229}
230
231/* 'connect' a RTP socket to a remote peer */
232int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port)
233{
234 int rc;
235
236 rc = rtp_sub_socket_connect(&rs->rtp, ip, port);
237 if (rc < 0)
238 return rc;
239
240 return rtp_sub_socket_connect(&rs->rtcp, ip, port+1);
241}
242
243/* bind two RTP/RTCP sockets together */
244int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other)
245{
246 this->rx_action = RTP_PROXY;
247 this->proxy.other_sock = other;
248
249 other->rx_action = RTP_PROXY;
250 other->proxy.other_sock = this;
251
252 return 0;
253}
254
255static void free_tx_queue(struct rtp_sub_socket *rss)
256{
257 struct msgb *msg;
258
259 while ((msg = msgb_dequeue(&rss->tx_queue)))
260 msgb_free(msg);
261}
262
263int rtp_socket_free(struct rtp_socket *rs)
264{
265
266 /* make sure we don't leave references dangling to us */
267 if (rs->rx_action == RTP_PROXY &&
268 rs->proxy.other_sock)
269 rs->proxy.other_sock->proxy.other_sock = NULL;
270
271 bsc_unregister_fd(&rs->rtp.bfd);
272 close(rs->rtp.bfd.fd);
273 free_tx_queue(&rs->rtp);
274
275 bsc_unregister_fd(&rs->rtcp.bfd);
276 close(rs->rtcp.bfd.fd);
277 free_tx_queue(&rs->rtcp);
278
279 talloc_free(rs);
280
281 return 0;
282}