blob: e37bb57ca8b298132107447e4b4467567f8b7b34 [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=fmtp:126 0/1/2\r\n" \
131 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200132
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200133#define MDCX4_ADDR0000 \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200134 "MDCX 18983216 1@mgw MGCP 1.0\r\n" \
135 "M: sendrecv\r" \
136 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100137 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200138 "L: p:20, a:AMR, nt:IN\r\n" \
139 "\n" \
140 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100141 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200142 "c=IN IP4 0.0.0.0\r\n" \
143 "t=0 0\r\n" \
144 "m=audio 4441 RTP/AVP 99\r\n" \
145 "a=rtpmap:99 AMR/8000\r\n" \
146 "a=ptime:40\r\n"
147
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200148#define MDCX4_ADDR0000_RET \
149 "527 18983216 FAIL\r\n"
150
151#define MDCX4 \
152 "MDCX 18983217 1@mgw MGCP 1.0\r\n" \
153 "M: sendrecv\r" \
154 "C: 2\r\n" \
155 "I: %s\r\n" \
156 "L: p:20, a:AMR, nt:IN\r\n" \
157 "\n" \
158 "v=0\r\n" \
159 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
160 "c=IN IP4 5.6.7.8\r\n" \
161 "t=0 0\r\n" \
162 "m=audio 4441 RTP/AVP 99\r\n" \
163 "a=rtpmap:99 AMR/8000\r\n" \
164 "a=ptime:40\r\n"
165
Philipp Maier87bd9be2017-08-22 16:35:41 +0200166#define MDCX4_RET(Ident) \
167 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100168 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200169 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100170 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200171 "s=-\r\n" \
172 "c=IN IP4 0.0.0.0\r\n" \
173 "t=0 0\r\n" \
174 "m=audio 16002 RTP/AVP 99\r\n" \
175 "a=rtpmap:99 AMR/8000\r\n" \
176 "a=ptime:40\r\n"
177
178#define MDCX4_RO_RET(Ident) \
179 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100180 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200181 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100182 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200183 "s=-\r\n" \
184 "c=IN IP4 0.0.0.0\r\n" \
185 "t=0 0\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200186 "m=audio 16002 RTP/AVP 112\r\n" \
187 "a=rtpmap:112 AMR\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200188 "a=ptime:40\r\n"
189
190#define MDCX4_PT1 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200191 "MDCX 18983218 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol17058482019-06-26 12:23:02 +0200192 "M: SENDRECV\r" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200193 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100194 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200195 "L: p:20-40, a:AMR, nt:IN\r\n" \
196 "\n" \
197 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200198 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
199 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200200 "t=0 0\r\n" \
201 "m=audio 4441 RTP/AVP 99\r\n" \
202 "a=rtpmap:99 AMR/8000\r\n" \
203 "a=ptime:40\r\n"
204
205#define MDCX4_PT2 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200206 "MDCX 18983219 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200207 "M: sendrecv\r" \
208 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100209 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200210 "L: p:20-20, a:AMR, nt:IN\r\n" \
211 "\n" \
212 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200213 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
214 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200215 "t=0 0\r\n" \
216 "m=audio 4441 RTP/AVP 99\r\n" \
217 "a=rtpmap:99 AMR/8000\r\n" \
218 "a=ptime:40\r\n"
219
220#define MDCX4_PT3 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200221 "MDCX 18983220 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200222 "M: sendrecv\r" \
223 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100224 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200225 "L: a:AMR, nt:IN\r\n" \
226 "\n" \
227 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200228 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
229 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200230 "t=0 0\r\n" \
231 "m=audio 4441 RTP/AVP 99\r\n" \
232 "a=rtpmap:99 AMR/8000\r\n" \
233 "a=ptime:40\r\n"
234
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200235/* Test different upper/lower case in options */
236#define MDCX4_PT4 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200237 "MDCX 18983221 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200238 "m: sendrecv\r" \
239 "c: 2\r\n" \
240 "i: %s\r\n" \
Pau Espin Pedrol83fd8a52019-06-26 12:55:26 +0200241 "l: A:amr, NT:IN\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200242 "\n" \
243 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200244 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
245 "c=IN IP4 5.6.7.8\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200246 "t=0 0\r\n" \
247 "m=audio 4441 RTP/AVP 99\r\n" \
248 "a=rtpmap:99 AMR/8000\r\n" \
249 "a=ptime:40\r\n"
250
251#define MDCX4_SO \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200252 "MDCX 18983222 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200253 "M: sendonly\r" \
254 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100255 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200256 "L: p:20, a:AMR, nt:IN\r\n" \
257 "\n" \
258 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200259 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
260 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200261 "t=0 0\r\n" \
262 "m=audio 4441 RTP/AVP 99\r\n" \
263 "a=rtpmap:99 AMR/8000\r\n" \
264 "a=ptime:40\r\n"
265
266#define MDCX4_RO \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200267 "MDCX 18983223 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200268 "M: recvonly\r" \
269 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100270 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200271 "L: p:20, a:AMR, nt:IN\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200272
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200273#define MDCX_TOO_LONG_CI \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200274 "MDCX 18983224 1@mgw MGCP 1.0\r\n" \
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200275 "I: 123456789012345678901234567890123\n"
276
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200277#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200278
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200279#define MDCX_NULL \
280 "MDCX 9 null@mgw MGCP 1.0\r\n" \
281 "I: %s\n"
282
283#define MDCX_NULL_RET "502 9 FAIL\r\n"
284
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200285#define SHORT2 "CRCX 1"
286#define SHORT2_RET "510 000000 FAIL\r\n"
287#define SHORT3 "CRCX 1 1@mgw"
288#define SHORT4 "CRCX 1 1@mgw MGCP"
289#define SHORT5 "CRCX 1 1@mgw MGCP 1.0"
290
Philipp Maier87bd9be2017-08-22 16:35:41 +0200291#define CRCX \
292 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200293 "m: recvonly\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200294 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200295 "L: p:20\r\n" \
296 "\r\n" \
297 "v=0\r\n" \
298 "c=IN IP4 123.12.12.123\r\n" \
299 "m=audio 5904 RTP/AVP 97\r\n" \
300 "a=rtpmap:97 GSM-EFR/8000\r\n" \
301 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200302
Philipp Maier87bd9be2017-08-22 16:35:41 +0200303#define CRCX_RET \
304 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100305 "I: %s\r\n" \
306 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200307 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100308 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200309 "s=-\r\n" \
310 "c=IN IP4 0.0.0.0\r\n" \
311 "t=0 0\r\n" \
312 "m=audio 16002 RTP/AVP 97\r\n" \
313 "a=rtpmap:97 GSM-EFR/8000\r\n" \
314 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200315
Philipp Maier87bd9be2017-08-22 16:35:41 +0200316#define CRCX_RET_NO_RTPMAP \
317 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100318 "I: %s\r\n" \
319 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200320 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100321 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200322 "s=-\r\n" \
323 "c=IN IP4 0.0.0.0\r\n" \
324 "t=0 0\r\n" \
325 "m=audio 16002 RTP/AVP 97\r\n" \
326 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200327
Philipp Maier87bd9be2017-08-22 16:35:41 +0200328#define CRCX_FMTP_RET \
329 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100330 "I: %s\r\n" \
331 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200332 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100333 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200334 "s=-\r\n" \
335 "c=IN IP4 0.0.0.0\r\n" \
336 "t=0 0\r\n" \
337 "m=audio 16006 RTP/AVP 97\r\n" \
338 "a=rtpmap:97 GSM-EFR/8000\r\n" \
339 "a=fmtp:126 0/1/2\r\n" \
340 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200341
Philipp Maier87bd9be2017-08-22 16:35:41 +0200342#define CRCX_ZYN \
343 "CRCX 2 1@mgw MGCP 1.0\r" \
344 "M: recvonly\r" \
345 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200346 "\n" \
347 "v=0\r" \
348 "c=IN IP4 123.12.12.123\r" \
349 "m=audio 5904 RTP/AVP 97\r" \
350 "a=rtpmap:97 GSM-EFR/8000\r"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200351
Philipp Maier87bd9be2017-08-22 16:35:41 +0200352#define CRCX_ZYN_RET \
353 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100354 "I: %s\r\n" \
355 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200356 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100357 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200358 "s=-\r\n" \
359 "c=IN IP4 0.0.0.0\r\n" \
360 "t=0 0\r\n" \
361 "m=audio 16004 RTP/AVP 97\r\n" \
362 "a=rtpmap:97 GSM-EFR/8000\r\n" \
363 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200364
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200365#define CRCX_X_OSMO_IGN \
366 "CRCX 2 1@mgw MGCP 1.0\r\n" \
367 "M: recvonly\r\n" \
368 "C: 2\r\n" \
369 "L: p:20\r\n" \
Neels Hofmeyrf2388ea2018-08-26 23:36:53 +0200370 "X-Osmo-IGN: C foo\r\n" \
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200371 "\r\n" \
372 "v=0\r\n" \
373 "c=IN IP4 123.12.12.123\r\n" \
374 "m=audio 5904 RTP/AVP 97\r\n" \
375 "a=rtpmap:97 GSM-EFR/8000\r\n" \
376 "a=ptime:40\r\n"
377
378#define CRCX_X_OSMO_IGN_RET \
379 "200 2 OK\r\n" \
380 "I: %s\r\n" \
381 "\r\n" \
382 "v=0\r\n" \
383 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
384 "s=-\r\n" \
385 "c=IN IP4 0.0.0.0\r\n" \
386 "t=0 0\r\n" \
387 "m=audio 16010 RTP/AVP 97\r\n" \
388 "a=rtpmap:97 GSM-EFR/8000\r\n" \
389 "a=ptime:40\r\n"
390
Philipp Maier87bd9be2017-08-22 16:35:41 +0200391#define DLCX \
392 "DLCX 7 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100393 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200394 "C: 2\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200395
Philipp Maier87bd9be2017-08-22 16:35:41 +0200396#define DLCX_RET \
397 "250 7 OK\r\n" \
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100398 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
399
400 #define DLCX_RET_OSMUX DLCX_RET \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200401 "X-Osmo-CP: EC TI=0, TO=0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200402
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200403#define DLCX_NULL \
404 "DLCX 8 null@mgw MGCP 1.0\r\n" \
405 "I: %s\r\n" \
406 "C: 2\r\n"
407
408#define DLCX_NULL_RET "502 8 FAIL\r\n"
409
Philipp Maier87bd9be2017-08-22 16:35:41 +0200410#define RQNT \
411 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
412 "X: B244F267488\r\n" \
413 "S: D/9\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200414
Philipp Maier87bd9be2017-08-22 16:35:41 +0200415#define RQNT2 \
416 "RQNT 186908781 1@mgw MGCP 1.0\r\n" \
417 "X: ADD4F26746F\r\n" \
418 "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200419
420#define RQNT1_RET "200 186908780 OK\r\n"
421#define RQNT2_RET "200 186908781 OK\r\n"
422
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200423#define RQNT_NULL \
424 "RQNT 186908782 null@mgw MGCP 1.0\r\n" \
425 "X: B244F267488\r\n" \
426 "S: D/9\r\n"
427
428#define RQNT_NULL_RET "502 186908782 FAIL\r\n"
429
Philipp Maier87bd9be2017-08-22 16:35:41 +0200430#define PTYPE_IGNORE 0 /* == default initializer */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200431#define PTYPE_NONE 128
432#define PTYPE_NYI PTYPE_NONE
433
Philipp Maier87bd9be2017-08-22 16:35:41 +0200434#define CRCX_MULT_1 \
435 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200436 "M: recvonly\r\n" \
437 "C: 2\r\n" \
438 "X\r\n" \
439 "L: p:20\r\n" \
440 "\r\n" \
441 "v=0\r\n" \
442 "c=IN IP4 123.12.12.123\r\n" \
443 "m=audio 5904 RTP/AVP 18 97\r\n" \
444 "a=rtpmap:18 G729/8000\r\n" \
445 "a=rtpmap:97 GSM-EFR/8000\r\n" \
446 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200447
Philipp Maier87bd9be2017-08-22 16:35:41 +0200448#define CRCX_MULT_2 \
449 "CRCX 2 2@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200450 "M: recvonly\r\n" \
451 "C: 2\r\n" \
452 "X\r\n" \
453 "L: p:20\r\n" \
454 "\r\n" \
455 "v=0\r\n" \
456 "c=IN IP4 123.12.12.123\r\n" \
457 "m=audio 5904 RTP/AVP 18 97 101\r\n" \
458 "a=rtpmap:18 G729/8000\r\n" \
459 "a=rtpmap:97 GSM-EFR/8000\r\n" \
460 "a=rtpmap:101 FOO/8000\r\n" \
461 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200462
Philipp Maier87bd9be2017-08-22 16:35:41 +0200463#define CRCX_MULT_3 \
464 "CRCX 2 3@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200465 "M: recvonly\r\n" \
466 "C: 2\r\n" \
467 "X\r\n" \
468 "L: p:20\r\n" \
469 "\r\n" \
470 "v=0\r\n" \
471 "c=IN IP4 123.12.12.123\r\n" \
472 "m=audio 5904 RTP/AVP\r\n" \
473 "a=rtpmap:18 G729/8000\r\n" \
474 "a=rtpmap:97 GSM-EFR/8000\r\n" \
475 "a=rtpmap:101 FOO/8000\r\n" \
476 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200477
Philipp Maier87bd9be2017-08-22 16:35:41 +0200478#define CRCX_MULT_4 \
479 "CRCX 2 4@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200480 "M: recvonly\r\n" \
481 "C: 2\r\n" \
482 "X\r\n" \
483 "L: p:20\r\n" \
484 "\r\n" \
485 "v=0\r\n" \
486 "c=IN IP4 123.12.12.123\r\n" \
487 "m=audio 5904 RTP/AVP 18\r\n" \
488 "a=rtpmap:18 G729/8000\r\n" \
489 "a=rtpmap:97 GSM-EFR/8000\r\n" \
490 "a=rtpmap:101 FOO/8000\r\n" \
491 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200492
493#define CRCX_MULT_GSM_EXACT \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200494 "CRCX 259260421 5@mgw MGCP 1.0\r\n" \
495 "C: 1355c6041e\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200496 "L: p:20, a:GSM, nt:IN\r\n" \
497 "M: recvonly\r\n" \
498 "\r\n" \
499 "v=0\r\n" \
500 "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
501 "s=-\r\nc=IN IP4 192.168.181.247\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200502 "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 +0200503 "a=rtpmap:0 PCMU/8000\r\n" \
504 "a=rtpmap:8 PCMA/8000\r\n" \
505 "a=rtpmap:3 gsm/8000\r\n" \
506 "a=rtpmap:18 G729/8000\r\n" \
507 "a=fmtp:18 annexb=no\r\n" \
508 "a=rtpmap:4 G723/8000\r\n" \
509 "a=rtpmap:96 iLBC/8000\r\n" \
510 "a=fmtp:96 mode=20\r\n" \
511 "a=rtpmap:97 iLBC/8000\r\n" \
512 "a=fmtp:97 mode=30\r\n" \
513 "a=rtpmap:101 telephone-event/8000\r\n" \
514 "a=fmtp:101 0-15\r\n" \
515 "a=recvonly\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200516
Philipp Maier87bd9be2017-08-22 16:35:41 +0200517#define MDCX_NAT_DUMMY \
518 "MDCX 23 5@mgw MGCP 1.0\r\n" \
519 "C: 1355c6041e\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100520 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200521 "\r\n" \
522 "c=IN IP4 8.8.8.8\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200523 "m=audio 16434 RTP/AVP 3\r\n"
524
525#define CRCX_NO_LCO_NO_SDP \
526 "CRCX 2 6@mgw MGCP 1.0\r\n" \
527 "M: recvonly\r\n" \
528 "C: 2\r\n"
529
Philipp Maier228e5912019-03-05 13:56:59 +0100530#define CRCX_AMR_WITH_FMTP \
531 "CRCX 2 7@mgw MGCP 1.0\r\n" \
532 "M: recvonly\r\n" \
533 "C: 2\r\n" \
534 "X\r\n" \
535 "L: p:20\r\n" \
536 "\r\n" \
537 "v=0\r\n" \
538 "c=IN IP4 123.12.12.123\r\n" \
539 "m=audio 5904 RTP/AVP 111\r\n" \
540 "a=rtpmap:111 AMR/8000/1\r\n" \
541 "a=ptime:20\r\n" \
542 "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
543
544#define CRCX_AMR_WITH_FMTP_RET \
545 "200 2 OK\r\n" \
546 "I: %s\r\n" \
547 "\r\n" \
548 "v=0\r\n" \
549 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
550 "s=-\r\n" \
551 "c=IN IP4 0.0.0.0\r\n" \
552 "t=0 0\r\n" \
553 "m=audio 16012 RTP/AVP 111\r\n" \
554 "a=rtpmap:111 AMR/8000/1\r\n" \
555 "a=fmtp:111 octet-align=1\r\n" \
556 "a=ptime:20\r\n"
557
Philipp Maierbc0346e2018-06-07 09:52:16 +0200558#define CRCX_NO_LCO_NO_SDP_RET \
559 "200 2 OK\r\n" \
560 "I: %s\r\n" \
561 "\r\n" \
562 "v=0\r\n" \
563 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
564 "s=-\r\n" \
565 "c=IN IP4 0.0.0.0\r\n" \
566 "t=0 0\r\n" \
567 "m=audio 16008 RTP/AVP 0\r\n" \
568 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200569
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200570#define CRCX_NULL \
571 "CRCX 2 null@mgw MGCP 1.0\r\n" \
572 "m: recvonly\r\n" \
573 "C: 2\r\n" \
574 "L: p:20\r\n" \
575 "\r\n" \
576 "v=0\r\n" \
577 "c=IN IP4 123.12.12.123\r\n" \
578 "m=audio 5904 RTP/AVP 97\r\n" \
579 "a=rtpmap:97 GSM-EFR/8000\r\n" \
580 "a=ptime:40\r\n"
581
582#define CRCX_NULL_RET "502 2 FAIL\r\n"
583
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200584struct mgcp_test {
585 const char *name;
586 const char *req;
587 const char *exp_resp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200588 int ptype;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200589 const char *extra_fmtp;
590};
591
592static const struct mgcp_test tests[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200593 {"AUEP1", AUEP1, AUEP1_RET},
594 {"AUEP2", AUEP2, AUEP2_RET},
595 {"MDCX1", MDCX_WRONG_EP, MDCX_ERR_RET},
596 {"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
597 {"CRCX", CRCX, CRCX_RET, 97},
598 {"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200599 {"MDCX4_ADDR000", MDCX4_ADDR0000, MDCX4_ADDR0000_RET},
600 {"MDCX4", MDCX4, MDCX4_RET("18983217"), 99},
601 {"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983218"), 99},
602 {"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983219"), 99},
603 {"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983220"), 99},
604 {"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983221"), 99},
605 {"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983222"), 99},
606 {"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983223"), PTYPE_IGNORE},
Philipp Maier87bd9be2017-08-22 16:35:41 +0200607 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
608 {"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
609 {"EMPTY", EMPTY, EMPTY_RET},
610 {"SHORT1", SHORT, SHORT_RET},
611 {"SHORT2", SHORT2, SHORT2_RET},
612 {"SHORT3", SHORT3, SHORT2_RET},
613 {"SHORT4", SHORT4, SHORT2_RET},
614 {"RQNT1", RQNT, RQNT1_RET},
615 {"RQNT2", RQNT2, RQNT2_RET},
616 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
617 {"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
618 {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
619 "a=fmtp:126 0/1/2"},
620 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
Philipp Maierbc0346e2018-06-07 09:52:16 +0200621 {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200622 {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200623 {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
Philipp Maier228e5912019-03-05 13:56:59 +0100624 {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
Pau Espin Pedrolaf0f58f2023-06-14 12:21:26 +0200625 {"AUEP_NULL", AUEP_NULL, AUEP_NULL_RET},
626 {"CRCX_NULL", CRCX_NULL, CRCX_NULL_RET},
627 {"MDCX_NULL", MDCX_NULL, MDCX_NULL_RET},
628 {"DLCX_NULL", DLCX_NULL, DLCX_NULL_RET},
629 {"RQNT_NULL", RQNT_NULL, RQNT_NULL_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200630};
631
632static const struct mgcp_test retransmit[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200633 {"CRCX", CRCX, CRCX_RET},
634 {"RQNT1", RQNT, RQNT1_RET},
635 {"RQNT2", RQNT2, RQNT2_RET},
636 {"MDCX3", MDCX3, MDCX3A_RET},
637 {"DLCX", DLCX, DLCX_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200638};
639
Philipp Maierffd75e42017-11-22 11:44:50 +0100640static struct msgb *create_msg(const char *str, const char *conn_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200641{
642 struct msgb *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100643 int len;
644
645 printf("creating message from statically defined input:\n");
646 printf("---------8<---------\n%s\n---------8<---------\n", str);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200647
648 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
Philipp Maierffd75e42017-11-22 11:44:50 +0100649 if (conn_id && strlen(conn_id))
650 len = sprintf((char *)msg->data, str, conn_id, conn_id);
651 else
652 len = sprintf((char *)msg->data, "%s", str);
653
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200654 msg->l2h = msgb_put(msg, len);
655 return msg;
656}
657
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200658static int dummy_packets = 0;
659/* override and forward */
660ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200661 const struct sockaddr *dest_addr, socklen_t addrlen)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200662{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200663 uint32_t dest_host =
664 htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
665 int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200666
Philipp Maierb3d14eb2021-05-20 14:18:52 +0200667 if (len == sizeof(rtp_dummy_payload)
668 && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200669 fprintf(stderr,
670 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
671 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200672 dummy_packets += 1;
673 }
674
Pau Espin Pedrola24dcc62021-07-06 17:48:47 +0200675 /* Make sure address+port are valid */
676 OSMO_ASSERT(dest_host);
677 OSMO_ASSERT(dest_port);
678
Philipp Maier3d9b6562017-10-13 18:33:44 +0200679 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200680}
681
682static int64_t force_monotonic_time_us = -1;
683/* override and forward */
684int clock_gettime(clockid_t clk_id, struct timespec *tp)
685{
686 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
687 static clock_gettime_t real_clock_gettime = NULL;
688
689 if (!real_clock_gettime)
690 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
691
692 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
693 tp->tv_sec = force_monotonic_time_us / 1000000;
694 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
695 return 0;
696 }
697
698 return real_clock_gettime(clk_id, tp);
699}
700
Philipp Maier14b27a82020-06-02 20:15:30 +0200701static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200702{
703 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200704 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200705 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200706}
707
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200708#define CONN_UNMODIFIED (0x1000)
709
710static void test_values(void)
711{
712 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200713 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200714
715 /* Check that LOOPBACK enables all output */
716 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200717 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200718}
719
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200720/* Extract a connection ID from a response and return in conn_id;
721 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100722static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200723 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100724{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200725 const char *conn_id_start;
726 const char *conn_id_end;
727 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100728
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200729 const char *header_I = "\r\nI: ";
730 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100731
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200732 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
733 if ((conn_id_start = strstr((char *)resp, header_I))) {
734 conn_id_start += strlen(header_I);
735 conn_id_end = strstr(conn_id_start, "\r\n");
736 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
737 conn_id_start += strlen(header_o);
738 conn_id_end = strchr(conn_id_start, ' ');
739 } else
740 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100741
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200742 if (conn_id_end)
743 conn_id_len = conn_id_end - conn_id_start;
744 else
745 conn_id_len = strlen(conn_id_start);
746 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100747
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200748 /* A valid conn_id must at least contain one digit, and must
749 * not exceed a length of 32 digits */
750 OSMO_ASSERT(conn_id_len <= 32);
751 OSMO_ASSERT(conn_id_len > 0);
752
753 strncpy(conn_id, conn_id_start, conn_id_len);
754 conn_id[conn_id_len] = '\0';
755 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100756}
757
758/* Check response, automatically patch connection ID if needed */
759static int check_response(uint8_t *resp, const char *exp_resp)
760{
761 char exp_resp_patched[4096];
762 const char *exp_resp_ptr;
763 char conn_id[256];
764
765 printf("checking response:\n");
766
767 /* If the expected response is intened to be patched
768 * (%s placeholder inside) we will patch it with the
769 * connection identifier we just received from the
770 * real response. This is necessary because the CI
771 * is generated by the mgcp code on CRCX and we can
772 * not know it in advance */
773 if (strstr(exp_resp, "%s")) {
774 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
775 0) {
776 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
777 exp_resp_ptr = exp_resp_patched;
778 printf
779 ("using message with patched conn_id for comparison\n");
780 } else {
781 printf
782 ("patching conn_id failed, using message as statically defined for comparison\n");
783 exp_resp_ptr = exp_resp;
784 }
785 } else {
786 printf("using message as statically defined for comparison\n");
787 exp_resp_ptr = exp_resp;
788 }
789
790 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
791 printf("Unexpected response, please check!\n");
792 printf
793 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
794 resp);
795 printf
796 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
797 exp_resp_ptr);
798 return -EINVAL;
799 }
800
801 printf("Response matches our expectations.\n");
802 return 0;
803}
804
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200805static void test_messages(void)
806{
807 struct mgcp_config *cfg;
808 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200809 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200810 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200811 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100812 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100813 int rc;
Philipp Maier39889e42021-08-04 17:42:57 +0200814 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200815
816 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200817 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200818
Philipp Maier889fe7f2020-07-06 17:44:12 +0200819 trunk->v.vty_number_endpoints = 64;
820 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200821
Philipp Maierffd75e42017-11-22 11:44:50 +0100822 memset(last_conn_id, 0, sizeof(last_conn_id));
823
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200824 for (i = 0; i < ARRAY_SIZE(tests); i++) {
825 const struct mgcp_test *t = &tests[i];
826 struct msgb *inp;
827 struct msgb *msg;
828
Philipp Maierffd75e42017-11-22 11:44:50 +0100829 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200830 printf("Testing %s\n", t->name);
831
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200832 dummy_packets = 0;
833
Philipp Maierd19de2e2020-06-03 13:55:33 +0200834 osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200835 t->extra_fmtp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200836
Philipp Maierffd75e42017-11-22 11:44:50 +0100837 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200838 msg = mgcp_handle_message(cfg, inp);
839 msgb_free(inp);
840 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200841 if (msg) {
842 printf("%s failed '%s'\n", t->name,
843 (char *)msg->data);
844 OSMO_ASSERT(false);
845 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100846 } else if (check_response(msg->data, t->exp_resp) != 0) {
847 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200848 OSMO_ASSERT(false);
849 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100850
Philipp Maier7df419b2017-12-04 17:11:42 +0100851 if (msg) {
852 rc = get_conn_id_from_response(msg->data, last_conn_id,
853 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200854 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100855 printf("(response contains a connection id)\n");
856 else
857 printf("(response does not contain a connection id)\n");
858 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100859
Philipp Maiera330b862017-12-04 17:16:16 +0100860 if (msg)
861 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200862
863 if (dummy_packets)
864 printf("Dummy packets: %d\n", dummy_packets);
865
Philipp Maier37a808c2020-07-03 15:48:31 +0200866 if (last_endpoint[0] != '\0') {
867 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
868 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200869
Philipp Maier01d24a32017-11-21 17:26:09 +0100870 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200871 if (conn) {
872 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200873
Philipp Maier87bd9be2017-08-22 16:35:41 +0200874 if (conn->end.packet_duration_ms != -1)
875 printf("Detected packet duration: %d\n",
876 conn->end.packet_duration_ms);
877 else
878 printf("Packet duration not set\n");
879 if (endp->local_options.pkt_period_min ||
880 endp->local_options.pkt_period_max)
881 printf
Oliver Smith169d50e2023-01-24 13:12:54 +0100882 ("Requested packetization period: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200883 "%d-%d\n",
884 endp->local_options.pkt_period_min,
885 endp->
886 local_options.pkt_period_max);
887 else
888 printf
889 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200890
Philipp Maier87bd9be2017-08-22 16:35:41 +0200891 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
892 printf("Connection mode: %d:%s%s%s%s\n",
893 conn->conn->mode,
894 !conn->conn->mode ? " NONE" : "",
895 conn->conn->mode & MGCP_CONN_SEND_ONLY
896 ? " SEND" : "",
897 conn->conn->mode & MGCP_CONN_RECV_ONLY
898 ? " RECV" : "",
899 conn->conn->mode & MGCP_CONN_LOOPBACK
900 & ~MGCP_CONN_RECV_SEND
901 ? " LOOP" : "");
902 fprintf(stderr,
903 "RTP output %sabled, NET output %sabled\n",
904 conn->end.output_enabled
905 ? "en" : "dis",
906 conn->end.output_enabled
907 ? "en" : "dis");
908 } else
909 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200910
Philipp Maier87bd9be2017-08-22 16:35:41 +0200911 OSMO_ASSERT(conn->end.output_enabled
Pau Espin Pedrol2c401642021-12-24 14:48:26 +0100912 == !!(conn->conn->mode & MGCP_CONN_SEND_ONLY));
Philipp Maier87bd9be2017-08-22 16:35:41 +0200913
914 conn->conn->mode |= CONN_UNMODIFIED;
915
916 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200917 endp->local_options.pkt_period_min = 0;
918 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200919 }
920
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200921 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100922 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200923 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200924
Philipp Maier37a808c2020-07-03 15:48:31 +0200925 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200926 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200927 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200928 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200929
Philipp Maier87bd9be2017-08-22 16:35:41 +0200930 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200931 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200932 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200933
934 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200935 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200936 }
937 }
938
Philipp Maierd19de2e2020-06-03 13:55:33 +0200939 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200940 talloc_free(cfg);
941}
942
943static void test_retransmission(void)
944{
945 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200946 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200947 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100948 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100949 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200950
951 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200952 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200953
Philipp Maier889fe7f2020-07-06 17:44:12 +0200954 trunk->v.vty_number_endpoints = 64;
955 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200956
Philipp Maierffd75e42017-11-22 11:44:50 +0100957 memset(last_conn_id, 0, sizeof(last_conn_id));
958
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200959 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
960 const struct mgcp_test *t = &retransmit[i];
961 struct msgb *inp;
962 struct msgb *msg;
963
Philipp Maierffd75e42017-11-22 11:44:50 +0100964 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200965 printf("Testing %s\n", t->name);
966
Philipp Maierffd75e42017-11-22 11:44:50 +0100967 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200968 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200969
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200970 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100971 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200972 printf("%s failed '%s'\n", t->name, (char *)msg->data);
973 OSMO_ASSERT(false);
974 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100975
Philipp Maier23b8e292017-12-04 16:48:45 +0100976 if (msg && strcmp(t->name, "CRCX") == 0) {
977 rc = get_conn_id_from_response(msg->data, last_conn_id,
978 sizeof(last_conn_id));
979 OSMO_ASSERT(rc == 0);
980 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100981
Philipp Maier7cedfd72017-12-04 16:49:12 +0100982 if (msg)
983 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200984
985 /* Retransmit... */
986 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100987 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200988 msg = mgcp_handle_message(cfg, inp);
989 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100990 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200991 printf("%s failed '%s'\n", t->name, (char *)msg->data);
992 OSMO_ASSERT(false);
993 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200994 msgb_free(msg);
995 }
996
Philipp Maierd19de2e2020-06-03 13:55:33 +0200997 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200998 talloc_free(cfg);
999}
1000
1001static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
1002{
1003 ptrdiff_t tone = _tone;
Ericfbf78d12021-08-23 22:31:39 +02001004 endp->trunk->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001005 return 0;
1006}
1007
1008static void test_rqnt_cb(void)
1009{
1010 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001011 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001012 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +01001013 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001014
1015 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001016 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001017 cfg->rqnt_cb = rqnt_cb;
1018
Philipp Maier889fe7f2020-07-06 17:44:12 +02001019 trunk->v.vty_number_endpoints = 64;
1020 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001021
Philipp Maierffd75e42017-11-22 11:44:50 +01001022 inp = create_msg(CRCX, NULL);
1023 msg = mgcp_handle_message(cfg, inp);
1024 OSMO_ASSERT(msg);
1025 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
1026 sizeof(conn_id)) == 0);
1027 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001028 msgb_free(inp);
1029
1030 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +01001031 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001033 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001034 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
1035 abort();
1036 }
1037
Philipp Maier87bd9be2017-08-22 16:35:41 +02001038 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001039 printf("FAILED: callback not called: %p\n", cfg->data);
1040 abort();
1041 }
1042
1043 msgb_free(msg);
1044 msgb_free(inp);
1045
Philipp Maierffd75e42017-11-22 11:44:50 +01001046 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001047 msgb_free(mgcp_handle_message(cfg, inp));
1048 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001049 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001050 talloc_free(cfg);
1051}
1052
1053struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001054 int cycles;
1055 uint16_t base_seq;
1056 uint16_t max_seq;
1057 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001058
Philipp Maier87bd9be2017-08-22 16:35:41 +02001059 uint32_t expected;
1060 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001061};
1062
1063static const struct pl_test pl_test_dat[] = {
1064 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001065 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1066 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001067 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001068 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1069 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001070 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001071 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1072 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001073 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001074 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1075 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001076 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001077 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1078 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001079};
1080
1081static void test_packet_loss_calc(void)
1082{
1083 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001084 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001085 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001086 struct mgcp_config *cfg;
1087 struct mgcp_trunk *trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001088
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001089 printf("Testing packet loss calculation.\n");
1090
Philipp Maiercede2a42018-07-03 14:14:21 +02001091 memset(&endp, 0, sizeof(endp));
Philipp Maier124a3e02021-07-26 11:17:15 +02001092 cfg = mgcp_config_alloc();
1093 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maiercede2a42018-07-03 14:14:21 +02001094 endp.type = &ep_typeset.rtp;
Philipp Maier124a3e02021-07-26 11:17:15 +02001095 trunk->v.vty_number_endpoints = 1;
1096 trunk->endpoints = endpoints;
1097 trunk->endpoints[0] = &endp;
1098 endp.trunk = trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001099 INIT_LLIST_HEAD(&endp.conns);
1100
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001101 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1102 uint32_t expected;
1103 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001104
Philipp Maiercede2a42018-07-03 14:14:21 +02001105 struct mgcp_conn_rtp *conn = NULL;
1106 struct mgcp_conn *_conn = NULL;
1107 struct mgcp_rtp_state *state;
1108 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001109
Philipp Maiercede2a42018-07-03 14:14:21 +02001110 _conn =
1111 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1112 "test-connection");
1113 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1114 state = &conn->state;
Pau Espin Pedroldaf5bce2022-09-22 19:14:24 +02001115 packets_rx = rate_ctr_group_get_ctr(conn->ctrg, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001116
1117 state->stats.initialized = 1;
1118 state->stats.base_seq = pl_test_dat[i].base_seq;
1119 state->stats.max_seq = pl_test_dat[i].max_seq;
1120 state->stats.cycles = pl_test_dat[i].cycles;
1121
1122 packets_rx->current = pl_test_dat[i].packets;
1123 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001124
Philipp Maier87bd9be2017-08-22 16:35:41 +02001125 if (loss != pl_test_dat[i].loss
1126 || expected != pl_test_dat[i].expected) {
1127 printf
1128 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1129 i, loss, pl_test_dat[i].loss, expected,
1130 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001131 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001132
1133 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001134 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001135
Philipp Maier124a3e02021-07-26 11:17:15 +02001136 talloc_free(trunk);
1137 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001138}
1139
Philipp Maier87bd9be2017-08-22 16:35:41 +02001140int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1141 uint32_t *pr, uint32_t *_or, int *loss,
1142 uint32_t *jitter)
1143{
1144 char *line, *save;
1145 int rc;
1146
1147 /* initialize with bad values */
1148 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1149 *loss = INT_MAX;
1150
1151 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1152 if (!line)
1153 return -1;
1154
1155 /* this can only parse the message that is created above... */
1156 for_each_non_empty_line(line, save) {
1157 switch (line[0]) {
1158 case 'P':
1159 rc = sscanf(line,
1160 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1161 ps, os, pr, _or, loss, jitter);
1162 return rc == 6 ? 0 : -1;
1163 }
1164 }
1165
1166 return -1;
1167}
1168
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001169static void test_mgcp_stats(void)
1170{
1171 printf("Testing stat parsing\n");
1172
1173 uint32_t bps, bos, pr, _or, jitter;
1174 struct msgb *msg;
1175 int loss;
1176 int rc;
1177
Philipp Maierffd75e42017-11-22 11:44:50 +01001178 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001179 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1180 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001181 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1182 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001183 printf("FAIL: Parsing failed1.\n");
1184 msgb_free(msg);
1185
Philipp Maier87bd9be2017-08-22 16:35:41 +02001186 msg =
1187 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001188 ("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 +02001189 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1190 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001191 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1192 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001193 printf("FAIL: Parsing failed2.\n");
1194 msgb_free(msg);
1195}
1196
1197struct rtp_packet_info {
1198 float txtime;
1199 int len;
1200 char *data;
1201};
1202
1203struct rtp_packet_info test_rtp_packets1[] = {
1204 /* RTP: SeqNo=0, TS=0 */
1205 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001206 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001207 /* RTP: SeqNo=1, TS=160 */
1208 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001209 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001210 /* RTP: SeqNo=2, TS=320 */
1211 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001212 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001213 /* Repeat RTP timestamp: */
1214 /* RTP: SeqNo=3, TS=320 */
1215 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001216 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001217 /* RTP: SeqNo=4, TS=480 */
1218 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001219 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001220 /* RTP: SeqNo=5, TS=640 */
1221 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001222 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001223 /* Double skip RTP timestamp (delta = 2*160): */
1224 /* RTP: SeqNo=6, TS=960 */
1225 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001226 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001227 /* RTP: SeqNo=7, TS=1120 */
1228 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001229 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001230 /* RTP: SeqNo=8, TS=1280 */
1231 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001232 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001233 /* Non 20ms RTP timestamp (delta = 120): */
1234 /* RTP: SeqNo=9, TS=1400 */
1235 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001236 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001237 /* RTP: SeqNo=10, TS=1560 */
1238 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001239 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001240 /* RTP: SeqNo=11, TS=1720 */
1241 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001242 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001243 /* SSRC changed to 0x10203040, RTP timestamp jump */
1244 /* RTP: SeqNo=12, TS=34688 */
1245 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001246 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001247 /* RTP: SeqNo=13, TS=34848 */
1248 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001249 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001250 /* RTP: SeqNo=14, TS=35008 */
1251 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001252 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001253 /* Non 20ms RTP timestamp (delta = 120): */
1254 /* RTP: SeqNo=15, TS=35128 */
1255 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001256 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001257 /* RTP: SeqNo=16, TS=35288 */
1258 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001259 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001260 /* RTP: SeqNo=17, TS=35448 */
1261 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001262 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001263 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1264 /* RTP: SeqNo=19, TS=35768 */
1265 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001266 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001267 /* RTP: SeqNo=20, TS=35928 */
1268 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001269 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001270 /* RTP: SeqNo=21, TS=36088 */
1271 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001272 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001273 /* Repeat last packet */
1274 /* RTP: SeqNo=21, TS=36088 */
1275 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001276 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001277 /* RTP: SeqNo=22, TS=36248 */
1278 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001279 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001280 /* RTP: SeqNo=23, TS=36408 */
1281 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001282 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001283 /* Don't increment SeqNo but increment timestamp by 160 */
1284 /* RTP: SeqNo=23, TS=36568 */
1285 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001286 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001287 /* RTP: SeqNo=24, TS=36728 */
1288 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001289 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001290 /* RTP: SeqNo=25, TS=36888 */
1291 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001292 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001293 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1294 * SeqNo jump */
1295 /* RTP: SeqNo=1000, TS=160000 */
1296 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
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=1001, TS=160160 */
1299 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001300 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001301 /* RTP: SeqNo=1002, TS=160320 */
1302 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001303 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001304 /* RTP: SeqNo=1003, TS=180320, Marker */
1305 {2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
1306 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1307 /* RTP: SeqNo=1004, TS=180480 */
1308 {2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
1309 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1310 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
1311 {2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
1312 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001313};
1314
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001315static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1316{
1317 int i;
1318
Philipp Maier124a3e02021-07-26 11:17:15 +02001319 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001320 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001321 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001322 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001323 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001324 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001325 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001326 uint32_t last_ssrc = 0;
1327 uint32_t last_timestamp = 0;
1328 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001329 uint64_t last_in_ts_err_cnt = 0;
1330 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001331 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001332 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001333 struct rate_ctr test_ctr_in;
1334 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001335
1336 printf("Testing packet error detection%s%s.\n",
1337 patch_ssrc ? ", patch SSRC" : "",
1338 patch_ts ? ", patch timestamps" : "");
1339
Philipp Maier124a3e02021-07-26 11:17:15 +02001340 cfg = mgcp_config_alloc();
1341 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001342 memset(&endp, 0, sizeof(endp));
1343 memset(&state, 0, sizeof(state));
1344
Philipp Maier9e1d1642018-05-09 16:26:34 +02001345 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1346 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1347 state.in_stream.err_ts_ctr = &test_ctr_in;
1348 state.out_stream.err_ts_ctr = &test_ctr_out;
1349
Philipp Maier87bd9be2017-08-22 16:35:41 +02001350 endp.type = &ep_typeset.rtp;
1351
Philipp Maier124a3e02021-07-26 11:17:15 +02001352 trunk->v.vty_number_endpoints = 1;
1353 trunk->endpoints = endpoints;
1354 trunk->endpoints[0] = &endp;
1355 trunk->force_constant_ssrc = patch_ssrc;
1356 trunk->force_aligned_timing = patch_ts;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001357
Philipp Maier124a3e02021-07-26 11:17:15 +02001358 endp.trunk = trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001359
Philipp Maier87bd9be2017-08-22 16:35:41 +02001360 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001361 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1362 "test-connection");
1363 OSMO_ASSERT(_conn);
1364 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001365 OSMO_ASSERT(conn);
1366
1367 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001368
Philipp Maier228e5912019-03-05 13:56:59 +01001369 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001370 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001371
1372 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1373 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001374 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001375
1376 force_monotonic_time_us = round(1000000.0 * info->txtime);
1377
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001378 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001379 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001380 msg->l3h = msgb_put(msg, info->len);
1381 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001382 mgcp_rtp_end_config(&endp, 1, rtp);
1383
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001384 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001385
1386 if (state.out_stream.ssrc != last_ssrc) {
1387 printf("Output SSRC changed to %08x\n",
1388 state.out_stream.ssrc);
1389 last_ssrc = state.out_stream.ssrc;
1390 }
1391
1392 printf("In TS: %d, dTS: %d, Seq: %d\n",
1393 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001394 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001395
1396 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001397 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001398 state.out_stream.last_timestamp - last_timestamp,
1399 state.out_stream.last_tsdelta,
1400 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001401 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1402 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001403
1404 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001405 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001406
Philipp Maier9e1d1642018-05-09 16:26:34 +02001407 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1408 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001409 last_timestamp = state.out_stream.last_timestamp;
1410 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001411
1412 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001413 }
1414
1415 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001416 mgcp_conn_free_all(&endp);
Philipp Maier124a3e02021-07-26 11:17:15 +02001417 talloc_free(trunk);
1418 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001419}
1420
1421static void test_multilple_codec(void)
1422{
1423 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001424 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001425 struct mgcp_endpoint *endp;
1426 struct msgb *inp, *resp;
1427 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001428 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001429 char conn_id[256];
Philipp Maier39889e42021-08-04 17:42:57 +02001430 char *last_endpoint = mgcp_debug_get_last_endpoint_name();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001431
1432 printf("Testing multiple payload types\n");
1433
1434 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001435 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001436 trunk->v.vty_number_endpoints = 64;
1437 mgcp_trunk_equip(trunk);
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001438
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001439 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001440 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001441 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001442 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001443 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1444 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001445 msgb_free(inp);
1446 msgb_free(resp);
1447
Philipp Maier37a808c2020-07-03 15:48:31 +02001448 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1449 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1450 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001451 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001452 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001453 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001454
1455 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001456 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001457 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001458 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001459 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1460 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001461 msgb_free(inp);
1462 msgb_free(resp);
1463
Philipp Maier37a808c2020-07-03 15:48:31 +02001464 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1465 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1466 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001467 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001468 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001469 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001470
Philipp Maierbc0346e2018-06-07 09:52:16 +02001471 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1472 /* Note: It usually makes no sense to leave the payload type list
1473 * out. However RFC 2327 does not clearly forbid this case and
1474 * it makes and since we already decided in OS#2658 that a missing
1475 * LCO should pick a sane default codec, it makes sense to expect
1476 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001477 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001478 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001479 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001480 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1481 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001482 msgb_free(inp);
1483 msgb_free(resp);
1484
Philipp Maier37a808c2020-07-03 15:48:31 +02001485 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1486 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1487 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001488 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001489 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001490 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001491
1492 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001493 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001494 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001495 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001496 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1497 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001498 msgb_free(inp);
1499 msgb_free(resp);
1500
Philipp Maier37a808c2020-07-03 15:48:31 +02001501 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1502 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1503 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001504 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001505 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001506 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001507
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001508 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
Philipp Maier37a808c2020-07-03 15:48:31 +02001509 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001510 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001511 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001512 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1513 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001514 msgb_free(inp);
1515 msgb_free(resp);
1516
Philipp Maier37a808c2020-07-03 15:48:31 +02001517 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1518 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1519 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001520 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001521 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001522 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001523
Philipp Maierffd75e42017-11-22 11:44:50 +01001524 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001525 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001526 resp = mgcp_handle_message(cfg, inp);
1527 msgb_free(inp);
1528 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001529 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1530 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1531 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001532 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001533 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001534 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Pau Espin Pedrol5ffd1272022-10-04 13:45:48 +02001535 OSMO_ASSERT(osmo_sockaddr_port(&conn->end.addr.u.sa) == 16434);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001536 memset(&addr, 0, sizeof(addr));
1537 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001538 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1539 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001540
1541 /* Check what happens without that flag */
1542
Philipp Maier87bd9be2017-08-22 16:35:41 +02001543 /* Free the previous endpoint and the data and
1544 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001545 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001546 talloc_free(endp->last_response);
1547 talloc_free(endp->last_trans);
1548 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001549 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001550 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001551
Philipp Maier37a808c2020-07-03 15:48:31 +02001552 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001553 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001554 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001555 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1556 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001557 msgb_free(inp);
1558 msgb_free(resp);
1559
Philipp Maier37a808c2020-07-03 15:48:31 +02001560 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1561 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1562 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001563 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001564 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001565 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001566
Philipp Maierd19de2e2020-06-03 13:55:33 +02001567 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001568 talloc_free(cfg);
1569}
1570
1571static void test_no_cycle(void)
1572{
1573 struct mgcp_config *cfg;
1574 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001575 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001576 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001577 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001578
1579 printf("Testing no sequence flow on initial packet\n");
1580
1581 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001582 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001583 trunk->v.vty_number_endpoints = 64;
1584 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001585
Philipp Maier37a808c2020-07-03 15:48:31 +02001586 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1587 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001588
Philipp Maierffd75e42017-11-22 11:44:50 +01001589 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1590 "test-connection");
1591 OSMO_ASSERT(_conn);
1592 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001593 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001594
Harald Welte49e3d5a2017-12-25 09:47:57 +01001595 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001596
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001597 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001598 OSMO_ASSERT(conn->state.stats.initialized == 1);
1599 OSMO_ASSERT(conn->state.stats.cycles == 0);
1600 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001601
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001602 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001603 OSMO_ASSERT(conn->state.stats.initialized == 1);
1604 OSMO_ASSERT(conn->state.stats.cycles == 0);
1605 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001606
1607 /* now jump.. */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001608 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001609 OSMO_ASSERT(conn->state.stats.initialized == 1);
1610 OSMO_ASSERT(conn->state.stats.cycles == 0);
1611 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001612
1613 /* and wrap */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001614 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001615 OSMO_ASSERT(conn->state.stats.initialized == 1);
1616 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1617 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001618
Philipp Maierd19de2e2020-06-03 13:55:33 +02001619 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001620 talloc_free(cfg);
1621}
1622
1623static void test_no_name(void)
1624{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001625 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001626 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001627 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001628
1629 printf("Testing no rtpmap name\n");
1630 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001631 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001632
Philipp Maier889fe7f2020-07-06 17:44:12 +02001633 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001634 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001635 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001636
Philipp Maierffd75e42017-11-22 11:44:50 +01001637 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001638 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001639
1640 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001641 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001642 (char *)msg->data);
1643 OSMO_ASSERT(false);
1644 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001645 msgb_free(inp);
1646 msgb_free(msg);
1647
Philipp Maierd19de2e2020-06-03 13:55:33 +02001648 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001649 talloc_free(cfg);
1650}
1651
1652static void test_osmux_cid(void)
1653{
1654 int id, i;
1655
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001656 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1657
1658 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001659 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001660 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1661
1662 osmux_cid_pool_get(30);
1663 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1664 osmux_cid_pool_get(30);
1665 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1666
1667 osmux_cid_pool_put(id);
1668 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1669 osmux_cid_pool_put(30);
1670 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001671
1672 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001673 id = osmux_cid_pool_get_next();
Pau Espin Pedrol310e41c2022-11-15 13:23:38 +01001674 /* We called osmux_cid_pool_get_next() above, so next CID is i+1. */
1675 OSMO_ASSERT(id == ((i + 1) & 0xff));
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001676 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001677 }
1678
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001679 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001680 OSMO_ASSERT(id == -1);
1681
1682 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001683 osmux_cid_pool_put(i);
1684 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001685}
1686
1687static const struct log_info_cat log_categories[] = {
1688};
1689
1690const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001691 .cat = log_categories,
1692 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001693};
1694
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001695static void test_get_lco_identifier(void)
1696{
1697 char *test;
1698 printf("Testing get_lco_identifier()\n");
1699
1700 /* Normal case at the beginning */
1701 test = "p:10, a:PCMU";
1702 printf("%s -> %s\n", test, get_lco_identifier(test));
1703
1704 test = "p:10, a:PCMU";
1705 printf("%s -> %s\n", test, get_lco_identifier(test));
1706
1707 /* Begin parsing in the middle of the value part of
1708 * the previous LCO option value */
1709 test = "XXXX, p:10, a:PCMU";
1710 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1711
1712 test = "XXXX,p:10,a:PCMU";
1713 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1714
1715 test = "10,a:PCMU";
1716 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1717
1718 test = "10, a:PCMU";
1719 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1720
1721 test = "10,a: PCMU";
1722 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1723
1724 test = "10 ,a: PCMU";
1725 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1726
1727 /* Begin parsing right at the end of the previous LCO
1728 * option value */
1729 test = ", a:PCMU";
1730 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1731
1732 test = " a:PCMU";
1733 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1734
1735 /* Empty string, result should be (null) */
1736 test = "";
1737 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1738
1739 /* Missing colons, result should be (null) */
1740 test = "p10, aPCMU";
1741 printf("%s -> %s\n", test, get_lco_identifier(test));
1742
1743 /* Colon separated from the identifier, result should be (null) */
1744 test = "10,a :PCMU";
1745 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1746}
1747
1748static void test_check_local_cx_options(void *ctx)
1749{
1750 /* Legal cases */
1751 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1752 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1753 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1754 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1755 0);
1756 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1757 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1758 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1759 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1760 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1761
1762 /* Illegal spaces before and after colon */
1763 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1764 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1765 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1766
1767 /* Check if multiple appearances of LCOs are rejected */
1768 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1769 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1770 -1);
1771 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1772
1773 /* Check if empty LCO are rejected */
1774 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1775 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1776 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1777 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1778 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1779
1780 /* Garbeled beginning and ends */
1781 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1782 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1783 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1784 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1785 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1786 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1787
1788 /* Illegal strings */
1789 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1790 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1791 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1792 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1793 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1794 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1795}
1796
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001797static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1798 .amr_octet_aligned_present = true,
1799 .amr_octet_aligned = true,
1800};
1801
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001802static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1803 .amr_octet_aligned_present = true,
1804 .amr_octet_aligned = false,
1805};
1806
1807static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1808 .amr_octet_aligned_present = false,
1809};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001810
Philipp Maier4c4d2272023-04-26 15:45:17 +02001811struct testcase_mgcp_codec_decide_codec {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001812 int payload_type;
1813 const char *audio_name;
1814 const struct mgcp_codec_param *param;
1815 int expect_rc;
1816};
1817
Philipp Maier4c4d2272023-04-26 15:45:17 +02001818struct testcase_mgcp_codec_decide_expect {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001819 int payload_type_map[2];
1820};
1821
Philipp Maier4c4d2272023-04-26 15:45:17 +02001822struct testcase_mgcp_codec_decide {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001823 const char *descr;
1824 /* two conns on an endpoint, each with N configured codecs */
Philipp Maier4c4d2272023-04-26 15:45:17 +02001825 struct testcase_mgcp_codec_decide_codec codecs[2][10];
1826 struct testcase_mgcp_codec_decide_expect expect[2];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001827};
1828
Philipp Maier4c4d2272023-04-26 15:45:17 +02001829static const struct testcase_mgcp_codec_decide test_mgcp_codec_find_convertible_cases[] = {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001830 {
1831 .descr = "same order, but differing payload type numbers",
1832 .codecs = {
1833 {
1834 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1835 { 0, "PCMU/8000/1", NULL, },
1836 { 111, "GSM-HR-08/8000/1", NULL, },
1837 },
1838 {
1839 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1840 { 0, "PCMU/8000/1", NULL, },
1841 { 97, "GSM-HR-08/8000/1", NULL, },
1842 },
1843 },
1844 .expect = {
1845 { .payload_type_map = {112, 96}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001846 { .payload_type_map = {112, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001847 },
1848 },
1849 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001850 .descr = "different order and different payload type numbers",
1851 .codecs = {
1852 {
1853 { 0, "PCMU/8000/1", NULL, },
1854 { 111, "GSM-HR-08/8000/1", NULL, },
1855 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1856 },
1857 {
1858 { 97, "GSM-HR-08/8000/1", NULL, },
1859 { 0, "PCMU/8000/1", NULL, },
1860 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1861 },
1862 },
1863 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001864 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001865 { .payload_type_map = {111, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001866 },
1867 },
1868 {
1869 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1870 .codecs = {
1871 {
1872 { 0, "PCMU/8000/1", NULL, },
1873 { 96, "GSM-HR-08/8000/1", NULL, },
1874 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1875 },
1876 {
1877 { 97, "GSM-HR-08/8000/1", NULL, },
1878 { 0, "PCMU/8000/1", NULL, },
1879 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1880 },
1881 },
1882 .expect = {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001883 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001884 { .payload_type_map = {96, 97}, },
Neels Hofmeyr26985402019-08-08 22:39:55 +02001885 },
1886 },
1887 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001888 .descr = "conn0 has no codecs",
1889 .codecs = {
1890 {
1891 /* no codecs */
1892 },
1893 {
1894 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1895 { 0, "PCMU/8000/1", NULL, },
1896 { 97, "GSM-HR-08/8000/1", NULL, },
1897 },
1898 },
1899 .expect = {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001900 { .payload_type_map = {-EINVAL, -EINVAL}, },
1901 { .payload_type_map = {-EINVAL, 96}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001902 },
1903 },
1904 {
1905 .descr = "conn1 has no codecs",
1906 .codecs = {
1907 {
1908 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1909 { 0, "PCMU/8000/1", NULL, },
1910 { 111, "GSM-HR-08/8000/1", NULL, },
1911 },
1912 {
1913 /* no codecs */
1914 },
1915 },
1916 .expect = {
1917 { .payload_type_map = {112, -EINVAL}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001918 { .payload_type_map = {-EINVAL, -EINVAL}, },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001919 },
1920 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001921 {
Philipp Maier4c4d2272023-04-26 15:45:17 +02001922 .descr = "test AMR with differing octet-aligned settings (both <-> both)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001923 .codecs = {
1924 {
1925 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Philipp Maierec967d72023-03-22 16:20:37 +01001926 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001927 },
1928 {
1929 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
Philipp Maierec967d72023-03-22 16:20:37 +01001930 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001931 },
1932 },
1933 .expect = {
Philipp Maierec967d72023-03-22 16:20:37 +01001934 { .payload_type_map = {111, 121}, },
1935 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001936 },
1937 },
1938 {
1939 .descr = "test AMR with differing octet-aligned settings (oa <-> both)",
1940 .codecs = {
1941 {
1942 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1943 },
1944 {
1945 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1946 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1947 },
1948 },
1949 .expect = {
1950 { .payload_type_map = {111, 121}, },
1951 { .payload_type_map = {111, 121}, },
1952 },
1953 },
1954 {
1955 .descr = "test AMR with differing octet-aligned settings (bwe <-> both)",
1956 .codecs = {
1957 {
1958 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1959 },
1960 {
1961 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1962 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1963 },
1964 },
1965 .expect = {
1966 { .payload_type_map = {112, 122}, },
1967 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001968 },
1969 },
1970 {
Philipp Maier621e8662023-03-22 16:53:30 +01001971 .descr = "test AMR with missing octet-aligned settings (oa <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001972 .codecs = {
1973 {
1974 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001975 },
1976 {
1977 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1978 },
1979 },
1980 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01001981 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001982 { .payload_type_map = {111, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001983 },
1984 },
1985 {
Philipp Maier621e8662023-03-22 16:53:30 +01001986 .descr = "test AMR with missing octet-aligned settings (bwe <-> unset)",
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001987 .codecs = {
1988 {
Philipp Maier621e8662023-03-22 16:53:30 +01001989 { 111, "AMR/8000", &amr_param_octet_aligned_false, },
1990 },
1991 {
1992 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1993 },
1994 },
1995 .expect = {
1996 { .payload_type_map = {111, 122}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02001997 { .payload_type_map = {111, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01001998 },
1999 },
2000 {
2001 .descr = "test AMR with NULL param (oa <-> null)",
2002 .codecs = {
2003 {
2004 { 112, "AMR/8000", &amr_param_octet_aligned_true, },
2005 },
2006 {
2007 { 122, "AMR/8000", NULL, },
2008 },
2009 },
2010 .expect = {
2011 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
2012 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002013 { .payload_type_map = {112, 122}, },
Philipp Maier621e8662023-03-22 16:53:30 +01002014 },
2015 },
2016 {
2017 .descr = "test AMR with NULL param (bwe <-> null)",
2018 .codecs = {
2019 {
Philipp Maierec967d72023-03-22 16:20:37 +01002020 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002021 },
2022 {
2023 { 122, "AMR/8000", NULL, },
2024 },
2025 },
2026 .expect = {
Philipp Maier621e8662023-03-22 16:53:30 +01002027 /* Note: Both 111, anbd 112 will translate to 122. The translation from 112 */
Philipp Maierec967d72023-03-22 16:20:37 +01002028 { .payload_type_map = {112, 122} },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002029 { .payload_type_map = {112, 122}, },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02002030 },
2031 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002032 {
2033 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
2034 .codecs = {
2035 {
2036 { 0, "PCMU/8000/1", NULL, },
2037 { 111, "GSM-HR-08/8000/1", NULL, },
2038 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2039 },
2040 {
2041 { 97, "GSM-HR-08/8000", NULL, },
2042 { 0, "PCMU/8000", NULL, },
2043 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
2044 },
2045 },
2046 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002047 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002048 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002049 },
2050 },
2051 {
2052 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
2053 .codecs = {
2054 {
2055 { 0, "PCMU/8000/1", NULL, },
2056 { 111, "GSM-HR-08/8000/1", NULL, },
2057 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2058 },
2059 {
2060 { 97, "GSM-HR-08", NULL, },
2061 { 0, "PCMU", NULL, },
2062 { 96, "AMR", &amr_param_octet_aligned_true, },
2063 },
2064 },
2065 .expect = {
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002066 { .payload_type_map = {0, 0}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002067 { .payload_type_map = {111, 97}, },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002068 },
2069 },
2070 {
2071 .descr = "test whether channel number matching is waterproof",
2072 .codecs = {
2073 {
2074 { 111, "GSM-HR-08/8000", },
2075 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
2076 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
2077 },
2078 {
2079 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
2080 { 121, "GSM-HR-08/8000/1", },
2081 },
2082 },
2083 .expect = {
2084 { .payload_type_map = {111, 121}, },
Philipp Maier4c4d2272023-04-26 15:45:17 +02002085 { .payload_type_map = {111, 121} },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02002086 },
2087 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002088};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002089
Philipp Maier4c4d2272023-04-26 15:45:17 +02002090static bool codec_decision(struct mgcp_conn_rtp *conn, unsigned int index_conn_src, unsigned int index_conn_dst,
2091 const struct testcase_mgcp_codec_decide_expect *expect)
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002092{
Philipp Maier4c4d2272023-04-26 15:45:17 +02002093 bool ok = true;
2094 int payload_type_conn_src;
2095 int payload_type_conn_dst;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002096
Philipp Maier4c4d2272023-04-26 15:45:17 +02002097 printf(" - mgcp_codec_decide(&conn[%u], &conn[%u]):\n", index_conn_src, index_conn_dst);
2098 if (mgcp_codec_decide(&conn[index_conn_src], &conn[index_conn_dst]) != 0) {
2099 if (expect->payload_type_map[index_conn_src] == -EINVAL
2100 && expect->payload_type_map[index_conn_dst] == -EINVAL)
2101 printf(" codec decision failed (expected)!\n");
2102 else {
2103 printf(" ERROR: codec decision failed!\n");
2104 ok = false;
2105 }
2106 } else {
2107 printf(" Codec decision result:\n");
2108 if (conn[index_conn_src].end.codec) {
2109 payload_type_conn_src = conn[index_conn_src].end.codec->payload_type;
2110 printf(" conn[%u]: codec:%s, pt:%d\n",
2111 index_conn_src, conn[index_conn_src].end.codec->subtype_name, payload_type_conn_src);
2112 } else {
2113 payload_type_conn_src = -EINVAL;
2114 printf(" conn[%u]: codec:none, pt:none\n", index_conn_src);
2115 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002116
Philipp Maier4c4d2272023-04-26 15:45:17 +02002117 if (conn[index_conn_dst].end.codec) {
2118 payload_type_conn_dst = conn[index_conn_dst].end.codec->payload_type;
2119 printf(" conn[%u]: codec:%s, pt:%d\n",
2120 index_conn_dst, conn[index_conn_dst].end.codec->subtype_name,
2121 payload_type_conn_dst);
2122 } else {
2123 payload_type_conn_dst = -EINVAL;
2124 printf(" conn[%u]: codec:none, pt:none\n", index_conn_dst);
2125 }
2126
2127 if (payload_type_conn_src != expect->payload_type_map[index_conn_src]) {
2128 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2129 index_conn_src, expect->payload_type_map[index_conn_src], payload_type_conn_src);
2130 ok = false;
2131 }
2132
2133 if (payload_type_conn_dst != expect->payload_type_map[index_conn_dst]) {
2134 printf(" ERROR: conn[%u] unexpected codec decision, expected pt=%d, got pt=%d\n",
2135 index_conn_dst, expect->payload_type_map[index_conn_dst],
2136 payload_type_conn_dst);
2137 ok = false;
2138 }
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002139 }
Philipp Maier4c4d2272023-04-26 15:45:17 +02002140
2141 return ok;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002142}
2143
Philipp Maier4c4d2272023-04-26 15:45:17 +02002144static void test_mgcp_codec_decide(void)
Philipp Maier6931f9a2018-07-26 09:29:31 +02002145{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002146 int i;
2147 bool ok = true;
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002148 printf("\nTesting mgcp_codec_find_convertible()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002149
Philipp Maier9dd80ca2023-03-27 15:45:36 +02002150 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_find_convertible_cases); i++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002151 const struct testcase_mgcp_codec_decide *t = &test_mgcp_codec_find_convertible_cases[i];
2152 struct mgcp_conn_rtp conn[2] = { };
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002153 int rc;
2154 int conn_i;
2155 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002156
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002157 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002158
Philipp Maier4c4d2272023-04-26 15:45:17 +02002159 /* Build testvector (add codecs to conn, set properties etc... */
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002160 for (conn_i = 0; conn_i < 2; conn_i++) {
2161 printf(" - add codecs on conn%d:\n", conn_i);
2162 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
Philipp Maier4c4d2272023-04-26 15:45:17 +02002163 const struct testcase_mgcp_codec_decide_codec *codec = &t->codecs[conn_i][c];
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002164 if (!codec->audio_name)
2165 break;
2166
Philipp Maier4c4d2272023-04-26 15:45:17 +02002167 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name,
2168 codec->param);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002169
2170 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2171 codec->param ?
Philipp Maier4c4d2272023-04-26 15:45:17 +02002172 (codec->param->amr_octet_aligned_present ?
2173 (codec->param->amr_octet_aligned ? " octet-aligned=1" : " octet-aligned=0")
2174 : " octet-aligned=unset")
2175 : "", rc);
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002176 if (rc != codec->expect_rc) {
2177 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2178 ok = false;
2179 }
2180 }
2181 if (!c)
2182 printf(" (none)\n");
2183 }
2184
Philipp Maier4c4d2272023-04-26 15:45:17 +02002185 /* Run codec decision and check expectation */
2186 if (!codec_decision(conn, 0, 1, &t->expect[0]))
2187 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002188
Philipp Maier4c4d2272023-04-26 15:45:17 +02002189 if (!codec_decision(conn, 1, 0, &t->expect[1]))
2190 ok = false;
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002191
Philipp Maier4c4d2272023-04-26 15:45:17 +02002192 if (ok)
2193 printf(" ===> SUCCESS: codec decision as expected!\n");
2194 else
2195 printf(" ===> FAIL: unexpected codec decision!\n");
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002196 }
2197
2198 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002199}
2200
Harald Welte9befdeb2022-11-03 11:41:05 +01002201void test_conn_id_matching(void)
Neels Hofmeyr65317262018-09-03 22:11:05 +02002202{
2203 struct mgcp_endpoint endp = {};
2204 struct mgcp_conn *conn;
2205 struct mgcp_conn *conn_match;
2206 int i;
2207 const char *conn_id_generated = "000023AB";
2208 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002209 "23AB",
2210 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002211 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002212 "00000023AB",
2213 "23ab",
2214 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002215 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002216 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002217 };
2218
2219 printf("\nTesting %s\n", __func__);
2220
2221 INIT_LLIST_HEAD(&endp.conns);
2222
2223 conn = talloc_zero(NULL, struct mgcp_conn);
2224 OSMO_ASSERT(conn);
2225 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2226 llist_add(&conn->entry, &endp.conns);
2227
2228 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2229 const char *needle = conn_id_request[i];
2230 printf("needle='%s' ", needle);
2231 conn_match = mgcp_conn_get(&endp, needle);
2232 OSMO_ASSERT(conn_match);
2233 printf("found '%s'\n", conn_match->id);
2234 OSMO_ASSERT(conn_match == conn);
2235 }
2236
2237 llist_del(&conn->entry);
2238 talloc_free(conn);
2239}
2240
Harald Welte9befdeb2022-11-03 11:41:05 +01002241void test_e1_trunk_nr_from_epname(void)
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002242{
Philipp Maierd70eef62021-07-19 13:53:28 +02002243 unsigned int trunk_nr;
2244 int rc;
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002245
2246 /* Note: e1_trunk_nr_from_epname does not check the text
2247 * after the E1 trunk number, after the delimiter
2248 * character "/" arbitrary text may follow. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002249 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
Philipp Maier0653cc82020-08-10 22:52:51 +02002250 OSMO_ASSERT(trunk_nr == 0);
Philipp Maierd70eef62021-07-19 13:53:28 +02002251 OSMO_ASSERT(rc == 0);
2252 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002253 OSMO_ASSERT(trunk_nr == 1);
Philipp Maierd70eef62021-07-19 13:53:28 +02002254 OSMO_ASSERT(rc == 0);
2255 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002256 OSMO_ASSERT(trunk_nr == 2);
Philipp Maierd70eef62021-07-19 13:53:28 +02002257 OSMO_ASSERT(rc == 0);
2258 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002259 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002260 OSMO_ASSERT(rc == 0);
2261 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002262 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002263 OSMO_ASSERT(rc == 0);
2264 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002265 OSMO_ASSERT(trunk_nr == 24);
Philipp Maierd70eef62021-07-19 13:53:28 +02002266 OSMO_ASSERT(rc == 0);
2267 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002268 OSMO_ASSERT(trunk_nr == 64);
Philipp Maierd70eef62021-07-19 13:53:28 +02002269 OSMO_ASSERT(rc == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002270
2271 /* The following endpoint strings should fail, either the
2272 * trunk number exceeds the valid range or the trunk prefix
2273 * is wrong. Also when the delimiter character "/" at the
2274 * end of the trunk is wrong the parsing should fail. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002275 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
2276 OSMO_ASSERT(rc == -EINVAL);
2277 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
2278 OSMO_ASSERT(rc == -EINVAL);
2279 rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
2280 OSMO_ASSERT(rc == -EINVAL);
2281 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
2282 OSMO_ASSERT(rc == -EINVAL);
2283 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
2284 OSMO_ASSERT(rc == -EINVAL);
2285 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
2286 OSMO_ASSERT(rc == -EINVAL);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002287
2288 return;
2289}
2290
Harald Welte9befdeb2022-11-03 11:41:05 +01002291void test_mgcp_is_rtp_dummy_payload(void)
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002292{
2293 /* realistic rtp packet */
2294 static const char rtp_payload[] =
2295 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2296 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2297 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2298 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2299 0x24 };
2300
2301 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2302 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2303 struct msgb *msg_dummy_rtp =
2304 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2305
2306 uint8_t *buf;
2307
2308 /* Dummy RTP packet */
2309 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2310 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2311
2312 /* Normal RTP packet */
2313 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2314 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2315
2316 /* Dummy RTP packet with normal RTP packet attached, this must not be
2317 * recognized as Dummy RTP packet */
2318 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2319 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2320 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2321 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2322
2323 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2324 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2325 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2326
2327 msgb_free(msg_dummy);
2328 msgb_free(msg_rtp);
2329 msgb_free(msg_dummy_rtp);
2330}
2331
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002332int main(int argc, char **argv)
2333{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002334 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2335 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2336 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002337
2338 test_strline();
2339 test_values();
2340 test_messages();
2341 test_retransmission();
2342 test_packet_loss_calc();
2343 test_rqnt_cb();
2344 test_mgcp_stats();
2345 test_packet_error_detection(1, 0);
2346 test_packet_error_detection(0, 0);
2347 test_packet_error_detection(0, 1);
2348 test_packet_error_detection(1, 1);
2349 test_multilple_codec();
2350 test_no_cycle();
2351 test_no_name();
2352 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002353 test_get_lco_identifier();
2354 test_check_local_cx_options(ctx);
Philipp Maier4c4d2272023-04-26 15:45:17 +02002355 test_mgcp_codec_decide();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002356 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002357 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002358 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002359
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002360 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2361 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2362 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002363 printf("Done\n");
2364 return EXIT_SUCCESS;
2365}