blob: 5bb7b2734dc3bdc929199073da8c71621093dbaf [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001/*
2 * (C) 2011-2012,2014 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * (C) 2011-2012,2014 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#undef _GNU_SOURCE
20#define _GNU_SOURCE
21
Philipp Maier87bd9be2017-08-22 16:35:41 +020022#include <osmocom/mgcp/mgcp.h>
23#include <osmocom/mgcp/vty.h>
Neels Hofmeyr67793542017-09-08 04:25:16 +020024#include <osmocom/mgcp/mgcp_common.h>
Philipp Maier993ea6b2020-08-04 18:26:50 +020025#include <osmocom/mgcp/mgcp_conn.h>
26#include <osmocom/mgcp/mgcp_protocol.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020027#include <osmocom/mgcp/mgcp_stat.h>
28#include <osmocom/mgcp/mgcp_msg.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010029#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020030#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maierbc0346e2018-06-07 09:52:16 +020031#include <osmocom/mgcp/mgcp_sdp.h>
32#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maierb3d14eb2021-05-20 14:18:52 +020033#include <osmocom/mgcp/mgcp_network.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020034
35#include <osmocom/core/application.h>
36#include <osmocom/core/talloc.h>
37#include <osmocom/core/utils.h>
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +020038#include <osmocom/core/socket.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020039#include <string.h>
40#include <limits.h>
41#include <dlfcn.h>
42#include <time.h>
43#include <math.h>
Neels Hofmeyrb861db92018-08-28 16:19:25 +020044#include <ctype.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020045
46char *strline_r(char *str, char **saveptr);
47
48const char *strline_test_data =
49 "one CR\r"
50 "two CR\r"
51 "\r"
52 "one CRLF\r\n"
53 "two CRLF\r\n"
Philipp Maier87bd9be2017-08-22 16:35:41 +020054 "\r\n" "one LF\n" "two LF\n" "\n" "mixed (4 lines)\r\r\n\n\r\n";
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020055
56#define EXPECTED_NUMBER_OF_LINES 13
57
58static void test_strline(void)
59{
60 char *save = NULL;
61 char *line;
62 char buf[2048];
63 int counter = 0;
64
65 osmo_strlcpy(buf, strline_test_data, sizeof(buf));
66
Philipp Maier87bd9be2017-08-22 16:35:41 +020067 for (line = mgcp_strline(buf, &save); line;
68 line = mgcp_strline(NULL, &save)) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020069 printf("line: '%s'\n", line);
70 counter++;
71 }
72
73 OSMO_ASSERT(counter == EXPECTED_NUMBER_OF_LINES);
74}
75
Philipp Maier12943ea2018-01-17 15:40:25 +010076#define AUEP1 "AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
Philipp Maierc66ab2c2020-06-02 20:55:34 +020077#define AUEP1_RET "500 158663169 FAIL\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010078#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020079#define AUEP2_RET "500 18983213 FAIL\r\n"
80#define EMPTY "\r\n"
81#define EMPTY_RET NULL
82#define SHORT "CRCX \r\n"
83#define SHORT_RET "510 000000 FAIL\r\n"
84
Philipp Maier12943ea2018-01-17 15:40:25 +010085#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
Harald Welteabbb6b92017-12-28 13:13:50 +010086#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010087#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
Philipp Maierc66ab2c2020-06-02 20:55:34 +020088#define MDCX_RET "500 18983214 FAIL\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020089
Philipp Maier87bd9be2017-08-22 16:35:41 +020090#define MDCX3 \
91 "MDCX 18983215 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010092 "I: %s\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020093
Philipp Maier87bd9be2017-08-22 16:35:41 +020094#define MDCX3_RET \
95 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +010096 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020097 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010098 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020099 "s=-\r\n" \
100 "c=IN IP4 0.0.0.0\r\n" \
101 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100102 "m=audio 16002 RTP/AVP 97\r\n" \
103 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200104 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200105
Philipp Maier87bd9be2017-08-22 16:35:41 +0200106#define MDCX3A_RET \
107 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100108 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200109 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100110 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200111 "s=-\r\n" \
112 "c=IN IP4 0.0.0.0\r\n" \
113 "t=0 0\r\n" \
114 "m=audio 16002 RTP/AVP 97\r\n" \
115 "a=rtpmap:97 GSM-EFR/8000\r\n" \
116 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200117
Philipp Maier87bd9be2017-08-22 16:35:41 +0200118#define MDCX3_FMTP_RET \
119 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100120 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200121 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100122 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200123 "s=-\r\n" \
124 "c=IN IP4 0.0.0.0\r\n" \
125 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100126 "m=audio 16006 RTP/AVP 97\r\n" \
127 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200128 "a=fmtp:126 0/1/2\r\n" \
129 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200130
Philipp Maier87bd9be2017-08-22 16:35:41 +0200131#define MDCX4 \
132 "MDCX 18983216 1@mgw MGCP 1.0\r\n" \
133 "M: sendrecv\r" \
134 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100135 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200136 "L: p:20, a:AMR, nt:IN\r\n" \
137 "\n" \
138 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100139 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200140 "c=IN IP4 0.0.0.0\r\n" \
141 "t=0 0\r\n" \
142 "m=audio 4441 RTP/AVP 99\r\n" \
143 "a=rtpmap:99 AMR/8000\r\n" \
144 "a=ptime:40\r\n"
145
146#define MDCX4_RET(Ident) \
147 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100148 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200149 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100150 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200151 "s=-\r\n" \
152 "c=IN IP4 0.0.0.0\r\n" \
153 "t=0 0\r\n" \
154 "m=audio 16002 RTP/AVP 99\r\n" \
155 "a=rtpmap:99 AMR/8000\r\n" \
156 "a=ptime:40\r\n"
157
158#define MDCX4_RO_RET(Ident) \
159 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100160 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200161 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100162 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200163 "s=-\r\n" \
164 "c=IN IP4 0.0.0.0\r\n" \
165 "t=0 0\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200166 "m=audio 16002 RTP/AVP 112\r\n" \
167 "a=rtpmap:112 AMR\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200168 "a=ptime:40\r\n"
169
170#define MDCX4_PT1 \
171 "MDCX 18983217 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol17058482019-06-26 12:23:02 +0200172 "M: SENDRECV\r" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200173 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100174 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200175 "L: p:20-40, a:AMR, nt:IN\r\n" \
176 "\n" \
177 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100178 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200179 "c=IN IP4 0.0.0.0\r\n" \
180 "t=0 0\r\n" \
181 "m=audio 4441 RTP/AVP 99\r\n" \
182 "a=rtpmap:99 AMR/8000\r\n" \
183 "a=ptime:40\r\n"
184
185#define MDCX4_PT2 \
186 "MDCX 18983218 1@mgw MGCP 1.0\r\n" \
187 "M: sendrecv\r" \
188 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100189 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200190 "L: p:20-20, a:AMR, nt:IN\r\n" \
191 "\n" \
192 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100193 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200194 "c=IN IP4 0.0.0.0\r\n" \
195 "t=0 0\r\n" \
196 "m=audio 4441 RTP/AVP 99\r\n" \
197 "a=rtpmap:99 AMR/8000\r\n" \
198 "a=ptime:40\r\n"
199
200#define MDCX4_PT3 \
201 "MDCX 18983219 1@mgw MGCP 1.0\r\n" \
202 "M: sendrecv\r" \
203 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100204 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200205 "L: a:AMR, nt:IN\r\n" \
206 "\n" \
207 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100208 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200209 "c=IN IP4 0.0.0.0\r\n" \
210 "t=0 0\r\n" \
211 "m=audio 4441 RTP/AVP 99\r\n" \
212 "a=rtpmap:99 AMR/8000\r\n" \
213 "a=ptime:40\r\n"
214
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200215/* Test different upper/lower case in options */
216#define MDCX4_PT4 \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200217 "MDCX 18983220 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200218 "m: sendrecv\r" \
219 "c: 2\r\n" \
220 "i: %s\r\n" \
Pau Espin Pedrol83fd8a52019-06-26 12:55:26 +0200221 "l: A:amr, NT:IN\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200222 "\n" \
223 "v=0\r\n" \
224 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
225 "c=IN IP4 0.0.0.0\r\n" \
226 "t=0 0\r\n" \
227 "m=audio 4441 RTP/AVP 99\r\n" \
228 "a=rtpmap:99 AMR/8000\r\n" \
229 "a=ptime:40\r\n"
230
231#define MDCX4_SO \
232 "MDCX 18983221 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200233 "M: sendonly\r" \
234 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100235 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200236 "L: p:20, a:AMR, nt:IN\r\n" \
237 "\n" \
238 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100239 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200240 "c=IN IP4 0.0.0.0\r\n" \
241 "t=0 0\r\n" \
242 "m=audio 4441 RTP/AVP 99\r\n" \
243 "a=rtpmap:99 AMR/8000\r\n" \
244 "a=ptime:40\r\n"
245
246#define MDCX4_RO \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200247 "MDCX 18983222 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200248 "M: recvonly\r" \
249 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100250 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200251 "L: p:20, a:AMR, nt:IN\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200252
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200253#define MDCX_TOO_LONG_CI \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200254 "MDCX 18983223 1@mgw MGCP 1.0\r\n" \
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200255 "I: 123456789012345678901234567890123\n"
256
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200257#define MDCX_TOO_LONG_CI_RET "510 18983223 FAIL\r\n"
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200258
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200259#define SHORT2 "CRCX 1"
260#define SHORT2_RET "510 000000 FAIL\r\n"
261#define SHORT3 "CRCX 1 1@mgw"
262#define SHORT4 "CRCX 1 1@mgw MGCP"
263#define SHORT5 "CRCX 1 1@mgw MGCP 1.0"
264
Philipp Maier87bd9be2017-08-22 16:35:41 +0200265#define CRCX \
266 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200267 "m: recvonly\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200268 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200269 "L: p:20\r\n" \
270 "\r\n" \
271 "v=0\r\n" \
272 "c=IN IP4 123.12.12.123\r\n" \
273 "m=audio 5904 RTP/AVP 97\r\n" \
274 "a=rtpmap:97 GSM-EFR/8000\r\n" \
275 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200276
Philipp Maier87bd9be2017-08-22 16:35:41 +0200277#define CRCX_RET \
278 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100279 "I: %s\r\n" \
280 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200281 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100282 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200283 "s=-\r\n" \
284 "c=IN IP4 0.0.0.0\r\n" \
285 "t=0 0\r\n" \
286 "m=audio 16002 RTP/AVP 97\r\n" \
287 "a=rtpmap:97 GSM-EFR/8000\r\n" \
288 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200289
Philipp Maier87bd9be2017-08-22 16:35:41 +0200290#define CRCX_RET_NO_RTPMAP \
291 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100292 "I: %s\r\n" \
293 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200294 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100295 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200296 "s=-\r\n" \
297 "c=IN IP4 0.0.0.0\r\n" \
298 "t=0 0\r\n" \
299 "m=audio 16002 RTP/AVP 97\r\n" \
300 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200301
Philipp Maier87bd9be2017-08-22 16:35:41 +0200302#define CRCX_FMTP_RET \
303 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100304 "I: %s\r\n" \
305 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200306 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100307 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200308 "s=-\r\n" \
309 "c=IN IP4 0.0.0.0\r\n" \
310 "t=0 0\r\n" \
311 "m=audio 16006 RTP/AVP 97\r\n" \
312 "a=rtpmap:97 GSM-EFR/8000\r\n" \
313 "a=fmtp:126 0/1/2\r\n" \
314 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200315
Philipp Maier87bd9be2017-08-22 16:35:41 +0200316#define CRCX_ZYN \
317 "CRCX 2 1@mgw MGCP 1.0\r" \
318 "M: recvonly\r" \
319 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200320 "\n" \
321 "v=0\r" \
322 "c=IN IP4 123.12.12.123\r" \
323 "m=audio 5904 RTP/AVP 97\r" \
324 "a=rtpmap:97 GSM-EFR/8000\r"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200325
Philipp Maier87bd9be2017-08-22 16:35:41 +0200326#define CRCX_ZYN_RET \
327 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100328 "I: %s\r\n" \
329 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200330 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100331 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200332 "s=-\r\n" \
333 "c=IN IP4 0.0.0.0\r\n" \
334 "t=0 0\r\n" \
335 "m=audio 16004 RTP/AVP 97\r\n" \
336 "a=rtpmap:97 GSM-EFR/8000\r\n" \
337 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200338
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200339#define CRCX_X_OSMO_IGN \
340 "CRCX 2 1@mgw MGCP 1.0\r\n" \
341 "M: recvonly\r\n" \
342 "C: 2\r\n" \
343 "L: p:20\r\n" \
Neels Hofmeyrf2388ea2018-08-26 23:36:53 +0200344 "X-Osmo-IGN: C foo\r\n" \
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200345 "\r\n" \
346 "v=0\r\n" \
347 "c=IN IP4 123.12.12.123\r\n" \
348 "m=audio 5904 RTP/AVP 97\r\n" \
349 "a=rtpmap:97 GSM-EFR/8000\r\n" \
350 "a=ptime:40\r\n"
351
352#define CRCX_X_OSMO_IGN_RET \
353 "200 2 OK\r\n" \
354 "I: %s\r\n" \
355 "\r\n" \
356 "v=0\r\n" \
357 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
358 "s=-\r\n" \
359 "c=IN IP4 0.0.0.0\r\n" \
360 "t=0 0\r\n" \
361 "m=audio 16010 RTP/AVP 97\r\n" \
362 "a=rtpmap:97 GSM-EFR/8000\r\n" \
363 "a=ptime:40\r\n"
364
Philipp Maier87bd9be2017-08-22 16:35:41 +0200365#define DLCX \
366 "DLCX 7 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100367 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200368 "C: 2\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200369
Philipp Maier87bd9be2017-08-22 16:35:41 +0200370#define DLCX_RET \
371 "250 7 OK\r\n" \
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100372 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
373
374 #define DLCX_RET_OSMUX DLCX_RET \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200375 "X-Osmo-CP: EC TI=0, TO=0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200376
Philipp Maier87bd9be2017-08-22 16:35:41 +0200377#define RQNT \
378 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
379 "X: B244F267488\r\n" \
380 "S: D/9\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200381
Philipp Maier87bd9be2017-08-22 16:35:41 +0200382#define RQNT2 \
383 "RQNT 186908781 1@mgw MGCP 1.0\r\n" \
384 "X: ADD4F26746F\r\n" \
385 "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200386
387#define RQNT1_RET "200 186908780 OK\r\n"
388#define RQNT2_RET "200 186908781 OK\r\n"
389
Philipp Maier87bd9be2017-08-22 16:35:41 +0200390#define PTYPE_IGNORE 0 /* == default initializer */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200391#define PTYPE_NONE 128
392#define PTYPE_NYI PTYPE_NONE
393
Philipp Maier87bd9be2017-08-22 16:35:41 +0200394#define CRCX_MULT_1 \
395 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200396 "M: recvonly\r\n" \
397 "C: 2\r\n" \
398 "X\r\n" \
399 "L: p:20\r\n" \
400 "\r\n" \
401 "v=0\r\n" \
402 "c=IN IP4 123.12.12.123\r\n" \
403 "m=audio 5904 RTP/AVP 18 97\r\n" \
404 "a=rtpmap:18 G729/8000\r\n" \
405 "a=rtpmap:97 GSM-EFR/8000\r\n" \
406 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200407
Philipp Maier87bd9be2017-08-22 16:35:41 +0200408#define CRCX_MULT_2 \
409 "CRCX 2 2@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200410 "M: recvonly\r\n" \
411 "C: 2\r\n" \
412 "X\r\n" \
413 "L: p:20\r\n" \
414 "\r\n" \
415 "v=0\r\n" \
416 "c=IN IP4 123.12.12.123\r\n" \
417 "m=audio 5904 RTP/AVP 18 97 101\r\n" \
418 "a=rtpmap:18 G729/8000\r\n" \
419 "a=rtpmap:97 GSM-EFR/8000\r\n" \
420 "a=rtpmap:101 FOO/8000\r\n" \
421 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200422
Philipp Maier87bd9be2017-08-22 16:35:41 +0200423#define CRCX_MULT_3 \
424 "CRCX 2 3@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200425 "M: recvonly\r\n" \
426 "C: 2\r\n" \
427 "X\r\n" \
428 "L: p:20\r\n" \
429 "\r\n" \
430 "v=0\r\n" \
431 "c=IN IP4 123.12.12.123\r\n" \
432 "m=audio 5904 RTP/AVP\r\n" \
433 "a=rtpmap:18 G729/8000\r\n" \
434 "a=rtpmap:97 GSM-EFR/8000\r\n" \
435 "a=rtpmap:101 FOO/8000\r\n" \
436 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200437
Philipp Maier87bd9be2017-08-22 16:35:41 +0200438#define CRCX_MULT_4 \
439 "CRCX 2 4@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200440 "M: recvonly\r\n" \
441 "C: 2\r\n" \
442 "X\r\n" \
443 "L: p:20\r\n" \
444 "\r\n" \
445 "v=0\r\n" \
446 "c=IN IP4 123.12.12.123\r\n" \
447 "m=audio 5904 RTP/AVP 18\r\n" \
448 "a=rtpmap:18 G729/8000\r\n" \
449 "a=rtpmap:97 GSM-EFR/8000\r\n" \
450 "a=rtpmap:101 FOO/8000\r\n" \
451 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200452
453#define CRCX_MULT_GSM_EXACT \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200454 "CRCX 259260421 5@mgw MGCP 1.0\r\n" \
455 "C: 1355c6041e\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200456 "L: p:20, a:GSM, nt:IN\r\n" \
457 "M: recvonly\r\n" \
458 "\r\n" \
459 "v=0\r\n" \
460 "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
461 "s=-\r\nc=IN IP4 192.168.181.247\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200462 "t=0 0\r\nm=audio 29084 RTP/AVP 0 8 3 18 4 96 97 101\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200463 "a=rtpmap:0 PCMU/8000\r\n" \
464 "a=rtpmap:8 PCMA/8000\r\n" \
465 "a=rtpmap:3 gsm/8000\r\n" \
466 "a=rtpmap:18 G729/8000\r\n" \
467 "a=fmtp:18 annexb=no\r\n" \
468 "a=rtpmap:4 G723/8000\r\n" \
469 "a=rtpmap:96 iLBC/8000\r\n" \
470 "a=fmtp:96 mode=20\r\n" \
471 "a=rtpmap:97 iLBC/8000\r\n" \
472 "a=fmtp:97 mode=30\r\n" \
473 "a=rtpmap:101 telephone-event/8000\r\n" \
474 "a=fmtp:101 0-15\r\n" \
475 "a=recvonly\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200476
Philipp Maier87bd9be2017-08-22 16:35:41 +0200477#define MDCX_NAT_DUMMY \
478 "MDCX 23 5@mgw MGCP 1.0\r\n" \
479 "C: 1355c6041e\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100480 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200481 "\r\n" \
482 "c=IN IP4 8.8.8.8\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200483 "m=audio 16434 RTP/AVP 3\r\n"
484
485#define CRCX_NO_LCO_NO_SDP \
486 "CRCX 2 6@mgw MGCP 1.0\r\n" \
487 "M: recvonly\r\n" \
488 "C: 2\r\n"
489
Philipp Maier228e5912019-03-05 13:56:59 +0100490#define CRCX_AMR_WITH_FMTP \
491 "CRCX 2 7@mgw MGCP 1.0\r\n" \
492 "M: recvonly\r\n" \
493 "C: 2\r\n" \
494 "X\r\n" \
495 "L: p:20\r\n" \
496 "\r\n" \
497 "v=0\r\n" \
498 "c=IN IP4 123.12.12.123\r\n" \
499 "m=audio 5904 RTP/AVP 111\r\n" \
500 "a=rtpmap:111 AMR/8000/1\r\n" \
501 "a=ptime:20\r\n" \
502 "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
503
504#define CRCX_AMR_WITH_FMTP_RET \
505 "200 2 OK\r\n" \
506 "I: %s\r\n" \
507 "\r\n" \
508 "v=0\r\n" \
509 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
510 "s=-\r\n" \
511 "c=IN IP4 0.0.0.0\r\n" \
512 "t=0 0\r\n" \
513 "m=audio 16012 RTP/AVP 111\r\n" \
514 "a=rtpmap:111 AMR/8000/1\r\n" \
515 "a=fmtp:111 octet-align=1\r\n" \
516 "a=ptime:20\r\n"
517
Philipp Maierbc0346e2018-06-07 09:52:16 +0200518#define CRCX_NO_LCO_NO_SDP_RET \
519 "200 2 OK\r\n" \
520 "I: %s\r\n" \
521 "\r\n" \
522 "v=0\r\n" \
523 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
524 "s=-\r\n" \
525 "c=IN IP4 0.0.0.0\r\n" \
526 "t=0 0\r\n" \
527 "m=audio 16008 RTP/AVP 0\r\n" \
528 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200529
530struct mgcp_test {
531 const char *name;
532 const char *req;
533 const char *exp_resp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200534 int ptype;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200535 const char *extra_fmtp;
536};
537
538static const struct mgcp_test tests[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200539 {"AUEP1", AUEP1, AUEP1_RET},
540 {"AUEP2", AUEP2, AUEP2_RET},
541 {"MDCX1", MDCX_WRONG_EP, MDCX_ERR_RET},
542 {"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
543 {"CRCX", CRCX, CRCX_RET, 97},
544 {"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
545 {"MDCX4", MDCX4, MDCX4_RET("18983216"), 99},
546 {"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99},
547 {"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99},
548 {"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99},
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200549 {"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983220"), 99},
550 {"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983221"), 99},
551 {"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983222"), PTYPE_IGNORE},
Philipp Maier87bd9be2017-08-22 16:35:41 +0200552 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
553 {"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
554 {"EMPTY", EMPTY, EMPTY_RET},
555 {"SHORT1", SHORT, SHORT_RET},
556 {"SHORT2", SHORT2, SHORT2_RET},
557 {"SHORT3", SHORT3, SHORT2_RET},
558 {"SHORT4", SHORT4, SHORT2_RET},
559 {"RQNT1", RQNT, RQNT1_RET},
560 {"RQNT2", RQNT2, RQNT2_RET},
561 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
562 {"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
563 {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
564 "a=fmtp:126 0/1/2"},
565 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
Philipp Maierbc0346e2018-06-07 09:52:16 +0200566 {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200567 {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200568 {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
Philipp Maier228e5912019-03-05 13:56:59 +0100569 {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200570};
571
572static const struct mgcp_test retransmit[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200573 {"CRCX", CRCX, CRCX_RET},
574 {"RQNT1", RQNT, RQNT1_RET},
575 {"RQNT2", RQNT2, RQNT2_RET},
576 {"MDCX3", MDCX3, MDCX3A_RET},
577 {"DLCX", DLCX, DLCX_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200578};
579
Philipp Maierffd75e42017-11-22 11:44:50 +0100580static struct msgb *create_msg(const char *str, const char *conn_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200581{
582 struct msgb *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100583 int len;
584
585 printf("creating message from statically defined input:\n");
586 printf("---------8<---------\n%s\n---------8<---------\n", str);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200587
588 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
Philipp Maierffd75e42017-11-22 11:44:50 +0100589 if (conn_id && strlen(conn_id))
590 len = sprintf((char *)msg->data, str, conn_id, conn_id);
591 else
592 len = sprintf((char *)msg->data, "%s", str);
593
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200594 msg->l2h = msgb_put(msg, len);
595 return msg;
596}
597
Philipp Maier37a808c2020-07-03 15:48:31 +0200598static char last_endpoint[MGCP_ENDPOINT_MAXLEN];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200599
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200600static int mgcp_test_policy_cb(struct mgcp_endpoint *endp,
601 int state, const char *transaction_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200602{
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200603 unsigned int i;
604 struct mgcp_trunk *trunk;
605
606 fprintf(stderr, "Policy CB got state %d on endpoint %s\n",
607 state, endp->name);
608
609 trunk = endp->trunk;
Philipp Maier37a808c2020-07-03 15:48:31 +0200610 last_endpoint[0] = '\0';
Philipp Maier869b21c2020-07-03 16:04:16 +0200611 for (i = 0; i < trunk->number_endpoints; i++) {
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200612 if (strcmp(endp->name, trunk->endpoints[i]->name) == 0)
Philipp Maier37a808c2020-07-03 15:48:31 +0200613 osmo_strlcpy(last_endpoint, trunk->endpoints[i]->name,
614 sizeof(last_endpoint));
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200615 }
616
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200617 return MGCP_POLICY_CONT;
618}
619
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200620static int dummy_packets = 0;
621/* override and forward */
622ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200623 const struct sockaddr *dest_addr, socklen_t addrlen)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200624{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200625 uint32_t dest_host =
626 htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
627 int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200628
Philipp Maierb3d14eb2021-05-20 14:18:52 +0200629 if (len == sizeof(rtp_dummy_payload)
630 && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200631 fprintf(stderr,
632 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
633 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200634 dummy_packets += 1;
635 }
636
Pau Espin Pedrola24dcc62021-07-06 17:48:47 +0200637 /* Make sure address+port are valid */
638 OSMO_ASSERT(dest_host);
639 OSMO_ASSERT(dest_port);
640
Philipp Maier3d9b6562017-10-13 18:33:44 +0200641 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200642}
643
644static int64_t force_monotonic_time_us = -1;
645/* override and forward */
646int clock_gettime(clockid_t clk_id, struct timespec *tp)
647{
648 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
649 static clock_gettime_t real_clock_gettime = NULL;
650
651 if (!real_clock_gettime)
652 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
653
654 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
655 tp->tv_sec = force_monotonic_time_us / 1000000;
656 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
657 return 0;
658 }
659
660 return real_clock_gettime(clk_id, tp);
661}
662
Philipp Maier14b27a82020-06-02 20:15:30 +0200663static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200664{
665 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200666 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200667 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200668}
669
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200670#define CONN_UNMODIFIED (0x1000)
671
672static void test_values(void)
673{
674 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200675 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200676
677 /* Check that LOOPBACK enables all output */
678 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200679 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200680}
681
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200682/* Extract a connection ID from a response and return in conn_id;
683 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100684static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200685 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100686{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200687 const char *conn_id_start;
688 const char *conn_id_end;
689 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100690
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200691 const char *header_I = "\r\nI: ";
692 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100693
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200694 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
695 if ((conn_id_start = strstr((char *)resp, header_I))) {
696 conn_id_start += strlen(header_I);
697 conn_id_end = strstr(conn_id_start, "\r\n");
698 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
699 conn_id_start += strlen(header_o);
700 conn_id_end = strchr(conn_id_start, ' ');
701 } else
702 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100703
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200704 if (conn_id_end)
705 conn_id_len = conn_id_end - conn_id_start;
706 else
707 conn_id_len = strlen(conn_id_start);
708 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100709
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200710 /* A valid conn_id must at least contain one digit, and must
711 * not exceed a length of 32 digits */
712 OSMO_ASSERT(conn_id_len <= 32);
713 OSMO_ASSERT(conn_id_len > 0);
714
715 strncpy(conn_id, conn_id_start, conn_id_len);
716 conn_id[conn_id_len] = '\0';
717 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100718}
719
720/* Check response, automatically patch connection ID if needed */
721static int check_response(uint8_t *resp, const char *exp_resp)
722{
723 char exp_resp_patched[4096];
724 const char *exp_resp_ptr;
725 char conn_id[256];
726
727 printf("checking response:\n");
728
729 /* If the expected response is intened to be patched
730 * (%s placeholder inside) we will patch it with the
731 * connection identifier we just received from the
732 * real response. This is necessary because the CI
733 * is generated by the mgcp code on CRCX and we can
734 * not know it in advance */
735 if (strstr(exp_resp, "%s")) {
736 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
737 0) {
738 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
739 exp_resp_ptr = exp_resp_patched;
740 printf
741 ("using message with patched conn_id for comparison\n");
742 } else {
743 printf
744 ("patching conn_id failed, using message as statically defined for comparison\n");
745 exp_resp_ptr = exp_resp;
746 }
747 } else {
748 printf("using message as statically defined for comparison\n");
749 exp_resp_ptr = exp_resp;
750 }
751
752 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
753 printf("Unexpected response, please check!\n");
754 printf
755 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
756 resp);
757 printf
758 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
759 exp_resp_ptr);
760 return -EINVAL;
761 }
762
763 printf("Response matches our expectations.\n");
764 return 0;
765}
766
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200767static void test_messages(void)
768{
769 struct mgcp_config *cfg;
770 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200771 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200772 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200773 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100774 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100775 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200776
777 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200778 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200779
Philipp Maier889fe7f2020-07-06 17:44:12 +0200780 trunk->v.vty_number_endpoints = 64;
781 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200782 cfg->policy_cb = mgcp_test_policy_cb;
783
Philipp Maierffd75e42017-11-22 11:44:50 +0100784 memset(last_conn_id, 0, sizeof(last_conn_id));
785
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200786 for (i = 0; i < ARRAY_SIZE(tests); i++) {
787 const struct mgcp_test *t = &tests[i];
788 struct msgb *inp;
789 struct msgb *msg;
790
Philipp Maierffd75e42017-11-22 11:44:50 +0100791 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200792 printf("Testing %s\n", t->name);
793
Philipp Maier37a808c2020-07-03 15:48:31 +0200794 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200795 dummy_packets = 0;
796
Philipp Maierd19de2e2020-06-03 13:55:33 +0200797 osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200798 t->extra_fmtp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200799
Philipp Maierffd75e42017-11-22 11:44:50 +0100800 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200801 msg = mgcp_handle_message(cfg, inp);
802 msgb_free(inp);
803 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200804 if (msg) {
805 printf("%s failed '%s'\n", t->name,
806 (char *)msg->data);
807 OSMO_ASSERT(false);
808 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100809 } else if (check_response(msg->data, t->exp_resp) != 0) {
810 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200811 OSMO_ASSERT(false);
812 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100813
Philipp Maier7df419b2017-12-04 17:11:42 +0100814 if (msg) {
815 rc = get_conn_id_from_response(msg->data, last_conn_id,
816 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200817 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100818 printf("(response contains a connection id)\n");
819 else
820 printf("(response does not contain a connection id)\n");
821 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100822
Philipp Maiera330b862017-12-04 17:16:16 +0100823 if (msg)
824 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200825
826 if (dummy_packets)
827 printf("Dummy packets: %d\n", dummy_packets);
828
Philipp Maier37a808c2020-07-03 15:48:31 +0200829 if (last_endpoint[0] != '\0') {
830 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
831 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200832
Philipp Maier01d24a32017-11-21 17:26:09 +0100833 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200834 if (conn) {
835 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200836
Philipp Maier87bd9be2017-08-22 16:35:41 +0200837 if (conn->end.packet_duration_ms != -1)
838 printf("Detected packet duration: %d\n",
839 conn->end.packet_duration_ms);
840 else
841 printf("Packet duration not set\n");
842 if (endp->local_options.pkt_period_min ||
843 endp->local_options.pkt_period_max)
844 printf
845 ("Requested packetetization period: "
846 "%d-%d\n",
847 endp->local_options.pkt_period_min,
848 endp->
849 local_options.pkt_period_max);
850 else
851 printf
852 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200853
Philipp Maier87bd9be2017-08-22 16:35:41 +0200854 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
855 printf("Connection mode: %d:%s%s%s%s\n",
856 conn->conn->mode,
857 !conn->conn->mode ? " NONE" : "",
858 conn->conn->mode & MGCP_CONN_SEND_ONLY
859 ? " SEND" : "",
860 conn->conn->mode & MGCP_CONN_RECV_ONLY
861 ? " RECV" : "",
862 conn->conn->mode & MGCP_CONN_LOOPBACK
863 & ~MGCP_CONN_RECV_SEND
864 ? " LOOP" : "");
865 fprintf(stderr,
866 "RTP output %sabled, NET output %sabled\n",
867 conn->end.output_enabled
868 ? "en" : "dis",
869 conn->end.output_enabled
870 ? "en" : "dis");
871 } else
872 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200873
Philipp Maier87bd9be2017-08-22 16:35:41 +0200874 OSMO_ASSERT(conn->end.output_enabled
875 == (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
876
877 conn->conn->mode |= CONN_UNMODIFIED;
878
879 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200880 endp->local_options.pkt_period_min = 0;
881 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200882 }
883
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200884 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100885 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200886 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200887
Philipp Maier37a808c2020-07-03 15:48:31 +0200888 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200889 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200890 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200891 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200892
Philipp Maier87bd9be2017-08-22 16:35:41 +0200893 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200894 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200895 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200896
897 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200898 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200899 }
900 }
901
Philipp Maierd19de2e2020-06-03 13:55:33 +0200902 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200903 talloc_free(cfg);
904}
905
906static void test_retransmission(void)
907{
908 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200909 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200910 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100911 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100912 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200913
914 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200915 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200916
Philipp Maier889fe7f2020-07-06 17:44:12 +0200917 trunk->v.vty_number_endpoints = 64;
918 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200919
Philipp Maierffd75e42017-11-22 11:44:50 +0100920 memset(last_conn_id, 0, sizeof(last_conn_id));
921
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200922 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
923 const struct mgcp_test *t = &retransmit[i];
924 struct msgb *inp;
925 struct msgb *msg;
926
Philipp Maierffd75e42017-11-22 11:44:50 +0100927 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200928 printf("Testing %s\n", t->name);
929
Philipp Maierffd75e42017-11-22 11:44:50 +0100930 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200931 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200932
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200933 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100934 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200935 printf("%s failed '%s'\n", t->name, (char *)msg->data);
936 OSMO_ASSERT(false);
937 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100938
Philipp Maier23b8e292017-12-04 16:48:45 +0100939 if (msg && strcmp(t->name, "CRCX") == 0) {
940 rc = get_conn_id_from_response(msg->data, last_conn_id,
941 sizeof(last_conn_id));
942 OSMO_ASSERT(rc == 0);
943 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100944
Philipp Maier7cedfd72017-12-04 16:49:12 +0100945 if (msg)
946 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200947
948 /* Retransmit... */
949 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100950 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200951 msg = mgcp_handle_message(cfg, inp);
952 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100953 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200954 printf("%s failed '%s'\n", t->name, (char *)msg->data);
955 OSMO_ASSERT(false);
956 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200957 msgb_free(msg);
958 }
959
Philipp Maierd19de2e2020-06-03 13:55:33 +0200960 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200961 talloc_free(cfg);
962}
963
964static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
965{
966 ptrdiff_t tone = _tone;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200967 endp->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200968 return 0;
969}
970
971static void test_rqnt_cb(void)
972{
973 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200974 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200975 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100976 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200977
978 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200979 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200980 cfg->rqnt_cb = rqnt_cb;
981
Philipp Maier889fe7f2020-07-06 17:44:12 +0200982 trunk->v.vty_number_endpoints = 64;
983 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200984
Philipp Maierffd75e42017-11-22 11:44:50 +0100985 inp = create_msg(CRCX, NULL);
986 msg = mgcp_handle_message(cfg, inp);
987 OSMO_ASSERT(msg);
988 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
989 sizeof(conn_id)) == 0);
990 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200991 msgb_free(inp);
992
993 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +0100994 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200995 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200996 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200997 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
998 abort();
999 }
1000
Philipp Maier87bd9be2017-08-22 16:35:41 +02001001 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001002 printf("FAILED: callback not called: %p\n", cfg->data);
1003 abort();
1004 }
1005
1006 msgb_free(msg);
1007 msgb_free(inp);
1008
Philipp Maierffd75e42017-11-22 11:44:50 +01001009 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001010 msgb_free(mgcp_handle_message(cfg, inp));
1011 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001012 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001013 talloc_free(cfg);
1014}
1015
1016struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001017 int cycles;
1018 uint16_t base_seq;
1019 uint16_t max_seq;
1020 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001021
Philipp Maier87bd9be2017-08-22 16:35:41 +02001022 uint32_t expected;
1023 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001024};
1025
1026static const struct pl_test pl_test_dat[] = {
1027 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001028 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1029 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001030 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001031 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1032 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001033 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001034 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1035 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001036 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001037 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1038 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001039 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001040 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1041 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001042};
1043
1044static void test_packet_loss_calc(void)
1045{
1046 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001047 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001048 struct mgcp_endpoint *endpoints[1];
Oliver Smithe36b7752019-01-22 16:31:36 +01001049 struct mgcp_config cfg = {0};
Philipp Maier14b27a82020-06-02 20:15:30 +02001050 struct mgcp_trunk trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001051
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001052 printf("Testing packet loss calculation.\n");
1053
Philipp Maiercede2a42018-07-03 14:14:21 +02001054 memset(&endp, 0, sizeof(endp));
1055 memset(&trunk, 0, sizeof(trunk));
1056
Oliver Smithe36b7752019-01-22 16:31:36 +01001057 endp.cfg = &cfg;
Philipp Maiercede2a42018-07-03 14:14:21 +02001058 endp.type = &ep_typeset.rtp;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001059 trunk.v.vty_number_endpoints = 1;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001060 trunk.endpoints = endpoints;
1061 trunk.endpoints[0] = &endp;
Philipp Maier14b27a82020-06-02 20:15:30 +02001062 endp.trunk = &trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001063 INIT_LLIST_HEAD(&endp.conns);
1064
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001065 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1066 uint32_t expected;
1067 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001068
Philipp Maiercede2a42018-07-03 14:14:21 +02001069 struct mgcp_conn_rtp *conn = NULL;
1070 struct mgcp_conn *_conn = NULL;
1071 struct mgcp_rtp_state *state;
1072 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001073
Philipp Maiercede2a42018-07-03 14:14:21 +02001074 _conn =
1075 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1076 "test-connection");
1077 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1078 state = &conn->state;
Pau Espin Pedrol907744e2021-06-04 17:57:34 +02001079 packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001080
1081 state->stats.initialized = 1;
1082 state->stats.base_seq = pl_test_dat[i].base_seq;
1083 state->stats.max_seq = pl_test_dat[i].max_seq;
1084 state->stats.cycles = pl_test_dat[i].cycles;
1085
1086 packets_rx->current = pl_test_dat[i].packets;
1087 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001088
Philipp Maier87bd9be2017-08-22 16:35:41 +02001089 if (loss != pl_test_dat[i].loss
1090 || expected != pl_test_dat[i].expected) {
1091 printf
1092 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1093 i, loss, pl_test_dat[i].loss, expected,
1094 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001095 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001096
1097 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001098 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001099
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001100}
1101
Philipp Maier87bd9be2017-08-22 16:35:41 +02001102int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1103 uint32_t *pr, uint32_t *_or, int *loss,
1104 uint32_t *jitter)
1105{
1106 char *line, *save;
1107 int rc;
1108
1109 /* initialize with bad values */
1110 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1111 *loss = INT_MAX;
1112
1113 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1114 if (!line)
1115 return -1;
1116
1117 /* this can only parse the message that is created above... */
1118 for_each_non_empty_line(line, save) {
1119 switch (line[0]) {
1120 case 'P':
1121 rc = sscanf(line,
1122 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1123 ps, os, pr, _or, loss, jitter);
1124 return rc == 6 ? 0 : -1;
1125 }
1126 }
1127
1128 return -1;
1129}
1130
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001131static void test_mgcp_stats(void)
1132{
1133 printf("Testing stat parsing\n");
1134
1135 uint32_t bps, bos, pr, _or, jitter;
1136 struct msgb *msg;
1137 int loss;
1138 int rc;
1139
Philipp Maierffd75e42017-11-22 11:44:50 +01001140 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001141 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1142 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001143 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1144 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001145 printf("FAIL: Parsing failed1.\n");
1146 msgb_free(msg);
1147
Philipp Maier87bd9be2017-08-22 16:35:41 +02001148 msg =
1149 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001150 ("250 7 OK\r\nP: PS=10, OS=20, PR=30, OR=40, PL=-3, JI=40\r\n", NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001151 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1152 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001153 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1154 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001155 printf("FAIL: Parsing failed2.\n");
1156 msgb_free(msg);
1157}
1158
1159struct rtp_packet_info {
1160 float txtime;
1161 int len;
1162 char *data;
1163};
1164
1165struct rtp_packet_info test_rtp_packets1[] = {
1166 /* RTP: SeqNo=0, TS=0 */
1167 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001168 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001169 /* RTP: SeqNo=1, TS=160 */
1170 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001171 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001172 /* RTP: SeqNo=2, TS=320 */
1173 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001174 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001175 /* Repeat RTP timestamp: */
1176 /* RTP: SeqNo=3, TS=320 */
1177 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001178 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001179 /* RTP: SeqNo=4, TS=480 */
1180 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001181 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001182 /* RTP: SeqNo=5, TS=640 */
1183 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001184 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001185 /* Double skip RTP timestamp (delta = 2*160): */
1186 /* RTP: SeqNo=6, TS=960 */
1187 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001188 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001189 /* RTP: SeqNo=7, TS=1120 */
1190 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001191 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001192 /* RTP: SeqNo=8, TS=1280 */
1193 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001194 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001195 /* Non 20ms RTP timestamp (delta = 120): */
1196 /* RTP: SeqNo=9, TS=1400 */
1197 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001198 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001199 /* RTP: SeqNo=10, TS=1560 */
1200 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001201 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001202 /* RTP: SeqNo=11, TS=1720 */
1203 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001204 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001205 /* SSRC changed to 0x10203040, RTP timestamp jump */
1206 /* RTP: SeqNo=12, TS=34688 */
1207 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001208 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001209 /* RTP: SeqNo=13, TS=34848 */
1210 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001211 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001212 /* RTP: SeqNo=14, TS=35008 */
1213 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001214 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001215 /* Non 20ms RTP timestamp (delta = 120): */
1216 /* RTP: SeqNo=15, TS=35128 */
1217 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001218 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001219 /* RTP: SeqNo=16, TS=35288 */
1220 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001221 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001222 /* RTP: SeqNo=17, TS=35448 */
1223 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001224 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001225 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1226 /* RTP: SeqNo=19, TS=35768 */
1227 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001228 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001229 /* RTP: SeqNo=20, TS=35928 */
1230 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001231 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001232 /* RTP: SeqNo=21, TS=36088 */
1233 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001234 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001235 /* Repeat last packet */
1236 /* RTP: SeqNo=21, TS=36088 */
1237 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001238 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001239 /* RTP: SeqNo=22, TS=36248 */
1240 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001241 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001242 /* RTP: SeqNo=23, TS=36408 */
1243 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001244 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001245 /* Don't increment SeqNo but increment timestamp by 160 */
1246 /* RTP: SeqNo=23, TS=36568 */
1247 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001248 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001249 /* RTP: SeqNo=24, TS=36728 */
1250 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001251 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001252 /* RTP: SeqNo=25, TS=36888 */
1253 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001254 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001255 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1256 * SeqNo jump */
1257 /* RTP: SeqNo=1000, TS=160000 */
1258 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001259 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001260 /* RTP: SeqNo=1001, TS=160160 */
1261 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001262 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001263 /* RTP: SeqNo=1002, TS=160320 */
1264 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001265 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001266};
1267
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001268static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1269{
1270 int i;
1271
Philipp Maier14b27a82020-06-02 20:15:30 +02001272 struct mgcp_trunk trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001273 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001274 struct mgcp_endpoint *endpoints[1];
Oliver Smithe36b7752019-01-22 16:31:36 +01001275 struct mgcp_config cfg = {0};
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001276 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001277 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001278 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001279 uint32_t last_ssrc = 0;
1280 uint32_t last_timestamp = 0;
1281 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001282 uint64_t last_in_ts_err_cnt = 0;
1283 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001284 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001285 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001286 struct rate_ctr test_ctr_in;
1287 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001288
1289 printf("Testing packet error detection%s%s.\n",
1290 patch_ssrc ? ", patch SSRC" : "",
1291 patch_ts ? ", patch timestamps" : "");
1292
1293 memset(&trunk, 0, sizeof(trunk));
1294 memset(&endp, 0, sizeof(endp));
1295 memset(&state, 0, sizeof(state));
1296
Philipp Maier9e1d1642018-05-09 16:26:34 +02001297 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1298 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1299 state.in_stream.err_ts_ctr = &test_ctr_in;
1300 state.out_stream.err_ts_ctr = &test_ctr_out;
1301
Oliver Smithe36b7752019-01-22 16:31:36 +01001302 endp.cfg = &cfg;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001303 endp.type = &ep_typeset.rtp;
1304
Philipp Maier889fe7f2020-07-06 17:44:12 +02001305 trunk.v.vty_number_endpoints = 1;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001306 trunk.endpoints = endpoints;
1307 trunk.endpoints[0] = &endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001308 trunk.force_constant_ssrc = patch_ssrc;
1309 trunk.force_aligned_timing = patch_ts;
1310
Philipp Maier14b27a82020-06-02 20:15:30 +02001311 endp.trunk = &trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001312
Philipp Maier87bd9be2017-08-22 16:35:41 +02001313 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001314 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1315 "test-connection");
1316 OSMO_ASSERT(_conn);
1317 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001318 OSMO_ASSERT(conn);
1319
1320 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001321
Philipp Maier228e5912019-03-05 13:56:59 +01001322 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001323 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001324
1325 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1326 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001327 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001328
1329 force_monotonic_time_us = round(1000000.0 * info->txtime);
1330
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001331 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001332 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001333 msg->l3h = msgb_put(msg, info->len);
1334 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001335 mgcp_rtp_end_config(&endp, 1, rtp);
1336
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001337 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001338
1339 if (state.out_stream.ssrc != last_ssrc) {
1340 printf("Output SSRC changed to %08x\n",
1341 state.out_stream.ssrc);
1342 last_ssrc = state.out_stream.ssrc;
1343 }
1344
1345 printf("In TS: %d, dTS: %d, Seq: %d\n",
1346 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001347 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001348
1349 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001350 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001351 state.out_stream.last_timestamp - last_timestamp,
1352 state.out_stream.last_tsdelta,
1353 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001354 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1355 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001356
1357 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001358 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001359
Philipp Maier9e1d1642018-05-09 16:26:34 +02001360 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1361 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001362 last_timestamp = state.out_stream.last_timestamp;
1363 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001364
1365 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001366 }
1367
1368 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001369 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001370}
1371
1372static void test_multilple_codec(void)
1373{
1374 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001375 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001376 struct mgcp_endpoint *endp;
1377 struct msgb *inp, *resp;
1378 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001379 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001380 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001381
1382 printf("Testing multiple payload types\n");
1383
1384 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001385 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001386 trunk->v.vty_number_endpoints = 64;
1387 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001388 cfg->policy_cb = mgcp_test_policy_cb;
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001389
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001390 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001391 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001392 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001393 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001394 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1395 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001396 msgb_free(inp);
1397 msgb_free(resp);
1398
Philipp Maier37a808c2020-07-03 15:48:31 +02001399 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1400 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1401 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001402 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001403 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001404 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001405
1406 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001407 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001408 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001409 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001410 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1411 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001412 msgb_free(inp);
1413 msgb_free(resp);
1414
Philipp Maier37a808c2020-07-03 15:48:31 +02001415 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1416 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1417 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001418 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001419 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001420 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001421
Philipp Maierbc0346e2018-06-07 09:52:16 +02001422 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1423 /* Note: It usually makes no sense to leave the payload type list
1424 * out. However RFC 2327 does not clearly forbid this case and
1425 * it makes and since we already decided in OS#2658 that a missing
1426 * LCO should pick a sane default codec, it makes sense to expect
1427 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001428 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001429 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001430 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001431 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1432 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001433 msgb_free(inp);
1434 msgb_free(resp);
1435
Philipp Maier37a808c2020-07-03 15:48:31 +02001436 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1437 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1438 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001439 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001440 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001441 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001442
1443 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001444 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001445 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001446 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001447 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1448 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001449 msgb_free(inp);
1450 msgb_free(resp);
1451
Philipp Maier37a808c2020-07-03 15:48:31 +02001452 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1453 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1454 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001455 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001456 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001457 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001458
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001459 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
Philipp Maier37a808c2020-07-03 15:48:31 +02001460 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001461 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001462 trunk->no_audio_transcoding = 1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001463 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001464 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1465 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001466 msgb_free(inp);
1467 msgb_free(resp);
1468
Philipp Maier37a808c2020-07-03 15:48:31 +02001469 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1470 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1471 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001472 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001473 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001474 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001475
Philipp Maierffd75e42017-11-22 11:44:50 +01001476 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001477 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001478 resp = mgcp_handle_message(cfg, inp);
1479 msgb_free(inp);
1480 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001481 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1482 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1483 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001484 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001485 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001486 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001487 OSMO_ASSERT(conn->end.rtp_port == htons(16434));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001488 memset(&addr, 0, sizeof(addr));
1489 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001490 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1491 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001492
1493 /* Check what happens without that flag */
1494
Philipp Maier87bd9be2017-08-22 16:35:41 +02001495 /* Free the previous endpoint and the data and
1496 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001497 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001498 talloc_free(endp->last_response);
1499 talloc_free(endp->last_trans);
1500 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001501 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001502 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001503
Philipp Maier37a808c2020-07-03 15:48:31 +02001504 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001505 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001506 trunk->no_audio_transcoding = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001507 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001508 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1509 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001510 msgb_free(inp);
1511 msgb_free(resp);
1512
Philipp Maier37a808c2020-07-03 15:48:31 +02001513 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1514 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1515 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001516 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001517 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001518 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001519
Philipp Maierd19de2e2020-06-03 13:55:33 +02001520 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001521 talloc_free(cfg);
1522}
1523
1524static void test_no_cycle(void)
1525{
1526 struct mgcp_config *cfg;
1527 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001528 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001529 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001530 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001531
1532 printf("Testing no sequence flow on initial packet\n");
1533
1534 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001535 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001536 trunk->v.vty_number_endpoints = 64;
1537 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001538
Philipp Maier37a808c2020-07-03 15:48:31 +02001539 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1540 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001541
Philipp Maierffd75e42017-11-22 11:44:50 +01001542 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1543 "test-connection");
1544 OSMO_ASSERT(_conn);
1545 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001546 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001547
Harald Welte49e3d5a2017-12-25 09:47:57 +01001548 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001549
1550 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001551 OSMO_ASSERT(conn->state.stats.initialized == 1);
1552 OSMO_ASSERT(conn->state.stats.cycles == 0);
1553 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001554
1555 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001556 OSMO_ASSERT(conn->state.stats.initialized == 1);
1557 OSMO_ASSERT(conn->state.stats.cycles == 0);
1558 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001559
1560 /* now jump.. */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001561 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001562 OSMO_ASSERT(conn->state.stats.initialized == 1);
1563 OSMO_ASSERT(conn->state.stats.cycles == 0);
1564 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001565
1566 /* and wrap */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001567 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001568 OSMO_ASSERT(conn->state.stats.initialized == 1);
1569 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1570 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001571
Philipp Maierd19de2e2020-06-03 13:55:33 +02001572 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001573 talloc_free(cfg);
1574}
1575
1576static void test_no_name(void)
1577{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001578 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001579 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001580 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001581
1582 printf("Testing no rtpmap name\n");
1583 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001584 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001585
Philipp Maier889fe7f2020-07-06 17:44:12 +02001586 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001587 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001588 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001589
1590 cfg->policy_cb = mgcp_test_policy_cb;
1591
Philipp Maierffd75e42017-11-22 11:44:50 +01001592 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001593 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001594
1595 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001596 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001597 (char *)msg->data);
1598 OSMO_ASSERT(false);
1599 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001600 msgb_free(inp);
1601 msgb_free(msg);
1602
Philipp Maierd19de2e2020-06-03 13:55:33 +02001603 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001604 talloc_free(cfg);
1605}
1606
1607static void test_osmux_cid(void)
1608{
1609 int id, i;
1610
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001611 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1612
1613 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001614 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001615 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1616
1617 osmux_cid_pool_get(30);
1618 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1619 osmux_cid_pool_get(30);
1620 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1621
1622 osmux_cid_pool_put(id);
1623 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1624 osmux_cid_pool_put(30);
1625 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001626
1627 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001628 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001629 OSMO_ASSERT(id == i);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001630 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001631 }
1632
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001633 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001634 OSMO_ASSERT(id == -1);
1635
1636 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001637 osmux_cid_pool_put(i);
1638 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001639}
1640
1641static const struct log_info_cat log_categories[] = {
1642};
1643
1644const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001645 .cat = log_categories,
1646 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001647};
1648
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001649static void test_get_lco_identifier(void)
1650{
1651 char *test;
1652 printf("Testing get_lco_identifier()\n");
1653
1654 /* Normal case at the beginning */
1655 test = "p:10, a:PCMU";
1656 printf("%s -> %s\n", test, get_lco_identifier(test));
1657
1658 test = "p:10, a:PCMU";
1659 printf("%s -> %s\n", test, get_lco_identifier(test));
1660
1661 /* Begin parsing in the middle of the value part of
1662 * the previous LCO option value */
1663 test = "XXXX, p:10, a:PCMU";
1664 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1665
1666 test = "XXXX,p:10,a:PCMU";
1667 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1668
1669 test = "10,a:PCMU";
1670 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1671
1672 test = "10, a:PCMU";
1673 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1674
1675 test = "10,a: PCMU";
1676 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1677
1678 test = "10 ,a: PCMU";
1679 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1680
1681 /* Begin parsing right at the end of the previous LCO
1682 * option value */
1683 test = ", a:PCMU";
1684 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1685
1686 test = " a:PCMU";
1687 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1688
1689 /* Empty string, result should be (null) */
1690 test = "";
1691 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1692
1693 /* Missing colons, result should be (null) */
1694 test = "p10, aPCMU";
1695 printf("%s -> %s\n", test, get_lco_identifier(test));
1696
1697 /* Colon separated from the identifier, result should be (null) */
1698 test = "10,a :PCMU";
1699 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1700}
1701
1702static void test_check_local_cx_options(void *ctx)
1703{
1704 /* Legal cases */
1705 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1706 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1707 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1708 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1709 0);
1710 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1711 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1712 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1713 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1714 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1715
1716 /* Illegal spaces before and after colon */
1717 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1718 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1719 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1720
1721 /* Check if multiple appearances of LCOs are rejected */
1722 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1723 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1724 -1);
1725 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1726
1727 /* Check if empty LCO are rejected */
1728 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1729 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1730 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1731 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1732 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1733
1734 /* Garbeled beginning and ends */
1735 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1736 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1737 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1738 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1739 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1740 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1741
1742 /* Illegal strings */
1743 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1744 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1745 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1746 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1747 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1748 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1749}
1750
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001751static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1752 .amr_octet_aligned_present = true,
1753 .amr_octet_aligned = true,
1754};
1755
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001756static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1757 .amr_octet_aligned_present = true,
1758 .amr_octet_aligned = false,
1759};
1760
1761static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1762 .amr_octet_aligned_present = false,
1763};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001764
1765struct testcase_mgcp_codec_pt_translate_codec {
1766 int payload_type;
1767 const char *audio_name;
1768 const struct mgcp_codec_param *param;
1769 int expect_rc;
1770};
1771
1772struct testcase_mgcp_codec_pt_translate_expect {
1773 bool end;
1774 int payload_type_map[2];
1775};
1776
1777struct testcase_mgcp_codec_pt_translate {
1778 const char *descr;
1779 /* two conns on an endpoint, each with N configured codecs */
1780 struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
1781 struct testcase_mgcp_codec_pt_translate_expect expect[32];
1782};
1783
1784static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
1785 {
1786 .descr = "same order, but differing payload type numbers",
1787 .codecs = {
1788 {
1789 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1790 { 0, "PCMU/8000/1", NULL, },
1791 { 111, "GSM-HR-08/8000/1", NULL, },
1792 },
1793 {
1794 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1795 { 0, "PCMU/8000/1", NULL, },
1796 { 97, "GSM-HR-08/8000/1", NULL, },
1797 },
1798 },
1799 .expect = {
1800 { .payload_type_map = {112, 96}, },
1801 { .payload_type_map = {0, 0}, },
1802 { .payload_type_map = {111, 97} },
1803 { .payload_type_map = {123, -EINVAL} },
1804 { .end = true },
1805 },
1806 },
1807 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001808 .descr = "different order and different payload type numbers",
1809 .codecs = {
1810 {
1811 { 0, "PCMU/8000/1", NULL, },
1812 { 111, "GSM-HR-08/8000/1", NULL, },
1813 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1814 },
1815 {
1816 { 97, "GSM-HR-08/8000/1", NULL, },
1817 { 0, "PCMU/8000/1", NULL, },
1818 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1819 },
1820 },
1821 .expect = {
1822 { .payload_type_map = {112, 96}, },
1823 { .payload_type_map = {0, 0}, },
1824 { .payload_type_map = {111, 97} },
1825 { .payload_type_map = {123, -EINVAL} },
1826 { .end = true },
1827 },
1828 },
1829 {
1830 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1831 .codecs = {
1832 {
1833 { 0, "PCMU/8000/1", NULL, },
1834 { 96, "GSM-HR-08/8000/1", NULL, },
1835 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1836 },
1837 {
1838 { 97, "GSM-HR-08/8000/1", NULL, },
1839 { 0, "PCMU/8000/1", NULL, },
1840 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1841 },
1842 },
1843 .expect = {
1844 { .payload_type_map = {96, 97}, },
1845 { .payload_type_map = {97, 96}, },
1846 { .payload_type_map = {0, 0}, },
1847 { .end = true },
1848 },
1849 },
1850 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001851 .descr = "conn0 has no codecs",
1852 .codecs = {
1853 {
1854 /* no codecs */
1855 },
1856 {
1857 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1858 { 0, "PCMU/8000/1", NULL, },
1859 { 97, "GSM-HR-08/8000/1", NULL, },
1860 },
1861 },
1862 .expect = {
1863 { .payload_type_map = {112, -EINVAL}, },
1864 { .payload_type_map = {0, -EINVAL}, },
1865 { .payload_type_map = {111, -EINVAL} },
1866 { .end = true },
1867 },
1868 },
1869 {
1870 .descr = "conn1 has no codecs",
1871 .codecs = {
1872 {
1873 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1874 { 0, "PCMU/8000/1", NULL, },
1875 { 111, "GSM-HR-08/8000/1", NULL, },
1876 },
1877 {
1878 /* no codecs */
1879 },
1880 },
1881 .expect = {
1882 { .payload_type_map = {112, -EINVAL}, },
1883 { .payload_type_map = {0, -EINVAL}, },
1884 { .payload_type_map = {111, -EINVAL} },
1885 { .end = true },
1886 },
1887 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001888 {
1889 .descr = "test AMR with differing octet-aligned settings",
1890 .codecs = {
1891 {
1892 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1893 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1894 },
1895 {
1896 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1897 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1898 },
1899 },
1900 .expect = {
1901 { .payload_type_map = {111, 121}, },
1902 { .payload_type_map = {112, 122} },
1903 { .end = true },
1904 },
1905 },
1906 {
1907 .descr = "test AMR with missing octet-aligned settings (defaults to 0)",
1908 .codecs = {
1909 {
1910 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1911 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1912 },
1913 {
1914 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1915 },
1916 },
1917 .expect = {
1918 { .payload_type_map = {111, -EINVAL}, },
1919 { .payload_type_map = {112, 122} },
1920 { .end = true },
1921 },
1922 },
1923 {
1924 .descr = "test AMR with NULL param (defaults to 0)",
1925 .codecs = {
1926 {
1927 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1928 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1929 },
1930 {
1931 { 122, "AMR/8000", NULL, },
1932 },
1933 },
1934 .expect = {
1935 { .payload_type_map = {111, -EINVAL}, },
1936 { .payload_type_map = {112, 122} },
1937 { .end = true },
1938 },
1939 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02001940 {
1941 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
1942 .codecs = {
1943 {
1944 { 0, "PCMU/8000/1", NULL, },
1945 { 111, "GSM-HR-08/8000/1", NULL, },
1946 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1947 },
1948 {
1949 { 97, "GSM-HR-08/8000", NULL, },
1950 { 0, "PCMU/8000", NULL, },
1951 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
1952 },
1953 },
1954 .expect = {
1955 { .payload_type_map = {112, 96}, },
1956 { .payload_type_map = {0, 0}, },
1957 { .payload_type_map = {111, 97} },
1958 { .payload_type_map = {123, -EINVAL} },
1959 { .end = true },
1960 },
1961 },
1962 {
1963 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
1964 .codecs = {
1965 {
1966 { 0, "PCMU/8000/1", NULL, },
1967 { 111, "GSM-HR-08/8000/1", NULL, },
1968 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1969 },
1970 {
1971 { 97, "GSM-HR-08", NULL, },
1972 { 0, "PCMU", NULL, },
1973 { 96, "AMR", &amr_param_octet_aligned_true, },
1974 },
1975 },
1976 .expect = {
1977 { .payload_type_map = {112, 96}, },
1978 { .payload_type_map = {0, 0}, },
1979 { .payload_type_map = {111, 97} },
1980 { .payload_type_map = {123, -EINVAL} },
1981 { .end = true },
1982 },
1983 },
1984 {
1985 .descr = "test whether channel number matching is waterproof",
1986 .codecs = {
1987 {
1988 { 111, "GSM-HR-08/8000", },
1989 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
1990 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
1991 },
1992 {
1993 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
1994 { 121, "GSM-HR-08/8000/1", },
1995 },
1996 },
1997 .expect = {
1998 { .payload_type_map = {111, 121}, },
1999 { .payload_type_map = {112, -EINVAL} },
2000 { .payload_type_map = {113, -EINVAL} },
2001 { .end = true },
2002 },
2003 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002004};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002005
2006static void test_mgcp_codec_pt_translate(void)
2007{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002008 int i;
2009 bool ok = true;
2010 printf("\nTesting mgcp_codec_pt_translate()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002011
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002012 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
2013 const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
2014 struct mgcp_conn_rtp conn[2] = {};
2015 int rc;
2016 int conn_i;
2017 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002018
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002019 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002020
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002021 for (conn_i = 0; conn_i < 2; conn_i++) {
2022 printf(" - add codecs on conn%d:\n", conn_i);
2023 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
2024 const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
2025 if (!codec->audio_name)
2026 break;
2027
2028 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
2029
2030 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2031 codec->param ?
2032 (codec->param->amr_octet_aligned_present?
2033 (codec->param->amr_octet_aligned ?
2034 " octet-aligned=1" : " octet-aligned=0")
2035 : " octet-aligned=unset")
2036 : "",
2037 rc);
2038 if (rc != codec->expect_rc) {
2039 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2040 ok = false;
2041 }
2042 }
2043 if (!c)
2044 printf(" (none)\n");
2045 }
2046
2047 for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
2048 const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
2049 int result;
2050
2051 if (expect->end)
2052 break;
2053
2054 result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
2055 printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
2056 expect->payload_type_map[0], result);
2057 if (result != expect->payload_type_map[1]) {
2058 printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
2059 ok = false;
2060 }
2061
2062 /* If the expected result is an error, don't do reverse map test */
2063 if (expect->payload_type_map[1] < 0)
2064 continue;
2065
2066 result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
2067 printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
2068 expect->payload_type_map[1], result);
2069 if (result != expect->payload_type_map[0]) {
2070 printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
2071 ok = false;
2072 }
2073 }
2074
2075 for (conn_i = 0; conn_i < 2; conn_i++)
2076 mgcp_codec_reset_all(&conn[conn_i]);
2077 }
2078
2079 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002080}
2081
Neels Hofmeyr65317262018-09-03 22:11:05 +02002082void test_conn_id_matching()
2083{
2084 struct mgcp_endpoint endp = {};
2085 struct mgcp_conn *conn;
2086 struct mgcp_conn *conn_match;
2087 int i;
2088 const char *conn_id_generated = "000023AB";
2089 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002090 "23AB",
2091 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002092 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002093 "00000023AB",
2094 "23ab",
2095 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002096 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002097 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002098 };
2099
2100 printf("\nTesting %s\n", __func__);
2101
2102 INIT_LLIST_HEAD(&endp.conns);
2103
2104 conn = talloc_zero(NULL, struct mgcp_conn);
2105 OSMO_ASSERT(conn);
2106 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2107 llist_add(&conn->entry, &endp.conns);
2108
2109 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2110 const char *needle = conn_id_request[i];
2111 printf("needle='%s' ", needle);
2112 conn_match = mgcp_conn_get(&endp, needle);
2113 OSMO_ASSERT(conn_match);
2114 printf("found '%s'\n", conn_match->id);
2115 OSMO_ASSERT(conn_match == conn);
2116 }
2117
2118 llist_del(&conn->entry);
2119 talloc_free(conn);
2120}
2121
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002122void test_e1_trunk_nr_from_epname()
2123{
2124 int trunk_nr;
2125
2126 /* Note: e1_trunk_nr_from_epname does not check the text
2127 * after the E1 trunk number, after the delimiter
2128 * character "/" arbitrary text may follow. */
Philipp Maier0653cc82020-08-10 22:52:51 +02002129 trunk_nr = e1_trunk_nr_from_epname("ds/e1-0/s-1/su16-0");
2130 OSMO_ASSERT(trunk_nr == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002131 trunk_nr = e1_trunk_nr_from_epname("ds/e1-1/s-1/su16-0");
2132 OSMO_ASSERT(trunk_nr == 1);
2133 trunk_nr = e1_trunk_nr_from_epname("ds/e1-2/s-2/su16-0");
2134 OSMO_ASSERT(trunk_nr == 2);
2135 trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/s-23/su32-0");
2136 OSMO_ASSERT(trunk_nr == 3);
2137 trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/xxxxxxx");
2138 OSMO_ASSERT(trunk_nr == 3);
2139 trunk_nr = e1_trunk_nr_from_epname("ds/e1-24/s-1/su16-0");
2140 OSMO_ASSERT(trunk_nr == 24);
2141 trunk_nr = e1_trunk_nr_from_epname("ds/e1-64/s-1/su16-0");
2142 OSMO_ASSERT(trunk_nr == 64);
2143
2144 /* The following endpoint strings should fail, either the
2145 * trunk number exceeds the valid range or the trunk prefix
2146 * is wrong. Also when the delimiter character "/" at the
2147 * end of the trunk is wrong the parsing should fail. */
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002148 trunk_nr = e1_trunk_nr_from_epname("ds/e1-65/s-1/su16-0");
2149 OSMO_ASSERT(trunk_nr == -EINVAL);
2150 trunk_nr = e1_trunk_nr_from_epname("ds/e1--1/s-1/su16-0");
2151 OSMO_ASSERT(trunk_nr == -EINVAL);
2152 trunk_nr = e1_trunk_nr_from_epname("xxxxxx4zyz");
2153 OSMO_ASSERT(trunk_nr == -EINVAL);
2154 trunk_nr = e1_trunk_nr_from_epname("ds/e1+2/s-1/su16-0");
2155 OSMO_ASSERT(trunk_nr == -EINVAL);
2156 trunk_nr = e1_trunk_nr_from_epname("ds/e2-24/s-1/su16-0");
2157 OSMO_ASSERT(trunk_nr == -EINVAL);
2158 trunk_nr = e1_trunk_nr_from_epname("ds/e1-24s-1/su16-0");
2159 OSMO_ASSERT(trunk_nr == -EINVAL);
2160
2161 return;
2162}
2163
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002164void test_mgcp_is_rtp_dummy_payload()
2165{
2166 /* realistic rtp packet */
2167 static const char rtp_payload[] =
2168 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2169 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2170 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2171 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2172 0x24 };
2173
2174 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2175 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2176 struct msgb *msg_dummy_rtp =
2177 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2178
2179 uint8_t *buf;
2180
2181 /* Dummy RTP packet */
2182 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2183 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2184
2185 /* Normal RTP packet */
2186 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2187 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2188
2189 /* Dummy RTP packet with normal RTP packet attached, this must not be
2190 * recognized as Dummy RTP packet */
2191 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2192 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2193 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2194 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2195
2196 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2197 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2198 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2199
2200 msgb_free(msg_dummy);
2201 msgb_free(msg_rtp);
2202 msgb_free(msg_dummy_rtp);
2203}
2204
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002205int main(int argc, char **argv)
2206{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002207 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2208 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2209 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002210
2211 test_strline();
2212 test_values();
2213 test_messages();
2214 test_retransmission();
2215 test_packet_loss_calc();
2216 test_rqnt_cb();
2217 test_mgcp_stats();
2218 test_packet_error_detection(1, 0);
2219 test_packet_error_detection(0, 0);
2220 test_packet_error_detection(0, 1);
2221 test_packet_error_detection(1, 1);
2222 test_multilple_codec();
2223 test_no_cycle();
2224 test_no_name();
2225 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002226 test_get_lco_identifier();
2227 test_check_local_cx_options(ctx);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002228 test_mgcp_codec_pt_translate();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002229 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002230 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002231 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002232
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002233 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2234 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2235 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002236 printf("Done\n");
2237 return EXIT_SUCCESS;
2238}