belle_sip_resolver_tester.c 26.2 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
	struct addrinfo *ai_list;
	belle_sip_list_t *srv_list; /**< List of struct dns_srv pointers */
Ghislain MARY's avatar
Ghislain MARY committed
46 47 48 49
} endpoint_t;

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

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

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

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

88
static void a_resolve_done(void *data, const char *name, struct addrinfo *ai_list, uint32_t ttl) {
89 90 91 92 93 94 95 96 97 98
	endpoint_t *client = (endpoint_t *)data;
	BELLESIP_UNUSED(name);
	client->resolve_done = 1;
	if (ai_list) {
		client->ai_list = ai_list;
		client->resolve_done = 1;
	} else
		client->resolve_ko = 1;
}

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

Ghislain MARY's avatar
Ghislain MARY committed
110 111
/* Successful IPv4 A query */
static void ipv4_a_query(void) {
112
	struct addrinfo *ai;
113
	int timeout;
114
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
115

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

Ghislain MARY's avatar
Ghislain MARY committed
133 134 135
	destroy_endpoint(client);
}

136 137 138 139 140 141 142
/* 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();

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

	destroy_endpoint(client);
}

163 164 165 166
static void local_query(void) {
	int timeout;
	endpoint_t *client = create_endpoint();

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


Ghislain MARY's avatar
Ghislain MARY committed
181 182 183
/* Successful IPv4 A query with no result */
static void ipv4_a_query_no_result(void) {
	int timeout;
184
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
185

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

Ghislain MARY's avatar
Ghislain MARY committed
193 194 195 196 197
	destroy_endpoint(client);
}

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

200
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
201
	belle_sip_stack_set_resolver_send_error(client->stack, -1);
202
	client->resolver_ctx = belle_sip_stack_resolve_a(client->stack, IPV4_SIP_DOMAIN, SIP_PORT, AF_INET, a_resolve_done, client);
203
	BC_ASSERT_PTR_NULL(client->resolver_ctx);
204
	belle_sip_stack_set_resolver_send_error(client->stack, 0);
205

Ghislain MARY's avatar
Ghislain MARY committed
206 207 208 209 210
	destroy_endpoint(client);
}

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

212
	endpoint_t *client = create_endpoint();
Ghislain MARY's avatar
Ghislain MARY committed
213

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

224 225 226
/* Successful IPv4 A query with multiple results */
static void ipv4_a_query_multiple_results(void) {
	int timeout;
227
	endpoint_t *client = create_endpoint();
228

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

	destroy_endpoint(client);
}

242 243
static void ipv4_a_query_with_v4mapped_results(void) {
	int timeout;
244
	endpoint_t *client;
245

246 247 248 249
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}
250

251
	client = create_endpoint();
252

253
	if (!BC_ASSERT_PTR_NOT_NULL(client)) return;
254 255
	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);
256 257 258
	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);
259 260

	destroy_endpoint(client);
261 262 263
}


Ghislain MARY's avatar
Ghislain MARY committed
264 265 266 267
/* Successful IPv6 AAAA query */
static void ipv6_aaaa_query(void) {
	struct addrinfo *ai;
	int timeout;
268 269
	endpoint_t *client;

270 271 272 273 274 275
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}

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

323 324 325
/* Successful SRV query */
static void srv_query(void) {
	int timeout;
326
	endpoint_t *client = create_endpoint();
327

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

	destroy_endpoint(client);
}

343 344 345 346 347
/* Successful SRV + A or AAAA queries */
static void srv_a_query(void) {
	int timeout;
	endpoint_t *client = create_endpoint();

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

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

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

	destroy_endpoint(client);
}

384 385 386 387
static void local_full_query(void) {
	int timeout;
	endpoint_t *client = create_endpoint();

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

402 403 404 405 406
/* No query needed because already resolved */
static void no_query_needed(void) {
	struct addrinfo *ai;
	endpoint_t *client = create_endpoint();

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

	destroy_endpoint(client);
}

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

443
static void _dns_fallback(const char *nameservers[]) {
Simon Morlat's avatar
Simon Morlat committed
444 445 446 447
	struct addrinfo *ai;
	int timeout;
	endpoint_t *client = create_endpoint();

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

	destroy_endpoint(client);
}

469 470 471 472 473 474 475 476 477
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);
}

478 479 480 481 482 483
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
	};
484 485
	_dns_fallback(nameservers);
}
486

487 488 489 490 491 492 493
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);
494 495
}

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

Simon Morlat's avatar
Simon Morlat committed
505 506 507 508
	if (!belle_sip_tester_ipv6_available()){
		belle_sip_warning("Test skipped, IPv6 connectivity not available.");
		return;
	}
509

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

	destroy_endpoint(client);
}
531

Simon Morlat's avatar
Simon Morlat committed
532 533 534 535 536 537 538 539 540
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
	};
541

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

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

Mickaël Turnel's avatar
Mickaël Turnel committed
568 569 570 571 572 573
#ifdef HAVE_MDNS
static void mdns_register_callback(void *data, int error) {
	int *register_error = (int *)data;
	*register_error = error;
}

574
static void mdns_query_ipv4_or_ipv6(int family) {
Mickaël Turnel's avatar
Mickaël Turnel committed
575 576
	belle_sip_mdns_register_t *reg;
	endpoint_t *client;
577
	int register_error = -1;
Mickaël Turnel's avatar
Mickaël Turnel committed
578 579 580

	client = create_endpoint();

581
	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
582 583 584
	BC_ASSERT_PTR_NOT_NULL(reg);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

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

	belle_sip_mdns_unregister(reg);
	destroy_endpoint(client);
}

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

	client = create_endpoint();

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

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

	client = create_endpoint();

630
	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
631 632 633
	BC_ASSERT_PTR_NOT_NULL(reg1);
	BC_ASSERT_TRUE(wait_for(client->stack, &register_error, 0, 5000));

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

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

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

	belle_sip_mdns_unregister(reg1);
	belle_sip_mdns_unregister(reg2);
	destroy_endpoint(client);
}
664 665 666 667 668 669 670 671

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

	client = create_endpoint();

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

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

Mickaël Turnel's avatar
Mickaël Turnel committed
684
	reset_endpoint(client);
685
	wait_for(client->stack, &client->resolve_done, 1, 5000); // Wait 5 seconds
686 687 688

	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);
689
	BC_ASSERT_TRUE(wait_for(client->stack, &client->resolve_done, 1, 10000));
690 691 692 693 694
	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
695 696
#endif

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

726 727
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};