Commit 41666379 authored by Simon Morlat's avatar Simon Morlat

Merge branch 'feature/resolver-improvements'

parents 0b57292c dbc0781b
Pipeline #274 failed with stage
in 0 seconds
......@@ -25,6 +25,9 @@ typedef struct belle_sip_dns_srv belle_sip_dns_srv_t;
typedef struct belle_sip_resolver_context belle_sip_resolver_context_t;
#define BELLE_SIP_RESOLVER_CONTEXT(obj) BELLE_SIP_CAST(obj,belle_sip_resolver_context_t)
typedef struct belle_sip_resolver_results belle_sip_resolver_results_t;
#define BELLE_SIP_RESOLVER_RESULTS(obj) BELLE_SIP_CAST(obj,belle_sip_resolver_results_t)
/**
* Callback prototype for asynchronous DNS SRV resolution.
* The srv_list contains struct dns_srv elements that must be taken and (possibly later) freed by the callee, using belle_sip_free().
......@@ -33,10 +36,10 @@ typedef void (*belle_sip_resolver_srv_callback_t)(void *data, const char *name,
/**
* Callback prototype for asynchronous DNS A and AAAA resolution.
* The ai_list contains addrinfo elements that must be taken and (possibly later) freed by the callee, using freeaddrinfo().
* These elements are linked by their ai_next field.
* The 'results' object must be acquired (ref'd) in order for being accessed outside of the callback.
* The results object provides SRV records list and addrinfo list.
**/
typedef void (*belle_sip_resolver_callback_t)(void *data, const char *name, struct addrinfo *ai_list, uint32_t ttl);
typedef void (*belle_sip_resolver_callback_t)(void *data, belle_sip_resolver_results_t *results);
BELLE_SIP_BEGIN_DECLS
......@@ -49,6 +52,20 @@ BELLESIP_EXPORT unsigned short belle_sip_dns_srv_get_weight(const belle_sip_dns_
BELLESIP_EXPORT unsigned short belle_sip_dns_srv_get_port(const belle_sip_dns_srv_t *obj);
/**
* Find the belle_sip_dns_srv_t object associated with a particular addrinfo.
* The srv_list and the addrinfo must be the ones given by the belle_sip_resolver_callback_t callback invoked consecutively to a call
* to belle_sip_stack_resolve().
**/
BELLESIP_EXPORT const belle_sip_dns_srv_t * belle_sip_resolver_results_get_srv_from_addrinfo(const belle_sip_resolver_results_t *obj, const struct addrinfo *ai);
BELLESIP_EXPORT const bctbx_list_t *belle_sip_resolver_results_get_srv_records(const belle_sip_resolver_results_t *obj);
BELLESIP_EXPORT const struct addrinfo *belle_sip_resolver_results_get_addrinfos(const belle_sip_resolver_results_t *obj);
BELLESIP_EXPORT int belle_sip_resolver_results_get_ttl(const belle_sip_resolver_results_t *obj);
BELLESIP_EXPORT const char * belle_sip_resolver_results_get_name(const belle_sip_resolver_results_t *obj);
/**
* Asynchronously performs DNS SRV followed A/AAAA query. Automatically fallbacks to A/AAAA if SRV isn't found.
......
......@@ -149,7 +149,8 @@ BELLE_SIP_DECLARE_TYPES_BEGIN(belle_sip,1)
BELLE_SIP_TYPE_ID(belle_sip_header_accept_t),
BELLE_SIP_TYPE_ID(belle_sip_header_reason_t),
BELLE_SIP_TYPE_ID(belle_sip_header_authentication_info_t),
BELLE_SIP_TYPE_ID(belle_sip_mdns_register_t)
BELLE_SIP_TYPE_ID(belle_sip_mdns_register_t),
BELLE_SIP_TYPE_ID(belle_sip_resolver_results_t)
BELLE_SIP_DECLARE_TYPES_END
......
......@@ -234,6 +234,7 @@ BELLE_SIP_DECLARE_VPTR(belle_sip_header_authentication_info_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_mdns_source_t);
BELLE_SIP_DECLARE_VPTR(belle_sip_mdns_register_t);
#endif
BELLE_SIP_DECLARE_VPTR(belle_sip_resolver_results_t);
BELLE_SIP_DECLARE_CUSTOM_VPTR_BEGIN(belle_sip_resolver_context_t,belle_sip_source_t)
......
This diff is collapsed.
......@@ -109,7 +109,6 @@ static size_t belle_sip_channel_input_stream_get_buff_length(belle_sip_channel_i
static void belle_sip_channel_destroy(belle_sip_channel_t *obj){
belle_sip_channel_input_stream_reset(&obj->input_stream);
if (obj->peer_list) bctbx_freeaddrinfo(obj->peer_list);
if (obj->peer_cname) belle_sip_free(obj->peer_cname);
belle_sip_free(obj->peer_name);
if (obj->local_ip) belle_sip_free(obj->local_ip);
......@@ -120,6 +119,8 @@ static void belle_sip_channel_destroy(belle_sip_channel_t *obj){
belle_sip_resolver_context_cancel(obj->resolver_ctx);
belle_sip_object_unref(obj->resolver_ctx);
}
SET_OBJECT_PROPERTY(obj, resolver_results, NULL);
if (obj->static_peer_list) bctbx_freeaddrinfo(obj->static_peer_list);
if (obj->inactivity_timer){
belle_sip_main_loop_remove_source(obj->stack->ml,obj->inactivity_timer);
belle_sip_object_unref(obj->inactivity_timer);
......@@ -745,7 +746,7 @@ static void update_inactivity_timer(belle_sip_channel_t *obj, int from_recv){
* locaport locaport to use for binding, can be set to 0 if port doesn't matter
* peer_cname canonical name of remote host, used for TLS verification
* peername peer's hostname, either ip address or DNS name
* pee_port peer's port to connect to.
* peer_port peer's port to connect to.
*/
void belle_sip_channel_init(belle_sip_channel_t *obj, belle_sip_stack_t *stack,const char *bindip,int localport,const char *peer_cname, const char *peername, int peer_port){
/*to initialize our base class:*/
......@@ -787,7 +788,7 @@ void belle_sip_channel_init_with_addr(belle_sip_channel_t *obj, belle_sip_stack_
ai.ai_addrlen=addrlen;
bctbx_addrinfo_to_ip_address(&ai,remoteip,sizeof(remoteip),&peer_port);
belle_sip_channel_init(obj,stack,bindip,localport,NULL,remoteip,peer_port);
obj->peer_list=obj->current_peer=bctbx_ip_address_to_addrinfo(ai.ai_family, ai.ai_socktype, obj->peer_name,obj->peer_port);
obj->peer_list = obj->current_peer = obj->static_peer_list = bctbx_ip_address_to_addrinfo(ai.ai_family, ai.ai_socktype, obj->peer_name,obj->peer_port);
obj->ai_family=ai.ai_family;
}
......@@ -835,7 +836,8 @@ void belle_sip_channel_remove_listener(belle_sip_channel_t *obj, belle_sip_chann
}
int belle_sip_channel_matches(const belle_sip_channel_t *obj, const belle_sip_hop_t *hop, const struct addrinfo *addr){
if (hop && strcmp(hop->host,obj->peer_name)==0 && (hop->port==obj->peer_port || obj->srv_overrides_port)){
if (hop && (strcmp(hop->host,obj->peer_name)==0 || (obj->current_peer_cname && strcmp(hop->host,obj->current_peer_cname)==0))
&& (hop->port==obj->peer_port || obj->srv_overrides_port)){
if (hop->cname && obj->peer_cname && strcmp(hop->cname,obj->peer_cname)!=0)
return 0; /*cname mismatch*/
return 1;
......@@ -1000,13 +1002,26 @@ static void channel_connect_next(belle_sip_channel_t *obj){
belle_sip_object_unref(obj);
}
static void channel_set_current_peer(belle_sip_channel_t *obj, const struct addrinfo *ai){
if (obj->resolver_results){
const belle_sip_dns_srv_t *srv = belle_sip_resolver_results_get_srv_from_addrinfo(obj->resolver_results, ai);
obj->current_peer_cname = srv ? belle_sip_dns_srv_get_target(srv) : NULL;
if (obj->current_peer_cname){
belle_sip_message("channel[%p]: current peer hostname is [%s].", obj, obj->current_peer_cname);
}
}else{
obj->current_peer_cname = NULL;
}
obj->current_peer = ai;
}
static void belle_sip_channel_handle_error(belle_sip_channel_t *obj){
if (obj->state!=BELLE_SIP_CHANNEL_READY || obj->soft_error){
/* Previous connection attempts were failed (channel could not get ready) OR soft error reported*/
obj->soft_error = FALSE;
/* See if you can retry on an alternate ip address.*/
if (obj->current_peer && obj->current_peer->ai_next){ /*obj->current_peer may be null in case of dns error*/
obj->current_peer=obj->current_peer->ai_next;
channel_set_current_peer(obj, obj->current_peer->ai_next);
channel_set_state(obj,BELLE_SIP_CHANNEL_RETRY);
belle_sip_channel_close(obj);
belle_sip_main_loop_do_later(obj->stack->ml,(belle_sip_callback_t)channel_connect_next,belle_sip_object_ref(obj));
......@@ -1440,50 +1455,63 @@ static int channel_dns_ttl_timeout(void *data, unsigned int event) {
return BELLE_SIP_STOP;
}
static bool_t addrinfo_in_list(const struct addrinfo *ai, const struct addrinfo *list) {
/* returns the addrinfo from list that matches 'ai' in terms of content*/
static const struct addrinfo* addrinfo_in_list(const struct addrinfo *ai, const struct addrinfo *list) {
const struct addrinfo *item = list;
bool_t in_list = FALSE;
while (item != NULL) {
if ((ai->ai_family == item->ai_family) && (bctbx_sockaddr_equals(ai->ai_addr, item->ai_addr))) {
in_list = TRUE;
break;
return item;
}
item = item->ai_next;
}
return in_list;
return NULL;
}
static bool_t addrinfo_is_first(const struct addrinfo *ai, const struct addrinfo *list) {
/* returns the first addrinfo from list, if it is matching 'ai' in terms content*/
static const struct addrinfo * addrinfo_is_first(const struct addrinfo *ai, const struct addrinfo *list) {
if (list != NULL && (ai->ai_family == list->ai_family) && (bctbx_sockaddr_equals(ai->ai_addr, list->ai_addr)))
return TRUE;
return FALSE;
return list;
return NULL;
}
static void channel_res_done(void *data, const char *name, struct addrinfo *ai_list, uint32_t ttl){
static void channel_res_done(void *data, belle_sip_resolver_results_t *results){
belle_sip_channel_t *obj=(belle_sip_channel_t*)data;
const struct addrinfo *ai_list = NULL;
const char *name = NULL;
if (obj->resolver_ctx){
belle_sip_object_unref(obj->resolver_ctx);
obj->resolver_ctx=NULL;
}
if (results){
ai_list = belle_sip_resolver_results_get_addrinfos(results);
SET_OBJECT_PROPERTY(obj, resolver_results, results);
name = belle_sip_resolver_results_get_name(results);
}
if (ai_list){
int ttl = belle_sip_resolver_results_get_ttl(results);
obj->peer_list = ai_list;
if (!obj->current_peer) {
obj->peer_list=obj->current_peer=ai_list;
channel_set_current_peer(obj, ai_list);
channel_set_state(obj,BELLE_SIP_CHANNEL_RES_DONE);
} else {
bool_t check;
const struct addrinfo *existing_peer;
if (belle_sip_stack_reconnect_to_primary_asap_enabled(obj->stack)) {
check = addrinfo_is_first(obj->current_peer, ai_list);
existing_peer = addrinfo_is_first(obj->current_peer, ai_list);
} else {
check = addrinfo_in_list(obj->current_peer, ai_list);
existing_peer = addrinfo_in_list(obj->current_peer, ai_list);
}
if (check) {
if (existing_peer) {
belle_sip_message("channel[%p]: DNS resolution returned the currently used address, continue using it", obj);
obj->peer_list = ai_list;
channel_set_current_peer(obj, existing_peer);
channel_set_state(obj, BELLE_SIP_CHANNEL_READY);
} else {
belle_sip_message("channel[%p]: DNS resolution returned an address different than the one being used, reconnect to the new address", obj);
obj->peer_list = obj->current_peer = ai_list;
channel_set_current_peer(obj, ai_list);
belle_sip_channel_close(obj);
belle_sip_main_loop_do_later(obj->stack->ml, (belle_sip_callback_t)channel_connect_next, belle_sip_object_ref(obj));
channel_set_state(obj, BELLE_SIP_CHANNEL_RETRY);
......
......@@ -94,16 +94,19 @@ struct belle_sip_channel{
belle_sip_list_t *state_listeners;
belle_sip_list_t *full_listeners;
int ai_family;
char *peer_cname;
char *peer_name;
char *peer_cname; /* A or SRV name */
char *peer_name; /* A or SRV name */
int peer_port;
char *local_ip;
int local_port;
char *public_ip;
int public_port;
belle_sip_resolver_context_t* resolver_ctx;
struct addrinfo *peer_list;
struct addrinfo *current_peer;
belle_sip_resolver_results_t* resolver_results;
struct addrinfo *static_peer_list; /*this is the addrinfo when the channel is instanciated from destination IP address directly (no dns resolution)*/
const struct addrinfo *peer_list; /*points to the addrinfo list in resolver_results, or to the static_peer_list*/
const struct addrinfo *current_peer; /*points in the currently used element in peer_list */
const char *current_peer_cname; /*name of the host we are currently connected to. Set only in SRV case*/
belle_sip_list_t *outgoing_messages;
belle_sip_message_t *cur_out_message;
output_stream_state_t out_state;
......
......@@ -414,17 +414,18 @@ static int tls_channel_connect_to(belle_sip_channel_t *obj, const struct addrinf
return -1;
}
static void http_proxy_res_done(void *data, const char *name, struct addrinfo *ai_list, uint32_t ttl){
static void http_proxy_res_done(void *data, belle_sip_resolver_results_t *results){
belle_sip_tls_channel_t *obj=(belle_sip_tls_channel_t*)data;
const struct addrinfo *ai_list;
if (obj->http_proxy_resolver_ctx){
belle_sip_object_unref(obj->http_proxy_resolver_ctx);
obj->http_proxy_resolver_ctx=NULL;
}
ai_list = belle_sip_resolver_results_get_addrinfos(results);
if (ai_list){
tls_channel_connect_to((belle_sip_channel_t *)obj,ai_list);
bctbx_freeaddrinfo(ai_list);
}else{
belle_sip_error("%s: DNS resolution failed for %s", __FUNCTION__, name);
belle_sip_error("%s: DNS resolution failed for %s", __FUNCTION__, belle_sip_resolver_results_get_name(results));
channel_set_state((belle_sip_channel_t*)obj,BELLE_SIP_CHANNEL_ERROR);
}
}
......
......@@ -41,8 +41,9 @@ typedef struct endpoint {
belle_sip_resolver_context_t *resolver_ctx;
int resolve_done;
int resolve_ko;
struct addrinfo *ai_list;
belle_sip_list_t *srv_list; /**< List of struct dns_srv pointers */
bctbx_list_t *srv_list;
belle_sip_resolver_results_t *results;
const struct addrinfo *ai_list;
} endpoint_t;
static unsigned int wait_for(belle_sip_stack_t *stack, int *current_value, int expected_value, int timeout) {
......@@ -68,12 +69,13 @@ static void reset_endpoint(endpoint_t *endpoint) {
endpoint->resolver_ctx = 0;
endpoint->resolve_done = 0;
endpoint->resolve_ko = 0;
if (endpoint->ai_list != NULL) {
bctbx_freeaddrinfo(endpoint->ai_list);
endpoint->ai_list = NULL;
if (endpoint->results) {
belle_sip_object_unref(endpoint->results);
endpoint->results = NULL;
}
if (endpoint->srv_list != NULL) {
belle_sip_list_free_with_data(endpoint->srv_list, belle_sip_object_unref);
endpoint->ai_list = NULL;
if (endpoint->srv_list){
bctbx_list_free_with_data(endpoint->srv_list, belle_sip_object_unref);
endpoint->srv_list = NULL;
}
}
......@@ -85,12 +87,14 @@ static void destroy_endpoint(endpoint_t *endpoint) {
belle_sip_uninit_sockets();
}
static void a_resolve_done(void *data, const char *name, struct addrinfo *ai_list, uint32_t ttl) {
static void a_resolve_done(void *data, belle_sip_resolver_results_t *results) {
endpoint_t *client = (endpoint_t *)data;
BELLESIP_UNUSED(name);
client->resolve_done = 1;
if (ai_list) {
client->ai_list = ai_list;
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);
client->resolve_done = 1;
} else
client->resolve_ko = 1;
......
......@@ -22,23 +22,21 @@
static belle_sip_stack_t *stack;
static void resolver_callback(void *data, const char *queried_name, struct addrinfo *ai_list, unsigned int ttl){
static void resolver_callback(void *data, belle_sip_resolver_results_t *results){
int err;
struct addrinfo *ai_it;
const struct addrinfo *ai_it;
char name[NI_MAXHOST];
char port[NI_MAXSERV];
const struct addrinfo *ai_list = belle_sip_resolver_results_get_addrinfos(results);
for(ai_it=ai_list;ai_it!=NULL;ai_it=ai_it->ai_next){
err=bctbx_getnameinfo(ai_it->ai_addr,ai_list->ai_addrlen,name,sizeof(name),port,sizeof(port),NI_NUMERICSERV|NI_NUMERICHOST);
if (err!=0){
fprintf(stderr,"getnameinfo error: %s",gai_strerror(err));
}else{
printf("\t%s %s (ttl:%u)\n",name,port,ttl);
printf("\t%s %s (ttl:%u)\n",name,port,belle_sip_resolver_results_get_ttl(results));
}
}
if (ai_list){
bctbx_freeaddrinfo(ai_list);
}
belle_sip_main_loop_quit(belle_sip_stack_get_main_loop(stack));
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment