blob: 621ee77029af87f15df015deb8df834f4ace50c7 [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 */
656ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200657 const struct sockaddr *dest_addr, socklen_t addrlen)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200658{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200659 uint32_t dest_host =
660 htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
661 int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200662
Philipp Maierb3d14eb2021-05-20 14:18:52 +0200663 if (len == sizeof(rtp_dummy_payload)
664 && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200665 fprintf(stderr,
666 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
667 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200668 dummy_packets += 1;
669 }
670
Pau Espin Pedrola24dcc62021-07-06 17:48:47 +0200671 /* Make sure address+port are valid */
672 OSMO_ASSERT(dest_host);
673 OSMO_ASSERT(dest_port);
674
Philipp Maier3d9b6562017-10-13 18:33:44 +0200675 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200676}
677
678static int64_t force_monotonic_time_us = -1;
679/* override and forward */
680int clock_gettime(clockid_t clk_id, struct timespec *tp)
681{
682 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
683 static clock_gettime_t real_clock_gettime = NULL;
684
685 if (!real_clock_gettime)
686 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
687
688 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
689 tp->tv_sec = force_monotonic_time_us / 1000000;
690 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
691 return 0;
692 }
693
694 return real_clock_gettime(clk_id, tp);
695}
696
Philipp Maier14b27a82020-06-02 20:15:30 +0200697static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200698{
699 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200700 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200701 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200702}
703
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200704#define CONN_UNMODIFIED (0x1000)
705
706static void test_values(void)
707{
708 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200709 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200710
711 /* Check that LOOPBACK enables all output */
712 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200713 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200714}
715
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200716/* Extract a connection ID from a response and return in conn_id;
717 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100718static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200719 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100720{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200721 const char *conn_id_start;
722 const char *conn_id_end;
723 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100724
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200725 const char *header_I = "\r\nI: ";
726 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100727
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200728 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
729 if ((conn_id_start = strstr((char *)resp, header_I))) {
730 conn_id_start += strlen(header_I);
731 conn_id_end = strstr(conn_id_start, "\r\n");
732 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
733 conn_id_start += strlen(header_o);
734 conn_id_end = strchr(conn_id_start, ' ');
735 } else
736 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100737
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200738 if (conn_id_end)
739 conn_id_len = conn_id_end - conn_id_start;
740 else
741 conn_id_len = strlen(conn_id_start);
742 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100743
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200744 /* A valid conn_id must at least contain one digit, and must
745 * not exceed a length of 32 digits */
746 OSMO_ASSERT(conn_id_len <= 32);
747 OSMO_ASSERT(conn_id_len > 0);
748
749 strncpy(conn_id, conn_id_start, conn_id_len);
750 conn_id[conn_id_len] = '\0';
751 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100752}
753
754/* Check response, automatically patch connection ID if needed */
755static int check_response(uint8_t *resp, const char *exp_resp)
756{
757 char exp_resp_patched[4096];
758 const char *exp_resp_ptr;
759 char conn_id[256];
760
761 printf("checking response:\n");
762
763 /* If the expected response is intened to be patched
764 * (%s placeholder inside) we will patch it with the
765 * connection identifier we just received from the
766 * real response. This is necessary because the CI
767 * is generated by the mgcp code on CRCX and we can
768 * not know it in advance */
769 if (strstr(exp_resp, "%s")) {
770 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
771 0) {
772 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
773 exp_resp_ptr = exp_resp_patched;
774 printf
775 ("using message with patched conn_id for comparison\n");
776 } else {
777 printf
778 ("patching conn_id failed, using message as statically defined for comparison\n");
779 exp_resp_ptr = exp_resp;
780 }
781 } else {
782 printf("using message as statically defined for comparison\n");
783 exp_resp_ptr = exp_resp;
784 }
785
786 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
787 printf("Unexpected response, please check!\n");
788 printf
789 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
790 resp);
791 printf
792 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
793 exp_resp_ptr);
794 return -EINVAL;
795 }
796
797 printf("Response matches our expectations.\n");
798 return 0;
799}
800
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200801static void test_messages(void)
802{
803 struct mgcp_config *cfg;
804 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200805 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200806 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200807 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100808 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100809 int rc;
Philipp Maier39889e42021-08-04 17:42:57 +0200810 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200811
812 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200813 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200814
Philipp Maier889fe7f2020-07-06 17:44:12 +0200815 trunk->v.vty_number_endpoints = 64;
816 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200817
Philipp Maierffd75e42017-11-22 11:44:50 +0100818 memset(last_conn_id, 0, sizeof(last_conn_id));
819
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200820 for (i = 0; i < ARRAY_SIZE(tests); i++) {
821 const struct mgcp_test *t = &tests[i];
822 struct msgb *inp;
823 struct msgb *msg;
824
Philipp Maierffd75e42017-11-22 11:44:50 +0100825 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200826 printf("Testing %s\n", t->name);
827
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200828 dummy_packets = 0;
829
Philipp Maierffd75e42017-11-22 11:44:50 +0100830 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200831 msg = mgcp_handle_message(cfg, inp);
832 msgb_free(inp);
833 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200834 if (msg) {
835 printf("%s failed '%s'\n", t->name,
836 (char *)msg->data);
837 OSMO_ASSERT(false);
838 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100839 } else if (check_response(msg->data, t->exp_resp) != 0) {
840 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200841 OSMO_ASSERT(false);
842 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100843
Philipp Maier7df419b2017-12-04 17:11:42 +0100844 if (msg) {
845 rc = get_conn_id_from_response(msg->data, last_conn_id,
846 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200847 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100848 printf("(response contains a connection id)\n");
849 else
850 printf("(response does not contain a connection id)\n");
851 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100852
Philipp Maiera330b862017-12-04 17:16:16 +0100853 if (msg)
854 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200855
856 if (dummy_packets)
857 printf("Dummy packets: %d\n", dummy_packets);
858
Philipp Maier37a808c2020-07-03 15:48:31 +0200859 if (last_endpoint[0] != '\0') {
860 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
861 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200862
Philipp Maier01d24a32017-11-21 17:26:09 +0100863 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200864 if (conn) {
865 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200866
Philipp Maier87bd9be2017-08-22 16:35:41 +0200867 if (conn->end.packet_duration_ms != -1)
868 printf("Detected packet duration: %d\n",
869 conn->end.packet_duration_ms);
870 else
871 printf("Packet duration not set\n");
872 if (endp->local_options.pkt_period_min ||
873 endp->local_options.pkt_period_max)
874 printf
Oliver Smith169d50e2023-01-24 13:12:54 +0100875 ("Requested packetization period: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200876 "%d-%d\n",
877 endp->local_options.pkt_period_min,
878 endp->
879 local_options.pkt_period_max);
880 else
881 printf
882 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200883
Philipp Maier87bd9be2017-08-22 16:35:41 +0200884 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
885 printf("Connection mode: %d:%s%s%s%s\n",
886 conn->conn->mode,
887 !conn->conn->mode ? " NONE" : "",
888 conn->conn->mode & MGCP_CONN_SEND_ONLY
889 ? " SEND" : "",
890 conn->conn->mode & MGCP_CONN_RECV_ONLY
891 ? " RECV" : "",
892 conn->conn->mode & MGCP_CONN_LOOPBACK
893 & ~MGCP_CONN_RECV_SEND
894 ? " LOOP" : "");
895 fprintf(stderr,
896 "RTP output %sabled, NET output %sabled\n",
897 conn->end.output_enabled
898 ? "en" : "dis",
899 conn->end.output_enabled
900 ? "en" : "dis");
901 } else
902 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200903
Philipp Maier87bd9be2017-08-22 16:35:41 +0200904 OSMO_ASSERT(conn->end.output_enabled
Pau Espin Pedrol2c401642021-12-24 14:48:26 +0100905 == !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200906
907 conn->conn->mode |= CONN_UNMODIFIED;
908
909 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200910 endp->local_options.pkt_period_min = 0;
911 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200912 }
913
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200914 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100915 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200916 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200917
Philipp Maier37a808c2020-07-03 15:48:31 +0200918 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200919 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200920 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200921 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200922
Philipp Maier87bd9be2017-08-22 16:35:41 +0200923 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200924 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200925 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200926
927 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200928 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200929 }
930 }
931
Philipp Maierd19de2e2020-06-03 13:55:33 +0200932 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200933 talloc_free(cfg);
934}
935
936static void test_retransmission(void)
937{
938 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200939 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200940 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100941 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100942 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200943
944 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200945 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200946
Philipp Maier889fe7f2020-07-06 17:44:12 +0200947 trunk->v.vty_number_endpoints = 64;
948 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200949
Philipp Maierffd75e42017-11-22 11:44:50 +0100950 memset(last_conn_id, 0, sizeof(last_conn_id));
951
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200952 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
953 const struct mgcp_test *t = &retransmit[i];
954 struct msgb *inp;
955 struct msgb *msg;
956
Philipp Maierffd75e42017-11-22 11:44:50 +0100957 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200958 printf("Testing %s\n", t->name);
959
Philipp Maierffd75e42017-11-22 11:44:50 +0100960 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200961 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200962
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200963 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100964 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200965 printf("%s failed '%s'\n", t->name, (char *)msg->data);
966 OSMO_ASSERT(false);
967 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100968
Philipp Maier23b8e292017-12-04 16:48:45 +0100969 if (msg && strcmp(t->name, "CRCX") == 0) {
970 rc = get_conn_id_from_response(msg->data, last_conn_id,
971 sizeof(last_conn_id));
972 OSMO_ASSERT(rc == 0);
973 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100974
Philipp Maier7cedfd72017-12-04 16:49:12 +0100975 if (msg)
976 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200977
978 /* Retransmit... */
979 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100980 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200981 msg = mgcp_handle_message(cfg, inp);
982 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100983 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200984 printf("%s failed '%s'\n", t->name, (char *)msg->data);
985 OSMO_ASSERT(false);
986 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200987 msgb_free(msg);
988 }
989
Philipp Maierd19de2e2020-06-03 13:55:33 +0200990 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200991 talloc_free(cfg);
992}
993
994static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
995{
996 ptrdiff_t tone = _tone;
Ericfbf78d12021-08-23 22:31:39 +0200997 endp->trunk->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200998 return 0;
999}
1000
1001static void test_rqnt_cb(void)
1002{
1003 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001004 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001005 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +01001006 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001007
1008 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001009 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001010 cfg->rqnt_cb = rqnt_cb;
1011
Philipp Maier889fe7f2020-07-06 17:44:12 +02001012 trunk->v.vty_number_endpoints = 64;
1013 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001014
Philipp Maierffd75e42017-11-22 11:44:50 +01001015 inp = create_msg(CRCX, NULL);
1016 msg = mgcp_handle_message(cfg, inp);
1017 OSMO_ASSERT(msg);
1018 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
1019 sizeof(conn_id)) == 0);
1020 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001021 msgb_free(inp);
1022
1023 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +01001024 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001025 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001026 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001027 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
1028 abort();
1029 }
1030
Philipp Maier87bd9be2017-08-22 16:35:41 +02001031 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032 printf("FAILED: callback not called: %p\n", cfg->data);
1033 abort();
1034 }
1035
1036 msgb_free(msg);
1037 msgb_free(inp);
1038
Philipp Maierffd75e42017-11-22 11:44:50 +01001039 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001040 msgb_free(mgcp_handle_message(cfg, inp));
1041 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001042 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001043 talloc_free(cfg);
1044}
1045
1046struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001047 int cycles;
1048 uint16_t base_seq;
1049 uint16_t max_seq;
1050 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001051
Philipp Maier87bd9be2017-08-22 16:35:41 +02001052 uint32_t expected;
1053 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001054};
1055
1056static const struct pl_test pl_test_dat[] = {
1057 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001058 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1059 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001060 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001061 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1062 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001063 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001064 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1065 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001066 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001067 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1068 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001069 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001070 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1071 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001072};
1073
1074static void test_packet_loss_calc(void)
1075{
1076 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001077 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001078 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001079 struct mgcp_config *cfg;
1080 struct mgcp_trunk *trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001081
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001082 printf("Testing packet loss calculation.\n");
1083
Philipp Maiercede2a42018-07-03 14:14:21 +02001084 memset(&endp, 0, sizeof(endp));
Philipp Maier124a3e02021-07-26 11:17:15 +02001085 cfg = mgcp_config_alloc();
1086 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maiercede2a42018-07-03 14:14:21 +02001087 endp.type = &ep_typeset.rtp;
Philipp Maier124a3e02021-07-26 11:17:15 +02001088 trunk->v.vty_number_endpoints = 1;
1089 trunk->endpoints = endpoints;
1090 trunk->endpoints[0] = &endp;
1091 endp.trunk = trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001092 INIT_LLIST_HEAD(&endp.conns);
1093
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001094 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1095 uint32_t expected;
1096 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001097
Philipp Maiercede2a42018-07-03 14:14:21 +02001098 struct mgcp_conn_rtp *conn = NULL;
1099 struct mgcp_conn *_conn = NULL;
1100 struct mgcp_rtp_state *state;
1101 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001102
Philipp Maiercede2a42018-07-03 14:14:21 +02001103 _conn =
1104 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1105 "test-connection");
1106 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1107 state = &conn->state;
Pau Espin Pedroldaf5bce2022-09-22 19:14:24 +02001108 packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001109
1110 state->stats.initialized = 1;
1111 state->stats.base_seq = pl_test_dat[i].base_seq;
1112 state->stats.max_seq = pl_test_dat[i].max_seq;
1113 state->stats.cycles = pl_test_dat[i].cycles;
1114
1115 packets_rx->current = pl_test_dat[i].packets;
1116 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001117
Philipp Maier87bd9be2017-08-22 16:35:41 +02001118 if (loss != pl_test_dat[i].loss
1119 || expected != pl_test_dat[i].expected) {
1120 printf
1121 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1122 i, loss, pl_test_dat[i].loss, expected,
1123 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001124 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001125
1126 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001127 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001128
Philipp Maier124a3e02021-07-26 11:17:15 +02001129 talloc_free(trunk);
1130 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001131}
1132
Philipp Maier87bd9be2017-08-22 16:35:41 +02001133int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1134 uint32_t *pr, uint32_t *_or, int *loss,
1135 uint32_t *jitter)
1136{
1137 char *line, *save;
1138 int rc;
1139
1140 /* initialize with bad values */
1141 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1142 *loss = INT_MAX;
1143
1144 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1145 if (!line)
1146 return -1;
1147
1148 /* this can only parse the message that is created above... */
1149 for_each_non_empty_line(line, save) {
1150 switch (line[0]) {
1151 case 'P':
1152 rc = sscanf(line,
1153 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1154 ps, os, pr, _or, loss, jitter);
1155 return rc == 6 ? 0 : -1;
1156 }
1157 }
1158
1159 return -1;
1160}
1161
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001162static void test_mgcp_stats(void)
1163{
1164 printf("Testing stat parsing\n");
1165
1166 uint32_t bps, bos, pr, _or, jitter;
1167 struct msgb *msg;
1168 int loss;
1169 int rc;
1170
Philipp Maierffd75e42017-11-22 11:44:50 +01001171 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001172 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1173 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001174 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1175 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001176 printf("FAIL: Parsing failed1.\n");
1177 msgb_free(msg);
1178
Philipp Maier87bd9be2017-08-22 16:35:41 +02001179 msg =
1180 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001181 ("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 +02001182 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1183 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001184 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1185 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001186 printf("FAIL: Parsing failed2.\n");
1187 msgb_free(msg);
1188}
1189
1190struct rtp_packet_info {
1191 float txtime;
1192 int len;
1193 char *data;
1194};
1195
1196struct rtp_packet_info test_rtp_packets1[] = {
1197 /* RTP: SeqNo=0, TS=0 */
1198 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001199 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001200 /* RTP: SeqNo=1, TS=160 */
1201 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\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=2, TS=320 */
1204 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\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 /* Repeat RTP timestamp: */
1207 /* RTP: SeqNo=3, TS=320 */
1208 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001209 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001210 /* RTP: SeqNo=4, TS=480 */
1211 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\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=5, TS=640 */
1214 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\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 /* Double skip RTP timestamp (delta = 2*160): */
1217 /* RTP: SeqNo=6, TS=960 */
1218 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001219 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001220 /* RTP: SeqNo=7, TS=1120 */
1221 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\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=8, TS=1280 */
1224 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\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 /* Non 20ms RTP timestamp (delta = 120): */
1227 /* RTP: SeqNo=9, TS=1400 */
1228 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001229 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001230 /* RTP: SeqNo=10, TS=1560 */
1231 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\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=11, TS=1720 */
1234 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\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 /* SSRC changed to 0x10203040, RTP timestamp jump */
1237 /* RTP: SeqNo=12, TS=34688 */
1238 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001239 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001240 /* RTP: SeqNo=13, TS=34848 */
1241 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\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=14, TS=35008 */
1244 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\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 /* Non 20ms RTP timestamp (delta = 120): */
1247 /* RTP: SeqNo=15, TS=35128 */
1248 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001249 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001250 /* RTP: SeqNo=16, TS=35288 */
1251 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\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=17, TS=35448 */
1254 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001255 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001256 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1257 /* RTP: SeqNo=19, TS=35768 */
1258 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001259 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001260 /* RTP: SeqNo=20, TS=35928 */
1261 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\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=21, TS=36088 */
1264 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\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 /* Repeat last packet */
1267 /* RTP: SeqNo=21, TS=36088 */
1268 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001269 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001270 /* RTP: SeqNo=22, TS=36248 */
1271 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\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=23, TS=36408 */
1274 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\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 /* Don't increment SeqNo but increment timestamp by 160 */
1277 /* RTP: SeqNo=23, TS=36568 */
1278 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001279 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001280 /* RTP: SeqNo=24, TS=36728 */
1281 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\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=25, TS=36888 */
1284 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\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 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1287 * SeqNo jump */
1288 /* RTP: SeqNo=1000, TS=160000 */
1289 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001290 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001291 /* RTP: SeqNo=1001, TS=160160 */
1292 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\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=1002, TS=160320 */
1295 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001296 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001297 /* RTP: SeqNo=1003, TS=180320, Marker */
1298 {2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
1299 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1300 /* RTP: SeqNo=1004, TS=180480 */
1301 {2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
1302 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1303 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
1304 {2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
1305 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001306};
1307
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001308static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1309{
1310 int i;
1311
Philipp Maier124a3e02021-07-26 11:17:15 +02001312 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001313 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001314 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001315 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001316 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001317 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001318 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001319 uint32_t last_ssrc = 0;
1320 uint32_t last_timestamp = 0;
1321 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001322 uint64_t last_in_ts_err_cnt = 0;
1323 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001324 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001325 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001326 struct rate_ctr test_ctr_in;
1327 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001328
1329 printf("Testing packet error detection%s%s.\n",
1330 patch_ssrc ? ", patch SSRC" : "",
1331 patch_ts ? ", patch timestamps" : "");
1332
Philipp Maier124a3e02021-07-26 11:17:15 +02001333 cfg = mgcp_config_alloc();
1334 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001335 memset(&endp, 0, sizeof(endp));
1336 memset(&state, 0, sizeof(state));
1337
Philipp Maier9e1d1642018-05-09 16:26:34 +02001338 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1339 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1340 state.in_stream.err_ts_ctr = &test_ctr_in;
1341 state.out_stream.err_ts_ctr = &test_ctr_out;
1342
Philipp Maier87bd9be2017-08-22 16:35:41 +02001343 endp.type = &ep_typeset.rtp;
1344
Philipp Maier124a3e02021-07-26 11:17:15 +02001345 trunk->v.vty_number_endpoints = 1;
1346 trunk->endpoints = endpoints;
1347 trunk->endpoints[0] = &endp;
1348 trunk->force_constant_ssrc = patch_ssrc;
1349 trunk->force_aligned_timing = patch_ts;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001350
Philipp Maier124a3e02021-07-26 11:17:15 +02001351 endp.trunk = trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001352
Philipp Maier87bd9be2017-08-22 16:35:41 +02001353 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001354 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1355 "test-connection");
1356 OSMO_ASSERT(_conn);
1357 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001358 OSMO_ASSERT(conn);
1359
1360 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001361
Philipp Maier228e5912019-03-05 13:56:59 +01001362 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001363 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001364
1365 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1366 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001367 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001368
1369 force_monotonic_time_us = round(1000000.0 * info->txtime);
1370
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001371 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001372 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001373 msg->l3h = msgb_put(msg, info->len);
1374 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001375 mgcp_rtp_end_config(&endp, 1, rtp);
1376
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001377 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001378
1379 if (state.out_stream.ssrc != last_ssrc) {
1380 printf("Output SSRC changed to %08x\n",
1381 state.out_stream.ssrc);
1382 last_ssrc = state.out_stream.ssrc;
1383 }
1384
1385 printf("In TS: %d, dTS: %d, Seq: %d\n",
1386 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001387 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001388
1389 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001390 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001391 state.out_stream.last_timestamp - last_timestamp,
1392 state.out_stream.last_tsdelta,
1393 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001394 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1395 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001396
1397 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001398 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001399
Philipp Maier9e1d1642018-05-09 16:26:34 +02001400 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1401 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001402 last_timestamp = state.out_stream.last_timestamp;
1403 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001404
1405 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001406 }
1407
1408 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001409 mgcp_conn_free_all(&endp);
Philipp Maier124a3e02021-07-26 11:17:15 +02001410 talloc_free(trunk);
1411 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001412}
1413
1414static void test_multilple_codec(void)
1415{
1416 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001417 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001418 struct mgcp_endpoint *endp;
1419 struct msgb *inp, *resp;
1420 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001421 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001422 char conn_id[256];
Philipp Maier39889e42021-08-04 17:42:57 +02001423 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001424
1425 printf("Testing multiple payload types\n");
1426
1427 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001428 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001429 trunk->v.vty_number_endpoints = 64;
1430 mgcp_trunk_equip(trunk);
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001431
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001432 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001433 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001434 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001435 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001436 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1437 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001438 msgb_free(inp);
1439 msgb_free(resp);
1440
Philipp Maier37a808c2020-07-03 15:48:31 +02001441 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1442 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1443 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001444 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001445 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001446 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001447
1448 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001449 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001450 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001451 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001452 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1453 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001454 msgb_free(inp);
1455 msgb_free(resp);
1456
Philipp Maier37a808c2020-07-03 15:48:31 +02001457 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1458 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1459 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001460 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001461 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001462 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001463
Philipp Maierbc0346e2018-06-07 09:52:16 +02001464 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1465 /* Note: It usually makes no sense to leave the payload type list
1466 * out. However RFC 2327 does not clearly forbid this case and
1467 * it makes and since we already decided in OS#2658 that a missing
1468 * LCO should pick a sane default codec, it makes sense to expect
1469 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001470 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001471 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001472 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001473 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1474 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001475 msgb_free(inp);
1476 msgb_free(resp);
1477
Philipp Maier37a808c2020-07-03 15:48:31 +02001478 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1479 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1480 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001481 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001482 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001483 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001484
1485 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001486 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001487 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001488 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001489 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1490 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001491 msgb_free(inp);
1492 msgb_free(resp);
1493
Philipp Maier37a808c2020-07-03 15:48:31 +02001494 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1495 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1496 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001497 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001498 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001499 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001500
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001501 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
Philipp Maier37a808c2020-07-03 15:48:31 +02001502 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001503 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001504 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001505 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1506 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001507 msgb_free(inp);
1508 msgb_free(resp);
1509
Philipp Maier37a808c2020-07-03 15:48:31 +02001510 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1511 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1512 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001513 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001514 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001515 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001516
Philipp Maierffd75e42017-11-22 11:44:50 +01001517 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001518 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001519 resp = mgcp_handle_message(cfg, inp);
1520 msgb_free(inp);
1521 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001522 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1523 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1524 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001525 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001526 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001527 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Pau Espin Pedrol5ffd1272022-10-04 13:45:48 +02001528 OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001529 memset(&addr, 0, sizeof(addr));
1530 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001531 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1532 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001533
1534 /* Check what happens without that flag */
1535
Philipp Maier87bd9be2017-08-22 16:35:41 +02001536 /* Free the previous endpoint and the data and
1537 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001538 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001539 talloc_free(endp->last_response);
1540 talloc_free(endp->last_trans);
1541 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001542 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001543 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001544
Philipp Maier37a808c2020-07-03 15:48:31 +02001545 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001546 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001547 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001548 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1549 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001550 msgb_free(inp);
1551 msgb_free(resp);
1552
Philipp Maier37a808c2020-07-03 15:48:31 +02001553 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1554 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1555 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001556 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001557 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001558 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001559
Philipp Maierd19de2e2020-06-03 13:55:33 +02001560 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001561 talloc_free(cfg);
1562}
1563
1564static void test_no_cycle(void)
1565{
1566 struct mgcp_config *cfg;
1567 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001568 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001569 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001570 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001571
1572 printf("Testing no sequence flow on initial packet\n");
1573
1574 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001575 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001576 trunk->v.vty_number_endpoints = 64;
1577 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001578
Philipp Maier37a808c2020-07-03 15:48:31 +02001579 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1580 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001581
Philipp Maierffd75e42017-11-22 11:44:50 +01001582 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1583 "test-connection");
1584 OSMO_ASSERT(_conn);
1585 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001586 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001587
Harald Welte49e3d5a2017-12-25 09:47:57 +01001588 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001589
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001590 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001591 OSMO_ASSERT(conn->state.stats.initialized == 1);
1592 OSMO_ASSERT(conn->state.stats.cycles == 0);
1593 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001594
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001595 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001596 OSMO_ASSERT(conn->state.stats.initialized == 1);
1597 OSMO_ASSERT(conn->state.stats.cycles == 0);
1598 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001599
1600 /* now jump.. */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001601 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001602 OSMO_ASSERT(conn->state.stats.initialized == 1);
1603 OSMO_ASSERT(conn->state.stats.cycles == 0);
1604 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001605
1606 /* and wrap */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001607 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001608 OSMO_ASSERT(conn->state.stats.initialized == 1);
1609 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1610 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001611
Philipp Maierd19de2e2020-06-03 13:55:33 +02001612 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001613 talloc_free(cfg);
1614}
1615
1616static void test_no_name(void)
1617{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001618 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001619 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001620 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001621
1622 printf("Testing no rtpmap name\n");
1623 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001624 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001625
Philipp Maier889fe7f2020-07-06 17:44:12 +02001626 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001627 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001628 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001629
Philipp Maierffd75e42017-11-22 11:44:50 +01001630 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001631 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001632
1633 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001634 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001635 (char *)msg->data);
1636 OSMO_ASSERT(false);
1637 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001638 msgb_free(inp);
1639 msgb_free(msg);
1640
Philipp Maierd19de2e2020-06-03 13:55:33 +02001641 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001642 talloc_free(cfg);
1643}
1644
1645static void test_osmux_cid(void)
1646{
1647 int id, i;
1648
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001649 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1650
1651 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001652 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001653 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1654
1655 osmux_cid_pool_get(30);
1656 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1657 osmux_cid_pool_get(30);
1658 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1659
1660 osmux_cid_pool_put(id);
1661 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1662 osmux_cid_pool_put(30);
1663 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001664
1665 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001666 id = osmux_cid_pool_get_next();
Pau Espin Pedrol310e41c2022-11-15 13:23:38 +01001667 /* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
1668 OSMO_ASSERT(id == ((i + 1) & 0xff));
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001669 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001670 }
1671
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001672 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001673 OSMO_ASSERT(id == -1);
1674
1675 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001676 osmux_cid_pool_put(i);
1677 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001678}
1679
1680static const struct log_info_cat log_categories[] = {
1681};
1682
1683const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001684 .cat = log_categories,
1685 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001686};
1687
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001688static void test_get_lco_identifier(void)
1689{
1690 char *test;
1691 printf("Testing get_lco_identifier()\n");
1692
1693 /* Normal case at the beginning */
1694 test = "p:10, a:PCMU";
1695 printf("%s -> %s\n", test, get_lco_identifier(test));
1696
1697 test = "p:10, a:PCMU";
1698 printf("%s -> %s\n", test, get_lco_identifier(test));
1699
1700 /* Begin parsing in the middle of the value part of
1701 * the previous LCO option value */
1702 test = "XXXX, p:10, a:PCMU";
1703 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1704
1705 test = "XXXX,p:10,a:PCMU";
1706 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1707
1708 test = "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 /* Begin parsing right at the end of the previous LCO
1721 * option value */
1722 test = ", a:PCMU";
1723 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1724
1725 test = " a:PCMU";
1726 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1727
1728 /* Empty string, result should be (null) */
1729 test = "";
1730 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1731
1732 /* Missing colons, result should be (null) */
1733 test = "p10, aPCMU";
1734 printf("%s -> %s\n", test, get_lco_identifier(test));
1735
1736 /* Colon separated from the identifier, result should be (null) */
1737 test = "10,a :PCMU";
1738 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1739}
1740
1741static void test_check_local_cx_options(void *ctx)
1742{
1743 /* Legal cases */
1744 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1745 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1746 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1747 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1748 0);
1749 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1750 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1751 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1752 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1753 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1754
1755 /* Illegal spaces before and after colon */
1756 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1757 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1758 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1759
1760 /* Check if multiple appearances of LCOs are rejected */
1761 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1762 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1763 -1);
1764 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1765
1766 /* Check if empty LCO are rejected */
1767 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1768 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1769 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1770 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1771 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1772
1773 /* Garbeled beginning and ends */
1774 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1775 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1776 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1777 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1778 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1779 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1780
1781 /* Illegal strings */
1782 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1783 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1784 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
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, ",,,") == -1);
1788}
1789
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001790static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1791 .amr_octet_aligned_present = true,
1792 .amr_octet_aligned = true,
1793};
1794
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001795static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1796 .amr_octet_aligned_present = true,
1797 .amr_octet_aligned = false,
1798};
1799
1800static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1801 .amr_octet_aligned_present = false,
1802};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001803
Philipp Maier4c4d2272023-04-26 15:45:17 +02001804struct testcase_mgcp_codec_decide_codec {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001805 int payload_type;
1806 const char *audio_name;
1807 const struct mgcp_codec_param *param;
1808 int expect_rc;
1809};
1810
Philipp Maier4c4d2272023-04-26 15:45:17 +02001811struct testcase_mgcp_codec_decide_expect {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001812 int payload_type_map[2];
1813};
1814
Philipp Maier4c4d2272023-04-26 15:45:17 +02001815struct testcase_mgcp_codec_decide {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001816 const char *descr;
1817 /* two conns on an endpoint, each with N configured codecs */
Philipp Maier4c4d2272023-04-26 15:45:17 +02001818 struct testcase_mgcp_codec_decide_codec codecs[2][10];
1819 struct testcase_mgcp_codec_decide_expect expect[2];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001820};
1821
Philipp Maier4c4d2272023-04-26 15:45:17 +02001822static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001823 {
1824 .descr = "same order, but differing payload type numbers",
1825 .codecs = {
1826 {
1827 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1828 { 0, "PCMU/8000/1", NULL, },
1829 { 111, "GSM-HR-08/8000/1", NULL, },
1830 },
1831 {
1832 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1833 { 0, "PCMU/8000/1", NULL, },
1834 { 97, "GSM-HR-08/8000/1", NULL, },
1835 },
1836 },
1837 .expect = {
1838 { .payload_type_map = {112, 96}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001839 { .payload_type_map = {112, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001840 },
1841 },
1842 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001843 .descr = "different order and different payload type numbers",
1844 .codecs = {
1845 {
1846 { 0, "PCMU/8000/1", NULL, },
1847 { 111, "GSM-HR-08/8000/1", NULL, },
1848 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1849 },
1850 {
1851 { 97, "GSM-HR-08/8000/1", NULL, },
1852 { 0, "PCMU/8000/1", NULL, },
1853 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1854 },
1855 },
1856 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001857 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001858 { .payload_type_map = {111, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001859 },
1860 },
1861 {
1862 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1863 .codecs = {
1864 {
1865 { 0, "PCMU/8000/1", NULL, },
1866 { 96, "GSM-HR-08/8000/1", NULL, },
1867 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1868 },
1869 {
1870 { 97, "GSM-HR-08/8000/1", NULL, },
1871 { 0, "PCMU/8000/1", NULL, },
1872 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1873 },
1874 },
1875 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001876 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001877 { .payload_type_map = {96, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001878 },
1879 },
1880 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001881 .descr = "conn0 has no codecs",
1882 .codecs = {
1883 {
1884 /* no codecs */
1885 },
1886 {
1887 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1888 { 0, "PCMU/8000/1", NULL, },
1889 { 97, "GSM-HR-08/8000/1", NULL, },
1890 },
1891 },
1892 .expect = {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001893 { .payload_type_map = {-EINVAL, -EINVAL}, },
1894 { .payload_type_map = {-EINVAL, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001895 },
1896 },
1897 {
1898 .descr = "conn1 has no codecs",
1899 .codecs = {
1900 {
1901 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1902 { 0, "PCMU/8000/1", NULL, },
1903 { 111, "GSM-HR-08/8000/1", NULL, },
1904 },
1905 {
1906 /* no codecs */
1907 },
1908 },
1909 .expect = {
1910 { .payload_type_map = {112, -EINVAL}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001911 { .payload_type_map = {-EINVAL, -EINVAL}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001912 },
1913 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001914 {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001915 .descr = "test AMR with differing octet-aligned settings (both <-> both)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001916 .codecs = {
1917 {
1918 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Philipp Maierec967d72023-03-22 16:20:37 +01001919 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001920 },
1921 {
1922 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
Philipp Maierec967d72023-03-22 16:20:37 +01001923 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001924 },
1925 },
1926 .expect = {
Philipp Maierec967d72023-03-22 16:20:37 +01001927 { .payload_type_map = {111, 121}, },
1928 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001929 },
1930 },
1931 {
1932 .descr = "test AMR with differing octet-aligned settings (oa <-> both)",
1933 .codecs = {
1934 {
1935 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1936 },
1937 {
1938 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1939 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1940 },
1941 },
1942 .expect = {
1943 { .payload_type_map = {111, 121}, },
1944 { .payload_type_map = {111, 121}, },
1945 },
1946 },
1947 {
1948 .descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
1949 .codecs = {
1950 {
1951 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1952 },
1953 {
1954 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1955 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1956 },
1957 },
1958 .expect = {
1959 { .payload_type_map = {112, 122}, },
1960 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001961 },
1962 },
1963 {
Philipp Maier621e8662023-03-22 16:53:30 +01001964 .descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001965 .codecs = {
1966 {
1967 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001968 },
1969 {
1970 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1971 },
1972 },
1973 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01001974 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001975 { .payload_type_map = {111, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001976 },
1977 },
1978 {
Philipp Maier621e8662023-03-22 16:53:30 +01001979 .descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001980 .codecs = {
1981 {
Philipp Maier621e8662023-03-22 16:53:30 +01001982 { 111, "AMR/8000", &amr_param_octet_aligned_false, },
1983 },
1984 {
1985 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1986 },
1987 },
1988 .expect = {
1989 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001990 { .payload_type_map = {111, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01001991 },
1992 },
1993 {
1994 .descr = "test AMR with NULL param (oa <-> null)",
1995 .codecs = {
1996 {
1997 { 112, "AMR/8000", &amr_param_octet_aligned_true, },
1998 },
1999 {
2000 { 122, "AMR/8000", NULL, },
2001 },
2002 },
2003 .expect = {
2004 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
2005 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002006 { .payload_type_map = {112, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01002007 },
2008 },
2009 {
2010 .descr = "test AMR with NULL param (bwe <-> null)",
2011 .codecs = {
2012 {
Philipp Maierec967d72023-03-22 16:20:37 +01002013 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002014 },
2015 {
2016 { 122, "AMR/8000", NULL, },
2017 },
2018 },
2019 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01002020 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
Philipp Maierec967d72023-03-22 16:20:37 +01002021 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002022 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002023 },
2024 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002025 {
2026 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
2027 .codecs = {
2028 {
2029 { 0, "PCMU/8000/1", NULL, },
2030 { 111, "GSM-HR-08/8000/1", NULL, },
2031 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2032 },
2033 {
2034 { 97, "GSM-HR-08/8000", NULL, },
2035 { 0, "PCMU/8000", NULL, },
2036 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
2037 },
2038 },
2039 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002040 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002041 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002042 },
2043 },
2044 {
2045 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
2046 .codecs = {
2047 {
2048 { 0, "PCMU/8000/1", NULL, },
2049 { 111, "GSM-HR-08/8000/1", NULL, },
2050 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2051 },
2052 {
2053 { 97, "GSM-HR-08", NULL, },
2054 { 0, "PCMU", NULL, },
2055 { 96, "AMR", &amr_param_octet_aligned_true, },
2056 },
2057 },
2058 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002059 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002060 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002061 },
2062 },
2063 {
2064 .descr = "test whether channel number matching is waterproof",
2065 .codecs = {
2066 {
2067 { 111, "GSM-HR-08/8000", },
2068 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
2069 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
2070 },
2071 {
2072 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
2073 { 121, "GSM-HR-08/8000/1", },
2074 },
2075 },
2076 .expect = {
2077 { .payload_type_map = {111, 121}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002078 { .payload_type_map = {111, 121} },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002079 },
2080 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002081};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002082
Philipp Maier4c4d2272023-04-26 15:45:17 +02002083static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
2084 const struct testcase_mgcp_codec_decide_expect *expect)
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002085{
Philipp Maier4c4d2272023-04-26 15:45:17 +02002086 bool ok = true;
2087 int payload_type_conn_src;
2088 int payload_type_conn_dst;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002089
Philipp Maier4c4d2272023-04-26 15:45:17 +02002090 printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
2091 if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
2092 if (expect->payload_type_map[index_conn_src] == -EINVAL
2093 && expect->payload_type_map[index_conn_dst] == -EINVAL)
2094 printf(" codec decision failed (expected)!\n");
2095 else {
2096 printf(" ERROR: codec decision failed!\n");
2097 ok = false;
2098 }
2099 } else {
2100 printf(" Codec decision result:\n");
2101 if (conn[index_conn_src].end.codec) {
2102 payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
2103 printf(" conn[%u]: codec:%s, pt:%d\n",
2104 index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
2105 } else {
2106 payload_type_conn_src = -EINVAL;
2107 printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
2108 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002109
Philipp Maier4c4d2272023-04-26 15:45:17 +02002110 if (conn[index_conn_dst].end.codec) {
2111 payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
2112 printf(" conn[%u]: codec:%s, pt:%d\n",
2113 index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
2114 payload_type_conn_dst);
2115 } else {
2116 payload_type_conn_dst = -EINVAL;
2117 printf(" conn[%u]: codec:none, pt:none\n", index_conn_dst);
2118 }
2119
2120 if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
2121 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2122 index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
2123 ok = false;
2124 }
2125
2126 if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
2127 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2128 index_conn_dst, expect->payload_type_map[index_conn_dst],
2129 payload_type_conn_dst);
2130 ok = false;
2131 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002132 }
Philipp Maier4c4d2272023-04-26 15:45:17 +02002133
2134 return ok;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002135}
2136
Philipp Maier4c4d2272023-04-26 15:45:17 +02002137static void test_mgcp_codec_decide(void)
Philipp Maier6931f9a2018-07-26 09:29:31 +02002138{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002139 int i;
2140 bool ok = true;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002141 printf("\nTesting mgcp_codec_find_convertible()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002142
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002143 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002144 const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
2145 struct mgcp_conn_rtp conn[2] = { };
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002146 int rc;
2147 int conn_i;
2148 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002149
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002150 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002151
Philipp Maier4c4d2272023-04-26 15:45:17 +02002152 /* Build testvector (add codecs to conn, set properties etc... */
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002153 for (conn_i = 0; conn_i < 2; conn_i++) {
2154 printf(" - add codecs on conn%d:\n", conn_i);
2155 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002156 const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002157 if (!codec->audio_name)
2158 break;
2159
Philipp Maier4c4d2272023-04-26 15:45:17 +02002160 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
2161 codec->param);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002162
2163 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2164 codec->param ?
Philipp Maier4c4d2272023-04-26 15:45:17 +02002165 (codec->param->amr_octet_aligned_present ?
2166 (codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
2167 : " octet-aligned=unset")
2168 : "", rc);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002169 if (rc != codec->expect_rc) {
2170 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2171 ok = false;
2172 }
2173 }
2174 if (!c)
2175 printf(" (none)\n");
2176 }
2177
Philipp Maier4c4d2272023-04-26 15:45:17 +02002178 /* Run codec decision and check expectation */
2179 if (!codec_decision(conn, 0, 1, &t->expect[0]))
2180 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002181
Philipp Maier4c4d2272023-04-26 15:45:17 +02002182 if (!codec_decision(conn, 1, 0, &t->expect[1]))
2183 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002184
Philipp Maier4c4d2272023-04-26 15:45:17 +02002185 if (ok)
2186 printf(" ===> SUCCESS: codec decision as expected!\n");
2187 else
2188 printf(" ===> FAIL: unexpected codec decision!\n");
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002189 }
2190
2191 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002192}
2193
Harald Welte9befdeb2022-11-03 11:41:05 +01002194void test_conn_id_matching(void)
Neels Hofmeyr65317262018-09-03 22:11:05 +02002195{
2196 struct mgcp_endpoint endp = {};
2197 struct mgcp_conn *conn;
2198 struct mgcp_conn *conn_match;
2199 int i;
2200 const char *conn_id_generated = "000023AB";
2201 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002202 "23AB",
2203 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002204 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002205 "00000023AB",
2206 "23ab",
2207 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002208 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002209 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002210 };
2211
2212 printf("\nTesting %s\n", __func__);
2213
2214 INIT_LLIST_HEAD(&endp.conns);
2215
2216 conn = talloc_zero(NULL, struct mgcp_conn);
2217 OSMO_ASSERT(conn);
2218 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2219 llist_add(&conn->entry, &endp.conns);
2220
2221 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2222 const char *needle = conn_id_request[i];
2223 printf("needle='%s' ", needle);
2224 conn_match = mgcp_conn_get(&endp, needle);
2225 OSMO_ASSERT(conn_match);
2226 printf("found '%s'\n", conn_match->id);
2227 OSMO_ASSERT(conn_match == conn);
2228 }
2229
2230 llist_del(&conn->entry);
2231 talloc_free(conn);
2232}
2233
Harald Welte9befdeb2022-11-03 11:41:05 +01002234void test_e1_trunk_nr_from_epname(void)
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002235{
Philipp Maierd70eef62021-07-19 13:53:28 +02002236 unsigned int trunk_nr;
2237 int rc;
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002238
2239 /* Note: e1_trunk_nr_from_epname does not check the text
2240 * after the E1 trunk number, after the delimiter
2241 * character "/" arbitrary text may follow. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002242 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
Philipp Maier0653cc82020-08-10 22:52:51 +02002243 OSMO_ASSERT(trunk_nr == 0);
Philipp Maierd70eef62021-07-19 13:53:28 +02002244 OSMO_ASSERT(rc == 0);
2245 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002246 OSMO_ASSERT(trunk_nr == 1);
Philipp Maierd70eef62021-07-19 13:53:28 +02002247 OSMO_ASSERT(rc == 0);
2248 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002249 OSMO_ASSERT(trunk_nr == 2);
Philipp Maierd70eef62021-07-19 13:53:28 +02002250 OSMO_ASSERT(rc == 0);
2251 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002252 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002253 OSMO_ASSERT(rc == 0);
2254 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002255 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002256 OSMO_ASSERT(rc == 0);
2257 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002258 OSMO_ASSERT(trunk_nr == 24);
Philipp Maierd70eef62021-07-19 13:53:28 +02002259 OSMO_ASSERT(rc == 0);
2260 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002261 OSMO_ASSERT(trunk_nr == 64);
Philipp Maierd70eef62021-07-19 13:53:28 +02002262 OSMO_ASSERT(rc == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002263
2264 /* The following endpoint strings should fail, either the
2265 * trunk number exceeds the valid range or the trunk prefix
2266 * is wrong. Also when the delimiter character "/" at the
2267 * end of the trunk is wrong the parsing should fail. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002268 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
2269 OSMO_ASSERT(rc == -EINVAL);
2270 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
2271 OSMO_ASSERT(rc == -EINVAL);
2272 rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
2273 OSMO_ASSERT(rc == -EINVAL);
2274 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
2275 OSMO_ASSERT(rc == -EINVAL);
2276 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
2277 OSMO_ASSERT(rc == -EINVAL);
2278 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
2279 OSMO_ASSERT(rc == -EINVAL);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002280
2281 return;
2282}
2283
Harald Welte9befdeb2022-11-03 11:41:05 +01002284void test_mgcp_is_rtp_dummy_payload(void)
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002285{
2286 /* realistic rtp packet */
2287 static const char rtp_payload[] =
2288 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2289 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2290 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2291 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2292 0x24 };
2293
2294 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2295 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2296 struct msgb *msg_dummy_rtp =
2297 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2298
2299 uint8_t *buf;
2300
2301 /* Dummy RTP packet */
2302 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2303 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2304
2305 /* Normal RTP packet */
2306 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2307 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2308
2309 /* Dummy RTP packet with normal RTP packet attached, this must not be
2310 * recognized as Dummy RTP packet */
2311 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2312 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2313 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2314 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2315
2316 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2317 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2318 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2319
2320 msgb_free(msg_dummy);
2321 msgb_free(msg_rtp);
2322 msgb_free(msg_dummy_rtp);
2323}
2324
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002325int main(int argc, char **argv)
2326{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002327 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2328 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2329 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002330
2331 test_strline();
2332 test_values();
2333 test_messages();
2334 test_retransmission();
2335 test_packet_loss_calc();
2336 test_rqnt_cb();
2337 test_mgcp_stats();
2338 test_packet_error_detection(1, 0);
2339 test_packet_error_detection(0, 0);
2340 test_packet_error_detection(0, 1);
2341 test_packet_error_detection(1, 1);
2342 test_multilple_codec();
2343 test_no_cycle();
2344 test_no_name();
2345 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002346 test_get_lco_identifier();
2347 test_check_local_cx_options(ctx);
Philipp Maier4c4d2272023-04-26 15:45:17 +02002348 test_mgcp_codec_decide();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002349 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002350 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002351 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002352
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002353 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2354 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2355 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002356 printf("Done\n");
2357 return EXIT_SUCCESS;
2358}