blob: ffc8a202ef8952ac46dd8827c0ab6233e943e7c3 [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"
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +020080#define AUEP_NULL "AUEP 18983215 null@mgw MGCP 1.0\r\n"
81#define AUEP_NULL_RET "200 18983215 OK\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020082#define EMPTY "\r\n"
83#define EMPTY_RET NULL
84#define SHORT "CRCX \r\n"
85#define SHORT_RET "510 000000 FAIL\r\n"
86
Philipp Maier12943ea2018-01-17 15:40:25 +010087#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
Harald Welteabbb6b92017-12-28 13:13:50 +010088#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010089#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
Philipp Maierc66ab2c2020-06-02 20:55:34 +020090#define MDCX_RET "500 18983214 FAIL\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020091
Philipp Maier87bd9be2017-08-22 16:35:41 +020092#define MDCX3 \
93 "MDCX 18983215 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010094 "I: %s\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020095
Philipp Maier87bd9be2017-08-22 16:35:41 +020096#define MDCX3_RET \
97 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +010098 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020099 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100100 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200101 "s=-\r\n" \
102 "c=IN IP4 0.0.0.0\r\n" \
103 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100104 "m=audio 16002 RTP/AVP 97\r\n" \
105 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200106 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200107
Philipp Maier87bd9be2017-08-22 16:35:41 +0200108#define MDCX3A_RET \
109 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100110 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200111 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100112 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200113 "s=-\r\n" \
114 "c=IN IP4 0.0.0.0\r\n" \
115 "t=0 0\r\n" \
116 "m=audio 16002 RTP/AVP 97\r\n" \
117 "a=rtpmap:97 GSM-EFR/8000\r\n" \
118 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200119
Philipp Maier87bd9be2017-08-22 16:35:41 +0200120#define MDCX3_FMTP_RET \
121 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100122 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200123 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100124 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200125 "s=-\r\n" \
126 "c=IN IP4 0.0.0.0\r\n" \
127 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100128 "m=audio 16006 RTP/AVP 97\r\n" \
129 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200130 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200131
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200132#define MDCX4_ADDR0000 \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200133 "MDCX 18983216 1@mgw MGCP 1.0\r\n" \
134 "M: sendrecv\r" \
135 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100136 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200137 "L: p:20, a:AMR, nt:IN\r\n" \
138 "\n" \
139 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100140 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200141 "c=IN IP4 0.0.0.0\r\n" \
142 "t=0 0\r\n" \
143 "m=audio 4441 RTP/AVP 99\r\n" \
144 "a=rtpmap:99 AMR/8000\r\n" \
145 "a=ptime:40\r\n"
146
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200147#define MDCX4_ADDR0000_RET \
148 "527 18983216 FAIL\r\n"
149
150#define MDCX4 \
151 "MDCX 18983217 1@mgw MGCP 1.0\r\n" \
152 "M: sendrecv\r" \
153 "C: 2\r\n" \
154 "I: %s\r\n" \
155 "L: p:20, a:AMR, nt:IN\r\n" \
156 "\n" \
157 "v=0\r\n" \
158 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
159 "c=IN IP4 5.6.7.8\r\n" \
160 "t=0 0\r\n" \
161 "m=audio 4441 RTP/AVP 99\r\n" \
162 "a=rtpmap:99 AMR/8000\r\n" \
163 "a=ptime:40\r\n"
164
Philipp Maier87bd9be2017-08-22 16:35:41 +0200165#define MDCX4_RET(Ident) \
166 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100167 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200168 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100169 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200170 "s=-\r\n" \
171 "c=IN IP4 0.0.0.0\r\n" \
172 "t=0 0\r\n" \
173 "m=audio 16002 RTP/AVP 99\r\n" \
174 "a=rtpmap:99 AMR/8000\r\n" \
175 "a=ptime:40\r\n"
176
177#define MDCX4_RO_RET(Ident) \
178 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100179 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200180 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100181 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200182 "s=-\r\n" \
183 "c=IN IP4 0.0.0.0\r\n" \
184 "t=0 0\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200185 "m=audio 16002 RTP/AVP 112\r\n" \
186 "a=rtpmap:112 AMR\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200187 "a=ptime:40\r\n"
188
189#define MDCX4_PT1 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200190 "MDCX 18983218 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol17058482019-06-26 12:23:02 +0200191 "M: SENDRECV\r" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200192 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100193 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200194 "L: p:20-40, a:AMR, nt:IN\r\n" \
195 "\n" \
196 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200197 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
198 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200199 "t=0 0\r\n" \
200 "m=audio 4441 RTP/AVP 99\r\n" \
201 "a=rtpmap:99 AMR/8000\r\n" \
202 "a=ptime:40\r\n"
203
204#define MDCX4_PT2 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200205 "MDCX 18983219 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200206 "M: sendrecv\r" \
207 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100208 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200209 "L: p:20-20, a:AMR, nt:IN\r\n" \
210 "\n" \
211 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200212 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
213 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200214 "t=0 0\r\n" \
215 "m=audio 4441 RTP/AVP 99\r\n" \
216 "a=rtpmap:99 AMR/8000\r\n" \
217 "a=ptime:40\r\n"
218
219#define MDCX4_PT3 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200220 "MDCX 18983220 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200221 "M: sendrecv\r" \
222 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100223 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200224 "L: a:AMR, nt:IN\r\n" \
225 "\n" \
226 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200227 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
228 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200229 "t=0 0\r\n" \
230 "m=audio 4441 RTP/AVP 99\r\n" \
231 "a=rtpmap:99 AMR/8000\r\n" \
232 "a=ptime:40\r\n"
233
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200234/* Test different upper/lower case in options */
235#define MDCX4_PT4 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200236 "MDCX 18983221 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200237 "m: sendrecv\r" \
238 "c: 2\r\n" \
239 "i: %s\r\n" \
Pau Espin Pedrol83fd8a52019-06-26 12:55:26 +0200240 "l: A:amr, NT:IN\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200241 "\n" \
242 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200243 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
244 "c=IN IP4 5.6.7.8\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200245 "t=0 0\r\n" \
246 "m=audio 4441 RTP/AVP 99\r\n" \
247 "a=rtpmap:99 AMR/8000\r\n" \
248 "a=ptime:40\r\n"
249
250#define MDCX4_SO \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200251 "MDCX 18983222 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200252 "M: sendonly\r" \
253 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100254 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200255 "L: p:20, a:AMR, nt:IN\r\n" \
256 "\n" \
257 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200258 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
259 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200260 "t=0 0\r\n" \
261 "m=audio 4441 RTP/AVP 99\r\n" \
262 "a=rtpmap:99 AMR/8000\r\n" \
263 "a=ptime:40\r\n"
264
265#define MDCX4_RO \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200266 "MDCX 18983223 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200267 "M: recvonly\r" \
268 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100269 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200270 "L: p:20, a:AMR, nt:IN\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200271
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200272#define MDCX_TOO_LONG_CI \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200273 "MDCX 18983224 1@mgw MGCP 1.0\r\n" \
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200274 "I: 123456789012345678901234567890123\n"
275
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200276#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200277
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200278#define MDCX_NULL \
279 "MDCX 9 null@mgw MGCP 1.0\r\n" \
280 "I: %s\n"
281
282#define MDCX_NULL_RET "502 9 FAIL\r\n"
283
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200284#define SHORT2 "CRCX 1"
285#define SHORT2_RET "510 000000 FAIL\r\n"
286#define SHORT3 "CRCX 1 1@mgw"
287#define SHORT4 "CRCX 1 1@mgw MGCP"
288#define SHORT5 "CRCX 1 1@mgw MGCP 1.0"
289
Philipp Maier87bd9be2017-08-22 16:35:41 +0200290#define CRCX \
291 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200292 "m: recvonly\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200293 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200294 "L: p:20\r\n" \
295 "\r\n" \
296 "v=0\r\n" \
297 "c=IN IP4 123.12.12.123\r\n" \
298 "m=audio 5904 RTP/AVP 97\r\n" \
299 "a=rtpmap:97 GSM-EFR/8000\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_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 16002 RTP/AVP 97\r\n" \
312 "a=rtpmap:97 GSM-EFR/8000\r\n" \
313 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200314
Philipp Maier87bd9be2017-08-22 16:35:41 +0200315#define CRCX_RET_NO_RTPMAP \
316 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100317 "I: %s\r\n" \
318 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200319 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100320 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200321 "s=-\r\n" \
322 "c=IN IP4 0.0.0.0\r\n" \
323 "t=0 0\r\n" \
324 "m=audio 16002 RTP/AVP 97\r\n" \
325 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200326
Philipp Maier87bd9be2017-08-22 16:35:41 +0200327#define CRCX_FMTP_RET \
328 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100329 "I: %s\r\n" \
330 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200331 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100332 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200333 "s=-\r\n" \
334 "c=IN IP4 0.0.0.0\r\n" \
335 "t=0 0\r\n" \
336 "m=audio 16006 RTP/AVP 97\r\n" \
337 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200338 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200339
Philipp Maier87bd9be2017-08-22 16:35:41 +0200340#define CRCX_ZYN \
341 "CRCX 2 1@mgw MGCP 1.0\r" \
342 "M: recvonly\r" \
343 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200344 "\n" \
345 "v=0\r" \
346 "c=IN IP4 123.12.12.123\r" \
347 "m=audio 5904 RTP/AVP 97\r" \
348 "a=rtpmap:97 GSM-EFR/8000\r"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200349
Philipp Maier87bd9be2017-08-22 16:35:41 +0200350#define CRCX_ZYN_RET \
351 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100352 "I: %s\r\n" \
353 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200354 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100355 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200356 "s=-\r\n" \
357 "c=IN IP4 0.0.0.0\r\n" \
358 "t=0 0\r\n" \
359 "m=audio 16004 RTP/AVP 97\r\n" \
360 "a=rtpmap:97 GSM-EFR/8000\r\n" \
361 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200362
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200363#define CRCX_X_OSMO_IGN \
364 "CRCX 2 1@mgw MGCP 1.0\r\n" \
365 "M: recvonly\r\n" \
366 "C: 2\r\n" \
367 "L: p:20\r\n" \
Neels Hofmeyrf2388ea2018-08-26 23:36:53 +0200368 "X-Osmo-IGN: C foo\r\n" \
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200369 "\r\n" \
370 "v=0\r\n" \
371 "c=IN IP4 123.12.12.123\r\n" \
372 "m=audio 5904 RTP/AVP 97\r\n" \
373 "a=rtpmap:97 GSM-EFR/8000\r\n" \
374 "a=ptime:40\r\n"
375
376#define CRCX_X_OSMO_IGN_RET \
377 "200 2 OK\r\n" \
378 "I: %s\r\n" \
379 "\r\n" \
380 "v=0\r\n" \
381 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
382 "s=-\r\n" \
383 "c=IN IP4 0.0.0.0\r\n" \
384 "t=0 0\r\n" \
385 "m=audio 16010 RTP/AVP 97\r\n" \
386 "a=rtpmap:97 GSM-EFR/8000\r\n" \
387 "a=ptime:40\r\n"
388
Philipp Maier87bd9be2017-08-22 16:35:41 +0200389#define DLCX \
390 "DLCX 7 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100391 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200392 "C: 2\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200393
Philipp Maier87bd9be2017-08-22 16:35:41 +0200394#define DLCX_RET \
395 "250 7 OK\r\n" \
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100396 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
397
398 #define DLCX_RET_OSMUX DLCX_RET \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200399 "X-Osmo-CP: EC TI=0, TO=0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200400
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200401#define DLCX_NULL \
402 "DLCX 8 null@mgw MGCP 1.0\r\n" \
403 "I: %s\r\n" \
404 "C: 2\r\n"
405
406#define DLCX_NULL_RET "502 8 FAIL\r\n"
407
Philipp Maier87bd9be2017-08-22 16:35:41 +0200408#define RQNT \
409 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
410 "X: B244F267488\r\n" \
411 "S: D/9\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200412
Philipp Maier87bd9be2017-08-22 16:35:41 +0200413#define RQNT2 \
414 "RQNT 186908781 1@mgw MGCP 1.0\r\n" \
415 "X: ADD4F26746F\r\n" \
416 "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200417
418#define RQNT1_RET "200 186908780 OK\r\n"
419#define RQNT2_RET "200 186908781 OK\r\n"
420
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200421#define RQNT_NULL \
422 "RQNT 186908782 null@mgw MGCP 1.0\r\n" \
423 "X: B244F267488\r\n" \
424 "S: D/9\r\n"
425
426#define RQNT_NULL_RET "502 186908782 FAIL\r\n"
427
Philipp Maier87bd9be2017-08-22 16:35:41 +0200428#define PTYPE_IGNORE 0 /* == default initializer */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200429#define PTYPE_NONE 128
430#define PTYPE_NYI PTYPE_NONE
431
Philipp Maier87bd9be2017-08-22 16:35:41 +0200432#define CRCX_MULT_1 \
433 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200434 "M: recvonly\r\n" \
435 "C: 2\r\n" \
436 "X\r\n" \
437 "L: p:20\r\n" \
438 "\r\n" \
439 "v=0\r\n" \
440 "c=IN IP4 123.12.12.123\r\n" \
441 "m=audio 5904 RTP/AVP 18 97\r\n" \
442 "a=rtpmap:18 G729/8000\r\n" \
443 "a=rtpmap:97 GSM-EFR/8000\r\n" \
444 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200445
Philipp Maier87bd9be2017-08-22 16:35:41 +0200446#define CRCX_MULT_2 \
447 "CRCX 2 2@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200448 "M: recvonly\r\n" \
449 "C: 2\r\n" \
450 "X\r\n" \
451 "L: p:20\r\n" \
452 "\r\n" \
453 "v=0\r\n" \
454 "c=IN IP4 123.12.12.123\r\n" \
455 "m=audio 5904 RTP/AVP 18 97 101\r\n" \
456 "a=rtpmap:18 G729/8000\r\n" \
457 "a=rtpmap:97 GSM-EFR/8000\r\n" \
458 "a=rtpmap:101 FOO/8000\r\n" \
459 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200460
Philipp Maier87bd9be2017-08-22 16:35:41 +0200461#define CRCX_MULT_3 \
462 "CRCX 2 3@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200463 "M: recvonly\r\n" \
464 "C: 2\r\n" \
465 "X\r\n" \
466 "L: p:20\r\n" \
467 "\r\n" \
468 "v=0\r\n" \
469 "c=IN IP4 123.12.12.123\r\n" \
470 "m=audio 5904 RTP/AVP\r\n" \
471 "a=rtpmap:18 G729/8000\r\n" \
472 "a=rtpmap:97 GSM-EFR/8000\r\n" \
473 "a=rtpmap:101 FOO/8000\r\n" \
474 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200475
Philipp Maier87bd9be2017-08-22 16:35:41 +0200476#define CRCX_MULT_4 \
477 "CRCX 2 4@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200478 "M: recvonly\r\n" \
479 "C: 2\r\n" \
480 "X\r\n" \
481 "L: p:20\r\n" \
482 "\r\n" \
483 "v=0\r\n" \
484 "c=IN IP4 123.12.12.123\r\n" \
485 "m=audio 5904 RTP/AVP 18\r\n" \
486 "a=rtpmap:18 G729/8000\r\n" \
487 "a=rtpmap:97 GSM-EFR/8000\r\n" \
488 "a=rtpmap:101 FOO/8000\r\n" \
489 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200490
491#define CRCX_MULT_GSM_EXACT \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200492 "CRCX 259260421 5@mgw MGCP 1.0\r\n" \
493 "C: 1355c6041e\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200494 "L: p:20, a:GSM, nt:IN\r\n" \
495 "M: recvonly\r\n" \
496 "\r\n" \
497 "v=0\r\n" \
498 "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
499 "s=-\r\nc=IN IP4 192.168.181.247\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200500 "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 +0200501 "a=rtpmap:0 PCMU/8000\r\n" \
502 "a=rtpmap:8 PCMA/8000\r\n" \
503 "a=rtpmap:3 gsm/8000\r\n" \
504 "a=rtpmap:18 G729/8000\r\n" \
505 "a=fmtp:18 annexb=no\r\n" \
506 "a=rtpmap:4 G723/8000\r\n" \
507 "a=rtpmap:96 iLBC/8000\r\n" \
508 "a=fmtp:96 mode=20\r\n" \
509 "a=rtpmap:97 iLBC/8000\r\n" \
510 "a=fmtp:97 mode=30\r\n" \
511 "a=rtpmap:101 telephone-event/8000\r\n" \
512 "a=fmtp:101 0-15\r\n" \
513 "a=recvonly\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200514
Philipp Maier87bd9be2017-08-22 16:35:41 +0200515#define MDCX_NAT_DUMMY \
516 "MDCX 23 5@mgw MGCP 1.0\r\n" \
517 "C: 1355c6041e\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100518 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200519 "\r\n" \
520 "c=IN IP4 8.8.8.8\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200521 "m=audio 16434 RTP/AVP 3\r\n"
522
523#define CRCX_NO_LCO_NO_SDP \
524 "CRCX 2 6@mgw MGCP 1.0\r\n" \
525 "M: recvonly\r\n" \
526 "C: 2\r\n"
527
Philipp Maier228e5912019-03-05 13:56:59 +0100528#define CRCX_AMR_WITH_FMTP \
529 "CRCX 2 7@mgw MGCP 1.0\r\n" \
530 "M: recvonly\r\n" \
531 "C: 2\r\n" \
532 "X\r\n" \
533 "L: p:20\r\n" \
534 "\r\n" \
535 "v=0\r\n" \
536 "c=IN IP4 123.12.12.123\r\n" \
537 "m=audio 5904 RTP/AVP 111\r\n" \
538 "a=rtpmap:111 AMR/8000/1\r\n" \
539 "a=ptime:20\r\n" \
540 "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
541
542#define CRCX_AMR_WITH_FMTP_RET \
543 "200 2 OK\r\n" \
544 "I: %s\r\n" \
545 "\r\n" \
546 "v=0\r\n" \
547 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
548 "s=-\r\n" \
549 "c=IN IP4 0.0.0.0\r\n" \
550 "t=0 0\r\n" \
551 "m=audio 16012 RTP/AVP 111\r\n" \
552 "a=rtpmap:111 AMR/8000/1\r\n" \
553 "a=fmtp:111 octet-align=1\r\n" \
554 "a=ptime:20\r\n"
555
Philipp Maierbc0346e2018-06-07 09:52:16 +0200556#define CRCX_NO_LCO_NO_SDP_RET \
557 "200 2 OK\r\n" \
558 "I: %s\r\n" \
559 "\r\n" \
560 "v=0\r\n" \
561 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
562 "s=-\r\n" \
563 "c=IN IP4 0.0.0.0\r\n" \
564 "t=0 0\r\n" \
565 "m=audio 16008 RTP/AVP 0\r\n" \
566 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200567
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200568#define CRCX_NULL \
569 "CRCX 2 null@mgw MGCP 1.0\r\n" \
570 "m: recvonly\r\n" \
571 "C: 2\r\n" \
572 "L: p:20\r\n" \
573 "\r\n" \
574 "v=0\r\n" \
575 "c=IN IP4 123.12.12.123\r\n" \
576 "m=audio 5904 RTP/AVP 97\r\n" \
577 "a=rtpmap:97 GSM-EFR/8000\r\n" \
578 "a=ptime:40\r\n"
579
580#define CRCX_NULL_RET "502 2 FAIL\r\n"
581
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200582struct mgcp_test {
583 const char *name;
584 const char *req;
585 const char *exp_resp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200586 int ptype;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200587};
588
589static const struct mgcp_test tests[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200590 {"AUEP1", AUEP1, AUEP1_RET},
591 {"AUEP2", AUEP2, AUEP2_RET},
592 {"MDCX1", MDCX_WRONG_EP, MDCX_ERR_RET},
593 {"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
594 {"CRCX", CRCX, CRCX_RET, 97},
595 {"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200596 {"MDCX4_ADDR000", MDCX4_ADDR0000, MDCX4_ADDR0000_RET},
597 {"MDCX4", MDCX4, MDCX4_RET("18983217"), 99},
598 {"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983218"), 99},
599 {"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983219"), 99},
600 {"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983220"), 99},
601 {"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983221"), 99},
602 {"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983222"), 99},
603 {"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983223"), PTYPE_IGNORE},
Philipp Maier87bd9be2017-08-22 16:35:41 +0200604 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
605 {"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
606 {"EMPTY", EMPTY, EMPTY_RET},
607 {"SHORT1", SHORT, SHORT_RET},
608 {"SHORT2", SHORT2, SHORT2_RET},
609 {"SHORT3", SHORT3, SHORT2_RET},
610 {"SHORT4", SHORT4, SHORT2_RET},
611 {"RQNT1", RQNT, RQNT1_RET},
612 {"RQNT2", RQNT2, RQNT2_RET},
613 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
Neels Hofmeyrd0dbda42023-12-23 03:54:58 +0100614 {"CRCX", CRCX, CRCX_FMTP_RET, 97},
615 {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE},
616 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
Philipp Maierbc0346e2018-06-07 09:52:16 +0200617 {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200618 {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200619 {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
Philipp Maier228e5912019-03-05 13:56:59 +0100620 {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200621 {"AUEP_NULL", AUEP_NULL, AUEP_NULL_RET},
622 {"CRCX_NULL", CRCX_NULL, CRCX_NULL_RET},
623 {"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
624 {"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
625 {"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200626};
627
628static const struct mgcp_test retransmit[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200629 {"CRCX", CRCX, CRCX_RET},
630 {"RQNT1", RQNT, RQNT1_RET},
631 {"RQNT2", RQNT2, RQNT2_RET},
632 {"MDCX3", MDCX3, MDCX3A_RET},
633 {"DLCX", DLCX, DLCX_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200634};
635
Philipp Maierffd75e42017-11-22 11:44:50 +0100636static struct msgb *create_msg(const char *str, const char *conn_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200637{
638 struct msgb *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100639 int len;
640
641 printf("creating message from statically defined input:\n");
642 printf("---------8<---------\n%s\n---------8<---------\n", str);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200643
644 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
Philipp Maierffd75e42017-11-22 11:44:50 +0100645 if (conn_id && strlen(conn_id))
646 len = sprintf((char *)msg->data, str, conn_id, conn_id);
647 else
648 len = sprintf((char *)msg->data, "%s", str);
649
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200650 msg->l2h = msgb_put(msg, len);
651 return msg;
652}
653
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200654static int dummy_packets = 0;
655/* override and forward */
Harald Welte352b9672024-03-17 12:03:24 +0100656int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200657{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200658 uint32_t dest_host =
Harald Welte352b9672024-03-17 12:03:24 +0100659 htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
660 int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
661 const uint8_t *buf = msgb_data(msg);
662 size_t len = msgb_length(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200663
Philipp Maierb3d14eb2021-05-20 14:18:52 +0200664 if (len == sizeof(rtp_dummy_payload)
665 && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200666 fprintf(stderr,
667 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
668 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200669 dummy_packets += 1;
670 }
671
Pau Espin Pedrola24dcc62021-07-06 17:48:47 +0200672 /* Make sure address+port are valid */
673 OSMO_ASSERT(dest_host);
674 OSMO_ASSERT(dest_port);
675
Harald Welte352b9672024-03-17 12:03:24 +0100676 msgb_free(msg);
677
Philipp Maier3d9b6562017-10-13 18:33:44 +0200678 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200679}
680
681static int64_t force_monotonic_time_us = -1;
682/* override and forward */
683int clock_gettime(clockid_t clk_id, struct timespec *tp)
684{
685 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
686 static clock_gettime_t real_clock_gettime = NULL;
687
688 if (!real_clock_gettime)
689 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
690
691 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
692 tp->tv_sec = force_monotonic_time_us / 1000000;
693 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
694 return 0;
695 }
696
697 return real_clock_gettime(clk_id, tp);
698}
699
Philipp Maier14b27a82020-06-02 20:15:30 +0200700static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200701{
702 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200703 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200704 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200705}
706
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200707#define CONN_UNMODIFIED (0x1000)
708
709static void test_values(void)
710{
711 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200712 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200713
714 /* Check that LOOPBACK enables all output */
715 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200716 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200717}
718
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200719/* Extract a connection ID from a response and return in conn_id;
720 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100721static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200722 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100723{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200724 const char *conn_id_start;
725 const char *conn_id_end;
726 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100727
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200728 const char *header_I = "\r\nI: ";
729 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100730
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200731 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
732 if ((conn_id_start = strstr((char *)resp, header_I))) {
733 conn_id_start += strlen(header_I);
734 conn_id_end = strstr(conn_id_start, "\r\n");
735 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
736 conn_id_start += strlen(header_o);
737 conn_id_end = strchr(conn_id_start, ' ');
738 } else
739 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100740
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200741 if (conn_id_end)
742 conn_id_len = conn_id_end - conn_id_start;
743 else
744 conn_id_len = strlen(conn_id_start);
745 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100746
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200747 /* A valid conn_id must at least contain one digit, and must
748 * not exceed a length of 32 digits */
749 OSMO_ASSERT(conn_id_len <= 32);
750 OSMO_ASSERT(conn_id_len > 0);
751
752 strncpy(conn_id, conn_id_start, conn_id_len);
753 conn_id[conn_id_len] = '\0';
754 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100755}
756
757/* Check response, automatically patch connection ID if needed */
758static int check_response(uint8_t *resp, const char *exp_resp)
759{
760 char exp_resp_patched[4096];
761 const char *exp_resp_ptr;
762 char conn_id[256];
763
764 printf("checking response:\n");
765
766 /* If the expected response is intened to be patched
767 * (%s placeholder inside) we will patch it with the
768 * connection identifier we just received from the
769 * real response. This is necessary because the CI
770 * is generated by the mgcp code on CRCX and we can
771 * not know it in advance */
772 if (strstr(exp_resp, "%s")) {
773 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
774 0) {
775 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
776 exp_resp_ptr = exp_resp_patched;
777 printf
778 ("using message with patched conn_id for comparison\n");
779 } else {
780 printf
781 ("patching conn_id failed, using message as statically defined for comparison\n");
782 exp_resp_ptr = exp_resp;
783 }
784 } else {
785 printf("using message as statically defined for comparison\n");
786 exp_resp_ptr = exp_resp;
787 }
788
789 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
790 printf("Unexpected response, please check!\n");
791 printf
792 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
793 resp);
794 printf
795 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
796 exp_resp_ptr);
797 return -EINVAL;
798 }
799
800 printf("Response matches our expectations.\n");
801 return 0;
802}
803
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200804static void test_messages(void)
805{
806 struct mgcp_config *cfg;
807 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200808 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200809 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200810 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100811 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100812 int rc;
Philipp Maier39889e42021-08-04 17:42:57 +0200813 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200814
815 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200816 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200817
Philipp Maier889fe7f2020-07-06 17:44:12 +0200818 trunk->v.vty_number_endpoints = 64;
819 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200820
Philipp Maierffd75e42017-11-22 11:44:50 +0100821 memset(last_conn_id, 0, sizeof(last_conn_id));
822
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200823 for (i = 0; i < ARRAY_SIZE(tests); i++) {
824 const struct mgcp_test *t = &tests[i];
825 struct msgb *inp;
826 struct msgb *msg;
827
Philipp Maierffd75e42017-11-22 11:44:50 +0100828 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200829 printf("Testing %s\n", t->name);
830
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200831 dummy_packets = 0;
832
Philipp Maierffd75e42017-11-22 11:44:50 +0100833 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200834 msg = mgcp_handle_message(cfg, inp);
835 msgb_free(inp);
836 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200837 if (msg) {
838 printf("%s failed '%s'\n", t->name,
839 (char *)msg->data);
840 OSMO_ASSERT(false);
841 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100842 } else if (check_response(msg->data, t->exp_resp) != 0) {
843 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200844 OSMO_ASSERT(false);
845 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100846
Philipp Maier7df419b2017-12-04 17:11:42 +0100847 if (msg) {
848 rc = get_conn_id_from_response(msg->data, last_conn_id,
849 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200850 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100851 printf("(response contains a connection id)\n");
852 else
853 printf("(response does not contain a connection id)\n");
854 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100855
Philipp Maiera330b862017-12-04 17:16:16 +0100856 if (msg)
857 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200858
859 if (dummy_packets)
860 printf("Dummy packets: %d\n", dummy_packets);
861
Philipp Maier37a808c2020-07-03 15:48:31 +0200862 if (last_endpoint[0] != '\0') {
863 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
864 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200865
Philipp Maier01d24a32017-11-21 17:26:09 +0100866 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200867 if (conn) {
868 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200869
Philipp Maier87bd9be2017-08-22 16:35:41 +0200870 if (conn->end.packet_duration_ms != -1)
871 printf("Detected packet duration: %d\n",
872 conn->end.packet_duration_ms);
873 else
874 printf("Packet duration not set\n");
875 if (endp->local_options.pkt_period_min ||
876 endp->local_options.pkt_period_max)
877 printf
Oliver Smith169d50e2023-01-24 13:12:54 +0100878 ("Requested packetization period: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200879 "%d-%d\n",
880 endp->local_options.pkt_period_min,
881 endp->
882 local_options.pkt_period_max);
883 else
884 printf
885 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200886
Philipp Maier87bd9be2017-08-22 16:35:41 +0200887 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
888 printf("Connection mode: %d:%s%s%s%s\n",
889 conn->conn->mode,
890 !conn->conn->mode ? " NONE" : "",
891 conn->conn->mode & MGCP_CONN_SEND_ONLY
892 ? " SEND" : "",
893 conn->conn->mode & MGCP_CONN_RECV_ONLY
894 ? " RECV" : "",
895 conn->conn->mode & MGCP_CONN_LOOPBACK
896 & ~MGCP_CONN_RECV_SEND
897 ? " LOOP" : "");
898 fprintf(stderr,
899 "RTP output %sabled, NET output %sabled\n",
900 conn->end.output_enabled
901 ? "en" : "dis",
902 conn->end.output_enabled
903 ? "en" : "dis");
904 } else
905 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200906
Philipp Maier87bd9be2017-08-22 16:35:41 +0200907 OSMO_ASSERT(conn->end.output_enabled
Pau Espin Pedrol2c401642021-12-24 14:48:26 +0100908 == !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200909
910 conn->conn->mode |= CONN_UNMODIFIED;
911
912 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200913 endp->local_options.pkt_period_min = 0;
914 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200915 }
916
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200917 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100918 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200919 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200920
Philipp Maier37a808c2020-07-03 15:48:31 +0200921 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200922 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200923 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200924 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200925
Philipp Maier87bd9be2017-08-22 16:35:41 +0200926 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200927 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200928 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200929
930 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200931 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200932 }
933 }
934
Philipp Maierd19de2e2020-06-03 13:55:33 +0200935 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200936 talloc_free(cfg);
937}
938
939static void test_retransmission(void)
940{
941 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200942 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200943 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100944 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100945 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200946
947 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200948 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200949
Philipp Maier889fe7f2020-07-06 17:44:12 +0200950 trunk->v.vty_number_endpoints = 64;
951 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200952
Philipp Maierffd75e42017-11-22 11:44:50 +0100953 memset(last_conn_id, 0, sizeof(last_conn_id));
954
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200955 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
956 const struct mgcp_test *t = &retransmit[i];
957 struct msgb *inp;
958 struct msgb *msg;
959
Philipp Maierffd75e42017-11-22 11:44:50 +0100960 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200961 printf("Testing %s\n", t->name);
962
Philipp Maierffd75e42017-11-22 11:44:50 +0100963 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200964 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200965
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200966 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100967 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200968 printf("%s failed '%s'\n", t->name, (char *)msg->data);
969 OSMO_ASSERT(false);
970 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100971
Philipp Maier23b8e292017-12-04 16:48:45 +0100972 if (msg && strcmp(t->name, "CRCX") == 0) {
973 rc = get_conn_id_from_response(msg->data, last_conn_id,
974 sizeof(last_conn_id));
975 OSMO_ASSERT(rc == 0);
976 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100977
Philipp Maier7cedfd72017-12-04 16:49:12 +0100978 if (msg)
979 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200980
981 /* Retransmit... */
982 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100983 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200984 msg = mgcp_handle_message(cfg, inp);
985 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100986 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200987 printf("%s failed '%s'\n", t->name, (char *)msg->data);
988 OSMO_ASSERT(false);
989 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200990 msgb_free(msg);
991 }
992
Philipp Maierd19de2e2020-06-03 13:55:33 +0200993 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200994 talloc_free(cfg);
995}
996
997static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
998{
999 ptrdiff_t tone = _tone;
Ericfbf78d12021-08-23 22:31:39 +02001000 endp->trunk->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001001 return 0;
1002}
1003
1004static void test_rqnt_cb(void)
1005{
1006 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001007 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001008 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +01001009 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001010
1011 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001012 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001013 cfg->rqnt_cb = rqnt_cb;
1014
Philipp Maier889fe7f2020-07-06 17:44:12 +02001015 trunk->v.vty_number_endpoints = 64;
1016 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001017
Philipp Maierffd75e42017-11-22 11:44:50 +01001018 inp = create_msg(CRCX, NULL);
1019 msg = mgcp_handle_message(cfg, inp);
1020 OSMO_ASSERT(msg);
1021 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
1022 sizeof(conn_id)) == 0);
1023 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001024 msgb_free(inp);
1025
1026 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +01001027 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001028 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001029 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001030 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
1031 abort();
1032 }
1033
Philipp Maier87bd9be2017-08-22 16:35:41 +02001034 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001035 printf("FAILED: callback not called: %p\n", cfg->data);
1036 abort();
1037 }
1038
1039 msgb_free(msg);
1040 msgb_free(inp);
1041
Philipp Maierffd75e42017-11-22 11:44:50 +01001042 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001043 msgb_free(mgcp_handle_message(cfg, inp));
1044 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001045 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001046 talloc_free(cfg);
1047}
1048
1049struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001050 int cycles;
1051 uint16_t base_seq;
1052 uint16_t max_seq;
1053 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001054
Philipp Maier87bd9be2017-08-22 16:35:41 +02001055 uint32_t expected;
1056 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001057};
1058
1059static const struct pl_test pl_test_dat[] = {
1060 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001061 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1062 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001063 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001064 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1065 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001066 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001067 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1068 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001069 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001070 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1071 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001072 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001073 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1074 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001075};
1076
1077static void test_packet_loss_calc(void)
1078{
1079 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001080 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001081 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001082 struct mgcp_config *cfg;
1083 struct mgcp_trunk *trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001084
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001085 printf("Testing packet loss calculation.\n");
1086
Philipp Maiercede2a42018-07-03 14:14:21 +02001087 memset(&endp, 0, sizeof(endp));
Philipp Maier124a3e02021-07-26 11:17:15 +02001088 cfg = mgcp_config_alloc();
1089 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maiercede2a42018-07-03 14:14:21 +02001090 endp.type = &ep_typeset.rtp;
Philipp Maier124a3e02021-07-26 11:17:15 +02001091 trunk->v.vty_number_endpoints = 1;
1092 trunk->endpoints = endpoints;
1093 trunk->endpoints[0] = &endp;
1094 endp.trunk = trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001095 INIT_LLIST_HEAD(&endp.conns);
1096
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001097 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1098 uint32_t expected;
1099 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001100
Philipp Maiercede2a42018-07-03 14:14:21 +02001101 struct mgcp_conn_rtp *conn = NULL;
1102 struct mgcp_conn *_conn = NULL;
1103 struct mgcp_rtp_state *state;
1104 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001105
Philipp Maiercede2a42018-07-03 14:14:21 +02001106 _conn =
1107 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1108 "test-connection");
1109 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1110 state = &conn->state;
Pau Espin Pedroldaf5bce2022-09-22 19:14:24 +02001111 packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001112
1113 state->stats.initialized = 1;
1114 state->stats.base_seq = pl_test_dat[i].base_seq;
1115 state->stats.max_seq = pl_test_dat[i].max_seq;
1116 state->stats.cycles = pl_test_dat[i].cycles;
1117
1118 packets_rx->current = pl_test_dat[i].packets;
1119 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001120
Philipp Maier87bd9be2017-08-22 16:35:41 +02001121 if (loss != pl_test_dat[i].loss
1122 || expected != pl_test_dat[i].expected) {
1123 printf
1124 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1125 i, loss, pl_test_dat[i].loss, expected,
1126 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001127 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001128
1129 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001130 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001131
Philipp Maier124a3e02021-07-26 11:17:15 +02001132 talloc_free(trunk);
1133 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001134}
1135
Philipp Maier87bd9be2017-08-22 16:35:41 +02001136int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1137 uint32_t *pr, uint32_t *_or, int *loss,
1138 uint32_t *jitter)
1139{
1140 char *line, *save;
1141 int rc;
1142
1143 /* initialize with bad values */
1144 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1145 *loss = INT_MAX;
1146
1147 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1148 if (!line)
1149 return -1;
1150
1151 /* this can only parse the message that is created above... */
1152 for_each_non_empty_line(line, save) {
1153 switch (line[0]) {
1154 case 'P':
1155 rc = sscanf(line,
1156 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1157 ps, os, pr, _or, loss, jitter);
1158 return rc == 6 ? 0 : -1;
1159 }
1160 }
1161
1162 return -1;
1163}
1164
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001165static void test_mgcp_stats(void)
1166{
1167 printf("Testing stat parsing\n");
1168
1169 uint32_t bps, bos, pr, _or, jitter;
1170 struct msgb *msg;
1171 int loss;
1172 int rc;
1173
Philipp Maierffd75e42017-11-22 11:44:50 +01001174 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001175 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1176 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001177 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1178 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001179 printf("FAIL: Parsing failed1.\n");
1180 msgb_free(msg);
1181
Philipp Maier87bd9be2017-08-22 16:35:41 +02001182 msg =
1183 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001184 ("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 +02001185 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1186 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001187 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1188 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001189 printf("FAIL: Parsing failed2.\n");
1190 msgb_free(msg);
1191}
1192
1193struct rtp_packet_info {
1194 float txtime;
1195 int len;
1196 char *data;
1197};
1198
1199struct rtp_packet_info test_rtp_packets1[] = {
1200 /* RTP: SeqNo=0, TS=0 */
1201 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001202 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001203 /* RTP: SeqNo=1, TS=160 */
1204 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001205 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001206 /* RTP: SeqNo=2, TS=320 */
1207 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001208 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001209 /* Repeat RTP timestamp: */
1210 /* RTP: SeqNo=3, TS=320 */
1211 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001212 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001213 /* RTP: SeqNo=4, TS=480 */
1214 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001215 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001216 /* RTP: SeqNo=5, TS=640 */
1217 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001218 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001219 /* Double skip RTP timestamp (delta = 2*160): */
1220 /* RTP: SeqNo=6, TS=960 */
1221 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001222 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001223 /* RTP: SeqNo=7, TS=1120 */
1224 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001225 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001226 /* RTP: SeqNo=8, TS=1280 */
1227 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001228 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001229 /* Non 20ms RTP timestamp (delta = 120): */
1230 /* RTP: SeqNo=9, TS=1400 */
1231 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001232 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001233 /* RTP: SeqNo=10, TS=1560 */
1234 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001235 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001236 /* RTP: SeqNo=11, TS=1720 */
1237 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001238 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001239 /* SSRC changed to 0x10203040, RTP timestamp jump */
1240 /* RTP: SeqNo=12, TS=34688 */
1241 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001242 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001243 /* RTP: SeqNo=13, TS=34848 */
1244 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001245 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001246 /* RTP: SeqNo=14, TS=35008 */
1247 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001248 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001249 /* Non 20ms RTP timestamp (delta = 120): */
1250 /* RTP: SeqNo=15, TS=35128 */
1251 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001252 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001253 /* RTP: SeqNo=16, TS=35288 */
1254 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
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=17, TS=35448 */
1257 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001258 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001259 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1260 /* RTP: SeqNo=19, TS=35768 */
1261 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001262 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001263 /* RTP: SeqNo=20, TS=35928 */
1264 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001265 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001266 /* RTP: SeqNo=21, TS=36088 */
1267 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001268 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001269 /* Repeat last packet */
1270 /* RTP: SeqNo=21, TS=36088 */
1271 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001272 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001273 /* RTP: SeqNo=22, TS=36248 */
1274 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001275 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001276 /* RTP: SeqNo=23, TS=36408 */
1277 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001278 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001279 /* Don't increment SeqNo but increment timestamp by 160 */
1280 /* RTP: SeqNo=23, TS=36568 */
1281 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001282 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001283 /* RTP: SeqNo=24, TS=36728 */
1284 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001285 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001286 /* RTP: SeqNo=25, TS=36888 */
1287 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001288 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001289 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1290 * SeqNo jump */
1291 /* RTP: SeqNo=1000, TS=160000 */
1292 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001293 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001294 /* RTP: SeqNo=1001, TS=160160 */
1295 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001296 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001297 /* RTP: SeqNo=1002, TS=160320 */
1298 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001299 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001300 /* RTP: SeqNo=1003, TS=180320, Marker */
1301 {2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
1302 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1303 /* RTP: SeqNo=1004, TS=180480 */
1304 {2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
1305 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1306 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
1307 {2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
1308 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001309};
1310
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001311static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1312{
1313 int i;
1314
Philipp Maier124a3e02021-07-26 11:17:15 +02001315 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001316 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001317 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001318 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001319 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001320 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001321 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001322 uint32_t last_ssrc = 0;
1323 uint32_t last_timestamp = 0;
1324 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001325 uint64_t last_in_ts_err_cnt = 0;
1326 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001327 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001328 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001329 struct rate_ctr test_ctr_in;
1330 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001331
1332 printf("Testing packet error detection%s%s.\n",
1333 patch_ssrc ? ", patch SSRC" : "",
1334 patch_ts ? ", patch timestamps" : "");
1335
Philipp Maier124a3e02021-07-26 11:17:15 +02001336 cfg = mgcp_config_alloc();
1337 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001338 memset(&endp, 0, sizeof(endp));
1339 memset(&state, 0, sizeof(state));
1340
Philipp Maier9e1d1642018-05-09 16:26:34 +02001341 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1342 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1343 state.in_stream.err_ts_ctr = &test_ctr_in;
1344 state.out_stream.err_ts_ctr = &test_ctr_out;
1345
Philipp Maier87bd9be2017-08-22 16:35:41 +02001346 endp.type = &ep_typeset.rtp;
1347
Philipp Maier124a3e02021-07-26 11:17:15 +02001348 trunk->v.vty_number_endpoints = 1;
1349 trunk->endpoints = endpoints;
1350 trunk->endpoints[0] = &endp;
1351 trunk->force_constant_ssrc = patch_ssrc;
1352 trunk->force_aligned_timing = patch_ts;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001353
Philipp Maier124a3e02021-07-26 11:17:15 +02001354 endp.trunk = trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001355
Philipp Maier87bd9be2017-08-22 16:35:41 +02001356 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001357 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1358 "test-connection");
1359 OSMO_ASSERT(_conn);
1360 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001361 OSMO_ASSERT(conn);
1362
1363 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001364
Philipp Maier228e5912019-03-05 13:56:59 +01001365 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001366 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001367
1368 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1369 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001370 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001371
1372 force_monotonic_time_us = round(1000000.0 * info->txtime);
1373
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001374 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001375 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001376 msg->l3h = msgb_put(msg, info->len);
1377 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001378 mgcp_rtp_end_config(&endp, 1, rtp);
1379
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001380 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001381
1382 if (state.out_stream.ssrc != last_ssrc) {
1383 printf("Output SSRC changed to %08x\n",
1384 state.out_stream.ssrc);
1385 last_ssrc = state.out_stream.ssrc;
1386 }
1387
1388 printf("In TS: %d, dTS: %d, Seq: %d\n",
1389 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001390 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001391
1392 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001393 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001394 state.out_stream.last_timestamp - last_timestamp,
1395 state.out_stream.last_tsdelta,
1396 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001397 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1398 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001399
1400 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001401 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001402
Philipp Maier9e1d1642018-05-09 16:26:34 +02001403 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1404 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001405 last_timestamp = state.out_stream.last_timestamp;
1406 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001407
1408 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001409 }
1410
1411 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001412 mgcp_conn_free_all(&endp);
Philipp Maier124a3e02021-07-26 11:17:15 +02001413 talloc_free(trunk);
1414 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001415}
1416
1417static void test_multilple_codec(void)
1418{
1419 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001420 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001421 struct mgcp_endpoint *endp;
1422 struct msgb *inp, *resp;
1423 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001424 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001425 char conn_id[256];
Philipp Maier39889e42021-08-04 17:42:57 +02001426 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001427
1428 printf("Testing multiple payload types\n");
1429
1430 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001431 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001432 trunk->v.vty_number_endpoints = 64;
1433 mgcp_trunk_equip(trunk);
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001434
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001435 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001436 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001437 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001438 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001439 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1440 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001441 msgb_free(inp);
1442 msgb_free(resp);
1443
Philipp Maier37a808c2020-07-03 15:48:31 +02001444 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1445 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1446 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001447 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001448 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001449 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001450
1451 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001452 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001453 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001454 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001455 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1456 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001457 msgb_free(inp);
1458 msgb_free(resp);
1459
Philipp Maier37a808c2020-07-03 15:48:31 +02001460 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1461 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1462 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001463 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001464 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001465 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001466
Philipp Maierbc0346e2018-06-07 09:52:16 +02001467 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1468 /* Note: It usually makes no sense to leave the payload type list
1469 * out. However RFC 2327 does not clearly forbid this case and
1470 * it makes and since we already decided in OS#2658 that a missing
1471 * LCO should pick a sane default codec, it makes sense to expect
1472 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001473 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001474 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001475 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001476 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1477 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001478 msgb_free(inp);
1479 msgb_free(resp);
1480
Philipp Maier37a808c2020-07-03 15:48:31 +02001481 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1482 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1483 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001484 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001485 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001486 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001487
1488 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001489 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001490 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001491 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001492 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1493 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001494 msgb_free(inp);
1495 msgb_free(resp);
1496
Philipp Maier37a808c2020-07-03 15:48:31 +02001497 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1498 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1499 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001500 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001501 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001502 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001503
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001504 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
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);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001507 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001508 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1509 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001510 msgb_free(inp);
1511 msgb_free(resp);
1512
Philipp Maier37a808c2020-07-03 15:48:31 +02001513 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1514 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1515 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001516 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001517 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001518 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001519
Philipp Maierffd75e42017-11-22 11:44:50 +01001520 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001521 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001522 resp = mgcp_handle_message(cfg, inp);
1523 msgb_free(inp);
1524 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001525 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1526 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1527 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001528 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001529 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001530 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Pau Espin Pedrol5ffd1272022-10-04 13:45:48 +02001531 OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001532 memset(&addr, 0, sizeof(addr));
1533 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001534 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1535 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001536
1537 /* Check what happens without that flag */
1538
Philipp Maier87bd9be2017-08-22 16:35:41 +02001539 /* Free the previous endpoint and the data and
1540 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001541 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001542 talloc_free(endp->last_response);
1543 talloc_free(endp->last_trans);
1544 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001545 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001546 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001547
Philipp Maier37a808c2020-07-03 15:48:31 +02001548 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001549 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001550 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001551 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1552 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001553 msgb_free(inp);
1554 msgb_free(resp);
1555
Philipp Maier37a808c2020-07-03 15:48:31 +02001556 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1557 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1558 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001559 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001560 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001561 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001562
Philipp Maierd19de2e2020-06-03 13:55:33 +02001563 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001564 talloc_free(cfg);
1565}
1566
1567static void test_no_cycle(void)
1568{
1569 struct mgcp_config *cfg;
1570 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001571 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001572 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001573 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001574
1575 printf("Testing no sequence flow on initial packet\n");
1576
1577 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001578 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001579 trunk->v.vty_number_endpoints = 64;
1580 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001581
Philipp Maier37a808c2020-07-03 15:48:31 +02001582 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1583 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001584
Philipp Maierffd75e42017-11-22 11:44:50 +01001585 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1586 "test-connection");
1587 OSMO_ASSERT(_conn);
1588 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001589 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001590
Harald Welte49e3d5a2017-12-25 09:47:57 +01001591 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001592
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001593 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001594 OSMO_ASSERT(conn->state.stats.initialized == 1);
1595 OSMO_ASSERT(conn->state.stats.cycles == 0);
1596 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001597
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001598 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001599 OSMO_ASSERT(conn->state.stats.initialized == 1);
1600 OSMO_ASSERT(conn->state.stats.cycles == 0);
1601 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001602
1603 /* now jump.. */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001604 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001605 OSMO_ASSERT(conn->state.stats.initialized == 1);
1606 OSMO_ASSERT(conn->state.stats.cycles == 0);
1607 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001608
1609 /* and wrap */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001610 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001611 OSMO_ASSERT(conn->state.stats.initialized == 1);
1612 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1613 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001614
Philipp Maierd19de2e2020-06-03 13:55:33 +02001615 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001616 talloc_free(cfg);
1617}
1618
1619static void test_no_name(void)
1620{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001621 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001622 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001623 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001624
1625 printf("Testing no rtpmap name\n");
1626 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001627 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001628
Philipp Maier889fe7f2020-07-06 17:44:12 +02001629 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001630 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001631 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001632
Philipp Maierffd75e42017-11-22 11:44:50 +01001633 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001634 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001635
1636 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001637 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001638 (char *)msg->data);
1639 OSMO_ASSERT(false);
1640 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001641 msgb_free(inp);
1642 msgb_free(msg);
1643
Philipp Maierd19de2e2020-06-03 13:55:33 +02001644 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001645 talloc_free(cfg);
1646}
1647
1648static void test_osmux_cid(void)
1649{
1650 int id, i;
1651
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001652 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1653
1654 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001655 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001656 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1657
1658 osmux_cid_pool_get(30);
1659 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1660 osmux_cid_pool_get(30);
1661 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1662
1663 osmux_cid_pool_put(id);
1664 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1665 osmux_cid_pool_put(30);
1666 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001667
1668 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001669 id = osmux_cid_pool_get_next();
Pau Espin Pedrol310e41c2022-11-15 13:23:38 +01001670 /* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
1671 OSMO_ASSERT(id == ((i + 1) & 0xff));
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001672 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001673 }
1674
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001675 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001676 OSMO_ASSERT(id == -1);
1677
1678 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001679 osmux_cid_pool_put(i);
1680 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001681}
1682
1683static const struct log_info_cat log_categories[] = {
1684};
1685
1686const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001687 .cat = log_categories,
1688 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001689};
1690
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001691static void test_get_lco_identifier(void)
1692{
1693 char *test;
1694 printf("Testing get_lco_identifier()\n");
1695
1696 /* Normal case at the beginning */
1697 test = "p:10, a:PCMU";
1698 printf("%s -> %s\n", test, get_lco_identifier(test));
1699
1700 test = "p:10, a:PCMU";
1701 printf("%s -> %s\n", test, get_lco_identifier(test));
1702
1703 /* Begin parsing in the middle of the value part of
1704 * the previous LCO option value */
1705 test = "XXXX, p:10, a:PCMU";
1706 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1707
1708 test = "XXXX,p:10,a:PCMU";
1709 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1710
1711 test = "10,a:PCMU";
1712 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1713
1714 test = "10, a:PCMU";
1715 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1716
1717 test = "10,a: PCMU";
1718 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1719
1720 test = "10 ,a: PCMU";
1721 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1722
1723 /* Begin parsing right at the end of the previous LCO
1724 * option value */
1725 test = ", a:PCMU";
1726 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1727
1728 test = " a:PCMU";
1729 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1730
1731 /* Empty string, result should be (null) */
1732 test = "";
1733 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1734
1735 /* Missing colons, result should be (null) */
1736 test = "p10, aPCMU";
1737 printf("%s -> %s\n", test, get_lco_identifier(test));
1738
1739 /* Colon separated from the identifier, result should be (null) */
1740 test = "10,a :PCMU";
1741 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1742}
1743
1744static void test_check_local_cx_options(void *ctx)
1745{
1746 /* Legal cases */
1747 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1748 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1749 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1750 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1751 0);
1752 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1753 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1754 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1755 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1756 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1757
1758 /* Illegal spaces before and after colon */
1759 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1760 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1761 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1762
1763 /* Check if multiple appearances of LCOs are rejected */
1764 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1765 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1766 -1);
1767 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1768
1769 /* Check if empty LCO are rejected */
1770 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1771 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1772 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1773 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1774 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1775
1776 /* Garbeled beginning and ends */
1777 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1778 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1779 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1780 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1781 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1782 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1783
1784 /* Illegal strings */
1785 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1786 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1787 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1788 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1789 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1790 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1791}
1792
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001793static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1794 .amr_octet_aligned_present = true,
1795 .amr_octet_aligned = true,
1796};
1797
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001798static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1799 .amr_octet_aligned_present = true,
1800 .amr_octet_aligned = false,
1801};
1802
1803static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1804 .amr_octet_aligned_present = false,
1805};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001806
Philipp Maier4c4d2272023-04-26 15:45:17 +02001807struct testcase_mgcp_codec_decide_codec {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001808 int payload_type;
1809 const char *audio_name;
1810 const struct mgcp_codec_param *param;
1811 int expect_rc;
1812};
1813
Philipp Maier4c4d2272023-04-26 15:45:17 +02001814struct testcase_mgcp_codec_decide_expect {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001815 int payload_type_map[2];
1816};
1817
Philipp Maier4c4d2272023-04-26 15:45:17 +02001818struct testcase_mgcp_codec_decide {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001819 const char *descr;
1820 /* two conns on an endpoint, each with N configured codecs */
Philipp Maier4c4d2272023-04-26 15:45:17 +02001821 struct testcase_mgcp_codec_decide_codec codecs[2][10];
1822 struct testcase_mgcp_codec_decide_expect expect[2];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001823};
1824
Philipp Maier4c4d2272023-04-26 15:45:17 +02001825static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001826 {
1827 .descr = "same order, but differing payload type numbers",
1828 .codecs = {
1829 {
1830 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1831 { 0, "PCMU/8000/1", NULL, },
1832 { 111, "GSM-HR-08/8000/1", NULL, },
1833 },
1834 {
1835 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1836 { 0, "PCMU/8000/1", NULL, },
1837 { 97, "GSM-HR-08/8000/1", NULL, },
1838 },
1839 },
1840 .expect = {
1841 { .payload_type_map = {112, 96}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001842 { .payload_type_map = {112, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001843 },
1844 },
1845 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001846 .descr = "different order and different payload type numbers",
1847 .codecs = {
1848 {
1849 { 0, "PCMU/8000/1", NULL, },
1850 { 111, "GSM-HR-08/8000/1", NULL, },
1851 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1852 },
1853 {
1854 { 97, "GSM-HR-08/8000/1", NULL, },
1855 { 0, "PCMU/8000/1", NULL, },
1856 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1857 },
1858 },
1859 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001860 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001861 { .payload_type_map = {111, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001862 },
1863 },
1864 {
1865 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1866 .codecs = {
1867 {
1868 { 0, "PCMU/8000/1", NULL, },
1869 { 96, "GSM-HR-08/8000/1", NULL, },
1870 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1871 },
1872 {
1873 { 97, "GSM-HR-08/8000/1", NULL, },
1874 { 0, "PCMU/8000/1", NULL, },
1875 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1876 },
1877 },
1878 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001879 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001880 { .payload_type_map = {96, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001881 },
1882 },
1883 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001884 .descr = "conn0 has no codecs",
1885 .codecs = {
1886 {
1887 /* no codecs */
1888 },
1889 {
1890 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1891 { 0, "PCMU/8000/1", NULL, },
1892 { 97, "GSM-HR-08/8000/1", NULL, },
1893 },
1894 },
1895 .expect = {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001896 { .payload_type_map = {-EINVAL, -EINVAL}, },
1897 { .payload_type_map = {-EINVAL, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001898 },
1899 },
1900 {
1901 .descr = "conn1 has no codecs",
1902 .codecs = {
1903 {
1904 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1905 { 0, "PCMU/8000/1", NULL, },
1906 { 111, "GSM-HR-08/8000/1", NULL, },
1907 },
1908 {
1909 /* no codecs */
1910 },
1911 },
1912 .expect = {
1913 { .payload_type_map = {112, -EINVAL}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001914 { .payload_type_map = {-EINVAL, -EINVAL}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001915 },
1916 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001917 {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001918 .descr = "test AMR with differing octet-aligned settings (both <-> both)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001919 .codecs = {
1920 {
1921 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Philipp Maierec967d72023-03-22 16:20:37 +01001922 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001923 },
1924 {
1925 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
Philipp Maierec967d72023-03-22 16:20:37 +01001926 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001927 },
1928 },
1929 .expect = {
Philipp Maierec967d72023-03-22 16:20:37 +01001930 { .payload_type_map = {111, 121}, },
1931 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001932 },
1933 },
1934 {
1935 .descr = "test AMR with differing octet-aligned settings (oa <-> both)",
1936 .codecs = {
1937 {
1938 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1939 },
1940 {
1941 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1942 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1943 },
1944 },
1945 .expect = {
1946 { .payload_type_map = {111, 121}, },
1947 { .payload_type_map = {111, 121}, },
1948 },
1949 },
1950 {
1951 .descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
1952 .codecs = {
1953 {
1954 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1955 },
1956 {
1957 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1958 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1959 },
1960 },
1961 .expect = {
1962 { .payload_type_map = {112, 122}, },
1963 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001964 },
1965 },
1966 {
Philipp Maier621e8662023-03-22 16:53:30 +01001967 .descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001968 .codecs = {
1969 {
1970 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001971 },
1972 {
1973 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1974 },
1975 },
1976 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01001977 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001978 { .payload_type_map = {111, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001979 },
1980 },
1981 {
Philipp Maier621e8662023-03-22 16:53:30 +01001982 .descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001983 .codecs = {
1984 {
Philipp Maier621e8662023-03-22 16:53:30 +01001985 { 111, "AMR/8000", &amr_param_octet_aligned_false, },
1986 },
1987 {
1988 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1989 },
1990 },
1991 .expect = {
1992 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001993 { .payload_type_map = {111, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01001994 },
1995 },
1996 {
1997 .descr = "test AMR with NULL param (oa <-> null)",
1998 .codecs = {
1999 {
2000 { 112, "AMR/8000", &amr_param_octet_aligned_true, },
2001 },
2002 {
2003 { 122, "AMR/8000", NULL, },
2004 },
2005 },
2006 .expect = {
2007 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
2008 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002009 { .payload_type_map = {112, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01002010 },
2011 },
2012 {
2013 .descr = "test AMR with NULL param (bwe <-> null)",
2014 .codecs = {
2015 {
Philipp Maierec967d72023-03-22 16:20:37 +01002016 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002017 },
2018 {
2019 { 122, "AMR/8000", NULL, },
2020 },
2021 },
2022 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01002023 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
Philipp Maierec967d72023-03-22 16:20:37 +01002024 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002025 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002026 },
2027 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002028 {
2029 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
2030 .codecs = {
2031 {
2032 { 0, "PCMU/8000/1", NULL, },
2033 { 111, "GSM-HR-08/8000/1", NULL, },
2034 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2035 },
2036 {
2037 { 97, "GSM-HR-08/8000", NULL, },
2038 { 0, "PCMU/8000", NULL, },
2039 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
2040 },
2041 },
2042 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002043 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002044 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002045 },
2046 },
2047 {
2048 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
2049 .codecs = {
2050 {
2051 { 0, "PCMU/8000/1", NULL, },
2052 { 111, "GSM-HR-08/8000/1", NULL, },
2053 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2054 },
2055 {
2056 { 97, "GSM-HR-08", NULL, },
2057 { 0, "PCMU", NULL, },
2058 { 96, "AMR", &amr_param_octet_aligned_true, },
2059 },
2060 },
2061 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002062 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002063 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002064 },
2065 },
2066 {
2067 .descr = "test whether channel number matching is waterproof",
2068 .codecs = {
2069 {
2070 { 111, "GSM-HR-08/8000", },
2071 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
2072 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
2073 },
2074 {
2075 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
2076 { 121, "GSM-HR-08/8000/1", },
2077 },
2078 },
2079 .expect = {
2080 { .payload_type_map = {111, 121}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002081 { .payload_type_map = {111, 121} },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002082 },
2083 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002084};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002085
Philipp Maier4c4d2272023-04-26 15:45:17 +02002086static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
2087 const struct testcase_mgcp_codec_decide_expect *expect)
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002088{
Philipp Maier4c4d2272023-04-26 15:45:17 +02002089 bool ok = true;
2090 int payload_type_conn_src;
2091 int payload_type_conn_dst;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002092
Philipp Maier4c4d2272023-04-26 15:45:17 +02002093 printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
2094 if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
2095 if (expect->payload_type_map[index_conn_src] == -EINVAL
2096 && expect->payload_type_map[index_conn_dst] == -EINVAL)
2097 printf(" codec decision failed (expected)!\n");
2098 else {
2099 printf(" ERROR: codec decision failed!\n");
2100 ok = false;
2101 }
2102 } else {
2103 printf(" Codec decision result:\n");
2104 if (conn[index_conn_src].end.codec) {
2105 payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
2106 printf(" conn[%u]: codec:%s, pt:%d\n",
2107 index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
2108 } else {
2109 payload_type_conn_src = -EINVAL;
2110 printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
2111 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002112
Philipp Maier4c4d2272023-04-26 15:45:17 +02002113 if (conn[index_conn_dst].end.codec) {
2114 payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
2115 printf(" conn[%u]: codec:%s, pt:%d\n",
2116 index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
2117 payload_type_conn_dst);
2118 } else {
2119 payload_type_conn_dst = -EINVAL;
2120 printf(" conn[%u]: codec:none, pt:none\n", index_conn_dst);
2121 }
2122
2123 if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
2124 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2125 index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
2126 ok = false;
2127 }
2128
2129 if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
2130 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2131 index_conn_dst, expect->payload_type_map[index_conn_dst],
2132 payload_type_conn_dst);
2133 ok = false;
2134 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002135 }
Philipp Maier4c4d2272023-04-26 15:45:17 +02002136
2137 return ok;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002138}
2139
Philipp Maier4c4d2272023-04-26 15:45:17 +02002140static void test_mgcp_codec_decide(void)
Philipp Maier6931f9a2018-07-26 09:29:31 +02002141{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002142 int i;
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002143 bool ok_all = true;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002144 printf("\nTesting mgcp_codec_find_convertible()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002145
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002146 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002147 const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
2148 struct mgcp_conn_rtp conn[2] = { };
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002149 int rc;
2150 int conn_i;
2151 int c;
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002152 bool ok = true;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002153
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002154 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002155
Philipp Maier4c4d2272023-04-26 15:45:17 +02002156 /* Build testvector (add codecs to conn, set properties etc... */
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002157 for (conn_i = 0; conn_i < 2; conn_i++) {
2158 printf(" - add codecs on conn%d:\n", conn_i);
2159 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002160 const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002161 if (!codec->audio_name)
2162 break;
2163
Philipp Maier4c4d2272023-04-26 15:45:17 +02002164 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
2165 codec->param);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002166
2167 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2168 codec->param ?
Philipp Maier4c4d2272023-04-26 15:45:17 +02002169 (codec->param->amr_octet_aligned_present ?
2170 (codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
2171 : " octet-aligned=unset")
2172 : "", rc);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002173 if (rc != codec->expect_rc) {
2174 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2175 ok = false;
2176 }
2177 }
2178 if (!c)
2179 printf(" (none)\n");
2180 }
2181
Philipp Maier4c4d2272023-04-26 15:45:17 +02002182 /* Run codec decision and check expectation */
2183 if (!codec_decision(conn, 0, 1, &t->expect[0]))
2184 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002185
Philipp Maier4c4d2272023-04-26 15:45:17 +02002186 if (!codec_decision(conn, 1, 0, &t->expect[1]))
2187 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002188
Philipp Maier4c4d2272023-04-26 15:45:17 +02002189 if (ok)
2190 printf(" ===> SUCCESS: codec decision as expected!\n");
2191 else
2192 printf(" ===> FAIL: unexpected codec decision!\n");
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002193
2194 if (!ok)
2195 ok_all = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002196 }
2197
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002198 OSMO_ASSERT(ok_all);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002199}
2200
Harald Welte9befdeb2022-11-03 11:41:05 +01002201void test_conn_id_matching(void)
Neels Hofmeyr65317262018-09-03 22:11:05 +02002202{
2203 struct mgcp_endpoint endp = {};
2204 struct mgcp_conn *conn;
2205 struct mgcp_conn *conn_match;
2206 int i;
2207 const char *conn_id_generated = "000023AB";
2208 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002209 "23AB",
2210 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002211 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002212 "00000023AB",
2213 "23ab",
2214 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002215 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002216 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002217 };
2218
2219 printf("\nTesting %s\n", __func__);
2220
2221 INIT_LLIST_HEAD(&endp.conns);
2222
2223 conn = talloc_zero(NULL, struct mgcp_conn);
2224 OSMO_ASSERT(conn);
2225 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2226 llist_add(&conn->entry, &endp.conns);
2227
2228 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2229 const char *needle = conn_id_request[i];
2230 printf("needle='%s' ", needle);
2231 conn_match = mgcp_conn_get(&endp, needle);
2232 OSMO_ASSERT(conn_match);
2233 printf("found '%s'\n", conn_match->id);
2234 OSMO_ASSERT(conn_match == conn);
2235 }
2236
2237 llist_del(&conn->entry);
2238 talloc_free(conn);
2239}
2240
Harald Welte9befdeb2022-11-03 11:41:05 +01002241void test_e1_trunk_nr_from_epname(void)
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002242{
Philipp Maierd70eef62021-07-19 13:53:28 +02002243 unsigned int trunk_nr;
2244 int rc;
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002245
2246 /* Note: e1_trunk_nr_from_epname does not check the text
2247 * after the E1 trunk number, after the delimiter
2248 * character "/" arbitrary text may follow. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002249 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
Philipp Maier0653cc82020-08-10 22:52:51 +02002250 OSMO_ASSERT(trunk_nr == 0);
Philipp Maierd70eef62021-07-19 13:53:28 +02002251 OSMO_ASSERT(rc == 0);
2252 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002253 OSMO_ASSERT(trunk_nr == 1);
Philipp Maierd70eef62021-07-19 13:53:28 +02002254 OSMO_ASSERT(rc == 0);
2255 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002256 OSMO_ASSERT(trunk_nr == 2);
Philipp Maierd70eef62021-07-19 13:53:28 +02002257 OSMO_ASSERT(rc == 0);
2258 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002259 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002260 OSMO_ASSERT(rc == 0);
2261 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002262 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002263 OSMO_ASSERT(rc == 0);
2264 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002265 OSMO_ASSERT(trunk_nr == 24);
Philipp Maierd70eef62021-07-19 13:53:28 +02002266 OSMO_ASSERT(rc == 0);
2267 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002268 OSMO_ASSERT(trunk_nr == 64);
Philipp Maierd70eef62021-07-19 13:53:28 +02002269 OSMO_ASSERT(rc == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002270
2271 /* The following endpoint strings should fail, either the
2272 * trunk number exceeds the valid range or the trunk prefix
2273 * is wrong. Also when the delimiter character "/" at the
2274 * end of the trunk is wrong the parsing should fail. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002275 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
2276 OSMO_ASSERT(rc == -EINVAL);
2277 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
2278 OSMO_ASSERT(rc == -EINVAL);
2279 rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
2280 OSMO_ASSERT(rc == -EINVAL);
2281 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
2282 OSMO_ASSERT(rc == -EINVAL);
2283 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
2284 OSMO_ASSERT(rc == -EINVAL);
2285 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
2286 OSMO_ASSERT(rc == -EINVAL);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002287
2288 return;
2289}
2290
Harald Welte9befdeb2022-11-03 11:41:05 +01002291void test_mgcp_is_rtp_dummy_payload(void)
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002292{
2293 /* realistic rtp packet */
2294 static const char rtp_payload[] =
2295 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2296 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2297 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2298 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2299 0x24 };
2300
2301 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2302 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2303 struct msgb *msg_dummy_rtp =
2304 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2305
2306 uint8_t *buf;
2307
2308 /* Dummy RTP packet */
2309 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2310 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2311
2312 /* Normal RTP packet */
2313 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2314 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2315
2316 /* Dummy RTP packet with normal RTP packet attached, this must not be
2317 * recognized as Dummy RTP packet */
2318 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2319 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2320 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2321 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2322
2323 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2324 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2325 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2326
2327 msgb_free(msg_dummy);
2328 msgb_free(msg_rtp);
2329 msgb_free(msg_dummy_rtp);
2330}
2331
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002332int main(int argc, char **argv)
2333{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002334 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2335 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2336 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002337
2338 test_strline();
2339 test_values();
2340 test_messages();
2341 test_retransmission();
2342 test_packet_loss_calc();
2343 test_rqnt_cb();
2344 test_mgcp_stats();
2345 test_packet_error_detection(1, 0);
2346 test_packet_error_detection(0, 0);
2347 test_packet_error_detection(0, 1);
2348 test_packet_error_detection(1, 1);
2349 test_multilple_codec();
2350 test_no_cycle();
2351 test_no_name();
2352 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002353 test_get_lco_identifier();
2354 test_check_local_cx_options(ctx);
Philipp Maier4c4d2272023-04-26 15:45:17 +02002355 test_mgcp_codec_decide();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002356 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002357 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002358 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002359
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002360 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2361 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2362 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002363 printf("Done\n");
2364 return EXIT_SUCCESS;
2365}