blob: 2ca0b4c02f70f13d1f8c4d092b3795f3d006c998 [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
Philipp Maier3d9b6562017-10-13 18:33:44 +0200637 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200638}
639
640static int64_t force_monotonic_time_us = -1;
641/* override and forward */
642int clock_gettime(clockid_t clk_id, struct timespec *tp)
643{
644 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
645 static clock_gettime_t real_clock_gettime = NULL;
646
647 if (!real_clock_gettime)
648 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
649
650 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
651 tp->tv_sec = force_monotonic_time_us / 1000000;
652 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
653 return 0;
654 }
655
656 return real_clock_gettime(clk_id, tp);
657}
658
Philipp Maier14b27a82020-06-02 20:15:30 +0200659static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200660{
661 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200662 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200663 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200664}
665
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200666#define CONN_UNMODIFIED (0x1000)
667
668static void test_values(void)
669{
670 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200671 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200672
673 /* Check that LOOPBACK enables all output */
674 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200675 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200676}
677
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200678/* Extract a connection ID from a response and return in conn_id;
679 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100680static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200681 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100682{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200683 const char *conn_id_start;
684 const char *conn_id_end;
685 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100686
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200687 const char *header_I = "\r\nI: ";
688 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100689
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200690 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
691 if ((conn_id_start = strstr((char *)resp, header_I))) {
692 conn_id_start += strlen(header_I);
693 conn_id_end = strstr(conn_id_start, "\r\n");
694 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
695 conn_id_start += strlen(header_o);
696 conn_id_end = strchr(conn_id_start, ' ');
697 } else
698 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100699
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200700 if (conn_id_end)
701 conn_id_len = conn_id_end - conn_id_start;
702 else
703 conn_id_len = strlen(conn_id_start);
704 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100705
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200706 /* A valid conn_id must at least contain one digit, and must
707 * not exceed a length of 32 digits */
708 OSMO_ASSERT(conn_id_len <= 32);
709 OSMO_ASSERT(conn_id_len > 0);
710
711 strncpy(conn_id, conn_id_start, conn_id_len);
712 conn_id[conn_id_len] = '\0';
713 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100714}
715
716/* Check response, automatically patch connection ID if needed */
717static int check_response(uint8_t *resp, const char *exp_resp)
718{
719 char exp_resp_patched[4096];
720 const char *exp_resp_ptr;
721 char conn_id[256];
722
723 printf("checking response:\n");
724
725 /* If the expected response is intened to be patched
726 * (%s placeholder inside) we will patch it with the
727 * connection identifier we just received from the
728 * real response. This is necessary because the CI
729 * is generated by the mgcp code on CRCX and we can
730 * not know it in advance */
731 if (strstr(exp_resp, "%s")) {
732 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
733 0) {
734 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
735 exp_resp_ptr = exp_resp_patched;
736 printf
737 ("using message with patched conn_id for comparison\n");
738 } else {
739 printf
740 ("patching conn_id failed, using message as statically defined for comparison\n");
741 exp_resp_ptr = exp_resp;
742 }
743 } else {
744 printf("using message as statically defined for comparison\n");
745 exp_resp_ptr = exp_resp;
746 }
747
748 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
749 printf("Unexpected response, please check!\n");
750 printf
751 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
752 resp);
753 printf
754 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
755 exp_resp_ptr);
756 return -EINVAL;
757 }
758
759 printf("Response matches our expectations.\n");
760 return 0;
761}
762
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200763static void test_messages(void)
764{
765 struct mgcp_config *cfg;
766 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200767 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200768 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200769 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100770 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100771 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200772
773 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200774 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200775
Philipp Maier889fe7f2020-07-06 17:44:12 +0200776 trunk->v.vty_number_endpoints = 64;
777 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200778 cfg->policy_cb = mgcp_test_policy_cb;
779
Philipp Maierffd75e42017-11-22 11:44:50 +0100780 memset(last_conn_id, 0, sizeof(last_conn_id));
781
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200782 for (i = 0; i < ARRAY_SIZE(tests); i++) {
783 const struct mgcp_test *t = &tests[i];
784 struct msgb *inp;
785 struct msgb *msg;
786
Philipp Maierffd75e42017-11-22 11:44:50 +0100787 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200788 printf("Testing %s\n", t->name);
789
Philipp Maier37a808c2020-07-03 15:48:31 +0200790 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200791 dummy_packets = 0;
792
Philipp Maierd19de2e2020-06-03 13:55:33 +0200793 osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200794 t->extra_fmtp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200795
Philipp Maierffd75e42017-11-22 11:44:50 +0100796 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200797 msg = mgcp_handle_message(cfg, inp);
798 msgb_free(inp);
799 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200800 if (msg) {
801 printf("%s failed '%s'\n", t->name,
802 (char *)msg->data);
803 OSMO_ASSERT(false);
804 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100805 } else if (check_response(msg->data, t->exp_resp) != 0) {
806 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200807 OSMO_ASSERT(false);
808 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100809
Philipp Maier7df419b2017-12-04 17:11:42 +0100810 if (msg) {
811 rc = get_conn_id_from_response(msg->data, last_conn_id,
812 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200813 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100814 printf("(response contains a connection id)\n");
815 else
816 printf("(response does not contain a connection id)\n");
817 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100818
Philipp Maiera330b862017-12-04 17:16:16 +0100819 if (msg)
820 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200821
822 if (dummy_packets)
823 printf("Dummy packets: %d\n", dummy_packets);
824
Philipp Maier37a808c2020-07-03 15:48:31 +0200825 if (last_endpoint[0] != '\0') {
826 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
827 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200828
Philipp Maier01d24a32017-11-21 17:26:09 +0100829 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200830 if (conn) {
831 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200832
Philipp Maier87bd9be2017-08-22 16:35:41 +0200833 if (conn->end.packet_duration_ms != -1)
834 printf("Detected packet duration: %d\n",
835 conn->end.packet_duration_ms);
836 else
837 printf("Packet duration not set\n");
838 if (endp->local_options.pkt_period_min ||
839 endp->local_options.pkt_period_max)
840 printf
841 ("Requested packetetization period: "
842 "%d-%d\n",
843 endp->local_options.pkt_period_min,
844 endp->
845 local_options.pkt_period_max);
846 else
847 printf
848 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200849
Philipp Maier87bd9be2017-08-22 16:35:41 +0200850 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
851 printf("Connection mode: %d:%s%s%s%s\n",
852 conn->conn->mode,
853 !conn->conn->mode ? " NONE" : "",
854 conn->conn->mode & MGCP_CONN_SEND_ONLY
855 ? " SEND" : "",
856 conn->conn->mode & MGCP_CONN_RECV_ONLY
857 ? " RECV" : "",
858 conn->conn->mode & MGCP_CONN_LOOPBACK
859 & ~MGCP_CONN_RECV_SEND
860 ? " LOOP" : "");
861 fprintf(stderr,
862 "RTP output %sabled, NET output %sabled\n",
863 conn->end.output_enabled
864 ? "en" : "dis",
865 conn->end.output_enabled
866 ? "en" : "dis");
867 } else
868 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200869
Philipp Maier87bd9be2017-08-22 16:35:41 +0200870 OSMO_ASSERT(conn->end.output_enabled
871 == (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
872
873 conn->conn->mode |= CONN_UNMODIFIED;
874
875 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200876 endp->local_options.pkt_period_min = 0;
877 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200878 }
879
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200880 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100881 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200882 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200883
Philipp Maier37a808c2020-07-03 15:48:31 +0200884 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200885 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200886 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200887 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200888
Philipp Maier87bd9be2017-08-22 16:35:41 +0200889 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200890 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200891 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200892
893 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200894 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200895 }
896 }
897
Philipp Maierd19de2e2020-06-03 13:55:33 +0200898 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200899 talloc_free(cfg);
900}
901
902static void test_retransmission(void)
903{
904 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200905 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200906 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100907 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100908 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200909
910 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200911 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200912
Philipp Maier889fe7f2020-07-06 17:44:12 +0200913 trunk->v.vty_number_endpoints = 64;
914 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200915
Philipp Maierffd75e42017-11-22 11:44:50 +0100916 memset(last_conn_id, 0, sizeof(last_conn_id));
917
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200918 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
919 const struct mgcp_test *t = &retransmit[i];
920 struct msgb *inp;
921 struct msgb *msg;
922
Philipp Maierffd75e42017-11-22 11:44:50 +0100923 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200924 printf("Testing %s\n", t->name);
925
Philipp Maierffd75e42017-11-22 11:44:50 +0100926 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200927 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200928
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200929 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100930 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200931 printf("%s failed '%s'\n", t->name, (char *)msg->data);
932 OSMO_ASSERT(false);
933 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100934
Philipp Maier23b8e292017-12-04 16:48:45 +0100935 if (msg && strcmp(t->name, "CRCX") == 0) {
936 rc = get_conn_id_from_response(msg->data, last_conn_id,
937 sizeof(last_conn_id));
938 OSMO_ASSERT(rc == 0);
939 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100940
Philipp Maier7cedfd72017-12-04 16:49:12 +0100941 if (msg)
942 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200943
944 /* Retransmit... */
945 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100946 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200947 msg = mgcp_handle_message(cfg, inp);
948 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100949 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200950 printf("%s failed '%s'\n", t->name, (char *)msg->data);
951 OSMO_ASSERT(false);
952 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200953 msgb_free(msg);
954 }
955
Philipp Maierd19de2e2020-06-03 13:55:33 +0200956 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200957 talloc_free(cfg);
958}
959
960static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
961{
962 ptrdiff_t tone = _tone;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200963 endp->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200964 return 0;
965}
966
967static void test_rqnt_cb(void)
968{
969 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200970 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200971 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100972 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200973
974 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200975 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200976 cfg->rqnt_cb = rqnt_cb;
977
Philipp Maier889fe7f2020-07-06 17:44:12 +0200978 trunk->v.vty_number_endpoints = 64;
979 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200980
Philipp Maierffd75e42017-11-22 11:44:50 +0100981 inp = create_msg(CRCX, NULL);
982 msg = mgcp_handle_message(cfg, inp);
983 OSMO_ASSERT(msg);
984 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
985 sizeof(conn_id)) == 0);
986 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200987 msgb_free(inp);
988
989 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +0100990 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200991 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200992 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200993 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
994 abort();
995 }
996
Philipp Maier87bd9be2017-08-22 16:35:41 +0200997 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200998 printf("FAILED: callback not called: %p\n", cfg->data);
999 abort();
1000 }
1001
1002 msgb_free(msg);
1003 msgb_free(inp);
1004
Philipp Maierffd75e42017-11-22 11:44:50 +01001005 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001006 msgb_free(mgcp_handle_message(cfg, inp));
1007 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001008 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001009 talloc_free(cfg);
1010}
1011
1012struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001013 int cycles;
1014 uint16_t base_seq;
1015 uint16_t max_seq;
1016 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001017
Philipp Maier87bd9be2017-08-22 16:35:41 +02001018 uint32_t expected;
1019 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001020};
1021
1022static const struct pl_test pl_test_dat[] = {
1023 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001024 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1025 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001026 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001027 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1028 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001029 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001030 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1031 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001033 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1034 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001035 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001036 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1037 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001038};
1039
1040static void test_packet_loss_calc(void)
1041{
1042 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001043 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001044 struct mgcp_endpoint *endpoints[1];
Oliver Smithe36b7752019-01-22 16:31:36 +01001045 struct mgcp_config cfg = {0};
Philipp Maier14b27a82020-06-02 20:15:30 +02001046 struct mgcp_trunk trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001047
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001048 printf("Testing packet loss calculation.\n");
1049
Philipp Maiercede2a42018-07-03 14:14:21 +02001050 memset(&endp, 0, sizeof(endp));
1051 memset(&trunk, 0, sizeof(trunk));
1052
Oliver Smithe36b7752019-01-22 16:31:36 +01001053 endp.cfg = &cfg;
Philipp Maiercede2a42018-07-03 14:14:21 +02001054 endp.type = &ep_typeset.rtp;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001055 trunk.v.vty_number_endpoints = 1;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001056 trunk.endpoints = endpoints;
1057 trunk.endpoints[0] = &endp;
Philipp Maier14b27a82020-06-02 20:15:30 +02001058 endp.trunk = &trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001059 INIT_LLIST_HEAD(&endp.conns);
1060
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001061 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1062 uint32_t expected;
1063 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001064
Philipp Maiercede2a42018-07-03 14:14:21 +02001065 struct mgcp_conn_rtp *conn = NULL;
1066 struct mgcp_conn *_conn = NULL;
1067 struct mgcp_rtp_state *state;
1068 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001069
Philipp Maiercede2a42018-07-03 14:14:21 +02001070 _conn =
1071 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1072 "test-connection");
1073 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1074 state = &conn->state;
Pau Espin Pedrol907744e2021-06-04 17:57:34 +02001075 packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001076
1077 state->stats.initialized = 1;
1078 state->stats.base_seq = pl_test_dat[i].base_seq;
1079 state->stats.max_seq = pl_test_dat[i].max_seq;
1080 state->stats.cycles = pl_test_dat[i].cycles;
1081
1082 packets_rx->current = pl_test_dat[i].packets;
1083 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001084
Philipp Maier87bd9be2017-08-22 16:35:41 +02001085 if (loss != pl_test_dat[i].loss
1086 || expected != pl_test_dat[i].expected) {
1087 printf
1088 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1089 i, loss, pl_test_dat[i].loss, expected,
1090 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001091 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001092
1093 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001094 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001095
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001096}
1097
Philipp Maier87bd9be2017-08-22 16:35:41 +02001098int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1099 uint32_t *pr, uint32_t *_or, int *loss,
1100 uint32_t *jitter)
1101{
1102 char *line, *save;
1103 int rc;
1104
1105 /* initialize with bad values */
1106 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1107 *loss = INT_MAX;
1108
1109 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1110 if (!line)
1111 return -1;
1112
1113 /* this can only parse the message that is created above... */
1114 for_each_non_empty_line(line, save) {
1115 switch (line[0]) {
1116 case 'P':
1117 rc = sscanf(line,
1118 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1119 ps, os, pr, _or, loss, jitter);
1120 return rc == 6 ? 0 : -1;
1121 }
1122 }
1123
1124 return -1;
1125}
1126
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001127static void test_mgcp_stats(void)
1128{
1129 printf("Testing stat parsing\n");
1130
1131 uint32_t bps, bos, pr, _or, jitter;
1132 struct msgb *msg;
1133 int loss;
1134 int rc;
1135
Philipp Maierffd75e42017-11-22 11:44:50 +01001136 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001137 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1138 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001139 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1140 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001141 printf("FAIL: Parsing failed1.\n");
1142 msgb_free(msg);
1143
Philipp Maier87bd9be2017-08-22 16:35:41 +02001144 msg =
1145 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001146 ("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 +02001147 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1148 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001149 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1150 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001151 printf("FAIL: Parsing failed2.\n");
1152 msgb_free(msg);
1153}
1154
1155struct rtp_packet_info {
1156 float txtime;
1157 int len;
1158 char *data;
1159};
1160
1161struct rtp_packet_info test_rtp_packets1[] = {
1162 /* RTP: SeqNo=0, TS=0 */
1163 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001164 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001165 /* RTP: SeqNo=1, TS=160 */
1166 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001167 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001168 /* RTP: SeqNo=2, TS=320 */
1169 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001170 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001171 /* Repeat RTP timestamp: */
1172 /* RTP: SeqNo=3, TS=320 */
1173 {0.060000, 20, "\x80\x62\x00\x03\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 /* RTP: SeqNo=4, TS=480 */
1176 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001177 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001178 /* RTP: SeqNo=5, TS=640 */
1179 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001180 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001181 /* Double skip RTP timestamp (delta = 2*160): */
1182 /* RTP: SeqNo=6, TS=960 */
1183 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\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 /* RTP: SeqNo=7, TS=1120 */
1186 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001187 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001188 /* RTP: SeqNo=8, TS=1280 */
1189 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001190 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001191 /* Non 20ms RTP timestamp (delta = 120): */
1192 /* RTP: SeqNo=9, TS=1400 */
1193 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\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 /* RTP: SeqNo=10, TS=1560 */
1196 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001197 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001198 /* RTP: SeqNo=11, TS=1720 */
1199 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001200 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001201 /* SSRC changed to 0x10203040, RTP timestamp jump */
1202 /* RTP: SeqNo=12, TS=34688 */
1203 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001204 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001205 /* RTP: SeqNo=13, TS=34848 */
1206 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001207 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001208 /* RTP: SeqNo=14, TS=35008 */
1209 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001210 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001211 /* Non 20ms RTP timestamp (delta = 120): */
1212 /* RTP: SeqNo=15, TS=35128 */
1213 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\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 /* RTP: SeqNo=16, TS=35288 */
1216 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001217 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001218 /* RTP: SeqNo=17, TS=35448 */
1219 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001220 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001221 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1222 /* RTP: SeqNo=19, TS=35768 */
1223 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001224 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001225 /* RTP: SeqNo=20, TS=35928 */
1226 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001227 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001228 /* RTP: SeqNo=21, TS=36088 */
1229 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001230 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001231 /* Repeat last packet */
1232 /* RTP: SeqNo=21, TS=36088 */
1233 {0.400000, 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 /* RTP: SeqNo=22, TS=36248 */
1236 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001237 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001238 /* RTP: SeqNo=23, TS=36408 */
1239 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001240 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001241 /* Don't increment SeqNo but increment timestamp by 160 */
1242 /* RTP: SeqNo=23, TS=36568 */
1243 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\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 /* RTP: SeqNo=24, TS=36728 */
1246 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001247 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001248 /* RTP: SeqNo=25, TS=36888 */
1249 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001250 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001251 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1252 * SeqNo jump */
1253 /* RTP: SeqNo=1000, TS=160000 */
1254 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001255 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001256 /* RTP: SeqNo=1001, TS=160160 */
1257 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001258 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001259 /* RTP: SeqNo=1002, TS=160320 */
1260 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001261 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001262};
1263
Philipp Maier87bd9be2017-08-22 16:35:41 +02001264void mgcp_patch_and_count(struct mgcp_endpoint *endp,
1265 struct mgcp_rtp_state *state,
1266 struct mgcp_rtp_end *rtp_end,
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001267 struct osmo_sockaddr *addr, struct msgb *msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001268
1269static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1270{
1271 int i;
1272
Philipp Maier14b27a82020-06-02 20:15:30 +02001273 struct mgcp_trunk trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001274 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001275 struct mgcp_endpoint *endpoints[1];
Oliver Smithe36b7752019-01-22 16:31:36 +01001276 struct mgcp_config cfg = {0};
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001277 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001278 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001279 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001280 uint32_t last_ssrc = 0;
1281 uint32_t last_timestamp = 0;
1282 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001283 uint64_t last_in_ts_err_cnt = 0;
1284 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001285 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001286 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001287 struct rate_ctr test_ctr_in;
1288 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001289
1290 printf("Testing packet error detection%s%s.\n",
1291 patch_ssrc ? ", patch SSRC" : "",
1292 patch_ts ? ", patch timestamps" : "");
1293
1294 memset(&trunk, 0, sizeof(trunk));
1295 memset(&endp, 0, sizeof(endp));
1296 memset(&state, 0, sizeof(state));
1297
Philipp Maier9e1d1642018-05-09 16:26:34 +02001298 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1299 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1300 state.in_stream.err_ts_ctr = &test_ctr_in;
1301 state.out_stream.err_ts_ctr = &test_ctr_out;
1302
Oliver Smithe36b7752019-01-22 16:31:36 +01001303 endp.cfg = &cfg;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001304 endp.type = &ep_typeset.rtp;
1305
Philipp Maier889fe7f2020-07-06 17:44:12 +02001306 trunk.v.vty_number_endpoints = 1;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001307 trunk.endpoints = endpoints;
1308 trunk.endpoints[0] = &endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001309 trunk.force_constant_ssrc = patch_ssrc;
1310 trunk.force_aligned_timing = patch_ts;
1311
Philipp Maier14b27a82020-06-02 20:15:30 +02001312 endp.trunk = &trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001313
Philipp Maier87bd9be2017-08-22 16:35:41 +02001314 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001315 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1316 "test-connection");
1317 OSMO_ASSERT(_conn);
1318 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001319 OSMO_ASSERT(conn);
1320
1321 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001322
Philipp Maier228e5912019-03-05 13:56:59 +01001323 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001324 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001325
1326 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1327 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001328 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001329
1330 force_monotonic_time_us = round(1000000.0 * info->txtime);
1331
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001332 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001333 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001334 msg->l3h = msgb_put(msg, info->len);
1335 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001336 mgcp_rtp_end_config(&endp, 1, rtp);
1337
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001338 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001339
1340 if (state.out_stream.ssrc != last_ssrc) {
1341 printf("Output SSRC changed to %08x\n",
1342 state.out_stream.ssrc);
1343 last_ssrc = state.out_stream.ssrc;
1344 }
1345
1346 printf("In TS: %d, dTS: %d, Seq: %d\n",
1347 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001348 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001349
1350 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001351 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001352 state.out_stream.last_timestamp - last_timestamp,
1353 state.out_stream.last_tsdelta,
1354 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001355 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1356 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001357
1358 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001359 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001360
Philipp Maier9e1d1642018-05-09 16:26:34 +02001361 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1362 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001363 last_timestamp = state.out_stream.last_timestamp;
1364 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001365
1366 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001367 }
1368
1369 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001370 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001371}
1372
1373static void test_multilple_codec(void)
1374{
1375 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001376 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001377 struct mgcp_endpoint *endp;
1378 struct msgb *inp, *resp;
1379 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001380 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001381 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001382
1383 printf("Testing multiple payload types\n");
1384
1385 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001386 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001387 trunk->v.vty_number_endpoints = 64;
1388 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001389 cfg->policy_cb = mgcp_test_policy_cb;
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001390
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001391 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001392 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001393 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001394 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001395 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1396 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001397 msgb_free(inp);
1398 msgb_free(resp);
1399
Philipp Maier37a808c2020-07-03 15:48:31 +02001400 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1401 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1402 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001403 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001404 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001405 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001406
1407 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001408 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001409 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001410 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001411 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1412 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001413 msgb_free(inp);
1414 msgb_free(resp);
1415
Philipp Maier37a808c2020-07-03 15:48:31 +02001416 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1417 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1418 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001419 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001420 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001421 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001422
Philipp Maierbc0346e2018-06-07 09:52:16 +02001423 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1424 /* Note: It usually makes no sense to leave the payload type list
1425 * out. However RFC 2327 does not clearly forbid this case and
1426 * it makes and since we already decided in OS#2658 that a missing
1427 * LCO should pick a sane default codec, it makes sense to expect
1428 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001429 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001430 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001431 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001432 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1433 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001434 msgb_free(inp);
1435 msgb_free(resp);
1436
Philipp Maier37a808c2020-07-03 15:48:31 +02001437 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1438 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1439 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001440 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001441 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001442 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001443
1444 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001445 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001446 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001447 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001448 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1449 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001450 msgb_free(inp);
1451 msgb_free(resp);
1452
Philipp Maier37a808c2020-07-03 15:48:31 +02001453 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1454 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1455 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001456 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001457 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001458 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001459
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001460 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
Philipp Maier37a808c2020-07-03 15:48:31 +02001461 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001462 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001463 trunk->no_audio_transcoding = 1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001464 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001465 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1466 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001467 msgb_free(inp);
1468 msgb_free(resp);
1469
Philipp Maier37a808c2020-07-03 15:48:31 +02001470 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1471 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1472 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001473 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001474 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001475 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001476
Philipp Maierffd75e42017-11-22 11:44:50 +01001477 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001478 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001479 resp = mgcp_handle_message(cfg, inp);
1480 msgb_free(inp);
1481 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001482 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1483 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1484 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001485 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001486 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001487 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001488 OSMO_ASSERT(conn->end.rtp_port == htons(16434));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001489 memset(&addr, 0, sizeof(addr));
1490 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001491 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1492 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001493
1494 /* Check what happens without that flag */
1495
Philipp Maier87bd9be2017-08-22 16:35:41 +02001496 /* Free the previous endpoint and the data and
1497 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001498 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001499 talloc_free(endp->last_response);
1500 talloc_free(endp->last_trans);
1501 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001502 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001503 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001504
Philipp Maier37a808c2020-07-03 15:48:31 +02001505 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001506 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001507 trunk->no_audio_transcoding = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001508 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001509 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1510 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001511 msgb_free(inp);
1512 msgb_free(resp);
1513
Philipp Maier37a808c2020-07-03 15:48:31 +02001514 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1515 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1516 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001517 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001518 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001519 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001520
Philipp Maierd19de2e2020-06-03 13:55:33 +02001521 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001522 talloc_free(cfg);
1523}
1524
1525static void test_no_cycle(void)
1526{
1527 struct mgcp_config *cfg;
1528 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001529 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001530 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001531 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001532
1533 printf("Testing no sequence flow on initial packet\n");
1534
1535 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001536 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001537 trunk->v.vty_number_endpoints = 64;
1538 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001539
Philipp Maier37a808c2020-07-03 15:48:31 +02001540 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1541 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001542
Philipp Maierffd75e42017-11-22 11:44:50 +01001543 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1544 "test-connection");
1545 OSMO_ASSERT(_conn);
1546 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001547 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001548
Harald Welte49e3d5a2017-12-25 09:47:57 +01001549 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001550
1551 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001552 OSMO_ASSERT(conn->state.stats.initialized == 1);
1553 OSMO_ASSERT(conn->state.stats.cycles == 0);
1554 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001555
1556 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001557 OSMO_ASSERT(conn->state.stats.initialized == 1);
1558 OSMO_ASSERT(conn->state.stats.cycles == 0);
1559 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001560
1561 /* now jump.. */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001562 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001563 OSMO_ASSERT(conn->state.stats.initialized == 1);
1564 OSMO_ASSERT(conn->state.stats.cycles == 0);
1565 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001566
1567 /* and wrap */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001568 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001569 OSMO_ASSERT(conn->state.stats.initialized == 1);
1570 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1571 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001572
Philipp Maierd19de2e2020-06-03 13:55:33 +02001573 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001574 talloc_free(cfg);
1575}
1576
1577static void test_no_name(void)
1578{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001579 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001580 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001581 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001582
1583 printf("Testing no rtpmap name\n");
1584 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001585 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001586
Philipp Maier889fe7f2020-07-06 17:44:12 +02001587 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001588 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001589 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001590
1591 cfg->policy_cb = mgcp_test_policy_cb;
1592
Philipp Maierffd75e42017-11-22 11:44:50 +01001593 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001594 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001595
1596 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001597 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001598 (char *)msg->data);
1599 OSMO_ASSERT(false);
1600 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001601 msgb_free(inp);
1602 msgb_free(msg);
1603
Philipp Maierd19de2e2020-06-03 13:55:33 +02001604 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001605 talloc_free(cfg);
1606}
1607
1608static void test_osmux_cid(void)
1609{
1610 int id, i;
1611
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001612 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1613
1614 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001615 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001616 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1617
1618 osmux_cid_pool_get(30);
1619 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1620 osmux_cid_pool_get(30);
1621 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1622
1623 osmux_cid_pool_put(id);
1624 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1625 osmux_cid_pool_put(30);
1626 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001627
1628 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001629 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001630 OSMO_ASSERT(id == i);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001631 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001632 }
1633
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001634 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001635 OSMO_ASSERT(id == -1);
1636
1637 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001638 osmux_cid_pool_put(i);
1639 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001640}
1641
1642static const struct log_info_cat log_categories[] = {
1643};
1644
1645const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001646 .cat = log_categories,
1647 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001648};
1649
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001650static void test_get_lco_identifier(void)
1651{
1652 char *test;
1653 printf("Testing get_lco_identifier()\n");
1654
1655 /* Normal case at the beginning */
1656 test = "p:10, a:PCMU";
1657 printf("%s -> %s\n", test, get_lco_identifier(test));
1658
1659 test = "p:10, a:PCMU";
1660 printf("%s -> %s\n", test, get_lco_identifier(test));
1661
1662 /* Begin parsing in the middle of the value part of
1663 * the previous LCO option value */
1664 test = "XXXX, p:10, a:PCMU";
1665 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1666
1667 test = "XXXX,p:10,a:PCMU";
1668 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1669
1670 test = "10,a:PCMU";
1671 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1672
1673 test = "10, a:PCMU";
1674 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1675
1676 test = "10,a: PCMU";
1677 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1678
1679 test = "10 ,a: PCMU";
1680 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1681
1682 /* Begin parsing right at the end of the previous LCO
1683 * option value */
1684 test = ", a:PCMU";
1685 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1686
1687 test = " a:PCMU";
1688 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1689
1690 /* Empty string, result should be (null) */
1691 test = "";
1692 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1693
1694 /* Missing colons, result should be (null) */
1695 test = "p10, aPCMU";
1696 printf("%s -> %s\n", test, get_lco_identifier(test));
1697
1698 /* Colon separated from the identifier, result should be (null) */
1699 test = "10,a :PCMU";
1700 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1701}
1702
1703static void test_check_local_cx_options(void *ctx)
1704{
1705 /* Legal cases */
1706 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1707 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1708 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1709 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1710 0);
1711 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1712 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1713 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1714 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1715 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1716
1717 /* Illegal spaces before and after colon */
1718 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1719 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1720 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1721
1722 /* Check if multiple appearances of LCOs are rejected */
1723 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1724 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1725 -1);
1726 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1727
1728 /* Check if empty LCO are rejected */
1729 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1730 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1731 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1732 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1733 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1734
1735 /* Garbeled beginning and ends */
1736 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1737 OSMO_ASSERT(check_local_cx_options(ctx, "10, 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 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1742
1743 /* Illegal strings */
1744 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1745 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1746 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1747 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1748 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1749 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1750}
1751
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001752static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1753 .amr_octet_aligned_present = true,
1754 .amr_octet_aligned = true,
1755};
1756
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001757static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1758 .amr_octet_aligned_present = true,
1759 .amr_octet_aligned = false,
1760};
1761
1762static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1763 .amr_octet_aligned_present = false,
1764};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001765
1766struct testcase_mgcp_codec_pt_translate_codec {
1767 int payload_type;
1768 const char *audio_name;
1769 const struct mgcp_codec_param *param;
1770 int expect_rc;
1771};
1772
1773struct testcase_mgcp_codec_pt_translate_expect {
1774 bool end;
1775 int payload_type_map[2];
1776};
1777
1778struct testcase_mgcp_codec_pt_translate {
1779 const char *descr;
1780 /* two conns on an endpoint, each with N configured codecs */
1781 struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
1782 struct testcase_mgcp_codec_pt_translate_expect expect[32];
1783};
1784
1785static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
1786 {
1787 .descr = "same order, but differing payload type numbers",
1788 .codecs = {
1789 {
1790 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1791 { 0, "PCMU/8000/1", NULL, },
1792 { 111, "GSM-HR-08/8000/1", NULL, },
1793 },
1794 {
1795 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1796 { 0, "PCMU/8000/1", NULL, },
1797 { 97, "GSM-HR-08/8000/1", NULL, },
1798 },
1799 },
1800 .expect = {
1801 { .payload_type_map = {112, 96}, },
1802 { .payload_type_map = {0, 0}, },
1803 { .payload_type_map = {111, 97} },
1804 { .payload_type_map = {123, -EINVAL} },
1805 { .end = true },
1806 },
1807 },
1808 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001809 .descr = "different order and different payload type numbers",
1810 .codecs = {
1811 {
1812 { 0, "PCMU/8000/1", NULL, },
1813 { 111, "GSM-HR-08/8000/1", NULL, },
1814 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1815 },
1816 {
1817 { 97, "GSM-HR-08/8000/1", NULL, },
1818 { 0, "PCMU/8000/1", NULL, },
1819 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1820 },
1821 },
1822 .expect = {
1823 { .payload_type_map = {112, 96}, },
1824 { .payload_type_map = {0, 0}, },
1825 { .payload_type_map = {111, 97} },
1826 { .payload_type_map = {123, -EINVAL} },
1827 { .end = true },
1828 },
1829 },
1830 {
1831 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1832 .codecs = {
1833 {
1834 { 0, "PCMU/8000/1", NULL, },
1835 { 96, "GSM-HR-08/8000/1", NULL, },
1836 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1837 },
1838 {
1839 { 97, "GSM-HR-08/8000/1", NULL, },
1840 { 0, "PCMU/8000/1", NULL, },
1841 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1842 },
1843 },
1844 .expect = {
1845 { .payload_type_map = {96, 97}, },
1846 { .payload_type_map = {97, 96}, },
1847 { .payload_type_map = {0, 0}, },
1848 { .end = true },
1849 },
1850 },
1851 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001852 .descr = "conn0 has no codecs",
1853 .codecs = {
1854 {
1855 /* no codecs */
1856 },
1857 {
1858 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1859 { 0, "PCMU/8000/1", NULL, },
1860 { 97, "GSM-HR-08/8000/1", NULL, },
1861 },
1862 },
1863 .expect = {
1864 { .payload_type_map = {112, -EINVAL}, },
1865 { .payload_type_map = {0, -EINVAL}, },
1866 { .payload_type_map = {111, -EINVAL} },
1867 { .end = true },
1868 },
1869 },
1870 {
1871 .descr = "conn1 has no codecs",
1872 .codecs = {
1873 {
1874 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1875 { 0, "PCMU/8000/1", NULL, },
1876 { 111, "GSM-HR-08/8000/1", NULL, },
1877 },
1878 {
1879 /* no codecs */
1880 },
1881 },
1882 .expect = {
1883 { .payload_type_map = {112, -EINVAL}, },
1884 { .payload_type_map = {0, -EINVAL}, },
1885 { .payload_type_map = {111, -EINVAL} },
1886 { .end = true },
1887 },
1888 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001889 {
1890 .descr = "test AMR with differing octet-aligned settings",
1891 .codecs = {
1892 {
1893 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1894 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1895 },
1896 {
1897 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1898 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1899 },
1900 },
1901 .expect = {
1902 { .payload_type_map = {111, 121}, },
1903 { .payload_type_map = {112, 122} },
1904 { .end = true },
1905 },
1906 },
1907 {
1908 .descr = "test AMR with missing octet-aligned settings (defaults to 0)",
1909 .codecs = {
1910 {
1911 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1912 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1913 },
1914 {
1915 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1916 },
1917 },
1918 .expect = {
1919 { .payload_type_map = {111, -EINVAL}, },
1920 { .payload_type_map = {112, 122} },
1921 { .end = true },
1922 },
1923 },
1924 {
1925 .descr = "test AMR with NULL param (defaults to 0)",
1926 .codecs = {
1927 {
1928 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1929 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1930 },
1931 {
1932 { 122, "AMR/8000", NULL, },
1933 },
1934 },
1935 .expect = {
1936 { .payload_type_map = {111, -EINVAL}, },
1937 { .payload_type_map = {112, 122} },
1938 { .end = true },
1939 },
1940 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02001941 {
1942 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
1943 .codecs = {
1944 {
1945 { 0, "PCMU/8000/1", NULL, },
1946 { 111, "GSM-HR-08/8000/1", NULL, },
1947 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1948 },
1949 {
1950 { 97, "GSM-HR-08/8000", NULL, },
1951 { 0, "PCMU/8000", NULL, },
1952 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
1953 },
1954 },
1955 .expect = {
1956 { .payload_type_map = {112, 96}, },
1957 { .payload_type_map = {0, 0}, },
1958 { .payload_type_map = {111, 97} },
1959 { .payload_type_map = {123, -EINVAL} },
1960 { .end = true },
1961 },
1962 },
1963 {
1964 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
1965 .codecs = {
1966 {
1967 { 0, "PCMU/8000/1", NULL, },
1968 { 111, "GSM-HR-08/8000/1", NULL, },
1969 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1970 },
1971 {
1972 { 97, "GSM-HR-08", NULL, },
1973 { 0, "PCMU", NULL, },
1974 { 96, "AMR", &amr_param_octet_aligned_true, },
1975 },
1976 },
1977 .expect = {
1978 { .payload_type_map = {112, 96}, },
1979 { .payload_type_map = {0, 0}, },
1980 { .payload_type_map = {111, 97} },
1981 { .payload_type_map = {123, -EINVAL} },
1982 { .end = true },
1983 },
1984 },
1985 {
1986 .descr = "test whether channel number matching is waterproof",
1987 .codecs = {
1988 {
1989 { 111, "GSM-HR-08/8000", },
1990 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
1991 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
1992 },
1993 {
1994 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
1995 { 121, "GSM-HR-08/8000/1", },
1996 },
1997 },
1998 .expect = {
1999 { .payload_type_map = {111, 121}, },
2000 { .payload_type_map = {112, -EINVAL} },
2001 { .payload_type_map = {113, -EINVAL} },
2002 { .end = true },
2003 },
2004 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002005};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002006
2007static void test_mgcp_codec_pt_translate(void)
2008{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002009 int i;
2010 bool ok = true;
2011 printf("\nTesting mgcp_codec_pt_translate()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002012
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002013 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
2014 const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
2015 struct mgcp_conn_rtp conn[2] = {};
2016 int rc;
2017 int conn_i;
2018 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002019
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002020 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002021
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002022 for (conn_i = 0; conn_i < 2; conn_i++) {
2023 printf(" - add codecs on conn%d:\n", conn_i);
2024 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
2025 const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
2026 if (!codec->audio_name)
2027 break;
2028
2029 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
2030
2031 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2032 codec->param ?
2033 (codec->param->amr_octet_aligned_present?
2034 (codec->param->amr_octet_aligned ?
2035 " octet-aligned=1" : " octet-aligned=0")
2036 : " octet-aligned=unset")
2037 : "",
2038 rc);
2039 if (rc != codec->expect_rc) {
2040 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2041 ok = false;
2042 }
2043 }
2044 if (!c)
2045 printf(" (none)\n");
2046 }
2047
2048 for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
2049 const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
2050 int result;
2051
2052 if (expect->end)
2053 break;
2054
2055 result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
2056 printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
2057 expect->payload_type_map[0], result);
2058 if (result != expect->payload_type_map[1]) {
2059 printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
2060 ok = false;
2061 }
2062
2063 /* If the expected result is an error, don't do reverse map test */
2064 if (expect->payload_type_map[1] < 0)
2065 continue;
2066
2067 result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
2068 printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
2069 expect->payload_type_map[1], result);
2070 if (result != expect->payload_type_map[0]) {
2071 printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
2072 ok = false;
2073 }
2074 }
2075
2076 for (conn_i = 0; conn_i < 2; conn_i++)
2077 mgcp_codec_reset_all(&conn[conn_i]);
2078 }
2079
2080 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002081}
2082
Neels Hofmeyr65317262018-09-03 22:11:05 +02002083void test_conn_id_matching()
2084{
2085 struct mgcp_endpoint endp = {};
2086 struct mgcp_conn *conn;
2087 struct mgcp_conn *conn_match;
2088 int i;
2089 const char *conn_id_generated = "000023AB";
2090 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002091 "23AB",
2092 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002093 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002094 "00000023AB",
2095 "23ab",
2096 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002097 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002098 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002099 };
2100
2101 printf("\nTesting %s\n", __func__);
2102
2103 INIT_LLIST_HEAD(&endp.conns);
2104
2105 conn = talloc_zero(NULL, struct mgcp_conn);
2106 OSMO_ASSERT(conn);
2107 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2108 llist_add(&conn->entry, &endp.conns);
2109
2110 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2111 const char *needle = conn_id_request[i];
2112 printf("needle='%s' ", needle);
2113 conn_match = mgcp_conn_get(&endp, needle);
2114 OSMO_ASSERT(conn_match);
2115 printf("found '%s'\n", conn_match->id);
2116 OSMO_ASSERT(conn_match == conn);
2117 }
2118
2119 llist_del(&conn->entry);
2120 talloc_free(conn);
2121}
2122
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002123void test_e1_trunk_nr_from_epname()
2124{
2125 int trunk_nr;
2126
2127 /* Note: e1_trunk_nr_from_epname does not check the text
2128 * after the E1 trunk number, after the delimiter
2129 * character "/" arbitrary text may follow. */
Philipp Maier0653cc82020-08-10 22:52:51 +02002130 trunk_nr = e1_trunk_nr_from_epname("ds/e1-0/s-1/su16-0");
2131 OSMO_ASSERT(trunk_nr == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002132 trunk_nr = e1_trunk_nr_from_epname("ds/e1-1/s-1/su16-0");
2133 OSMO_ASSERT(trunk_nr == 1);
2134 trunk_nr = e1_trunk_nr_from_epname("ds/e1-2/s-2/su16-0");
2135 OSMO_ASSERT(trunk_nr == 2);
2136 trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/s-23/su32-0");
2137 OSMO_ASSERT(trunk_nr == 3);
2138 trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/xxxxxxx");
2139 OSMO_ASSERT(trunk_nr == 3);
2140 trunk_nr = e1_trunk_nr_from_epname("ds/e1-24/s-1/su16-0");
2141 OSMO_ASSERT(trunk_nr == 24);
2142 trunk_nr = e1_trunk_nr_from_epname("ds/e1-64/s-1/su16-0");
2143 OSMO_ASSERT(trunk_nr == 64);
2144
2145 /* The following endpoint strings should fail, either the
2146 * trunk number exceeds the valid range or the trunk prefix
2147 * is wrong. Also when the delimiter character "/" at the
2148 * end of the trunk is wrong the parsing should fail. */
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002149 trunk_nr = e1_trunk_nr_from_epname("ds/e1-65/s-1/su16-0");
2150 OSMO_ASSERT(trunk_nr == -EINVAL);
2151 trunk_nr = e1_trunk_nr_from_epname("ds/e1--1/s-1/su16-0");
2152 OSMO_ASSERT(trunk_nr == -EINVAL);
2153 trunk_nr = e1_trunk_nr_from_epname("xxxxxx4zyz");
2154 OSMO_ASSERT(trunk_nr == -EINVAL);
2155 trunk_nr = e1_trunk_nr_from_epname("ds/e1+2/s-1/su16-0");
2156 OSMO_ASSERT(trunk_nr == -EINVAL);
2157 trunk_nr = e1_trunk_nr_from_epname("ds/e2-24/s-1/su16-0");
2158 OSMO_ASSERT(trunk_nr == -EINVAL);
2159 trunk_nr = e1_trunk_nr_from_epname("ds/e1-24s-1/su16-0");
2160 OSMO_ASSERT(trunk_nr == -EINVAL);
2161
2162 return;
2163}
2164
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002165void test_mgcp_is_rtp_dummy_payload()
2166{
2167 /* realistic rtp packet */
2168 static const char rtp_payload[] =
2169 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2170 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2171 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2172 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2173 0x24 };
2174
2175 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2176 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2177 struct msgb *msg_dummy_rtp =
2178 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2179
2180 uint8_t *buf;
2181
2182 /* Dummy RTP packet */
2183 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2184 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2185
2186 /* Normal RTP packet */
2187 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2188 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2189
2190 /* Dummy RTP packet with normal RTP packet attached, this must not be
2191 * recognized as Dummy RTP packet */
2192 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2193 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2194 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2195 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2196
2197 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2198 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2199 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2200
2201 msgb_free(msg_dummy);
2202 msgb_free(msg_rtp);
2203 msgb_free(msg_dummy_rtp);
2204}
2205
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002206int main(int argc, char **argv)
2207{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002208 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2209 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2210 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002211
2212 test_strline();
2213 test_values();
2214 test_messages();
2215 test_retransmission();
2216 test_packet_loss_calc();
2217 test_rqnt_cb();
2218 test_mgcp_stats();
2219 test_packet_error_detection(1, 0);
2220 test_packet_error_detection(0, 0);
2221 test_packet_error_detection(0, 1);
2222 test_packet_error_detection(1, 1);
2223 test_multilple_codec();
2224 test_no_cycle();
2225 test_no_name();
2226 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002227 test_get_lco_identifier();
2228 test_check_local_cx_options(ctx);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002229 test_mgcp_codec_pt_translate();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002230 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002231 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002232 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002233
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002234 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2235 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2236 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002237 printf("Done\n");
2238 return EXIT_SUCCESS;
2239}