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