blob: c72382ef8e804b3300f8ec55167291550f45c661 [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 Maier87bd9be2017-08-22 16:35:41 +020025#include <osmocom/mgcp/mgcp_internal.h>
26#include <osmocom/mgcp/mgcp_stat.h>
27#include <osmocom/mgcp/mgcp_msg.h>
Philipp Maier37d11c82018-02-01 14:38:12 +010028#include <osmocom/mgcp/mgcp_endp.h>
Philipp Maierbc0346e2018-06-07 09:52:16 +020029#include <osmocom/mgcp/mgcp_sdp.h>
30#include <osmocom/mgcp/mgcp_codec.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020031
32#include <osmocom/core/application.h>
33#include <osmocom/core/talloc.h>
34#include <osmocom/core/utils.h>
35#include <string.h>
36#include <limits.h>
37#include <dlfcn.h>
38#include <time.h>
39#include <math.h>
Neels Hofmeyrb861db92018-08-28 16:19:25 +020040#include <ctype.h>
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020041
42char *strline_r(char *str, char **saveptr);
43
44const char *strline_test_data =
45 "one CR\r"
46 "two CR\r"
47 "\r"
48 "one CRLF\r\n"
49 "two CRLF\r\n"
Philipp Maier87bd9be2017-08-22 16:35:41 +020050 "\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 +020051
52#define EXPECTED_NUMBER_OF_LINES 13
53
54static void test_strline(void)
55{
56 char *save = NULL;
57 char *line;
58 char buf[2048];
59 int counter = 0;
60
61 osmo_strlcpy(buf, strline_test_data, sizeof(buf));
62
Philipp Maier87bd9be2017-08-22 16:35:41 +020063 for (line = mgcp_strline(buf, &save); line;
64 line = mgcp_strline(NULL, &save)) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020065 printf("line: '%s'\n", line);
66 counter++;
67 }
68
69 OSMO_ASSERT(counter == EXPECTED_NUMBER_OF_LINES);
70}
71
Philipp Maier12943ea2018-01-17 15:40:25 +010072#define AUEP1 "AUEP 158663169 ds/e1-1/2@mgw MGCP 1.0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020073#define AUEP1_RET "200 158663169 OK\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010074#define AUEP2 "AUEP 18983213 ds/e1-2/1@mgw MGCP 1.0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020075#define AUEP2_RET "500 18983213 FAIL\r\n"
76#define EMPTY "\r\n"
77#define EMPTY_RET NULL
78#define SHORT "CRCX \r\n"
79#define SHORT_RET "510 000000 FAIL\r\n"
80
Philipp Maier12943ea2018-01-17 15:40:25 +010081#define MDCX_WRONG_EP "MDCX 18983213 ds/e1-3/1@mgw MGCP 1.0\r\n"
Harald Welteabbb6b92017-12-28 13:13:50 +010082#define MDCX_ERR_RET "500 18983213 FAIL\r\n"
Philipp Maier12943ea2018-01-17 15:40:25 +010083#define MDCX_UNALLOCATED "MDCX 18983214 ds/e1-1/2@mgw MGCP 1.0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020084#define MDCX_RET "400 18983214 FAIL\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020085
Philipp Maier87bd9be2017-08-22 16:35:41 +020086#define MDCX3 \
87 "MDCX 18983215 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010088 "I: %s\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +020089
Philipp Maier87bd9be2017-08-22 16:35:41 +020090#define MDCX3_RET \
91 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +010092 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020093 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010094 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +020095 "s=-\r\n" \
96 "c=IN IP4 0.0.0.0\r\n" \
97 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +010098 "m=audio 16002 RTP/AVP 97\r\n" \
99 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200100 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200101
Philipp Maier87bd9be2017-08-22 16:35:41 +0200102#define MDCX3A_RET \
103 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100104 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200105 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100106 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200107 "s=-\r\n" \
108 "c=IN IP4 0.0.0.0\r\n" \
109 "t=0 0\r\n" \
110 "m=audio 16002 RTP/AVP 97\r\n" \
111 "a=rtpmap:97 GSM-EFR/8000\r\n" \
112 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200113
Philipp Maier87bd9be2017-08-22 16:35:41 +0200114#define MDCX3_FMTP_RET \
115 "200 18983215 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100116 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200117 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100118 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200119 "s=-\r\n" \
120 "c=IN IP4 0.0.0.0\r\n" \
121 "t=0 0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100122 "m=audio 16006 RTP/AVP 97\r\n" \
123 "a=rtpmap:97 GSM-EFR/8000\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200124 "a=fmtp:126 0/1/2\r\n" \
125 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200126
Philipp Maier87bd9be2017-08-22 16:35:41 +0200127#define MDCX4 \
128 "MDCX 18983216 1@mgw MGCP 1.0\r\n" \
129 "M: sendrecv\r" \
130 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100131 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200132 "L: p:20, a:AMR, nt:IN\r\n" \
133 "\n" \
134 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100135 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200136 "c=IN IP4 0.0.0.0\r\n" \
137 "t=0 0\r\n" \
138 "m=audio 4441 RTP/AVP 99\r\n" \
139 "a=rtpmap:99 AMR/8000\r\n" \
140 "a=ptime:40\r\n"
141
142#define MDCX4_RET(Ident) \
143 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100144 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200145 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100146 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200147 "s=-\r\n" \
148 "c=IN IP4 0.0.0.0\r\n" \
149 "t=0 0\r\n" \
150 "m=audio 16002 RTP/AVP 99\r\n" \
151 "a=rtpmap:99 AMR/8000\r\n" \
152 "a=ptime:40\r\n"
153
154#define MDCX4_RO_RET(Ident) \
155 "200 " Ident " OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100156 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200157 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100158 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200159 "s=-\r\n" \
160 "c=IN IP4 0.0.0.0\r\n" \
161 "t=0 0\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200162 "m=audio 16002 RTP/AVP 112\r\n" \
163 "a=rtpmap:112 AMR\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200164 "a=ptime:40\r\n"
165
166#define MDCX4_PT1 \
167 "MDCX 18983217 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol17058482019-06-26 12:23:02 +0200168 "M: SENDRECV\r" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200169 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100170 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200171 "L: p:20-40, a:AMR, nt:IN\r\n" \
172 "\n" \
173 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100174 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200175 "c=IN IP4 0.0.0.0\r\n" \
176 "t=0 0\r\n" \
177 "m=audio 4441 RTP/AVP 99\r\n" \
178 "a=rtpmap:99 AMR/8000\r\n" \
179 "a=ptime:40\r\n"
180
181#define MDCX4_PT2 \
182 "MDCX 18983218 1@mgw MGCP 1.0\r\n" \
183 "M: sendrecv\r" \
184 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100185 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200186 "L: p:20-20, a:AMR, nt:IN\r\n" \
187 "\n" \
188 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100189 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200190 "c=IN IP4 0.0.0.0\r\n" \
191 "t=0 0\r\n" \
192 "m=audio 4441 RTP/AVP 99\r\n" \
193 "a=rtpmap:99 AMR/8000\r\n" \
194 "a=ptime:40\r\n"
195
196#define MDCX4_PT3 \
197 "MDCX 18983219 1@mgw MGCP 1.0\r\n" \
198 "M: sendrecv\r" \
199 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100200 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200201 "L: a:AMR, nt:IN\r\n" \
202 "\n" \
203 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100204 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200205 "c=IN IP4 0.0.0.0\r\n" \
206 "t=0 0\r\n" \
207 "m=audio 4441 RTP/AVP 99\r\n" \
208 "a=rtpmap:99 AMR/8000\r\n" \
209 "a=ptime:40\r\n"
210
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200211/* Test different upper/lower case in options */
212#define MDCX4_PT4 \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200213 "MDCX 18983220 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200214 "m: sendrecv\r" \
215 "c: 2\r\n" \
216 "i: %s\r\n" \
Pau Espin Pedrol83fd8a52019-06-26 12:55:26 +0200217 "l: A:amr, NT:IN\r\n" \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200218 "\n" \
219 "v=0\r\n" \
220 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
221 "c=IN IP4 0.0.0.0\r\n" \
222 "t=0 0\r\n" \
223 "m=audio 4441 RTP/AVP 99\r\n" \
224 "a=rtpmap:99 AMR/8000\r\n" \
225 "a=ptime:40\r\n"
226
227#define MDCX4_SO \
228 "MDCX 18983221 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200229 "M: sendonly\r" \
230 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100231 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200232 "L: p:20, a:AMR, nt:IN\r\n" \
233 "\n" \
234 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100235 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200236 "c=IN IP4 0.0.0.0\r\n" \
237 "t=0 0\r\n" \
238 "m=audio 4441 RTP/AVP 99\r\n" \
239 "a=rtpmap:99 AMR/8000\r\n" \
240 "a=ptime:40\r\n"
241
242#define MDCX4_RO \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200243 "MDCX 18983222 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200244 "M: recvonly\r" \
245 "C: 2\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100246 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200247 "L: p:20, a:AMR, nt:IN\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200248
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200249#define MDCX_TOO_LONG_CI \
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200250 "MDCX 18983223 1@mgw MGCP 1.0\r\n" \
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200251 "I: 123456789012345678901234567890123\n"
252
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200253#define MDCX_TOO_LONG_CI_RET "510 18983223 FAIL\r\n"
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200254
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200255#define SHORT2 "CRCX 1"
256#define SHORT2_RET "510 000000 FAIL\r\n"
257#define SHORT3 "CRCX 1 1@mgw"
258#define SHORT4 "CRCX 1 1@mgw MGCP"
259#define SHORT5 "CRCX 1 1@mgw MGCP 1.0"
260
Philipp Maier87bd9be2017-08-22 16:35:41 +0200261#define CRCX \
262 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Pau Espin Pedrol0c6c3c12019-06-25 17:18:12 +0200263 "m: recvonly\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200264 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200265 "L: p:20\r\n" \
266 "\r\n" \
267 "v=0\r\n" \
268 "c=IN IP4 123.12.12.123\r\n" \
269 "m=audio 5904 RTP/AVP 97\r\n" \
270 "a=rtpmap:97 GSM-EFR/8000\r\n" \
271 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200272
Philipp Maier87bd9be2017-08-22 16:35:41 +0200273#define CRCX_RET \
274 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100275 "I: %s\r\n" \
276 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200277 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100278 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200279 "s=-\r\n" \
280 "c=IN IP4 0.0.0.0\r\n" \
281 "t=0 0\r\n" \
282 "m=audio 16002 RTP/AVP 97\r\n" \
283 "a=rtpmap:97 GSM-EFR/8000\r\n" \
284 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200285
Philipp Maier87bd9be2017-08-22 16:35:41 +0200286#define CRCX_RET_NO_RTPMAP \
287 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100288 "I: %s\r\n" \
289 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200290 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100291 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200292 "s=-\r\n" \
293 "c=IN IP4 0.0.0.0\r\n" \
294 "t=0 0\r\n" \
295 "m=audio 16002 RTP/AVP 97\r\n" \
296 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200297
Philipp Maier87bd9be2017-08-22 16:35:41 +0200298#define CRCX_FMTP_RET \
299 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100300 "I: %s\r\n" \
301 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200302 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100303 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200304 "s=-\r\n" \
305 "c=IN IP4 0.0.0.0\r\n" \
306 "t=0 0\r\n" \
307 "m=audio 16006 RTP/AVP 97\r\n" \
308 "a=rtpmap:97 GSM-EFR/8000\r\n" \
309 "a=fmtp:126 0/1/2\r\n" \
310 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200311
Philipp Maier87bd9be2017-08-22 16:35:41 +0200312#define CRCX_ZYN \
313 "CRCX 2 1@mgw MGCP 1.0\r" \
314 "M: recvonly\r" \
315 "C: 2\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200316 "\n" \
317 "v=0\r" \
318 "c=IN IP4 123.12.12.123\r" \
319 "m=audio 5904 RTP/AVP 97\r" \
320 "a=rtpmap:97 GSM-EFR/8000\r"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200321
Philipp Maier87bd9be2017-08-22 16:35:41 +0200322#define CRCX_ZYN_RET \
323 "200 2 OK\r\n" \
Philipp Maierc3cfae22018-01-22 12:03:03 +0100324 "I: %s\r\n" \
325 "\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200326 "v=0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100327 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200328 "s=-\r\n" \
329 "c=IN IP4 0.0.0.0\r\n" \
330 "t=0 0\r\n" \
331 "m=audio 16004 RTP/AVP 97\r\n" \
332 "a=rtpmap:97 GSM-EFR/8000\r\n" \
333 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200334
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200335#define CRCX_X_OSMO_IGN \
336 "CRCX 2 1@mgw MGCP 1.0\r\n" \
337 "M: recvonly\r\n" \
338 "C: 2\r\n" \
339 "L: p:20\r\n" \
Neels Hofmeyrf2388ea2018-08-26 23:36:53 +0200340 "X-Osmo-IGN: C foo\r\n" \
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200341 "\r\n" \
342 "v=0\r\n" \
343 "c=IN IP4 123.12.12.123\r\n" \
344 "m=audio 5904 RTP/AVP 97\r\n" \
345 "a=rtpmap:97 GSM-EFR/8000\r\n" \
346 "a=ptime:40\r\n"
347
348#define CRCX_X_OSMO_IGN_RET \
349 "200 2 OK\r\n" \
350 "I: %s\r\n" \
351 "\r\n" \
352 "v=0\r\n" \
353 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
354 "s=-\r\n" \
355 "c=IN IP4 0.0.0.0\r\n" \
356 "t=0 0\r\n" \
357 "m=audio 16010 RTP/AVP 97\r\n" \
358 "a=rtpmap:97 GSM-EFR/8000\r\n" \
359 "a=ptime:40\r\n"
360
Philipp Maier87bd9be2017-08-22 16:35:41 +0200361#define DLCX \
362 "DLCX 7 1@mgw MGCP 1.0\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100363 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200364 "C: 2\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200365
Philipp Maier87bd9be2017-08-22 16:35:41 +0200366#define DLCX_RET \
367 "250 7 OK\r\n" \
Pau Espin Pedrol2da99a22018-02-20 13:11:17 +0100368 "P: PS=0, OS=0, PR=0, OR=0, PL=0, JI=0\r\n"
369
370 #define DLCX_RET_OSMUX DLCX_RET \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200371 "X-Osmo-CP: EC TI=0, TO=0\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200372
Philipp Maier87bd9be2017-08-22 16:35:41 +0200373#define RQNT \
374 "RQNT 186908780 1@mgw MGCP 1.0\r\n" \
375 "X: B244F267488\r\n" \
376 "S: D/9\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200377
Philipp Maier87bd9be2017-08-22 16:35:41 +0200378#define RQNT2 \
379 "RQNT 186908781 1@mgw MGCP 1.0\r\n" \
380 "X: ADD4F26746F\r\n" \
381 "R: D/[0-9#*](N), G/ft, fxr/t38\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200382
383#define RQNT1_RET "200 186908780 OK\r\n"
384#define RQNT2_RET "200 186908781 OK\r\n"
385
Philipp Maier87bd9be2017-08-22 16:35:41 +0200386#define PTYPE_IGNORE 0 /* == default initializer */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200387#define PTYPE_NONE 128
388#define PTYPE_NYI PTYPE_NONE
389
Philipp Maier87bd9be2017-08-22 16:35:41 +0200390#define CRCX_MULT_1 \
391 "CRCX 2 1@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200392 "M: recvonly\r\n" \
393 "C: 2\r\n" \
394 "X\r\n" \
395 "L: p:20\r\n" \
396 "\r\n" \
397 "v=0\r\n" \
398 "c=IN IP4 123.12.12.123\r\n" \
399 "m=audio 5904 RTP/AVP 18 97\r\n" \
400 "a=rtpmap:18 G729/8000\r\n" \
401 "a=rtpmap:97 GSM-EFR/8000\r\n" \
402 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200403
Philipp Maier87bd9be2017-08-22 16:35:41 +0200404#define CRCX_MULT_2 \
405 "CRCX 2 2@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200406 "M: recvonly\r\n" \
407 "C: 2\r\n" \
408 "X\r\n" \
409 "L: p:20\r\n" \
410 "\r\n" \
411 "v=0\r\n" \
412 "c=IN IP4 123.12.12.123\r\n" \
413 "m=audio 5904 RTP/AVP 18 97 101\r\n" \
414 "a=rtpmap:18 G729/8000\r\n" \
415 "a=rtpmap:97 GSM-EFR/8000\r\n" \
416 "a=rtpmap:101 FOO/8000\r\n" \
417 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200418
Philipp Maier87bd9be2017-08-22 16:35:41 +0200419#define CRCX_MULT_3 \
420 "CRCX 2 3@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200421 "M: recvonly\r\n" \
422 "C: 2\r\n" \
423 "X\r\n" \
424 "L: p:20\r\n" \
425 "\r\n" \
426 "v=0\r\n" \
427 "c=IN IP4 123.12.12.123\r\n" \
428 "m=audio 5904 RTP/AVP\r\n" \
429 "a=rtpmap:18 G729/8000\r\n" \
430 "a=rtpmap:97 GSM-EFR/8000\r\n" \
431 "a=rtpmap:101 FOO/8000\r\n" \
432 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200433
Philipp Maier87bd9be2017-08-22 16:35:41 +0200434#define CRCX_MULT_4 \
435 "CRCX 2 4@mgw MGCP 1.0\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200436 "M: recvonly\r\n" \
437 "C: 2\r\n" \
438 "X\r\n" \
439 "L: p:20\r\n" \
440 "\r\n" \
441 "v=0\r\n" \
442 "c=IN IP4 123.12.12.123\r\n" \
443 "m=audio 5904 RTP/AVP 18\r\n" \
444 "a=rtpmap:18 G729/8000\r\n" \
445 "a=rtpmap:97 GSM-EFR/8000\r\n" \
446 "a=rtpmap:101 FOO/8000\r\n" \
447 "a=ptime:40\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200448
449#define CRCX_MULT_GSM_EXACT \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200450 "CRCX 259260421 5@mgw MGCP 1.0\r\n" \
451 "C: 1355c6041e\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200452 "L: p:20, a:GSM, nt:IN\r\n" \
453 "M: recvonly\r\n" \
454 "\r\n" \
455 "v=0\r\n" \
456 "o=- 1439038275 1439038275 IN IP4 192.168.181.247\r\n" \
457 "s=-\r\nc=IN IP4 192.168.181.247\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200458 "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 +0200459 "a=rtpmap:0 PCMU/8000\r\n" \
460 "a=rtpmap:8 PCMA/8000\r\n" \
461 "a=rtpmap:3 gsm/8000\r\n" \
462 "a=rtpmap:18 G729/8000\r\n" \
463 "a=fmtp:18 annexb=no\r\n" \
464 "a=rtpmap:4 G723/8000\r\n" \
465 "a=rtpmap:96 iLBC/8000\r\n" \
466 "a=fmtp:96 mode=20\r\n" \
467 "a=rtpmap:97 iLBC/8000\r\n" \
468 "a=fmtp:97 mode=30\r\n" \
469 "a=rtpmap:101 telephone-event/8000\r\n" \
470 "a=fmtp:101 0-15\r\n" \
471 "a=recvonly\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200472
Philipp Maier87bd9be2017-08-22 16:35:41 +0200473#define MDCX_NAT_DUMMY \
474 "MDCX 23 5@mgw MGCP 1.0\r\n" \
475 "C: 1355c6041e\r\n" \
Philipp Maierffd75e42017-11-22 11:44:50 +0100476 "I: %s\r\n" \
Philipp Maier87bd9be2017-08-22 16:35:41 +0200477 "\r\n" \
478 "c=IN IP4 8.8.8.8\r\n" \
Philipp Maierbc0346e2018-06-07 09:52:16 +0200479 "m=audio 16434 RTP/AVP 3\r\n"
480
481#define CRCX_NO_LCO_NO_SDP \
482 "CRCX 2 6@mgw MGCP 1.0\r\n" \
483 "M: recvonly\r\n" \
484 "C: 2\r\n"
485
Philipp Maier228e5912019-03-05 13:56:59 +0100486#define CRCX_AMR_WITH_FMTP \
487 "CRCX 2 7@mgw MGCP 1.0\r\n" \
488 "M: recvonly\r\n" \
489 "C: 2\r\n" \
490 "X\r\n" \
491 "L: p:20\r\n" \
492 "\r\n" \
493 "v=0\r\n" \
494 "c=IN IP4 123.12.12.123\r\n" \
495 "m=audio 5904 RTP/AVP 111\r\n" \
496 "a=rtpmap:111 AMR/8000/1\r\n" \
497 "a=ptime:20\r\n" \
498 "a=fmtp:111 mode-change-capability=2; octet-align=1\r\n" \
499
500#define CRCX_AMR_WITH_FMTP_RET \
501 "200 2 OK\r\n" \
502 "I: %s\r\n" \
503 "\r\n" \
504 "v=0\r\n" \
505 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
506 "s=-\r\n" \
507 "c=IN IP4 0.0.0.0\r\n" \
508 "t=0 0\r\n" \
509 "m=audio 16012 RTP/AVP 111\r\n" \
510 "a=rtpmap:111 AMR/8000/1\r\n" \
511 "a=fmtp:111 octet-align=1\r\n" \
512 "a=ptime:20\r\n"
513
Philipp Maierbc0346e2018-06-07 09:52:16 +0200514#define CRCX_NO_LCO_NO_SDP_RET \
515 "200 2 OK\r\n" \
516 "I: %s\r\n" \
517 "\r\n" \
518 "v=0\r\n" \
519 "o=- %s 23 IN IP4 0.0.0.0\r\n" \
520 "s=-\r\n" \
521 "c=IN IP4 0.0.0.0\r\n" \
522 "t=0 0\r\n" \
523 "m=audio 16008 RTP/AVP 0\r\n" \
524 "a=ptime:20\r\n"
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200525
526struct mgcp_test {
527 const char *name;
528 const char *req;
529 const char *exp_resp;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200530 int ptype;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200531 const char *extra_fmtp;
532};
533
534static const struct mgcp_test tests[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200535 {"AUEP1", AUEP1, AUEP1_RET},
536 {"AUEP2", AUEP2, AUEP2_RET},
537 {"MDCX1", MDCX_WRONG_EP, MDCX_ERR_RET},
538 {"MDCX2", MDCX_UNALLOCATED, MDCX_RET},
539 {"CRCX", CRCX, CRCX_RET, 97},
540 {"MDCX3", MDCX3, MDCX3_RET, PTYPE_IGNORE},
541 {"MDCX4", MDCX4, MDCX4_RET("18983216"), 99},
542 {"MDCX4_PT1", MDCX4_PT1, MDCX4_RET("18983217"), 99},
543 {"MDCX4_PT2", MDCX4_PT2, MDCX4_RET("18983218"), 99},
544 {"MDCX4_PT3", MDCX4_PT3, MDCX4_RET("18983219"), 99},
Pau Espin Pedrolfe9a1fe2019-06-25 16:59:15 +0200545 {"MDCX4_PT4", MDCX4_PT4, MDCX4_RET("18983220"), 99},
546 {"MDCX4_SO", MDCX4_SO, MDCX4_RET("18983221"), 99},
547 {"MDCX4_RO", MDCX4_RO, MDCX4_RO_RET("18983222"), PTYPE_IGNORE},
Philipp Maier87bd9be2017-08-22 16:35:41 +0200548 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
549 {"CRCX_ZYN", CRCX_ZYN, CRCX_ZYN_RET, 97},
550 {"EMPTY", EMPTY, EMPTY_RET},
551 {"SHORT1", SHORT, SHORT_RET},
552 {"SHORT2", SHORT2, SHORT2_RET},
553 {"SHORT3", SHORT3, SHORT2_RET},
554 {"SHORT4", SHORT4, SHORT2_RET},
555 {"RQNT1", RQNT, RQNT1_RET},
556 {"RQNT2", RQNT2, RQNT2_RET},
557 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE},
558 {"CRCX", CRCX, CRCX_FMTP_RET, 97,.extra_fmtp = "a=fmtp:126 0/1/2"},
559 {"MDCX3", MDCX3, MDCX3_FMTP_RET, PTYPE_NONE,.extra_fmtp =
560 "a=fmtp:126 0/1/2"},
561 {"DLCX", DLCX, DLCX_RET, PTYPE_IGNORE,.extra_fmtp = "a=fmtp:126 0/1/2"},
Philipp Maierbc0346e2018-06-07 09:52:16 +0200562 {"CRCX", CRCX_NO_LCO_NO_SDP, CRCX_NO_LCO_NO_SDP_RET, 97},
Neels Hofmeyre6d8e912018-08-23 16:36:48 +0200563 {"CRCX", CRCX_X_OSMO_IGN, CRCX_X_OSMO_IGN_RET, 97},
Neels Hofmeyr5336f572018-09-03 22:05:48 +0200564 {"MDCX_TOO_LONG_CI", MDCX_TOO_LONG_CI, MDCX_TOO_LONG_CI_RET},
Philipp Maier228e5912019-03-05 13:56:59 +0100565 {"CRCX", CRCX_AMR_WITH_FMTP, CRCX_AMR_WITH_FMTP_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200566};
567
568static const struct mgcp_test retransmit[] = {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200569 {"CRCX", CRCX, CRCX_RET},
570 {"RQNT1", RQNT, RQNT1_RET},
571 {"RQNT2", RQNT2, RQNT2_RET},
572 {"MDCX3", MDCX3, MDCX3A_RET},
573 {"DLCX", DLCX, DLCX_RET},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200574};
575
Philipp Maierffd75e42017-11-22 11:44:50 +0100576static struct msgb *create_msg(const char *str, const char *conn_id)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200577{
578 struct msgb *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100579 int len;
580
581 printf("creating message from statically defined input:\n");
582 printf("---------8<---------\n%s\n---------8<---------\n", str);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200583
584 msg = msgb_alloc_headroom(4096, 128, "MGCP msg");
Philipp Maierffd75e42017-11-22 11:44:50 +0100585 if (conn_id && strlen(conn_id))
586 len = sprintf((char *)msg->data, str, conn_id, conn_id);
587 else
588 len = sprintf((char *)msg->data, "%s", str);
589
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200590 msg->l2h = msgb_put(msg, len);
591 return msg;
592}
593
594static int last_endpoint = -1;
595
596static int mgcp_test_policy_cb(struct mgcp_trunk_config *cfg, int endpoint,
597 int state, const char *transactio_id)
598{
Pau Espin Pedrol9ecceb62018-10-16 15:35:58 +0200599 fprintf(stderr, "Policy CB got state %d on endpoint 0x%x\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200600 state, endpoint);
601 last_endpoint = endpoint;
602 return MGCP_POLICY_CONT;
603}
604
605#define MGCP_DUMMY_LOAD 0x23
606static int dummy_packets = 0;
607/* override and forward */
608ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
Philipp Maier87bd9be2017-08-22 16:35:41 +0200609 const struct sockaddr *dest_addr, socklen_t addrlen)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200610{
Philipp Maier87bd9be2017-08-22 16:35:41 +0200611 uint32_t dest_host =
612 htonl(((struct sockaddr_in *)dest_addr)->sin_addr.s_addr);
613 int dest_port = htons(((struct sockaddr_in *)dest_addr)->sin_port);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200614
Philipp Maier87bd9be2017-08-22 16:35:41 +0200615 if (len == 1 && ((const char *)buf)[0] == MGCP_DUMMY_LOAD) {
616 fprintf(stderr,
617 "Dummy packet to 0x%08x:%d, msg length %zu\n%s\n\n",
618 dest_host, dest_port, len, osmo_hexdump(buf, len));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200619 dummy_packets += 1;
620 }
621
Philipp Maier3d9b6562017-10-13 18:33:44 +0200622 return len;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200623}
624
625static int64_t force_monotonic_time_us = -1;
626/* override and forward */
627int clock_gettime(clockid_t clk_id, struct timespec *tp)
628{
629 typedef int (*clock_gettime_t)(clockid_t clk_id, struct timespec *tp);
630 static clock_gettime_t real_clock_gettime = NULL;
631
632 if (!real_clock_gettime)
633 real_clock_gettime = dlsym(RTLD_NEXT, "clock_gettime");
634
635 if (clk_id == CLOCK_MONOTONIC && force_monotonic_time_us >= 0) {
636 tp->tv_sec = force_monotonic_time_us / 1000000;
637 tp->tv_nsec = (force_monotonic_time_us % 1000000) * 1000;
638 return 0;
639 }
640
641 return real_clock_gettime(clk_id, tp);
642}
643
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200644static void mgcp_endpoints_release(struct mgcp_trunk_config *trunk)
645{
646 int i;
647 for (i = 1; i < trunk->number_endpoints; i++)
648 mgcp_endp_release(&trunk->endpoints[i]);
649}
650
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200651#define CONN_UNMODIFIED (0x1000)
652
653static void test_values(void)
654{
655 /* Check that NONE disables all output */
Philipp Maier87bd9be2017-08-22 16:35:41 +0200656 OSMO_ASSERT((MGCP_CONN_NONE & MGCP_CONN_RECV_SEND) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200657
658 /* Check that LOOPBACK enables all output */
659 OSMO_ASSERT((MGCP_CONN_LOOPBACK & MGCP_CONN_RECV_SEND) ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200660 MGCP_CONN_RECV_SEND);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200661}
662
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200663/* Extract a connection ID from a response and return in conn_id;
664 * if there is none, return -EINVAL and leave conn_id unchanged. */
Philipp Maierffd75e42017-11-22 11:44:50 +0100665static int get_conn_id_from_response(uint8_t *resp, char *conn_id,
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200666 size_t conn_id_buflen)
Philipp Maierffd75e42017-11-22 11:44:50 +0100667{
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200668 const char *conn_id_start;
669 const char *conn_id_end;
670 int conn_id_len;
Philipp Maierffd75e42017-11-22 11:44:50 +0100671
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200672 const char *header_I = "\r\nI: ";
673 const char *header_o = "\r\no=- ";
Philipp Maierffd75e42017-11-22 11:44:50 +0100674
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200675 /* Try to get the conn_id from the 'I:' or 'o=-' parameter */
676 if ((conn_id_start = strstr((char *)resp, header_I))) {
677 conn_id_start += strlen(header_I);
678 conn_id_end = strstr(conn_id_start, "\r\n");
679 } else if ((conn_id_start = strstr((char *)resp, header_o))) {
680 conn_id_start += strlen(header_o);
681 conn_id_end = strchr(conn_id_start, ' ');
682 } else
683 return -EINVAL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100684
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200685 if (conn_id_end)
686 conn_id_len = conn_id_end - conn_id_start;
687 else
688 conn_id_len = strlen(conn_id_start);
689 OSMO_ASSERT(conn_id_len <= conn_id_buflen - 1);
Philipp Maier55295f72018-01-15 14:00:28 +0100690
Neels Hofmeyre28b6732018-08-28 16:19:25 +0200691 /* A valid conn_id must at least contain one digit, and must
692 * not exceed a length of 32 digits */
693 OSMO_ASSERT(conn_id_len <= 32);
694 OSMO_ASSERT(conn_id_len > 0);
695
696 strncpy(conn_id, conn_id_start, conn_id_len);
697 conn_id[conn_id_len] = '\0';
698 return 0;
Philipp Maierffd75e42017-11-22 11:44:50 +0100699}
700
701/* Check response, automatically patch connection ID if needed */
702static int check_response(uint8_t *resp, const char *exp_resp)
703{
704 char exp_resp_patched[4096];
705 const char *exp_resp_ptr;
706 char conn_id[256];
707
708 printf("checking response:\n");
709
710 /* If the expected response is intened to be patched
711 * (%s placeholder inside) we will patch it with the
712 * connection identifier we just received from the
713 * real response. This is necessary because the CI
714 * is generated by the mgcp code on CRCX and we can
715 * not know it in advance */
716 if (strstr(exp_resp, "%s")) {
717 if (get_conn_id_from_response(resp, conn_id, sizeof(conn_id)) ==
718 0) {
719 sprintf(exp_resp_patched, exp_resp, conn_id, conn_id);
720 exp_resp_ptr = exp_resp_patched;
721 printf
722 ("using message with patched conn_id for comparison\n");
723 } else {
724 printf
725 ("patching conn_id failed, using message as statically defined for comparison\n");
726 exp_resp_ptr = exp_resp;
727 }
728 } else {
729 printf("using message as statically defined for comparison\n");
730 exp_resp_ptr = exp_resp;
731 }
732
733 if (strcmp((char *)resp, exp_resp_ptr) != 0) {
734 printf("Unexpected response, please check!\n");
735 printf
736 ("Got:\n---------8<---------\n%s\n---------8<---------\n\n",
737 resp);
738 printf
739 ("Expected:\n---------8<---------\n%s\n---------8<---------\n",
740 exp_resp_ptr);
741 return -EINVAL;
742 }
743
744 printf("Response matches our expectations.\n");
745 return 0;
746}
747
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200748static void test_messages(void)
749{
750 struct mgcp_config *cfg;
751 struct mgcp_endpoint *endp;
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200752 struct mgcp_trunk_config *trunk2;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200753 int i;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200754 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +0100755 char last_conn_id[256];
Philipp Maier7df419b2017-12-04 17:11:42 +0100756 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200757
758 cfg = mgcp_config_alloc();
759
Philipp Maierfcd06552017-11-10 17:32:22 +0100760 cfg->trunk.vty_number_endpoints = 64;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200761 mgcp_endpoints_allocate(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200762 cfg->policy_cb = mgcp_test_policy_cb;
763
Philipp Maierffd75e42017-11-22 11:44:50 +0100764 memset(last_conn_id, 0, sizeof(last_conn_id));
765
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200766 trunk2 = mgcp_trunk_alloc(cfg, 1);
767 mgcp_endpoints_allocate(trunk2);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200768
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200769 for (i = 0; i < ARRAY_SIZE(tests); i++) {
770 const struct mgcp_test *t = &tests[i];
771 struct msgb *inp;
772 struct msgb *msg;
773
Philipp Maierffd75e42017-11-22 11:44:50 +0100774 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200775 printf("Testing %s\n", t->name);
776
777 last_endpoint = -1;
778 dummy_packets = 0;
779
Philipp Maier87bd9be2017-08-22 16:35:41 +0200780 osmo_talloc_replace_string(cfg, &cfg->trunk.audio_fmtp_extra,
781 t->extra_fmtp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200782
Philipp Maierffd75e42017-11-22 11:44:50 +0100783 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200784 msg = mgcp_handle_message(cfg, inp);
785 msgb_free(inp);
786 if (!t->exp_resp) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200787 if (msg) {
788 printf("%s failed '%s'\n", t->name,
789 (char *)msg->data);
790 OSMO_ASSERT(false);
791 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100792 } else if (check_response(msg->data, t->exp_resp) != 0) {
793 printf("%s failed.\n", t->name);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200794 OSMO_ASSERT(false);
795 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100796
Philipp Maier7df419b2017-12-04 17:11:42 +0100797 if (msg) {
798 rc = get_conn_id_from_response(msg->data, last_conn_id,
799 sizeof(last_conn_id));
Neels Hofmeyr08e07042018-08-28 16:22:14 +0200800 if (rc == 0)
Philipp Maier7df419b2017-12-04 17:11:42 +0100801 printf("(response contains a connection id)\n");
802 else
803 printf("(response does not contain a connection id)\n");
804 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100805
Philipp Maiera330b862017-12-04 17:16:16 +0100806 if (msg)
807 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200808
809 if (dummy_packets)
810 printf("Dummy packets: %d\n", dummy_packets);
811
812 if (last_endpoint != -1) {
813 endp = &cfg->trunk.endpoints[last_endpoint];
814
Philipp Maier01d24a32017-11-21 17:26:09 +0100815 conn = mgcp_conn_get_rtp(endp, "1");
Philipp Maier87bd9be2017-08-22 16:35:41 +0200816 if (conn) {
817 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200818
Philipp Maier87bd9be2017-08-22 16:35:41 +0200819 if (conn->end.packet_duration_ms != -1)
820 printf("Detected packet duration: %d\n",
821 conn->end.packet_duration_ms);
822 else
823 printf("Packet duration not set\n");
824 if (endp->local_options.pkt_period_min ||
825 endp->local_options.pkt_period_max)
826 printf
827 ("Requested packetetization period: "
828 "%d-%d\n",
829 endp->local_options.pkt_period_min,
830 endp->
831 local_options.pkt_period_max);
832 else
833 printf
834 ("Requested packetization period not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200835
Philipp Maier87bd9be2017-08-22 16:35:41 +0200836 if ((conn->conn->mode & CONN_UNMODIFIED) == 0) {
837 printf("Connection mode: %d:%s%s%s%s\n",
838 conn->conn->mode,
839 !conn->conn->mode ? " NONE" : "",
840 conn->conn->mode & MGCP_CONN_SEND_ONLY
841 ? " SEND" : "",
842 conn->conn->mode & MGCP_CONN_RECV_ONLY
843 ? " RECV" : "",
844 conn->conn->mode & MGCP_CONN_LOOPBACK
845 & ~MGCP_CONN_RECV_SEND
846 ? " LOOP" : "");
847 fprintf(stderr,
848 "RTP output %sabled, NET output %sabled\n",
849 conn->end.output_enabled
850 ? "en" : "dis",
851 conn->end.output_enabled
852 ? "en" : "dis");
853 } else
854 printf("Connection mode not set\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200855
Philipp Maier87bd9be2017-08-22 16:35:41 +0200856 OSMO_ASSERT(conn->end.output_enabled
857 == (conn->conn->mode & MGCP_CONN_SEND_ONLY ? 1 : 0));
858
859 conn->conn->mode |= CONN_UNMODIFIED;
860
861 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200862 endp->local_options.pkt_period_min = 0;
863 endp->local_options.pkt_period_max = 0;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200864 }
865
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200866 /* Check detected payload type */
Philipp Maierffd75e42017-11-22 11:44:50 +0100867 if (conn && t->ptype != PTYPE_IGNORE) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200868 OSMO_ASSERT(last_endpoint != -1);
869 endp = &cfg->trunk.endpoints[last_endpoint];
870
Pau Espin Pedrol9ecceb62018-10-16 15:35:58 +0200871 fprintf(stderr, "endpoint 0x%x: "
Philipp Maier87bd9be2017-08-22 16:35:41 +0200872 "payload type %d (expected %d)\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200873 last_endpoint,
Philipp Maierbc0346e2018-06-07 09:52:16 +0200874 conn->end.codec->payload_type, t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200875
Philipp Maier87bd9be2017-08-22 16:35:41 +0200876 if (t->ptype != PTYPE_IGNORE)
Philipp Maierbc0346e2018-06-07 09:52:16 +0200877 OSMO_ASSERT(conn->end.codec->payload_type ==
Philipp Maier87bd9be2017-08-22 16:35:41 +0200878 t->ptype);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200879
880 /* Reset them again for next test */
Philipp Maierbc0346e2018-06-07 09:52:16 +0200881 conn->end.codec->payload_type = PTYPE_NONE;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200882 }
883 }
884
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200885 mgcp_endpoints_release(trunk2);
886 mgcp_endpoints_release(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200887 talloc_free(cfg);
888}
889
890static void test_retransmission(void)
891{
892 struct mgcp_config *cfg;
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200893 struct mgcp_trunk_config *trunk2;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200894 int i;
Philipp Maierffd75e42017-11-22 11:44:50 +0100895 char last_conn_id[256];
Philipp Maier23b8e292017-12-04 16:48:45 +0100896 int rc;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200897
898 cfg = mgcp_config_alloc();
899
Philipp Maierfcd06552017-11-10 17:32:22 +0100900 cfg->trunk.vty_number_endpoints = 64;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200901 mgcp_endpoints_allocate(&cfg->trunk);
902
Philipp Maierffd75e42017-11-22 11:44:50 +0100903 memset(last_conn_id, 0, sizeof(last_conn_id));
904
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200905 trunk2 = mgcp_trunk_alloc(cfg, 1);
906 mgcp_endpoints_allocate(trunk2);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200907
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200908 for (i = 0; i < ARRAY_SIZE(retransmit); i++) {
909 const struct mgcp_test *t = &retransmit[i];
910 struct msgb *inp;
911 struct msgb *msg;
912
Philipp Maierffd75e42017-11-22 11:44:50 +0100913 printf("\n================================================\n");
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200914 printf("Testing %s\n", t->name);
915
Philipp Maierffd75e42017-11-22 11:44:50 +0100916 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200917 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200918
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200919 msgb_free(inp);
Philipp Maier7cedfd72017-12-04 16:49:12 +0100920 if (msg && check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200921 printf("%s failed '%s'\n", t->name, (char *)msg->data);
922 OSMO_ASSERT(false);
923 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100924
Philipp Maier23b8e292017-12-04 16:48:45 +0100925 if (msg && strcmp(t->name, "CRCX") == 0) {
926 rc = get_conn_id_from_response(msg->data, last_conn_id,
927 sizeof(last_conn_id));
928 OSMO_ASSERT(rc == 0);
929 }
Philipp Maierffd75e42017-11-22 11:44:50 +0100930
Philipp Maier7cedfd72017-12-04 16:49:12 +0100931 if (msg)
932 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200933
934 /* Retransmit... */
935 printf("Re-transmitting %s\n", t->name);
Philipp Maierffd75e42017-11-22 11:44:50 +0100936 inp = create_msg(t->req, last_conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200937 msg = mgcp_handle_message(cfg, inp);
938 msgb_free(inp);
Philipp Maierffd75e42017-11-22 11:44:50 +0100939 if (check_response(msg->data, t->exp_resp) != 0) {
Philipp Maier87bd9be2017-08-22 16:35:41 +0200940 printf("%s failed '%s'\n", t->name, (char *)msg->data);
941 OSMO_ASSERT(false);
942 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200943 msgb_free(msg);
944 }
945
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200946 mgcp_endpoints_release(trunk2);
947 mgcp_endpoints_release(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200948 talloc_free(cfg);
949}
950
951static int rqnt_cb(struct mgcp_endpoint *endp, char _tone)
952{
953 ptrdiff_t tone = _tone;
Philipp Maier87bd9be2017-08-22 16:35:41 +0200954 endp->cfg->data = (void *)tone;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200955 return 0;
956}
957
958static void test_rqnt_cb(void)
959{
960 struct mgcp_config *cfg;
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200961 struct mgcp_trunk_config *trunk2;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200962 struct msgb *inp, *msg;
Philipp Maierffd75e42017-11-22 11:44:50 +0100963 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200964
965 cfg = mgcp_config_alloc();
966 cfg->rqnt_cb = rqnt_cb;
967
Philipp Maierfcd06552017-11-10 17:32:22 +0100968 cfg->trunk.vty_number_endpoints = 64;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200969 mgcp_endpoints_allocate(&cfg->trunk);
970
Pau Espin Pedrold071a302019-09-19 17:39:31 +0200971 trunk2 = mgcp_trunk_alloc(cfg, 1);
972 mgcp_endpoints_allocate(trunk2);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200973
Philipp Maierffd75e42017-11-22 11:44:50 +0100974 inp = create_msg(CRCX, NULL);
975 msg = mgcp_handle_message(cfg, inp);
976 OSMO_ASSERT(msg);
977 OSMO_ASSERT(get_conn_id_from_response(msg->data, conn_id,
978 sizeof(conn_id)) == 0);
979 msgb_free(msg);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200980 msgb_free(inp);
981
982 /* send the RQNT and check for the CB */
Philipp Maierffd75e42017-11-22 11:44:50 +0100983 inp = create_msg(RQNT, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200984 msg = mgcp_handle_message(cfg, inp);
Philipp Maier87bd9be2017-08-22 16:35:41 +0200985 if (strncmp((const char *)msg->l2h, "200", 3) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200986 printf("FAILED: message is not 200. '%s'\n", msg->l2h);
987 abort();
988 }
989
Philipp Maier87bd9be2017-08-22 16:35:41 +0200990 if (cfg->data != (void *)'9') {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200991 printf("FAILED: callback not called: %p\n", cfg->data);
992 abort();
993 }
994
995 msgb_free(msg);
996 msgb_free(inp);
997
Philipp Maierffd75e42017-11-22 11:44:50 +0100998 inp = create_msg(DLCX, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +0200999 msgb_free(mgcp_handle_message(cfg, inp));
1000 msgb_free(inp);
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001001 mgcp_endpoints_release(trunk2);
1002 mgcp_endpoints_release(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001003 talloc_free(cfg);
1004}
1005
1006struct pl_test {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001007 int cycles;
1008 uint16_t base_seq;
1009 uint16_t max_seq;
1010 uint32_t packets;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001011
Philipp Maier87bd9be2017-08-22 16:35:41 +02001012 uint32_t expected;
1013 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001014};
1015
1016static const struct pl_test pl_test_dat[] = {
1017 /* basic.. just one package */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001018 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = 1,.expected =
1019 1,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001020 /* some packages and a bit of loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001021 {.cycles = 0,.base_seq = 0,.max_seq = 100,.packets = 100,.expected =
1022 101,.loss = 1},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001023 /* wrap around */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001024 {.cycles = 1 << 16,.base_seq = 0xffff,.max_seq = 2,.packets =
1025 4,.expected = 4,.loss = 0},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001026 /* min loss */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001027 {.cycles = 0,.base_seq = 0,.max_seq = 0,.packets = UINT_MAX,.expected =
1028 1,.loss = INT_MIN},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001029 /* max loss, with wrap around on expected max */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001030 {.cycles = INT_MAX,.base_seq = 0,.max_seq = UINT16_MAX,.packets =
1031 0,.expected = ((uint32_t) (INT_MAX) + UINT16_MAX + 1),.loss = INT_MAX},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001032};
1033
1034static void test_packet_loss_calc(void)
1035{
1036 int i;
Philipp Maiercede2a42018-07-03 14:14:21 +02001037 struct mgcp_endpoint endp;
Oliver Smithe36b7752019-01-22 16:31:36 +01001038 struct mgcp_config cfg = {0};
Philipp Maiercede2a42018-07-03 14:14:21 +02001039 struct mgcp_trunk_config trunk;
1040
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001041 printf("Testing packet loss calculation.\n");
1042
Philipp Maiercede2a42018-07-03 14:14:21 +02001043 memset(&endp, 0, sizeof(endp));
1044 memset(&trunk, 0, sizeof(trunk));
1045
Oliver Smithe36b7752019-01-22 16:31:36 +01001046 endp.cfg = &cfg;
Philipp Maiercede2a42018-07-03 14:14:21 +02001047 endp.type = &ep_typeset.rtp;
1048 trunk.vty_number_endpoints = 1;
1049 trunk.endpoints = &endp;
1050 endp.tcfg = &trunk;
1051 INIT_LLIST_HEAD(&endp.conns);
1052
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001053 for (i = 0; i < ARRAY_SIZE(pl_test_dat); ++i) {
1054 uint32_t expected;
1055 int loss;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001056
Philipp Maiercede2a42018-07-03 14:14:21 +02001057 struct mgcp_conn_rtp *conn = NULL;
1058 struct mgcp_conn *_conn = NULL;
1059 struct mgcp_rtp_state *state;
1060 struct rate_ctr *packets_rx;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001061
Philipp Maiercede2a42018-07-03 14:14:21 +02001062 _conn =
1063 mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1064 "test-connection");
1065 conn = mgcp_conn_get_rtp(&endp, _conn->id);
1066 state = &conn->state;
1067 packets_rx = &conn->rate_ctr_group->ctr[RTP_PACKETS_RX_CTR];
1068
1069 state->stats.initialized = 1;
1070 state->stats.base_seq = pl_test_dat[i].base_seq;
1071 state->stats.max_seq = pl_test_dat[i].max_seq;
1072 state->stats.cycles = pl_test_dat[i].cycles;
1073
1074 packets_rx->current = pl_test_dat[i].packets;
1075 calc_loss(conn, &expected, &loss);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001076
Philipp Maier87bd9be2017-08-22 16:35:41 +02001077 if (loss != pl_test_dat[i].loss
1078 || expected != pl_test_dat[i].expected) {
1079 printf
1080 ("FAIL: Wrong exp/loss at idx(%d) Loss(%d vs. %d) Exp(%u vs. %u)\n",
1081 i, loss, pl_test_dat[i].loss, expected,
1082 pl_test_dat[i].expected);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001083 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001084
1085 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001086 }
Philipp Maiercede2a42018-07-03 14:14:21 +02001087
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001088}
1089
Philipp Maier87bd9be2017-08-22 16:35:41 +02001090int mgcp_parse_stats(struct msgb *msg, uint32_t *ps, uint32_t *os,
1091 uint32_t *pr, uint32_t *_or, int *loss,
1092 uint32_t *jitter)
1093{
1094 char *line, *save;
1095 int rc;
1096
1097 /* initialize with bad values */
1098 *ps = *os = *pr = *_or = *jitter = UINT_MAX;
1099 *loss = INT_MAX;
1100
1101 line = strtok_r((char *)msg->l2h, "\r\n", &save);
1102 if (!line)
1103 return -1;
1104
1105 /* this can only parse the message that is created above... */
1106 for_each_non_empty_line(line, save) {
1107 switch (line[0]) {
1108 case 'P':
1109 rc = sscanf(line,
1110 "P: PS=%u, OS=%u, PR=%u, OR=%u, PL=%d, JI=%u",
1111 ps, os, pr, _or, loss, jitter);
1112 return rc == 6 ? 0 : -1;
1113 }
1114 }
1115
1116 return -1;
1117}
1118
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001119static void test_mgcp_stats(void)
1120{
1121 printf("Testing stat parsing\n");
1122
1123 uint32_t bps, bos, pr, _or, jitter;
1124 struct msgb *msg;
1125 int loss;
1126 int rc;
1127
Philipp Maierffd75e42017-11-22 11:44:50 +01001128 msg = create_msg(DLCX_RET, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001129 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1130 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001131 if (bps != 0 || bos != 0 || pr != 0 || _or != 0 || loss != 0
1132 || jitter != 0)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001133 printf("FAIL: Parsing failed1.\n");
1134 msgb_free(msg);
1135
Philipp Maier87bd9be2017-08-22 16:35:41 +02001136 msg =
1137 create_msg
Philipp Maierffd75e42017-11-22 11:44:50 +01001138 ("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 +02001139 rc = mgcp_parse_stats(msg, &bps, &bos, &pr, &_or, &loss, &jitter);
1140 printf("Parsing result: %d\n", rc);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001141 if (bps != 10 || bos != 20 || pr != 30 || _or != 40 || loss != -3
1142 || jitter != 40)
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001143 printf("FAIL: Parsing failed2.\n");
1144 msgb_free(msg);
1145}
1146
1147struct rtp_packet_info {
1148 float txtime;
1149 int len;
1150 char *data;
1151};
1152
1153struct rtp_packet_info test_rtp_packets1[] = {
1154 /* RTP: SeqNo=0, TS=0 */
1155 {0.000000, 20, "\x80\x62\x00\x00\x00\x00\x00\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001156 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001157 /* RTP: SeqNo=1, TS=160 */
1158 {0.020000, 20, "\x80\x62\x00\x01\x00\x00\x00\xA0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001159 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001160 /* RTP: SeqNo=2, TS=320 */
1161 {0.040000, 20, "\x80\x62\x00\x02\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001162 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001163 /* Repeat RTP timestamp: */
1164 /* RTP: SeqNo=3, TS=320 */
1165 {0.060000, 20, "\x80\x62\x00\x03\x00\x00\x01\x40\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001166 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001167 /* RTP: SeqNo=4, TS=480 */
1168 {0.080000, 20, "\x80\x62\x00\x04\x00\x00\x01\xE0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001169 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001170 /* RTP: SeqNo=5, TS=640 */
1171 {0.100000, 20, "\x80\x62\x00\x05\x00\x00\x02\x80\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001172 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001173 /* Double skip RTP timestamp (delta = 2*160): */
1174 /* RTP: SeqNo=6, TS=960 */
1175 {0.120000, 20, "\x80\x62\x00\x06\x00\x00\x03\xC0\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001176 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001177 /* RTP: SeqNo=7, TS=1120 */
1178 {0.140000, 20, "\x80\x62\x00\x07\x00\x00\x04\x60\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001179 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001180 /* RTP: SeqNo=8, TS=1280 */
1181 {0.160000, 20, "\x80\x62\x00\x08\x00\x00\x05\x00\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001182 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001183 /* Non 20ms RTP timestamp (delta = 120): */
1184 /* RTP: SeqNo=9, TS=1400 */
1185 {0.180000, 20, "\x80\x62\x00\x09\x00\x00\x05\x78\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001186 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001187 /* RTP: SeqNo=10, TS=1560 */
1188 {0.200000, 20, "\x80\x62\x00\x0A\x00\x00\x06\x18\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001189 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001190 /* RTP: SeqNo=11, TS=1720 */
1191 {0.220000, 20, "\x80\x62\x00\x0B\x00\x00\x06\xB8\x11\x22\x33\x44"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001192 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001193 /* SSRC changed to 0x10203040, RTP timestamp jump */
1194 /* RTP: SeqNo=12, TS=34688 */
1195 {0.240000, 20, "\x80\x62\x00\x0C\x00\x00\x87\x80\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001196 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001197 /* RTP: SeqNo=13, TS=34848 */
1198 {0.260000, 20, "\x80\x62\x00\x0D\x00\x00\x88\x20\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001199 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001200 /* RTP: SeqNo=14, TS=35008 */
1201 {0.280000, 20, "\x80\x62\x00\x0E\x00\x00\x88\xC0\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001202 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001203 /* Non 20ms RTP timestamp (delta = 120): */
1204 /* RTP: SeqNo=15, TS=35128 */
1205 {0.300000, 20, "\x80\x62\x00\x0F\x00\x00\x89\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001206 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001207 /* RTP: SeqNo=16, TS=35288 */
1208 {0.320000, 20, "\x80\x62\x00\x10\x00\x00\x89\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001209 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001210 /* RTP: SeqNo=17, TS=35448 */
1211 {0.340000, 20, "\x80\x62\x00\x11\x00\x00\x8A\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001212 "\x01\x23\x45\x67\x8A\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001213 /* SeqNo increment by 2, RTP timestamp delta = 320: */
1214 /* RTP: SeqNo=19, TS=35768 */
1215 {0.360000, 20, "\x80\x62\x00\x13\x00\x00\x8B\xB8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001216 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001217 /* RTP: SeqNo=20, TS=35928 */
1218 {0.380000, 20, "\x80\x62\x00\x14\x00\x00\x8C\x58\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001219 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001220 /* RTP: SeqNo=21, TS=36088 */
1221 {0.380000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001222 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001223 /* Repeat last packet */
1224 /* RTP: SeqNo=21, TS=36088 */
1225 {0.400000, 20, "\x80\x62\x00\x15\x00\x00\x8C\xF8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001226 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001227 /* RTP: SeqNo=22, TS=36248 */
1228 {0.420000, 20, "\x80\x62\x00\x16\x00\x00\x8D\x98\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001229 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001230 /* RTP: SeqNo=23, TS=36408 */
1231 {0.440000, 20, "\x80\x62\x00\x17\x00\x00\x8E\x38\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001232 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001233 /* Don't increment SeqNo but increment timestamp by 160 */
1234 /* RTP: SeqNo=23, TS=36568 */
1235 {0.460000, 20, "\x80\x62\x00\x17\x00\x00\x8E\xD8\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001236 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001237 /* RTP: SeqNo=24, TS=36728 */
1238 {0.480000, 20, "\x80\x62\x00\x18\x00\x00\x8F\x78\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001239 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001240 /* RTP: SeqNo=25, TS=36888 */
1241 {0.500000, 20, "\x80\x62\x00\x19\x00\x00\x90\x18\x10\x20\x30\x40"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001242 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001243 /* SSRC changed to 0x50607080, RTP timestamp jump, Delay of 1.5s,
1244 * SeqNo jump */
1245 /* RTP: SeqNo=1000, TS=160000 */
1246 {2.000000, 20, "\x80\x62\x03\xE8\x00\x02\x71\x00\x50\x60\x70\x80"
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=1001, TS=160160 */
1249 {2.020000, 20, "\x80\x62\x03\xE9\x00\x02\x71\xA0\x50\x60\x70\x80"
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=1002, TS=160320 */
1252 {2.040000, 20, "\x80\x62\x03\xEA\x00\x02\x72\x40\x50\x60\x70\x80"
Philipp Maier87bd9be2017-08-22 16:35:41 +02001253 "\x01\x23\x45\x67\x89\xAB\xCD\xEF"},
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001254};
1255
Philipp Maier87bd9be2017-08-22 16:35:41 +02001256void mgcp_patch_and_count(struct mgcp_endpoint *endp,
1257 struct mgcp_rtp_state *state,
1258 struct mgcp_rtp_end *rtp_end,
1259 struct sockaddr_in *addr, char *data, int len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001260
1261static void test_packet_error_detection(int patch_ssrc, int patch_ts)
1262{
1263 int i;
1264
1265 struct mgcp_trunk_config trunk;
1266 struct mgcp_endpoint endp;
Oliver Smithe36b7752019-01-22 16:31:36 +01001267 struct mgcp_config cfg = {0};
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001268 struct mgcp_rtp_state state;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001269 struct mgcp_rtp_end *rtp;
1270 struct sockaddr_in addr = { 0 };
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001271 char buffer[4096];
1272 uint32_t last_ssrc = 0;
1273 uint32_t last_timestamp = 0;
1274 uint32_t last_seqno = 0;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001275 uint64_t last_in_ts_err_cnt = 0;
1276 uint64_t last_out_ts_err_cnt = 0;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001277 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001278 struct mgcp_conn *_conn = NULL;
Philipp Maier9e1d1642018-05-09 16:26:34 +02001279 struct rate_ctr test_ctr_in;
1280 struct rate_ctr test_ctr_out;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001281
1282 printf("Testing packet error detection%s%s.\n",
1283 patch_ssrc ? ", patch SSRC" : "",
1284 patch_ts ? ", patch timestamps" : "");
1285
1286 memset(&trunk, 0, sizeof(trunk));
1287 memset(&endp, 0, sizeof(endp));
1288 memset(&state, 0, sizeof(state));
1289
Philipp Maier9e1d1642018-05-09 16:26:34 +02001290 memset(&test_ctr_in, 0, sizeof(test_ctr_in));
1291 memset(&test_ctr_out, 0, sizeof(test_ctr_out));
1292 state.in_stream.err_ts_ctr = &test_ctr_in;
1293 state.out_stream.err_ts_ctr = &test_ctr_out;
1294
Oliver Smithe36b7752019-01-22 16:31:36 +01001295 endp.cfg = &cfg;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001296 endp.type = &ep_typeset.rtp;
1297
Philipp Maierfcd06552017-11-10 17:32:22 +01001298 trunk.vty_number_endpoints = 1;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001299 trunk.endpoints = &endp;
1300 trunk.force_constant_ssrc = patch_ssrc;
1301 trunk.force_aligned_timing = patch_ts;
1302
1303 endp.tcfg = &trunk;
1304
Philipp Maier87bd9be2017-08-22 16:35:41 +02001305 INIT_LLIST_HEAD(&endp.conns);
Philipp Maierffd75e42017-11-22 11:44:50 +01001306 _conn = mgcp_conn_alloc(NULL, &endp, MGCP_CONN_TYPE_RTP,
1307 "test-connection");
1308 OSMO_ASSERT(_conn);
1309 conn = mgcp_conn_get_rtp(&endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001310 OSMO_ASSERT(conn);
1311
1312 rtp = &conn->end;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001313
Philipp Maier228e5912019-03-05 13:56:59 +01001314 OSMO_ASSERT(mgcp_codec_add(conn, PTYPE_UNDEFINED, "AMR/8000/1", NULL) == 0);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001315 rtp->codec = &rtp->codecs[0];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001316
1317 for (i = 0; i < ARRAY_SIZE(test_rtp_packets1); ++i) {
1318 struct rtp_packet_info *info = test_rtp_packets1 + i;
1319
1320 force_monotonic_time_us = round(1000000.0 * info->txtime);
1321
1322 OSMO_ASSERT(info->len <= sizeof(buffer));
1323 OSMO_ASSERT(info->len >= 0);
1324 memmove(buffer, info->data, info->len);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001325 mgcp_rtp_end_config(&endp, 1, rtp);
1326
1327 mgcp_patch_and_count(&endp, &state, rtp, &addr,
1328 buffer, info->len);
1329
1330 if (state.out_stream.ssrc != last_ssrc) {
1331 printf("Output SSRC changed to %08x\n",
1332 state.out_stream.ssrc);
1333 last_ssrc = state.out_stream.ssrc;
1334 }
1335
1336 printf("In TS: %d, dTS: %d, Seq: %d\n",
1337 state.in_stream.last_timestamp,
Philipp Maier87bd9be2017-08-22 16:35:41 +02001338 state.in_stream.last_tsdelta, state.in_stream.last_seq);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001339
1340 printf("Out TS change: %d, dTS: %d, Seq change: %d, "
Philipp Maier9e1d1642018-05-09 16:26:34 +02001341 "TS Err change: in +%u, out +%u\n",
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001342 state.out_stream.last_timestamp - last_timestamp,
1343 state.out_stream.last_tsdelta,
1344 state.out_stream.last_seq - last_seqno,
Philipp Maier9e1d1642018-05-09 16:26:34 +02001345 (unsigned int) (state.in_stream.err_ts_ctr->current - last_in_ts_err_cnt),
1346 (unsigned int) (state.out_stream.err_ts_ctr->current - last_out_ts_err_cnt));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001347
1348 printf("Stats: Jitter = %u, Transit = %d\n",
Harald Welte49e3d5a2017-12-25 09:47:57 +01001349 calc_jitter(&state), state.stats.transit);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001350
Philipp Maier9e1d1642018-05-09 16:26:34 +02001351 last_in_ts_err_cnt = state.in_stream.err_ts_ctr->current;
1352 last_out_ts_err_cnt = state.out_stream.err_ts_ctr->current;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001353 last_timestamp = state.out_stream.last_timestamp;
1354 last_seqno = state.out_stream.last_seq;
1355 }
1356
1357 force_monotonic_time_us = -1;
Neels Hofmeyrd20910c2017-11-18 21:27:50 +01001358 mgcp_conn_free_all(&endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001359}
1360
1361static void test_multilple_codec(void)
1362{
1363 struct mgcp_config *cfg;
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001364 struct mgcp_trunk_config *trunk2;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001365 struct mgcp_endpoint *endp;
1366 struct msgb *inp, *resp;
1367 struct in_addr addr;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001368 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001369 char conn_id[256];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001370
1371 printf("Testing multiple payload types\n");
1372
1373 cfg = mgcp_config_alloc();
Philipp Maierfcd06552017-11-10 17:32:22 +01001374 cfg->trunk.vty_number_endpoints = 64;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001375 mgcp_endpoints_allocate(&cfg->trunk);
1376 cfg->policy_cb = mgcp_test_policy_cb;
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001377
1378 trunk2 = mgcp_trunk_alloc(cfg, 1);
1379 mgcp_endpoints_allocate(trunk2);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001380
1381 /* Allocate endpoint 1@mgw with two codecs */
1382 last_endpoint = -1;
Philipp Maierffd75e42017-11-22 11:44:50 +01001383 inp = create_msg(CRCX_MULT_1, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001384 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001385 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1386 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001387 msgb_free(inp);
1388 msgb_free(resp);
1389
1390 OSMO_ASSERT(last_endpoint == 1);
1391 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001392 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001393 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001394 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001395
1396 /* Allocate 2@mgw with three codecs, last one ignored */
1397 last_endpoint = -1;
Philipp Maierffd75e42017-11-22 11:44:50 +01001398 inp = create_msg(CRCX_MULT_2, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001399 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001400 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1401 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001402 msgb_free(inp);
1403 msgb_free(resp);
1404
1405 OSMO_ASSERT(last_endpoint == 2);
1406 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001407 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001408 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001409 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001410
Philipp Maierbc0346e2018-06-07 09:52:16 +02001411 /* Allocate 3@mgw with no codecs, check for PT == 0 */
1412 /* Note: It usually makes no sense to leave the payload type list
1413 * out. However RFC 2327 does not clearly forbid this case and
1414 * it makes and since we already decided in OS#2658 that a missing
1415 * LCO should pick a sane default codec, it makes sense to expect
1416 * the same behaviour if SDP lacks proper payload type information */
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001417 last_endpoint = -1;
Philipp Maierffd75e42017-11-22 11:44:50 +01001418 inp = create_msg(CRCX_MULT_3, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001419 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001420 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1421 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001422 msgb_free(inp);
1423 msgb_free(resp);
1424
1425 OSMO_ASSERT(last_endpoint == 3);
1426 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001427 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001428 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001429 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001430
1431 /* Allocate 4@mgw with a single codec */
1432 last_endpoint = -1;
Philipp Maierffd75e42017-11-22 11:44:50 +01001433 inp = create_msg(CRCX_MULT_4, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001434 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001435 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1436 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001437 msgb_free(inp);
1438 msgb_free(resp);
1439
1440 OSMO_ASSERT(last_endpoint == 4);
1441 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001442 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001443 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001444 OSMO_ASSERT(conn->end.codec->payload_type == 18);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001445
1446 /* Allocate 5@mgw at select GSM.. */
1447 last_endpoint = -1;
Philipp Maierffd75e42017-11-22 11:44:50 +01001448 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001449 talloc_free(cfg->trunk.audio_name);
1450 cfg->trunk.audio_name = "GSM/8000";
1451 cfg->trunk.no_audio_transcoding = 1;
1452 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001453 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1454 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001455 msgb_free(inp);
1456 msgb_free(resp);
1457
1458 OSMO_ASSERT(last_endpoint == 5);
1459 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001460 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001461 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001462 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001463
Philipp Maierffd75e42017-11-22 11:44:50 +01001464 inp = create_msg(MDCX_NAT_DUMMY, conn_id);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001465 last_endpoint = -1;
1466 resp = mgcp_handle_message(cfg, inp);
1467 msgb_free(inp);
1468 msgb_free(resp);
1469 OSMO_ASSERT(last_endpoint == 5);
1470 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001471 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001472 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001473 OSMO_ASSERT(conn->end.codec->payload_type == 3);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001474 OSMO_ASSERT(conn->end.rtp_port == htons(16434));
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001475 memset(&addr, 0, sizeof(addr));
1476 inet_aton("8.8.8.8", &addr);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001477 OSMO_ASSERT(conn->end.addr.s_addr == addr.s_addr);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001478
1479 /* Check what happens without that flag */
1480
Philipp Maier87bd9be2017-08-22 16:35:41 +02001481 /* Free the previous endpoint and the data and
1482 * check if the connection really vanished... */
Philipp Maier1355d7e2018-02-01 14:30:06 +01001483 mgcp_endp_release(endp);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001484 talloc_free(endp->last_response);
1485 talloc_free(endp->last_trans);
1486 endp->last_response = endp->last_trans = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001487 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001488 OSMO_ASSERT(!conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001489
1490 last_endpoint = -1;
Philipp Maierffd75e42017-11-22 11:44:50 +01001491 inp = create_msg(CRCX_MULT_GSM_EXACT, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001492 cfg->trunk.no_audio_transcoding = 0;
1493 resp = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001494 OSMO_ASSERT(get_conn_id_from_response(resp->data, conn_id,
1495 sizeof(conn_id)) == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001496 msgb_free(inp);
1497 msgb_free(resp);
1498
1499 OSMO_ASSERT(last_endpoint == 5);
1500 endp = &cfg->trunk.endpoints[last_endpoint];
Philipp Maierffd75e42017-11-22 11:44:50 +01001501 conn = mgcp_conn_get_rtp(endp, conn_id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001502 OSMO_ASSERT(conn);
Philipp Maierbc0346e2018-06-07 09:52:16 +02001503 OSMO_ASSERT(conn->end.codec->payload_type == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001504
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001505 mgcp_endpoints_release(trunk2);
1506 mgcp_endpoints_release(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001507 talloc_free(cfg);
1508}
1509
1510static void test_no_cycle(void)
1511{
1512 struct mgcp_config *cfg;
1513 struct mgcp_endpoint *endp;
Philipp Maier87bd9be2017-08-22 16:35:41 +02001514 struct mgcp_conn_rtp *conn = NULL;
Philipp Maierffd75e42017-11-22 11:44:50 +01001515 struct mgcp_conn *_conn = NULL;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001516
1517 printf("Testing no sequence flow on initial packet\n");
1518
1519 cfg = mgcp_config_alloc();
Philipp Maierfcd06552017-11-10 17:32:22 +01001520 cfg->trunk.vty_number_endpoints = 64;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001521 mgcp_endpoints_allocate(&cfg->trunk);
1522
1523 endp = &cfg->trunk.endpoints[1];
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001524
Philipp Maierffd75e42017-11-22 11:44:50 +01001525 _conn = mgcp_conn_alloc(NULL, endp, MGCP_CONN_TYPE_RTP,
1526 "test-connection");
1527 OSMO_ASSERT(_conn);
1528 conn = mgcp_conn_get_rtp(endp, _conn->id);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001529 OSMO_ASSERT(conn);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001530
Harald Welte49e3d5a2017-12-25 09:47:57 +01001531 OSMO_ASSERT(conn->state.stats.initialized == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001532
1533 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001534 OSMO_ASSERT(conn->state.stats.initialized == 1);
1535 OSMO_ASSERT(conn->state.stats.cycles == 0);
1536 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Philipp Maier87bd9be2017-08-22 16:35:41 +02001537
1538 mgcp_rtp_annex_count(endp, &conn->state, 1, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001539 OSMO_ASSERT(conn->state.stats.initialized == 1);
1540 OSMO_ASSERT(conn->state.stats.cycles == 0);
1541 OSMO_ASSERT(conn->state.stats.max_seq == 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001542
1543 /* now jump.. */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001544 mgcp_rtp_annex_count(endp, &conn->state, UINT16_MAX, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001545 OSMO_ASSERT(conn->state.stats.initialized == 1);
1546 OSMO_ASSERT(conn->state.stats.cycles == 0);
1547 OSMO_ASSERT(conn->state.stats.max_seq == UINT16_MAX);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001548
1549 /* and wrap */
Philipp Maier87bd9be2017-08-22 16:35:41 +02001550 mgcp_rtp_annex_count(endp, &conn->state, 0, 0, 2342);
Harald Welte49e3d5a2017-12-25 09:47:57 +01001551 OSMO_ASSERT(conn->state.stats.initialized == 1);
1552 OSMO_ASSERT(conn->state.stats.cycles == UINT16_MAX + 1);
1553 OSMO_ASSERT(conn->state.stats.max_seq == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001554
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001555 mgcp_endpoints_release(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001556 talloc_free(cfg);
1557}
1558
1559static void test_no_name(void)
1560{
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001561 struct mgcp_trunk_config *trunk2;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001562 struct mgcp_config *cfg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001563 struct msgb *inp, *msg;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001564
1565 printf("Testing no rtpmap name\n");
1566 cfg = mgcp_config_alloc();
1567
Philipp Maierfcd06552017-11-10 17:32:22 +01001568 cfg->trunk.vty_number_endpoints = 64;
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001569 cfg->trunk.audio_send_name = 0;
1570 mgcp_endpoints_allocate(&cfg->trunk);
1571
1572 cfg->policy_cb = mgcp_test_policy_cb;
1573
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001574 trunk2 = mgcp_trunk_alloc(cfg, 1);
1575 mgcp_endpoints_allocate(trunk2);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001576
Philipp Maierffd75e42017-11-22 11:44:50 +01001577 inp = create_msg(CRCX, NULL);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001578 msg = mgcp_handle_message(cfg, inp);
Philipp Maierffd75e42017-11-22 11:44:50 +01001579
1580 if (check_response(msg->data, CRCX_RET_NO_RTPMAP) != 0) {
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001581 printf("FAILED: there should not be a RTPMAP: %s\n",
Philipp Maier87bd9be2017-08-22 16:35:41 +02001582 (char *)msg->data);
1583 OSMO_ASSERT(false);
1584 }
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001585 msgb_free(inp);
1586 msgb_free(msg);
1587
Pau Espin Pedrold071a302019-09-19 17:39:31 +02001588 mgcp_endpoints_release(trunk2);
1589 mgcp_endpoints_release(&cfg->trunk);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001590 talloc_free(cfg);
1591}
1592
1593static void test_osmux_cid(void)
1594{
1595 int id, i;
1596
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001597 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
1598
1599 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001600 OSMO_ASSERT(id == 0);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001601 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1602
1603 osmux_cid_pool_get(30);
1604 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1605 osmux_cid_pool_get(30);
1606 OSMO_ASSERT(osmux_cid_pool_count_used() == 2);
1607
1608 osmux_cid_pool_put(id);
1609 OSMO_ASSERT(osmux_cid_pool_count_used() == 1);
1610 osmux_cid_pool_put(30);
1611 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001612
1613 for (i = 0; i < 256; ++i) {
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001614 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001615 OSMO_ASSERT(id == i);
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001616 OSMO_ASSERT(osmux_cid_pool_count_used() == i + 1);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001617 }
1618
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001619 id = osmux_cid_pool_get_next();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001620 OSMO_ASSERT(id == -1);
1621
1622 for (i = 0; i < 256; ++i)
Pau Espin Pedrol8de58e72019-04-24 13:33:46 +02001623 osmux_cid_pool_put(i);
1624 OSMO_ASSERT(osmux_cid_pool_count_used() == 0);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001625}
1626
1627static const struct log_info_cat log_categories[] = {
1628};
1629
1630const struct log_info log_info = {
Philipp Maier87bd9be2017-08-22 16:35:41 +02001631 .cat = log_categories,
1632 .num_cat = ARRAY_SIZE(log_categories),
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02001633};
1634
Philipp Maier3d7b58d2018-06-06 09:35:31 +02001635static void test_get_lco_identifier(void)
1636{
1637 char *test;
1638 printf("Testing get_lco_identifier()\n");
1639
1640 /* Normal case at the beginning */
1641 test = "p:10, a:PCMU";
1642 printf("%s -> %s\n", test, get_lco_identifier(test));
1643
1644 test = "p:10, a:PCMU";
1645 printf("%s -> %s\n", test, get_lco_identifier(test));
1646
1647 /* Begin parsing in the middle of the value part of
1648 * the previous LCO option value */
1649 test = "XXXX, p:10, a:PCMU";
1650 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1651
1652 test = "XXXX,p:10,a:PCMU";
1653 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1654
1655 test = "10,a:PCMU";
1656 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1657
1658 test = "10, a:PCMU";
1659 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1660
1661 test = "10,a: PCMU";
1662 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1663
1664 test = "10 ,a: PCMU";
1665 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1666
1667 /* Begin parsing right at the end of the previous LCO
1668 * option value */
1669 test = ", a:PCMU";
1670 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1671
1672 test = " a:PCMU";
1673 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1674
1675 /* Empty string, result should be (null) */
1676 test = "";
1677 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1678
1679 /* Missing colons, result should be (null) */
1680 test = "p10, aPCMU";
1681 printf("%s -> %s\n", test, get_lco_identifier(test));
1682
1683 /* Colon separated from the identifier, result should be (null) */
1684 test = "10,a :PCMU";
1685 printf("'%s' -> '%s'\n", test, get_lco_identifier(test));
1686}
1687
1688static void test_check_local_cx_options(void *ctx)
1689{
1690 /* Legal cases */
1691 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1692 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU") == 0);
1693 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p:10, IN:10") == 0);
1694 OSMO_ASSERT(check_local_cx_options(ctx, "one:AAA, two:BB, tree:C") ==
1695 0);
1696 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU") == 0);
1697 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:G726-32") == 0);
1698 OSMO_ASSERT(check_local_cx_options(ctx, "p:10-20, b:64") == 0);
1699 OSMO_ASSERT(check_local_cx_options(ctx, "b:32-64, e:off") == 0);
1700 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU;G726-32") == 0);
1701
1702 /* Illegal spaces before and after colon */
1703 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, p :10") == -1);
1704 OSMO_ASSERT(check_local_cx_options(ctx, "a :PCMU, p:10") == -1);
1705 OSMO_ASSERT(check_local_cx_options(ctx, "p: 10, a:PCMU") == -1);
1706
1707 /* Check if multiple appearances of LCOs are rejected */
1708 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, p:10") == -1);
1709 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:PCMU, a:PCMU, p:10") ==
1710 -1);
1711 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, p:10") == -1);
1712
1713 /* Check if empty LCO are rejected */
1714 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a:PCMU") == -1);
1715 OSMO_ASSERT(check_local_cx_options(ctx, "p: , a: PCMU") == -1);
1716 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a: PCMU") == -1);
1717 OSMO_ASSERT(check_local_cx_options(ctx, "p:, a:PCMU") == -1);
1718 OSMO_ASSERT(check_local_cx_options(ctx, "p:10, a:") == -1);
1719
1720 /* Garbeled beginning and ends */
1721 OSMO_ASSERT(check_local_cx_options(ctx, ":10, a:10") == -1);
1722 OSMO_ASSERT(check_local_cx_options(ctx, "10, a:PCMU") == -1);
1723 OSMO_ASSERT(check_local_cx_options(ctx, ", a:PCMU") == -1);
1724 OSMO_ASSERT(check_local_cx_options(ctx, " a:PCMU") == -1);
1725 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU,") == -1);
1726 OSMO_ASSERT(check_local_cx_options(ctx, "a:PCMU, ") == -1);
1727
1728 /* Illegal strings */
1729 OSMO_ASSERT(check_local_cx_options(ctx, " ") == -1);
1730 OSMO_ASSERT(check_local_cx_options(ctx, "") == -1);
1731 OSMO_ASSERT(check_local_cx_options(ctx, "AAA") == -1);
1732 OSMO_ASSERT(check_local_cx_options(ctx, ":,") == -1);
1733 OSMO_ASSERT(check_local_cx_options(ctx, ",:") == -1);
1734 OSMO_ASSERT(check_local_cx_options(ctx, ",,,") == -1);
1735}
1736
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001737static const struct mgcp_codec_param amr_param_octet_aligned_true = {
1738 .amr_octet_aligned_present = true,
1739 .amr_octet_aligned = true,
1740};
1741
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001742static const struct mgcp_codec_param amr_param_octet_aligned_false = {
1743 .amr_octet_aligned_present = true,
1744 .amr_octet_aligned = false,
1745};
1746
1747static const struct mgcp_codec_param amr_param_octet_aligned_unset = {
1748 .amr_octet_aligned_present = false,
1749};
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001750
1751struct testcase_mgcp_codec_pt_translate_codec {
1752 int payload_type;
1753 const char *audio_name;
1754 const struct mgcp_codec_param *param;
1755 int expect_rc;
1756};
1757
1758struct testcase_mgcp_codec_pt_translate_expect {
1759 bool end;
1760 int payload_type_map[2];
1761};
1762
1763struct testcase_mgcp_codec_pt_translate {
1764 const char *descr;
1765 /* two conns on an endpoint, each with N configured codecs */
1766 struct testcase_mgcp_codec_pt_translate_codec codecs[2][10];
1767 struct testcase_mgcp_codec_pt_translate_expect expect[32];
1768};
1769
1770static const struct testcase_mgcp_codec_pt_translate test_mgcp_codec_pt_translate_cases[] = {
1771 {
1772 .descr = "same order, but differing payload type numbers",
1773 .codecs = {
1774 {
1775 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1776 { 0, "PCMU/8000/1", NULL, },
1777 { 111, "GSM-HR-08/8000/1", NULL, },
1778 },
1779 {
1780 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1781 { 0, "PCMU/8000/1", NULL, },
1782 { 97, "GSM-HR-08/8000/1", NULL, },
1783 },
1784 },
1785 .expect = {
1786 { .payload_type_map = {112, 96}, },
1787 { .payload_type_map = {0, 0}, },
1788 { .payload_type_map = {111, 97} },
1789 { .payload_type_map = {123, -EINVAL} },
1790 { .end = true },
1791 },
1792 },
1793 {
Neels Hofmeyr26985402019-08-08 22:39:55 +02001794 .descr = "different order and different payload type numbers",
1795 .codecs = {
1796 {
1797 { 0, "PCMU/8000/1", NULL, },
1798 { 111, "GSM-HR-08/8000/1", NULL, },
1799 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1800 },
1801 {
1802 { 97, "GSM-HR-08/8000/1", NULL, },
1803 { 0, "PCMU/8000/1", NULL, },
1804 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1805 },
1806 },
1807 .expect = {
1808 { .payload_type_map = {112, 96}, },
1809 { .payload_type_map = {0, 0}, },
1810 { .payload_type_map = {111, 97} },
1811 { .payload_type_map = {123, -EINVAL} },
1812 { .end = true },
1813 },
1814 },
1815 {
1816 .descr = "both sides have the same payload_type numbers assigned to differing codecs",
1817 .codecs = {
1818 {
1819 { 0, "PCMU/8000/1", NULL, },
1820 { 96, "GSM-HR-08/8000/1", NULL, },
1821 { 97, "AMR/8000/1", &amr_param_octet_aligned_true, },
1822 },
1823 {
1824 { 97, "GSM-HR-08/8000/1", NULL, },
1825 { 0, "PCMU/8000/1", NULL, },
1826 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1827 },
1828 },
1829 .expect = {
1830 { .payload_type_map = {96, 97}, },
1831 { .payload_type_map = {97, 96}, },
1832 { .payload_type_map = {0, 0}, },
1833 { .end = true },
1834 },
1835 },
1836 {
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001837 .descr = "conn0 has no codecs",
1838 .codecs = {
1839 {
1840 /* no codecs */
1841 },
1842 {
1843 { 96, "AMR/8000/1", &amr_param_octet_aligned_true, },
1844 { 0, "PCMU/8000/1", NULL, },
1845 { 97, "GSM-HR-08/8000/1", NULL, },
1846 },
1847 },
1848 .expect = {
1849 { .payload_type_map = {112, -EINVAL}, },
1850 { .payload_type_map = {0, -EINVAL}, },
1851 { .payload_type_map = {111, -EINVAL} },
1852 { .end = true },
1853 },
1854 },
1855 {
1856 .descr = "conn1 has no codecs",
1857 .codecs = {
1858 {
1859 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1860 { 0, "PCMU/8000/1", NULL, },
1861 { 111, "GSM-HR-08/8000/1", NULL, },
1862 },
1863 {
1864 /* no codecs */
1865 },
1866 },
1867 .expect = {
1868 { .payload_type_map = {112, -EINVAL}, },
1869 { .payload_type_map = {0, -EINVAL}, },
1870 { .payload_type_map = {111, -EINVAL} },
1871 { .end = true },
1872 },
1873 },
Neels Hofmeyr16b637b2019-08-08 22:47:10 +02001874 {
1875 .descr = "test AMR with differing octet-aligned settings",
1876 .codecs = {
1877 {
1878 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1879 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1880 },
1881 {
1882 { 122, "AMR/8000", &amr_param_octet_aligned_false, },
1883 { 121, "AMR/8000", &amr_param_octet_aligned_true, },
1884 },
1885 },
1886 .expect = {
1887 { .payload_type_map = {111, 121}, },
1888 { .payload_type_map = {112, 122} },
1889 { .end = true },
1890 },
1891 },
1892 {
1893 .descr = "test AMR with missing octet-aligned settings (defaults to 0)",
1894 .codecs = {
1895 {
1896 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1897 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1898 },
1899 {
1900 { 122, "AMR/8000", &amr_param_octet_aligned_unset, },
1901 },
1902 },
1903 .expect = {
1904 { .payload_type_map = {111, -EINVAL}, },
1905 { .payload_type_map = {112, 122} },
1906 { .end = true },
1907 },
1908 },
1909 {
1910 .descr = "test AMR with NULL param (defaults to 0)",
1911 .codecs = {
1912 {
1913 { 111, "AMR/8000", &amr_param_octet_aligned_true, },
1914 { 112, "AMR/8000", &amr_param_octet_aligned_false, },
1915 },
1916 {
1917 { 122, "AMR/8000", NULL, },
1918 },
1919 },
1920 .expect = {
1921 { .payload_type_map = {111, -EINVAL}, },
1922 { .payload_type_map = {112, 122} },
1923 { .end = true },
1924 },
1925 },
Neels Hofmeyr683e05f2019-08-08 22:48:18 +02001926 {
1927 .descr = "match FOO/8000/1 and FOO/8000 as identical, single channel is implicit",
1928 .codecs = {
1929 {
1930 { 0, "PCMU/8000/1", NULL, },
1931 { 111, "GSM-HR-08/8000/1", NULL, },
1932 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1933 },
1934 {
1935 { 97, "GSM-HR-08/8000", NULL, },
1936 { 0, "PCMU/8000", NULL, },
1937 { 96, "AMR/8000", &amr_param_octet_aligned_true, },
1938 },
1939 },
1940 .expect = {
1941 { .payload_type_map = {112, 96}, },
1942 { .payload_type_map = {0, 0}, },
1943 { .payload_type_map = {111, 97} },
1944 { .payload_type_map = {123, -EINVAL} },
1945 { .end = true },
1946 },
1947 },
1948 {
1949 .descr = "match FOO/8000/1 and FOO as identical, 8k and single channel are implicit",
1950 .codecs = {
1951 {
1952 { 0, "PCMU/8000/1", NULL, },
1953 { 111, "GSM-HR-08/8000/1", NULL, },
1954 { 112, "AMR/8000/1", &amr_param_octet_aligned_true, },
1955 },
1956 {
1957 { 97, "GSM-HR-08", NULL, },
1958 { 0, "PCMU", NULL, },
1959 { 96, "AMR", &amr_param_octet_aligned_true, },
1960 },
1961 },
1962 .expect = {
1963 { .payload_type_map = {112, 96}, },
1964 { .payload_type_map = {0, 0}, },
1965 { .payload_type_map = {111, 97} },
1966 { .payload_type_map = {123, -EINVAL} },
1967 { .end = true },
1968 },
1969 },
1970 {
1971 .descr = "test whether channel number matching is waterproof",
1972 .codecs = {
1973 {
1974 { 111, "GSM-HR-08/8000", },
1975 { 112, "GSM-HR-08/8000/2", .expect_rc = -22},
1976 { 113, "GSM-HR-08/8000/3", .expect_rc = -22},
1977 },
1978 {
1979 { 122, "GSM-HR-08/8000/2", .expect_rc = -22},
1980 { 121, "GSM-HR-08/8000/1", },
1981 },
1982 },
1983 .expect = {
1984 { .payload_type_map = {111, 121}, },
1985 { .payload_type_map = {112, -EINVAL} },
1986 { .payload_type_map = {113, -EINVAL} },
1987 { .end = true },
1988 },
1989 },
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001990};
Philipp Maier6931f9a2018-07-26 09:29:31 +02001991
1992static void test_mgcp_codec_pt_translate(void)
1993{
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001994 int i;
1995 bool ok = true;
1996 printf("\nTesting mgcp_codec_pt_translate()\n");
Philipp Maier6931f9a2018-07-26 09:29:31 +02001997
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02001998 for (i = 0; i < ARRAY_SIZE(test_mgcp_codec_pt_translate_cases); i++) {
1999 const struct testcase_mgcp_codec_pt_translate *t = &test_mgcp_codec_pt_translate_cases[i];
2000 struct mgcp_conn_rtp conn[2] = {};
2001 int rc;
2002 int conn_i;
2003 int c;
Philipp Maier6931f9a2018-07-26 09:29:31 +02002004
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002005 printf("#%d: %s\n", i, t->descr);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002006
Neels Hofmeyrd2f5e692019-08-08 21:59:26 +02002007 for (conn_i = 0; conn_i < 2; conn_i++) {
2008 printf(" - add codecs on conn%d:\n", conn_i);
2009 for (c = 0; c < ARRAY_SIZE(t->codecs[conn_i]); c++) {
2010 const struct testcase_mgcp_codec_pt_translate_codec *codec = &t->codecs[conn_i][c];
2011 if (!codec->audio_name)
2012 break;
2013
2014 rc = mgcp_codec_add(&conn[conn_i], codec->payload_type, codec->audio_name, codec->param);
2015
2016 printf(" %2d: %3d %s%s -> rc=%d\n", c, codec->payload_type, codec->audio_name,
2017 codec->param ?
2018 (codec->param->amr_octet_aligned_present?
2019 (codec->param->amr_octet_aligned ?
2020 " octet-aligned=1" : " octet-aligned=0")
2021 : " octet-aligned=unset")
2022 : "",
2023 rc);
2024 if (rc != codec->expect_rc) {
2025 printf(" ERROR: expected rc=%d\n", codec->expect_rc);
2026 ok = false;
2027 }
2028 }
2029 if (!c)
2030 printf(" (none)\n");
2031 }
2032
2033 for (c = 0; c < ARRAY_SIZE(t->expect); c++) {
2034 const struct testcase_mgcp_codec_pt_translate_expect *expect = &t->expect[c];
2035 int result;
2036
2037 if (expect->end)
2038 break;
2039
2040 result = mgcp_codec_pt_translate(&conn[0], &conn[1], expect->payload_type_map[0]);
2041 printf(" - mgcp_codec_pt_translate(conn0, conn1, %d) -> %d\n",
2042 expect->payload_type_map[0], result);
2043 if (result != expect->payload_type_map[1]) {
2044 printf(" ERROR: expected -> %d\n", expect->payload_type_map[1]);
2045 ok = false;
2046 }
2047
2048 /* If the expected result is an error, don't do reverse map test */
2049 if (expect->payload_type_map[1] < 0)
2050 continue;
2051
2052 result = mgcp_codec_pt_translate(&conn[1], &conn[0], expect->payload_type_map[1]);
2053 printf(" - mgcp_codec_pt_translate(conn1, conn0, %d) -> %d\n",
2054 expect->payload_type_map[1], result);
2055 if (result != expect->payload_type_map[0]) {
2056 printf(" ERROR: expected -> %d\n", expect->payload_type_map[0]);
2057 ok = false;
2058 }
2059 }
2060
2061 for (conn_i = 0; conn_i < 2; conn_i++)
2062 mgcp_codec_reset_all(&conn[conn_i]);
2063 }
2064
2065 OSMO_ASSERT(ok);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002066}
2067
Neels Hofmeyr65317262018-09-03 22:11:05 +02002068void test_conn_id_matching()
2069{
2070 struct mgcp_endpoint endp = {};
2071 struct mgcp_conn *conn;
2072 struct mgcp_conn *conn_match;
2073 int i;
2074 const char *conn_id_generated = "000023AB";
2075 const char *conn_id_request[] = {
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002076 "23AB",
2077 "0023AB",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002078 "000023AB",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002079 "00000023AB",
2080 "23ab",
2081 "0023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002082 "000023ab",
Neels Hofmeyra77eade2018-08-29 02:30:39 +02002083 "00000023ab",
Neels Hofmeyr65317262018-09-03 22:11:05 +02002084 };
2085
2086 printf("\nTesting %s\n", __func__);
2087
2088 INIT_LLIST_HEAD(&endp.conns);
2089
2090 conn = talloc_zero(NULL, struct mgcp_conn);
2091 OSMO_ASSERT(conn);
2092 osmo_strlcpy(conn->id, conn_id_generated, sizeof(conn->id));
2093 llist_add(&conn->entry, &endp.conns);
2094
2095 for (i = 0; i < ARRAY_SIZE(conn_id_request); i++) {
2096 const char *needle = conn_id_request[i];
2097 printf("needle='%s' ", needle);
2098 conn_match = mgcp_conn_get(&endp, needle);
2099 OSMO_ASSERT(conn_match);
2100 printf("found '%s'\n", conn_match->id);
2101 OSMO_ASSERT(conn_match == conn);
2102 }
2103
2104 llist_del(&conn->entry);
2105 talloc_free(conn);
2106}
2107
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002108int main(int argc, char **argv)
2109{
Neels Hofmeyr60f8e312018-03-30 23:01:07 +02002110 void *ctx = talloc_named_const(NULL, 0, "mgcp_test");
2111 void *msgb_ctx = msgb_talloc_ctx_init(ctx, 0);
2112 osmo_init_logging2(ctx, &log_info);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002113
2114 test_strline();
2115 test_values();
2116 test_messages();
2117 test_retransmission();
2118 test_packet_loss_calc();
2119 test_rqnt_cb();
2120 test_mgcp_stats();
2121 test_packet_error_detection(1, 0);
2122 test_packet_error_detection(0, 0);
2123 test_packet_error_detection(0, 1);
2124 test_packet_error_detection(1, 1);
2125 test_multilple_codec();
2126 test_no_cycle();
2127 test_no_name();
2128 test_osmux_cid();
Philipp Maier3d7b58d2018-06-06 09:35:31 +02002129 test_get_lco_identifier();
2130 test_check_local_cx_options(ctx);
Philipp Maier6931f9a2018-07-26 09:29:31 +02002131 test_mgcp_codec_pt_translate();
Neels Hofmeyr65317262018-09-03 22:11:05 +02002132 test_conn_id_matching();
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002133
Neels Hofmeyr465446b2017-11-18 21:26:26 +01002134 OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0);
2135 OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1);
2136 talloc_free(msgb_ctx);
Neels Hofmeyrf83ec562017-09-07 19:18:40 +02002137 printf("Done\n");
2138 return EXIT_SUCCESS;
2139}