blob: 65756e0c8628f536a45f6ff690065be7bf6b6c8c [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
Neels Hofmeyr23140d62024-06-14 16:03:24 +0200389#define CRCX_PORT_0 \
390 "CRCX 3 1@mgw MGCP 1.0\r\n" \
391 "m: recvonly\r\n" \
392 "C: 2\r\n" \
393 "L: p:20\r\n" \
394 "\r\n" \
395 "v=0\r\n" \
396 "c=IN IP4 123.12.12.123\r\n" \
397 "m=audio 0 RTP/AVP 97\r\n" \
398 "a=rtpmap:97 GSM-EFR/8000\r\n" \
399 "a=ptime:40\r\n"
400
401#define CRCX_PORT_0_RET \
402 "200 3 OK\r\n" \
403 "I: %s\r\n" \
404 "\r\n" \
405 "v=0\r\n" \
406 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
407 "s=-\r\n" \
408 "c=IN IP4 0.0.0.0\r\n" \
409 "t=0 0\r\n" \
410 "m=audio 16014 RTP/AVP 97\r\n" \
411 "a=rtpmap:97 GSM-EFR/8000\r\n" \
412 "a=ptime:40\r\n"
413
414#define CRCX_PORT_0_IUFP \
415 "CRCX 4 1@mgw MGCP 1.0\r\n" \
416 "m: recvonly\r\n" \
417 "C: 2\r\n" \
418 "L: p:20\r\n" \
419 "\r\n" \
420 "v=0\r\n" \
421 "c=IN IP4 123.12.12.123\r\n" \
422 "m=audio 0 RTP/AVP 96\r\n" \
423 "a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
424 "a=ptime:40\r\n"
425
426#define CRCX_PORT_0_IUFP_RET \
427 "200 4 OK\r\n" \
428 "I: %s\r\n" \
429 "\r\n" \
430 "v=0\r\n" \
431 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
432 "s=-\r\n" \
433 "c=IN IP4 0.0.0.0\r\n" \
434 "t=0 0\r\n" \
435 "m=audio 16016 RTP/AVP 96\r\n" \
436 "a=rtpmap:96 VND.3GPP.IUFP/16000\r\n" \
437 "a=ptime:40\r\n"
438
Philipp Maier87bd9be2017-08-22 16:35:41 +0200439#define DLCX \
440 "DLCX 7 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100441 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200442 "C: 2\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200443
Philipp Maier87bd9be2017-08-22 16:35:41 +0200444#define DLCX_RET \
445 "250 7 OK\r\n" \
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100446 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
447
448 #define DLCX_RET_OSMUX DLCX_RET \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200449 "X-Osmo-CP: EC TI=0, TO=0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200450
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200451#define DLCX_NULL \
452 "DLCX 8 null@mgw MGCP 1.0\r\n" \
453 "I: %s\r\n" \
454 "C: 2\r\n"
455
456#define DLCX_NULL_RET "502 8 FAIL\r\n"
457
Philipp Maier87bd9be2017-08-22 16:35:41 +0200458#define RQNT \
459 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
460 "X: B244F267488\r\n" \
461 "S: D/9\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200462
Philipp Maier87bd9be2017-08-22 16:35:41 +0200463#define RQNT2 \
464 "RQNT 186908781 1@mgw MGCP 1.0\r\n" \
465 "X: ADD4F26746F\r\n" \
466 "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200467
468#define RQNT1_RET "200 186908780 OK\r\n"
469#define RQNT2_RET "200 186908781 OK\r\n"
470
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200471#define RQNT_NULL \
472 "RQNT 186908782 null@mgw MGCP 1.0\r\n" \
473 "X: B244F267488\r\n" \
474 "S: D/9\r\n"
475
476#define RQNT_NULL_RET "502 186908782 FAIL\r\n"
477
Philipp Maier87bd9be2017-08-22 16:35:41 +0200478#define PTYPE_IGNORE 0 /* == default initializer */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200479#define PTYPE_NONE 128
480#define PTYPE_NYI PTYPE_NONE
481
Philipp Maier87bd9be2017-08-22 16:35:41 +0200482#define CRCX_MULT_1 \
483 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200484 "M: recvonly\r\n" \
485 "C: 2\r\n" \
486 "X\r\n" \
487 "L: p:20\r\n" \
488 "\r\n" \
489 "v=0\r\n" \
490 "c=IN IP4 123.12.12.123\r\n" \
491 "m=audio 5904 RTP/AVP 18 97\r\n" \
492 "a=rtpmap:18 G729/8000\r\n" \
493 "a=rtpmap:97 GSM-EFR/8000\r\n" \
494 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200495
Philipp Maier87bd9be2017-08-22 16:35:41 +0200496#define CRCX_MULT_2 \
497 "CRCX 2 2@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200498 "M: recvonly\r\n" \
499 "C: 2\r\n" \
500 "X\r\n" \
501 "L: p:20\r\n" \
502 "\r\n" \
503 "v=0\r\n" \
504 "c=IN IP4 123.12.12.123\r\n" \
505 "m=audio 5904 RTP/AVP 18 97 101\r\n" \
506 "a=rtpmap:18 G729/8000\r\n" \
507 "a=rtpmap:97 GSM-EFR/8000\r\n" \
508 "a=rtpmap:101 FOO/8000\r\n" \
509 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200510
Philipp Maier87bd9be2017-08-22 16:35:41 +0200511#define CRCX_MULT_3 \
512 "CRCX 2 3@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200513 "M: recvonly\r\n" \
514 "C: 2\r\n" \
515 "X\r\n" \
516 "L: p:20\r\n" \
517 "\r\n" \
518 "v=0\r\n" \
519 "c=IN IP4 123.12.12.123\r\n" \
520 "m=audio 5904 RTP/AVP\r\n" \
521 "a=rtpmap:18 G729/8000\r\n" \
522 "a=rtpmap:97 GSM-EFR/8000\r\n" \
523 "a=rtpmap:101 FOO/8000\r\n" \
524 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200525
Philipp Maier87bd9be2017-08-22 16:35:41 +0200526#define CRCX_MULT_4 \
527 "CRCX 2 4@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200528 "M: recvonly\r\n" \
529 "C: 2\r\n" \
530 "X\r\n" \
531 "L: p:20\r\n" \
532 "\r\n" \
533 "v=0\r\n" \
534 "c=IN IP4 123.12.12.123\r\n" \
535 "m=audio 5904 RTP/AVP 18\r\n" \
536 "a=rtpmap:18 G729/8000\r\n" \
537 "a=rtpmap:97 GSM-EFR/8000\r\n" \
538 "a=rtpmap:101 FOO/8000\r\n" \
539 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200540
541#define CRCX_MULT_GSM_EXACT \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200542 "CRCX 259260421 5@mgw MGCP 1.0\r\n" \
543 "C: 1355c6041e\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200544 "L: p:20, a:GSM, nt:IN\r\n" \
545 "M: recvonly\r\n" \
546 "\r\n" \
547 "v=0\r\n" \
548 "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
549 "s=-\r\nc=IN IP4 192.168.181.247\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200550 "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 +0200551 "a=rtpmap:0 PCMU/8000\r\n" \
552 "a=rtpmap:8 PCMA/8000\r\n" \
553 "a=rtpmap:3 gsm/8000\r\n" \
554 "a=rtpmap:18 G729/8000\r\n" \
555 "a=fmtp:18 annexb=no\r\n" \
556 "a=rtpmap:4 G723/8000\r\n" \
557 "a=rtpmap:96 iLBC/8000\r\n" \
558 "a=fmtp:96 mode=20\r\n" \
559 "a=rtpmap:97 iLBC/8000\r\n" \
560 "a=fmtp:97 mode=30\r\n" \
561 "a=rtpmap:101 telephone-event/8000\r\n" \
562 "a=fmtp:101 0-15\r\n" \
563 "a=recvonly\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200564
Philipp Maier87bd9be2017-08-22 16:35:41 +0200565#define MDCX_NAT_DUMMY \
566 "MDCX 23 5@mgw MGCP 1.0\r\n" \
567 "C: 1355c6041e\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100568 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200569 "\r\n" \
570 "c=IN IP4 8.8.8.8\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200571 "m=audio 16434 RTP/AVP 3\r\n"
572
573#define CRCX_NO_LCO_NO_SDP \
574 "CRCX 2 6@mgw MGCP 1.0\r\n" \
575 "M: recvonly\r\n" \
576 "C: 2\r\n"
577
Philipp Maier228e5912019-03-05 13:56:59 +0100578#define CRCX_AMR_WITH_FMTP \
579 "CRCX 2 7@mgw MGCP 1.0\r\n" \
580 "M: recvonly\r\n" \
581 "C: 2\r\n" \
582 "X\r\n" \
583 "L: p:20\r\n" \
584 "\r\n" \
585 "v=0\r\n" \
586 "c=IN IP4 123.12.12.123\r\n" \
587 "m=audio 5904 RTP/AVP 111\r\n" \
588 "a=rtpmap:111 AMR/8000/1\r\n" \
589 "a=ptime:20\r\n" \
590 "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
591
592#define CRCX_AMR_WITH_FMTP_RET \
593 "200 2 OK\r\n" \
594 "I: %s\r\n" \
595 "\r\n" \
596 "v=0\r\n" \
597 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
598 "s=-\r\n" \
599 "c=IN IP4 0.0.0.0\r\n" \
600 "t=0 0\r\n" \
601 "m=audio 16012 RTP/AVP 111\r\n" \
602 "a=rtpmap:111 AMR/8000/1\r\n" \
603 "a=fmtp:111 octet-align=1\r\n" \
604 "a=ptime:20\r\n"
605
Philipp Maierbc0346e2018-06-07 09:52:16 +0200606#define CRCX_NO_LCO_NO_SDP_RET \
607 "200 2 OK\r\n" \
608 "I: %s\r\n" \
609 "\r\n" \
610 "v=0\r\n" \
611 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
612 "s=-\r\n" \
613 "c=IN IP4 0.0.0.0\r\n" \
614 "t=0 0\r\n" \
615 "m=audio 16008 RTP/AVP 0\r\n" \
616 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200617
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200618#define CRCX_NULL \
619 "CRCX 2 null@mgw MGCP 1.0\r\n" \
620 "m: recvonly\r\n" \
621 "C: 2\r\n" \
622 "L: p:20\r\n" \
623 "\r\n" \
624 "v=0\r\n" \
625 "c=IN IP4 123.12.12.123\r\n" \
626 "m=audio 5904 RTP/AVP 97\r\n" \
627 "a=rtpmap:97 GSM-EFR/8000\r\n" \
628 "a=ptime:40\r\n"
629
630#define CRCX_NULL_RET "502 2 FAIL\r\n"
631
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200632struct mgcp_test {
633 const char *name;
634 const char *req;
635 const char *exp_resp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200636 int ptype;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200637};
638
639static const struct mgcp_test tests[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200640 {"AUEP1", AUEP1, AUEP1_RET},
641 {"AUEP2", AUEP2, AUEP2_RET},
642 {"MDCX1", MDCX_WRONG_EP, MDCX_ERR_RET},
643 {"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
644 {"CRCX", CRCX, CRCX_RET, 97},
645 {"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200646 {"MDCX4_ADDR000", MDCX4_ADDR0000, MDCX4_ADDR0000_RET},
647 {"MDCX4", MDCX4, MDCX4_RET("18983217"), 99},
648 {"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983218"), 99},
649 {"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983219"), 99},
650 {"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983220"), 99},
651 {"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983221"), 99},
652 {"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983222"), 99},
653 {"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983223"), PTYPE_IGNORE},
Philipp Maier87bd9be2017-08-22 16:35:41 +0200654 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
655 {"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
656 {"EMPTY", EMPTY, EMPTY_RET},
657 {"SHORT1", SHORT, SHORT_RET},
658 {"SHORT2", SHORT2, SHORT2_RET},
659 {"SHORT3", SHORT3, SHORT2_RET},
660 {"SHORT4", SHORT4, SHORT2_RET},
661 {"RQNT1", RQNT, RQNT1_RET},
662 {"RQNT2", RQNT2, RQNT2_RET},
663 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
Neels Hofmeyrd0dbda42023-12-23 03:54:58 +0100664 {"CRCX", CRCX, CRCX_FMTP_RET, 97},
665 {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE},
666 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
Philipp Maierbc0346e2018-06-07 09:52:16 +0200667 {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200668 {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200669 {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
Philipp Maier228e5912019-03-05 13:56:59 +0100670 {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200671 {"AUEP_NULL", AUEP_NULL, AUEP_NULL_RET},
672 {"CRCX_NULL", CRCX_NULL, CRCX_NULL_RET},
673 {"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
674 {"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
675 {"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
Neels Hofmeyr23140d62024-06-14 16:03:24 +0200676 {"CRCX_PORT_0", CRCX_PORT_0, CRCX_PORT_0_RET, 97},
677 {"CRCX_PORT_0_IUFP", CRCX_PORT_0_IUFP, CRCX_PORT_0_IUFP_RET, 96},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200678};
679
680static const struct mgcp_test retransmit[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200681 {"CRCX", CRCX, CRCX_RET},
682 {"RQNT1", RQNT, RQNT1_RET},
683 {"RQNT2", RQNT2, RQNT2_RET},
684 {"MDCX3", MDCX3, MDCX3A_RET},
685 {"DLCX", DLCX, DLCX_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200686};
687
Philipp Maierffd75e42017-11-22 11:44:50 +0100688static struct msgb *create_msg(const char *str, const char *conn_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200689{
690 struct msgb *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100691 int len;
692
693 printf("creating message from statically defined input:\n");
694 printf("---------8<---------\n%s\n---------8<---------\n", str);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200695
696 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
Philipp Maierffd75e42017-11-22 11:44:50 +0100697 if (conn_id && strlen(conn_id))
698 len = sprintf((char *)msg->data, str, conn_id, conn_id);
699 else
700 len = sprintf((char *)msg->data, "%s", str);
701
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200702 msg->l2h = msgb_put(msg, len);
703 return msg;
704}
705
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200706static int dummy_packets = 0;
707/* override and forward */
Harald Welte352b9672024-03-17 12:03:24 +0100708int osmo_iofd_sendto_msgb(struct osmo_io_fd *iofd, struct msgb *msg, int flags, const struct osmo_sockaddr *addr)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200709{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200710 uint32_t dest_host =
Harald Welte352b9672024-03-17 12:03:24 +0100711 htonl(((struct sockaddr_in *)addr)->sin_addr.s_addr);
712 int dest_port = htons(((struct sockaddr_in *)addr)->sin_port);
713 const uint8_t *buf = msgb_data(msg);
714 size_t len = msgb_length(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200715
Philipp Maierb3d14eb2021-05-20 14:18:52 +0200716 if (len == sizeof(rtp_dummy_payload)
717 && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200718 fprintf(stderr,
719 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
720 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200721 dummy_packets += 1;
722 }
723
Pau Espin Pedrola24dcc62021-07-06 17:48:47 +0200724 /* Make sure address+port are valid */
725 OSMO_ASSERT(dest_host);
726 OSMO_ASSERT(dest_port);
727
Harald Welte352b9672024-03-17 12:03:24 +0100728 msgb_free(msg);
729
Philipp Maier3d9b6562017-10-13 18:33:44 +0200730 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200731}
732
733static int64_t force_monotonic_time_us = -1;
734/* override and forward */
735int clock_gettime(clockid_t clk_id, struct timespec *tp)
736{
737 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
738 static clock_gettime_t real_clock_gettime = NULL;
739
740 if (!real_clock_gettime)
741 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
742
743 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
744 tp->tv_sec = force_monotonic_time_us / 1000000;
745 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
746 return 0;
747 }
748
749 return real_clock_gettime(clk_id, tp);
750}
751
Philipp Maier14b27a82020-06-02 20:15:30 +0200752static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200753{
754 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200755 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200756 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200757}
758
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200759#define CONN_UNMODIFIED (0x1000)
760
761static void test_values(void)
762{
763 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200764 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200765
766 /* Check that LOOPBACK enables all output */
767 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200768 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200769}
770
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200771/* Extract a connection ID from a response and return in conn_id;
772 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100773static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200774 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100775{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200776 const char *conn_id_start;
777 const char *conn_id_end;
778 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100779
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200780 const char *header_I = "\r\nI: ";
781 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100782
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200783 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
784 if ((conn_id_start = strstr((char *)resp, header_I))) {
785 conn_id_start += strlen(header_I);
786 conn_id_end = strstr(conn_id_start, "\r\n");
787 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
788 conn_id_start += strlen(header_o);
789 conn_id_end = strchr(conn_id_start, ' ');
790 } else
791 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100792
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200793 if (conn_id_end)
794 conn_id_len = conn_id_end - conn_id_start;
795 else
796 conn_id_len = strlen(conn_id_start);
797 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100798
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200799 /* A valid conn_id must at least contain one digit, and must
800 * not exceed a length of 32 digits */
801 OSMO_ASSERT(conn_id_len <= 32);
802 OSMO_ASSERT(conn_id_len > 0);
803
804 strncpy(conn_id, conn_id_start, conn_id_len);
805 conn_id[conn_id_len] = '\0';
806 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100807}
808
809/* Check response, automatically patch connection ID if needed */
810static int check_response(uint8_t *resp, const char *exp_resp)
811{
812 char exp_resp_patched[4096];
813 const char *exp_resp_ptr;
814 char conn_id[256];
815
816 printf("checking response:\n");
817
818 /* If the expected response is intened to be patched
819 * (%s placeholder inside) we will patch it with the
820 * connection identifier we just received from the
821 * real response. This is necessary because the CI
822 * is generated by the mgcp code on CRCX and we can
823 * not know it in advance */
824 if (strstr(exp_resp, "%s")) {
825 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
826 0) {
827 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
828 exp_resp_ptr = exp_resp_patched;
829 printf
830 ("using message with patched conn_id for comparison\n");
831 } else {
832 printf
833 ("patching conn_id failed, using message as statically defined for comparison\n");
834 exp_resp_ptr = exp_resp;
835 }
836 } else {
837 printf("using message as statically defined for comparison\n");
838 exp_resp_ptr = exp_resp;
839 }
840
841 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
842 printf("Unexpected response, please check!\n");
843 printf
844 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
845 resp);
846 printf
847 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
848 exp_resp_ptr);
849 return -EINVAL;
850 }
851
852 printf("Response matches our expectations.\n");
853 return 0;
854}
855
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200856static void test_messages(void)
857{
858 struct mgcp_config *cfg;
859 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200860 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200861 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200862 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100863 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100864 int rc;
Philipp Maier39889e42021-08-04 17:42:57 +0200865 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200866
867 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200868 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200869
Philipp Maier889fe7f2020-07-06 17:44:12 +0200870 trunk->v.vty_number_endpoints = 64;
871 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200872
Philipp Maierffd75e42017-11-22 11:44:50 +0100873 memset(last_conn_id, 0, sizeof(last_conn_id));
874
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200875 for (i = 0; i < ARRAY_SIZE(tests); i++) {
876 const struct mgcp_test *t = &tests[i];
877 struct msgb *inp;
878 struct msgb *msg;
879
Philipp Maierffd75e42017-11-22 11:44:50 +0100880 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200881 printf("Testing %s\n", t->name);
882
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200883 dummy_packets = 0;
884
Philipp Maierffd75e42017-11-22 11:44:50 +0100885 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200886 msg = mgcp_handle_message(cfg, inp);
887 msgb_free(inp);
888 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200889 if (msg) {
890 printf("%s failed '%s'\n", t->name,
891 (char *)msg->data);
892 OSMO_ASSERT(false);
893 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100894 } else if (check_response(msg->data, t->exp_resp) != 0) {
895 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200896 OSMO_ASSERT(false);
897 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100898
Philipp Maier7df419b2017-12-04 17:11:42 +0100899 if (msg) {
900 rc = get_conn_id_from_response(msg->data, last_conn_id,
901 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200902 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100903 printf("(response contains a connection id)\n");
904 else
905 printf("(response does not contain a connection id)\n");
906 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100907
Philipp Maiera330b862017-12-04 17:16:16 +0100908 if (msg)
909 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200910
911 if (dummy_packets)
912 printf("Dummy packets: %d\n", dummy_packets);
913
Philipp Maier37a808c2020-07-03 15:48:31 +0200914 if (last_endpoint[0] != '\0') {
915 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
916 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200917
Philipp Maier01d24a32017-11-21 17:26:09 +0100918 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200919 if (conn) {
920 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200921
Philipp Maier87bd9be2017-08-22 16:35:41 +0200922 if (conn->end.packet_duration_ms != -1)
923 printf("Detected packet duration: %d\n",
924 conn->end.packet_duration_ms);
925 else
926 printf("Packet duration not set\n");
927 if (endp->local_options.pkt_period_min ||
928 endp->local_options.pkt_period_max)
929 printf
Oliver Smith169d50e2023-01-24 13:12:54 +0100930 ("Requested packetization period: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200931 "%d-%d\n",
932 endp->local_options.pkt_period_min,
933 endp->
934 local_options.pkt_period_max);
935 else
936 printf
937 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200938
Philipp Maier87bd9be2017-08-22 16:35:41 +0200939 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
940 printf("Connection mode: %d:%s%s%s%s\n",
941 conn->conn->mode,
942 !conn->conn->mode ? " NONE" : "",
943 conn->conn->mode & MGCP_CONN_SEND_ONLY
944 ? " SEND" : "",
945 conn->conn->mode & MGCP_CONN_RECV_ONLY
946 ? " RECV" : "",
947 conn->conn->mode & MGCP_CONN_LOOPBACK
948 & ~MGCP_CONN_RECV_SEND
949 ? " LOOP" : "");
950 fprintf(stderr,
951 "RTP output %sabled, NET output %sabled\n",
952 conn->end.output_enabled
953 ? "en" : "dis",
954 conn->end.output_enabled
955 ? "en" : "dis");
956 } else
957 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200958
Philipp Maier87bd9be2017-08-22 16:35:41 +0200959 OSMO_ASSERT(conn->end.output_enabled
Pau Espin Pedrol2c401642021-12-24 14:48:26 +0100960 == !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200961
962 conn->conn->mode |= CONN_UNMODIFIED;
963
964 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200965 endp->local_options.pkt_period_min = 0;
966 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200967 }
968
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200969 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100970 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200971 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200972
Philipp Maier37a808c2020-07-03 15:48:31 +0200973 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200974 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200975 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200976 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200977
Philipp Maier87bd9be2017-08-22 16:35:41 +0200978 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200979 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200980 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200981
982 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200983 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200984 }
985 }
986
Philipp Maierd19de2e2020-06-03 13:55:33 +0200987 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200988 talloc_free(cfg);
989}
990
991static void test_retransmission(void)
992{
993 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200994 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200995 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100996 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100997 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200998
999 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001000 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001001
Philipp Maier889fe7f2020-07-06 17:44:12 +02001002 trunk->v.vty_number_endpoints = 64;
1003 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001004
Philipp Maierffd75e42017-11-22 11:44:50 +01001005 memset(last_conn_id, 0, sizeof(last_conn_id));
1006
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001007 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
1008 const struct mgcp_test *t = &retransmit[i];
1009 struct msgb *inp;
1010 struct msgb *msg;
1011
Philipp Maierffd75e42017-11-22 11:44:50 +01001012 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001013 printf("Testing %s\n", t->name);
1014
Philipp Maierffd75e42017-11-22 11:44:50 +01001015 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001016 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001017
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001018 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +01001019 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001020 printf("%s failed '%s'\n", t->name, (char *)msg->data);
1021 OSMO_ASSERT(false);
1022 }
Philipp Maierffd75e42017-11-22 11:44:50 +01001023
Philipp Maier23b8e292017-12-04 16:48:45 +01001024 if (msg && strcmp(t->name, "CRCX") == 0) {
1025 rc = get_conn_id_from_response(msg->data, last_conn_id,
1026 sizeof(last_conn_id));
1027 OSMO_ASSERT(rc == 0);
1028 }
Philipp Maierffd75e42017-11-22 11:44:50 +01001029
Philipp Maier7cedfd72017-12-04 16:49:12 +01001030 if (msg)
1031 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032
1033 /* Retransmit... */
1034 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +01001035 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001036 msg = mgcp_handle_message(cfg, inp);
1037 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001038 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001039 printf("%s failed '%s'\n", t->name, (char *)msg->data);
1040 OSMO_ASSERT(false);
1041 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001042 msgb_free(msg);
1043 }
1044
Philipp Maierd19de2e2020-06-03 13:55:33 +02001045 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001046 talloc_free(cfg);
1047}
1048
1049static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
1050{
1051 ptrdiff_t tone = _tone;
Ericfbf78d12021-08-23 22:31:39 +02001052 endp->trunk->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001053 return 0;
1054}
1055
1056static void test_rqnt_cb(void)
1057{
1058 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001059 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001060 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +01001061 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001062
1063 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001064 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001065 cfg->rqnt_cb = rqnt_cb;
1066
Philipp Maier889fe7f2020-07-06 17:44:12 +02001067 trunk->v.vty_number_endpoints = 64;
1068 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001069
Philipp Maierffd75e42017-11-22 11:44:50 +01001070 inp = create_msg(CRCX, NULL);
1071 msg = mgcp_handle_message(cfg, inp);
1072 OSMO_ASSERT(msg);
1073 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
1074 sizeof(conn_id)) == 0);
1075 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001076 msgb_free(inp);
1077
1078 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +01001079 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001080 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001081 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001082 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
1083 abort();
1084 }
1085
Philipp Maier87bd9be2017-08-22 16:35:41 +02001086 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001087 printf("FAILED: callback not called: %p\n", cfg->data);
1088 abort();
1089 }
1090
1091 msgb_free(msg);
1092 msgb_free(inp);
1093
Philipp Maierffd75e42017-11-22 11:44:50 +01001094 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001095 msgb_free(mgcp_handle_message(cfg, inp));
1096 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001097 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001098 talloc_free(cfg);
1099}
1100
1101struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001102 int cycles;
1103 uint16_t base_seq;
1104 uint16_t max_seq;
1105 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001106
Philipp Maier87bd9be2017-08-22 16:35:41 +02001107 uint32_t expected;
1108 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001109};
1110
1111static const struct pl_test pl_test_dat[] = {
1112 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001113 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1114 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001115 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001116 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1117 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001118 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001119 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1120 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001121 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001122 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1123 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001124 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001125 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1126 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001127};
1128
1129static void test_packet_loss_calc(void)
1130{
1131 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001132 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001133 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001134 struct mgcp_config *cfg;
1135 struct mgcp_trunk *trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001136
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001137 printf("Testing packet loss calculation.\n");
1138
Philipp Maiercede2a42018-07-03 14:14:21 +02001139 memset(&endp, 0, sizeof(endp));
Philipp Maier124a3e02021-07-26 11:17:15 +02001140 cfg = mgcp_config_alloc();
1141 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maiercede2a42018-07-03 14:14:21 +02001142 endp.type = &ep_typeset.rtp;
Philipp Maier124a3e02021-07-26 11:17:15 +02001143 trunk->v.vty_number_endpoints = 1;
1144 trunk->endpoints = endpoints;
1145 trunk->endpoints[0] = &endp;
1146 endp.trunk = trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001147 INIT_LLIST_HEAD(&endp.conns);
1148
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001149 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1150 uint32_t expected;
1151 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001152
Philipp Maiercede2a42018-07-03 14:14:21 +02001153 struct mgcp_conn_rtp *conn = NULL;
1154 struct mgcp_conn *_conn = NULL;
1155 struct mgcp_rtp_state *state;
1156 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001157
Philipp Maiercede2a42018-07-03 14:14:21 +02001158 _conn =
1159 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1160 "test-connection");
1161 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1162 state = &conn->state;
Pau Espin Pedroldaf5bce2022-09-22 19:14:24 +02001163 packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001164
1165 state->stats.initialized = 1;
1166 state->stats.base_seq = pl_test_dat[i].base_seq;
1167 state->stats.max_seq = pl_test_dat[i].max_seq;
1168 state->stats.cycles = pl_test_dat[i].cycles;
1169
1170 packets_rx->current = pl_test_dat[i].packets;
1171 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001172
Philipp Maier87bd9be2017-08-22 16:35:41 +02001173 if (loss != pl_test_dat[i].loss
1174 || expected != pl_test_dat[i].expected) {
1175 printf
1176 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1177 i, loss, pl_test_dat[i].loss, expected,
1178 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001179 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001180
1181 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001182 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001183
Philipp Maier124a3e02021-07-26 11:17:15 +02001184 talloc_free(trunk);
1185 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001186}
1187
Philipp Maier87bd9be2017-08-22 16:35:41 +02001188int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1189 uint32_t *pr, uint32_t *_or, int *loss,
1190 uint32_t *jitter)
1191{
1192 char *line, *save;
1193 int rc;
1194
1195 /* initialize with bad values */
1196 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1197 *loss = INT_MAX;
1198
1199 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1200 if (!line)
1201 return -1;
1202
1203 /* this can only parse the message that is created above... */
1204 for_each_non_empty_line(line, save) {
1205 switch (line[0]) {
1206 case 'P':
1207 rc = sscanf(line,
1208 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1209 ps, os, pr, _or, loss, jitter);
1210 return rc == 6 ? 0 : -1;
1211 }
1212 }
1213
1214 return -1;
1215}
1216
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001217static void test_mgcp_stats(void)
1218{
1219 printf("Testing stat parsing\n");
1220
1221 uint32_t bps, bos, pr, _or, jitter;
1222 struct msgb *msg;
1223 int loss;
1224 int rc;
1225
Philipp Maierffd75e42017-11-22 11:44:50 +01001226 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001227 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1228 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001229 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1230 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001231 printf("FAIL: Parsing failed1.\n");
1232 msgb_free(msg);
1233
Philipp Maier87bd9be2017-08-22 16:35:41 +02001234 msg =
1235 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001236 ("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 +02001237 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1238 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001239 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1240 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001241 printf("FAIL: Parsing failed2.\n");
1242 msgb_free(msg);
1243}
1244
1245struct rtp_packet_info {
1246 float txtime;
1247 int len;
1248 char *data;
1249};
1250
1251struct rtp_packet_info test_rtp_packets1[] = {
1252 /* RTP: SeqNo=0, TS=0 */
1253 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001254 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001255 /* RTP: SeqNo=1, TS=160 */
1256 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001257 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001258 /* RTP: SeqNo=2, TS=320 */
1259 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001260 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001261 /* Repeat RTP timestamp: */
1262 /* RTP: SeqNo=3, TS=320 */
1263 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001264 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001265 /* RTP: SeqNo=4, TS=480 */
1266 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001267 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001268 /* RTP: SeqNo=5, TS=640 */
1269 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001270 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001271 /* Double skip RTP timestamp (delta = 2*160): */
1272 /* RTP: SeqNo=6, TS=960 */
1273 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001274 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001275 /* RTP: SeqNo=7, TS=1120 */
1276 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001277 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001278 /* RTP: SeqNo=8, TS=1280 */
1279 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001280 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001281 /* Non 20ms RTP timestamp (delta = 120): */
1282 /* RTP: SeqNo=9, TS=1400 */
1283 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001284 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001285 /* RTP: SeqNo=10, TS=1560 */
1286 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001287 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001288 /* RTP: SeqNo=11, TS=1720 */
1289 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001290 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001291 /* SSRC changed to 0x10203040, RTP timestamp jump */
1292 /* RTP: SeqNo=12, TS=34688 */
1293 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001294 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001295 /* RTP: SeqNo=13, TS=34848 */
1296 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001297 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001298 /* RTP: SeqNo=14, TS=35008 */
1299 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001300 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001301 /* Non 20ms RTP timestamp (delta = 120): */
1302 /* RTP: SeqNo=15, TS=35128 */
1303 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001304 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001305 /* RTP: SeqNo=16, TS=35288 */
1306 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001307 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001308 /* RTP: SeqNo=17, TS=35448 */
1309 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001310 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001311 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1312 /* RTP: SeqNo=19, TS=35768 */
1313 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001314 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001315 /* RTP: SeqNo=20, TS=35928 */
1316 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001317 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001318 /* RTP: SeqNo=21, TS=36088 */
1319 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001320 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001321 /* Repeat last packet */
1322 /* RTP: SeqNo=21, TS=36088 */
1323 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001324 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001325 /* RTP: SeqNo=22, TS=36248 */
1326 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001327 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001328 /* RTP: SeqNo=23, TS=36408 */
1329 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001330 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001331 /* Don't increment SeqNo but increment timestamp by 160 */
1332 /* RTP: SeqNo=23, TS=36568 */
1333 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001334 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001335 /* RTP: SeqNo=24, TS=36728 */
1336 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001337 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001338 /* RTP: SeqNo=25, TS=36888 */
1339 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001340 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001341 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1342 * SeqNo jump */
1343 /* RTP: SeqNo=1000, TS=160000 */
1344 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001345 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001346 /* RTP: SeqNo=1001, TS=160160 */
1347 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001348 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001349 /* RTP: SeqNo=1002, TS=160320 */
1350 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001351 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001352 /* RTP: SeqNo=1003, TS=180320, Marker */
1353 {2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
1354 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1355 /* RTP: SeqNo=1004, TS=180480 */
1356 {2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
1357 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1358 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
1359 {2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
1360 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001361};
1362
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001363static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1364{
1365 int i;
1366
Philipp Maier124a3e02021-07-26 11:17:15 +02001367 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001368 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001369 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001370 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001371 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001372 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001373 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001374 uint32_t last_ssrc = 0;
1375 uint32_t last_timestamp = 0;
1376 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001377 uint64_t last_in_ts_err_cnt = 0;
1378 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001379 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001380 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001381 struct rate_ctr test_ctr_in;
1382 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001383
1384 printf("Testing packet error detection%s%s.\n",
1385 patch_ssrc ? ", patch SSRC" : "",
1386 patch_ts ? ", patch timestamps" : "");
1387
Philipp Maier124a3e02021-07-26 11:17:15 +02001388 cfg = mgcp_config_alloc();
1389 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001390 memset(&endp, 0, sizeof(endp));
1391 memset(&state, 0, sizeof(state));
1392
Philipp Maier9e1d1642018-05-09 16:26:34 +02001393 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1394 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1395 state.in_stream.err_ts_ctr = &test_ctr_in;
1396 state.out_stream.err_ts_ctr = &test_ctr_out;
1397
Philipp Maier87bd9be2017-08-22 16:35:41 +02001398 endp.type = &ep_typeset.rtp;
1399
Philipp Maier124a3e02021-07-26 11:17:15 +02001400 trunk->v.vty_number_endpoints = 1;
1401 trunk->endpoints = endpoints;
1402 trunk->endpoints[0] = &endp;
1403 trunk->force_constant_ssrc = patch_ssrc;
1404 trunk->force_aligned_timing = patch_ts;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001405
Philipp Maier124a3e02021-07-26 11:17:15 +02001406 endp.trunk = trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001407
Philipp Maier87bd9be2017-08-22 16:35:41 +02001408 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001409 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1410 "test-connection");
1411 OSMO_ASSERT(_conn);
1412 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001413 OSMO_ASSERT(conn);
1414
1415 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001416
Philipp Maier228e5912019-03-05 13:56:59 +01001417 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001418 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001419
1420 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1421 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001422 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001423
1424 force_monotonic_time_us = round(1000000.0 * info->txtime);
1425
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001426 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001427 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001428 msg->l3h = msgb_put(msg, info->len);
1429 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001430 mgcp_rtp_end_config(&endp, 1, rtp);
1431
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001432 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001433
1434 if (state.out_stream.ssrc != last_ssrc) {
1435 printf("Output SSRC changed to %08x\n",
1436 state.out_stream.ssrc);
1437 last_ssrc = state.out_stream.ssrc;
1438 }
1439
1440 printf("In TS: %d, dTS: %d, Seq: %d\n",
1441 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001442 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001443
1444 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001445 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001446 state.out_stream.last_timestamp - last_timestamp,
1447 state.out_stream.last_tsdelta,
1448 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001449 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1450 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001451
1452 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001453 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001454
Philipp Maier9e1d1642018-05-09 16:26:34 +02001455 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1456 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001457 last_timestamp = state.out_stream.last_timestamp;
1458 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001459
1460 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001461 }
1462
1463 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001464 mgcp_conn_free_all(&endp);
Philipp Maier124a3e02021-07-26 11:17:15 +02001465 talloc_free(trunk);
1466 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001467}
1468
1469static void test_multilple_codec(void)
1470{
1471 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001472 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001473 struct mgcp_endpoint *endp;
1474 struct msgb *inp, *resp;
1475 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001476 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001477 char conn_id[256];
Philipp Maier39889e42021-08-04 17:42:57 +02001478 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001479
1480 printf("Testing multiple payload types\n");
1481
1482 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001483 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001484 trunk->v.vty_number_endpoints = 64;
1485 mgcp_trunk_equip(trunk);
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001486
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001487 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001488 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001489 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001490 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001491 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1492 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001493 msgb_free(inp);
1494 msgb_free(resp);
1495
Philipp Maier37a808c2020-07-03 15:48:31 +02001496 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1497 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1498 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001499 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001500 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001501 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001502
1503 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001504 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001505 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001506 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001507 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1508 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001509 msgb_free(inp);
1510 msgb_free(resp);
1511
Philipp Maier37a808c2020-07-03 15:48:31 +02001512 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1513 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1514 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001515 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001516 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001517 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001518
Philipp Maierbc0346e2018-06-07 09:52:16 +02001519 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1520 /* Note: It usually makes no sense to leave the payload type list
1521 * out. However RFC 2327 does not clearly forbid this case and
1522 * it makes and since we already decided in OS#2658 that a missing
1523 * LCO should pick a sane default codec, it makes sense to expect
1524 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001525 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001526 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001527 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001528 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1529 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001530 msgb_free(inp);
1531 msgb_free(resp);
1532
Philipp Maier37a808c2020-07-03 15:48:31 +02001533 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1534 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1535 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001536 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001537 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001538 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001539
1540 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001541 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001542 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001543 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001544 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1545 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001546 msgb_free(inp);
1547 msgb_free(resp);
1548
Philipp Maier37a808c2020-07-03 15:48:31 +02001549 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1550 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1551 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001552 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001553 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001554 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001555
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001556 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
Philipp Maier37a808c2020-07-03 15:48:31 +02001557 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001558 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001559 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001560 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1561 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001562 msgb_free(inp);
1563 msgb_free(resp);
1564
Philipp Maier37a808c2020-07-03 15:48:31 +02001565 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1566 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1567 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001568 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001569 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001570 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001571
Philipp Maierffd75e42017-11-22 11:44:50 +01001572 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001573 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001574 resp = mgcp_handle_message(cfg, inp);
1575 msgb_free(inp);
1576 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001577 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1578 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1579 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001580 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001581 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001582 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Pau Espin Pedrol5ffd1272022-10-04 13:45:48 +02001583 OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001584 memset(&addr, 0, sizeof(addr));
1585 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001586 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1587 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001588
1589 /* Check what happens without that flag */
1590
Philipp Maier87bd9be2017-08-22 16:35:41 +02001591 /* Free the previous endpoint and the data and
1592 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001593 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001594 talloc_free(endp->last_response);
1595 talloc_free(endp->last_trans);
1596 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001597 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001598 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001599
Philipp Maier37a808c2020-07-03 15:48:31 +02001600 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001601 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001602 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001603 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1604 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001605 msgb_free(inp);
1606 msgb_free(resp);
1607
Philipp Maier37a808c2020-07-03 15:48:31 +02001608 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1609 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1610 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001611 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001612 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001613 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001614
Philipp Maierd19de2e2020-06-03 13:55:33 +02001615 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001616 talloc_free(cfg);
1617}
1618
1619static void test_no_cycle(void)
1620{
1621 struct mgcp_config *cfg;
1622 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001623 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001624 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001625 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001626
1627 printf("Testing no sequence flow on initial packet\n");
1628
1629 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001630 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001631 trunk->v.vty_number_endpoints = 64;
1632 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001633
Philipp Maier37a808c2020-07-03 15:48:31 +02001634 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1635 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001636
Philipp Maierffd75e42017-11-22 11:44:50 +01001637 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1638 "test-connection");
1639 OSMO_ASSERT(_conn);
1640 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001641 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001642
Harald Welte49e3d5a2017-12-25 09:47:57 +01001643 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001644
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001645 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001646 OSMO_ASSERT(conn->state.stats.initialized == 1);
1647 OSMO_ASSERT(conn->state.stats.cycles == 0);
1648 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001649
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001650 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001651 OSMO_ASSERT(conn->state.stats.initialized == 1);
1652 OSMO_ASSERT(conn->state.stats.cycles == 0);
1653 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001654
1655 /* now jump.. */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001656 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001657 OSMO_ASSERT(conn->state.stats.initialized == 1);
1658 OSMO_ASSERT(conn->state.stats.cycles == 0);
1659 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001660
1661 /* and wrap */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001662 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001663 OSMO_ASSERT(conn->state.stats.initialized == 1);
1664 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1665 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001666
Philipp Maierd19de2e2020-06-03 13:55:33 +02001667 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001668 talloc_free(cfg);
1669}
1670
1671static void test_no_name(void)
1672{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001673 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001674 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001675 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001676
1677 printf("Testing no rtpmap name\n");
1678 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001679 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001680
Philipp Maier889fe7f2020-07-06 17:44:12 +02001681 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001682 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001683 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001684
Philipp Maierffd75e42017-11-22 11:44:50 +01001685 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001686 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001687
1688 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001689 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001690 (char *)msg->data);
1691 OSMO_ASSERT(false);
1692 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001693 msgb_free(inp);
1694 msgb_free(msg);
1695
Philipp Maierd19de2e2020-06-03 13:55:33 +02001696 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001697 talloc_free(cfg);
1698}
1699
1700static void test_osmux_cid(void)
1701{
1702 int id, i;
1703
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001704 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1705
1706 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001707 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001708 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1709
1710 osmux_cid_pool_get(30);
1711 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1712 osmux_cid_pool_get(30);
1713 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1714
1715 osmux_cid_pool_put(id);
1716 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1717 osmux_cid_pool_put(30);
1718 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001719
1720 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001721 id = osmux_cid_pool_get_next();
Pau Espin Pedrol310e41c2022-11-15 13:23:38 +01001722 /* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
1723 OSMO_ASSERT(id == ((i + 1) & 0xff));
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001724 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001725 }
1726
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001727 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001728 OSMO_ASSERT(id == -1);
1729
1730 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001731 osmux_cid_pool_put(i);
1732 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001733}
1734
1735static const struct log_info_cat log_categories[] = {
1736};
1737
1738const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001739 .cat = log_categories,
1740 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001741};
1742
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001743static void test_get_lco_identifier(void)
1744{
1745 char *test;
1746 printf("Testing get_lco_identifier()\n");
1747
1748 /* Normal case at the beginning */
1749 test = "p:10, a:PCMU";
1750 printf("%s -> %s\n", test, get_lco_identifier(test));
1751
1752 test = "p:10, a:PCMU";
1753 printf("%s -> %s\n", test, get_lco_identifier(test));
1754
1755 /* Begin parsing in the middle of the value part of
1756 * the previous LCO option value */
1757 test = "XXXX, p:10, a:PCMU";
1758 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1759
1760 test = "XXXX,p:10,a:PCMU";
1761 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1762
1763 test = "10,a:PCMU";
1764 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1765
1766 test = "10, a:PCMU";
1767 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1768
1769 test = "10,a: PCMU";
1770 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1771
1772 test = "10 ,a: PCMU";
1773 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1774
1775 /* Begin parsing right at the end of the previous LCO
1776 * option value */
1777 test = ", a:PCMU";
1778 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1779
1780 test = " a:PCMU";
1781 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1782
1783 /* Empty string, result should be (null) */
1784 test = "";
1785 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1786
1787 /* Missing colons, result should be (null) */
1788 test = "p10, aPCMU";
1789 printf("%s -> %s\n", test, get_lco_identifier(test));
1790
1791 /* Colon separated from the identifier, result should be (null) */
1792 test = "10,a :PCMU";
1793 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1794}
1795
1796static void test_check_local_cx_options(void *ctx)
1797{
1798 /* Legal cases */
1799 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1800 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1801 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1802 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1803 0);
1804 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1805 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1806 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1807 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1808 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1809
1810 /* Illegal spaces before and after colon */
1811 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1812 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1813 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1814
1815 /* Check if multiple appearances of LCOs are rejected */
1816 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1817 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1818 -1);
1819 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1820
1821 /* Check if empty LCO are rejected */
1822 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1823 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1824 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1825 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1826 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1827
1828 /* Garbeled beginning and ends */
1829 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1830 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1831 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1832 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1833 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1834 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1835
1836 /* Illegal strings */
1837 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1838 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1839 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1840 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1841 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1842 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1843}
1844
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001845static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1846 .amr_octet_aligned_present = true,
1847 .amr_octet_aligned = true,
1848};
1849
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001850static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1851 .amr_octet_aligned_present = true,
1852 .amr_octet_aligned = false,
1853};
1854
1855static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1856 .amr_octet_aligned_present = false,
1857};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001858
Philipp Maier4c4d2272023-04-26 15:45:17 +02001859struct testcase_mgcp_codec_decide_codec {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001860 int payload_type;
1861 const char *audio_name;
1862 const struct mgcp_codec_param *param;
1863 int expect_rc;
1864};
1865
Philipp Maier4c4d2272023-04-26 15:45:17 +02001866struct testcase_mgcp_codec_decide_expect {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001867 int payload_type_map[2];
1868};
1869
Philipp Maier4c4d2272023-04-26 15:45:17 +02001870struct testcase_mgcp_codec_decide {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001871 const char *descr;
1872 /* two conns on an endpoint, each with N configured codecs */
Philipp Maier4c4d2272023-04-26 15:45:17 +02001873 struct testcase_mgcp_codec_decide_codec codecs[2][10];
1874 struct testcase_mgcp_codec_decide_expect expect[2];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001875};
1876
Philipp Maier4c4d2272023-04-26 15:45:17 +02001877static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001878 {
1879 .descr = "same order, but differing payload type numbers",
1880 .codecs = {
1881 {
1882 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1883 { 0, "PCMU/8000/1", NULL, },
1884 { 111, "GSM-HR-08/8000/1", NULL, },
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 = {
1893 { .payload_type_map = {112, 96}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001894 { .payload_type_map = {112, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001895 },
1896 },
1897 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001898 .descr = "different order and different payload type numbers",
1899 .codecs = {
1900 {
1901 { 0, "PCMU/8000/1", NULL, },
1902 { 111, "GSM-HR-08/8000/1", NULL, },
1903 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1904 },
1905 {
1906 { 97, "GSM-HR-08/8000/1", NULL, },
1907 { 0, "PCMU/8000/1", NULL, },
1908 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1909 },
1910 },
1911 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001912 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001913 { .payload_type_map = {111, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001914 },
1915 },
1916 {
1917 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1918 .codecs = {
1919 {
1920 { 0, "PCMU/8000/1", NULL, },
1921 { 96, "GSM-HR-08/8000/1", NULL, },
1922 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1923 },
1924 {
1925 { 97, "GSM-HR-08/8000/1", NULL, },
1926 { 0, "PCMU/8000/1", NULL, },
1927 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1928 },
1929 },
1930 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001931 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001932 { .payload_type_map = {96, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001933 },
1934 },
1935 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001936 .descr = "conn0 has no codecs",
1937 .codecs = {
1938 {
1939 /* no codecs */
1940 },
1941 {
1942 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1943 { 0, "PCMU/8000/1", NULL, },
1944 { 97, "GSM-HR-08/8000/1", NULL, },
1945 },
1946 },
1947 .expect = {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001948 { .payload_type_map = {-EINVAL, -EINVAL}, },
1949 { .payload_type_map = {-EINVAL, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001950 },
1951 },
1952 {
1953 .descr = "conn1 has no codecs",
1954 .codecs = {
1955 {
1956 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1957 { 0, "PCMU/8000/1", NULL, },
1958 { 111, "GSM-HR-08/8000/1", NULL, },
1959 },
1960 {
1961 /* no codecs */
1962 },
1963 },
1964 .expect = {
1965 { .payload_type_map = {112, -EINVAL}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001966 { .payload_type_map = {-EINVAL, -EINVAL}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001967 },
1968 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001969 {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001970 .descr = "test AMR with differing octet-aligned settings (both <-> both)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001971 .codecs = {
1972 {
1973 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Philipp Maierec967d72023-03-22 16:20:37 +01001974 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001975 },
1976 {
1977 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
Philipp Maierec967d72023-03-22 16:20:37 +01001978 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001979 },
1980 },
1981 .expect = {
Philipp Maierec967d72023-03-22 16:20:37 +01001982 { .payload_type_map = {111, 121}, },
1983 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001984 },
1985 },
1986 {
1987 .descr = "test AMR with differing octet-aligned settings (oa <-> both)",
1988 .codecs = {
1989 {
1990 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1991 },
1992 {
1993 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1994 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1995 },
1996 },
1997 .expect = {
1998 { .payload_type_map = {111, 121}, },
1999 { .payload_type_map = {111, 121}, },
2000 },
2001 },
2002 {
2003 .descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
2004 .codecs = {
2005 {
2006 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
2007 },
2008 {
2009 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
2010 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
2011 },
2012 },
2013 .expect = {
2014 { .payload_type_map = {112, 122}, },
2015 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002016 },
2017 },
2018 {
Philipp Maier621e8662023-03-22 16:53:30 +01002019 .descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002020 .codecs = {
2021 {
2022 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002023 },
2024 {
2025 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
2026 },
2027 },
2028 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01002029 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002030 { .payload_type_map = {111, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002031 },
2032 },
2033 {
Philipp Maier621e8662023-03-22 16:53:30 +01002034 .descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002035 .codecs = {
2036 {
Philipp Maier621e8662023-03-22 16:53:30 +01002037 { 111, "AMR/8000", &amr_param_octet_aligned_false, },
2038 },
2039 {
2040 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
2041 },
2042 },
2043 .expect = {
2044 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002045 { .payload_type_map = {111, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01002046 },
2047 },
2048 {
2049 .descr = "test AMR with NULL param (oa <-> null)",
2050 .codecs = {
2051 {
2052 { 112, "AMR/8000", &amr_param_octet_aligned_true, },
2053 },
2054 {
2055 { 122, "AMR/8000", NULL, },
2056 },
2057 },
2058 .expect = {
2059 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
2060 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002061 { .payload_type_map = {112, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01002062 },
2063 },
2064 {
2065 .descr = "test AMR with NULL param (bwe <-> null)",
2066 .codecs = {
2067 {
Philipp Maierec967d72023-03-22 16:20:37 +01002068 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002069 },
2070 {
2071 { 122, "AMR/8000", NULL, },
2072 },
2073 },
2074 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01002075 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
Philipp Maierec967d72023-03-22 16:20:37 +01002076 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002077 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002078 },
2079 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002080 {
2081 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
2082 .codecs = {
2083 {
2084 { 0, "PCMU/8000/1", NULL, },
2085 { 111, "GSM-HR-08/8000/1", NULL, },
2086 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2087 },
2088 {
2089 { 97, "GSM-HR-08/8000", NULL, },
2090 { 0, "PCMU/8000", NULL, },
2091 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
2092 },
2093 },
2094 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002095 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002096 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002097 },
2098 },
2099 {
2100 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
2101 .codecs = {
2102 {
2103 { 0, "PCMU/8000/1", NULL, },
2104 { 111, "GSM-HR-08/8000/1", NULL, },
2105 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2106 },
2107 {
2108 { 97, "GSM-HR-08", NULL, },
2109 { 0, "PCMU", NULL, },
2110 { 96, "AMR", &amr_param_octet_aligned_true, },
2111 },
2112 },
2113 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002114 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002115 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002116 },
2117 },
2118 {
2119 .descr = "test whether channel number matching is waterproof",
2120 .codecs = {
2121 {
2122 { 111, "GSM-HR-08/8000", },
2123 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
2124 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
2125 },
2126 {
2127 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
2128 { 121, "GSM-HR-08/8000/1", },
2129 },
2130 },
2131 .expect = {
2132 { .payload_type_map = {111, 121}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002133 { .payload_type_map = {111, 121} },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002134 },
2135 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002136};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002137
Philipp Maier4c4d2272023-04-26 15:45:17 +02002138static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
2139 const struct testcase_mgcp_codec_decide_expect *expect)
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002140{
Philipp Maier4c4d2272023-04-26 15:45:17 +02002141 bool ok = true;
2142 int payload_type_conn_src;
2143 int payload_type_conn_dst;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002144
Philipp Maier4c4d2272023-04-26 15:45:17 +02002145 printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
2146 if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
2147 if (expect->payload_type_map[index_conn_src] == -EINVAL
2148 && expect->payload_type_map[index_conn_dst] == -EINVAL)
2149 printf(" codec decision failed (expected)!\n");
2150 else {
2151 printf(" ERROR: codec decision failed!\n");
2152 ok = false;
2153 }
2154 } else {
2155 printf(" Codec decision result:\n");
2156 if (conn[index_conn_src].end.codec) {
2157 payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
2158 printf(" conn[%u]: codec:%s, pt:%d\n",
2159 index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
2160 } else {
2161 payload_type_conn_src = -EINVAL;
2162 printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
2163 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002164
Philipp Maier4c4d2272023-04-26 15:45:17 +02002165 if (conn[index_conn_dst].end.codec) {
2166 payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
2167 printf(" conn[%u]: codec:%s, pt:%d\n",
2168 index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
2169 payload_type_conn_dst);
2170 } else {
2171 payload_type_conn_dst = -EINVAL;
2172 printf(" conn[%u]: codec:none, pt:none\n", index_conn_dst);
2173 }
2174
2175 if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
2176 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2177 index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
2178 ok = false;
2179 }
2180
2181 if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
2182 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2183 index_conn_dst, expect->payload_type_map[index_conn_dst],
2184 payload_type_conn_dst);
2185 ok = false;
2186 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002187 }
Philipp Maier4c4d2272023-04-26 15:45:17 +02002188
2189 return ok;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002190}
2191
Philipp Maier4c4d2272023-04-26 15:45:17 +02002192static void test_mgcp_codec_decide(void)
Philipp Maier6931f9a2018-07-26 09:29:31 +02002193{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002194 int i;
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002195 bool ok_all = true;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002196 printf("\nTesting mgcp_codec_find_convertible()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002197
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002198 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002199 const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
2200 struct mgcp_conn_rtp conn[2] = { };
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002201 int rc;
2202 int conn_i;
2203 int c;
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002204 bool ok = true;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002205
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002206 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002207
Philipp Maier4c4d2272023-04-26 15:45:17 +02002208 /* Build testvector (add codecs to conn, set properties etc... */
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002209 for (conn_i = 0; conn_i < 2; conn_i++) {
2210 printf(" - add codecs on conn%d:\n", conn_i);
2211 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002212 const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002213 if (!codec->audio_name)
2214 break;
2215
Philipp Maier4c4d2272023-04-26 15:45:17 +02002216 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
2217 codec->param);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002218
2219 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2220 codec->param ?
Philipp Maier4c4d2272023-04-26 15:45:17 +02002221 (codec->param->amr_octet_aligned_present ?
2222 (codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
2223 : " octet-aligned=unset")
2224 : "", rc);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002225 if (rc != codec->expect_rc) {
2226 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2227 ok = false;
2228 }
2229 }
2230 if (!c)
2231 printf(" (none)\n");
2232 }
2233
Philipp Maier4c4d2272023-04-26 15:45:17 +02002234 /* Run codec decision and check expectation */
2235 if (!codec_decision(conn, 0, 1, &t->expect[0]))
2236 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002237
Philipp Maier4c4d2272023-04-26 15:45:17 +02002238 if (!codec_decision(conn, 1, 0, &t->expect[1]))
2239 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002240
Philipp Maier4c4d2272023-04-26 15:45:17 +02002241 if (ok)
2242 printf(" ===> SUCCESS: codec decision as expected!\n");
2243 else
2244 printf(" ===> FAIL: unexpected codec decision!\n");
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002245
2246 if (!ok)
2247 ok_all = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002248 }
2249
Neels Hofmeyr17b57012023-12-10 07:12:39 +01002250 OSMO_ASSERT(ok_all);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002251}
2252
Harald Welte9befdeb2022-11-03 11:41:05 +01002253void test_conn_id_matching(void)
Neels Hofmeyr65317262018-09-03 22:11:05 +02002254{
2255 struct mgcp_endpoint endp = {};
2256 struct mgcp_conn *conn;
2257 struct mgcp_conn *conn_match;
2258 int i;
2259 const char *conn_id_generated = "000023AB";
2260 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002261 "23AB",
2262 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002263 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002264 "00000023AB",
2265 "23ab",
2266 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002267 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002268 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002269 };
2270
2271 printf("\nTesting %s\n", __func__);
2272
2273 INIT_LLIST_HEAD(&endp.conns);
2274
2275 conn = talloc_zero(NULL, struct mgcp_conn);
2276 OSMO_ASSERT(conn);
2277 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2278 llist_add(&conn->entry, &endp.conns);
2279
2280 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2281 const char *needle = conn_id_request[i];
2282 printf("needle='%s' ", needle);
2283 conn_match = mgcp_conn_get(&endp, needle);
2284 OSMO_ASSERT(conn_match);
2285 printf("found '%s'\n", conn_match->id);
2286 OSMO_ASSERT(conn_match == conn);
2287 }
2288
2289 llist_del(&conn->entry);
2290 talloc_free(conn);
2291}
2292
Harald Welte9befdeb2022-11-03 11:41:05 +01002293void test_e1_trunk_nr_from_epname(void)
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002294{
Philipp Maierd70eef62021-07-19 13:53:28 +02002295 unsigned int trunk_nr;
2296 int rc;
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002297
2298 /* Note: e1_trunk_nr_from_epname does not check the text
2299 * after the E1 trunk number, after the delimiter
2300 * character "/" arbitrary text may follow. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002301 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
Philipp Maier0653cc82020-08-10 22:52:51 +02002302 OSMO_ASSERT(trunk_nr == 0);
Philipp Maierd70eef62021-07-19 13:53:28 +02002303 OSMO_ASSERT(rc == 0);
2304 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002305 OSMO_ASSERT(trunk_nr == 1);
Philipp Maierd70eef62021-07-19 13:53:28 +02002306 OSMO_ASSERT(rc == 0);
2307 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002308 OSMO_ASSERT(trunk_nr == 2);
Philipp Maierd70eef62021-07-19 13:53:28 +02002309 OSMO_ASSERT(rc == 0);
2310 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002311 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002312 OSMO_ASSERT(rc == 0);
2313 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002314 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002315 OSMO_ASSERT(rc == 0);
2316 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002317 OSMO_ASSERT(trunk_nr == 24);
Philipp Maierd70eef62021-07-19 13:53:28 +02002318 OSMO_ASSERT(rc == 0);
2319 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002320 OSMO_ASSERT(trunk_nr == 64);
Philipp Maierd70eef62021-07-19 13:53:28 +02002321 OSMO_ASSERT(rc == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002322
2323 /* The following endpoint strings should fail, either the
2324 * trunk number exceeds the valid range or the trunk prefix
2325 * is wrong. Also when the delimiter character "/" at the
2326 * end of the trunk is wrong the parsing should fail. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002327 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
2328 OSMO_ASSERT(rc == -EINVAL);
2329 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
2330 OSMO_ASSERT(rc == -EINVAL);
2331 rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
2332 OSMO_ASSERT(rc == -EINVAL);
2333 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
2334 OSMO_ASSERT(rc == -EINVAL);
2335 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
2336 OSMO_ASSERT(rc == -EINVAL);
2337 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
2338 OSMO_ASSERT(rc == -EINVAL);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002339
2340 return;
2341}
2342
Harald Welte9befdeb2022-11-03 11:41:05 +01002343void test_mgcp_is_rtp_dummy_payload(void)
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002344{
2345 /* realistic rtp packet */
2346 static const char rtp_payload[] =
2347 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2348 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2349 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2350 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2351 0x24 };
2352
2353 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2354 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2355 struct msgb *msg_dummy_rtp =
2356 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2357
2358 uint8_t *buf;
2359
2360 /* Dummy RTP packet */
2361 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2362 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2363
2364 /* Normal RTP packet */
2365 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2366 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2367
2368 /* Dummy RTP packet with normal RTP packet attached, this must not be
2369 * recognized as Dummy RTP packet */
2370 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2371 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2372 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2373 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2374
2375 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2376 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2377 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2378
2379 msgb_free(msg_dummy);
2380 msgb_free(msg_rtp);
2381 msgb_free(msg_dummy_rtp);
2382}
2383
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002384int main(int argc, char **argv)
2385{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002386 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2387 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2388 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002389
2390 test_strline();
2391 test_values();
2392 test_messages();
2393 test_retransmission();
2394 test_packet_loss_calc();
2395 test_rqnt_cb();
2396 test_mgcp_stats();
2397 test_packet_error_detection(1, 0);
2398 test_packet_error_detection(0, 0);
2399 test_packet_error_detection(0, 1);
2400 test_packet_error_detection(1, 1);
2401 test_multilple_codec();
2402 test_no_cycle();
2403 test_no_name();
2404 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002405 test_get_lco_identifier();
2406 test_check_local_cx_options(ctx);
Philipp Maier4c4d2272023-04-26 15:45:17 +02002407 test_mgcp_codec_decide();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002408 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002409 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002410 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002411
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002412 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2413 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2414 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002415 printf("Done\n");
2416 return EXIT_SUCCESS;
2417}