blob: 26fcc2a22806d3ef5f65c33a2440f8ac6861c970 [file] [log] [blame]
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001/*
2 * (C) 2011-2012,2014 by Holger Hans Peter Freyther <zecke@selfish.org>
3 * (C) 2011-2012,2014 by On-Waves
4 * All Rights Reserved
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19#undef _GNU_SOURCE
20#define _GNU_SOURCE
21
Philipp Maier87bd9be2017-08-22 16:35:41 +020022#include <osmocom/mgcp/mgcp.h>
23#include <osmocom/mgcp/vty.h>
Neels Hofmeyr67793542017-09-08 04:25:16 +020024#include <osmocom/mgcp/mgcp_common.h>
Philipp Maier993ea6b2020-08-04 18:26:50 +020025#include <osmocom/mgcp/mgcp_conn.h>
26#include <osmocom/mgcp/mgcp_protocol.h>
Philipp Maier87bd9be2017-08-22 16:35:41 +020027#include <osmocom/mgcp/mgcp_stat.h>
28#include <osmocom/mgcp/mgcp_msg.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010029#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maierc66ab2c2020-06-02 20:55:34 +020030#include <osmocom/mgcp/mgcp_trunk.h>
Philipp Maierbc0346e2018-06-07 09:52:16 +020031#include <osmocom/mgcp/mgcp_sdp.h>
32#include <osmocom/mgcp/mgcp_codec.h>
Philipp Maierb3d14eb2021-05-20 14:18:52 +020033#include <osmocom/mgcp/mgcp_network.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020034
35#include <osmocom/core/application.h>
36#include <osmocom/core/talloc.h>
37#include <osmocom/core/utils.h>
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +020038#include <osmocom/core/socket.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020039#include <string.h>
40#include <limits.h>
41#include <dlfcn.h>
42#include <time.h>
43#include <math.h>
Neels Hofmeyrb861db92018-08-28 16:19:25 +020044#include <ctype.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020045
46char *strline_r(char *str, char **saveptr);
47
48const char *strline_test_data =
49 "one CR\r"
50 "two CR\r"
51 "\r"
52 "one CRLF\r\n"
53 "two CRLF\r\n"
Philipp Maier87bd9be2017-08-22 16:35:41 +020054 "\r\n" "one LF\n" "two LF\n" "\n" "mixed (4 lines)\r\r\n\n\r\n";
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020055
56#define EXPECTED_NUMBER_OF_LINES 13
57
58static void test_strline(void)
59{
60 char *save = NULL;
61 char *line;
62 char buf[2048];
63 int counter = 0;
64
65 osmo_strlcpy(buf, strline_test_data, sizeof(buf));
66
Philipp Maier87bd9be2017-08-22 16:35:41 +020067 for (line = mgcp_strline(buf, &save); line;
68 line = mgcp_strline(NULL, &save)) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020069 printf("line: '%s'\n", line);
70 counter++;
71 }
72
73 OSMO_ASSERT(counter == EXPECTED_NUMBER_OF_LINES);
74}
75
Philipp Maier12943ea2018-01-17 15:40:25 +010076#define AUEP1 "AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
Philipp Maierc66ab2c2020-06-02 20:55:34 +020077#define AUEP1_RET "500 158663169 FAIL\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010078#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020079#define AUEP2_RET "500 18983213 FAIL\r\n"
80#define EMPTY "\r\n"
81#define EMPTY_RET NULL
82#define SHORT "CRCX \r\n"
83#define SHORT_RET "510 000000 FAIL\r\n"
84
Philipp Maier12943ea2018-01-17 15:40:25 +010085#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
Harald Welteabbb6b92017-12-28 13:13:50 +010086#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010087#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
Philipp Maierc66ab2c2020-06-02 20:55:34 +020088#define MDCX_RET "500 18983214 FAIL\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020089
Philipp Maier87bd9be2017-08-22 16:35:41 +020090#define MDCX3 \
91 "MDCX 18983215 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010092 "I: %s\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020093
Philipp Maier87bd9be2017-08-22 16:35:41 +020094#define MDCX3_RET \
95 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +010096 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020097 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010098 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020099 "s=-\r\n" \
100 "c=IN IP4 0.0.0.0\r\n" \
101 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100102 "m=audio 16002 RTP/AVP 97\r\n" \
103 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200104 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200105
Philipp Maier87bd9be2017-08-22 16:35:41 +0200106#define MDCX3A_RET \
107 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100108 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200109 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100110 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200111 "s=-\r\n" \
112 "c=IN IP4 0.0.0.0\r\n" \
113 "t=0 0\r\n" \
114 "m=audio 16002 RTP/AVP 97\r\n" \
115 "a=rtpmap:97 GSM-EFR/8000\r\n" \
116 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200117
Philipp Maier87bd9be2017-08-22 16:35:41 +0200118#define MDCX3_FMTP_RET \
119 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100120 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200121 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100122 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200123 "s=-\r\n" \
124 "c=IN IP4 0.0.0.0\r\n" \
125 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100126 "m=audio 16006 RTP/AVP 97\r\n" \
127 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200128 "a=fmtp:126 0/1/2\r\n" \
129 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200130
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200131#define MDCX4_ADDR0000 \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200132 "MDCX 18983216 1@mgw MGCP 1.0\r\n" \
133 "M: sendrecv\r" \
134 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100135 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200136 "L: p:20, a:AMR, nt:IN\r\n" \
137 "\n" \
138 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100139 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200140 "c=IN IP4 0.0.0.0\r\n" \
141 "t=0 0\r\n" \
142 "m=audio 4441 RTP/AVP 99\r\n" \
143 "a=rtpmap:99 AMR/8000\r\n" \
144 "a=ptime:40\r\n"
145
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200146#define MDCX4_ADDR0000_RET \
147 "527 18983216 FAIL\r\n"
148
149#define MDCX4 \
150 "MDCX 18983217 1@mgw MGCP 1.0\r\n" \
151 "M: sendrecv\r" \
152 "C: 2\r\n" \
153 "I: %s\r\n" \
154 "L: p:20, a:AMR, nt:IN\r\n" \
155 "\n" \
156 "v=0\r\n" \
157 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
158 "c=IN IP4 5.6.7.8\r\n" \
159 "t=0 0\r\n" \
160 "m=audio 4441 RTP/AVP 99\r\n" \
161 "a=rtpmap:99 AMR/8000\r\n" \
162 "a=ptime:40\r\n"
163
Philipp Maier87bd9be2017-08-22 16:35:41 +0200164#define MDCX4_RET(Ident) \
165 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100166 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200167 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100168 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200169 "s=-\r\n" \
170 "c=IN IP4 0.0.0.0\r\n" \
171 "t=0 0\r\n" \
172 "m=audio 16002 RTP/AVP 99\r\n" \
173 "a=rtpmap:99 AMR/8000\r\n" \
174 "a=ptime:40\r\n"
175
176#define MDCX4_RO_RET(Ident) \
177 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100178 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200179 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100180 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200181 "s=-\r\n" \
182 "c=IN IP4 0.0.0.0\r\n" \
183 "t=0 0\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200184 "m=audio 16002 RTP/AVP 112\r\n" \
185 "a=rtpmap:112 AMR\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200186 "a=ptime:40\r\n"
187
188#define MDCX4_PT1 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200189 "MDCX 18983218 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol17058482019-06-26 12:23:02 +0200190 "M: SENDRECV\r" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200191 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100192 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200193 "L: p:20-40, a:AMR, nt:IN\r\n" \
194 "\n" \
195 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200196 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
197 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200198 "t=0 0\r\n" \
199 "m=audio 4441 RTP/AVP 99\r\n" \
200 "a=rtpmap:99 AMR/8000\r\n" \
201 "a=ptime:40\r\n"
202
203#define MDCX4_PT2 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200204 "MDCX 18983219 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200205 "M: sendrecv\r" \
206 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100207 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200208 "L: p:20-20, a:AMR, nt:IN\r\n" \
209 "\n" \
210 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200211 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
212 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200213 "t=0 0\r\n" \
214 "m=audio 4441 RTP/AVP 99\r\n" \
215 "a=rtpmap:99 AMR/8000\r\n" \
216 "a=ptime:40\r\n"
217
218#define MDCX4_PT3 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200219 "MDCX 18983220 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200220 "M: sendrecv\r" \
221 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100222 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200223 "L: a:AMR, nt:IN\r\n" \
224 "\n" \
225 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200226 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
227 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200228 "t=0 0\r\n" \
229 "m=audio 4441 RTP/AVP 99\r\n" \
230 "a=rtpmap:99 AMR/8000\r\n" \
231 "a=ptime:40\r\n"
232
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200233/* Test different upper/lower case in options */
234#define MDCX4_PT4 \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200235 "MDCX 18983221 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200236 "m: sendrecv\r" \
237 "c: 2\r\n" \
238 "i: %s\r\n" \
Pau Espin Pedrol83fd8a52019-06-26 12:55:26 +0200239 "l: A:amr, NT:IN\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200240 "\n" \
241 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200242 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
243 "c=IN IP4 5.6.7.8\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200244 "t=0 0\r\n" \
245 "m=audio 4441 RTP/AVP 99\r\n" \
246 "a=rtpmap:99 AMR/8000\r\n" \
247 "a=ptime:40\r\n"
248
249#define MDCX4_SO \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200250 "MDCX 18983222 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200251 "M: sendonly\r" \
252 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100253 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200254 "L: p:20, a:AMR, nt:IN\r\n" \
255 "\n" \
256 "v=0\r\n" \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200257 "o=- %s 23 IN IP4 5.6.7.8\r\n" \
258 "c=IN IP4 5.6.7.8\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200259 "t=0 0\r\n" \
260 "m=audio 4441 RTP/AVP 99\r\n" \
261 "a=rtpmap:99 AMR/8000\r\n" \
262 "a=ptime:40\r\n"
263
264#define MDCX4_RO \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200265 "MDCX 18983223 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200266 "M: recvonly\r" \
267 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100268 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200269 "L: p:20, a:AMR, nt:IN\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200270
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200271#define MDCX_TOO_LONG_CI \
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200272 "MDCX 18983224 1@mgw MGCP 1.0\r\n" \
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200273 "I: 123456789012345678901234567890123\n"
274
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200275#define MDCX_TOO_LONG_CI_RET "510 18983224 FAIL\r\n"
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200276
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200277#define SHORT2 "CRCX 1"
278#define SHORT2_RET "510 000000 FAIL\r\n"
279#define SHORT3 "CRCX 1 1@mgw"
280#define SHORT4 "CRCX 1 1@mgw MGCP"
281#define SHORT5 "CRCX 1 1@mgw MGCP 1.0"
282
Philipp Maier87bd9be2017-08-22 16:35:41 +0200283#define CRCX \
284 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200285 "m: recvonly\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200286 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200287 "L: p:20\r\n" \
288 "\r\n" \
289 "v=0\r\n" \
290 "c=IN IP4 123.12.12.123\r\n" \
291 "m=audio 5904 RTP/AVP 97\r\n" \
292 "a=rtpmap:97 GSM-EFR/8000\r\n" \
293 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200294
Philipp Maier87bd9be2017-08-22 16:35:41 +0200295#define CRCX_RET \
296 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100297 "I: %s\r\n" \
298 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200299 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100300 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200301 "s=-\r\n" \
302 "c=IN IP4 0.0.0.0\r\n" \
303 "t=0 0\r\n" \
304 "m=audio 16002 RTP/AVP 97\r\n" \
305 "a=rtpmap:97 GSM-EFR/8000\r\n" \
306 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200307
Philipp Maier87bd9be2017-08-22 16:35:41 +0200308#define CRCX_RET_NO_RTPMAP \
309 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100310 "I: %s\r\n" \
311 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200312 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100313 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200314 "s=-\r\n" \
315 "c=IN IP4 0.0.0.0\r\n" \
316 "t=0 0\r\n" \
317 "m=audio 16002 RTP/AVP 97\r\n" \
318 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200319
Philipp Maier87bd9be2017-08-22 16:35:41 +0200320#define CRCX_FMTP_RET \
321 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100322 "I: %s\r\n" \
323 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200324 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100325 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200326 "s=-\r\n" \
327 "c=IN IP4 0.0.0.0\r\n" \
328 "t=0 0\r\n" \
329 "m=audio 16006 RTP/AVP 97\r\n" \
330 "a=rtpmap:97 GSM-EFR/8000\r\n" \
331 "a=fmtp:126 0/1/2\r\n" \
332 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200333
Philipp Maier87bd9be2017-08-22 16:35:41 +0200334#define CRCX_ZYN \
335 "CRCX 2 1@mgw MGCP 1.0\r" \
336 "M: recvonly\r" \
337 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200338 "\n" \
339 "v=0\r" \
340 "c=IN IP4 123.12.12.123\r" \
341 "m=audio 5904 RTP/AVP 97\r" \
342 "a=rtpmap:97 GSM-EFR/8000\r"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200343
Philipp Maier87bd9be2017-08-22 16:35:41 +0200344#define CRCX_ZYN_RET \
345 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100346 "I: %s\r\n" \
347 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200348 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100349 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200350 "s=-\r\n" \
351 "c=IN IP4 0.0.0.0\r\n" \
352 "t=0 0\r\n" \
353 "m=audio 16004 RTP/AVP 97\r\n" \
354 "a=rtpmap:97 GSM-EFR/8000\r\n" \
355 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200356
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200357#define CRCX_X_OSMO_IGN \
358 "CRCX 2 1@mgw MGCP 1.0\r\n" \
359 "M: recvonly\r\n" \
360 "C: 2\r\n" \
361 "L: p:20\r\n" \
Neels Hofmeyrf2388ea2018-08-26 23:36:53 +0200362 "X-Osmo-IGN: C foo\r\n" \
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200363 "\r\n" \
364 "v=0\r\n" \
365 "c=IN IP4 123.12.12.123\r\n" \
366 "m=audio 5904 RTP/AVP 97\r\n" \
367 "a=rtpmap:97 GSM-EFR/8000\r\n" \
368 "a=ptime:40\r\n"
369
370#define CRCX_X_OSMO_IGN_RET \
371 "200 2 OK\r\n" \
372 "I: %s\r\n" \
373 "\r\n" \
374 "v=0\r\n" \
375 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
376 "s=-\r\n" \
377 "c=IN IP4 0.0.0.0\r\n" \
378 "t=0 0\r\n" \
379 "m=audio 16010 RTP/AVP 97\r\n" \
380 "a=rtpmap:97 GSM-EFR/8000\r\n" \
381 "a=ptime:40\r\n"
382
Philipp Maier87bd9be2017-08-22 16:35:41 +0200383#define DLCX \
384 "DLCX 7 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100385 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200386 "C: 2\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200387
Philipp Maier87bd9be2017-08-22 16:35:41 +0200388#define DLCX_RET \
389 "250 7 OK\r\n" \
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100390 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
391
392 #define DLCX_RET_OSMUX DLCX_RET \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200393 "X-Osmo-CP: EC TI=0, TO=0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200394
Philipp Maier87bd9be2017-08-22 16:35:41 +0200395#define RQNT \
396 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
397 "X: B244F267488\r\n" \
398 "S: D/9\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200399
Philipp Maier87bd9be2017-08-22 16:35:41 +0200400#define RQNT2 \
401 "RQNT 186908781 1@mgw MGCP 1.0\r\n" \
402 "X: ADD4F26746F\r\n" \
403 "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200404
405#define RQNT1_RET "200 186908780 OK\r\n"
406#define RQNT2_RET "200 186908781 OK\r\n"
407
Philipp Maier87bd9be2017-08-22 16:35:41 +0200408#define PTYPE_IGNORE 0 /* == default initializer */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200409#define PTYPE_NONE 128
410#define PTYPE_NYI PTYPE_NONE
411
Philipp Maier87bd9be2017-08-22 16:35:41 +0200412#define CRCX_MULT_1 \
413 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200414 "M: recvonly\r\n" \
415 "C: 2\r\n" \
416 "X\r\n" \
417 "L: p:20\r\n" \
418 "\r\n" \
419 "v=0\r\n" \
420 "c=IN IP4 123.12.12.123\r\n" \
421 "m=audio 5904 RTP/AVP 18 97\r\n" \
422 "a=rtpmap:18 G729/8000\r\n" \
423 "a=rtpmap:97 GSM-EFR/8000\r\n" \
424 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200425
Philipp Maier87bd9be2017-08-22 16:35:41 +0200426#define CRCX_MULT_2 \
427 "CRCX 2 2@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200428 "M: recvonly\r\n" \
429 "C: 2\r\n" \
430 "X\r\n" \
431 "L: p:20\r\n" \
432 "\r\n" \
433 "v=0\r\n" \
434 "c=IN IP4 123.12.12.123\r\n" \
435 "m=audio 5904 RTP/AVP 18 97 101\r\n" \
436 "a=rtpmap:18 G729/8000\r\n" \
437 "a=rtpmap:97 GSM-EFR/8000\r\n" \
438 "a=rtpmap:101 FOO/8000\r\n" \
439 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200440
Philipp Maier87bd9be2017-08-22 16:35:41 +0200441#define CRCX_MULT_3 \
442 "CRCX 2 3@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200443 "M: recvonly\r\n" \
444 "C: 2\r\n" \
445 "X\r\n" \
446 "L: p:20\r\n" \
447 "\r\n" \
448 "v=0\r\n" \
449 "c=IN IP4 123.12.12.123\r\n" \
450 "m=audio 5904 RTP/AVP\r\n" \
451 "a=rtpmap:18 G729/8000\r\n" \
452 "a=rtpmap:97 GSM-EFR/8000\r\n" \
453 "a=rtpmap:101 FOO/8000\r\n" \
454 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200455
Philipp Maier87bd9be2017-08-22 16:35:41 +0200456#define CRCX_MULT_4 \
457 "CRCX 2 4@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200458 "M: recvonly\r\n" \
459 "C: 2\r\n" \
460 "X\r\n" \
461 "L: p:20\r\n" \
462 "\r\n" \
463 "v=0\r\n" \
464 "c=IN IP4 123.12.12.123\r\n" \
465 "m=audio 5904 RTP/AVP 18\r\n" \
466 "a=rtpmap:18 G729/8000\r\n" \
467 "a=rtpmap:97 GSM-EFR/8000\r\n" \
468 "a=rtpmap:101 FOO/8000\r\n" \
469 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200470
471#define CRCX_MULT_GSM_EXACT \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200472 "CRCX 259260421 5@mgw MGCP 1.0\r\n" \
473 "C: 1355c6041e\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200474 "L: p:20, a:GSM, nt:IN\r\n" \
475 "M: recvonly\r\n" \
476 "\r\n" \
477 "v=0\r\n" \
478 "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
479 "s=-\r\nc=IN IP4 192.168.181.247\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200480 "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 +0200481 "a=rtpmap:0 PCMU/8000\r\n" \
482 "a=rtpmap:8 PCMA/8000\r\n" \
483 "a=rtpmap:3 gsm/8000\r\n" \
484 "a=rtpmap:18 G729/8000\r\n" \
485 "a=fmtp:18 annexb=no\r\n" \
486 "a=rtpmap:4 G723/8000\r\n" \
487 "a=rtpmap:96 iLBC/8000\r\n" \
488 "a=fmtp:96 mode=20\r\n" \
489 "a=rtpmap:97 iLBC/8000\r\n" \
490 "a=fmtp:97 mode=30\r\n" \
491 "a=rtpmap:101 telephone-event/8000\r\n" \
492 "a=fmtp:101 0-15\r\n" \
493 "a=recvonly\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200494
Philipp Maier87bd9be2017-08-22 16:35:41 +0200495#define MDCX_NAT_DUMMY \
496 "MDCX 23 5@mgw MGCP 1.0\r\n" \
497 "C: 1355c6041e\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100498 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200499 "\r\n" \
500 "c=IN IP4 8.8.8.8\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200501 "m=audio 16434 RTP/AVP 3\r\n"
502
503#define CRCX_NO_LCO_NO_SDP \
504 "CRCX 2 6@mgw MGCP 1.0\r\n" \
505 "M: recvonly\r\n" \
506 "C: 2\r\n"
507
Philipp Maier228e5912019-03-05 13:56:59 +0100508#define CRCX_AMR_WITH_FMTP \
509 "CRCX 2 7@mgw MGCP 1.0\r\n" \
510 "M: recvonly\r\n" \
511 "C: 2\r\n" \
512 "X\r\n" \
513 "L: p:20\r\n" \
514 "\r\n" \
515 "v=0\r\n" \
516 "c=IN IP4 123.12.12.123\r\n" \
517 "m=audio 5904 RTP/AVP 111\r\n" \
518 "a=rtpmap:111 AMR/8000/1\r\n" \
519 "a=ptime:20\r\n" \
520 "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
521
522#define CRCX_AMR_WITH_FMTP_RET \
523 "200 2 OK\r\n" \
524 "I: %s\r\n" \
525 "\r\n" \
526 "v=0\r\n" \
527 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
528 "s=-\r\n" \
529 "c=IN IP4 0.0.0.0\r\n" \
530 "t=0 0\r\n" \
531 "m=audio 16012 RTP/AVP 111\r\n" \
532 "a=rtpmap:111 AMR/8000/1\r\n" \
533 "a=fmtp:111 octet-align=1\r\n" \
534 "a=ptime:20\r\n"
535
Philipp Maierbc0346e2018-06-07 09:52:16 +0200536#define CRCX_NO_LCO_NO_SDP_RET \
537 "200 2 OK\r\n" \
538 "I: %s\r\n" \
539 "\r\n" \
540 "v=0\r\n" \
541 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
542 "s=-\r\n" \
543 "c=IN IP4 0.0.0.0\r\n" \
544 "t=0 0\r\n" \
545 "m=audio 16008 RTP/AVP 0\r\n" \
546 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200547
548struct mgcp_test {
549 const char *name;
550 const char *req;
551 const char *exp_resp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200552 int ptype;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200553 const char *extra_fmtp;
554};
555
556static const struct mgcp_test tests[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200557 {"AUEP1", AUEP1, AUEP1_RET},
558 {"AUEP2", AUEP2, AUEP2_RET},
559 {"MDCX1", MDCX_WRONG_EP, MDCX_ERR_RET},
560 {"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
561 {"CRCX", CRCX, CRCX_RET, 97},
562 {"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
Pau Espin Pedrold6769ea2021-07-06 19:44:27 +0200563 {"MDCX4_ADDR000", MDCX4_ADDR0000, MDCX4_ADDR0000_RET},
564 {"MDCX4", MDCX4, MDCX4_RET("18983217"), 99},
565 {"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983218"), 99},
566 {"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983219"), 99},
567 {"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983220"), 99},
568 {"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983221"), 99},
569 {"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983222"), 99},
570 {"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983223"), PTYPE_IGNORE},
Philipp Maier87bd9be2017-08-22 16:35:41 +0200571 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
572 {"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
573 {"EMPTY", EMPTY, EMPTY_RET},
574 {"SHORT1", SHORT, SHORT_RET},
575 {"SHORT2", SHORT2, SHORT2_RET},
576 {"SHORT3", SHORT3, SHORT2_RET},
577 {"SHORT4", SHORT4, SHORT2_RET},
578 {"RQNT1", RQNT, RQNT1_RET},
579 {"RQNT2", RQNT2, RQNT2_RET},
580 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
581 {"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
582 {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
583 "a=fmtp:126 0/1/2"},
584 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
Philipp Maierbc0346e2018-06-07 09:52:16 +0200585 {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200586 {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200587 {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
Philipp Maier228e5912019-03-05 13:56:59 +0100588 {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200589};
590
591static const struct mgcp_test retransmit[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200592 {"CRCX", CRCX, CRCX_RET},
593 {"RQNT1", RQNT, RQNT1_RET},
594 {"RQNT2", RQNT2, RQNT2_RET},
595 {"MDCX3", MDCX3, MDCX3A_RET},
596 {"DLCX", DLCX, DLCX_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200597};
598
Philipp Maierffd75e42017-11-22 11:44:50 +0100599static struct msgb *create_msg(const char *str, const char *conn_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200600{
601 struct msgb *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100602 int len;
603
604 printf("creating message from statically defined input:\n");
605 printf("---------8<---------\n%s\n---------8<---------\n", str);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200606
607 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
Philipp Maierffd75e42017-11-22 11:44:50 +0100608 if (conn_id && strlen(conn_id))
609 len = sprintf((char *)msg->data, str, conn_id, conn_id);
610 else
611 len = sprintf((char *)msg->data, "%s", str);
612
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200613 msg->l2h = msgb_put(msg, len);
614 return msg;
615}
616
Philipp Maier37a808c2020-07-03 15:48:31 +0200617static char last_endpoint[MGCP_ENDPOINT_MAXLEN];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200618
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200619static int mgcp_test_policy_cb(struct mgcp_endpoint *endp,
620 int state, const char *transaction_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200621{
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200622 unsigned int i;
623 struct mgcp_trunk *trunk;
624
625 fprintf(stderr, "Policy CB got state %d on endpoint %s\n",
626 state, endp->name);
627
628 trunk = endp->trunk;
Philipp Maier37a808c2020-07-03 15:48:31 +0200629 last_endpoint[0] = '\0';
Philipp Maier869b21c2020-07-03 16:04:16 +0200630 for (i = 0; i < trunk->number_endpoints; i++) {
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200631 if (strcmp(endp->name, trunk->endpoints[i]->name) == 0)
Philipp Maier37a808c2020-07-03 15:48:31 +0200632 osmo_strlcpy(last_endpoint, trunk->endpoints[i]->name,
633 sizeof(last_endpoint));
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200634 }
635
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200636 return MGCP_POLICY_CONT;
637}
638
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200639static int dummy_packets = 0;
640/* override and forward */
641ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200642 const struct sockaddr *dest_addr, socklen_t addrlen)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200643{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200644 uint32_t dest_host =
645 htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
646 int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200647
Philipp Maierb3d14eb2021-05-20 14:18:52 +0200648 if (len == sizeof(rtp_dummy_payload)
649 && memcmp(buf, rtp_dummy_payload, sizeof(rtp_dummy_payload)) == 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200650 fprintf(stderr,
651 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
652 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200653 dummy_packets += 1;
654 }
655
Pau Espin Pedrola24dcc62021-07-06 17:48:47 +0200656 /* Make sure address+port are valid */
657 OSMO_ASSERT(dest_host);
658 OSMO_ASSERT(dest_port);
659
Philipp Maier3d9b6562017-10-13 18:33:44 +0200660 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200661}
662
663static int64_t force_monotonic_time_us = -1;
664/* override and forward */
665int clock_gettime(clockid_t clk_id, struct timespec *tp)
666{
667 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
668 static clock_gettime_t real_clock_gettime = NULL;
669
670 if (!real_clock_gettime)
671 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
672
673 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
674 tp->tv_sec = force_monotonic_time_us / 1000000;
675 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
676 return 0;
677 }
678
679 return real_clock_gettime(clk_id, tp);
680}
681
Philipp Maier14b27a82020-06-02 20:15:30 +0200682static void mgcp_endpoints_release(struct mgcp_trunk *trunk)
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200683{
684 int i;
Philipp Maier869b21c2020-07-03 16:04:16 +0200685 for (i = 0; i < trunk->number_endpoints; i++)
Philipp Maierc66ab2c2020-06-02 20:55:34 +0200686 mgcp_endp_release(trunk->endpoints[i]);
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200687}
688
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200689#define CONN_UNMODIFIED (0x1000)
690
691static void test_values(void)
692{
693 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200694 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200695
696 /* Check that LOOPBACK enables all output */
697 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200698 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200699}
700
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200701/* Extract a connection ID from a response and return in conn_id;
702 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100703static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200704 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100705{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200706 const char *conn_id_start;
707 const char *conn_id_end;
708 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100709
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200710 const char *header_I = "\r\nI: ";
711 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100712
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200713 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
714 if ((conn_id_start = strstr((char *)resp, header_I))) {
715 conn_id_start += strlen(header_I);
716 conn_id_end = strstr(conn_id_start, "\r\n");
717 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
718 conn_id_start += strlen(header_o);
719 conn_id_end = strchr(conn_id_start, ' ');
720 } else
721 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100722
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200723 if (conn_id_end)
724 conn_id_len = conn_id_end - conn_id_start;
725 else
726 conn_id_len = strlen(conn_id_start);
727 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100728
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200729 /* A valid conn_id must at least contain one digit, and must
730 * not exceed a length of 32 digits */
731 OSMO_ASSERT(conn_id_len <= 32);
732 OSMO_ASSERT(conn_id_len > 0);
733
734 strncpy(conn_id, conn_id_start, conn_id_len);
735 conn_id[conn_id_len] = '\0';
736 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100737}
738
739/* Check response, automatically patch connection ID if needed */
740static int check_response(uint8_t *resp, const char *exp_resp)
741{
742 char exp_resp_patched[4096];
743 const char *exp_resp_ptr;
744 char conn_id[256];
745
746 printf("checking response:\n");
747
748 /* If the expected response is intened to be patched
749 * (%s placeholder inside) we will patch it with the
750 * connection identifier we just received from the
751 * real response. This is necessary because the CI
752 * is generated by the mgcp code on CRCX and we can
753 * not know it in advance */
754 if (strstr(exp_resp, "%s")) {
755 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
756 0) {
757 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
758 exp_resp_ptr = exp_resp_patched;
759 printf
760 ("using message with patched conn_id for comparison\n");
761 } else {
762 printf
763 ("patching conn_id failed, using message as statically defined for comparison\n");
764 exp_resp_ptr = exp_resp;
765 }
766 } else {
767 printf("using message as statically defined for comparison\n");
768 exp_resp_ptr = exp_resp;
769 }
770
771 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
772 printf("Unexpected response, please check!\n");
773 printf
774 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
775 resp);
776 printf
777 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
778 exp_resp_ptr);
779 return -EINVAL;
780 }
781
782 printf("Response matches our expectations.\n");
783 return 0;
784}
785
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200786static void test_messages(void)
787{
788 struct mgcp_config *cfg;
789 struct mgcp_endpoint *endp;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200790 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200791 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200792 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100793 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100794 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200795
796 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200797 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200798
Philipp Maier889fe7f2020-07-06 17:44:12 +0200799 trunk->v.vty_number_endpoints = 64;
800 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200801 cfg->policy_cb = mgcp_test_policy_cb;
802
Philipp Maierffd75e42017-11-22 11:44:50 +0100803 memset(last_conn_id, 0, sizeof(last_conn_id));
804
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200805 for (i = 0; i < ARRAY_SIZE(tests); i++) {
806 const struct mgcp_test *t = &tests[i];
807 struct msgb *inp;
808 struct msgb *msg;
809
Philipp Maierffd75e42017-11-22 11:44:50 +0100810 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200811 printf("Testing %s\n", t->name);
812
Philipp Maier37a808c2020-07-03 15:48:31 +0200813 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200814 dummy_packets = 0;
815
Philipp Maierd19de2e2020-06-03 13:55:33 +0200816 osmo_talloc_replace_string(cfg, &trunk->audio_fmtp_extra,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200817 t->extra_fmtp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200818
Philipp Maierffd75e42017-11-22 11:44:50 +0100819 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200820 msg = mgcp_handle_message(cfg, inp);
821 msgb_free(inp);
822 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200823 if (msg) {
824 printf("%s failed '%s'\n", t->name,
825 (char *)msg->data);
826 OSMO_ASSERT(false);
827 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100828 } else if (check_response(msg->data, t->exp_resp) != 0) {
829 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200830 OSMO_ASSERT(false);
831 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100832
Philipp Maier7df419b2017-12-04 17:11:42 +0100833 if (msg) {
834 rc = get_conn_id_from_response(msg->data, last_conn_id,
835 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200836 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100837 printf("(response contains a connection id)\n");
838 else
839 printf("(response does not contain a connection id)\n");
840 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100841
Philipp Maiera330b862017-12-04 17:16:16 +0100842 if (msg)
843 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200844
845 if (dummy_packets)
846 printf("Dummy packets: %d\n", dummy_packets);
847
Philipp Maier37a808c2020-07-03 15:48:31 +0200848 if (last_endpoint[0] != '\0') {
849 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
850 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200851
Philipp Maier01d24a32017-11-21 17:26:09 +0100852 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200853 if (conn) {
854 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200855
Philipp Maier87bd9be2017-08-22 16:35:41 +0200856 if (conn->end.packet_duration_ms != -1)
857 printf("Detected packet duration: %d\n",
858 conn->end.packet_duration_ms);
859 else
860 printf("Packet duration not set\n");
861 if (endp->local_options.pkt_period_min ||
862 endp->local_options.pkt_period_max)
863 printf
864 ("Requested packetetization period: "
865 "%d-%d\n",
866 endp->local_options.pkt_period_min,
867 endp->
868 local_options.pkt_period_max);
869 else
870 printf
871 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200872
Philipp Maier87bd9be2017-08-22 16:35:41 +0200873 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
874 printf("Connection mode: %d:%s%s%s%s\n",
875 conn->conn->mode,
876 !conn->conn->mode ? " NONE" : "",
877 conn->conn->mode & MGCP_CONN_SEND_ONLY
878 ? " SEND" : "",
879 conn->conn->mode & MGCP_CONN_RECV_ONLY
880 ? " RECV" : "",
881 conn->conn->mode & MGCP_CONN_LOOPBACK
882 & ~MGCP_CONN_RECV_SEND
883 ? " LOOP" : "");
884 fprintf(stderr,
885 "RTP output %sabled, NET output %sabled\n",
886 conn->end.output_enabled
887 ? "en" : "dis",
888 conn->end.output_enabled
889 ? "en" : "dis");
890 } else
891 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200892
Philipp Maier87bd9be2017-08-22 16:35:41 +0200893 OSMO_ASSERT(conn->end.output_enabled
894 == (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
895
896 conn->conn->mode |= CONN_UNMODIFIED;
897
898 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200899 endp->local_options.pkt_period_min = 0;
900 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200901 }
902
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200903 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100904 if (conn && t->ptype != PTYPE_IGNORE) {
Philipp Maier37a808c2020-07-03 15:48:31 +0200905 OSMO_ASSERT(last_endpoint[0] != '\0');
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200906
Philipp Maier37a808c2020-07-03 15:48:31 +0200907 fprintf(stderr, "endpoint:%s: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200908 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200909 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200910 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200911
Philipp Maier87bd9be2017-08-22 16:35:41 +0200912 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200913 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200914 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200915
916 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200917 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200918 }
919 }
920
Philipp Maierd19de2e2020-06-03 13:55:33 +0200921 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200922 talloc_free(cfg);
923}
924
925static void test_retransmission(void)
926{
927 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200928 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200929 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100930 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100931 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200932
933 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200934 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200935
Philipp Maier889fe7f2020-07-06 17:44:12 +0200936 trunk->v.vty_number_endpoints = 64;
937 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200938
Philipp Maierffd75e42017-11-22 11:44:50 +0100939 memset(last_conn_id, 0, sizeof(last_conn_id));
940
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200941 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
942 const struct mgcp_test *t = &retransmit[i];
943 struct msgb *inp;
944 struct msgb *msg;
945
Philipp Maierffd75e42017-11-22 11:44:50 +0100946 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200947 printf("Testing %s\n", t->name);
948
Philipp Maierffd75e42017-11-22 11:44:50 +0100949 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200950 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200951
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200952 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100953 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200954 printf("%s failed '%s'\n", t->name, (char *)msg->data);
955 OSMO_ASSERT(false);
956 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100957
Philipp Maier23b8e292017-12-04 16:48:45 +0100958 if (msg && strcmp(t->name, "CRCX") == 0) {
959 rc = get_conn_id_from_response(msg->data, last_conn_id,
960 sizeof(last_conn_id));
961 OSMO_ASSERT(rc == 0);
962 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100963
Philipp Maier7cedfd72017-12-04 16:49:12 +0100964 if (msg)
965 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200966
967 /* Retransmit... */
968 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100969 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200970 msg = mgcp_handle_message(cfg, inp);
971 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100972 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200973 printf("%s failed '%s'\n", t->name, (char *)msg->data);
974 OSMO_ASSERT(false);
975 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200976 msgb_free(msg);
977 }
978
Philipp Maierd19de2e2020-06-03 13:55:33 +0200979 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200980 talloc_free(cfg);
981}
982
983static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
984{
985 ptrdiff_t tone = _tone;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200986 endp->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200987 return 0;
988}
989
990static void test_rqnt_cb(void)
991{
992 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +0200993 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200994 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100995 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200996
997 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +0200998 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200999 cfg->rqnt_cb = rqnt_cb;
1000
Philipp Maier889fe7f2020-07-06 17:44:12 +02001001 trunk->v.vty_number_endpoints = 64;
1002 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001003
Philipp Maierffd75e42017-11-22 11:44:50 +01001004 inp = create_msg(CRCX, NULL);
1005 msg = mgcp_handle_message(cfg, inp);
1006 OSMO_ASSERT(msg);
1007 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
1008 sizeof(conn_id)) == 0);
1009 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001010 msgb_free(inp);
1011
1012 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +01001013 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001014 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001015 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001016 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
1017 abort();
1018 }
1019
Philipp Maier87bd9be2017-08-22 16:35:41 +02001020 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001021 printf("FAILED: callback not called: %p\n", cfg->data);
1022 abort();
1023 }
1024
1025 msgb_free(msg);
1026 msgb_free(inp);
1027
Philipp Maierffd75e42017-11-22 11:44:50 +01001028 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001029 msgb_free(mgcp_handle_message(cfg, inp));
1030 msgb_free(inp);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001031 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032 talloc_free(cfg);
1033}
1034
1035struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001036 int cycles;
1037 uint16_t base_seq;
1038 uint16_t max_seq;
1039 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001040
Philipp Maier87bd9be2017-08-22 16:35:41 +02001041 uint32_t expected;
1042 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001043};
1044
1045static const struct pl_test pl_test_dat[] = {
1046 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001047 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1048 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001049 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001050 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1051 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001052 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001053 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1054 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001055 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001056 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1057 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001058 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001059 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1060 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001061};
1062
1063static void test_packet_loss_calc(void)
1064{
1065 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001066 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001067 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001068 struct mgcp_config *cfg;
1069 struct mgcp_trunk *trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001070
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001071 printf("Testing packet loss calculation.\n");
1072
Philipp Maiercede2a42018-07-03 14:14:21 +02001073 memset(&endp, 0, sizeof(endp));
Philipp Maier124a3e02021-07-26 11:17:15 +02001074 cfg = mgcp_config_alloc();
1075 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
1076 endp.cfg = cfg;
Philipp Maiercede2a42018-07-03 14:14:21 +02001077 endp.type = &ep_typeset.rtp;
Philipp Maier124a3e02021-07-26 11:17:15 +02001078 trunk->v.vty_number_endpoints = 1;
1079 trunk->endpoints = endpoints;
1080 trunk->endpoints[0] = &endp;
1081 endp.trunk = trunk;
Philipp Maiercede2a42018-07-03 14:14:21 +02001082 INIT_LLIST_HEAD(&endp.conns);
1083
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001084 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1085 uint32_t expected;
1086 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001087
Philipp Maiercede2a42018-07-03 14:14:21 +02001088 struct mgcp_conn_rtp *conn = NULL;
1089 struct mgcp_conn *_conn = NULL;
1090 struct mgcp_rtp_state *state;
1091 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001092
Philipp Maiercede2a42018-07-03 14:14:21 +02001093 _conn =
1094 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1095 "test-connection");
1096 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1097 state = &conn->state;
Pau Espin Pedrol907744e2021-06-04 17:57:34 +02001098 packets_rx = rate_ctr_group_get_ctr(conn->rate_ctr_group, RTP_PACKETS_RX_CTR);
Philipp Maiercede2a42018-07-03 14:14:21 +02001099
1100 state->stats.initialized = 1;
1101 state->stats.base_seq = pl_test_dat[i].base_seq;
1102 state->stats.max_seq = pl_test_dat[i].max_seq;
1103 state->stats.cycles = pl_test_dat[i].cycles;
1104
1105 packets_rx->current = pl_test_dat[i].packets;
1106 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001107
Philipp Maier87bd9be2017-08-22 16:35:41 +02001108 if (loss != pl_test_dat[i].loss
1109 || expected != pl_test_dat[i].expected) {
1110 printf
1111 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1112 i, loss, pl_test_dat[i].loss, expected,
1113 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001114 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001115
1116 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001117 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001118
Philipp Maier124a3e02021-07-26 11:17:15 +02001119 talloc_free(trunk);
1120 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001121}
1122
Philipp Maier87bd9be2017-08-22 16:35:41 +02001123int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1124 uint32_t *pr, uint32_t *_or, int *loss,
1125 uint32_t *jitter)
1126{
1127 char *line, *save;
1128 int rc;
1129
1130 /* initialize with bad values */
1131 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1132 *loss = INT_MAX;
1133
1134 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1135 if (!line)
1136 return -1;
1137
1138 /* this can only parse the message that is created above... */
1139 for_each_non_empty_line(line, save) {
1140 switch (line[0]) {
1141 case 'P':
1142 rc = sscanf(line,
1143 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1144 ps, os, pr, _or, loss, jitter);
1145 return rc == 6 ? 0 : -1;
1146 }
1147 }
1148
1149 return -1;
1150}
1151
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001152static void test_mgcp_stats(void)
1153{
1154 printf("Testing stat parsing\n");
1155
1156 uint32_t bps, bos, pr, _or, jitter;
1157 struct msgb *msg;
1158 int loss;
1159 int rc;
1160
Philipp Maierffd75e42017-11-22 11:44:50 +01001161 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001162 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1163 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001164 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1165 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001166 printf("FAIL: Parsing failed1.\n");
1167 msgb_free(msg);
1168
Philipp Maier87bd9be2017-08-22 16:35:41 +02001169 msg =
1170 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001171 ("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 +02001172 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1173 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001174 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1175 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001176 printf("FAIL: Parsing failed2.\n");
1177 msgb_free(msg);
1178}
1179
1180struct rtp_packet_info {
1181 float txtime;
1182 int len;
1183 char *data;
1184};
1185
1186struct rtp_packet_info test_rtp_packets1[] = {
1187 /* RTP: SeqNo=0, TS=0 */
1188 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001189 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001190 /* RTP: SeqNo=1, TS=160 */
1191 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001192 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001193 /* RTP: SeqNo=2, TS=320 */
1194 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001195 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001196 /* Repeat RTP timestamp: */
1197 /* RTP: SeqNo=3, TS=320 */
1198 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001199 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001200 /* RTP: SeqNo=4, TS=480 */
1201 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001202 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001203 /* RTP: SeqNo=5, TS=640 */
1204 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001205 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001206 /* Double skip RTP timestamp (delta = 2*160): */
1207 /* RTP: SeqNo=6, TS=960 */
1208 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\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=7, TS=1120 */
1211 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001212 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001213 /* RTP: SeqNo=8, TS=1280 */
1214 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001215 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001216 /* Non 20ms RTP timestamp (delta = 120): */
1217 /* RTP: SeqNo=9, TS=1400 */
1218 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\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=10, TS=1560 */
1221 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001222 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001223 /* RTP: SeqNo=11, TS=1720 */
1224 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001225 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001226 /* SSRC changed to 0x10203040, RTP timestamp jump */
1227 /* RTP: SeqNo=12, TS=34688 */
1228 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
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=13, TS=34848 */
1231 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001232 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001233 /* RTP: SeqNo=14, TS=35008 */
1234 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001235 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001236 /* Non 20ms RTP timestamp (delta = 120): */
1237 /* RTP: SeqNo=15, TS=35128 */
1238 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001239 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001240 /* RTP: SeqNo=16, TS=35288 */
1241 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001242 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001243 /* RTP: SeqNo=17, TS=35448 */
1244 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001245 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001246 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1247 /* RTP: SeqNo=19, TS=35768 */
1248 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\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=20, TS=35928 */
1251 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001252 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001253 /* RTP: SeqNo=21, TS=36088 */
1254 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001255 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001256 /* Repeat last packet */
1257 /* RTP: SeqNo=21, TS=36088 */
1258 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\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=22, TS=36248 */
1261 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001262 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001263 /* RTP: SeqNo=23, TS=36408 */
1264 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001265 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001266 /* Don't increment SeqNo but increment timestamp by 160 */
1267 /* RTP: SeqNo=23, TS=36568 */
1268 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\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=24, TS=36728 */
1271 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001272 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001273 /* RTP: SeqNo=25, TS=36888 */
1274 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001275 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001276 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1277 * SeqNo jump */
1278 /* RTP: SeqNo=1000, TS=160000 */
1279 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001280 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001281 /* RTP: SeqNo=1001, TS=160160 */
1282 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001283 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001284 /* RTP: SeqNo=1002, TS=160320 */
1285 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001286 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001287 /* RTP: SeqNo=1003, TS=180320, Marker */
1288 {2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
1289 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1290 /* RTP: SeqNo=1004, TS=180480 */
1291 {2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
1292 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1293 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
1294 {2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
1295 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001296};
1297
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001298static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1299{
1300 int i;
1301
Philipp Maier124a3e02021-07-26 11:17:15 +02001302 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001303 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001304 struct mgcp_endpoint *endpoints[1];
Philipp Maier124a3e02021-07-26 11:17:15 +02001305 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001306 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001307 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001308 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001309 uint32_t last_ssrc = 0;
1310 uint32_t last_timestamp = 0;
1311 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001312 uint64_t last_in_ts_err_cnt = 0;
1313 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001314 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001315 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001316 struct rate_ctr test_ctr_in;
1317 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001318
1319 printf("Testing packet error detection%s%s.\n",
1320 patch_ssrc ? ", patch SSRC" : "",
1321 patch_ts ? ", patch timestamps" : "");
1322
Philipp Maier124a3e02021-07-26 11:17:15 +02001323 cfg = mgcp_config_alloc();
1324 trunk = mgcp_trunk_alloc(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001325 memset(&endp, 0, sizeof(endp));
1326 memset(&state, 0, sizeof(state));
1327
Philipp Maier9e1d1642018-05-09 16:26:34 +02001328 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1329 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1330 state.in_stream.err_ts_ctr = &test_ctr_in;
1331 state.out_stream.err_ts_ctr = &test_ctr_out;
1332
Philipp Maier124a3e02021-07-26 11:17:15 +02001333 endp.cfg = cfg;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001334 endp.type = &ep_typeset.rtp;
1335
Philipp Maier124a3e02021-07-26 11:17:15 +02001336 trunk->v.vty_number_endpoints = 1;
1337 trunk->endpoints = endpoints;
1338 trunk->endpoints[0] = &endp;
1339 trunk->force_constant_ssrc = patch_ssrc;
1340 trunk->force_aligned_timing = patch_ts;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001341
Philipp Maier124a3e02021-07-26 11:17:15 +02001342 endp.trunk = trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001343
Philipp Maier87bd9be2017-08-22 16:35:41 +02001344 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001345 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1346 "test-connection");
1347 OSMO_ASSERT(_conn);
1348 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001349 OSMO_ASSERT(conn);
1350
1351 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001352
Philipp Maier228e5912019-03-05 13:56:59 +01001353 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001354 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001355
1356 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1357 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001358 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001359
1360 force_monotonic_time_us = round(1000000.0 * info->txtime);
1361
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001362 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001363 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001364 msg->l3h = msgb_put(msg, info->len);
1365 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001366 mgcp_rtp_end_config(&endp, 1, rtp);
1367
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001368 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001369
1370 if (state.out_stream.ssrc != last_ssrc) {
1371 printf("Output SSRC changed to %08x\n",
1372 state.out_stream.ssrc);
1373 last_ssrc = state.out_stream.ssrc;
1374 }
1375
1376 printf("In TS: %d, dTS: %d, Seq: %d\n",
1377 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001378 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001379
1380 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001381 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001382 state.out_stream.last_timestamp - last_timestamp,
1383 state.out_stream.last_tsdelta,
1384 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001385 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1386 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001387
1388 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001389 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001390
Philipp Maier9e1d1642018-05-09 16:26:34 +02001391 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1392 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001393 last_timestamp = state.out_stream.last_timestamp;
1394 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001395
1396 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001397 }
1398
1399 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001400 mgcp_conn_free_all(&endp);
Philipp Maier124a3e02021-07-26 11:17:15 +02001401 talloc_free(trunk);
1402 talloc_free(cfg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001403}
1404
1405static void test_multilple_codec(void)
1406{
1407 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001408 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001409 struct mgcp_endpoint *endp;
1410 struct msgb *inp, *resp;
1411 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001412 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001413 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001414
1415 printf("Testing multiple payload types\n");
1416
1417 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001418 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001419 trunk->v.vty_number_endpoints = 64;
1420 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001421 cfg->policy_cb = mgcp_test_policy_cb;
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001422
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001423 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001424 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001425 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001426 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001427 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1428 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001429 msgb_free(inp);
1430 msgb_free(resp);
1431
Philipp Maier37a808c2020-07-03 15:48:31 +02001432 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1433 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1434 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001435 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001436 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001437 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001438
1439 /* Allocate 2@mgw with three codecs, last one ignored */
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_2, 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/2@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
Philipp Maierbc0346e2018-06-07 09:52:16 +02001455 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1456 /* Note: It usually makes no sense to leave the payload type list
1457 * out. However RFC 2327 does not clearly forbid this case and
1458 * it makes and since we already decided in OS#2658 that a missing
1459 * LCO should pick a sane default codec, it makes sense to expect
1460 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001461 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001462 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001463 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001464 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1465 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001466 msgb_free(inp);
1467 msgb_free(resp);
1468
Philipp Maier37a808c2020-07-03 15:48:31 +02001469 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1470 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1471 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001472 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001473 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001474 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001475
1476 /* Allocate 4@mgw with a single codec */
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_4, 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/4@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 == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001491
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001492 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
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_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001495 trunk->no_audio_transcoding = 1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001496 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001497 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1498 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001499 msgb_free(inp);
1500 msgb_free(resp);
1501
Philipp Maier37a808c2020-07-03 15:48:31 +02001502 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1503 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1504 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001505 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001506 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001507 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001508
Philipp Maierffd75e42017-11-22 11:44:50 +01001509 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001510 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001511 resp = mgcp_handle_message(cfg, inp);
1512 msgb_free(inp);
1513 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001514 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1515 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1516 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001517 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001518 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001519 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001520 OSMO_ASSERT(conn->end.rtp_port == htons(16434));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001521 memset(&addr, 0, sizeof(addr));
1522 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001523 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1524 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001525
1526 /* Check what happens without that flag */
1527
Philipp Maier87bd9be2017-08-22 16:35:41 +02001528 /* Free the previous endpoint and the data and
1529 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001530 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001531 talloc_free(endp->last_response);
1532 talloc_free(endp->last_trans);
1533 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001534 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001535 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001536
Philipp Maier37a808c2020-07-03 15:48:31 +02001537 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001538 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001539 trunk->no_audio_transcoding = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001540 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001541 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1542 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001543 msgb_free(inp);
1544 msgb_free(resp);
1545
Philipp Maier37a808c2020-07-03 15:48:31 +02001546 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1547 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1548 OSMO_ASSERT(endp);
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);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001551 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001552
Philipp Maierd19de2e2020-06-03 13:55:33 +02001553 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001554 talloc_free(cfg);
1555}
1556
1557static void test_no_cycle(void)
1558{
1559 struct mgcp_config *cfg;
1560 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001561 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001562 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001563 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001564
1565 printf("Testing no sequence flow on initial packet\n");
1566
1567 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001568 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001569 trunk->v.vty_number_endpoints = 64;
1570 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001571
Philipp Maier37a808c2020-07-03 15:48:31 +02001572 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1573 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001574
Philipp Maierffd75e42017-11-22 11:44:50 +01001575 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1576 "test-connection");
1577 OSMO_ASSERT(_conn);
1578 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001579 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001580
Harald Welte49e3d5a2017-12-25 09:47:57 +01001581 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001582
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001583 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001584 OSMO_ASSERT(conn->state.stats.initialized == 1);
1585 OSMO_ASSERT(conn->state.stats.cycles == 0);
1586 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001587
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001588 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001589 OSMO_ASSERT(conn->state.stats.initialized == 1);
1590 OSMO_ASSERT(conn->state.stats.cycles == 0);
1591 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001592
1593 /* now jump.. */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001594 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001595 OSMO_ASSERT(conn->state.stats.initialized == 1);
1596 OSMO_ASSERT(conn->state.stats.cycles == 0);
1597 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001598
1599 /* and wrap */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001600 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001601 OSMO_ASSERT(conn->state.stats.initialized == 1);
1602 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1603 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001604
Philipp Maierd19de2e2020-06-03 13:55:33 +02001605 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001606 talloc_free(cfg);
1607}
1608
1609static void test_no_name(void)
1610{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001611 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001612 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001613 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001614
1615 printf("Testing no rtpmap name\n");
1616 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001617 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001618
Philipp Maier889fe7f2020-07-06 17:44:12 +02001619 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001620 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001621 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001622
1623 cfg->policy_cb = mgcp_test_policy_cb;
1624
Philipp Maierffd75e42017-11-22 11:44:50 +01001625 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001626 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001627
1628 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001629 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001630 (char *)msg->data);
1631 OSMO_ASSERT(false);
1632 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001633 msgb_free(inp);
1634 msgb_free(msg);
1635
Philipp Maierd19de2e2020-06-03 13:55:33 +02001636 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001637 talloc_free(cfg);
1638}
1639
1640static void test_osmux_cid(void)
1641{
1642 int id, i;
1643
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001644 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1645
1646 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001647 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001648 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1649
1650 osmux_cid_pool_get(30);
1651 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1652 osmux_cid_pool_get(30);
1653 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1654
1655 osmux_cid_pool_put(id);
1656 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1657 osmux_cid_pool_put(30);
1658 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001659
1660 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001661 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001662 OSMO_ASSERT(id == i);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001663 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001664 }
1665
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001666 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001667 OSMO_ASSERT(id == -1);
1668
1669 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001670 osmux_cid_pool_put(i);
1671 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001672}
1673
1674static const struct log_info_cat log_categories[] = {
1675};
1676
1677const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001678 .cat = log_categories,
1679 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001680};
1681
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001682static void test_get_lco_identifier(void)
1683{
1684 char *test;
1685 printf("Testing get_lco_identifier()\n");
1686
1687 /* Normal case at the beginning */
1688 test = "p:10, a:PCMU";
1689 printf("%s -> %s\n", test, get_lco_identifier(test));
1690
1691 test = "p:10, a:PCMU";
1692 printf("%s -> %s\n", test, get_lco_identifier(test));
1693
1694 /* Begin parsing in the middle of the value part of
1695 * the previous LCO option value */
1696 test = "XXXX, p:10, a:PCMU";
1697 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1698
1699 test = "XXXX,p:10,a:PCMU";
1700 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1701
1702 test = "10,a:PCMU";
1703 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1704
1705 test = "10, a:PCMU";
1706 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1707
1708 test = "10,a: PCMU";
1709 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1710
1711 test = "10 ,a: PCMU";
1712 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1713
1714 /* Begin parsing right at the end of the previous LCO
1715 * option value */
1716 test = ", a:PCMU";
1717 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1718
1719 test = " a:PCMU";
1720 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1721
1722 /* Empty string, result should be (null) */
1723 test = "";
1724 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1725
1726 /* Missing colons, result should be (null) */
1727 test = "p10, aPCMU";
1728 printf("%s -> %s\n", test, get_lco_identifier(test));
1729
1730 /* Colon separated from the identifier, result should be (null) */
1731 test = "10,a :PCMU";
1732 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1733}
1734
1735static void test_check_local_cx_options(void *ctx)
1736{
1737 /* Legal cases */
1738 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1739 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1740 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1741 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1742 0);
1743 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1744 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1745 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1746 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1747 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1748
1749 /* Illegal spaces before and after colon */
1750 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1751 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1752 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1753
1754 /* Check if multiple appearances of LCOs are rejected */
1755 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1756 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1757 -1);
1758 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1759
1760 /* Check if empty LCO are rejected */
1761 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1762 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1763 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1764 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1765 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1766
1767 /* Garbeled beginning and ends */
1768 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1769 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1770 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1771 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1772 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1773 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1774
1775 /* Illegal strings */
1776 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1777 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1778 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1779 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1780 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1781 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1782}
1783
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001784static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1785 .amr_octet_aligned_present = true,
1786 .amr_octet_aligned = true,
1787};
1788
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001789static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1790 .amr_octet_aligned_present = true,
1791 .amr_octet_aligned = false,
1792};
1793
1794static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1795 .amr_octet_aligned_present = false,
1796};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001797
1798struct testcase_mgcp_codec_pt_translate_codec {
1799 int payload_type;
1800 const char *audio_name;
1801 const struct mgcp_codec_param *param;
1802 int expect_rc;
1803};
1804
1805struct testcase_mgcp_codec_pt_translate_expect {
1806 bool end;
1807 int payload_type_map[2];
1808};
1809
1810struct testcase_mgcp_codec_pt_translate {
1811 const char *descr;
1812 /* two conns on an endpoint, each with N configured codecs */
1813 struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
1814 struct testcase_mgcp_codec_pt_translate_expect expect[32];
1815};
1816
1817static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
1818 {
1819 .descr = "same order, but differing payload type numbers",
1820 .codecs = {
1821 {
1822 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1823 { 0, "PCMU/8000/1", NULL, },
1824 { 111, "GSM-HR-08/8000/1", NULL, },
1825 },
1826 {
1827 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1828 { 0, "PCMU/8000/1", NULL, },
1829 { 97, "GSM-HR-08/8000/1", NULL, },
1830 },
1831 },
1832 .expect = {
1833 { .payload_type_map = {112, 96}, },
1834 { .payload_type_map = {0, 0}, },
1835 { .payload_type_map = {111, 97} },
1836 { .payload_type_map = {123, -EINVAL} },
1837 { .end = true },
1838 },
1839 },
1840 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001841 .descr = "different order and different payload type numbers",
1842 .codecs = {
1843 {
1844 { 0, "PCMU/8000/1", NULL, },
1845 { 111, "GSM-HR-08/8000/1", NULL, },
1846 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1847 },
1848 {
1849 { 97, "GSM-HR-08/8000/1", NULL, },
1850 { 0, "PCMU/8000/1", NULL, },
1851 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1852 },
1853 },
1854 .expect = {
1855 { .payload_type_map = {112, 96}, },
1856 { .payload_type_map = {0, 0}, },
1857 { .payload_type_map = {111, 97} },
1858 { .payload_type_map = {123, -EINVAL} },
1859 { .end = true },
1860 },
1861 },
1862 {
1863 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1864 .codecs = {
1865 {
1866 { 0, "PCMU/8000/1", NULL, },
1867 { 96, "GSM-HR-08/8000/1", NULL, },
1868 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1869 },
1870 {
1871 { 97, "GSM-HR-08/8000/1", NULL, },
1872 { 0, "PCMU/8000/1", NULL, },
1873 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1874 },
1875 },
1876 .expect = {
1877 { .payload_type_map = {96, 97}, },
1878 { .payload_type_map = {97, 96}, },
1879 { .payload_type_map = {0, 0}, },
1880 { .end = true },
1881 },
1882 },
1883 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001884 .descr = "conn0 has no codecs",
1885 .codecs = {
1886 {
1887 /* no codecs */
1888 },
1889 {
1890 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1891 { 0, "PCMU/8000/1", NULL, },
1892 { 97, "GSM-HR-08/8000/1", NULL, },
1893 },
1894 },
1895 .expect = {
1896 { .payload_type_map = {112, -EINVAL}, },
1897 { .payload_type_map = {0, -EINVAL}, },
1898 { .payload_type_map = {111, -EINVAL} },
1899 { .end = true },
1900 },
1901 },
1902 {
1903 .descr = "conn1 has no codecs",
1904 .codecs = {
1905 {
1906 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1907 { 0, "PCMU/8000/1", NULL, },
1908 { 111, "GSM-HR-08/8000/1", NULL, },
1909 },
1910 {
1911 /* no codecs */
1912 },
1913 },
1914 .expect = {
1915 { .payload_type_map = {112, -EINVAL}, },
1916 { .payload_type_map = {0, -EINVAL}, },
1917 { .payload_type_map = {111, -EINVAL} },
1918 { .end = true },
1919 },
1920 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001921 {
1922 .descr = "test AMR with differing octet-aligned settings",
1923 .codecs = {
1924 {
1925 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1926 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1927 },
1928 {
1929 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1930 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1931 },
1932 },
1933 .expect = {
1934 { .payload_type_map = {111, 121}, },
1935 { .payload_type_map = {112, 122} },
1936 { .end = true },
1937 },
1938 },
1939 {
1940 .descr = "test AMR with missing octet-aligned settings (defaults to 0)",
1941 .codecs = {
1942 {
1943 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1944 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1945 },
1946 {
1947 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1948 },
1949 },
1950 .expect = {
1951 { .payload_type_map = {111, -EINVAL}, },
1952 { .payload_type_map = {112, 122} },
1953 { .end = true },
1954 },
1955 },
1956 {
1957 .descr = "test AMR with NULL param (defaults to 0)",
1958 .codecs = {
1959 {
1960 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1961 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1962 },
1963 {
1964 { 122, "AMR/8000", NULL, },
1965 },
1966 },
1967 .expect = {
1968 { .payload_type_map = {111, -EINVAL}, },
1969 { .payload_type_map = {112, 122} },
1970 { .end = true },
1971 },
1972 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02001973 {
1974 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
1975 .codecs = {
1976 {
1977 { 0, "PCMU/8000/1", NULL, },
1978 { 111, "GSM-HR-08/8000/1", NULL, },
1979 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1980 },
1981 {
1982 { 97, "GSM-HR-08/8000", NULL, },
1983 { 0, "PCMU/8000", NULL, },
1984 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
1985 },
1986 },
1987 .expect = {
1988 { .payload_type_map = {112, 96}, },
1989 { .payload_type_map = {0, 0}, },
1990 { .payload_type_map = {111, 97} },
1991 { .payload_type_map = {123, -EINVAL} },
1992 { .end = true },
1993 },
1994 },
1995 {
1996 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
1997 .codecs = {
1998 {
1999 { 0, "PCMU/8000/1", NULL, },
2000 { 111, "GSM-HR-08/8000/1", NULL, },
2001 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
2002 },
2003 {
2004 { 97, "GSM-HR-08", NULL, },
2005 { 0, "PCMU", NULL, },
2006 { 96, "AMR", &amr_param_octet_aligned_true, },
2007 },
2008 },
2009 .expect = {
2010 { .payload_type_map = {112, 96}, },
2011 { .payload_type_map = {0, 0}, },
2012 { .payload_type_map = {111, 97} },
2013 { .payload_type_map = {123, -EINVAL} },
2014 { .end = true },
2015 },
2016 },
2017 {
2018 .descr = "test whether channel number matching is waterproof",
2019 .codecs = {
2020 {
2021 { 111, "GSM-HR-08/8000", },
2022 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
2023 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
2024 },
2025 {
2026 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
2027 { 121, "GSM-HR-08/8000/1", },
2028 },
2029 },
2030 .expect = {
2031 { .payload_type_map = {111, 121}, },
2032 { .payload_type_map = {112, -EINVAL} },
2033 { .payload_type_map = {113, -EINVAL} },
2034 { .end = true },
2035 },
2036 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002037};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002038
2039static void test_mgcp_codec_pt_translate(void)
2040{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002041 int i;
2042 bool ok = true;
2043 printf("\nTesting mgcp_codec_pt_translate()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002044
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002045 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
2046 const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
2047 struct mgcp_conn_rtp conn[2] = {};
2048 int rc;
2049 int conn_i;
2050 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002051
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002052 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002053
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002054 for (conn_i = 0; conn_i < 2; conn_i++) {
2055 printf(" - add codecs on conn%d:\n", conn_i);
2056 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
2057 const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
2058 if (!codec->audio_name)
2059 break;
2060
2061 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
2062
2063 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2064 codec->param ?
2065 (codec->param->amr_octet_aligned_present?
2066 (codec->param->amr_octet_aligned ?
2067 " octet-aligned=1" : " octet-aligned=0")
2068 : " octet-aligned=unset")
2069 : "",
2070 rc);
2071 if (rc != codec->expect_rc) {
2072 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2073 ok = false;
2074 }
2075 }
2076 if (!c)
2077 printf(" (none)\n");
2078 }
2079
2080 for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
2081 const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
2082 int result;
2083
2084 if (expect->end)
2085 break;
2086
2087 result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
2088 printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
2089 expect->payload_type_map[0], result);
2090 if (result != expect->payload_type_map[1]) {
2091 printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
2092 ok = false;
2093 }
2094
2095 /* If the expected result is an error, don't do reverse map test */
2096 if (expect->payload_type_map[1] < 0)
2097 continue;
2098
2099 result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
2100 printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
2101 expect->payload_type_map[1], result);
2102 if (result != expect->payload_type_map[0]) {
2103 printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
2104 ok = false;
2105 }
2106 }
2107
2108 for (conn_i = 0; conn_i < 2; conn_i++)
2109 mgcp_codec_reset_all(&conn[conn_i]);
2110 }
2111
2112 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002113}
2114
Neels Hofmeyr65317262018-09-03 22:11:05 +02002115void test_conn_id_matching()
2116{
2117 struct mgcp_endpoint endp = {};
2118 struct mgcp_conn *conn;
2119 struct mgcp_conn *conn_match;
2120 int i;
2121 const char *conn_id_generated = "000023AB";
2122 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002123 "23AB",
2124 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002125 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002126 "00000023AB",
2127 "23ab",
2128 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002129 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002130 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002131 };
2132
2133 printf("\nTesting %s\n", __func__);
2134
2135 INIT_LLIST_HEAD(&endp.conns);
2136
2137 conn = talloc_zero(NULL, struct mgcp_conn);
2138 OSMO_ASSERT(conn);
2139 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2140 llist_add(&conn->entry, &endp.conns);
2141
2142 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2143 const char *needle = conn_id_request[i];
2144 printf("needle='%s' ", needle);
2145 conn_match = mgcp_conn_get(&endp, needle);
2146 OSMO_ASSERT(conn_match);
2147 printf("found '%s'\n", conn_match->id);
2148 OSMO_ASSERT(conn_match == conn);
2149 }
2150
2151 llist_del(&conn->entry);
2152 talloc_free(conn);
2153}
2154
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002155void test_e1_trunk_nr_from_epname()
2156{
Philipp Maierd70eef62021-07-19 13:53:28 +02002157 unsigned int trunk_nr;
2158 int rc;
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002159
2160 /* Note: e1_trunk_nr_from_epname does not check the text
2161 * after the E1 trunk number, after the delimiter
2162 * character "/" arbitrary text may follow. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002163 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-0/s-1/su16-0");
Philipp Maier0653cc82020-08-10 22:52:51 +02002164 OSMO_ASSERT(trunk_nr == 0);
Philipp Maierd70eef62021-07-19 13:53:28 +02002165 OSMO_ASSERT(rc == 0);
2166 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-1/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002167 OSMO_ASSERT(trunk_nr == 1);
Philipp Maierd70eef62021-07-19 13:53:28 +02002168 OSMO_ASSERT(rc == 0);
2169 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-2/s-2/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002170 OSMO_ASSERT(trunk_nr == 2);
Philipp Maierd70eef62021-07-19 13:53:28 +02002171 OSMO_ASSERT(rc == 0);
2172 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/s-23/su32-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002173 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002174 OSMO_ASSERT(rc == 0);
2175 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-3/xxxxxxx");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002176 OSMO_ASSERT(trunk_nr == 3);
Philipp Maierd70eef62021-07-19 13:53:28 +02002177 OSMO_ASSERT(rc == 0);
2178 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002179 OSMO_ASSERT(trunk_nr == 24);
Philipp Maierd70eef62021-07-19 13:53:28 +02002180 OSMO_ASSERT(rc == 0);
2181 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-64/s-1/su16-0");
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002182 OSMO_ASSERT(trunk_nr == 64);
Philipp Maierd70eef62021-07-19 13:53:28 +02002183 OSMO_ASSERT(rc == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002184
2185 /* The following endpoint strings should fail, either the
2186 * trunk number exceeds the valid range or the trunk prefix
2187 * is wrong. Also when the delimiter character "/" at the
2188 * end of the trunk is wrong the parsing should fail. */
Philipp Maierd70eef62021-07-19 13:53:28 +02002189 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-65/s-1/su16-0");
2190 OSMO_ASSERT(rc == -EINVAL);
2191 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1--1/s-1/su16-0");
2192 OSMO_ASSERT(rc == -EINVAL);
2193 rc = e1_trunk_nr_from_epname(&trunk_nr, "xxxxxx4zyz");
2194 OSMO_ASSERT(rc == -EINVAL);
2195 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1+2/s-1/su16-0");
2196 OSMO_ASSERT(rc == -EINVAL);
2197 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e2-24/s-1/su16-0");
2198 OSMO_ASSERT(rc == -EINVAL);
2199 rc = e1_trunk_nr_from_epname(&trunk_nr, "ds/e1-24s-1/su16-0");
2200 OSMO_ASSERT(rc == -EINVAL);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002201
2202 return;
2203}
2204
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002205void test_mgcp_is_rtp_dummy_payload()
2206{
2207 /* realistic rtp packet */
2208 static const char rtp_payload[] =
2209 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2210 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2211 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2212 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2213 0x24 };
2214
2215 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2216 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2217 struct msgb *msg_dummy_rtp =
2218 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2219
2220 uint8_t *buf;
2221
2222 /* Dummy RTP packet */
2223 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2224 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2225
2226 /* Normal RTP packet */
2227 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2228 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2229
2230 /* Dummy RTP packet with normal RTP packet attached, this must not be
2231 * recognized as Dummy RTP packet */
2232 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2233 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2234 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2235 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2236
2237 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2238 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2239 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2240
2241 msgb_free(msg_dummy);
2242 msgb_free(msg_rtp);
2243 msgb_free(msg_dummy_rtp);
2244}
2245
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002246int main(int argc, char **argv)
2247{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002248 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2249 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2250 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002251
2252 test_strline();
2253 test_values();
2254 test_messages();
2255 test_retransmission();
2256 test_packet_loss_calc();
2257 test_rqnt_cb();
2258 test_mgcp_stats();
2259 test_packet_error_detection(1, 0);
2260 test_packet_error_detection(0, 0);
2261 test_packet_error_detection(0, 1);
2262 test_packet_error_detection(1, 1);
2263 test_multilple_codec();
2264 test_no_cycle();
2265 test_no_name();
2266 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002267 test_get_lco_identifier();
2268 test_check_local_cx_options(ctx);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002269 test_mgcp_codec_pt_translate();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002270 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002271 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002272 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002273
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002274 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2275 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2276 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002277 printf("Done\n");
2278 return EXIT_SUCCESS;
2279}