belle_sip_resolver_tester.c 26.3 KB
Newer Older
Ghislain MARY's avatar
Ghislain MARY committed
1 2 3 4 5 6
/*
	belle-sip - SIP (RFC3261) library.
    Copyright (C) 2010-2013  Belledonne Communications SARL

    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
7
    the Free Software Foundation, either version 2 of the License, or
Ghislain MARY's avatar
Ghislain MARY committed
8 9 10 11 12 13 14 15 16 17 18 19 20
    (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/>.
*/

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


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

31 32 33
/* 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"
34 35
#define IPV6_SIP_IPV4		"88.191.250.2"

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

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

static unsigned int  wait_for(belle_sip_stack_t *stack, int *current_value, int expected_value, int timeout) {
#define ITER 100
51 52 53 54
	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
55 56 57 58 59 60
		if (stack) belle_sip_stack_sleep(stack, ITER);
	}
	if (*current_value != expected_value) return FALSE;
	else return TRUE;
}

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

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

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

90
static void a_resolve_done(void *data, belle_sip_resolver_results_t *results) {
91
	endpoint_t *client = (endpoint_t *)data;
92
	
93
	client->resolve_done = 1;
94 95 96 97
	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);
98 99 100 101 102
		client->resolve_done = 1;
	} else
		client->resolve_ko = 1;
}

103
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
104
	endpoint_t *client = (endpoint_t *)data;
105
	BELLESIP_UNUSED(name);
106
	client->resolve_done = 1;
107 108
	if (srv_list) {
		client->srv_list = srv_list;
109 110 111
		client->resolve_done = 1;
	} else
		client->resolve_ko = 1;
Ghislain MARY's avatar
Ghislain MARY committed
112 113
}

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

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

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

140 141 142 143 144 145 146
/* 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();

147
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
148 149
	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);
150 151 152
	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);
153 154
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
155 156
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
157
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_CNAME_IP, SIP_PORT);
158
		if (ai) {
159
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
160
			bctbx_freeaddrinfo(ai);
161 162 163 164 165 166
		}
	}

	destroy_endpoint(client);
}

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

171
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
172 173
	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);
174 175
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, timeout));
	BC_ASSERT_PTR_NOT_EQUAL(client->ai_list, NULL);
176 177
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
178 179
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
180 181 182 183 184
	}
	destroy_endpoint(client);
}


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

190
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Ghislain MARY's avatar
Ghislain MARY committed
191
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
192
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_BAD_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
193 194 195
	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);
196

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

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

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

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

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

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

218
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
jehan's avatar
jehan committed
219
	belle_sip_stack_set_dns_timeout(client->stack, 0);
220
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, "toto.com", SIP_PORT, AF_INET, a_resolve_done, client);
221 222 223 224
	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
225 226 227
	destroy_endpoint(client);
}

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

233
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
234
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
235
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_MULTIRES_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
236 237 238
	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);
239
	if (client->ai_list) {
240
		BC_ASSERT_PTR_NOT_NULL(client->ai_list->ai_next);
241 242 243 244 245
	}

	destroy_endpoint(client);
}

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

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

255
	client = create_endpoint();
256

257
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
258 259
	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);
260 261 262
	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);
263 264

	destroy_endpoint(client);
265 266 267
}


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

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

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

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

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

	destroy_endpoint(client);
}

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

352
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
353
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
354
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "udp", SRV_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
355 356 357
	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);
358 359 360 361 362 363 364 365 366 367

	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();

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

	destroy_endpoint(client);
}

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

392
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
393
	timeout = belle_sip_stack_get_dns_timeout(client->stack);
394
	client->resolver_ctx = belle_sip_stack_resolve(client->stack, "sip", "tcp", "localhost", SIP_PORT, AF_INET, a_resolve_done, client);
395 396 397
	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);
398 399
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
400 401
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
402 403 404 405
	}
	destroy_endpoint(client);
}

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

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

	destroy_endpoint(client);
}

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

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

452
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Simon Morlat's avatar
Simon Morlat committed
453 454 455
	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);
456 457 458
	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
459 460
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
461 462
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
463
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
Simon Morlat's avatar
Simon Morlat committed
464
		if (ai) {
465
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
466
			bctbx_freeaddrinfo(ai);
Simon Morlat's avatar
Simon Morlat committed
467 468 469 470 471 472
		}
	}

	destroy_endpoint(client);
}

473 474 475 476 477 478 479 480 481
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);
}

482 483 484 485 486 487
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
	};
488 489
	_dns_fallback(nameservers);
}
490

491 492 493 494 495 496 497
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);
498 499
}

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

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

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

	destroy_endpoint(client);
}
535

Simon Morlat's avatar
Simon Morlat committed
536 537 538 539 540 541 542 543 544
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
	};
545

Simon Morlat's avatar
Simon Morlat committed
546 547 548 549 550
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}
	client = create_endpoint();
551
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
Simon Morlat's avatar
Simon Morlat committed
552 553 554
	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);
555 556 557
	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
558 559
	if (client->ai_list) {
		struct sockaddr_in *sock_in = (struct sockaddr_in *)client->ai_list->ai_addr;
560 561
		int ntohsi = (int)ntohs(sock_in->sin_port);
		BC_ASSERT_EQUAL(ntohsi, SIP_PORT, int, "%d");
562
		ai = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_STREAM, IPV4_SIP_IP, SIP_PORT);
Simon Morlat's avatar
Simon Morlat committed
563
		if (ai) {
564
			BC_ASSERT_EQUAL(sock_in->sin_addr.s_addr, ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr, int, "%d");
565
			bctbx_freeaddrinfo(ai);
Simon Morlat's avatar
Simon Morlat committed
566 567 568 569 570
		}
	}

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

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

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

	client = create_endpoint();

585
	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
586 587 588
	BC_ASSERT_PTR_NOT_NULL(reg);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

589
	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
590
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
Mickaël Turnel's avatar
Mickaël Turnel committed
591
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
Mickaël Turnel's avatar
Mickaël Turnel committed
592 593 594 595 596 597
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);

	belle_sip_mdns_unregister(reg);
	destroy_endpoint(client);
}

598 599 600 601 602 603 604 605 606 607 608 609 610
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
611 612 613 614 615
static void mdns_query_no_result(void) {
	endpoint_t *client;

	client = create_endpoint();

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

619
	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
620
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
621
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
Mickaël Turnel's avatar
Mickaël Turnel committed
622 623 624 625 626 627 628 629
	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;
630
	int register_error = -1;
Mickaël Turnel's avatar
Mickaël Turnel committed
631 632 633

	client = create_endpoint();

634
	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
635 636 637
	BC_ASSERT_PTR_NOT_NULL(reg1);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

638
	register_error = -1;
639
	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
640 641 642
	BC_ASSERT_PTR_NOT_NULL(reg2);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

643
	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
644
	BC_ASSERT_PTR_NOT_NULL(client->resolver_ctx);
645
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
Mickaël Turnel's avatar
Mickaël Turnel committed
646 647 648

	BC_ASSERT_PTR_NOT_NULL(client->ai_list);
	if (client->ai_list) {
Mickaël Turnel's avatar
Mickaël Turnel committed
649 650 651
		/* 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
652 653 654
		/* 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;
655 656
			int ntohsi = (int)ntohs(sock_in->sin_port);
			BC_ASSERT_EQUAL(ntohsi, 5070, int, "%d");
Mickaël Turnel's avatar
Mickaël Turnel committed
657 658
		} else {
			struct sockaddr_in6 *sock_in = (struct sockaddr_in6 *)client->ai_list->ai_addr;
659 660
			int ntohsi = (int)ntohs(sock_in->sin6_port);
			BC_ASSERT_EQUAL(ntohsi, 5070, int, "%d");
Mickaël Turnel's avatar
Mickaël Turnel committed
661 662 663 664 665 666 667
		}
	}

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

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

	client = create_endpoint();

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

679
	reg = belle_sip_mdns_register("sip", "tcp", "test.linphone.local", NULL, 5060, 10, 100, 3600, mdns_register_callback, &register_error);
680 681 682 683 684
	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);
685
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
686 687
	BC_ASSERT_PTR_NOT_NULL(client->ai_list);

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

	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);
693
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
694 695 696 697 698
	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
699 700
#endif

Ghislain MARY's avatar
Ghislain MARY committed
701
test_t resolver_tests[] = {
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
	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
720 721 722
	TEST_NO_TAG("IPv4 and v6 DNS servers", ipv4_and_ipv6_dns_server),
#ifdef HAVE_MDNS
	TEST_NO_TAG("MDNS query", mdns_query),
723
	TEST_NO_TAG("MDNS query with ipv6", mdns_query_ipv6),
Mickaël Turnel's avatar
Mickaël Turnel committed
724
	TEST_NO_TAG("MDNS query with no result", mdns_query_no_result),
725 726
	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
727
#endif
Ghislain MARY's avatar
Ghislain MARY committed
728 729
};

730 731
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};