blob: dac16988e2fdd5abe39efaacdd2e9c5c719c1375 [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001/* A Media Gateway Control Protocol Media Gateway: RFC 3435 */
2/* The protocol implementation */
3
4/*
5 * (C) 2009-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
6 * (C) 2009-2012 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 Affero General Public License as published by
11 * the Free Software Foundation; either version 3 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 Affero General Public License for more details.
18 *
19 * You should have received a copy of the GNU Affero General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 *
22 */
23
24#include <string.h>
25#include <stdlib.h>
26#include <unistd.h>
27#include <errno.h>
28#include <time.h>
29#include <limits.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020030#include <sys/socket.h>
31#include <arpa/inet.h>
32
33#include <osmocom/core/msgb.h>
34#include <osmocom/core/select.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020035#include <osmocom/netif/rtp.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020036#include <osmocom/mgcp/mgcp.h>
Neels Hofmeyr67793542017-09-08 04:25:16 +020037#include <osmocom/mgcp/mgcp_common.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020038#include <osmocom/mgcp/mgcp_internal.h>
39#include <osmocom/mgcp/mgcp_stat.h>
40#include <osmocom/mgcp/osmux.h>
41#include <osmocom/mgcp/mgcp_conn.h>
42#include <osmocom/mgcp/mgcp_ep.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020043
44#define RTP_SEQ_MOD (1 << 16)
45#define RTP_MAX_DROPOUT 3000
46#define RTP_MAX_MISORDER 100
47#define RTP_BUF_SIZE 4096
48
49enum {
50 MGCP_PROTO_RTP,
51 MGCP_PROTO_RTCP,
52};
53
Philipp Maier87bd9be2017-08-22 16:35:41 +020054/* This does not need to be a precision timestamp and
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020055 * is allowed to wrap quite fast. The returned value is
Philipp Maier87bd9be2017-08-22 16:35:41 +020056 * 1/codec_rate seconds. */
57static uint32_t get_current_ts(unsigned codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020058{
59 struct timespec tp;
60 uint64_t ret;
61
Philipp Maier87bd9be2017-08-22 16:35:41 +020062 if (!codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020063 return 0;
64
65 memset(&tp, 0, sizeof(tp));
66 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +020067 LOGP(DLMGCP, LOGL_NOTICE, "Getting the clock failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020068
69 /* convert it to 1/unit seconds */
70 ret = tp.tv_sec;
Philipp Maier87bd9be2017-08-22 16:35:41 +020071 ret *= codec_rate;
72 ret += (int64_t) tp.tv_nsec * codec_rate / 1000 / 1000 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020073
74 return ret;
75}
76
Philipp Maier87bd9be2017-08-22 16:35:41 +020077/*! send udp packet.
78 * \param[in] fd associated file descriptor
79 * \param[in] addr destination ip-address
80 * \param[in] port destination UDP port
81 * \param[in] buf buffer that holds the data to be send
82 * \param[in] len length of the data to be sent
83 * \returns bytes sent, -1 on error */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020084int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
85{
86 struct sockaddr_in out;
Philipp Maier87bd9be2017-08-22 16:35:41 +020087
88 LOGP(DLMGCP, LOGL_DEBUG,
89 "sending %i bytes length packet to %s:%u ...\n",
90 len, inet_ntoa(*addr), ntohs(port));
91
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020092 out.sin_family = AF_INET;
93 out.sin_port = port;
94 memcpy(&out.sin_addr, addr, sizeof(*addr));
95
96 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
97}
98
Philipp Maier87bd9be2017-08-22 16:35:41 +020099/*! send RTP dummy packet (to keep NAT connection open).
100 * \param[in] endp mcgp endpoint that holds the RTP connection
101 * \param[in] conn associated RTP connection
102 * \returns bytes sent, -1 on error */
103int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200104{
105 static char buf[] = { MGCP_DUMMY_LOAD };
106 int rc;
107 int was_rtcp = 0;
108
Philipp Maier87bd9be2017-08-22 16:35:41 +0200109 OSMO_ASSERT(endp);
110 OSMO_ASSERT(conn);
111
112 LOGP(DLMGCP, LOGL_DEBUG,
113 "endpoint:%x sending dummy packet...\n", ENDPOINT_NUMBER(endp));
114 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x conn:%s\n",
115 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
116
117 rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
118 conn->end.rtp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200119
120 if (rc == -1)
121 goto failed;
122
123 if (endp->tcfg->omit_rtcp)
124 return rc;
125
126 was_rtcp = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200127 rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
128 conn->end.rtcp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200129
130 if (rc >= 0)
131 return rc;
132
133failed:
134 LOGP(DLMGCP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200135 "endpoint:%x Failed to send dummy %s packet.\n",
136 ENDPOINT_NUMBER(endp), was_rtcp ? "RTCP" : "RTP");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200137
138 return -1;
139}
140
Philipp Maier87bd9be2017-08-22 16:35:41 +0200141/* Compute timestamp alignment error */
142static int32_t ts_alignment_error(struct mgcp_rtp_stream_state *sstate,
143 int ptime, uint32_t timestamp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200144{
145 int32_t timestamp_delta;
146
147 if (ptime == 0)
148 return 0;
149
150 /* Align according to: T - Tlast = k * Tptime */
151 timestamp_delta = timestamp - sstate->last_timestamp;
152
153 return timestamp_delta % ptime;
154}
155
Philipp Maier87bd9be2017-08-22 16:35:41 +0200156/* Check timestamp and sequence number for plausibility */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200157static int check_rtp_timestamp(struct mgcp_endpoint *endp,
158 struct mgcp_rtp_state *state,
159 struct mgcp_rtp_stream_state *sstate,
160 struct mgcp_rtp_end *rtp_end,
161 struct sockaddr_in *addr,
162 uint16_t seq, uint32_t timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200163 const char *text, int32_t * tsdelta_out)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200164{
165 int32_t tsdelta;
166 int32_t timestamp_error;
167
168 /* Not fully intialized, skip */
169 if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
170 return 0;
171
172 if (seq == sstate->last_seq) {
173 if (timestamp != sstate->last_timestamp) {
174 sstate->err_ts_counter += 1;
175 LOGP(DLMGCP, LOGL_ERROR,
176 "The %s timestamp delta is != 0 but the sequence "
177 "number %d is the same, "
178 "TS offset: %d, SeqNo offset: %d "
179 "on 0x%x SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200180 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200181 text, seq,
182 state->timestamp_offset, state->seq_offset,
183 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200184 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200185 }
186 return 0;
187 }
188
189 tsdelta =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200190 (int32_t)(timestamp - sstate->last_timestamp) /
191 (int16_t)(seq - sstate->last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200192
193 if (tsdelta == 0) {
194 /* Don't update *tsdelta_out */
195 LOGP(DLMGCP, LOGL_NOTICE,
196 "The %s timestamp delta is %d "
197 "on 0x%x SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200198 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200199 text, tsdelta,
200 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200201 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200202
203 return 0;
204 }
205
206 if (sstate->last_tsdelta != tsdelta) {
207 if (sstate->last_tsdelta) {
208 LOGP(DLMGCP, LOGL_INFO,
209 "The %s timestamp delta changes from %d to %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200210 "on 0x%x SSRC: %u timestamp: %u from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200211 text, sstate->last_tsdelta, tsdelta,
212 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200213 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200214 }
215 }
216
217 if (tsdelta_out)
218 *tsdelta_out = tsdelta;
219
220 timestamp_error =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200221 ts_alignment_error(sstate, state->packet_duration, timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200222
223 if (timestamp_error) {
224 sstate->err_ts_counter += 1;
225 LOGP(DLMGCP, LOGL_NOTICE,
226 "The %s timestamp has an alignment error of %d "
227 "on 0x%x SSRC: %u "
228 "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200229 "from %s:%d. ptime: %d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200230 text, timestamp_error,
231 ENDPOINT_NUMBER(endp), sstate->ssrc,
232 (int16_t)(seq - sstate->last_seq),
233 (int32_t)(timestamp - sstate->last_timestamp),
234 tsdelta,
235 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200236 state->packet_duration);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200237 }
238 return 1;
239}
240
241/* Set the timestamp offset according to the packet duration. */
242static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
243 struct mgcp_rtp_state *state,
244 struct mgcp_rtp_end *rtp_end,
245 struct sockaddr_in *addr,
246 int16_t delta_seq, uint32_t in_timestamp)
247{
248 int32_t tsdelta = state->packet_duration;
249 int timestamp_offset;
250 uint32_t out_timestamp;
251
252 if (tsdelta == 0) {
253 tsdelta = state->out_stream.last_tsdelta;
254 if (tsdelta != 0) {
255 LOGP(DLMGCP, LOGL_NOTICE,
256 "A fixed packet duration is not available on 0x%x, "
257 "using last output timestamp delta instead: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200258 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200259 ENDPOINT_NUMBER(endp), tsdelta,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200260 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200261 } else {
262 tsdelta = rtp_end->codec.rate * 20 / 1000;
263 LOGP(DLMGCP, LOGL_NOTICE,
264 "Fixed packet duration and last timestamp delta "
265 "are not available on 0x%x, "
266 "using fixed 20ms instead: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200267 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200268 ENDPOINT_NUMBER(endp), tsdelta,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200269 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200270 }
271 }
272
273 out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
274 timestamp_offset = out_timestamp - in_timestamp;
275
276 if (state->timestamp_offset != timestamp_offset) {
277 state->timestamp_offset = timestamp_offset;
278
279 LOGP(DLMGCP, LOGL_NOTICE,
280 "Timestamp offset change on 0x%x SSRC: %u "
281 "SeqNo delta: %d, TS offset: %d, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200282 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200283 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
284 delta_seq, state->timestamp_offset,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200285 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200286 }
287
288 return timestamp_offset;
289}
290
291/* Set the timestamp offset according to the packet duration. */
292static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
293 struct mgcp_rtp_state *state,
294 struct mgcp_rtp_end *rtp_end,
295 struct sockaddr_in *addr,
296 uint32_t timestamp)
297{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200298 int ts_error = 0;
299 int ts_check = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200300 int ptime = state->packet_duration;
301
302 /* Align according to: T + Toffs - Tlast = k * Tptime */
303
Philipp Maier87bd9be2017-08-22 16:35:41 +0200304 ts_error = ts_alignment_error(&state->out_stream, ptime,
305 timestamp + state->timestamp_offset);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200306
Philipp Maier87bd9be2017-08-22 16:35:41 +0200307 /* If there is an alignment error, we have to compensate it */
308 if (ts_error) {
309 state->timestamp_offset += ptime - ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200310
311 LOGP(DLMGCP, LOGL_NOTICE,
312 "Corrected timestamp alignment error of %d on 0x%x SSRC: %u "
313 "new TS offset: %d, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200314 "from %s:%d\n",
315 ts_error,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200316 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
317 state->timestamp_offset, inet_ntoa(addr->sin_addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200318 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200319 }
320
Philipp Maier87bd9be2017-08-22 16:35:41 +0200321 /* Check we really managed to compensate the timestamp
322 * offset. There should not be any remaining error, failing
323 * here would point to a serous problem with the alingnment
324 * error computation fuction */
325 ts_check = ts_alignment_error(&state->out_stream, ptime,
326 timestamp + state->timestamp_offset);
327 OSMO_ASSERT(ts_check == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200328
Philipp Maier87bd9be2017-08-22 16:35:41 +0200329 /* Return alignment error before compensation */
330 return ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200331}
332
Philipp Maier87bd9be2017-08-22 16:35:41 +0200333/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
334 * \param[in] associated endpoint
335 * \param[in] destination RTP end
336 * \param[in,out] pointer to buffer with voice data
337 * \param[in] voice data length
338 * \param[in] maxmimum size of caller provided voice data buffer
339 * \returns ignores input parameters, return always 0 */
340int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
341 struct mgcp_rtp_end *dst_end,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200342 char *data, int *len, int buf_size)
343{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200344 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x transcoding disabled\n",
345 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200346 return 0;
347}
348
Philipp Maier87bd9be2017-08-22 16:35:41 +0200349/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
350 * \param[in] associated endpoint
351 * \param[in] destination RTP end
352 * \param[in] source RTP end
353 * \returns ignores input parameters, return always 0 */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200354int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
355 struct mgcp_rtp_end *dst_end,
356 struct mgcp_rtp_end *src_end)
357{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200358 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x transcoding disabled\n",
359 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200360 return 0;
361}
362
363void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
364 int *payload_type,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200365 const char **audio_name,
366 const char **fmtp_extra,
367 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200368{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200369 LOGP(DLMGCP, LOGL_DEBUG,
370 "endpoint:%x conn:%s using format defaults\n",
371 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
372
373 *payload_type = conn->end.codec.payload_type;
374 *audio_name = conn->end.codec.audio_name;
375 *fmtp_extra = conn->end.fmtp_extra;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200376}
377
Philipp Maier87bd9be2017-08-22 16:35:41 +0200378void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
379 struct mgcp_rtp_state *state, const uint16_t seq,
380 const int32_t transit, const uint32_t ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200381{
382 int32_t d;
383
384 /* initialize or re-initialize */
385 if (!state->stats_initialized || state->stats_ssrc != ssrc) {
386 state->stats_initialized = 1;
387 state->stats_base_seq = seq;
388 state->stats_max_seq = seq - 1;
389 state->stats_ssrc = ssrc;
390 state->stats_jitter = 0;
391 state->stats_transit = transit;
392 state->stats_cycles = 0;
393 } else {
394 uint16_t udelta;
395
Philipp Maier87bd9be2017-08-22 16:35:41 +0200396 /* The below takes the shape of the validation of
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200397 * Appendix A. Check if there is something weird with
398 * the sequence number, otherwise check for a wrap
399 * around in the sequence number.
400 * It can't wrap during the initialization so let's
401 * skip it here. The Appendix A probably doesn't have
Philipp Maier87bd9be2017-08-22 16:35:41 +0200402 * this issue because of the probation. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200403 udelta = seq - state->stats_max_seq;
404 if (udelta < RTP_MAX_DROPOUT) {
405 if (seq < state->stats_max_seq)
406 state->stats_cycles += RTP_SEQ_MOD;
407 } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
408 LOGP(DLMGCP, LOGL_NOTICE,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200409 "RTP seqno made a very large jump on 0x%x delta: %u\n",
410 ENDPOINT_NUMBER(endp), udelta);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200411 }
412 }
413
Philipp Maier87bd9be2017-08-22 16:35:41 +0200414 /* Calculate the jitter between the two packages. The TS should be
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200415 * taken closer to the read function. This was taken from the
416 * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
Philipp Maier87bd9be2017-08-22 16:35:41 +0200417 * resolution. */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200418 d = transit - state->stats_transit;
419 state->stats_transit = transit;
420 if (d < 0)
421 d = -d;
422 state->stats_jitter += d - ((state->stats_jitter + 8) >> 4);
423 state->stats_max_seq = seq;
424}
425
Philipp Maier87bd9be2017-08-22 16:35:41 +0200426/* The RFC 3550 Appendix A assumes there are multiple sources but
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200427 * some of the supported endpoints (e.g. the nanoBTS) can only handle
428 * one source and this code will patch RTP header to appear as if there
429 * is only one source.
430 * There is also no probation period for new sources. Every RTP header
Philipp Maier87bd9be2017-08-22 16:35:41 +0200431 * we receive will be seen as a switch in streams. */
432void mgcp_patch_and_count(struct mgcp_endpoint *endp,
433 struct mgcp_rtp_state *state,
434 struct mgcp_rtp_end *rtp_end,
435 struct sockaddr_in *addr, char *data, int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200436{
437 uint32_t arrival_time;
438 int32_t transit;
439 uint16_t seq;
440 uint32_t timestamp, ssrc;
441 struct rtp_hdr *rtp_hdr;
442 int payload = rtp_end->codec.payload_type;
443
444 if (len < sizeof(*rtp_hdr))
445 return;
446
Philipp Maier87bd9be2017-08-22 16:35:41 +0200447 rtp_hdr = (struct rtp_hdr *)data;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200448 seq = ntohs(rtp_hdr->sequence);
449 timestamp = ntohl(rtp_hdr->timestamp);
450 arrival_time = get_current_ts(rtp_end->codec.rate);
451 ssrc = ntohl(rtp_hdr->ssrc);
452 transit = arrival_time - timestamp;
453
454 mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
455
456 if (!state->initialized) {
457 state->initialized = 1;
458 state->in_stream.last_seq = seq - 1;
459 state->in_stream.ssrc = state->orig_ssrc = ssrc;
460 state->in_stream.last_tsdelta = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200461 state->packet_duration =
462 mgcp_rtp_packet_duration(endp, rtp_end);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200463 state->out_stream = state->in_stream;
464 state->out_stream.last_timestamp = timestamp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200465 state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200466 LOGP(DLMGCP, LOGL_INFO,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200467 "endpoint:%x initializing stream, SSRC: %u timestamp: %u "
468 "pkt-duration: %d, from %s:%d\n",
469 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
470 state->seq_offset, state->packet_duration,
471 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200472 if (state->packet_duration == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200473 state->packet_duration =
474 rtp_end->codec.rate * 20 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200475 LOGP(DLMGCP, LOGL_NOTICE,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200476 "endpoint:%x fixed packet duration is not available, "
477 "using fixed 20ms instead: %d from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200478 ENDPOINT_NUMBER(endp), state->packet_duration,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200479 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200480 }
481 } else if (state->in_stream.ssrc != ssrc) {
482 LOGP(DLMGCP, LOGL_NOTICE,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200483 "endpoint:%x SSRC changed: %u -> %u "
484 "from %s:%d\n",
485 ENDPOINT_NUMBER(endp),
486 state->in_stream.ssrc, rtp_hdr->ssrc,
487 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200488
489 state->in_stream.ssrc = ssrc;
490 if (rtp_end->force_constant_ssrc) {
491 int16_t delta_seq;
492
493 /* Always increment seqno by 1 */
494 state->seq_offset =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200495 (state->out_stream.last_seq + 1) - seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200496
497 /* Estimate number of packets that would have been sent */
498 delta_seq =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200499 (arrival_time - state->in_stream.last_arrival_time
500 + state->packet_duration / 2) /
501 state->packet_duration;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200502
503 adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
504 delta_seq, timestamp);
505
506 state->patch_ssrc = 1;
507 ssrc = state->orig_ssrc;
508 if (rtp_end->force_constant_ssrc != -1)
509 rtp_end->force_constant_ssrc -= 1;
510
511 LOGP(DLMGCP, LOGL_NOTICE,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200512 "endpoint:%x SSRC patching enabled, SSRC: %u "
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200513 "SeqNo offset: %d, TS offset: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200514 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200515 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
516 state->seq_offset, state->timestamp_offset,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200517 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200518 }
519
520 state->in_stream.last_tsdelta = 0;
521 } else {
522 /* Compute current per-packet timestamp delta */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200523 check_rtp_timestamp(endp, state, &state->in_stream, rtp_end,
524 addr, seq, timestamp, "input",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200525 &state->in_stream.last_tsdelta);
526
527 if (state->patch_ssrc)
528 ssrc = state->orig_ssrc;
529 }
530
531 /* Save before patching */
532 state->in_stream.last_timestamp = timestamp;
533 state->in_stream.last_seq = seq;
534 state->in_stream.last_arrival_time = arrival_time;
535
536 if (rtp_end->force_aligned_timing &&
537 state->out_stream.ssrc == ssrc && state->packet_duration)
538 /* Align the timestamp offset */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200539 align_rtp_timestamp_offset(endp, state, rtp_end, addr,
540 timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200541
542 /* Store the updated SSRC back to the packet */
543 if (state->patch_ssrc)
544 rtp_hdr->ssrc = htonl(ssrc);
545
546 /* Apply the offset and store it back to the packet.
547 * This won't change anything if the offset is 0, so the conditional is
548 * omitted. */
549 seq += state->seq_offset;
550 rtp_hdr->sequence = htons(seq);
551 timestamp += state->timestamp_offset;
552 rtp_hdr->timestamp = htonl(timestamp);
553
554 /* Check again, whether the timestamps are still valid */
555 if (state->out_stream.ssrc == ssrc)
556 check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
557 addr, seq, timestamp, "output",
558 &state->out_stream.last_tsdelta);
559
560 /* Save output values */
561 state->out_stream.last_seq = seq;
562 state->out_stream.last_timestamp = timestamp;
563 state->out_stream.ssrc = ssrc;
564
565 if (payload < 0)
566 return;
567
568#if 0
Philipp Maier87bd9be2017-08-22 16:35:41 +0200569 DEBUGP(DLMGCP,
570 "endpoint:%x payload hdr payload %u -> endp payload %u\n",
571 ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200572 rtp_hdr->payload_type = payload;
573#endif
574}
575
Philipp Maier87bd9be2017-08-22 16:35:41 +0200576/* Forward data to a debug tap. This is debug function that is intended for
577 * debugging the voice traffic with tools like gstreamer */
578static int forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,
579 int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200580{
581 if (!tap->enabled)
582 return 0;
583
584 return sendto(fd, buf, len, 0,
585 (struct sockaddr *)&tap->forward, sizeof(tap->forward));
586}
587
Philipp Maier87bd9be2017-08-22 16:35:41 +0200588/*! Send RTP/RTCP data to a specified destination connection.
589 * \param[in] endp associated endpoint (for configuration, logging)
590 * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP
591 * \param[in] spoofed source address (set to NULL to disable)
592 * \param[in] buf buffer that contains the RTP/RTCP data
593 * \param[in] len length of the buffer that contains the RTP/RTCP data
594 * \param[in] conn_src associated source connection
595 * \param[in] conn_dst associated destination connection
596 * \returns 0 on success, -1 on ERROR */
597int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
598 char *buf, int len, struct mgcp_conn_rtp *conn_src,
599 struct mgcp_conn_rtp *conn_dst)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200600{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200601 /*! When no destination connection is available (e.g. when only one
602 * connection in loopback mode exists), then the source connection
603 * shall be specified as destination connection */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200604
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200605 struct mgcp_trunk_config *tcfg = endp->tcfg;
606 struct mgcp_rtp_end *rtp_end;
607 struct mgcp_rtp_state *rtp_state;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200608 char *dest_name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200609
Philipp Maier87bd9be2017-08-22 16:35:41 +0200610 OSMO_ASSERT(conn_src);
611 OSMO_ASSERT(conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200612
Philipp Maier87bd9be2017-08-22 16:35:41 +0200613 if (is_rtp) {
614 LOGP(DLMGCP, LOGL_DEBUG,
615 "endpoint:%x delivering RTP packet...\n",
616 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200617 } else {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200618 LOGP(DLMGCP, LOGL_DEBUG,
619 "endpoint:%x delivering RTCP packet...\n",
620 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200621 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200622
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200623 LOGP(DLMGCP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200624 "endpoint:%x loop:%d, mode:%d ",
625 ENDPOINT_NUMBER(endp), tcfg->audio_loop, conn_src->conn->mode);
626 if (conn_src->conn->mode == MGCP_CONN_LOOPBACK)
627 LOGPC(DLMGCP, LOGL_DEBUG, "(loopback)\n");
628 else
629 LOGPC(DLMGCP, LOGL_DEBUG, "\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200630
Philipp Maier87bd9be2017-08-22 16:35:41 +0200631 /* Note: In case of loopback configuration, both, the source and the
632 * destination will point to the same connection. */
633 rtp_end = &conn_dst->end;
634 rtp_state = &conn_src->state;
635 dest_name = conn_dst->conn->name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200636
637 if (!rtp_end->output_enabled) {
638 rtp_end->dropped_packets += 1;
639 LOGP(DLMGCP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200640 "endpoint:%x output disabled, drop to %s %s "
641 "rtp_port:%u rtcp_port:%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200642 ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200643 dest_name,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200644 inet_ntoa(rtp_end->addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200645 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200646 );
647 } else if (is_rtp) {
648 int cont;
649 int nbytes = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200650 int buflen = len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200651 do {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200652 /* Run transcoder */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200653 cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200654 buf, &buflen,
655 RTP_BUF_SIZE);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200656 if (cont < 0)
657 break;
658
Philipp Maier87bd9be2017-08-22 16:35:41 +0200659 if (addr)
660 mgcp_patch_and_count(endp, rtp_state, rtp_end,
661 addr, buf, buflen);
662 LOGP(DLMGCP, LOGL_DEBUG,
663 "endpoint:%x process/send to %s %s "
664 "rtp_port:%u rtcp_port:%u\n",
665 ENDPOINT_NUMBER(endp), dest_name,
666 inet_ntoa(rtp_end->addr), ntohs(rtp_end->rtp_port),
667 ntohs(rtp_end->rtcp_port)
668 );
669
670 /* Forward a copy of the RTP data to a debug ip/port */
671 forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
672 buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200673
674 /* FIXME: HACK HACK HACK. See OS#2459.
675 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
676 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
677 * cells (as long as we patch only the first RTP payload in each stream).
678 */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200679 if (!rtp_state->patched_first_rtp_payload) {
680 uint8_t *data = (uint8_t *) & buf[12];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200681 data[0] = 0xe4;
682 data[1] = 0x00;
683 rtp_state->patched_first_rtp_payload = true;
684 }
685
Philipp Maier87bd9be2017-08-22 16:35:41 +0200686 len = mgcp_udp_send(rtp_end->rtp.fd,
687 &rtp_end->addr,
688 rtp_end->rtp_port, buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200689
Philipp Maier87bd9be2017-08-22 16:35:41 +0200690 if (len <= 0)
691 return len;
692
693 conn_dst->end.packets_tx += 1;
694 conn_dst->end.octets_tx += len;
695
696 nbytes += len;
697 buflen = cont;
698 } while (buflen > 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200699 return nbytes;
700 } else if (!tcfg->omit_rtcp) {
701 LOGP(DLMGCP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200702 "endpoint:%x send to %s %s rtp_port:%u rtcp_port:%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200703 ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200704 dest_name,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200705 inet_ntoa(rtp_end->addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200706 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200707 );
708
Philipp Maier87bd9be2017-08-22 16:35:41 +0200709 len = mgcp_udp_send(rtp_end->rtcp.fd,
710 &rtp_end->addr,
711 rtp_end->rtcp_port, buf, len);
712
713 conn_dst->end.packets_tx += 1;
714 conn_dst->end.octets_tx += len;
715
716 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200717 }
718
719 return 0;
720}
721
Philipp Maier87bd9be2017-08-22 16:35:41 +0200722/* Helper function for mgcp_recv(),
723 Receive one RTP Packet + Originating address from file descriptor */
724static int receive_from(struct mgcp_endpoint *endp, int fd,
725 struct sockaddr_in *addr, char *buf, int bufsize)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200726{
727 int rc;
728 socklen_t slen = sizeof(*addr);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200729 struct sockaddr_in addr_sink;
730 char buf_sink[RTP_BUF_SIZE];
731 bool tossed = false;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200732
Philipp Maier87bd9be2017-08-22 16:35:41 +0200733 if (!addr)
734 addr = &addr_sink;
735 if (!buf) {
736 tossed = true;
737 buf = buf_sink;
738 bufsize = sizeof(buf_sink);
739 }
740
741 rc = recvfrom(fd, buf, bufsize, 0, (struct sockaddr *)addr, &slen);
742
743 LOGP(DLMGCP, LOGL_DEBUG,
744 "receiving %u bytes length packet from %s:%u ...\n",
745 rc, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
746
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200747 if (rc < 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200748 LOGP(DLMGCP, LOGL_ERROR,
749 "endpoint:%x failed to receive packet, errno: %d/%s\n",
750 ENDPOINT_NUMBER(endp), errno, strerror(errno));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200751 return -1;
752 }
753
Philipp Maier87bd9be2017-08-22 16:35:41 +0200754 if (tossed) {
755 LOGP(DLMGCP, LOGL_ERROR, "endpoint:%x packet tossed\n",
756 ENDPOINT_NUMBER(endp));
757 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200758
759 return rc;
760}
761
Philipp Maier87bd9be2017-08-22 16:35:41 +0200762/* Check if the origin (addr) matches the address/port data of the RTP
763 * connections. */
764static int check_rtp_origin(struct mgcp_conn_rtp *conn,
765 struct sockaddr_in *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200766{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200767 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200768 endp = conn->conn->endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200769
Philipp Maier87bd9be2017-08-22 16:35:41 +0200770 /* Note: Check if the inbound RTP data comes from the same host to
771 * which we send our outgoing RTP traffic. */
772 if (memcmp(&addr->sin_addr, &conn->end.addr, sizeof(addr->sin_addr))
773 != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200774 LOGP(DLMGCP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200775 "endpoint:%x data from wrong address: %s, ",
776 ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr));
777 LOGPC(DLMGCP, LOGL_ERROR, "expected: %s\n",
778 inet_ntoa(conn->end.addr));
779 LOGP(DLMGCP, LOGL_ERROR, "endpoint:%x packet tossed\n",
780 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200781 return -1;
782 }
783
Philipp Maier87bd9be2017-08-22 16:35:41 +0200784 /* Note: Usually the remote remote port of the data we receive will be
785 * the same as the remote port where we transmit outgoing RTP traffic
786 * to (set by MDCX). We use this to check the origin of the data for
787 * plausibility. */
788 if (conn->end.rtp_port != addr->sin_port &&
789 conn->end.rtcp_port != addr->sin_port) {
790 LOGP(DLMGCP, LOGL_ERROR,
791 "endpoint:%x data from wrong source port: %d, ",
792 ENDPOINT_NUMBER(endp), ntohs(addr->sin_port));
793 LOGPC(DLMGCP, LOGL_ERROR,
794 "expected: %d for RTP or %d for RTCP\n",
795 ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
796 LOGP(DLMGCP, LOGL_ERROR, "endpoint:%x packet tossed\n",
797 ENDPOINT_NUMBER(endp));
798 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200799 }
800
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200801 return 0;
802}
803
Philipp Maier87bd9be2017-08-22 16:35:41 +0200804/* Check the if the destination address configuration of an RTP connection
805 * makes sense */
806static int check_rtp_destin(struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200807{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200808 struct mgcp_endpoint *endp;
809 endp = conn->conn->endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200810
Philipp Maier87bd9be2017-08-22 16:35:41 +0200811 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0) {
812 LOGP(DLMGCP, LOGL_ERROR,
813 "endpoint:%x destination IP-address is invalid\n",
814 ENDPOINT_NUMBER(endp));
815 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200816 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200817
818 if (conn->end.rtp_port == 0) {
819 LOGP(DLMGCP, LOGL_ERROR,
820 "endpoint:%x destination rtp port is invalid\n",
821 ENDPOINT_NUMBER(endp));
822 return -1;
823 }
824
825 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200826}
827
Philipp Maier87bd9be2017-08-22 16:35:41 +0200828/* Receive RTP data from a specified source connection and dispatch it to a
829 * destination connection. */
830static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
831 unsigned int buf_size, struct osmo_fd *fd)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200832{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200833 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200834 struct mgcp_conn_rtp *conn;
835 struct mgcp_trunk_config *tcfg;
836 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200837
Philipp Maier87bd9be2017-08-22 16:35:41 +0200838 conn = (struct mgcp_conn_rtp*) fd->data;
839 endp = conn->conn->endp;
840 tcfg = endp->tcfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200841
Philipp Maier87bd9be2017-08-22 16:35:41 +0200842 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x receiving RTP/RTCP packet...\n",
843 ENDPOINT_NUMBER(endp));
844
845 rc = receive_from(endp, fd->fd, addr, buf, buf_size);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200846 if (rc <= 0)
847 return -1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200848 *proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200849
Philipp Maier87bd9be2017-08-22 16:35:41 +0200850 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x ", ENDPOINT_NUMBER(endp));
851 LOGPC(DLMGCP, LOGL_DEBUG, "receiveing from %s %s %d\n",
852 conn->conn->name, inet_ntoa(addr->sin_addr),
853 ntohs(addr->sin_port));
854 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x conn:%s\n", ENDPOINT_NUMBER(endp),
855 mgcp_conn_dump(conn->conn));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200856
Philipp Maier87bd9be2017-08-22 16:35:41 +0200857 /* Check if the origin of the RTP packet seems plausible */
858 if (tcfg->rtp_accept_all == 0) {
859 if (check_rtp_origin(conn, addr) != 0)
860 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200861 }
862
Philipp Maier87bd9be2017-08-22 16:35:41 +0200863 /* Filter out dummy message */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200864 if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200865 LOGP(DLMGCP, LOGL_NOTICE,
866 "endpoint:%x dummy message received\n",
867 ENDPOINT_NUMBER(endp));
868 LOGP(DLMGCP, LOGL_ERROR,
869 "endpoint:%x packet tossed\n", ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200870 return 0;
871 }
872
Philipp Maier87bd9be2017-08-22 16:35:41 +0200873 /* Increment RX statistics */
874 conn->end.packets_rx += 1;
875 conn->end.octets_rx += rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200876
Philipp Maier87bd9be2017-08-22 16:35:41 +0200877 /* Forward a copy of the RTP data to a debug ip/port */
878 forward_data(fd->fd, &conn->tap_in, buf, rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200879
Philipp Maier87bd9be2017-08-22 16:35:41 +0200880 return rc;
881}
882
883/* Send RTP data. Possible options are standard RTP packet
884 * transmission or trsmission via an osmux connection */
885static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
886 unsigned int buf_size,
887 struct mgcp_conn_rtp *conn_src,
888 struct mgcp_conn_rtp *conn_dst)
889{
890 struct mgcp_endpoint *endp;
891 endp = conn_src->conn->endp;
892
893 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x destin conn:%s\n",
894 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_dst->conn));
895
896 /* Before we try to deliver the packet, we check if the destination
897 * port and IP-Address make sense at all. If not, we will be unable
898 * to deliver the packet. */
899 if (check_rtp_destin(conn_dst) != 0)
900 return -1;
901
902 /* Depending on the RTP connection type, deliver the RTP packet to the
903 * destination connection. */
904 switch (conn_dst->type) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200905 case MGCP_RTP_DEFAULT:
906 LOGP(DLMGCP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200907 "endpoint:%x endpoint type is MGCP_RTP_DEFAULT, "
908 "using mgcp_send() to forward data directly\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200909 ENDPOINT_NUMBER(endp));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200910 return mgcp_send(endp, proto == MGCP_PROTO_RTP,
911 addr, buf, buf_size, conn_src, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200912 case MGCP_OSMUX_BSC_NAT:
Philipp Maier87bd9be2017-08-22 16:35:41 +0200913 case MGCP_OSMUX_BSC:
914 LOGP(DLMGCP, LOGL_DEBUG,
915 "endpoint:%x endpoint type is MGCP_OSMUX_BSC_NAT, "
916 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n",
917 ENDPOINT_NUMBER(endp));
918 return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200919 }
920
Philipp Maier87bd9be2017-08-22 16:35:41 +0200921 /* If the data has not been handled/forwarded until here, it will
922 * be discarded, this should not happen, normally the MGCP type
923 * should be properly set */
924 LOGP(DLMGCP, LOGL_ERROR,
925 "endpoint:%x bad MGCP type -- data discarded!\n",
926 ENDPOINT_NUMBER(endp));
927
928 return -1;
929}
930
931/*! dispatch incoming RTP packet to opposite RTP connection.
932 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP)
933 * \param[in] addr socket address where the RTP packet has been received from
934 * \param[in] buf buffer that hold the RTP payload
935 * \param[in] buf_size size data length of buf
936 * \param[in] conn originating connection
937 * \returns 0 on success, -1 on ERROR */
938int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
939 unsigned int buf_size, struct mgcp_conn *conn)
940{
941 struct mgcp_conn *conn_dst;
942 struct mgcp_endpoint *endp;
943 endp = conn->endp;
944
945 /*! NOTE: This callback function implements the endpoint specific
946 * dispatch bahviour of an rtp bridge/proxy endpoint. It is assumed
947 * that the endpoint will hold only two connections. This premise
948 * is used to determine the opposite connection (it is always the
949 * connection that is not the originating connection). Once the
950 * destination connection is known the RTP packet is sent via
951 * the destination connection. */
952
953 /* Find a destination connection. */
954 /* NOTE: This code path runs every time an RTP packet is received. The
955 * function mgcp_find_dst_conn() we use to determine the detination
956 * connection will iterate the connection list inside the endpoint.
957 * Since list iterations are quite costly, we will figure out the
958 * destination only once and use the optional private data pointer of
959 * the connection to cache the destination connection pointer. */
960 if (!conn->priv) {
961 conn_dst = mgcp_find_dst_conn(conn);
962 conn->priv = conn_dst;
963 } else {
964 conn_dst = (struct mgcp_conn *)conn->priv;
965 }
966
967 /* There is no destination conn, stop here */
968 if (!conn_dst) {
969 LOGP(DLMGCP, LOGL_ERROR,
970 "endpoint:%x unable to find destination conn\n",
971 ENDPOINT_NUMBER(endp));
972 return -1;
973 }
974
975 /* The destination conn is not an RTP connection */
976 if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
977 LOGP(DLMGCP, LOGL_ERROR,
978 "endpoint:%x unable to find suitable destination conn\n",
979 ENDPOINT_NUMBER(endp));
980 return -1;
981 }
982
983 /* Dispatch RTP packet to destination RTP connection */
984 return mgcp_send_rtp(proto, addr, buf,
985 buf_size, &conn->u.rtp, &conn_dst->u.rtp);
986
987}
988
989/* Handle incoming RTP data from NET */
990static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
991{
992 /* NOTE: This is a generic implementation. RTP data is received. In
993 * case of loopback the data is just sent back to its origin. All
994 * other cases implement endpoint specific behaviour (e.g. how is the
995 * destination connection determined?). That specific behaviour is
996 * implemented by the callback function that is called at the end of
997 * the function */
998
999 struct mgcp_conn_rtp *conn_src;
1000 struct mgcp_endpoint *endp;
1001 struct sockaddr_in addr;
1002
1003 char buf[RTP_BUF_SIZE];
1004 int proto;
1005 int rc;
1006
1007 conn_src = (struct mgcp_conn_rtp *)fd->data;
1008 OSMO_ASSERT(conn_src);
1009 endp = conn_src->conn->endp;
1010 OSMO_ASSERT(endp);
1011
1012 LOGP(DLMGCP, LOGL_DEBUG, "endpoint:%x source conn:%s\n",
1013 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_src->conn));
1014
1015 /* Receive packet */
1016 rc = mgcp_recv(&proto, &addr, buf, sizeof(buf), fd);
1017 if (rc < 0)
1018 return -1;
1019
1020 /* Check if the connection is in loopback mode, if yes, just send the
1021 * incoming data back to the origin */
1022 if (conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
1023 return mgcp_send_rtp(proto, &addr, buf,
1024 sizeof(buf), conn_src, conn_src);
1025 }
1026
1027 /* Execute endpoint specific implementation that handles the
1028 * dispatching of the RTP data */
1029 return endp->type->dispatch_rtp_cb(proto, &addr, buf, sizeof(buf),
1030 conn_src->conn);
1031}
1032
1033/*! set IP Type of Service parameter.
1034 * \param[in] fd associated file descriptor
1035 * \param[in] tos dscp value
1036 * \returns 0 on success, -1 on ERROR */
1037int mgcp_set_ip_tos(int fd, int tos)
1038{
1039 int ret;
1040 ret = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
1041
1042 if (ret < 0)
1043 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001044 return 0;
1045}
1046
Philipp Maier87bd9be2017-08-22 16:35:41 +02001047/*! bind RTP port to osmo_fd.
1048 * \param[in] source_addr source (local) address to bind on
1049 * \param[in] fd associated file descriptor
1050 * \param[in] port to bind on
1051 * \returns 0 on success, -1 on ERROR */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001052int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
1053{
1054 struct sockaddr_in addr;
1055 int on = 1;
1056
1057 fd->fd = socket(AF_INET, SOCK_DGRAM, 0);
1058 if (fd->fd < 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001059 LOGP(DLMGCP, LOGL_ERROR, "failed to create UDP port (%s:%i).\n",
1060 source_addr, port);
1061 return -1;
1062 } else {
1063 LOGP(DLMGCP, LOGL_DEBUG,
1064 "created UDP port (%s:%i).\n", source_addr, port);
1065 }
1066
1067 if (setsockopt(fd->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
1068 LOGP(DLMGCP, LOGL_ERROR,
1069 "failed to set socket options (%s:%i).\n", source_addr,
1070 port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001071 return -1;
1072 }
1073
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001074 memset(&addr, 0, sizeof(addr));
1075 addr.sin_family = AF_INET;
1076 addr.sin_port = htons(port);
1077 inet_aton(source_addr, &addr.sin_addr);
1078
Philipp Maier87bd9be2017-08-22 16:35:41 +02001079 if (bind(fd->fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001080 close(fd->fd);
1081 fd->fd = -1;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001082 LOGP(DLMGCP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
1083 source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001084 return -1;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001085 } else {
1086 LOGP(DLMGCP, LOGL_DEBUG,
1087 "bound UDP port (%s:%i).\n", source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001088 }
1089
1090 return 0;
1091}
1092
Philipp Maier87bd9be2017-08-22 16:35:41 +02001093/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001094static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001095 struct mgcp_rtp_end *rtp_end, int endpno)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001096{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001097 /* NOTE: The port that is used for RTCP is the RTP port incremented by one
1098 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
1099
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001100 if (mgcp_create_bind(source_addr, &rtp_end->rtp,
1101 rtp_end->local_port) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001102 LOGP(DLMGCP, LOGL_ERROR,
1103 "endpoint:%x failed to create RTP port: %s:%d\n", endpno,
1104 source_addr, rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001105 goto cleanup0;
1106 }
1107
1108 if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
1109 rtp_end->local_port + 1) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001110 LOGP(DLMGCP, LOGL_ERROR,
1111 "endpoint:%x failed to create RTCP port: %s:%d\n", endpno,
1112 source_addr, rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001113 goto cleanup1;
1114 }
1115
Philipp Maier87bd9be2017-08-22 16:35:41 +02001116 /* Set Type of Service (DSCP-Value) as configured via VTY */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001117 mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
1118 mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
1119
1120 rtp_end->rtp.when = BSC_FD_READ;
1121 if (osmo_fd_register(&rtp_end->rtp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001122 LOGP(DLMGCP, LOGL_ERROR,
1123 "endpoint:%x failed to register RTP port %d\n", endpno,
1124 rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001125 goto cleanup2;
1126 }
1127
1128 rtp_end->rtcp.when = BSC_FD_READ;
1129 if (osmo_fd_register(&rtp_end->rtcp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001130 LOGP(DLMGCP, LOGL_ERROR,
1131 "endpoint:%x failed to register RTCP port %d\n", endpno,
1132 rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001133 goto cleanup3;
1134 }
1135
1136 return 0;
1137
1138cleanup3:
1139 osmo_fd_unregister(&rtp_end->rtp);
1140cleanup2:
1141 close(rtp_end->rtcp.fd);
1142 rtp_end->rtcp.fd = -1;
1143cleanup1:
1144 close(rtp_end->rtp.fd);
1145 rtp_end->rtp.fd = -1;
1146cleanup0:
1147 return -1;
1148}
1149
Philipp Maier87bd9be2017-08-22 16:35:41 +02001150/*! bind RTP port to endpoint/connection.
1151 * \param[in] endp endpoint that holds the RTP connection
1152 * \param[in] rtp_port port number to bind on
1153 * \param[in] conn associated RTP connection
1154 * \returns 0 on success, -1 on ERROR */
1155int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
1156 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001157{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001158 char name[512];
1159 struct mgcp_rtp_end *end;
1160
1161 snprintf(name, sizeof(name), "%s-%u", conn->conn->name, conn->conn->id);
1162 end = &conn->end;
1163
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001164 if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001165 LOGP(DLMGCP, LOGL_ERROR,
1166 "endpoint:%x %u was already bound on conn:%s\n",
1167 ENDPOINT_NUMBER(endp), rtp_port,
1168 mgcp_conn_dump(conn->conn));
1169
1170 /* Double bindings should never occour! Since we always allocate
1171 * connections dynamically and free them when they are not
1172 * needed anymore, there must be no previous binding leftover.
1173 * Should there be a connection bound twice, we have a serious
1174 * problem and must exit immediately! */
1175 OSMO_ASSERT(false);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001176 }
1177
1178 end->local_port = rtp_port;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001179 end->rtp.cb = rtp_data_net;
1180 end->rtp.data = conn;
1181 end->rtcp.data = conn;
1182 end->rtcp.cb = rtp_data_net;
1183
1184 return bind_rtp(endp->cfg, mgcp_net_src_addr(endp), end,
1185 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001186}
1187
Philipp Maier87bd9be2017-08-22 16:35:41 +02001188/*! free allocated RTP and RTCP ports.
1189 * \param[in] end RTP end */
1190void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001191{
1192 if (end->rtp.fd != -1) {
1193 close(end->rtp.fd);
1194 end->rtp.fd = -1;
1195 osmo_fd_unregister(&end->rtp);
1196 }
1197
1198 if (end->rtcp.fd != -1) {
1199 close(end->rtcp.fd);
1200 end->rtcp.fd = -1;
1201 osmo_fd_unregister(&end->rtcp);
1202 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001203}