blob: 7397f5cf2074088cc215e3efc89db876bd26a2f6 [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];
Oliver Smithe36b7752019-01-22 16:31:36 +01001068 struct mgcp_config cfg = {0};
Philipp Maier14b27a82020-06-02 20:15:30 +02001069 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));
1074 memset(&trunk, 0, sizeof(trunk));
1075
Oliver Smithe36b7752019-01-22 16:31:36 +01001076 endp.cfg = &cfg;
Philipp Maiercede2a42018-07-03 14:14:21 +02001077 endp.type = &ep_typeset.rtp;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001078 trunk.v.vty_number_endpoints = 1;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001079 trunk.endpoints = endpoints;
1080 trunk.endpoints[0] = &endp;
Philipp Maier14b27a82020-06-02 20:15:30 +02001081 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
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001119}
1120
Philipp Maier87bd9be2017-08-22 16:35:41 +02001121int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1122 uint32_t *pr, uint32_t *_or, int *loss,
1123 uint32_t *jitter)
1124{
1125 char *line, *save;
1126 int rc;
1127
1128 /* initialize with bad values */
1129 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1130 *loss = INT_MAX;
1131
1132 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1133 if (!line)
1134 return -1;
1135
1136 /* this can only parse the message that is created above... */
1137 for_each_non_empty_line(line, save) {
1138 switch (line[0]) {
1139 case 'P':
1140 rc = sscanf(line,
1141 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1142 ps, os, pr, _or, loss, jitter);
1143 return rc == 6 ? 0 : -1;
1144 }
1145 }
1146
1147 return -1;
1148}
1149
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001150static void test_mgcp_stats(void)
1151{
1152 printf("Testing stat parsing\n");
1153
1154 uint32_t bps, bos, pr, _or, jitter;
1155 struct msgb *msg;
1156 int loss;
1157 int rc;
1158
Philipp Maierffd75e42017-11-22 11:44:50 +01001159 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001160 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1161 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001162 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1163 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001164 printf("FAIL: Parsing failed1.\n");
1165 msgb_free(msg);
1166
Philipp Maier87bd9be2017-08-22 16:35:41 +02001167 msg =
1168 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001169 ("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 +02001170 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1171 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001172 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1173 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001174 printf("FAIL: Parsing failed2.\n");
1175 msgb_free(msg);
1176}
1177
1178struct rtp_packet_info {
1179 float txtime;
1180 int len;
1181 char *data;
1182};
1183
1184struct rtp_packet_info test_rtp_packets1[] = {
1185 /* RTP: SeqNo=0, TS=0 */
1186 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001187 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001188 /* RTP: SeqNo=1, TS=160 */
1189 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001190 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001191 /* RTP: SeqNo=2, TS=320 */
1192 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001193 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001194 /* Repeat RTP timestamp: */
1195 /* RTP: SeqNo=3, TS=320 */
1196 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001197 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001198 /* RTP: SeqNo=4, TS=480 */
1199 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001200 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001201 /* RTP: SeqNo=5, TS=640 */
1202 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001203 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001204 /* Double skip RTP timestamp (delta = 2*160): */
1205 /* RTP: SeqNo=6, TS=960 */
1206 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001207 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001208 /* RTP: SeqNo=7, TS=1120 */
1209 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001210 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001211 /* RTP: SeqNo=8, TS=1280 */
1212 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001213 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001214 /* Non 20ms RTP timestamp (delta = 120): */
1215 /* RTP: SeqNo=9, TS=1400 */
1216 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001217 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001218 /* RTP: SeqNo=10, TS=1560 */
1219 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001220 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001221 /* RTP: SeqNo=11, TS=1720 */
1222 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001223 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001224 /* SSRC changed to 0x10203040, RTP timestamp jump */
1225 /* RTP: SeqNo=12, TS=34688 */
1226 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001227 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001228 /* RTP: SeqNo=13, TS=34848 */
1229 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001230 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001231 /* RTP: SeqNo=14, TS=35008 */
1232 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001233 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001234 /* Non 20ms RTP timestamp (delta = 120): */
1235 /* RTP: SeqNo=15, TS=35128 */
1236 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001237 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001238 /* RTP: SeqNo=16, TS=35288 */
1239 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001240 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001241 /* RTP: SeqNo=17, TS=35448 */
1242 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001243 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001244 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1245 /* RTP: SeqNo=19, TS=35768 */
1246 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001247 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001248 /* RTP: SeqNo=20, TS=35928 */
1249 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001250 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001251 /* RTP: SeqNo=21, TS=36088 */
1252 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001253 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001254 /* Repeat last packet */
1255 /* RTP: SeqNo=21, TS=36088 */
1256 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001257 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001258 /* RTP: SeqNo=22, TS=36248 */
1259 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001260 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001261 /* RTP: SeqNo=23, TS=36408 */
1262 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001263 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001264 /* Don't increment SeqNo but increment timestamp by 160 */
1265 /* RTP: SeqNo=23, TS=36568 */
1266 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001267 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001268 /* RTP: SeqNo=24, TS=36728 */
1269 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001270 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001271 /* RTP: SeqNo=25, TS=36888 */
1272 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001273 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001274 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1275 * SeqNo jump */
1276 /* RTP: SeqNo=1000, TS=160000 */
1277 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001278 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001279 /* RTP: SeqNo=1001, TS=160160 */
1280 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001281 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001282 /* RTP: SeqNo=1002, TS=160320 */
1283 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001284 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001285 /* RTP: SeqNo=1003, TS=180320, Marker */
1286 {2.060000, 20, "\x80\xE2\x03\xEB\x00\x02\xC0\x60\x50\x60\x70\x80"
1287 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1288 /* RTP: SeqNo=1004, TS=180480 */
1289 {2.080000, 20, "\x80\x62\x03\xEC\x00\x02\xC1\x00\x50\x60\x70\x80"
1290 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
1291 /* RTP: SeqNo=1005, TS=180480, 10ms too late */
1292 {2.110000, 20, "\x80\x62\x03\xED\x00\x02\xC1\xA0\x50\x60\x70\x80"
1293 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001294};
1295
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001296static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1297{
1298 int i;
1299
Philipp Maier14b27a82020-06-02 20:15:30 +02001300 struct mgcp_trunk trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001301 struct mgcp_endpoint endp;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001302 struct mgcp_endpoint *endpoints[1];
Oliver Smithe36b7752019-01-22 16:31:36 +01001303 struct mgcp_config cfg = {0};
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001304 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001305 struct mgcp_rtp_end *rtp;
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001306 struct osmo_sockaddr addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001307 uint32_t last_ssrc = 0;
1308 uint32_t last_timestamp = 0;
1309 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001310 uint64_t last_in_ts_err_cnt = 0;
1311 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001312 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001313 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001314 struct rate_ctr test_ctr_in;
1315 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001316
1317 printf("Testing packet error detection%s%s.\n",
1318 patch_ssrc ? ", patch SSRC" : "",
1319 patch_ts ? ", patch timestamps" : "");
1320
1321 memset(&trunk, 0, sizeof(trunk));
1322 memset(&endp, 0, sizeof(endp));
1323 memset(&state, 0, sizeof(state));
1324
Philipp Maier9e1d1642018-05-09 16:26:34 +02001325 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1326 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1327 state.in_stream.err_ts_ctr = &test_ctr_in;
1328 state.out_stream.err_ts_ctr = &test_ctr_out;
1329
Oliver Smithe36b7752019-01-22 16:31:36 +01001330 endp.cfg = &cfg;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001331 endp.type = &ep_typeset.rtp;
1332
Philipp Maier889fe7f2020-07-06 17:44:12 +02001333 trunk.v.vty_number_endpoints = 1;
Philipp Maierc66ab2c2020-06-02 20:55:34 +02001334 trunk.endpoints = endpoints;
1335 trunk.endpoints[0] = &endp;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001336 trunk.force_constant_ssrc = patch_ssrc;
1337 trunk.force_aligned_timing = patch_ts;
1338
Philipp Maier14b27a82020-06-02 20:15:30 +02001339 endp.trunk = &trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001340
Philipp Maier87bd9be2017-08-22 16:35:41 +02001341 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001342 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1343 "test-connection");
1344 OSMO_ASSERT(_conn);
1345 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001346 OSMO_ASSERT(conn);
1347
1348 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001349
Philipp Maier228e5912019-03-05 13:56:59 +01001350 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001351 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001352
1353 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1354 struct rtp_packet_info *info = test_rtp_packets1 + i;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001355 struct msgb *msg = msgb_alloc(4096, __func__);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001356
1357 force_monotonic_time_us = round(1000000.0 * info->txtime);
1358
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001359 OSMO_ASSERT(info->len <= msgb_tailroom(msg));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001360 OSMO_ASSERT(info->len >= 0);
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001361 msg->l3h = msgb_put(msg, info->len);
1362 memcpy((char*)msgb_l3(msg), info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001363 mgcp_rtp_end_config(&endp, 1, rtp);
1364
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001365 mgcp_patch_and_count(&endp, &state, rtp, &addr, msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001366
1367 if (state.out_stream.ssrc != last_ssrc) {
1368 printf("Output SSRC changed to %08x\n",
1369 state.out_stream.ssrc);
1370 last_ssrc = state.out_stream.ssrc;
1371 }
1372
1373 printf("In TS: %d, dTS: %d, Seq: %d\n",
1374 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001375 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001376
1377 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001378 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001379 state.out_stream.last_timestamp - last_timestamp,
1380 state.out_stream.last_tsdelta,
1381 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001382 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1383 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001384
1385 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001386 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001387
Philipp Maier9e1d1642018-05-09 16:26:34 +02001388 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1389 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001390 last_timestamp = state.out_stream.last_timestamp;
1391 last_seqno = state.out_stream.last_seq;
Neels Hofmeyr51b42ff2020-06-19 01:34:42 +02001392
1393 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001394 }
1395
1396 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001397 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001398}
1399
1400static void test_multilple_codec(void)
1401{
1402 struct mgcp_config *cfg;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001403 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001404 struct mgcp_endpoint *endp;
1405 struct msgb *inp, *resp;
1406 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001407 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001408 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001409
1410 printf("Testing multiple payload types\n");
1411
1412 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001413 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001414 trunk->v.vty_number_endpoints = 64;
1415 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001416 cfg->policy_cb = mgcp_test_policy_cb;
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001417
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001418 /* Allocate endpoint 1@mgw with two codecs */
Philipp Maier37a808c2020-07-03 15:48:31 +02001419 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001420 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001421 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001422 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1423 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001424 msgb_free(inp);
1425 msgb_free(resp);
1426
Philipp Maier37a808c2020-07-03 15:48:31 +02001427 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/1@mgw") == 0);
1428 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1429 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001430 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001431 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001432 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001433
1434 /* Allocate 2@mgw with three codecs, last one ignored */
Philipp Maier37a808c2020-07-03 15:48:31 +02001435 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001436 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001437 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001438 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1439 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001440 msgb_free(inp);
1441 msgb_free(resp);
1442
Philipp Maier37a808c2020-07-03 15:48:31 +02001443 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/2@mgw") == 0);
1444 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1445 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001446 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001447 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001448 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001449
Philipp Maierbc0346e2018-06-07 09:52:16 +02001450 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1451 /* Note: It usually makes no sense to leave the payload type list
1452 * out. However RFC 2327 does not clearly forbid this case and
1453 * it makes and since we already decided in OS#2658 that a missing
1454 * LCO should pick a sane default codec, it makes sense to expect
1455 * the same behaviour if SDP lacks proper payload type information */
Philipp Maier37a808c2020-07-03 15:48:31 +02001456 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001457 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001458 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001459 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1460 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001461 msgb_free(inp);
1462 msgb_free(resp);
1463
Philipp Maier37a808c2020-07-03 15:48:31 +02001464 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/3@mgw") == 0);
1465 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1466 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001467 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001468 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001469 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001470
1471 /* Allocate 4@mgw with a single codec */
Philipp Maier37a808c2020-07-03 15:48:31 +02001472 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001473 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001474 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001475 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1476 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001477 msgb_free(inp);
1478 msgb_free(resp);
1479
Philipp Maier37a808c2020-07-03 15:48:31 +02001480 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/4@mgw") == 0);
1481 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1482 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001483 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001484 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001485 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001486
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001487 /* Allocate 5@mgw and let osmo-mgw pick a codec from the list */
Philipp Maier37a808c2020-07-03 15:48:31 +02001488 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001489 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001490 trunk->no_audio_transcoding = 1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001491 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001492 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1493 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001494 msgb_free(inp);
1495 msgb_free(resp);
1496
Philipp Maier37a808c2020-07-03 15:48:31 +02001497 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1498 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1499 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001500 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001501 OSMO_ASSERT(conn);
Philipp Maier7f90ddb2020-06-02 21:52:53 +02001502 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001503
Philipp Maierffd75e42017-11-22 11:44:50 +01001504 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Philipp Maier37a808c2020-07-03 15:48:31 +02001505 last_endpoint[0] = '\0';
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001506 resp = mgcp_handle_message(cfg, inp);
1507 msgb_free(inp);
1508 msgb_free(resp);
Philipp Maier37a808c2020-07-03 15:48:31 +02001509 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1510 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1511 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001512 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001513 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001514 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001515 OSMO_ASSERT(conn->end.rtp_port == htons(16434));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001516 memset(&addr, 0, sizeof(addr));
1517 inet_aton("8.8.8.8", &addr);
Pau Espin Pedrola790f0c2020-08-31 13:29:11 +02001518 OSMO_ASSERT(conn->end.addr.u.sa.sa_family == AF_INET);
1519 OSMO_ASSERT(conn->end.addr.u.sin.sin_addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001520
1521 /* Check what happens without that flag */
1522
Philipp Maier87bd9be2017-08-22 16:35:41 +02001523 /* Free the previous endpoint and the data and
1524 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001525 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001526 talloc_free(endp->last_response);
1527 talloc_free(endp->last_trans);
1528 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001529 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001530 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001531
Philipp Maier37a808c2020-07-03 15:48:31 +02001532 last_endpoint[0] = '\0';
Philipp Maierffd75e42017-11-22 11:44:50 +01001533 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Philipp Maierd19de2e2020-06-03 13:55:33 +02001534 trunk->no_audio_transcoding = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001535 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001536 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1537 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001538 msgb_free(inp);
1539 msgb_free(resp);
1540
Philipp Maier37a808c2020-07-03 15:48:31 +02001541 OSMO_ASSERT(strcmp(last_endpoint,"rtpbridge/5@mgw") == 0);
1542 endp = mgcp_endp_by_name(NULL, last_endpoint, cfg);
1543 OSMO_ASSERT(endp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001544 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001545 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001546 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001547
Philipp Maierd19de2e2020-06-03 13:55:33 +02001548 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001549 talloc_free(cfg);
1550}
1551
1552static void test_no_cycle(void)
1553{
1554 struct mgcp_config *cfg;
1555 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001556 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001557 struct mgcp_conn *_conn = NULL;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001558 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001559
1560 printf("Testing no sequence flow on initial packet\n");
1561
1562 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001563 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Philipp Maier889fe7f2020-07-06 17:44:12 +02001564 trunk->v.vty_number_endpoints = 64;
1565 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001566
Philipp Maier37a808c2020-07-03 15:48:31 +02001567 endp = mgcp_endp_by_name(NULL, "rtpbridge/1@mgw", cfg);
1568 OSMO_ASSERT(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001569
Philipp Maierffd75e42017-11-22 11:44:50 +01001570 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1571 "test-connection");
1572 OSMO_ASSERT(_conn);
1573 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001574 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001575
Harald Welte49e3d5a2017-12-25 09:47:57 +01001576 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001577
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001578 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001579 OSMO_ASSERT(conn->state.stats.initialized == 1);
1580 OSMO_ASSERT(conn->state.stats.cycles == 0);
1581 OSMO_ASSERT(conn->state.stats.max_seq == 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, 1, 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 == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001587
1588 /* now jump.. */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001589 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001590 OSMO_ASSERT(conn->state.stats.initialized == 1);
1591 OSMO_ASSERT(conn->state.stats.cycles == 0);
1592 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001593
1594 /* and wrap */
Pau Espin Pedrolb066bd02021-07-07 13:41:19 +02001595 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342, false);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001596 OSMO_ASSERT(conn->state.stats.initialized == 1);
1597 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1598 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001599
Philipp Maierd19de2e2020-06-03 13:55:33 +02001600 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001601 talloc_free(cfg);
1602}
1603
1604static void test_no_name(void)
1605{
Philipp Maierd19de2e2020-06-03 13:55:33 +02001606 struct mgcp_trunk *trunk;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001607 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001608 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001609
1610 printf("Testing no rtpmap name\n");
1611 cfg = mgcp_config_alloc();
Philipp Maier6fbbeec2020-07-01 23:00:54 +02001612 trunk = mgcp_trunk_by_num(cfg, MGCP_TRUNK_VIRTUAL, MGCP_VIRT_TRUNK_ID);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001613
Philipp Maier889fe7f2020-07-06 17:44:12 +02001614 trunk->v.vty_number_endpoints = 64;
Philipp Maierd19de2e2020-06-03 13:55:33 +02001615 trunk->audio_send_name = 0;
Philipp Maier889fe7f2020-07-06 17:44:12 +02001616 mgcp_trunk_equip(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001617
1618 cfg->policy_cb = mgcp_test_policy_cb;
1619
Philipp Maierffd75e42017-11-22 11:44:50 +01001620 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001621 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001622
1623 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001624 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001625 (char *)msg->data);
1626 OSMO_ASSERT(false);
1627 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001628 msgb_free(inp);
1629 msgb_free(msg);
1630
Philipp Maierd19de2e2020-06-03 13:55:33 +02001631 mgcp_endpoints_release(trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001632 talloc_free(cfg);
1633}
1634
1635static void test_osmux_cid(void)
1636{
1637 int id, i;
1638
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001639 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1640
1641 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001642 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001643 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1644
1645 osmux_cid_pool_get(30);
1646 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1647 osmux_cid_pool_get(30);
1648 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1649
1650 osmux_cid_pool_put(id);
1651 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1652 osmux_cid_pool_put(30);
1653 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001654
1655 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001656 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001657 OSMO_ASSERT(id == i);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001658 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001659 }
1660
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 == -1);
1663
1664 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001665 osmux_cid_pool_put(i);
1666 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001667}
1668
1669static const struct log_info_cat log_categories[] = {
1670};
1671
1672const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001673 .cat = log_categories,
1674 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001675};
1676
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001677static void test_get_lco_identifier(void)
1678{
1679 char *test;
1680 printf("Testing get_lco_identifier()\n");
1681
1682 /* Normal case at the beginning */
1683 test = "p:10, a:PCMU";
1684 printf("%s -> %s\n", test, get_lco_identifier(test));
1685
1686 test = "p:10, a:PCMU";
1687 printf("%s -> %s\n", test, get_lco_identifier(test));
1688
1689 /* Begin parsing in the middle of the value part of
1690 * the previous LCO option value */
1691 test = "XXXX, p:10, a:PCMU";
1692 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1693
1694 test = "XXXX,p:10,a:PCMU";
1695 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1696
1697 test = "10,a:PCMU";
1698 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1699
1700 test = "10, a:PCMU";
1701 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1702
1703 test = "10,a: PCMU";
1704 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1705
1706 test = "10 ,a: PCMU";
1707 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1708
1709 /* Begin parsing right at the end of the previous LCO
1710 * option value */
1711 test = ", a:PCMU";
1712 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1713
1714 test = " a:PCMU";
1715 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1716
1717 /* Empty string, result should be (null) */
1718 test = "";
1719 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1720
1721 /* Missing colons, result should be (null) */
1722 test = "p10, aPCMU";
1723 printf("%s -> %s\n", test, get_lco_identifier(test));
1724
1725 /* Colon separated from the identifier, result should be (null) */
1726 test = "10,a :PCMU";
1727 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1728}
1729
1730static void test_check_local_cx_options(void *ctx)
1731{
1732 /* Legal cases */
1733 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1734 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1735 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1736 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1737 0);
1738 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1739 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1740 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1741 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1742 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1743
1744 /* Illegal spaces before and after colon */
1745 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1746 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1747 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1748
1749 /* Check if multiple appearances of LCOs are rejected */
1750 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1751 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1752 -1);
1753 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1754
1755 /* Check if empty LCO are rejected */
1756 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1757 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1758 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1759 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1760 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1761
1762 /* Garbeled beginning and ends */
1763 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1764 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1765 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1766 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1767 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1768 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1769
1770 /* Illegal strings */
1771 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1772 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1773 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1774 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1775 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1776 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1777}
1778
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001779static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1780 .amr_octet_aligned_present = true,
1781 .amr_octet_aligned = true,
1782};
1783
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001784static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1785 .amr_octet_aligned_present = true,
1786 .amr_octet_aligned = false,
1787};
1788
1789static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1790 .amr_octet_aligned_present = false,
1791};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001792
1793struct testcase_mgcp_codec_pt_translate_codec {
1794 int payload_type;
1795 const char *audio_name;
1796 const struct mgcp_codec_param *param;
1797 int expect_rc;
1798};
1799
1800struct testcase_mgcp_codec_pt_translate_expect {
1801 bool end;
1802 int payload_type_map[2];
1803};
1804
1805struct testcase_mgcp_codec_pt_translate {
1806 const char *descr;
1807 /* two conns on an endpoint, each with N configured codecs */
1808 struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
1809 struct testcase_mgcp_codec_pt_translate_expect expect[32];
1810};
1811
1812static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
1813 {
1814 .descr = "same order, but differing payload type numbers",
1815 .codecs = {
1816 {
1817 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1818 { 0, "PCMU/8000/1", NULL, },
1819 { 111, "GSM-HR-08/8000/1", NULL, },
1820 },
1821 {
1822 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1823 { 0, "PCMU/8000/1", NULL, },
1824 { 97, "GSM-HR-08/8000/1", NULL, },
1825 },
1826 },
1827 .expect = {
1828 { .payload_type_map = {112, 96}, },
1829 { .payload_type_map = {0, 0}, },
1830 { .payload_type_map = {111, 97} },
1831 { .payload_type_map = {123, -EINVAL} },
1832 { .end = true },
1833 },
1834 },
1835 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001836 .descr = "different order and different payload type numbers",
1837 .codecs = {
1838 {
1839 { 0, "PCMU/8000/1", NULL, },
1840 { 111, "GSM-HR-08/8000/1", NULL, },
1841 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1842 },
1843 {
1844 { 97, "GSM-HR-08/8000/1", NULL, },
1845 { 0, "PCMU/8000/1", NULL, },
1846 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1847 },
1848 },
1849 .expect = {
1850 { .payload_type_map = {112, 96}, },
1851 { .payload_type_map = {0, 0}, },
1852 { .payload_type_map = {111, 97} },
1853 { .payload_type_map = {123, -EINVAL} },
1854 { .end = true },
1855 },
1856 },
1857 {
1858 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1859 .codecs = {
1860 {
1861 { 0, "PCMU/8000/1", NULL, },
1862 { 96, "GSM-HR-08/8000/1", NULL, },
1863 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1864 },
1865 {
1866 { 97, "GSM-HR-08/8000/1", NULL, },
1867 { 0, "PCMU/8000/1", NULL, },
1868 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1869 },
1870 },
1871 .expect = {
1872 { .payload_type_map = {96, 97}, },
1873 { .payload_type_map = {97, 96}, },
1874 { .payload_type_map = {0, 0}, },
1875 { .end = true },
1876 },
1877 },
1878 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001879 .descr = "conn0 has no codecs",
1880 .codecs = {
1881 {
1882 /* no codecs */
1883 },
1884 {
1885 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1886 { 0, "PCMU/8000/1", NULL, },
1887 { 97, "GSM-HR-08/8000/1", NULL, },
1888 },
1889 },
1890 .expect = {
1891 { .payload_type_map = {112, -EINVAL}, },
1892 { .payload_type_map = {0, -EINVAL}, },
1893 { .payload_type_map = {111, -EINVAL} },
1894 { .end = true },
1895 },
1896 },
1897 {
1898 .descr = "conn1 has no codecs",
1899 .codecs = {
1900 {
1901 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1902 { 0, "PCMU/8000/1", NULL, },
1903 { 111, "GSM-HR-08/8000/1", NULL, },
1904 },
1905 {
1906 /* no codecs */
1907 },
1908 },
1909 .expect = {
1910 { .payload_type_map = {112, -EINVAL}, },
1911 { .payload_type_map = {0, -EINVAL}, },
1912 { .payload_type_map = {111, -EINVAL} },
1913 { .end = true },
1914 },
1915 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001916 {
1917 .descr = "test AMR with differing octet-aligned settings",
1918 .codecs = {
1919 {
1920 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1921 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1922 },
1923 {
1924 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1925 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1926 },
1927 },
1928 .expect = {
1929 { .payload_type_map = {111, 121}, },
1930 { .payload_type_map = {112, 122} },
1931 { .end = true },
1932 },
1933 },
1934 {
1935 .descr = "test AMR with missing octet-aligned settings (defaults to 0)",
1936 .codecs = {
1937 {
1938 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1939 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1940 },
1941 {
1942 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1943 },
1944 },
1945 .expect = {
1946 { .payload_type_map = {111, -EINVAL}, },
1947 { .payload_type_map = {112, 122} },
1948 { .end = true },
1949 },
1950 },
1951 {
1952 .descr = "test AMR with NULL param (defaults to 0)",
1953 .codecs = {
1954 {
1955 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1956 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1957 },
1958 {
1959 { 122, "AMR/8000", NULL, },
1960 },
1961 },
1962 .expect = {
1963 { .payload_type_map = {111, -EINVAL}, },
1964 { .payload_type_map = {112, 122} },
1965 { .end = true },
1966 },
1967 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02001968 {
1969 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
1970 .codecs = {
1971 {
1972 { 0, "PCMU/8000/1", NULL, },
1973 { 111, "GSM-HR-08/8000/1", NULL, },
1974 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1975 },
1976 {
1977 { 97, "GSM-HR-08/8000", NULL, },
1978 { 0, "PCMU/8000", NULL, },
1979 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
1980 },
1981 },
1982 .expect = {
1983 { .payload_type_map = {112, 96}, },
1984 { .payload_type_map = {0, 0}, },
1985 { .payload_type_map = {111, 97} },
1986 { .payload_type_map = {123, -EINVAL} },
1987 { .end = true },
1988 },
1989 },
1990 {
1991 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
1992 .codecs = {
1993 {
1994 { 0, "PCMU/8000/1", NULL, },
1995 { 111, "GSM-HR-08/8000/1", NULL, },
1996 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1997 },
1998 {
1999 { 97, "GSM-HR-08", NULL, },
2000 { 0, "PCMU", NULL, },
2001 { 96, "AMR", &amr_param_octet_aligned_true, },
2002 },
2003 },
2004 .expect = {
2005 { .payload_type_map = {112, 96}, },
2006 { .payload_type_map = {0, 0}, },
2007 { .payload_type_map = {111, 97} },
2008 { .payload_type_map = {123, -EINVAL} },
2009 { .end = true },
2010 },
2011 },
2012 {
2013 .descr = "test whether channel number matching is waterproof",
2014 .codecs = {
2015 {
2016 { 111, "GSM-HR-08/8000", },
2017 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
2018 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
2019 },
2020 {
2021 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
2022 { 121, "GSM-HR-08/8000/1", },
2023 },
2024 },
2025 .expect = {
2026 { .payload_type_map = {111, 121}, },
2027 { .payload_type_map = {112, -EINVAL} },
2028 { .payload_type_map = {113, -EINVAL} },
2029 { .end = true },
2030 },
2031 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002032};
Philipp Maier6931f9a2018-07-26 09:29:31 +02002033
2034static void test_mgcp_codec_pt_translate(void)
2035{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002036 int i;
2037 bool ok = true;
2038 printf("\nTesting mgcp_codec_pt_translate()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02002039
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002040 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
2041 const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
2042 struct mgcp_conn_rtp conn[2] = {};
2043 int rc;
2044 int conn_i;
2045 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002046
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002047 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002048
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002049 for (conn_i = 0; conn_i < 2; conn_i++) {
2050 printf(" - add codecs on conn%d:\n", conn_i);
2051 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
2052 const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
2053 if (!codec->audio_name)
2054 break;
2055
2056 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
2057
2058 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2059 codec->param ?
2060 (codec->param->amr_octet_aligned_present?
2061 (codec->param->amr_octet_aligned ?
2062 " octet-aligned=1" : " octet-aligned=0")
2063 : " octet-aligned=unset")
2064 : "",
2065 rc);
2066 if (rc != codec->expect_rc) {
2067 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2068 ok = false;
2069 }
2070 }
2071 if (!c)
2072 printf(" (none)\n");
2073 }
2074
2075 for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
2076 const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
2077 int result;
2078
2079 if (expect->end)
2080 break;
2081
2082 result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
2083 printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
2084 expect->payload_type_map[0], result);
2085 if (result != expect->payload_type_map[1]) {
2086 printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
2087 ok = false;
2088 }
2089
2090 /* If the expected result is an error, don't do reverse map test */
2091 if (expect->payload_type_map[1] < 0)
2092 continue;
2093
2094 result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
2095 printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
2096 expect->payload_type_map[1], result);
2097 if (result != expect->payload_type_map[0]) {
2098 printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
2099 ok = false;
2100 }
2101 }
2102
2103 for (conn_i = 0; conn_i < 2; conn_i++)
2104 mgcp_codec_reset_all(&conn[conn_i]);
2105 }
2106
2107 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002108}
2109
Neels Hofmeyr65317262018-09-03 22:11:05 +02002110void test_conn_id_matching()
2111{
2112 struct mgcp_endpoint endp = {};
2113 struct mgcp_conn *conn;
2114 struct mgcp_conn *conn_match;
2115 int i;
2116 const char *conn_id_generated = "000023AB";
2117 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002118 "23AB",
2119 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002120 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002121 "00000023AB",
2122 "23ab",
2123 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002124 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002125 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002126 };
2127
2128 printf("\nTesting %s\n", __func__);
2129
2130 INIT_LLIST_HEAD(&endp.conns);
2131
2132 conn = talloc_zero(NULL, struct mgcp_conn);
2133 OSMO_ASSERT(conn);
2134 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2135 llist_add(&conn->entry, &endp.conns);
2136
2137 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2138 const char *needle = conn_id_request[i];
2139 printf("needle='%s' ", needle);
2140 conn_match = mgcp_conn_get(&endp, needle);
2141 OSMO_ASSERT(conn_match);
2142 printf("found '%s'\n", conn_match->id);
2143 OSMO_ASSERT(conn_match == conn);
2144 }
2145
2146 llist_del(&conn->entry);
2147 talloc_free(conn);
2148}
2149
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002150void test_e1_trunk_nr_from_epname()
2151{
2152 int trunk_nr;
2153
2154 /* Note: e1_trunk_nr_from_epname does not check the text
2155 * after the E1 trunk number, after the delimiter
2156 * character "/" arbitrary text may follow. */
Philipp Maier0653cc82020-08-10 22:52:51 +02002157 trunk_nr = e1_trunk_nr_from_epname("ds/e1-0/s-1/su16-0");
2158 OSMO_ASSERT(trunk_nr == 0);
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002159 trunk_nr = e1_trunk_nr_from_epname("ds/e1-1/s-1/su16-0");
2160 OSMO_ASSERT(trunk_nr == 1);
2161 trunk_nr = e1_trunk_nr_from_epname("ds/e1-2/s-2/su16-0");
2162 OSMO_ASSERT(trunk_nr == 2);
2163 trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/s-23/su32-0");
2164 OSMO_ASSERT(trunk_nr == 3);
2165 trunk_nr = e1_trunk_nr_from_epname("ds/e1-3/xxxxxxx");
2166 OSMO_ASSERT(trunk_nr == 3);
2167 trunk_nr = e1_trunk_nr_from_epname("ds/e1-24/s-1/su16-0");
2168 OSMO_ASSERT(trunk_nr == 24);
2169 trunk_nr = e1_trunk_nr_from_epname("ds/e1-64/s-1/su16-0");
2170 OSMO_ASSERT(trunk_nr == 64);
2171
2172 /* The following endpoint strings should fail, either the
2173 * trunk number exceeds the valid range or the trunk prefix
2174 * is wrong. Also when the delimiter character "/" at the
2175 * end of the trunk is wrong the parsing should fail. */
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002176 trunk_nr = e1_trunk_nr_from_epname("ds/e1-65/s-1/su16-0");
2177 OSMO_ASSERT(trunk_nr == -EINVAL);
2178 trunk_nr = e1_trunk_nr_from_epname("ds/e1--1/s-1/su16-0");
2179 OSMO_ASSERT(trunk_nr == -EINVAL);
2180 trunk_nr = e1_trunk_nr_from_epname("xxxxxx4zyz");
2181 OSMO_ASSERT(trunk_nr == -EINVAL);
2182 trunk_nr = e1_trunk_nr_from_epname("ds/e1+2/s-1/su16-0");
2183 OSMO_ASSERT(trunk_nr == -EINVAL);
2184 trunk_nr = e1_trunk_nr_from_epname("ds/e2-24/s-1/su16-0");
2185 OSMO_ASSERT(trunk_nr == -EINVAL);
2186 trunk_nr = e1_trunk_nr_from_epname("ds/e1-24s-1/su16-0");
2187 OSMO_ASSERT(trunk_nr == -EINVAL);
2188
2189 return;
2190}
2191
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002192void test_mgcp_is_rtp_dummy_payload()
2193{
2194 /* realistic rtp packet */
2195 static const char rtp_payload[] =
2196 { 0x80, 0x03, 0xca, 0xd7, 0x62, 0x12, 0x75, 0xc4, 0x43, 0x4b, 0x3e,
2197 0x72, 0xd2, 0x57, 0x7a, 0x1c, 0xda, 0x50, 0x00, 0x49, 0x24, 0x92,
2198 0x49, 0x24, 0x50, 0x00, 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00,
2199 0x49, 0x24, 0x92, 0x49, 0x24, 0x50, 0x00, 0x49, 0x23, 0x92, 0x49,
2200 0x24 };
2201
2202 struct msgb *msg_dummy = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy");
2203 struct msgb *msg_rtp = msgb_alloc(RTP_BUF_SIZE, "RTP-msg_rtp");
2204 struct msgb *msg_dummy_rtp =
2205 msgb_alloc(RTP_BUF_SIZE, "RTP-msg_dummy_rtp");
2206
2207 uint8_t *buf;
2208
2209 /* Dummy RTP packet */
2210 buf = msgb_put(msg_dummy, ARRAY_SIZE(rtp_dummy_payload));
2211 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2212
2213 /* Normal RTP packet */
2214 buf = msgb_put(msg_rtp, ARRAY_SIZE(rtp_payload));
2215 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2216
2217 /* Dummy RTP packet with normal RTP packet attached, this must not be
2218 * recognized as Dummy RTP packet */
2219 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_dummy_payload));
2220 memcpy(buf, rtp_dummy_payload, ARRAY_SIZE(rtp_dummy_payload));
2221 buf = msgb_put(msg_dummy_rtp, ARRAY_SIZE(rtp_payload));
2222 memcpy(buf, rtp_payload, ARRAY_SIZE(rtp_payload));
2223
2224 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy) == true);
2225 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_rtp) == false);
2226 OSMO_ASSERT(mgcp_is_rtp_dummy_payload(msg_dummy_rtp) == false);
2227
2228 msgb_free(msg_dummy);
2229 msgb_free(msg_rtp);
2230 msgb_free(msg_dummy_rtp);
2231}
2232
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002233int main(int argc, char **argv)
2234{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002235 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2236 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2237 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002238
2239 test_strline();
2240 test_values();
2241 test_messages();
2242 test_retransmission();
2243 test_packet_loss_calc();
2244 test_rqnt_cb();
2245 test_mgcp_stats();
2246 test_packet_error_detection(1, 0);
2247 test_packet_error_detection(0, 0);
2248 test_packet_error_detection(0, 1);
2249 test_packet_error_detection(1, 1);
2250 test_multilple_codec();
2251 test_no_cycle();
2252 test_no_name();
2253 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002254 test_get_lco_identifier();
2255 test_check_local_cx_options(ctx);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002256 test_mgcp_codec_pt_translate();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002257 test_conn_id_matching();
Philipp Maier7e9ddc92020-06-10 15:22:32 +02002258 test_e1_trunk_nr_from_epname();
Philipp Maierb3d14eb2021-05-20 14:18:52 +02002259 test_mgcp_is_rtp_dummy_payload();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002260
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002261 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2262 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2263 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002264 printf("Done\n");
2265 return EXIT_SUCCESS;
2266}