blob: 1b1867a7be1f2adbfe2950dec72113e43714aef2 [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 <arpa/inet.h>
31
32#include <osmocom/core/msgb.h>
33#include <osmocom/core/select.h>
Philipp Maier1cb1e382017-11-02 17:16:04 +010034#include <osmocom/core/socket.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>
Philipp Maier37d11c82018-02-01 14:38:12 +010042#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maier6931f9a2018-07-26 09:29:31 +020043#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maierc3413882017-10-27 12:26:54 +020044#include <osmocom/mgcp/debug.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020045
Philipp Maier6931f9a2018-07-26 09:29:31 +020046
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020047#define RTP_SEQ_MOD (1 << 16)
48#define RTP_MAX_DROPOUT 3000
49#define RTP_MAX_MISORDER 100
50#define RTP_BUF_SIZE 4096
51
52enum {
53 MGCP_PROTO_RTP,
54 MGCP_PROTO_RTCP,
55};
56
Philipp Maier1cb1e382017-11-02 17:16:04 +010057/*! Determine the local rtp bind IP-address.
58 * \param[out] addr caller provided memory to store the resulting IP-Address
59 * \param[in] endp mgcp endpoint, that holds a copy of the VTY parameters
60 *
61 * The local bind IP-address is automatically selected by probing the
62 * IP-Address of the interface that is pointing towards the remote IP-Address,
63 * if no remote IP-Address is known yet, the statically configured
64 * IP-Addresses are used as fallback. */
65void mgcp_get_local_addr(char *addr, struct mgcp_conn_rtp *conn)
66{
67
68 struct mgcp_endpoint *endp;
69 int rc;
70 endp = conn->conn->endp;
71
72 /* Try probing the local IP-Address */
73 if (endp->cfg->net_ports.bind_addr_probe && conn->end.addr.s_addr != 0) {
74 rc = osmo_sock_local_ip(addr, inet_ntoa(conn->end.addr));
75 if (rc < 0)
76 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +010077 "endpoint:0x%x CI:%s local interface auto detection failed, using configured addresses...\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +010078 ENDPOINT_NUMBER(endp), conn->conn->id);
79 else {
80 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +010081 "endpoint:0x%x CI:%s selected local rtp bind ip %s by probing using remote ip %s\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +010082 ENDPOINT_NUMBER(endp), conn->conn->id, addr,
83 inet_ntoa(conn->end.addr));
84 return;
85 }
86 }
87
88 /* Select from preconfigured IP-Addresses */
89 if (endp->cfg->net_ports.bind_addr) {
90 /* Check there is a bind IP for the RTP traffic configured,
91 * if so, use that IP-Address */
Philipp Maierf8bfbe82017-11-23 19:32:31 +010092 osmo_strlcpy(addr, endp->cfg->net_ports.bind_addr, INET_ADDRSTRLEN);
Philipp Maier1cb1e382017-11-02 17:16:04 +010093 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +010094 "endpoint:0x%x CI:%s using configured rtp bind ip as local bind ip %s\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +010095 ENDPOINT_NUMBER(endp), conn->conn->id, addr);
96 } else {
97 /* No specific bind IP is configured for the RTP traffic, so
98 * assume the IP where we listen for incoming MGCP messages
99 * as bind IP */
Philipp Maierf8bfbe82017-11-23 19:32:31 +0100100 osmo_strlcpy(addr, endp->cfg->source_addr, INET_ADDRSTRLEN);
Philipp Maier1cb1e382017-11-02 17:16:04 +0100101 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100102 "endpoint:0x%x CI:%s using mgcp bind ip as local rtp bind ip: %s\n",
Philipp Maier1cb1e382017-11-02 17:16:04 +0100103 ENDPOINT_NUMBER(endp), conn->conn->id, addr);
104 }
105}
106
Philipp Maier87bd9be2017-08-22 16:35:41 +0200107/* This does not need to be a precision timestamp and
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200108 * is allowed to wrap quite fast. The returned value is
Philipp Maier87bd9be2017-08-22 16:35:41 +0200109 * 1/codec_rate seconds. */
110static uint32_t get_current_ts(unsigned codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200111{
112 struct timespec tp;
113 uint64_t ret;
114
Philipp Maier87bd9be2017-08-22 16:35:41 +0200115 if (!codec_rate)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200116 return 0;
117
118 memset(&tp, 0, sizeof(tp));
119 if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0)
Philipp Maierc3413882017-10-27 12:26:54 +0200120 LOGP(DRTP, LOGL_NOTICE, "Getting the clock failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200121
122 /* convert it to 1/unit seconds */
123 ret = tp.tv_sec;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200124 ret *= codec_rate;
125 ret += (int64_t) tp.tv_nsec * codec_rate / 1000 / 1000 / 1000;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200126
127 return ret;
128}
129
Philipp Maier87bd9be2017-08-22 16:35:41 +0200130/*! send udp packet.
131 * \param[in] fd associated file descriptor
132 * \param[in] addr destination ip-address
133 * \param[in] port destination UDP port
134 * \param[in] buf buffer that holds the data to be send
135 * \param[in] len length of the data to be sent
136 * \returns bytes sent, -1 on error */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200137int mgcp_udp_send(int fd, struct in_addr *addr, int port, char *buf, int len)
138{
139 struct sockaddr_in out;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200140
Philipp Maierc3413882017-10-27 12:26:54 +0200141 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200142 "sending %i bytes length packet to %s:%u ...\n",
143 len, inet_ntoa(*addr), ntohs(port));
144
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200145 out.sin_family = AF_INET;
146 out.sin_port = port;
147 memcpy(&out.sin_addr, addr, sizeof(*addr));
148
149 return sendto(fd, buf, len, 0, (struct sockaddr *)&out, sizeof(out));
150}
151
Philipp Maier87bd9be2017-08-22 16:35:41 +0200152/*! send RTP dummy packet (to keep NAT connection open).
153 * \param[in] endp mcgp endpoint that holds the RTP connection
154 * \param[in] conn associated RTP connection
155 * \returns bytes sent, -1 on error */
156int mgcp_send_dummy(struct mgcp_endpoint *endp, struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200157{
158 static char buf[] = { MGCP_DUMMY_LOAD };
159 int rc;
160 int was_rtcp = 0;
161
Philipp Maier87bd9be2017-08-22 16:35:41 +0200162 OSMO_ASSERT(endp);
163 OSMO_ASSERT(conn);
164
Philipp Maierc3413882017-10-27 12:26:54 +0200165 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100166 "endpoint:0x%x sending dummy packet...\n", ENDPOINT_NUMBER(endp));
167 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200168 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
169
170 rc = mgcp_udp_send(conn->end.rtp.fd, &conn->end.addr,
171 conn->end.rtp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200172
173 if (rc == -1)
174 goto failed;
175
176 if (endp->tcfg->omit_rtcp)
177 return rc;
178
179 was_rtcp = 1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200180 rc = mgcp_udp_send(conn->end.rtcp.fd, &conn->end.addr,
181 conn->end.rtcp_port, buf, 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200182
183 if (rc >= 0)
184 return rc;
185
186failed:
Philipp Maierc3413882017-10-27 12:26:54 +0200187 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100188 "endpoint:0x%x Failed to send dummy %s packet.\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200189 ENDPOINT_NUMBER(endp), was_rtcp ? "RTCP" : "RTP");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200190
191 return -1;
192}
193
Philipp Maier87bd9be2017-08-22 16:35:41 +0200194/* Compute timestamp alignment error */
195static int32_t ts_alignment_error(struct mgcp_rtp_stream_state *sstate,
196 int ptime, uint32_t timestamp)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200197{
198 int32_t timestamp_delta;
199
200 if (ptime == 0)
201 return 0;
202
203 /* Align according to: T - Tlast = k * Tptime */
204 timestamp_delta = timestamp - sstate->last_timestamp;
205
206 return timestamp_delta % ptime;
207}
208
Philipp Maier87bd9be2017-08-22 16:35:41 +0200209/* Check timestamp and sequence number for plausibility */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200210static int check_rtp_timestamp(struct mgcp_endpoint *endp,
211 struct mgcp_rtp_state *state,
212 struct mgcp_rtp_stream_state *sstate,
213 struct mgcp_rtp_end *rtp_end,
214 struct sockaddr_in *addr,
215 uint16_t seq, uint32_t timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200216 const char *text, int32_t * tsdelta_out)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200217{
218 int32_t tsdelta;
219 int32_t timestamp_error;
220
221 /* Not fully intialized, skip */
222 if (sstate->last_tsdelta == 0 && timestamp == sstate->last_timestamp)
223 return 0;
224
225 if (seq == sstate->last_seq) {
226 if (timestamp != sstate->last_timestamp) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200227 rate_ctr_inc(sstate->err_ts_ctr);
Philipp Maierc3413882017-10-27 12:26:54 +0200228 LOGP(DRTP, LOGL_ERROR,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200229 "The %s timestamp delta is != 0 but the sequence "
230 "number %d is the same, "
231 "TS offset: %d, SeqNo offset: %d "
232 "on 0x%x SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200233 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200234 text, seq,
Harald Welte33381352017-12-25 09:44:26 +0100235 state->patch.timestamp_offset, state->patch.seq_offset,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200236 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200237 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200238 }
239 return 0;
240 }
241
242 tsdelta =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200243 (int32_t)(timestamp - sstate->last_timestamp) /
244 (int16_t)(seq - sstate->last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200245
246 if (tsdelta == 0) {
247 /* Don't update *tsdelta_out */
Philipp Maierc3413882017-10-27 12:26:54 +0200248 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200249 "The %s timestamp delta is %d "
250 "on 0x%x SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200251 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200252 text, tsdelta,
253 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200254 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200255
256 return 0;
257 }
258
259 if (sstate->last_tsdelta != tsdelta) {
260 if (sstate->last_tsdelta) {
Philipp Maierc3413882017-10-27 12:26:54 +0200261 LOGP(DRTP, LOGL_INFO,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200262 "The %s timestamp delta changes from %d to %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200263 "on 0x%x SSRC: %u timestamp: %u from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200264 text, sstate->last_tsdelta, tsdelta,
265 ENDPOINT_NUMBER(endp), sstate->ssrc, timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200266 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200267 }
268 }
269
270 if (tsdelta_out)
271 *tsdelta_out = tsdelta;
272
273 timestamp_error =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200274 ts_alignment_error(sstate, state->packet_duration, timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200275
276 if (timestamp_error) {
Philipp Maier9e1d1642018-05-09 16:26:34 +0200277 rate_ctr_inc(sstate->err_ts_ctr);
Philipp Maierc3413882017-10-27 12:26:54 +0200278 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200279 "The %s timestamp has an alignment error of %d "
280 "on 0x%x SSRC: %u "
281 "SeqNo delta: %d, TS delta: %d, dTS/dSeq: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200282 "from %s:%d. ptime: %d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200283 text, timestamp_error,
284 ENDPOINT_NUMBER(endp), sstate->ssrc,
285 (int16_t)(seq - sstate->last_seq),
286 (int32_t)(timestamp - sstate->last_timestamp),
287 tsdelta,
288 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200289 state->packet_duration);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200290 }
291 return 1;
292}
293
294/* Set the timestamp offset according to the packet duration. */
295static int adjust_rtp_timestamp_offset(struct mgcp_endpoint *endp,
296 struct mgcp_rtp_state *state,
297 struct mgcp_rtp_end *rtp_end,
298 struct sockaddr_in *addr,
299 int16_t delta_seq, uint32_t in_timestamp)
300{
301 int32_t tsdelta = state->packet_duration;
302 int timestamp_offset;
303 uint32_t out_timestamp;
304
305 if (tsdelta == 0) {
306 tsdelta = state->out_stream.last_tsdelta;
307 if (tsdelta != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200308 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200309 "A fixed packet duration is not available on 0x%x, "
310 "using last output timestamp delta instead: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200311 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200312 ENDPOINT_NUMBER(endp), tsdelta,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200313 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200314 } else {
Philipp Maierbc0346e2018-06-07 09:52:16 +0200315 tsdelta = rtp_end->codec->rate * 20 / 1000;
Philipp Maierc3413882017-10-27 12:26:54 +0200316 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200317 "Fixed packet duration and last timestamp delta "
318 "are not available on 0x%x, "
319 "using fixed 20ms instead: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200320 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200321 ENDPOINT_NUMBER(endp), tsdelta,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200322 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200323 }
324 }
325
326 out_timestamp = state->out_stream.last_timestamp + delta_seq * tsdelta;
327 timestamp_offset = out_timestamp - in_timestamp;
328
Harald Welte33381352017-12-25 09:44:26 +0100329 if (state->patch.timestamp_offset != timestamp_offset) {
330 state->patch.timestamp_offset = timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200331
Philipp Maierc3413882017-10-27 12:26:54 +0200332 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200333 "Timestamp offset change on 0x%x SSRC: %u "
334 "SeqNo delta: %d, TS offset: %d, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200335 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200336 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100337 delta_seq, state->patch.timestamp_offset,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200338 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200339 }
340
341 return timestamp_offset;
342}
343
344/* Set the timestamp offset according to the packet duration. */
345static int align_rtp_timestamp_offset(struct mgcp_endpoint *endp,
346 struct mgcp_rtp_state *state,
347 struct mgcp_rtp_end *rtp_end,
348 struct sockaddr_in *addr,
349 uint32_t timestamp)
350{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200351 int ts_error = 0;
352 int ts_check = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200353 int ptime = state->packet_duration;
354
355 /* Align according to: T + Toffs - Tlast = k * Tptime */
356
Philipp Maier87bd9be2017-08-22 16:35:41 +0200357 ts_error = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100358 timestamp + state->patch.timestamp_offset);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200359
Philipp Maier87bd9be2017-08-22 16:35:41 +0200360 /* If there is an alignment error, we have to compensate it */
361 if (ts_error) {
Harald Welte33381352017-12-25 09:44:26 +0100362 state->patch.timestamp_offset += ptime - ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200363
Philipp Maierc3413882017-10-27 12:26:54 +0200364 LOGP(DRTP, LOGL_NOTICE,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200365 "Corrected timestamp alignment error of %d on 0x%x SSRC: %u "
366 "new TS offset: %d, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200367 "from %s:%d\n",
368 ts_error,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200369 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100370 state->patch.timestamp_offset, inet_ntoa(addr->sin_addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200371 ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200372 }
373
Philipp Maier87bd9be2017-08-22 16:35:41 +0200374 /* Check we really managed to compensate the timestamp
375 * offset. There should not be any remaining error, failing
Harald Welte1d1b98f2017-12-25 10:03:40 +0100376 * here would point to a serous problem with the alignment
377 * error computation function */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200378 ts_check = ts_alignment_error(&state->out_stream, ptime,
Harald Welte33381352017-12-25 09:44:26 +0100379 timestamp + state->patch.timestamp_offset);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200380 OSMO_ASSERT(ts_check == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200381
Philipp Maier87bd9be2017-08-22 16:35:41 +0200382 /* Return alignment error before compensation */
383 return ts_error;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200384}
385
Philipp Maier87bd9be2017-08-22 16:35:41 +0200386/*! dummy callback to disable transcoding (see also cfg->rtp_processing_cb).
387 * \param[in] associated endpoint
388 * \param[in] destination RTP end
389 * \param[in,out] pointer to buffer with voice data
390 * \param[in] voice data length
Harald Welte1d1b98f2017-12-25 10:03:40 +0100391 * \param[in] maximum size of caller provided voice data buffer
Philipp Maier87bd9be2017-08-22 16:35:41 +0200392 * \returns ignores input parameters, return always 0 */
393int mgcp_rtp_processing_default(struct mgcp_endpoint *endp,
394 struct mgcp_rtp_end *dst_end,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200395 char *data, int *len, int buf_size)
396{
Philipp Maier230e4fc2017-11-28 09:38:45 +0100397 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x transcoding disabled\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200398 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200399 return 0;
400}
401
Philipp Maier87bd9be2017-08-22 16:35:41 +0200402/*! dummy callback to disable transcoding (see also cfg->setup_rtp_processing_cb).
403 * \param[in] associated endpoint
Philipp Maieracc10352018-07-19 18:07:57 +0200404 * \param[in] destination RTP connnection
405 * \param[in] source RTP connection
Philipp Maier87bd9be2017-08-22 16:35:41 +0200406 * \returns ignores input parameters, return always 0 */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200407int mgcp_setup_rtp_processing_default(struct mgcp_endpoint *endp,
Philipp Maieracc10352018-07-19 18:07:57 +0200408 struct mgcp_conn_rtp *conn_dst,
409 struct mgcp_conn_rtp *conn_src)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200410{
Philipp Maier230e4fc2017-11-28 09:38:45 +0100411 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x transcoding disabled\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200412 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200413 return 0;
414}
415
416void mgcp_get_net_downlink_format_default(struct mgcp_endpoint *endp,
417 int *payload_type,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200418 const char **audio_name,
419 const char **fmtp_extra,
420 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200421{
Philipp Maierc3413882017-10-27 12:26:54 +0200422 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100423 "endpoint:0x%x conn:%s using format defaults\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200424 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn->conn));
425
Philipp Maierbc0346e2018-06-07 09:52:16 +0200426 *payload_type = conn->end.codec->payload_type;
427 *audio_name = conn->end.codec->audio_name;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200428 *fmtp_extra = conn->end.fmtp_extra;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200429}
430
Philipp Maier87bd9be2017-08-22 16:35:41 +0200431void mgcp_rtp_annex_count(struct mgcp_endpoint *endp,
432 struct mgcp_rtp_state *state, const uint16_t seq,
433 const int32_t transit, const uint32_t ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200434{
435 int32_t d;
436
437 /* initialize or re-initialize */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100438 if (!state->stats.initialized || state->stats.ssrc != ssrc) {
439 state->stats.initialized = 1;
440 state->stats.base_seq = seq;
441 state->stats.max_seq = seq - 1;
442 state->stats.ssrc = ssrc;
443 state->stats.jitter = 0;
444 state->stats.transit = transit;
445 state->stats.cycles = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200446 } else {
447 uint16_t udelta;
448
Philipp Maier87bd9be2017-08-22 16:35:41 +0200449 /* The below takes the shape of the validation of
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200450 * Appendix A. Check if there is something weird with
451 * the sequence number, otherwise check for a wrap
452 * around in the sequence number.
453 * It can't wrap during the initialization so let's
454 * skip it here. The Appendix A probably doesn't have
Philipp Maier87bd9be2017-08-22 16:35:41 +0200455 * this issue because of the probation. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100456 udelta = seq - state->stats.max_seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200457 if (udelta < RTP_MAX_DROPOUT) {
Harald Welte49e3d5a2017-12-25 09:47:57 +0100458 if (seq < state->stats.max_seq)
459 state->stats.cycles += RTP_SEQ_MOD;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200460 } else if (udelta <= RTP_SEQ_MOD - RTP_MAX_MISORDER) {
Philipp Maierc3413882017-10-27 12:26:54 +0200461 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200462 "RTP seqno made a very large jump on 0x%x delta: %u\n",
463 ENDPOINT_NUMBER(endp), udelta);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200464 }
465 }
466
Philipp Maier87bd9be2017-08-22 16:35:41 +0200467 /* Calculate the jitter between the two packages. The TS should be
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200468 * taken closer to the read function. This was taken from the
469 * Appendix A of RFC 3550. Timestamp and arrival_time have a 1/rate
Philipp Maier87bd9be2017-08-22 16:35:41 +0200470 * resolution. */
Harald Welte49e3d5a2017-12-25 09:47:57 +0100471 d = transit - state->stats.transit;
472 state->stats.transit = transit;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200473 if (d < 0)
474 d = -d;
Harald Welte49e3d5a2017-12-25 09:47:57 +0100475 state->stats.jitter += d - ((state->stats.jitter + 8) >> 4);
476 state->stats.max_seq = seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200477}
478
Philipp Maier6931f9a2018-07-26 09:29:31 +0200479/* There may be different payload type numbers negotiated for two connections.
480 * Patch the payload type of an RTP packet so that it uses the payload type
481 * that is valid for the destination connection (conn_dst) */
482static int mgcp_patch_pt(struct mgcp_conn_rtp *conn_src,
483 struct mgcp_conn_rtp *conn_dst, char *data, int len)
484{
485 struct rtp_hdr *rtp_hdr;
486 uint8_t pt_in;
487 int pt_out;
488
489 OSMO_ASSERT(len >= sizeof(struct rtp_hdr));
490 rtp_hdr = (struct rtp_hdr *)data;
491
492 pt_in = rtp_hdr->payload_type;
493 pt_out = mgcp_codec_pt_translate(conn_src, conn_dst, pt_in);
494 if (pt_out < 0)
495 return -EINVAL;
496
497 rtp_hdr->payload_type = (uint8_t) pt_out;
498 return 0;
499}
500
Philipp Maier87bd9be2017-08-22 16:35:41 +0200501/* The RFC 3550 Appendix A assumes there are multiple sources but
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200502 * some of the supported endpoints (e.g. the nanoBTS) can only handle
503 * one source and this code will patch RTP header to appear as if there
504 * is only one source.
505 * There is also no probation period for new sources. Every RTP header
Philipp Maier87bd9be2017-08-22 16:35:41 +0200506 * we receive will be seen as a switch in streams. */
507void mgcp_patch_and_count(struct mgcp_endpoint *endp,
508 struct mgcp_rtp_state *state,
509 struct mgcp_rtp_end *rtp_end,
510 struct sockaddr_in *addr, char *data, int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200511{
512 uint32_t arrival_time;
513 int32_t transit;
514 uint16_t seq;
515 uint32_t timestamp, ssrc;
516 struct rtp_hdr *rtp_hdr;
Philipp Maierbc0346e2018-06-07 09:52:16 +0200517 int payload = rtp_end->codec->payload_type;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200518
519 if (len < sizeof(*rtp_hdr))
520 return;
521
Philipp Maier87bd9be2017-08-22 16:35:41 +0200522 rtp_hdr = (struct rtp_hdr *)data;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200523 seq = ntohs(rtp_hdr->sequence);
524 timestamp = ntohl(rtp_hdr->timestamp);
Philipp Maierbc0346e2018-06-07 09:52:16 +0200525 arrival_time = get_current_ts(rtp_end->codec->rate);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200526 ssrc = ntohl(rtp_hdr->ssrc);
527 transit = arrival_time - timestamp;
528
529 mgcp_rtp_annex_count(endp, state, seq, transit, ssrc);
530
531 if (!state->initialized) {
532 state->initialized = 1;
533 state->in_stream.last_seq = seq - 1;
Harald Welte33381352017-12-25 09:44:26 +0100534 state->in_stream.ssrc = state->patch.orig_ssrc = ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200535 state->in_stream.last_tsdelta = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200536 state->packet_duration =
537 mgcp_rtp_packet_duration(endp, rtp_end);
Philipp Maier0ec1d4e2018-05-16 11:09:42 +0200538 state->out_stream.last_seq = seq - 1;
539 state->out_stream.ssrc = state->patch.orig_ssrc = ssrc;
540 state->out_stream.last_tsdelta = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200541 state->out_stream.last_timestamp = timestamp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200542 state->out_stream.ssrc = ssrc - 1; /* force output SSRC change */
Philipp Maierc3413882017-10-27 12:26:54 +0200543 LOGP(DRTP, LOGL_INFO,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100544 "endpoint:0x%x initializing stream, SSRC: %u timestamp: %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200545 "pkt-duration: %d, from %s:%d\n",
546 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100547 state->patch.seq_offset, state->packet_duration,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200548 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200549 if (state->packet_duration == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200550 state->packet_duration =
Philipp Maierbc0346e2018-06-07 09:52:16 +0200551 rtp_end->codec->rate * 20 / 1000;
Philipp Maierc3413882017-10-27 12:26:54 +0200552 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100553 "endpoint:0x%x fixed packet duration is not available, "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200554 "using fixed 20ms instead: %d from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200555 ENDPOINT_NUMBER(endp), state->packet_duration,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200556 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200557 }
558 } else if (state->in_stream.ssrc != ssrc) {
Philipp Maierc3413882017-10-27 12:26:54 +0200559 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100560 "endpoint:0x%x SSRC changed: %u -> %u "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200561 "from %s:%d\n",
562 ENDPOINT_NUMBER(endp),
563 state->in_stream.ssrc, rtp_hdr->ssrc,
564 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200565
566 state->in_stream.ssrc = ssrc;
567 if (rtp_end->force_constant_ssrc) {
568 int16_t delta_seq;
569
570 /* Always increment seqno by 1 */
Harald Welte33381352017-12-25 09:44:26 +0100571 state->patch.seq_offset =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200572 (state->out_stream.last_seq + 1) - seq;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200573
574 /* Estimate number of packets that would have been sent */
575 delta_seq =
Philipp Maier87bd9be2017-08-22 16:35:41 +0200576 (arrival_time - state->in_stream.last_arrival_time
577 + state->packet_duration / 2) /
578 state->packet_duration;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200579
580 adjust_rtp_timestamp_offset(endp, state, rtp_end, addr,
581 delta_seq, timestamp);
582
Harald Welte33381352017-12-25 09:44:26 +0100583 state->patch.patch_ssrc = 1;
584 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200585 if (rtp_end->force_constant_ssrc != -1)
586 rtp_end->force_constant_ssrc -= 1;
587
Philipp Maierc3413882017-10-27 12:26:54 +0200588 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100589 "endpoint:0x%x SSRC patching enabled, SSRC: %u "
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200590 "SeqNo offset: %d, TS offset: %d "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200591 "from %s:%d\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200592 ENDPOINT_NUMBER(endp), state->in_stream.ssrc,
Harald Welte33381352017-12-25 09:44:26 +0100593 state->patch.seq_offset, state->patch.timestamp_offset,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200594 inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200595 }
596
597 state->in_stream.last_tsdelta = 0;
598 } else {
599 /* Compute current per-packet timestamp delta */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200600 check_rtp_timestamp(endp, state, &state->in_stream, rtp_end,
601 addr, seq, timestamp, "input",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200602 &state->in_stream.last_tsdelta);
603
Harald Welte33381352017-12-25 09:44:26 +0100604 if (state->patch.patch_ssrc)
605 ssrc = state->patch.orig_ssrc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200606 }
607
608 /* Save before patching */
609 state->in_stream.last_timestamp = timestamp;
610 state->in_stream.last_seq = seq;
611 state->in_stream.last_arrival_time = arrival_time;
612
613 if (rtp_end->force_aligned_timing &&
614 state->out_stream.ssrc == ssrc && state->packet_duration)
615 /* Align the timestamp offset */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200616 align_rtp_timestamp_offset(endp, state, rtp_end, addr,
617 timestamp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200618
619 /* Store the updated SSRC back to the packet */
Harald Welte33381352017-12-25 09:44:26 +0100620 if (state->patch.patch_ssrc)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200621 rtp_hdr->ssrc = htonl(ssrc);
622
623 /* Apply the offset and store it back to the packet.
624 * This won't change anything if the offset is 0, so the conditional is
625 * omitted. */
Harald Welte33381352017-12-25 09:44:26 +0100626 seq += state->patch.seq_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200627 rtp_hdr->sequence = htons(seq);
Harald Welte33381352017-12-25 09:44:26 +0100628 timestamp += state->patch.timestamp_offset;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200629 rtp_hdr->timestamp = htonl(timestamp);
630
631 /* Check again, whether the timestamps are still valid */
632 if (state->out_stream.ssrc == ssrc)
633 check_rtp_timestamp(endp, state, &state->out_stream, rtp_end,
634 addr, seq, timestamp, "output",
635 &state->out_stream.last_tsdelta);
636
637 /* Save output values */
638 state->out_stream.last_seq = seq;
639 state->out_stream.last_timestamp = timestamp;
640 state->out_stream.ssrc = ssrc;
641
642 if (payload < 0)
643 return;
644
645#if 0
Philipp Maierc3413882017-10-27 12:26:54 +0200646 DEBUGP(DRTP,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100647 "endpoint:0x%x payload hdr payload %u -> endp payload %u\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200648 ENDPOINT_NUMBER(endp), rtp_hdr->payload_type, payload);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200649 rtp_hdr->payload_type = payload;
650#endif
651}
652
Philipp Maier87bd9be2017-08-22 16:35:41 +0200653/* Forward data to a debug tap. This is debug function that is intended for
654 * debugging the voice traffic with tools like gstreamer */
Philipp Maiere6f172d2017-11-07 12:00:01 +0100655static void forward_data(int fd, struct mgcp_rtp_tap *tap, const char *buf,
656 int len)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200657{
Philipp Maiere6f172d2017-11-07 12:00:01 +0100658 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200659
Philipp Maiere6f172d2017-11-07 12:00:01 +0100660 if (!tap->enabled)
661 return;
662
663 rc = sendto(fd, buf, len, 0, (struct sockaddr *)&tap->forward,
664 sizeof(tap->forward));
665
666 if (rc < 0)
667 LOGP(DRTP, LOGL_ERROR,
668 "Forwarding tapped (debug) voice data failed.\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200669}
670
Philipp Maier87bd9be2017-08-22 16:35:41 +0200671/*! Send RTP/RTCP data to a specified destination connection.
672 * \param[in] endp associated endpoint (for configuration, logging)
673 * \param[in] is_rtp flag to specify if the packet is of type RTP or RTCP
674 * \param[in] spoofed source address (set to NULL to disable)
675 * \param[in] buf buffer that contains the RTP/RTCP data
676 * \param[in] len length of the buffer that contains the RTP/RTCP data
677 * \param[in] conn_src associated source connection
678 * \param[in] conn_dst associated destination connection
679 * \returns 0 on success, -1 on ERROR */
680int mgcp_send(struct mgcp_endpoint *endp, int is_rtp, struct sockaddr_in *addr,
681 char *buf, int len, struct mgcp_conn_rtp *conn_src,
682 struct mgcp_conn_rtp *conn_dst)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200683{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200684 /*! When no destination connection is available (e.g. when only one
685 * connection in loopback mode exists), then the source connection
686 * shall be specified as destination connection */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200687
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200688 struct mgcp_trunk_config *tcfg = endp->tcfg;
689 struct mgcp_rtp_end *rtp_end;
690 struct mgcp_rtp_state *rtp_state;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200691 char *dest_name;
Philipp Maier6931f9a2018-07-26 09:29:31 +0200692 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200693
Philipp Maier87bd9be2017-08-22 16:35:41 +0200694 OSMO_ASSERT(conn_src);
695 OSMO_ASSERT(conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200696
Philipp Maier87bd9be2017-08-22 16:35:41 +0200697 if (is_rtp) {
Philipp Maierc3413882017-10-27 12:26:54 +0200698 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100699 "endpoint:0x%x delivering RTP packet...\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200700 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200701 } else {
Philipp Maierc3413882017-10-27 12:26:54 +0200702 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100703 "endpoint:0x%x delivering RTCP packet...\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200704 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200705 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200706
Philipp Maierc3413882017-10-27 12:26:54 +0200707 LOGP(DRTP, LOGL_DEBUG,
Neels Hofmeyr7066af82018-07-23 18:28:36 +0200708 "endpoint:0x%x loop:%d, mode:%d%s\n",
709 ENDPOINT_NUMBER(endp), tcfg->audio_loop, conn_src->conn->mode,
710 conn_src->conn->mode == MGCP_CONN_LOOPBACK ? " (loopback)" : "");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200711
Philipp Maier6931f9a2018-07-26 09:29:31 +0200712 /* FIXME: It is legal that the payload type on the egress connection is
713 * different from the payload type that has been negotiated on the
714 * ingress connection. Essentially the codecs are the same so we can
715 * match them and patch the payload type. However, if we can not find
716 * the codec pendant (everything ist equal except the PT), we are of
717 * course unable to patch the payload type. A situation like this
718 * should not occur if transcoding is consequently avoided. Until
719 * we have transcoding support in osmo-mgw we can not resolve this. */
720 rc = mgcp_patch_pt(conn_src, conn_dst, buf, len);
721 if (rc < 0) {
722 LOGP(DRTP, LOGL_ERROR,
723 "endpoint:0x%x can not patch PT because no suitable egress codec was found.\n",
724 ENDPOINT_NUMBER(endp));
725 }
726
Philipp Maier87bd9be2017-08-22 16:35:41 +0200727 /* Note: In case of loopback configuration, both, the source and the
728 * destination will point to the same connection. */
729 rtp_end = &conn_dst->end;
730 rtp_state = &conn_src->state;
731 dest_name = conn_dst->conn->name;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200732
733 if (!rtp_end->output_enabled) {
Philipp Maiercede2a42018-07-03 14:14:21 +0200734 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_DROPPED_PACKETS_CTR]);
Philipp Maierc3413882017-10-27 12:26:54 +0200735 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100736 "endpoint:0x%x output disabled, drop to %s %s "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200737 "rtp_port:%u rtcp_port:%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200738 ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200739 dest_name,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200740 inet_ntoa(rtp_end->addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200741 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200742 );
743 } else if (is_rtp) {
744 int cont;
745 int nbytes = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200746 int buflen = len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200747 do {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200748 /* Run transcoder */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200749 cont = endp->cfg->rtp_processing_cb(endp, rtp_end,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200750 buf, &buflen,
751 RTP_BUF_SIZE);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200752 if (cont < 0)
753 break;
754
Philipp Maier87bd9be2017-08-22 16:35:41 +0200755 if (addr)
756 mgcp_patch_and_count(endp, rtp_state, rtp_end,
757 addr, buf, buflen);
Philipp Maierc3413882017-10-27 12:26:54 +0200758 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100759 "endpoint:0x%x process/send to %s %s "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200760 "rtp_port:%u rtcp_port:%u\n",
761 ENDPOINT_NUMBER(endp), dest_name,
762 inet_ntoa(rtp_end->addr), ntohs(rtp_end->rtp_port),
763 ntohs(rtp_end->rtcp_port)
764 );
765
766 /* Forward a copy of the RTP data to a debug ip/port */
767 forward_data(rtp_end->rtp.fd, &conn_src->tap_out,
768 buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200769
770 /* FIXME: HACK HACK HACK. See OS#2459.
771 * The ip.access nano3G needs the first RTP payload's first two bytes to read hex
772 * 'e400', or it will reject the RAB assignment. It seems to not harm other femto
773 * cells (as long as we patch only the first RTP payload in each stream).
774 */
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200775 if (!rtp_state->patched_first_rtp_payload
776 && conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200777 uint8_t *data = (uint8_t *) & buf[12];
Neels Hofmeyr35a38292018-07-23 18:29:04 +0200778 if (data[0] == 0xe0) {
779 data[0] = 0xe4;
780 data[1] = 0x00;
781 rtp_state->patched_first_rtp_payload = true;
782 LOGP(DRTP, LOGL_DEBUG,
783 "endpoint:0x%x Patching over first two bytes"
784 " to fake an IuUP Initialization Ack\n",
785 ENDPOINT_NUMBER(endp));
786 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200787 }
788
Philipp Maier87bd9be2017-08-22 16:35:41 +0200789 len = mgcp_udp_send(rtp_end->rtp.fd,
790 &rtp_end->addr,
791 rtp_end->rtp_port, buf, buflen);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200792
Philipp Maier87bd9be2017-08-22 16:35:41 +0200793 if (len <= 0)
794 return len;
795
Philipp Maiercede2a42018-07-03 14:14:21 +0200796 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
797 rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200798
799 nbytes += len;
800 buflen = cont;
801 } while (buflen > 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200802 return nbytes;
803 } else if (!tcfg->omit_rtcp) {
Philipp Maierc3413882017-10-27 12:26:54 +0200804 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100805 "endpoint:0x%x send to %s %s rtp_port:%u rtcp_port:%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200806 ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200807 dest_name,
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200808 inet_ntoa(rtp_end->addr),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200809 ntohs(rtp_end->rtp_port), ntohs(rtp_end->rtcp_port)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200810 );
811
Philipp Maier87bd9be2017-08-22 16:35:41 +0200812 len = mgcp_udp_send(rtp_end->rtcp.fd,
813 &rtp_end->addr,
814 rtp_end->rtcp_port, buf, len);
815
Philipp Maiercede2a42018-07-03 14:14:21 +0200816 rate_ctr_inc(&conn_dst->rate_ctr_group->ctr[RTP_PACKETS_TX_CTR]);
817 rate_ctr_add(&conn_dst->rate_ctr_group->ctr[RTP_OCTETS_TX_CTR], len);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200818
819 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200820 }
821
822 return 0;
823}
824
Philipp Maier87bd9be2017-08-22 16:35:41 +0200825/* Helper function for mgcp_recv(),
826 Receive one RTP Packet + Originating address from file descriptor */
827static int receive_from(struct mgcp_endpoint *endp, int fd,
828 struct sockaddr_in *addr, char *buf, int bufsize)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200829{
830 int rc;
831 socklen_t slen = sizeof(*addr);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200832 struct sockaddr_in addr_sink;
833 char buf_sink[RTP_BUF_SIZE];
834 bool tossed = false;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200835
Philipp Maier87bd9be2017-08-22 16:35:41 +0200836 if (!addr)
837 addr = &addr_sink;
838 if (!buf) {
839 tossed = true;
840 buf = buf_sink;
841 bufsize = sizeof(buf_sink);
842 }
843
844 rc = recvfrom(fd, buf, bufsize, 0, (struct sockaddr *)addr, &slen);
845
Philipp Maierc3413882017-10-27 12:26:54 +0200846 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200847 "receiving %u bytes length packet from %s:%u ...\n",
848 rc, inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
849
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200850 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200851 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100852 "endpoint:0x%x failed to receive packet, errno: %d/%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200853 ENDPOINT_NUMBER(endp), errno, strerror(errno));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200854 return -1;
855 }
856
Philipp Maier87bd9be2017-08-22 16:35:41 +0200857 if (tossed) {
Philipp Maier230e4fc2017-11-28 09:38:45 +0100858 LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200859 ENDPOINT_NUMBER(endp));
860 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200861
862 return rc;
863}
864
Philipp Maier87bd9be2017-08-22 16:35:41 +0200865/* Check if the origin (addr) matches the address/port data of the RTP
866 * connections. */
867static int check_rtp_origin(struct mgcp_conn_rtp *conn,
868 struct sockaddr_in *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200869{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200870 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200871 endp = conn->conn->endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200872
Philipp Maier87bd9be2017-08-22 16:35:41 +0200873 /* Note: Check if the inbound RTP data comes from the same host to
874 * which we send our outgoing RTP traffic. */
875 if (memcmp(&addr->sin_addr, &conn->end.addr, sizeof(addr->sin_addr))
876 != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200877 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100878 "endpoint:0x%x data from wrong address: %s, ",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200879 ENDPOINT_NUMBER(endp), inet_ntoa(addr->sin_addr));
Philipp Maierc3413882017-10-27 12:26:54 +0200880 LOGPC(DRTP, LOGL_ERROR, "expected: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200881 inet_ntoa(conn->end.addr));
Philipp Maier230e4fc2017-11-28 09:38:45 +0100882 LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200883 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200884 return -1;
885 }
886
Philipp Maier87bd9be2017-08-22 16:35:41 +0200887 /* Note: Usually the remote remote port of the data we receive will be
888 * the same as the remote port where we transmit outgoing RTP traffic
889 * to (set by MDCX). We use this to check the origin of the data for
890 * plausibility. */
891 if (conn->end.rtp_port != addr->sin_port &&
892 conn->end.rtcp_port != addr->sin_port) {
Philipp Maierc3413882017-10-27 12:26:54 +0200893 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100894 "endpoint:0x%x data from wrong source port: %d, ",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200895 ENDPOINT_NUMBER(endp), ntohs(addr->sin_port));
Philipp Maierc3413882017-10-27 12:26:54 +0200896 LOGPC(DRTP, LOGL_ERROR,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200897 "expected: %d for RTP or %d for RTCP\n",
898 ntohs(conn->end.rtp_port), ntohs(conn->end.rtcp_port));
Philipp Maier230e4fc2017-11-28 09:38:45 +0100899 LOGP(DRTP, LOGL_ERROR, "endpoint:0x%x packet tossed\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200900 ENDPOINT_NUMBER(endp));
901 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200902 }
903
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200904 return 0;
905}
906
Philipp Maier87bd9be2017-08-22 16:35:41 +0200907/* Check the if the destination address configuration of an RTP connection
908 * makes sense */
909static int check_rtp_destin(struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200910{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200911 struct mgcp_endpoint *endp;
912 endp = conn->conn->endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200913
Philipp Maiere6df0e42018-05-29 14:03:06 +0200914 /* Note: it is legal to create a connection but never setting a port
915 * and IP-address for outgoing data. */
916 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0 && conn->end.rtp_port == 0) {
917 LOGP(DRTP, LOGL_DEBUG,
918 "endpoint:0x%x destination IP-address and rtp port is (not yet) known\n",
919 ENDPOINT_NUMBER(endp));
920 return -1;
921 }
922
Philipp Maier87bd9be2017-08-22 16:35:41 +0200923 if (strcmp(inet_ntoa(conn->end.addr), "0.0.0.0") == 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200924 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100925 "endpoint:0x%x destination IP-address is invalid\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200926 ENDPOINT_NUMBER(endp));
927 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200928 }
Philipp Maier87bd9be2017-08-22 16:35:41 +0200929
930 if (conn->end.rtp_port == 0) {
Philipp Maierc3413882017-10-27 12:26:54 +0200931 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100932 "endpoint:0x%x destination rtp port is invalid\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200933 ENDPOINT_NUMBER(endp));
934 return -1;
935 }
936
937 return 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200938}
939
Philipp Maier87bd9be2017-08-22 16:35:41 +0200940/* Receive RTP data from a specified source connection and dispatch it to a
941 * destination connection. */
942static int mgcp_recv(int *proto, struct sockaddr_in *addr, char *buf,
943 unsigned int buf_size, struct osmo_fd *fd)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200944{
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200945 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200946 struct mgcp_conn_rtp *conn;
947 struct mgcp_trunk_config *tcfg;
948 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200949
Philipp Maier87bd9be2017-08-22 16:35:41 +0200950 conn = (struct mgcp_conn_rtp*) fd->data;
951 endp = conn->conn->endp;
952 tcfg = endp->tcfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200953
Philipp Maier230e4fc2017-11-28 09:38:45 +0100954 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x receiving RTP/RTCP packet...\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200955 ENDPOINT_NUMBER(endp));
956
957 rc = receive_from(endp, fd->fd, addr, buf, buf_size);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200958 if (rc <= 0)
959 return -1;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200960 *proto = fd == &conn->end.rtp ? MGCP_PROTO_RTP : MGCP_PROTO_RTCP;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200961
Philipp Maier230e4fc2017-11-28 09:38:45 +0100962 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x ", ENDPOINT_NUMBER(endp));
Neels Hofmeyr56725632018-01-15 15:15:07 +0100963 LOGPC(DRTP, LOGL_DEBUG, "receiving from %s %s %d\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200964 conn->conn->name, inet_ntoa(addr->sin_addr),
965 ntohs(addr->sin_port));
Philipp Maier230e4fc2017-11-28 09:38:45 +0100966 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x conn:%s\n", ENDPOINT_NUMBER(endp),
Philipp Maier87bd9be2017-08-22 16:35:41 +0200967 mgcp_conn_dump(conn->conn));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200968
Philipp Maier87bd9be2017-08-22 16:35:41 +0200969 /* Check if the origin of the RTP packet seems plausible */
970 if (tcfg->rtp_accept_all == 0) {
971 if (check_rtp_origin(conn, addr) != 0)
972 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200973 }
974
Philipp Maier87bd9be2017-08-22 16:35:41 +0200975 /* Filter out dummy message */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200976 if (rc == 1 && buf[0] == MGCP_DUMMY_LOAD) {
Philipp Maierc3413882017-10-27 12:26:54 +0200977 LOGP(DRTP, LOGL_NOTICE,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100978 "endpoint:0x%x dummy message received\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +0200979 ENDPOINT_NUMBER(endp));
Philipp Maierc3413882017-10-27 12:26:54 +0200980 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +0100981 "endpoint:0x%x packet tossed\n", ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200982 return 0;
983 }
984
Philipp Maier87bd9be2017-08-22 16:35:41 +0200985 /* Increment RX statistics */
Philipp Maiercede2a42018-07-03 14:14:21 +0200986 rate_ctr_inc(&conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR]);
987 rate_ctr_add(&conn->rate_ctr_group->ctr[RTP_OCTETS_RX_CTR], rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200988
Philipp Maier87bd9be2017-08-22 16:35:41 +0200989 /* Forward a copy of the RTP data to a debug ip/port */
990 forward_data(fd->fd, &conn->tap_in, buf, rc);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200991
Philipp Maier87bd9be2017-08-22 16:35:41 +0200992 return rc;
993}
994
995/* Send RTP data. Possible options are standard RTP packet
996 * transmission or trsmission via an osmux connection */
997static int mgcp_send_rtp(int proto, struct sockaddr_in *addr, char *buf,
998 unsigned int buf_size,
999 struct mgcp_conn_rtp *conn_src,
1000 struct mgcp_conn_rtp *conn_dst)
1001{
1002 struct mgcp_endpoint *endp;
1003 endp = conn_src->conn->endp;
1004
Philipp Maier230e4fc2017-11-28 09:38:45 +01001005 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x destin conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001006 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_dst->conn));
1007
1008 /* Before we try to deliver the packet, we check if the destination
1009 * port and IP-Address make sense at all. If not, we will be unable
1010 * to deliver the packet. */
1011 if (check_rtp_destin(conn_dst) != 0)
1012 return -1;
1013
1014 /* Depending on the RTP connection type, deliver the RTP packet to the
1015 * destination connection. */
1016 switch (conn_dst->type) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001017 case MGCP_RTP_DEFAULT:
Philipp Maierc3413882017-10-27 12:26:54 +02001018 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001019 "endpoint:0x%x endpoint type is MGCP_RTP_DEFAULT, "
Philipp Maier87bd9be2017-08-22 16:35:41 +02001020 "using mgcp_send() to forward data directly\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001021 ENDPOINT_NUMBER(endp));
Philipp Maier87bd9be2017-08-22 16:35:41 +02001022 return mgcp_send(endp, proto == MGCP_PROTO_RTP,
1023 addr, buf, buf_size, conn_src, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001024 case MGCP_OSMUX_BSC_NAT:
Philipp Maier87bd9be2017-08-22 16:35:41 +02001025 case MGCP_OSMUX_BSC:
Philipp Maierc3413882017-10-27 12:26:54 +02001026 LOGP(DRTP, LOGL_DEBUG,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001027 "endpoint:0x%x endpoint type is MGCP_OSMUX_BSC_NAT, "
Philipp Maier87bd9be2017-08-22 16:35:41 +02001028 "using osmux_xfrm_to_osmux() to forward data through OSMUX\n",
1029 ENDPOINT_NUMBER(endp));
1030 return osmux_xfrm_to_osmux(buf, buf_size, conn_dst);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001031 }
1032
Philipp Maier87bd9be2017-08-22 16:35:41 +02001033 /* If the data has not been handled/forwarded until here, it will
1034 * be discarded, this should not happen, normally the MGCP type
1035 * should be properly set */
Philipp Maierc3413882017-10-27 12:26:54 +02001036 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001037 "endpoint:0x%x bad MGCP type -- data discarded!\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001038 ENDPOINT_NUMBER(endp));
1039
1040 return -1;
1041}
1042
1043/*! dispatch incoming RTP packet to opposite RTP connection.
1044 * \param[in] proto protocol (MGCP_CONN_TYPE_RTP or MGCP_CONN_TYPE_RTCP)
1045 * \param[in] addr socket address where the RTP packet has been received from
1046 * \param[in] buf buffer that hold the RTP payload
1047 * \param[in] buf_size size data length of buf
1048 * \param[in] conn originating connection
1049 * \returns 0 on success, -1 on ERROR */
1050int mgcp_dispatch_rtp_bridge_cb(int proto, struct sockaddr_in *addr, char *buf,
1051 unsigned int buf_size, struct mgcp_conn *conn)
1052{
1053 struct mgcp_conn *conn_dst;
1054 struct mgcp_endpoint *endp;
1055 endp = conn->endp;
1056
1057 /*! NOTE: This callback function implements the endpoint specific
1058 * dispatch bahviour of an rtp bridge/proxy endpoint. It is assumed
1059 * that the endpoint will hold only two connections. This premise
1060 * is used to determine the opposite connection (it is always the
1061 * connection that is not the originating connection). Once the
1062 * destination connection is known the RTP packet is sent via
1063 * the destination connection. */
1064
1065 /* Find a destination connection. */
1066 /* NOTE: This code path runs every time an RTP packet is received. The
1067 * function mgcp_find_dst_conn() we use to determine the detination
1068 * connection will iterate the connection list inside the endpoint.
1069 * Since list iterations are quite costly, we will figure out the
1070 * destination only once and use the optional private data pointer of
1071 * the connection to cache the destination connection pointer. */
1072 if (!conn->priv) {
1073 conn_dst = mgcp_find_dst_conn(conn);
1074 conn->priv = conn_dst;
1075 } else {
1076 conn_dst = (struct mgcp_conn *)conn->priv;
1077 }
1078
1079 /* There is no destination conn, stop here */
1080 if (!conn_dst) {
Philipp Maierc3413882017-10-27 12:26:54 +02001081 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001082 "endpoint:0x%x unable to find destination conn\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001083 ENDPOINT_NUMBER(endp));
1084 return -1;
1085 }
1086
1087 /* The destination conn is not an RTP connection */
1088 if (conn_dst->type != MGCP_CONN_TYPE_RTP) {
Philipp Maierc3413882017-10-27 12:26:54 +02001089 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001090 "endpoint:0x%x unable to find suitable destination conn\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001091 ENDPOINT_NUMBER(endp));
1092 return -1;
1093 }
1094
1095 /* Dispatch RTP packet to destination RTP connection */
1096 return mgcp_send_rtp(proto, addr, buf,
1097 buf_size, &conn->u.rtp, &conn_dst->u.rtp);
1098
1099}
1100
Philipp Maierdf5d2192018-01-24 11:39:32 +01001101/*! cleanup an endpoint when a connection on an RTP bridge endpoint is removed.
1102 * \param[in] endp Endpoint on which the connection resides.
1103 * \param[in] conn Connection that is about to be removed (ignored).
1104 * \returns 0 on success, -1 on ERROR. */
1105void mgcp_cleanup_rtp_bridge_cb(struct mgcp_endpoint *endp, struct mgcp_conn *conn)
1106{
1107 struct mgcp_conn *conn_cleanup;
1108
1109 /* In mgcp_dispatch_rtp_bridge_cb() we use conn->priv to cache the
1110 * pointer to the destination connection, so that we do not have
1111 * to go through the list every time an RTP packet arrives. To prevent
1112 * a use-after-free situation we invalidate this information for all
1113 * connections present when one connection is removed from the
1114 * endpoint. */
1115 llist_for_each_entry(conn_cleanup, &endp->conns, entry) {
1116 conn_cleanup->priv = NULL;
1117 }
1118}
1119
Philipp Maier87bd9be2017-08-22 16:35:41 +02001120/* Handle incoming RTP data from NET */
1121static int rtp_data_net(struct osmo_fd *fd, unsigned int what)
1122{
1123 /* NOTE: This is a generic implementation. RTP data is received. In
1124 * case of loopback the data is just sent back to its origin. All
1125 * other cases implement endpoint specific behaviour (e.g. how is the
1126 * destination connection determined?). That specific behaviour is
1127 * implemented by the callback function that is called at the end of
1128 * the function */
1129
1130 struct mgcp_conn_rtp *conn_src;
1131 struct mgcp_endpoint *endp;
1132 struct sockaddr_in addr;
1133
1134 char buf[RTP_BUF_SIZE];
1135 int proto;
Philipp Maierb9694552017-11-08 16:53:57 +01001136 int len;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001137
1138 conn_src = (struct mgcp_conn_rtp *)fd->data;
1139 OSMO_ASSERT(conn_src);
1140 endp = conn_src->conn->endp;
1141 OSMO_ASSERT(endp);
1142
Philipp Maier230e4fc2017-11-28 09:38:45 +01001143 LOGP(DRTP, LOGL_DEBUG, "endpoint:0x%x source conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001144 ENDPOINT_NUMBER(endp), mgcp_conn_dump(conn_src->conn));
1145
1146 /* Receive packet */
Philipp Maierb9694552017-11-08 16:53:57 +01001147 len = mgcp_recv(&proto, &addr, buf, sizeof(buf), fd);
1148 if (len < 0)
Philipp Maier87bd9be2017-08-22 16:35:41 +02001149 return -1;
1150
1151 /* Check if the connection is in loopback mode, if yes, just send the
1152 * incoming data back to the origin */
Philipp Maier5dbfc782017-12-12 16:20:25 +01001153
Philipp Maier87bd9be2017-08-22 16:35:41 +02001154 if (conn_src->conn->mode == MGCP_CONN_LOOPBACK) {
Philipp Maier5dbfc782017-12-12 16:20:25 +01001155 /* When we are in loopback mode, we loop back all incoming
1156 * packets back to their origin. We will use the originating
1157 * address data from the UDP packet header to patch the
1158 * outgoing address in connection on the fly */
1159 if (conn_src->end.rtp_port == 0) {
1160 conn_src->end.addr = addr.sin_addr;
1161 conn_src->end.rtp_port = addr.sin_port;
1162 }
Philipp Maier87bd9be2017-08-22 16:35:41 +02001163 return mgcp_send_rtp(proto, &addr, buf,
Philipp Maierb9694552017-11-08 16:53:57 +01001164 len, conn_src, conn_src);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001165 }
1166
1167 /* Execute endpoint specific implementation that handles the
1168 * dispatching of the RTP data */
Philipp Maierb9694552017-11-08 16:53:57 +01001169 return endp->type->dispatch_rtp_cb(proto, &addr, buf, len,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001170 conn_src->conn);
1171}
1172
1173/*! set IP Type of Service parameter.
1174 * \param[in] fd associated file descriptor
1175 * \param[in] tos dscp value
1176 * \returns 0 on success, -1 on ERROR */
1177int mgcp_set_ip_tos(int fd, int tos)
1178{
1179 int ret;
1180 ret = setsockopt(fd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
1181
1182 if (ret < 0)
1183 return -1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001184 return 0;
1185}
1186
Philipp Maier87bd9be2017-08-22 16:35:41 +02001187/*! bind RTP port to osmo_fd.
1188 * \param[in] source_addr source (local) address to bind on
1189 * \param[in] fd associated file descriptor
1190 * \param[in] port to bind on
1191 * \returns 0 on success, -1 on ERROR */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001192int mgcp_create_bind(const char *source_addr, struct osmo_fd *fd, int port)
1193{
Harald Welte8890dfa2017-11-17 15:09:30 +01001194 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001195
Harald Welte8890dfa2017-11-17 15:09:30 +01001196 rc = osmo_sock_init2(AF_INET, SOCK_DGRAM, IPPROTO_UDP, source_addr, port,
1197 NULL, 0, OSMO_SOCK_F_BIND);
1198 if (rc < 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001199 LOGP(DRTP, LOGL_ERROR, "failed to bind UDP port (%s:%i).\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001200 source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001201 return -1;
1202 }
Harald Welte8890dfa2017-11-17 15:09:30 +01001203 fd->fd = rc;
1204 LOGP(DRTP, LOGL_DEBUG, "created socket + bound UDP port (%s:%i).\n", source_addr, port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001205
1206 return 0;
1207}
1208
Philipp Maier87bd9be2017-08-22 16:35:41 +02001209/* Bind RTP and RTCP port (helper function for mgcp_bind_net_rtp_port()) */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001210static int bind_rtp(struct mgcp_config *cfg, const char *source_addr,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001211 struct mgcp_rtp_end *rtp_end, int endpno)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001212{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001213 /* NOTE: The port that is used for RTCP is the RTP port incremented by one
1214 * (e.g. RTP-Port = 16000 ==> RTCP-Port = 16001) */
1215
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001216 if (mgcp_create_bind(source_addr, &rtp_end->rtp,
1217 rtp_end->local_port) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001218 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001219 "endpoint:0x%x failed to create RTP port: %s:%d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001220 source_addr, rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001221 goto cleanup0;
1222 }
1223
1224 if (mgcp_create_bind(source_addr, &rtp_end->rtcp,
1225 rtp_end->local_port + 1) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001226 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001227 "endpoint:0x%x failed to create RTCP port: %s:%d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001228 source_addr, rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001229 goto cleanup1;
1230 }
1231
Philipp Maier87bd9be2017-08-22 16:35:41 +02001232 /* Set Type of Service (DSCP-Value) as configured via VTY */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001233 mgcp_set_ip_tos(rtp_end->rtp.fd, cfg->endp_dscp);
1234 mgcp_set_ip_tos(rtp_end->rtcp.fd, cfg->endp_dscp);
1235
1236 rtp_end->rtp.when = BSC_FD_READ;
1237 if (osmo_fd_register(&rtp_end->rtp) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001238 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001239 "endpoint:0x%x failed to register RTP port %d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001240 rtp_end->local_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001241 goto cleanup2;
1242 }
1243
1244 rtp_end->rtcp.when = BSC_FD_READ;
1245 if (osmo_fd_register(&rtp_end->rtcp) != 0) {
Philipp Maierc3413882017-10-27 12:26:54 +02001246 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001247 "endpoint:0x%x failed to register RTCP port %d\n", endpno,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001248 rtp_end->local_port + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001249 goto cleanup3;
1250 }
1251
1252 return 0;
1253
1254cleanup3:
1255 osmo_fd_unregister(&rtp_end->rtp);
1256cleanup2:
1257 close(rtp_end->rtcp.fd);
1258 rtp_end->rtcp.fd = -1;
1259cleanup1:
1260 close(rtp_end->rtp.fd);
1261 rtp_end->rtp.fd = -1;
1262cleanup0:
1263 return -1;
1264}
1265
Philipp Maier87bd9be2017-08-22 16:35:41 +02001266/*! bind RTP port to endpoint/connection.
1267 * \param[in] endp endpoint that holds the RTP connection
1268 * \param[in] rtp_port port number to bind on
1269 * \param[in] conn associated RTP connection
1270 * \returns 0 on success, -1 on ERROR */
1271int mgcp_bind_net_rtp_port(struct mgcp_endpoint *endp, int rtp_port,
1272 struct mgcp_conn_rtp *conn)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001273{
Philipp Maier87bd9be2017-08-22 16:35:41 +02001274 char name[512];
1275 struct mgcp_rtp_end *end;
Philipp Maier1cb1e382017-11-02 17:16:04 +01001276 char local_ip_addr[INET_ADDRSTRLEN];
Philipp Maier87bd9be2017-08-22 16:35:41 +02001277
Philipp Maier01d24a32017-11-21 17:26:09 +01001278 snprintf(name, sizeof(name), "%s-%s", conn->conn->name, conn->conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001279 end = &conn->end;
1280
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001281 if (end->rtp.fd != -1 || end->rtcp.fd != -1) {
Philipp Maierc3413882017-10-27 12:26:54 +02001282 LOGP(DRTP, LOGL_ERROR,
Philipp Maier230e4fc2017-11-28 09:38:45 +01001283 "endpoint:0x%x %u was already bound on conn:%s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001284 ENDPOINT_NUMBER(endp), rtp_port,
1285 mgcp_conn_dump(conn->conn));
1286
1287 /* Double bindings should never occour! Since we always allocate
1288 * connections dynamically and free them when they are not
1289 * needed anymore, there must be no previous binding leftover.
1290 * Should there be a connection bound twice, we have a serious
1291 * problem and must exit immediately! */
1292 OSMO_ASSERT(false);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001293 }
1294
1295 end->local_port = rtp_port;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001296 end->rtp.cb = rtp_data_net;
1297 end->rtp.data = conn;
1298 end->rtcp.data = conn;
1299 end->rtcp.cb = rtp_data_net;
1300
Philipp Maier1cb1e382017-11-02 17:16:04 +01001301 mgcp_get_local_addr(local_ip_addr, conn);
1302
1303 return bind_rtp(endp->cfg, local_ip_addr, end,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001304 ENDPOINT_NUMBER(endp));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001305}
1306
Philipp Maier87bd9be2017-08-22 16:35:41 +02001307/*! free allocated RTP and RTCP ports.
1308 * \param[in] end RTP end */
1309void mgcp_free_rtp_port(struct mgcp_rtp_end *end)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001310{
1311 if (end->rtp.fd != -1) {
1312 close(end->rtp.fd);
1313 end->rtp.fd = -1;
1314 osmo_fd_unregister(&end->rtp);
1315 }
1316
1317 if (end->rtcp.fd != -1) {
1318 close(end->rtcp.fd);
1319 end->rtcp.fd = -1;
1320 osmo_fd_unregister(&end->rtcp);
1321 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001322}