blob: f9207d661685df5e71440145729f6404e1b1d1a9 [file] [log] [blame]
Harald Welte0b0bbce2009-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>
Harald Welte3c062072009-07-28 18:25:29 +020026#include <arpa/inet.h>
Harald Welte3971ad52009-12-19 22:23:05 +010027#include <sys/time.h> /* gettimeofday() */
28#include <unistd.h> /* get..() */
29#include <time.h> /* clock() */
30#include <sys/utsname.h> /* uname() */
Harald Welte0b0bbce2009-07-28 00:01:58 +020031
32#include <openbsc/talloc.h>
33#include <openbsc/gsm_data.h>
34#include <openbsc/msgb.h>
35#include <openbsc/select.h>
Harald Welte3c062072009-07-28 18:25:29 +020036#include <openbsc/debug.h>
Harald Welte0b0bbce2009-07-28 00:01:58 +020037#include <openbsc/rtp_proxy.h>
38
39static LLIST_HEAD(rtp_sockets);
40
Harald Welte3c062072009-07-28 18:25:29 +020041/* should we mangle the CNAME inside SDES of RTCP packets? We disable
42 * this by default, as it seems to be not needed */
43static int mangle_rtcp_cname = 0;
44
Harald Welte0b0bbce2009-07-28 00:01:58 +020045enum rtp_bfd_priv {
46 RTP_PRIV_NONE,
47 RTP_PRIV_RTP,
48 RTP_PRIV_RTCP
49};
50
51#define RTP_ALLOC_SIZE 1500
52
Harald Welte3c062072009-07-28 18:25:29 +020053/* according to RFC 1889 */
54struct rtcp_hdr {
55 u_int8_t byte0;
56 u_int8_t type;
57 u_int16_t length;
58} __attribute__((packed));
59
60#define RTCP_TYPE_SDES 202
61
62#define RTCP_IE_CNAME 1
63
Harald Welte3971ad52009-12-19 22:23:05 +010064/* according to RFC 3550 */
65struct rtp_hdr {
66 u_int8_t csrc_count:4,
67 extension:1,
68 padding:1,
69 version:2;
70 u_int8_t payload_type:7,
71 marker:1;
72 u_int16_t sequence;
73 u_int32_t timestamp;
74 u_int32_t ssrc;
75} __attribute__((packed));
76
77struct rtp_x_hdr {
78 u_int16_t by_profile;
79 u_int16_t length;
80} __attribute__((packed));
81
82#define RTP_VERSION 2
83
84#define RTP_PT_GSM_FULL 3
85
86/* decode an rtp frame and create a new buffer with payload */
87static int rtp_decode(struct msgb *msg, u_int32_t callref, struct msgb **data)
88{
89 struct msgb *new_msg;
90 struct gsm_data_frame *frame;
91 struct rtp_hdr *rtph = (struct rtp_hdr *)msg->data;
92 struct rtp_x_hdr *rtpxh;
93 u_int8_t *payload;
94 int payload_len;
95 int msg_type;
96 int x_len;
97
98 if (msg->len < 12) {
99 DEBUGPC(DMUX, "received RTP frame too short (len = %d)\n",
100 msg->len);
101 return -EINVAL;
102 }
103 if (rtph->version != RTP_VERSION) {
104 DEBUGPC(DMUX, "received RTP version %d not supported.\n",
105 rtph->version);
106 return -EINVAL;
107 }
108 payload = msg->data + sizeof(struct rtp_hdr) + (rtph->csrc_count << 2);
109 payload_len = msg->len - sizeof(struct rtp_hdr) - (rtph->csrc_count << 2);
110 if (payload_len < 0) {
111 DEBUGPC(DMUX, "received RTP frame too short (len = %d, "
112 "csrc count = %d)\n", msg->len, rtph->csrc_count);
113 return -EINVAL;
114 }
115 if (rtph->extension) {
116 if (payload_len < sizeof(struct rtp_x_hdr)) {
117 DEBUGPC(DMUX, "received RTP frame too short for "
118 "extension header\n");
119 return -EINVAL;
120 }
121 rtpxh = (struct rtp_x_hdr *)payload;
122 x_len = ntohs(rtpxh->length) * 4 + sizeof(struct rtp_x_hdr);
123 payload += x_len;
124 payload_len -= x_len;
125 if (payload_len < 0) {
126 DEBUGPC(DMUX, "received RTP frame too short, "
127 "extension header exceeds frame length\n");
128 return -EINVAL;
129 }
130 }
131 if (rtph->padding) {
132 if (payload_len < 0) {
133 DEBUGPC(DMUX, "received RTP frame too short for "
134 "padding length\n");
135 return -EINVAL;
136 }
137 payload_len -= payload[payload_len - 1];
138 if (payload_len < 0) {
139 DEBUGPC(DMUX, "received RTP frame with padding "
140 "greater than payload\n");
141 return -EINVAL;
142 }
143 }
144
145 switch (rtph->payload_type) {
146 case RTP_PT_GSM_FULL:
147 msg_type = GSM_TCHF_FRAME;
148 if (payload_len != 33) {
149 DEBUGPC(DMUX, "received RTP full rate frame with "
150 "payload length != 32 (len = %d)\n",
151 payload_len);
152 return -EINVAL;
153 }
154 break;
155 default:
156 DEBUGPC(DMUX, "received RTP frame with unknown payload "
157 "type %d\n", rtph->payload_type);
158 return -EINVAL;
159 }
160
161 new_msg = msgb_alloc(sizeof(struct gsm_data_frame) + payload_len,
162 "GSM-DATA");
163 if (!new_msg)
164 return -ENOMEM;
165 frame = (struct gsm_data_frame *)(new_msg->data);
166 frame->msg_type = msg_type;
167 frame->callref = callref;
168 memcpy(frame->data, payload, payload_len);
169 msgb_put(new_msg, sizeof(struct gsm_data_frame) + payload_len);
170
171 *data = new_msg;
172 return 0;
173}
174
175/* encode and send a rtp frame */
176int rtp_send_frame(struct rtp_socket *rs, struct gsm_data_frame *frame)
177{
178 struct rtp_sub_socket *rss = &rs->rtp;
179 struct msgb *msg;
180 struct rtp_hdr *rtph;
181 int payload_type;
182 int payload_len;
183 int duration; /* in samples */
184
185 if (rs->tx_action != RTP_SEND_DOWNSTREAM) {
186 /* initialize sequences */
187 rs->tx_action = RTP_SEND_DOWNSTREAM;
188 rs->transmit.ssrc = rand();
189 rs->transmit.sequence = random();
190 rs->transmit.timestamp = random();
191 }
192
193 switch (frame->msg_type) {
194 case GSM_TCHF_FRAME:
195 payload_type = RTP_PT_GSM_FULL;
196 payload_len = 33;
197 duration = 160;
198 break;
199 default:
200 DEBUGPC(DMUX, "unsupported message type %d\n",
201 frame->msg_type);
202 return -EINVAL;
203 }
204
205 msg = msgb_alloc(sizeof(struct rtp_hdr) + payload_len, "RTP-GSM-FULL");
206 if (!msg)
207 return -ENOMEM;
208 rtph = (struct rtp_hdr *)msg->data;
209 rtph->version = RTP_VERSION;
210 rtph->padding = 0;
211 rtph->extension = 0;
212 rtph->csrc_count = 0;
213 rtph->marker = 0;
214 rtph->payload_type = payload_type;
215 rtph->sequence = htons(rs->transmit.sequence++);
216 rtph->timestamp = htonl(rs->transmit.timestamp);
217 rs->transmit.timestamp += duration;
218 rtph->ssrc = htonl(rs->transmit.ssrc);
219 memcpy(msg->data + sizeof(struct rtp_hdr), frame->data, payload_len);
220 msgb_put(msg, sizeof(struct rtp_hdr) + payload_len);
221 msgb_enqueue(&rss->tx_queue, msg);
222 rss->bfd.when |= BSC_FD_WRITE;
223
224 return 0;
225}
226
Holger Hans Peter Freyther0168dc12009-07-29 06:46:26 +0200227/* iterate over all chunks in one RTCP message, look for CNAME IEs and
Harald Welte3c062072009-07-28 18:25:29 +0200228 * replace all of those with 'new_cname' */
229static int rtcp_sdes_cname_mangle(struct msgb *msg, struct rtcp_hdr *rh,
230 u_int16_t *rtcp_len, const char *new_cname)
231{
232 u_int8_t *rtcp_end;
233 u_int8_t *cur = (u_int8_t *) rh;
234 u_int8_t tag, len = 0;
235
236 rtcp_end = cur + *rtcp_len;
237 /* move cur to end of RTP header */
Harald Welte6977a292009-07-29 10:46:41 +0200238 cur += sizeof(*rh);
Harald Welte3c062072009-07-28 18:25:29 +0200239
240 /* iterate over Chunks */
241 while (cur+4 < rtcp_end) {
242 /* skip four bytes SSRC/CSRC */
243 cur += 4;
244
245 /* iterate over IE's inside the chunk */
246 while (cur+1 < rtcp_end) {
247 tag = *cur++;
248 if (tag == 0) {
249 /* end of chunk, skip additional zero */
250 while (*cur++ == 0) { }
251 break;
252 }
253 len = *cur++;
254
255 if (tag == RTCP_IE_CNAME) {
256 /* we've found the CNAME, lets mangle it */
257 if (len < strlen(new_cname)) {
258 /* we need to make more space */
259 int increase = strlen(new_cname) - len;
260
261 msgb_push(msg, increase);
262 memmove(cur+len+increase, cur+len,
263 rtcp_end - (cur+len));
264 /* FIXME: we have to respect RTCP
265 * padding/alignment rules! */
266 len += increase;
267 *(cur-1) += increase;
268 rtcp_end += increase;
269 *rtcp_len += increase;
270 }
271 /* copy new CNAME into message */
272 memcpy(cur, new_cname, strlen(new_cname));
273 /* FIXME: zero the padding in case new CNAME
274 * is smaller than old one !!! */
275 }
276 cur += len;
277 }
278 }
279
280 return 0;
281}
282
283static int rtcp_mangle(struct msgb *msg, struct rtp_socket *rs)
284{
285 struct rtp_sub_socket *rss = &rs->rtcp;
286 struct rtcp_hdr *rtph;
287 u_int16_t old_len;
288 int rc;
289
290 if (!mangle_rtcp_cname)
291 return 0;
292
Harald Welte3971ad52009-12-19 22:23:05 +0100293 printf("RTCP\n");
Harald Welte3c062072009-07-28 18:25:29 +0200294 /* iterate over list of RTCP messages */
295 rtph = (struct rtcp_hdr *)msg->data;
Harald Welte3971ad52009-12-19 22:23:05 +0100296 while ((void *)rtph + sizeof(*rtph) <= (void *)msg->data + msg->len) {
Harald Welte3c062072009-07-28 18:25:29 +0200297 old_len = (ntohs(rtph->length) + 1) * 4;
Harald Welte3971ad52009-12-19 22:23:05 +0100298 if ((void *)rtph + old_len > (void *)msg->data + msg->len) {
299 DEBUGPC(DMUX, "received RTCP packet too short for "
300 "length element\n");
301 return -EINVAL;
302 }
Harald Welte3c062072009-07-28 18:25:29 +0200303 if (rtph->type == RTCP_TYPE_SDES) {
304 char new_cname[255];
305 strncpy(new_cname, inet_ntoa(rss->sin_local.sin_addr),
306 sizeof(new_cname));
307 new_cname[sizeof(new_cname)-1] = '\0';
308 rc = rtcp_sdes_cname_mangle(msg, rtph, &old_len,
309 new_cname);
310 if (rc < 0)
311 return rc;
312 }
313 rtph = (void *)rtph + old_len;
314 }
315
316 return 0;
317}
318
Harald Welte0b0bbce2009-07-28 00:01:58 +0200319/* read from incoming RTP/RTCP socket */
320static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss)
321{
322 int rc;
323 struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP");
Harald Welte3971ad52009-12-19 22:23:05 +0100324 struct msgb *new_msg;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200325 struct rtp_sub_socket *other_rss;
326
327 if (!msg)
328 return -ENOMEM;
329
330 rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE);
331 if (rc <= 0) {
332 rss->bfd.when &= ~BSC_FD_READ;
333 return rc;
334 }
335
336 msgb_put(msg, rc);
337
338 switch (rs->rx_action) {
339 case RTP_PROXY:
Harald Welte3c062072009-07-28 18:25:29 +0200340 if (!rs->proxy.other_sock) {
341 rc = -EIO;
342 goto out_free;
343 }
Harald Welte0b0bbce2009-07-28 00:01:58 +0200344 if (rss->bfd.priv_nr == RTP_PRIV_RTP)
345 other_rss = &rs->proxy.other_sock->rtp;
Harald Welte3c062072009-07-28 18:25:29 +0200346 else if (rss->bfd.priv_nr == RTP_PRIV_RTCP) {
Harald Welte0b0bbce2009-07-28 00:01:58 +0200347 other_rss = &rs->proxy.other_sock->rtcp;
Harald Welte3c062072009-07-28 18:25:29 +0200348 /* modify RTCP SDES CNAME */
349 rc = rtcp_mangle(msg, rs);
350 if (rc < 0)
351 goto out_free;
352 } else {
353 rc = -EINVAL;
354 goto out_free;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200355 }
356 msgb_enqueue(&other_rss->tx_queue, msg);
357 other_rss->bfd.when |= BSC_FD_WRITE;
358 break;
Holger Hans Peter Freyther911b2012009-08-10 07:57:13 +0200359
360 case RTP_RECV_UPSTREAM:
Harald Welte3971ad52009-12-19 22:23:05 +0100361 if (!rs->receive.callref || !rs->receive.net) {
362 rc = -EIO;
363 goto out_free;
364 }
365 if (rss->bfd.priv_nr == RTP_PRIV_RTCP) {
366 if (!mangle_rtcp_cname) {
367 msgb_free(msg);
368 break;
369 }
370 /* modify RTCP SDES CNAME */
371 rc = rtcp_mangle(msg, rs);
372 if (rc < 0)
373 goto out_free;
374 msgb_enqueue(&rss->tx_queue, msg);
375 rss->bfd.when |= BSC_FD_WRITE;
376 break;
377 }
378 if (rss->bfd.priv_nr != RTP_PRIV_RTP) {
379 rc = -EINVAL;
380 goto out_free;
381 }
382 rc = rtp_decode(msg, rs->receive.callref, &new_msg);
383 if (rc < 0)
384 goto out_free;
385 msgb_free(msg);
386 msgb_enqueue(&rs->receive.net->upqueue, new_msg);
387 break;
388
389 case RTP_NONE: /* if socket exists, but disabled by app */
390 msgb_free(msg);
Holger Hans Peter Freyther911b2012009-08-10 07:57:13 +0200391 break;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200392 }
393
Harald Welte3971ad52009-12-19 22:23:05 +0100394 return 0;
Harald Welte3c062072009-07-28 18:25:29 +0200395
396out_free:
397 msgb_free(msg);
398 return rc;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200399}
400
401/* write from tx_queue to RTP/RTCP socket */
402static int rtp_socket_write(struct rtp_socket *rs, struct rtp_sub_socket *rss)
403{
404 struct msgb *msg;
405 int written;
406
407 msg = msgb_dequeue(&rss->tx_queue);
408 if (!msg) {
409 rss->bfd.when &= ~BSC_FD_WRITE;
410 return 0;
411 }
412
413 written = write(rss->bfd.fd, msg->data, msg->len);
414 if (written < msg->len) {
Harald Weltecf2ec4a2009-12-17 23:10:46 +0100415 LOGP(DMIB, LOGL_ERROR, "short write");
Harald Welte0b0bbce2009-07-28 00:01:58 +0200416 msgb_free(msg);
417 return -EIO;
418 }
419
420 msgb_free(msg);
421
422 return 0;
423}
424
425
426/* callback for the select.c:bfd_* layer */
427static int rtp_bfd_cb(struct bsc_fd *bfd, unsigned int flags)
428{
429 struct rtp_socket *rs = bfd->data;
430 struct rtp_sub_socket *rss;
431
432 switch (bfd->priv_nr) {
433 case RTP_PRIV_RTP:
434 rss = &rs->rtp;
435 break;
436 case RTP_PRIV_RTCP:
437 rss = &rs->rtcp;
438 break;
439 default:
440 return -EINVAL;
441 }
442
443 if (flags & BSC_FD_READ)
444 rtp_socket_read(rs, rss);
445
446 if (flags & BSC_FD_WRITE)
447 rtp_socket_write(rs, rss);
448
449 return 0;
450}
451
452static void init_rss(struct rtp_sub_socket *rss,
453 struct rtp_socket *rs, int fd, int priv_nr)
454{
455 /* initialize bfd */
456 rss->bfd.fd = fd;
457 rss->bfd.data = rs;
458 rss->bfd.priv_nr = priv_nr;
459 rss->bfd.cb = rtp_bfd_cb;
460}
461
462struct rtp_socket *rtp_socket_create(void)
463{
464 int rc;
465 struct rtp_socket *rs;
466
Harald Welte3c062072009-07-28 18:25:29 +0200467 DEBUGP(DMUX, "rtp_socket_create(): ");
468
Harald Welte0b0bbce2009-07-28 00:01:58 +0200469 rs = talloc_zero(tall_bsc_ctx, struct rtp_socket);
470 if (!rs)
471 return NULL;
472
473 INIT_LLIST_HEAD(&rs->rtp.tx_queue);
474 INIT_LLIST_HEAD(&rs->rtcp.tx_queue);
475
476 rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
477 if (rc < 0)
478 goto out_free;
479
480 init_rss(&rs->rtp, rs, rc, RTP_PRIV_RTP);
481 rc = bsc_register_fd(&rs->rtp.bfd);
482 if (rc < 0)
483 goto out_rtp_socket;
484
485 rc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
486 if (rc < 0)
487 goto out_rtp_bfd;
488
489 init_rss(&rs->rtcp, rs, rc, RTP_PRIV_RTCP);
490 rc = bsc_register_fd(&rs->rtcp.bfd);
491 if (rc < 0)
492 goto out_rtcp_socket;
493
Harald Welte3c062072009-07-28 18:25:29 +0200494 DEBUGPC(DMUX, "success\n");
495
496 rc = rtp_socket_bind(rs, INADDR_ANY);
497 if (rc < 0)
498 goto out_rtcp_bfd;
499
Harald Welte0b0bbce2009-07-28 00:01:58 +0200500 return rs;
501
Harald Welte3c062072009-07-28 18:25:29 +0200502out_rtcp_bfd:
503 bsc_unregister_fd(&rs->rtcp.bfd);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200504out_rtcp_socket:
505 close(rs->rtcp.bfd.fd);
506out_rtp_bfd:
507 bsc_unregister_fd(&rs->rtp.bfd);
508out_rtp_socket:
509 close(rs->rtp.bfd.fd);
510out_free:
511 talloc_free(rs);
Harald Welte3c062072009-07-28 18:25:29 +0200512 DEBUGPC(DMUX, "failed\n");
Harald Welte0b0bbce2009-07-28 00:01:58 +0200513 return NULL;
514}
515
516static int rtp_sub_socket_bind(struct rtp_sub_socket *rss, u_int32_t ip,
517 u_int16_t port)
518{
Harald Welte3c062072009-07-28 18:25:29 +0200519 int rc;
520 socklen_t alen = sizeof(rss->sin_local);
521
Harald Welte0b0bbce2009-07-28 00:01:58 +0200522 rss->sin_local.sin_family = AF_INET;
523 rss->sin_local.sin_addr.s_addr = htonl(ip);
524 rss->sin_local.sin_port = htons(port);
525 rss->bfd.when |= BSC_FD_READ;
526
Harald Welte3c062072009-07-28 18:25:29 +0200527 rc = bind(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
528 sizeof(rss->sin_local));
529 if (rc < 0)
530 return rc;
531
532 /* retrieve the address we actually bound to, in case we
533 * passed INADDR_ANY as IP address */
534 return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
535 &alen);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200536}
537
538#define RTP_PORT_BASE 30000
Harald Welte3c062072009-07-28 18:25:29 +0200539static unsigned int next_udp_port = RTP_PORT_BASE;
Harald Welte0b0bbce2009-07-28 00:01:58 +0200540
541/* bind a RTP socket to a local address */
542int rtp_socket_bind(struct rtp_socket *rs, u_int32_t ip)
543{
Harald Welte3c062072009-07-28 18:25:29 +0200544 int rc = -EIO;
545 struct in_addr ia;
546
547 ia.s_addr = htonl(ip);
548 DEBUGP(DMUX, "rtp_socket_bind(rs=%p, IP=%s): ", rs,
549 inet_ntoa(ia));
Harald Welte0b0bbce2009-07-28 00:01:58 +0200550
551 /* try to bind to a consecutive pair of ports */
Harald Welte3c062072009-07-28 18:25:29 +0200552 for (next_udp_port = next_udp_port % 0xffff;
553 next_udp_port < 0xffff; next_udp_port += 2) {
Harald Welte0b0bbce2009-07-28 00:01:58 +0200554 rc = rtp_sub_socket_bind(&rs->rtp, ip, next_udp_port);
555 if (rc != 0)
556 continue;
557
558 rc = rtp_sub_socket_bind(&rs->rtcp, ip, next_udp_port+1);
559 if (rc == 0)
560 break;
561 }
Harald Welte3c062072009-07-28 18:25:29 +0200562 if (rc < 0) {
563 DEBUGPC(DMUX, "failed\n");
Harald Welte0b0bbce2009-07-28 00:01:58 +0200564 return rc;
Harald Welte3c062072009-07-28 18:25:29 +0200565 }
Harald Welte0b0bbce2009-07-28 00:01:58 +0200566
Harald Welte3c062072009-07-28 18:25:29 +0200567 ia.s_addr = rs->rtp.sin_local.sin_addr.s_addr;
568 DEBUGPC(DMUX, "BOUND_IP=%s, BOUND_PORT=%u\n",
569 inet_ntoa(ia), ntohs(rs->rtp.sin_local.sin_port));
Harald Welte0b0bbce2009-07-28 00:01:58 +0200570 return ntohs(rs->rtp.sin_local.sin_port);
571}
572
573static int rtp_sub_socket_connect(struct rtp_sub_socket *rss,
574 u_int32_t ip, u_int16_t port)
575{
Harald Welte3c062072009-07-28 18:25:29 +0200576 int rc;
577 socklen_t alen = sizeof(rss->sin_local);
578
Harald Welte0b0bbce2009-07-28 00:01:58 +0200579 rss->sin_remote.sin_family = AF_INET;
580 rss->sin_remote.sin_addr.s_addr = htonl(ip);
581 rss->sin_remote.sin_port = htons(port);
582
Harald Welte3c062072009-07-28 18:25:29 +0200583 rc = connect(rss->bfd.fd, (struct sockaddr *) &rss->sin_remote,
584 sizeof(rss->sin_remote));
585 if (rc < 0)
586 return rc;
587
588 return getsockname(rss->bfd.fd, (struct sockaddr *)&rss->sin_local,
589 &alen);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200590}
591
592/* 'connect' a RTP socket to a remote peer */
593int rtp_socket_connect(struct rtp_socket *rs, u_int32_t ip, u_int16_t port)
594{
595 int rc;
Harald Welte3c062072009-07-28 18:25:29 +0200596 struct in_addr ia;
597
598 ia.s_addr = htonl(ip);
599 DEBUGP(DMUX, "rtp_socket_connect(rs=%p, ip=%s, port=%u)\n",
600 rs, inet_ntoa(ia), port);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200601
602 rc = rtp_sub_socket_connect(&rs->rtp, ip, port);
603 if (rc < 0)
604 return rc;
605
606 return rtp_sub_socket_connect(&rs->rtcp, ip, port+1);
607}
608
609/* bind two RTP/RTCP sockets together */
610int rtp_socket_proxy(struct rtp_socket *this, struct rtp_socket *other)
611{
Harald Welte3c062072009-07-28 18:25:29 +0200612 DEBUGP(DMUX, "rtp_socket_proxy(this=%p, other=%p)\n",
613 this, other);
614
Harald Welte0b0bbce2009-07-28 00:01:58 +0200615 this->rx_action = RTP_PROXY;
616 this->proxy.other_sock = other;
617
618 other->rx_action = RTP_PROXY;
619 other->proxy.other_sock = this;
620
621 return 0;
622}
623
Harald Welte3971ad52009-12-19 22:23:05 +0100624/* bind RTP/RTCP socket to application */
625int rtp_socket_upstream(struct rtp_socket *this, struct gsm_network *net, u_int32_t callref)
626{
627 DEBUGP(DMUX, "rtp_socket_proxy(this=%p, callref=%lu)\n",
628 this, callref);
629
630 if (callref) {
631 this->rx_action = RTP_RECV_UPSTREAM;
632 this->receive.net = net;
633 this->receive.callref = callref;
634 } else
635 this->rx_action = RTP_NONE;
636
637 return 0;
638}
639
Harald Welte0b0bbce2009-07-28 00:01:58 +0200640static void free_tx_queue(struct rtp_sub_socket *rss)
641{
642 struct msgb *msg;
643
644 while ((msg = msgb_dequeue(&rss->tx_queue)))
645 msgb_free(msg);
646}
647
648int rtp_socket_free(struct rtp_socket *rs)
649{
Harald Welte3c062072009-07-28 18:25:29 +0200650 DEBUGP(DMUX, "rtp_socket_free(rs=%p)\n", rs);
Harald Welte0b0bbce2009-07-28 00:01:58 +0200651
652 /* make sure we don't leave references dangling to us */
653 if (rs->rx_action == RTP_PROXY &&
654 rs->proxy.other_sock)
655 rs->proxy.other_sock->proxy.other_sock = NULL;
656
657 bsc_unregister_fd(&rs->rtp.bfd);
658 close(rs->rtp.bfd.fd);
659 free_tx_queue(&rs->rtp);
660
661 bsc_unregister_fd(&rs->rtcp.bfd);
662 close(rs->rtcp.bfd.fd);
663 free_tx_queue(&rs->rtcp);
664
665 talloc_free(rs);
666
667 return 0;
668}