1 /*
2 liblinphone_tester - liblinphone test suite
3 Copyright (C) 2015 Belledonne Communications SARL
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19
20 #include "linphone/core.h"
21 #include "liblinphone_tester.h"
22 #include "linphone/lpconfig.h"
23 #include "private.h"
24
25
26 #if HAVE_SIPP
check_rtcp(LinphoneCall * call)27 void check_rtcp(LinphoneCall *call) {
28 MSTimeSpec ts;
29 LinphoneCallStats *audio_stats, *video_stats;
30
31 linphone_call_ref(call);
32 liblinphone_tester_clock_start(&ts);
33
34 do {
35 audio_stats = linphone_call_get_audio_stats(call);
36 video_stats = linphone_call_get_video_stats(call);
37 if (linphone_call_stats_get_round_trip_delay(audio_stats) > 0.0 && (!linphone_call_log_video_enabled(linphone_call_get_call_log(call)) || linphone_call_stats_get_round_trip_delay(video_stats) > 0.0)) {
38 break;
39 }
40 linphone_call_stats_unref(audio_stats);
41 if (video_stats) linphone_call_stats_unref(video_stats);
42 wait_for_until(call->core, NULL, NULL, 0, 20); /*just to sleep while iterating*/
43 } while (!liblinphone_tester_clock_elapsed(&ts, 15000));
44
45 audio_stats = linphone_call_get_audio_stats(call);
46 BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(audio_stats), 0.0, float, "%f");
47 if (linphone_call_log_video_enabled(linphone_call_get_call_log(call))) {
48 video_stats = linphone_call_get_video_stats(call);
49 BC_ASSERT_GREATER(linphone_call_stats_get_round_trip_delay(video_stats), 0.0, float, "%f");
50 linphone_call_stats_unref(video_stats);
51 }
52 linphone_call_stats_unref(audio_stats);
53
54 linphone_call_unref(call);
55 }
56
sip_start(const char * senario,const char * dest_username,const char * passwd,LinphoneAddress * dest_addres)57 FILE *sip_start(const char *senario, const char* dest_username, const char *passwd, LinphoneAddress* dest_addres) {
58 char *dest;
59 char *command;
60 FILE *file;
61
62 if (linphone_address_get_port(dest_addres)>0)
63 dest = ms_strdup_printf("%s:%i",linphone_address_get_domain(dest_addres),linphone_address_get_port(dest_addres));
64 else
65 dest = ms_strdup_printf("%s",linphone_address_get_domain(dest_addres));
66 //until errors logs are handled correctly and stop breaks output, they will be DISABLED
67 command = ms_strdup_printf(SIPP_COMMAND" -sf %s -s %s %s -trace_err -trace_msg -rtp_echo -m 1 -d 1000 -ap %s 2>/dev/null",senario
68 ,dest_username
69 ,dest
70 ,(passwd?passwd:"none"));
71
72 ms_message("Starting sipp command [%s]",command);
73 file = popen(command, "r");
74 ms_free(command);
75 ms_free(dest);
76 return file;
77 }
78
79
sip_start_recv(const char * senario)80 static FILE *sip_start_recv(const char *senario) {
81 char *command;
82 FILE *file;
83
84 //until errors logs are handled correctly and stop breaks output, they will be DISABLED
85 command = ms_strdup_printf(SIPP_COMMAND" -sf %s -trace_err -trace_msg -rtp_echo -m 1 -d 1000 2>/dev/null",senario);
86
87 ms_message("Starting sipp command [%s]",command);
88 file = popen(command, "r");
89 ms_free(command);
90 return file;
91 }
92
dest_server_server_resolved(void * data,const char * name,struct addrinfo * ai_list,uint32_t ttl)93 static void dest_server_server_resolved(void *data, const char *name, struct addrinfo *ai_list, uint32_t ttl) {
94 *(struct addrinfo **)data =ai_list;
95 }
96
linphone_core_manager_resolve(LinphoneCoreManager * mgr,const LinphoneAddress * source)97 LinphoneAddress * linphone_core_manager_resolve(LinphoneCoreManager *mgr, const LinphoneAddress *source) {
98 struct addrinfo *addrinfo = NULL;
99 char ipstring [INET6_ADDRSTRLEN];
100 int err;
101 int port = linphone_address_get_port(source);
102 LinphoneAddress * dest;
103
104 sal_resolve_a( mgr->lc->sal
105 ,linphone_address_get_domain(source)
106 ,linphone_address_get_port(source)
107 ,AF_INET
108 ,dest_server_server_resolved
109 ,&addrinfo);
110
111 dest=linphone_address_new(NULL);
112
113 wait_for(mgr->lc, mgr->lc, (int*)&addrinfo, 1);
114 err=bctbx_getnameinfo((struct sockaddr*)addrinfo->ai_addr,addrinfo->ai_addrlen,ipstring,INET6_ADDRSTRLEN,NULL,0,NI_NUMERICHOST);
115 if (err !=0 ){
116 ms_error("linphone_core_manager_resolve(): getnameinfo error %s", gai_strerror(err));
117 }
118 linphone_address_set_domain(dest, ipstring);
119 if (port > 0)
120 linphone_address_set_port(dest, port);
121
122 return dest;
123 }
124
125
sip_update_within_icoming_reinvite_with_no_sdp(void)126 static void sip_update_within_icoming_reinvite_with_no_sdp(void) {
127 LinphoneCoreManager *mgr;
128 char *identity_char;
129 char *scen;
130 FILE * sipp_out;
131
132 /*currently we use direct connection because sipp do not properly set ACK request uri*/
133 mgr= linphone_core_manager_new2( "empty_rc", FALSE);
134 mgr->identity= linphone_core_get_primary_contact_parsed(mgr->lc);
135 linphone_address_set_username(mgr->identity,"marie");
136 identity_char=linphone_address_as_string(mgr->identity);
137 linphone_core_set_primary_contact(mgr->lc,identity_char);
138 linphone_core_iterate(mgr->lc);
139 scen = bc_tester_res("sipp/sip_update_within_icoming_reinvite_with_no_sdp.xml");
140 sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity),NULL, mgr->identity);
141
142 if (sipp_out) {
143 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
144 linphone_call_accept(linphone_core_get_current_call(mgr->lc));
145 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 2));
146 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
147 pclose(sipp_out);
148 }
149 linphone_core_manager_destroy(mgr);
150 }
151
call_with_audio_mline_before_video_in_sdp(void)152 static void call_with_audio_mline_before_video_in_sdp(void) {
153 LinphoneCoreManager *mgr;
154 char *identity_char;
155 char *scen;
156 FILE * sipp_out;
157 LinphoneCall *call = NULL;
158
159 /*currently we use direct connection because sipp do not properly set ACK request uri*/
160 mgr= linphone_core_manager_new2( "empty_rc", FALSE);
161 mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
162 linphone_address_set_username(mgr->identity,"marie");
163 identity_char = linphone_address_as_string(mgr->identity);
164 linphone_core_set_primary_contact(mgr->lc,identity_char);
165
166 linphone_core_iterate(mgr->lc);
167
168 scen = bc_tester_res("sipp/call_with_audio_mline_before_video_in_sdp.xml");
169
170 sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
171
172 if (sipp_out) {
173 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
174 call = linphone_core_get_current_call(mgr->lc);
175 BC_ASSERT_PTR_NOT_NULL(call);
176 if (call) {
177 linphone_call_accept(call);
178 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
179 BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d");
180 BC_ASSERT_EQUAL(call->main_video_stream_index, 1, int, "%d");
181 BC_ASSERT_TRUE(call->main_text_stream_index > 1);
182 BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));
183
184 check_rtcp(call);
185 }
186
187 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
188 pclose(sipp_out);
189 }
190 linphone_core_manager_destroy(mgr);
191 }
192
call_with_video_mline_before_audio_in_sdp(void)193 static void call_with_video_mline_before_audio_in_sdp(void) {
194 LinphoneCoreManager *mgr;
195 char *identity_char;
196 char *scen;
197 FILE * sipp_out;
198 LinphoneCall *call = NULL;
199
200 /*currently we use direct connection because sipp do not properly set ACK request uri*/
201 mgr= linphone_core_manager_new2( "empty_rc", FALSE);
202 mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
203 linphone_address_set_username(mgr->identity,"marie");
204 identity_char = linphone_address_as_string(mgr->identity);
205 linphone_core_set_primary_contact(mgr->lc,identity_char);
206
207 linphone_core_iterate(mgr->lc);
208
209 scen = bc_tester_res("sipp/call_with_video_mline_before_audio_in_sdp.xml");
210
211 sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
212
213 if (sipp_out) {
214 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
215 call = linphone_core_get_current_call(mgr->lc);
216 BC_ASSERT_PTR_NOT_NULL(call);
217 if (call) {
218 linphone_call_accept(call);
219 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
220 BC_ASSERT_EQUAL(call->main_audio_stream_index, 1, int, "%d");
221 BC_ASSERT_EQUAL(call->main_video_stream_index, 0, int, "%d");
222 BC_ASSERT_TRUE(call->main_text_stream_index > 1);
223 BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));
224
225 check_rtcp(call);
226 }
227
228 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
229 pclose(sipp_out);
230 }
231 linphone_core_manager_destroy(mgr);
232 }
233
call_with_multiple_audio_mline_in_sdp(void)234 static void call_with_multiple_audio_mline_in_sdp(void) {
235 LinphoneCoreManager *mgr;
236 char *identity_char;
237 char *scen;
238 FILE * sipp_out;
239 LinphoneCall *call = NULL;
240
241 /*currently we use direct connection because sipp do not properly set ACK request uri*/
242 mgr= linphone_core_manager_new2( "empty_rc", FALSE);
243 mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
244 linphone_address_set_username(mgr->identity,"marie");
245 identity_char = linphone_address_as_string(mgr->identity);
246 linphone_core_set_primary_contact(mgr->lc,identity_char);
247
248 linphone_core_iterate(mgr->lc);
249
250 scen = bc_tester_res("sipp/call_with_multiple_audio_mline_in_sdp.xml");
251
252 sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
253
254 if (sipp_out) {
255 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
256 call = linphone_core_get_current_call(mgr->lc);
257 BC_ASSERT_PTR_NOT_NULL(call);
258 if (call) {
259 linphone_call_accept(call);
260 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
261 BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d");
262 BC_ASSERT_EQUAL(call->main_video_stream_index, 2, int, "%d");
263 BC_ASSERT_TRUE(call->main_text_stream_index > 2);
264 BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));
265
266 check_rtcp(call);
267 }
268
269 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
270 pclose(sipp_out);
271 }
272 linphone_core_manager_destroy(mgr);
273 }
274
call_with_multiple_video_mline_in_sdp(void)275 static void call_with_multiple_video_mline_in_sdp(void) {
276 LinphoneCoreManager *mgr;
277 char *identity_char;
278 char *scen;
279 FILE * sipp_out;
280 LinphoneCall *call = NULL;
281
282 /*currently we use direct connection because sipp do not properly set ACK request uri*/
283 mgr= linphone_core_manager_new2( "empty_rc", FALSE);
284 mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
285 linphone_address_set_username(mgr->identity,"marie");
286 identity_char = linphone_address_as_string(mgr->identity);
287 linphone_core_set_primary_contact(mgr->lc,identity_char);
288
289 linphone_core_iterate(mgr->lc);
290
291 scen = bc_tester_res("sipp/call_with_multiple_video_mline_in_sdp.xml");
292
293 sipp_out = sip_start(scen, linphone_address_get_username(mgr->identity), NULL, mgr->identity);
294
295 if (sipp_out) {
296 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallIncomingReceived, 1));
297 call = linphone_core_get_current_call(mgr->lc);
298 BC_ASSERT_PTR_NOT_NULL(call);
299 if (call) {
300 linphone_call_accept(call);
301 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallStreamsRunning, 1));
302 BC_ASSERT_EQUAL(call->main_audio_stream_index, 0, int, "%d");
303 BC_ASSERT_EQUAL(call->main_video_stream_index, 1, int, "%d");
304 BC_ASSERT_TRUE(call->main_text_stream_index > 3);
305 BC_ASSERT_TRUE(linphone_call_log_video_enabled(linphone_call_get_call_log(call)));
306
307 check_rtcp(call);
308 }
309
310 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
311 pclose(sipp_out);
312 }
313 linphone_core_manager_destroy(mgr);
314 }
315
316
call_invite_200ok_without_contact_header(void)317 static void call_invite_200ok_without_contact_header(void) {
318 LinphoneCoreManager *mgr;
319 char *identity_char;
320 char *scen;
321 FILE * sipp_out;
322 LinphoneCall *call = NULL;
323
324 /*currently we use direct connection because sipp do not properly set ACK request uri*/
325 mgr= linphone_core_manager_new2("empty_rc", FALSE);
326 mgr->identity = linphone_core_get_primary_contact_parsed(mgr->lc);
327 linphone_address_set_username(mgr->identity,"marie");
328 identity_char = linphone_address_as_string(mgr->identity);
329 linphone_core_set_primary_contact(mgr->lc,identity_char);
330
331 linphone_core_iterate(mgr->lc);
332
333 scen = bc_tester_res("sipp/call_invite_200ok_without_contact_header.xml");
334
335 sipp_out = sip_start_recv(scen);
336
337 if (sipp_out) {
338 call = linphone_core_invite(mgr->lc, "sipp@127.0.0.1");
339 BC_ASSERT_PTR_NOT_NULL(call);
340 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallOutgoingInit, 1));
341 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallOutgoingProgress, 1));
342 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallOutgoingRinging, 1));
343 /*assert that the call never gets connected nor terminated*/
344 BC_ASSERT_FALSE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallConnected, 1));
345 BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneCallEnd, 0, int, "%d");
346 BC_ASSERT_EQUAL(mgr->stat.number_of_LinphoneCallError, 0, int, "%d");
347 linphone_call_terminate(call);
348 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallEnd, 1));
349 BC_ASSERT_TRUE(wait_for(mgr->lc, mgr->lc, &mgr->stat.number_of_LinphoneCallReleased, 1));
350 pclose(sipp_out);
351 }
352 linphone_core_manager_destroy(mgr);
353 }
354
355
356 static test_t tests[] = {
357 TEST_NO_TAG("SIP UPDATE within incoming reinvite without sdp", sip_update_within_icoming_reinvite_with_no_sdp),
358 TEST_NO_TAG("Call with audio mline before video in sdp", call_with_audio_mline_before_video_in_sdp),
359 TEST_NO_TAG("Call with video mline before audio in sdp", call_with_video_mline_before_audio_in_sdp),
360 TEST_NO_TAG("Call with multiple audio mline in sdp", call_with_multiple_audio_mline_in_sdp),
361 TEST_NO_TAG("Call with multiple video mline in sdp", call_with_multiple_video_mline_in_sdp),
362 TEST_NO_TAG("Call invite 200ok without contact header", call_invite_200ok_without_contact_header)
363 };
364 #endif
365
366 test_suite_t complex_sip_call_test_suite = {
367 "Complex SIP Case",
368 NULL,
369 NULL,
370 liblinphone_tester_before_each,
371 liblinphone_tester_after_each,
372 #if HAVE_SIPP
373 sizeof(tests) / sizeof(tests[0]),
374 tests
375 #else
376 0,
377 NULL
378 #endif
379 };
380