belle_sip_resolver_tester.c 26.3 KB
Newer Older
Ghislain MARY's avatar
Ghislain MARY committed
1
/*
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 * Copyright (c) 2012-2019 Belledonne Communications SARL.
 *
 * This file is part of belle-sip.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
Ghislain MARY's avatar
Ghislain MARY committed
19 20 21

#include "belle-sip/belle-sip.h"
#include "belle_sip_internal.h"
Ghislain MARY's avatar
Ghislain MARY committed
22
#include "belle_sip_tester.h"
Ghislain MARY's avatar
Ghislain MARY committed
23 24


25
#define IPV4_SIP_DOMAIN		"sip.linphone.org"
26
#define IPV4_SIP_IP		"91.121.209.194"
27
#define IPV4_CNAME		"stun.linphone.org"
28
#define IPV4_CNAME_IP		"54.37.202.229"
29
#define IPV4_SIP_BAD_DOMAIN	"dummy.linphone.org"
Simon Morlat's avatar
Simon Morlat committed
30
#define IPV4_MULTIRES_DOMAIN	"yahoo.fr"
31

32 33 34
/* sip2.linphone.org has an IPv6 and an IPv4 IP*/
#define IPV6_SIP_DOMAIN		"sip2.linphone.org"
#define IPV6_SIP_IP		"2001:41d0:2:14b0::1"
35 36
#define IPV6_SIP_IPV4		"88.191.250.2"

Simon Morlat's avatar
Simon Morlat committed
37
#define SRV_DOMAIN		"linphone.org"
38
#define SIP_PORT		5060
Ghislain MARY's avatar
Ghislain MARY committed
39 40 41

typedef struct endpoint {
	belle_sip_stack_t* stack;
42
	belle_sip_resolver_context_t *resolver_ctx;
43
	int resolve_done;
44
	int resolve_ko;
45 46 47
	bctbx_list_t *srv_list;
	belle_sip_resolver_results_t *results;
	const struct addrinfo *ai_list;
Ghislain MARY's avatar
Ghislain MARY committed
48 49 50 51
} endpoint_t;

static unsigned int  wait_for(belle_sip_stack_t *stack, int *current_value, int expected_value, int timeout) {
#define ITER 100
52 53 54 55
	uint64_t begin, end;
	begin = belle_sip_time_ms();
	end = begin + timeout;
	while ((*current_value != expected_value) && (belle_sip_time_ms() < end)) {
Ghislain MARY's avatar
Ghislain MARY committed
56 57 58 59 60 61
		if (stack) belle_sip_stack_sleep(stack, ITER);
	}
	if (*current_value != expected_value) return FALSE;
	else return TRUE;
}

62
static endpoint_t* create_endpoint(void) {
63 64
	endpoint_t* endpoint;
	endpoint = belle_sip_new0(endpoint_t);
Ghislain MARY's avatar
Ghislain MARY committed
65 66 67 68
	endpoint->stack = belle_sip_stack_new(NULL);
	return endpoint;
}

69
static void reset_endpoint(endpoint_t *endpoint) {
70
	endpoint->resolver_ctx = 0;
71
	endpoint->resolve_done = 0;
72
	endpoint->resolve_ko = 0;
73 74 75
	if (endpoint->results) {
		belle_sip_object_unref(endpoint->results);
		endpoint->results = NULL;
76
	}
77 78 79
	endpoint->ai_list = NULL;
	if (endpoint->srv_list){
		bctbx_list_free_with_data(endpoint->srv_list, belle_sip_object_unref);
80
		endpoint->srv_list = NULL;
81
	}
82 83 84
}

static void destroy_endpoint(endpoint_t *endpoint) {
85
	reset_endpoint(endpoint);
Ghislain MARY's avatar
Ghislain MARY committed
86 87
	belle_sip_object_unref(endpoint->stack);
	belle_sip_free(endpoint);
88
	belle_sip_uninit_sockets();
Ghislain MARY's avatar
Ghislain MARY committed
89 90
}

91
static void a_resolve_done(void *data, belle_sip_resolver_results_t *results) {
92
	endpoint_t *client = (endpoint_t *)data;
93

94
	client->resolve_done = 1;
95 96 97 98
	belle_sip_object_ref(results);
	client->results = results;
	if (belle_sip_resolver_results_get_addrinfos(results)) {
		client->ai_list = belle_sip_resolver_results_get_addrinfos(results);
99 100 101 102 103
		client->resolve_done = 1;
	} else
		client->resolve_ko = 1;
}

104
static void srv_resolve_done(void *data, const char *name, belle_sip_list_t *srv_list, uint32_t ttl) {
Ghislain MARY's avatar
Ghislain MARY committed
105
	endpoint_t *client = (endpoint_t *)data;
106
	BELLESIP_UNUSED(name);
107
	client->resolve_done = 1;
108 109
	if (srv_list) {
		client->srv_list = srv_list;
110 111 112
		client->resolve_done = 1;
	} else
		client->resolve_ko = 1;
Ghislain MARY's avatar
Ghislain MARY committed
113 114
}

Ghislain MARY's avatar
Ghislain MARY committed
115 116
/* Successful IPv4 A query */
static void ipv4_a_query(void) {
117
	struct addrinfo *ai;
118
	int timeout;
119
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
120

121
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
122
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
123
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
124 125 126
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);
127 128
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
129 130
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
131
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
132
		if (ai) {
133
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
134
			bctbx_freeaddrinfo(ai);
135 136 137
		}
	}

Ghislain MARY's avatar
Ghislain MARY committed
138 139 140
	destroy_endpoint(client);
}

141 142 143 144 145 146 147
/* Successful IPv4 A query to a CNAME*/
/*This tests the recursion of dns.c*/
static void ipv4_cname_a_query(void) {
	struct addrinfo *ai;
	int timeout;
	endpoint_t *client = create_endpoint();

148
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
149 150
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_CNAME, SIP_PORT, AF_INET, a_resolve_done, client);
151 152 153
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
154 155
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
156 157
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
158
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_CNAME_IP, SIP_PORT);
159
		if (ai) {
160
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
161
			bctbx_freeaddrinfo(ai);
162 163 164 165 166 167
		}
	}

	destroy_endpoint(client);
}

168 169 170 171
static void local_query(void) {
	int timeout;
	endpoint_t *client = create_endpoint();

172
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
173 174
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, "localhost", SIP_PORT, AF_INET, a_resolve_done, client);
175 176
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
177 178
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
179 180
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
181 182 183 184 185
	}
	destroy_endpoint(client);
}


Ghislain MARY's avatar
Ghislain MARY committed
186 187 188
/* Successful IPv4 A query with no result */
static void ipv4_a_query_no_result(void) {
	int timeout;
189
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
190

191
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Ghislain MARY's avatar
Ghislain MARY committed
192
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
193
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_BAD_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
194 195 196
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_EQUAL(client->ai_list, NULL);
197

Ghislain MARY's avatar
Ghislain MARY committed
198 199 200 201 202
	destroy_endpoint(client);
}

/* IPv4 A query send failure */
static void ipv4_a_query_send_failure(void) {
203
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
204

205
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
206
	belle_sip_stack_set_resolver_send_error(client->stack, -1);
207
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
208
	BC_ASSERT_PTR_NULL(client->resolver_ctx);
209
	belle_sip_stack_set_resolver_send_error(client->stack, 0);
210

Ghislain MARY's avatar
Ghislain MARY committed
211 212 213 214 215
	destroy_endpoint(client);
}

/* IPv4 A query timeout */
static void ipv4_a_query_timeout(void) {
jehan's avatar
jehan committed
216

217
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
218

219
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
jehan's avatar
jehan committed
220
	belle_sip_stack_set_dns_timeout(client->stack, 0);
221
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, "toto.com", SIP_PORT, AF_INET, a_resolve_done, client);
222 223 224 225
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 2000));
	BC_ASSERT_PTR_EQUAL(client->ai_list, NULL);
	BC_ASSERT_EQUAL(client->resolve_ko,1, int, "%d");
Ghislain MARY's avatar
Ghislain MARY committed
226 227 228
	destroy_endpoint(client);
}

229 230 231
/* Successful IPv4 A query with multiple results */
static void ipv4_a_query_multiple_results(void) {
	int timeout;
232
	endpoint_t *client = create_endpoint();
233

234
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
235
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
236
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_MULTIRES_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
237 238 239
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
240
	if (client->ai_list) {
241
		BC_ASSERT_PTR_NOT_NULL(client->ai_list->ai_next);
242 243 244 245 246
	}

	destroy_endpoint(client);
}

247 248
static void ipv4_a_query_with_v4mapped_results(void) {
	int timeout;
249
	endpoint_t *client;
250

251 252 253 254
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}
255

256
	client = create_endpoint();
257

258
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
259 260
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET6, a_resolve_done, client);
261 262 263
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);
264 265

	destroy_endpoint(client);
266 267 268
}


Ghislain MARY's avatar
Ghislain MARY committed
269 270 271 272
/* Successful IPv6 AAAA query */
static void ipv6_aaaa_query(void) {
	struct addrinfo *ai;
	int timeout;
273 274
	endpoint_t *client;

275 276 277 278 279 280
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}

	client = create_endpoint();
281
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
282 283
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV6_SIP_DOMAIN, SIP_PORT, AF_INET6, a_resolve_done, client);
284 285 286
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
287 288 289
	if (client->ai_list) {
		struct addrinfo *next;
		struct sockaddr_in6 *sock_in6 = (struct sockaddr_in6 *)client->ai_list->ai_addr;
290 291
		int ntohsi = ntohs(sock_in6->sin6_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
292
		/*the IPv6 address shall return first, and must be a real ipv6 address*/
293
		BC_ASSERT_EQUAL(client->ai_list->ai_family,AF_INET6,int,"%d");
294
		BC_ASSERT_FALSE(IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr));
295
		ai = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_STREAM, IPV6_SIP_IP, SIP_PORT);
296
		BC_ASSERT_PTR_NOT_NULL(ai);
297 298 299 300
		if (ai) {
			struct in6_addr *ipv6_address = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
			int i;
			for (i = 0; i < 8; i++) {
301
				BC_ASSERT_EQUAL(sock_in6->sin6_addr.s6_addr[i], ipv6_address->s6_addr[i], int, "%d");
302
			}
303
			bctbx_freeaddrinfo(ai);
304 305
		}
		next=client->ai_list->ai_next;
306
		BC_ASSERT_PTR_NOT_NULL(next);
307
		if (next){
308
			int ntohsi = ntohs(sock_in6->sin6_port);
309
			sock_in6 = (struct sockaddr_in6 *)next->ai_addr;
310
			BC_ASSERT_EQUAL(next->ai_family,AF_INET6,int,"%d");
311
			BC_ASSERT_TRUE(IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr));
312
			BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
313
			ai = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_STREAM, IPV6_SIP_IPV4, SIP_PORT);
314
			BC_ASSERT_PTR_NOT_NULL(ai);
315 316 317 318
			if (ai) {
				struct in6_addr *ipv6_address = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
				int i;
				for (i = 0; i < 8; i++) {
319
					BC_ASSERT_EQUAL(sock_in6->sin6_addr.s6_addr[i], ipv6_address->s6_addr[i], int, "%d");
320
				}
321
				bctbx_freeaddrinfo(ai);
322 323
			}
		}
324
	}
325
	destroy_endpoint(client);
Ghislain MARY's avatar
Ghislain MARY committed
326 327
}

328 329 330
/* Successful SRV query */
static void srv_query(void) {
	int timeout;
331
	endpoint_t *client = create_endpoint();
332

333
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
334
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
335
	client->resolver_ctx = belle_sip_stack_resolve_srv(client->stack, "sip", "udp", SRV_DOMAIN, srv_resolve_done, client);
336 337 338
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_NULL(client->srv_list);
339
	BC_ASSERT_NOT_EQUAL((unsigned int)belle_sip_list_size(client->srv_list), 0,unsigned int,"%u");
340
	if (client->srv_list && (belle_sip_list_size(client->srv_list) > 0)) {
341
		belle_sip_dns_srv_t *result_srv = belle_sip_list_nth_data(client->srv_list, 0);
342
		BC_ASSERT_EQUAL(belle_sip_dns_srv_get_port(result_srv), SIP_PORT, int, "%d");
343 344 345 346 347
	}

	destroy_endpoint(client);
}

348 349 350 351 352
/* Successful SRV + A or AAAA queries */
static void srv_a_query(void) {
	int timeout;
	endpoint_t *client = create_endpoint();

353
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
354
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
355
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "udp", SRV_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
356 357 358
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
359 360 361 362 363 364 365 366 367 368

	destroy_endpoint(client);
}

/* Successful SRV query with no result + A query */
static void srv_a_query_no_srv_result(void) {
	struct addrinfo *ai;
	int timeout;
	endpoint_t *client = create_endpoint();

369
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
370
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
371
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "udp", IPV4_CNAME, SIP_PORT, AF_INET, a_resolve_done, client);
372 373 374
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);
375 376
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
377 378
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
379
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_CNAME_IP, SIP_PORT);
380
		if (ai) {
381
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
382
			bctbx_freeaddrinfo(ai);
383 384 385 386 387 388
		}
	}

	destroy_endpoint(client);
}

389 390 391 392
static void local_full_query(void) {
	int timeout;
	endpoint_t *client = create_endpoint();

393
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
394
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
395
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "localhost", SIP_PORT, AF_INET, a_resolve_done, client);
396 397 398
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
399 400
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
401 402
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
403 404 405 406
	}
	destroy_endpoint(client);
}

407 408 409 410 411
/* No query needed because already resolved */
static void no_query_needed(void) {
	struct addrinfo *ai;
	endpoint_t *client = create_endpoint();

412
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
413
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "udp", IPV4_SIP_IP, SIP_PORT, AF_INET, a_resolve_done, client);
414
	BC_ASSERT_PTR_NULL(client->resolver_ctx);
415 416
	BC_ASSERT_TRUE(client->resolve_done);
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
417 418
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
419 420
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
421
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
422
		if (ai) {
423
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
424
			bctbx_freeaddrinfo(ai);
425 426 427 428 429 430
		}
	}

	destroy_endpoint(client);
}

Simon Morlat's avatar
Simon Morlat committed
431
static void set_custom_resolv_conf(belle_sip_stack_t *stack, const char *ns[3]){
432 433
	char *resolv_file = bc_tester_file("tmp_resolv.conf");
	FILE *f=fopen(resolv_file,"w");
434
	BC_ASSERT_PTR_NOT_NULL(f);
Simon Morlat's avatar
Simon Morlat committed
435 436 437 438 439
	if (f){
		int i;
		for (i=0; i<3; ++i){
			if (ns[i]!=NULL){
				fprintf(f,"nameserver %s\n",ns[i]);
440
			}else break;
Simon Morlat's avatar
Simon Morlat committed
441 442 443
		}
		fclose(f);
	}
444 445
	belle_sip_stack_set_dns_resolv_conf_file(stack, resolv_file);
	free(resolv_file);
Simon Morlat's avatar
Simon Morlat committed
446 447
}

448
static void _dns_fallback(const char *nameservers[]) {
Simon Morlat's avatar
Simon Morlat committed
449 450 451 452
	struct addrinfo *ai;
	int timeout;
	endpoint_t *client = create_endpoint();

453
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Simon Morlat's avatar
Simon Morlat committed
454 455 456
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	set_custom_resolv_conf(client->stack,nameservers);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
457 458 459
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
Simon Morlat's avatar
Simon Morlat committed
460 461
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
462 463
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
464
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
Simon Morlat's avatar
Simon Morlat committed
465
		if (ai) {
466
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
467
			bctbx_freeaddrinfo(ai);
Simon Morlat's avatar
Simon Morlat committed
468 469 470 471 472 473
		}
	}

	destroy_endpoint(client);
}

474 475 476 477 478 479 480 481 482
static void dns_fallback(void) {
	const char *nameservers[]={
		"94.23.19.176", /*linphone.org ; this is not a name server, it will not respond*/
		"8.8.8.8", /* public nameserver, should work*/
		NULL
	};
	_dns_fallback(nameservers);
}

483 484 485 486 487 488
static void dns_fallback_because_of_scope_link_ipv6(void) {
	const char *nameservers[]={
		"fe80::fdc5:99ef:ac05:5c55%enp0s25", /* Scope link IPv6 name server that will not respond */
		"8.8.8.8", /* public nameserver, should work*/
		NULL
	};
489 490
	_dns_fallback(nameservers);
}
491

492 493 494 495 496 497 498
static void dns_fallback_because_of_invalid_ipv6(void) {
	const char *nameservers[]={
		"fe80::ba26:6cff:feb9:145c", /* Invalid IPv6 name server */
		"8.8.8.8", /* public nameserver, should work*/
		NULL
	};
	_dns_fallback(nameservers);
499 500
}

Simon Morlat's avatar
Simon Morlat committed
501 502 503 504 505
static void ipv6_dns_server(void) {
	struct addrinfo *ai;
	int timeout;
	endpoint_t *client;
	const char *nameservers[]={
506
		"2001:4860:4860::8888",
Simon Morlat's avatar
Simon Morlat committed
507 508
		NULL
	};
509

Simon Morlat's avatar
Simon Morlat committed
510 511 512 513
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}
514

Simon Morlat's avatar
Simon Morlat committed
515
	client = create_endpoint();
516
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Simon Morlat's avatar
Simon Morlat committed
517 518 519
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	set_custom_resolv_conf(client->stack,nameservers);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
520 521
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
522
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);
Simon Morlat's avatar
Simon Morlat committed
523 524
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
525 526
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
527
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
Simon Morlat's avatar
Simon Morlat committed
528
		if (ai) {
529
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
530
			bctbx_freeaddrinfo(ai);
Simon Morlat's avatar
Simon Morlat committed
531 532 533 534 535
		}
	}

	destroy_endpoint(client);
}
536

Simon Morlat's avatar
Simon Morlat committed
537 538 539 540 541 542 543 544 545
static void ipv4_and_ipv6_dns_server(void) {
	struct addrinfo *ai;
	int timeout;
	endpoint_t *client;
	const char *nameservers[]={
		"8.8.8.8",
		"2a01:e00::2",
		NULL
	};
546

Simon Morlat's avatar
Simon Morlat committed
547 548 549 550 551
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}
	client = create_endpoint();
552
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Simon Morlat's avatar
Simon Morlat committed
553 554 555
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
	set_custom_resolv_conf(client->stack,nameservers);
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
556 557 558
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
Simon Morlat's avatar
Simon Morlat committed
559 560
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
561 562
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
563
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
Simon Morlat's avatar
Simon Morlat committed
564
		if (ai) {
565
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
566
			bctbx_freeaddrinfo(ai);
Simon Morlat's avatar
Simon Morlat committed
567 568 569 570 571
		}
	}

	destroy_endpoint(client);
}
Ghislain MARY's avatar
Ghislain MARY committed
572

Mickaël Turnel's avatar
Mickaël Turnel committed
573 574 575 576 577 578
#ifdef HAVE_MDNS
static void mdns_register_callback(void *data, int error) {
	int *register_error = (int *)data;
	*register_error = error;
}

579
static void mdns_query_ipv4_or_ipv6(int family) {
Mickaël Turnel's avatar
Mickaël Turnel committed
580 581
	belle_sip_mdns_register_t *reg;
	endpoint_t *client;
582
	int register_error = -1;
Mickaël Turnel's avatar
Mickaël Turnel committed
583 584 585

	client = create_endpoint();

586
	reg = belle_sip_mdns_register("sip", "tcp", "test.linphone.local", NULL, 5060, 10, 100, 3600, mdns_register_callback, &register_error);
Mickaël Turnel's avatar
Mickaël Turnel committed
587 588 589
	BC_ASSERT_PTR_NOT_NULL(reg);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

590
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "test.linphone.local", 5060, family, a_resolve_done, client);
Mickaël Turnel's avatar
Mickaël Turnel committed
591
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
Mickaël Turnel's avatar
Mickaël Turnel committed
592
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
Mickaël Turnel's avatar
Mickaël Turnel committed
593 594 595 596 597 598
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);

	belle_sip_mdns_unregister(reg);
	destroy_endpoint(client);
}

599 600 601 602 603 604 605 606 607 608 609 610 611
static void mdns_query(void) {
	mdns_query_ipv4_or_ipv6(AF_INET);
}

static void mdns_query_ipv6(void) {
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}

	mdns_query_ipv4_or_ipv6(AF_INET6);
}

Mickaël Turnel's avatar
Mickaël Turnel committed
612 613 614 615 616
static void mdns_query_no_result(void) {
	endpoint_t *client;

	client = create_endpoint();

617 618
	/* Wait some time to be sure that the services from last test are stopped */
	wait_for(client->stack, &client->resolve_done, 1, 1000);
619

620
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "test.linphone.local", 5060, AF_INET, a_resolve_done, client);
Mickaël Turnel's avatar
Mickaël Turnel committed
621
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
622
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
Mickaël Turnel's avatar
Mickaël Turnel committed
623 624 625 626 627 628 629 630
	BC_ASSERT_PTR_NULL(client->ai_list);

	destroy_endpoint(client);
}

static void mdns_query_multiple_result(void) {
	belle_sip_mdns_register_t *reg1, *reg2;
	endpoint_t *client;
631
	int register_error = -1;
Mickaël Turnel's avatar
Mickaël Turnel committed
632 633 634

	client = create_endpoint();

635
	reg1 = belle_sip_mdns_register("sip", "tcp", "test.linphone.local", "Register1", 5060, 20, 100, 3600, mdns_register_callback, &register_error);
Mickaël Turnel's avatar
Mickaël Turnel committed
636 637 638
	BC_ASSERT_PTR_NOT_NULL(reg1);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

639
	register_error = -1;
640
	reg2 = belle_sip_mdns_register("sip", "tcp", "test.linphone.local", "Register2", 5070, 10, 100, 3600, mdns_register_callback, &register_error);
Mickaël Turnel's avatar
Mickaël Turnel committed
641 642 643
	BC_ASSERT_PTR_NOT_NULL(reg2);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

644
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "test.linphone.local", 5060, AF_INET, a_resolve_done, client);
Mickaël Turnel's avatar
Mickaël Turnel committed
645
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
646
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
Mickaël Turnel's avatar
Mickaël Turnel committed
647 648 649

	BC_ASSERT_PTR_NOT_NULL(client->ai_list);
	if (client->ai_list) {
Mickaël Turnel's avatar
Mickaël Turnel committed
650 651 652
		/* We need to know if we have two results, if ai_list is != NULL then we have one so we check ai_next */
		BC_ASSERT_PTR_NOT_NULL(client->ai_list->ai_next);

Mickaël Turnel's avatar
Mickaël Turnel committed
653 654 655
		/* The first adress should be the one registered on port 5070 since it has higher priority */
		if (client->ai_list->ai_addr->sa_family == AF_INET) {
			struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
656 657
			int ntohsi = (int)ntohs(sock_in->sin_port);
			BC_ASSERT_EQUAL(ntohsi, 5070, int, "%d");
Mickaël Turnel's avatar
Mickaël Turnel committed
658 659
		} else {
			struct sockaddr_in6 *sock_in = (struct sockaddr_in6 *)client->ai_list->ai_addr;
660 661
			int ntohsi = (int)ntohs(sock_in->sin6_port);
			BC_ASSERT_EQUAL(ntohsi, 5070, int, "%d");
Mickaël Turnel's avatar
Mickaël Turnel committed
662 663 664 665 666 667 668
		}
	}

	belle_sip_mdns_unregister(reg1);
	belle_sip_mdns_unregister(reg2);
	destroy_endpoint(client);
}
669 670 671 672 673 674 675 676

static void mdns_queries(void) {
	belle_sip_mdns_register_t *reg;
	endpoint_t *client;
	int register_error = -1;

	client = create_endpoint();

677 678 679
	/* Wait some time to be sure that the services from last test are stopped */
	wait_for(client->stack, &client->resolve_done, 1, 1000);

680
	reg = belle_sip_mdns_register("sip", "tcp", "test.linphone.local", NULL, 5060, 10, 100, 3600, mdns_register_callback, &register_error);
681 682 683 684 685
	BC_ASSERT_PTR_NOT_NULL(reg);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "test.linphone.local", 5060, AF_INET, a_resolve_done, client);
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
686
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
687 688
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);

Mickaël Turnel's avatar
Mickaël Turnel committed
689
	reset_endpoint(client);
690
	wait_for(client->stack, &client->resolve_done, 1, 5000); // Wait 5 seconds
691 692 693

	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "test.linphone.local", 5060, AF_INET, a_resolve_done, client);
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
694
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
695 696 697 698 699
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);

	belle_sip_mdns_unregister(reg);
	destroy_endpoint(client);
}
Mickaël Turnel's avatar
Mickaël Turnel committed
700 701
#endif

Ghislain MARY's avatar
Ghislain MARY committed
702
test_t resolver_tests[] = {
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720
	TEST_NO_TAG("A query (IPv4)", ipv4_a_query),
	TEST_NO_TAG("A query (IPv4) with CNAME", ipv4_cname_a_query),
	TEST_NO_TAG("A query (IPv4) with no result", ipv4_a_query_no_result),
	TEST_NO_TAG("A query (IPv4) with send failure", ipv4_a_query_send_failure),
	TEST_NO_TAG("A query (IPv4) with timeout", ipv4_a_query_timeout),
	TEST_NO_TAG("A query (IPv4) with multiple results", ipv4_a_query_multiple_results),
	TEST_NO_TAG("A query (IPv4) with AI_V4MAPPED results", ipv4_a_query_with_v4mapped_results),
	TEST_NO_TAG("Local query", local_query),
	TEST_NO_TAG("AAAA query (IPv6)", ipv6_aaaa_query),
	TEST_NO_TAG("SRV query", srv_query),
	TEST_NO_TAG("SRV + A query", srv_a_query),
	TEST_NO_TAG("SRV + A query with no SRV result", srv_a_query_no_srv_result),
	TEST_NO_TAG("Local SRV+A query", local_full_query),
	TEST_NO_TAG("No query needed", no_query_needed),
	TEST_NO_TAG("DNS fallback", dns_fallback),
	TEST_NO_TAG("DNS fallback because of scope link IPv6", dns_fallback_because_of_scope_link_ipv6),
	TEST_NO_TAG("DNS fallback because of invalid IPv6", dns_fallback_because_of_invalid_ipv6),
	TEST_NO_TAG("IPv6 DNS server", ipv6_dns_server),
Mickaël Turnel's avatar
Mickaël Turnel committed
721 722 723
	TEST_NO_TAG("IPv4 and v6 DNS servers", ipv4_and_ipv6_dns_server),
#ifdef HAVE_MDNS
	TEST_NO_TAG("MDNS query", mdns_query),
724
	TEST_NO_TAG("MDNS query with ipv6", mdns_query_ipv6),
Mickaël Turnel's avatar
Mickaël Turnel committed
725
	TEST_NO_TAG("MDNS query with no result", mdns_query_no_result),
726 727
	TEST_NO_TAG("MDNS query with multiple result", mdns_query_multiple_result),
	TEST_NO_TAG("MDNS multiple queries", mdns_queries)
Mickaël Turnel's avatar
Mickaël Turnel committed
728
#endif
Ghislain MARY's avatar
Ghislain MARY committed
729 730
};

731 732
test_suite_t resolver_test_suite = {"Resolver", NULL, NULL, belle_sip_tester_before_each, belle_sip_tester_after_each,
									sizeof(resolver_tests) / sizeof(resolver_tests[0]), resolver_tests};