Commit aec5bc22 authored by Ghislain MARY's avatar Ghislain MARY

Merge branch 'dev_resolver'

parents 8b72d74b 85254465
......@@ -123,6 +123,7 @@
<ClInclude Include="..\..\..\src\belle_sip_messageParser.h" />
<ClInclude Include="..\..\..\src\belle_sip_resolver.h" />
<ClInclude Include="..\..\..\src\channel.h" />
<ClInclude Include="..\..\..\src\dns.h" />
<ClInclude Include="..\..\..\src\listeningpoint_internal.h" />
<ClInclude Include="..\..\..\src\md5.h" />
<ClInclude Include="..\..\..\src\port.h" />
......@@ -168,6 +169,7 @@
<ClCompile Include="..\..\..\src\dialog.c">
<CompileAs Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'">CompileAsC</CompileAs>
</ClCompile>
<ClCompile Include="..\..\..\src\dns.c" />
<ClCompile Include="..\..\..\src\ict.c">
<CompileAs Condition="'$(Configuration)|$(Platform)'=='ReleaseDLL|Win32'">CompileAsC</CompileAs>
</ClCompile>
......
......@@ -21,6 +21,7 @@ AM_SILENT_RULES(yes)
# Checks for programs.
AC_PROG_CC
AM_PROG_CC_C_O
dnl AC_PROG_CC_C99
LT_INIT(disable-static win32-dll)
if test -f /etc/debian_version ; then
......@@ -141,7 +142,7 @@ case "$target_os" in
;;
*mingw*)
CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0501"
LIBS="$LIBS -lws2_32"
LIBS="$LIBS -lws2_32 -liphlpapi"
LDFLAGS="$LDFLAGS -Wl,--export-all-symbols"
;;
esac
......
......@@ -55,6 +55,7 @@ void belle_sip_stack_sleep(belle_sip_stack_t *stack, unsigned int milliseconds);
int belle_sip_stack_get_transport_timeout(const belle_sip_stack_t *stack);
int belle_sip_stack_get_dns_timeout(const belle_sip_stack_t *stack);
void belle_sip_hop_free(belle_sip_hop_t *hop);
......
......@@ -59,7 +59,8 @@ libbellesip_la_SOURCES= \
transports/stream_channel.h \
transports/stream_listeningpoint.c \
transports/tls_listeningpoint.c \
refresher.c refresher-helper.h
refresher.c refresher-helper.h \
dns.c dns.h
if BUILD_TLS
libbellesip_la_SOURCES+=transports/tls_channel.c
endif
......
......@@ -456,6 +456,7 @@ struct belle_sip_stack{
belle_sip_main_loop_t *ml;
belle_sip_timer_config_t timer_config;
int transport_timeout;
int dns_timeout;
int tx_delay; /*used to simulate network transmission delay, for tests*/
int send_error; /* used to simulate network error. if <0, channel_send will return this value*/
......
......@@ -123,7 +123,14 @@ static unsigned int belle_sip_source_get_revents(belle_sip_source_t *s,belle_sip
}
static int belle_sip_poll(belle_sip_pollfd_t *pfd, int count, int duration){
DWORD ret=WaitForMultipleObjectsEx(count,pfd,FALSE,duration,FALSE);
DWORD ret;
if (count == 0) {
Sleep(duration);
return 0;
}
ret=WaitForMultipleObjectsEx(count,pfd,FALSE,duration,FALSE);
if (ret==WAIT_FAILED){
belle_sip_error("WaitForMultipleObjectsEx() failed.");
return -1;
......
......@@ -18,6 +18,184 @@
#include "belle_sip_resolver.h"
#include <stdlib.h>
#define DNS_EAGAIN EAGAIN
static struct dns_resolv_conf *resconf(belle_sip_resolver_context_t *ctx) {
#ifndef _WIN32
const char *path;
#endif
int error;
if (ctx->resconf)
return ctx->resconf;
if (!(ctx->resconf = dns_resconf_open(&error))) {
belle_sip_error("%s dns_resconf_open error: %s", __FUNCTION__, dns_strerror(error));
return NULL;
}
#ifdef _WIN32
error = dns_resconf_loadwin(ctx->resconf);
#else
path = "/etc/resolv.conf";
error = dns_resconf_loadpath(ctx->resconf, path);
if (error) {
belle_sip_error("%s dns_resconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error));
return NULL;
}
path = "/etc/nsswitch.conf";
error = dns_nssconf_loadpath(ctx->resconf, path);
if (error) {
belle_sip_error("%s dns_nssconf_loadpath error [%s]: %s", __FUNCTION__, path, dns_strerror(error));
return NULL;
}
#endif
return ctx->resconf;
}
static struct dns_hosts *hosts(belle_sip_resolver_context_t *ctx) {
int error;
if (ctx->hosts)
return ctx->hosts;
if (!(ctx->hosts = dns_hosts_local(&error))) {
belle_sip_error("%s dns_hosts_local error: %s", __FUNCTION__, dns_strerror(error));
return NULL;
}
return ctx->hosts;
}
struct dns_cache *cache(belle_sip_resolver_context_t *ctx) {
return NULL;
}
static int resolver_process_a_data(belle_sip_resolver_context_t *ctx, unsigned int revents) {
char host[NI_MAXHOST + 1];
char service[NI_MAXSERV + 1];
struct dns_packet *ans;
struct dns_rr_i *I;
int error;
#ifndef HAVE_C99
struct dns_rr_i dns_rr_it;
#endif
if (revents & BELLE_SIP_EVENT_TIMEOUT) {
belle_sip_error("%s timed-out", __FUNCTION__);
return BELLE_SIP_STOP;
}
if (ctx->cancelled) {
return BELLE_SIP_STOP;
}
error = dns_res_check(ctx->R);
if (!error) {
struct dns_rr rr;
union dns_any any;
enum dns_section section = DNS_S_AN;
ans = dns_res_fetch(ctx->R, &error);
#ifdef HAVE_C99
I = dns_rr_i_new(ans, .section = 0);
#else
memset(&dns_rr_it, 0, sizeof dns_rr_it);
I = dns_rr_i_init(&dns_rr_it, ans);
#endif
while (dns_rr_grep(&rr, 1, I, ans, &error)) {
if (rr.section == section) {
if ((error = dns_any_parse(dns_any_init(&any, sizeof(any)), &rr, ans))) {
belle_sip_error("%s dns_any_parse error: %s", __FUNCTION__, dns_strerror(error));
free(ans);
return BELLE_SIP_STOP;
}
if ((ctx->family == AF_INET6) && (rr.class == DNS_C_IN) && (rr.type == DNS_T_AAAA)) {
struct dns_aaaa *aaaa = &any.aaaa;
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(sin6));
memcpy(&sin6.sin6_addr, &aaaa->addr, sizeof(sin6.sin6_addr));
sin6.sin6_family = AF_INET6;
sin6.sin6_port = ctx->port;
if (getnameinfo((struct sockaddr *)&sin6, sizeof(sin6), host, sizeof(host), service, sizeof(service), NI_NUMERICHOST) != 0)
continue;
ctx->ai = belle_sip_ip_address_to_addrinfo(host, ctx->port);
belle_sip_message("%s has address %s", ctx->name, host);
break;
} else {
if ((rr.class == DNS_C_IN) && (rr.type == DNS_T_A)) {
struct dns_a *a = &any.a;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
memcpy(&sin.sin_addr, &a->addr, sizeof(sin.sin_addr));
sin.sin_family = AF_INET;
sin.sin_port = ctx->port;
if (getnameinfo((struct sockaddr *)&sin, sizeof(sin), host, sizeof(host), service, sizeof(service), NI_NUMERICHOST) != 0)
continue;
ctx->ai = belle_sip_ip_address_to_addrinfo(host, ctx->port);
belle_sip_message("%s has address %s", ctx->name, host);
break;
}
}
}
}
free(ans);
ctx->cb(ctx->cb_data, ctx->name, ctx->ai);
return BELLE_SIP_STOP;
}
if (error != DNS_EAGAIN) {
belle_sip_error("%s dns_res_check error: %s (%d)", __FUNCTION__, dns_strerror(error), error);
return BELLE_SIP_STOP;
}
dns_res_poll(ctx->R, 0);
return BELLE_SIP_CONTINUE;
}
static int resolver_start_query(belle_sip_resolver_context_t *ctx, belle_sip_source_func_t datafunc, enum dns_type type, int timeout) {
struct dns_hints *(*hints)() = &dns_hints_local;
struct dns_options *opts;
#ifndef HAVE_C99
struct dns_options opts_st;
#endif
int error;
if (!ctx->name) return -1;
if (resconf(ctx))
resconf(ctx)->options.recurse = 0;
else
return -1;
if (!hosts(ctx))
return -1;
#ifdef HAVE_C99
opts = dns_opts();
#else
memset(&opts_st, 0, sizeof opts_st);
opts = &opts_st;
#endif
if (!(ctx->R = dns_res_open(ctx->resconf, ctx->hosts, dns_hints_mortal(hints(ctx->resconf, &error)), cache(ctx), opts, &error))) {
belle_sip_error("%s dns_res_open error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
return -1;
}
if ((error = dns_res_submit(ctx->R, ctx->name, type, DNS_C_IN))) {
belle_sip_error("%s dns_res_submit error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
return -1;
}
(*datafunc)(ctx, 0);
belle_sip_socket_source_init((belle_sip_source_t*)ctx, datafunc, ctx, dns_res_pollfd(ctx->R), BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT, timeout);
return 0;
}
int belle_sip_addrinfo_to_ip(const struct addrinfo *ai, char *ip, size_t ip_size, int *port){
char serv[16];
......@@ -48,124 +226,47 @@ struct addrinfo * belle_sip_ip_address_to_addrinfo(const char *ipaddress, int po
static void belle_sip_resolver_context_destroy(belle_sip_resolver_context_t *ctx){
if (ctx->thread!=0){
belle_sip_thread_join(ctx->thread,NULL);
}
/* Do not free ctx->ai with freeaddrinfo(). Let the caller do it, otherwise
it will not be able to use it after the resolver has been destroyed. */
if (ctx->name)
belle_sip_free(ctx->name);
if (ctx->ai){
freeaddrinfo(ctx->ai);
}
#ifndef WIN32
close(ctx->ctlpipe[0]);
close(ctx->ctlpipe[1]);
#else
if (ctx->ctlevent!=(belle_sip_fd_t)-1)
CloseHandle(ctx->ctlevent);
#endif
if (ctx->R)
dns_res_close(ctx->R);
if (ctx->hosts)
free(ctx->hosts);
if (ctx->resconf)
free(ctx->resconf);
}
BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_resolver_context_t);
BELLE_SIP_INSTANCIATE_VPTR(belle_sip_resolver_context_t, belle_sip_source_t,belle_sip_resolver_context_destroy, NULL, NULL,FALSE);
static int resolver_callback(belle_sip_resolver_context_t *ctx){
belle_sip_message("resolver_callback() for %p (%s) called, done=%i, cancelled=%i",ctx->cb_data,ctx->name,(int)ctx->done,(int)ctx->cancelled);
if (!ctx->cancelled){
ctx->cb(ctx->cb_data, ctx->name, ctx->ai);
ctx->ai=NULL;
}
#ifndef WIN32
{
char tmp;
if (read(ctx->source.fd,&tmp,1)!=1){
belle_sip_fatal("Unexpected read from resolver_callback");
unsigned long belle_sip_resolve(belle_sip_stack_t *stack, const char *name, int port, int family, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml) {
struct addrinfo *res = belle_sip_ip_address_to_addrinfo(name, port);
if (res == NULL) {
/* Then perform asynchronous DNS query */
belle_sip_resolver_context_t *ctx = belle_sip_object_new(belle_sip_resolver_context_t);
ctx->cb_data = data;
ctx->cb = cb;
ctx->name = belle_sip_strdup(name);
ctx->port = port;
ctx->ai = NULL;
if (family == 0) family = AF_UNSPEC;
ctx->family = family;
if (resolver_start_query(ctx,
(belle_sip_source_func_t)resolver_process_a_data,
(ctx->family == AF_INET6) ? DNS_T_AAAA : DNS_T_A,
belle_sip_stack_get_dns_timeout(stack)) < 0) {
belle_sip_object_unref(ctx);
return 0;
}
}
#endif
/*by returning stop, we'll be removed from main loop and destroyed. */
return BELLE_SIP_STOP;
}
belle_sip_resolver_context_t *belle_sip_resolver_context_new(){
belle_sip_resolver_context_t *ctx=belle_sip_object_new(belle_sip_resolver_context_t);
#ifdef WIN32
ctx->ctlevent=(belle_sip_fd_t)-1;
#endif
return ctx;
}
static void *belle_sip_resolver_thread(void *ptr){
belle_sip_resolver_context_t *ctx=(belle_sip_resolver_context_t *)ptr;
struct addrinfo *res=NULL;
struct addrinfo hints={0};
char serv[10];
int err;
/*the thread owns a ref on the resolver context*/
belle_sip_object_ref(ctx);
belle_sip_message("Resolver thread started.");
snprintf(serv,sizeof(serv),"%i",ctx->port);
hints.ai_family=ctx->family;
hints.ai_flags=AI_NUMERICSERV;
err=getaddrinfo(ctx->name,serv,&hints,&res);
if (err!=0){
belle_sip_error("DNS resolution of %s failed: %s",ctx->name,gai_strerror(err));
}else{
char host[64];
belle_sip_addrinfo_to_ip(res,host,sizeof(host),NULL);
belle_sip_message("%s has address %s.",ctx->name,host);
ctx->ai=res;
}
ctx->done=TRUE;
#ifndef WIN32
if (write(ctx->ctlpipe[1],"q",1)==-1){
belle_sip_error("belle_sip_resolver_thread(): Fail to write on pipe.");
}
#else
SetEvent(ctx->ctlevent);
#endif
belle_sip_object_unref(ctx);
return NULL;
}
static void belle_sip_resolver_context_start(belle_sip_resolver_context_t *ctx){
belle_sip_fd_t fd=(belle_sip_fd_t)-1;
belle_sip_thread_create(&ctx->thread,NULL,belle_sip_resolver_thread,ctx);
#ifndef WIN32
if (pipe(ctx->ctlpipe)==-1){
belle_sip_fatal("pipe() failed: %s",strerror(errno));
}
fd=ctx->ctlpipe[0];
#else
/*we don't use the thread handle itself, because it is not a manual-reset event.
The mainloop implementation can only work with manual-reset events*/
ctx->ctlevent=CreateEvent(NULL,TRUE,FALSE,NULL);
/*use CreateEventEx on wp8*/
fd=(HANDLE)ctx->ctlevent;
#endif
belle_sip_fd_source_init(&ctx->source,(belle_sip_source_func_t)resolver_callback,ctx,fd,BELLE_SIP_EVENT_READ,-1);
}
unsigned long belle_sip_resolve(const char *name, int port, int family, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml){
struct addrinfo *res=belle_sip_ip_address_to_addrinfo (name, port);
if (res==NULL){
/*then perform asynchronous DNS query */
belle_sip_resolver_context_t *ctx=belle_sip_resolver_context_new();
ctx->cb_data=data;
ctx->cb=cb;
ctx->name=belle_sip_strdup(name);
ctx->port=port;
if (family==0) family=AF_UNSPEC;
ctx->family=family;
belle_sip_resolver_context_start(ctx);
/*the resolver context must never be removed manually from the main loop*/
/* The resolver context must never be removed manually from the main loop */
belle_sip_main_loop_add_source(ml,(belle_sip_source_t*)ctx);
belle_sip_object_unref(ctx);/*the main loop and the thread have a ref on it*/
belle_sip_object_unref(ctx); /* The main loop has a ref on it */
return ctx->source.id;
}else{
cb(data,name,res);
} else {
cb(data, name, res);
return 0;
}
}
......@@ -211,4 +312,3 @@ fail:
}
if (sock==(belle_sip_socket_t)-1) close_socket(sock);
}
......@@ -21,6 +21,7 @@
#define belle_sip_resolver_h
#include "belle_sip_internal.h"
#include "dns.h"
typedef struct belle_sip_resolver_context belle_sip_resolver_context_t;
......@@ -38,22 +39,20 @@ struct belle_sip_resolver_context{
belle_sip_source_t source;
belle_sip_resolver_callback_t cb;
void *cb_data;
struct dns_resolv_conf *resconf;
struct dns_hosts *hosts;
struct dns_resolver *R;
char *name;
int port;
struct addrinfo *ai;
int family;
belle_sip_thread_t thread;
#ifndef WIN32
int ctlpipe[2];
#else
HANDLE ctlevent;
#endif
uint8_t cancelled;
uint8_t done;
};
int belle_sip_addrinfo_to_ip(const struct addrinfo *ai, char *ip, size_t ip_size, int *port);
struct addrinfo * belle_sip_ip_address_to_addrinfo(const char *ipaddress, int port);
unsigned long belle_sip_resolve(const char *name, int port, int family, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml);
unsigned long belle_sip_resolve(belle_sip_stack_t *stack, const char *name, int port, int family, belle_sip_resolver_callback_t cb , void *data, belle_sip_main_loop_t *ml);
void belle_sip_resolve_cancel(belle_sip_main_loop_t *ml, unsigned long id);
void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen);
......
......@@ -464,7 +464,7 @@ static void channel_res_done(void *data, const char *name, struct addrinfo *res)
void belle_sip_channel_resolve(belle_sip_channel_t *obj){
channel_set_state(obj,BELLE_SIP_CHANNEL_RES_IN_PROGRESS);
obj->resolver_id=belle_sip_resolve(obj->peer_name, obj->peer_port, 0, channel_res_done, obj, obj->stack->ml);
obj->resolver_id=belle_sip_resolve(obj->stack, obj->peer_name, obj->peer_port, 0, channel_res_done, obj, obj->stack->ml);
return ;
}
......
This diff is collapsed.
This diff is collapsed.
......@@ -42,37 +42,6 @@ void belle_sip_uninit_sockets(void){
if (sockets_initd==0) WSACleanup();
}
typedef struct thread_param{
void * (*func)(void *);
void * arg;
}thread_param_t;
static unsigned WINAPI thread_starter(void *data){
thread_param_t *params=(thread_param_t*)data;
void *ret=params->func(params->arg);
belle_sip_free(data);
return (DWORD)ret;
}
int belle_sip_thread_create(belle_sip_thread_t *th, void *attr, void * (*func)(void *), void *data)
{
thread_param_t *params=belle_sip_new(thread_param_t);
params->func=func;
params->arg=data;
*th=(HANDLE)_beginthreadex( NULL, 0, thread_starter, params, 0, NULL);
return 0;
}
int belle_sip_thread_join(belle_sip_thread_t thread_h, void **unused)
{
if (thread_h!=NULL)
{
WaitForSingleObject(thread_h, INFINITE);
CloseHandle(thread_h);
}
return 0;
}
int belle_sip_socket_set_nonblocking (belle_sip_socket_t sock)
{
unsigned long nonBlock = 1;
......
......@@ -28,7 +28,6 @@
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <pthread.h>
#else
......@@ -104,27 +103,6 @@ static inline int get_socket_error(void){
#endif
/*
* Thread abstraction layer
*/
#ifdef WIN32
typedef HANDLE belle_sip_thread_t;
int belle_sip_thread_join(belle_sip_thread_t thread, void **retptr);
int belle_sip_thread_create(belle_sip_thread_t *thread, void *attr, void * (*routine)(void*), void *arg);
#else
#include <pthread.h>
typedef pthread_t belle_sip_thread_t;
#define belle_sip_thread_join(thread,retptr) pthread_join(thread,retptr)
#define belle_sip_thread_create(thread,attr,routine,arg) pthread_create(thread,attr,routine,arg)
#endif
#endif
......
......@@ -34,6 +34,7 @@ belle_sip_stack_t * belle_sip_stack_new(const char *properties){
stack->timer_config.T2=4000;
stack->timer_config.T4=5000;
stack->transport_timeout=30000;
stack->dns_timeout=2000;
return stack;
}
......@@ -45,6 +46,10 @@ int belle_sip_stack_get_transport_timeout(const belle_sip_stack_t *stack){
return stack->transport_timeout;
}
int belle_sip_stack_get_dns_timeout(const belle_sip_stack_t *stack) {
return stack->dns_timeout;
}
belle_sip_listening_point_t *belle_sip_stack_create_listening_point(belle_sip_stack_t *s, const char *ipaddress, int port, const char *transport){
belle_sip_listening_point_t *lp=NULL;
if (strcasecmp(transport,"UDP")==0) {
......
......@@ -13,7 +13,8 @@ belle_sip_tester_SOURCES= belle_sip_tester.c \
cast_test.c \
belle_sip_register_tester.c \
belle_sip_dialog_tester.c \
belle_sip_refresher_tester.c
belle_sip_refresher_tester.c \
belle_sip_resolver_tester.c
belle_sip_tester_CFLAGS=$(CUNIT_CFLAGS) $(STRICT_OPTIONS)
......
......@@ -19,7 +19,6 @@
#include <stdio.h>
#include "CUnit/Basic.h"
#include "belle-sip/belle-sip.h"
#include "pthread.h"
extern belle_sip_stack_t * stack;
extern belle_sip_provider_t *prov;
......
......@@ -19,7 +19,6 @@
#include <stdio.h>
#include "CUnit/Basic.h"
#include "belle-sip/belle-sip.h"
#include "pthread.h"
const char *test_domain="test.linphone.org";
const char *auth_domain="sip.linphone.org";
......
/*
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
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