Commit 9d07cdad authored by Simon Morlat's avatar Simon Morlat

UDP channel wasn't failing to send an IPv6 packet if IPv6 is not available....

UDP channel wasn't failing to send an IPv6 packet if IPv6 is not available. This is now fixed and allows fallback to ipv4.
parent 459c3994
......@@ -96,8 +96,10 @@ BELLESIP_EXPORT void belle_sip_resolver_context_cancel(belle_sip_resolver_contex
/**
* Lookups the source address from local interface that can be used to connect to a destination address.
* local_port is only used to be assigned into the result source address.
* This function always puts something in src and srclen (the loopback address) even if anything fails.
* The return code is 0 if successful, or -errno if an error was encoutered. Typical error is -ENETUNREACH when IPv6 network is not reachable.
**/
BELLESIP_EXPORT void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port);
BELLESIP_EXPORT int belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port);
BELLE_SIP_END_DECLS
......
......@@ -1097,11 +1097,11 @@ void belle_sip_resolver_context_cancel(belle_sip_resolver_context_t *obj){
This function does the connect() method to get local ip address suitable to reach a given destination.
It works on all platform except for windows using ipv6 sockets. TODO: find a workaround for win32+ipv6 socket
*/
void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port){
int belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen, struct sockaddr *src, socklen_t *srclen, int local_port){
int af_type=dest->sa_family;
int sock=(int)socket(af_type,SOCK_DGRAM,IPPROTO_UDP);
int ret = 0;
belle_sip_message("belle_sip_get_src_addr_for(): af_inet6=%i",af_type==AF_INET6);
if (sock==(belle_sip_socket_t)-1){
if (af_type == AF_INET){
belle_sip_fatal("Could not create socket: %s",belle_sip_get_socket_error_string());
......@@ -1110,17 +1110,19 @@ void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen,
}
if (af_type==AF_INET6 && (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)dest)->sin6_addr))){
/*this is actually required only for windows, who is enable to provide an ipv4 mapped local address if the remote is ipv4 mapped,
/*this is actually required only for windows, who is unable to provide an ipv4 mapped local address if the remote is ipv4 mapped,
and unable to provide a correct local address if the remote address is true ipv6 address when in dual stack mode*/
belle_sip_socket_enable_dual_stack(sock);
}
if (connect(sock,dest,destlen)==-1){
belle_sip_error("belle_sip_get_src_addr_for: connect() failed: %s",belle_sip_get_socket_error_string());
ret = -get_socket_error();
goto fail;
}
if (getsockname(sock,src,srclen)==-1){
belle_sip_error("belle_sip_get_src_addr_for: getsockname() failed: %s",belle_sip_get_socket_error_string());
ret = -get_socket_error();
goto fail;
}
......@@ -1133,7 +1135,7 @@ void belle_sip_get_src_addr_for(const struct sockaddr *dest, socklen_t destlen,
}
belle_sip_close_socket(sock);
return;
return ret;
fail:
{
struct addrinfo *res = bctbx_ip_address_to_addrinfo(af_type, SOCK_STREAM, af_type == AF_INET ? "127.0.0.1" : "::1", local_port);
......@@ -1146,4 +1148,5 @@ fail:
}
}
if (sock!=(belle_sip_socket_t)-1) belle_sip_close_socket(sock);
return ret;
}
......@@ -25,6 +25,8 @@ BELLE_SIP_DECLARE_CUSTOM_VPTR_END
struct belle_sip_udp_channel{
belle_sip_channel_t base;
belle_sip_socket_t shared_socket; /*the socket that belongs to the listening point. It is stored here because the channel parent class
may erase its value in the belle_sip_source_t base class*/
};
typedef struct belle_sip_udp_channel belle_sip_udp_channel_t;
......@@ -63,12 +65,17 @@ static int udp_channel_recv(belle_sip_channel_t *obj, void *buf, size_t buflen){
}
int udp_channel_connect(belle_sip_channel_t *obj, const struct addrinfo *ai){
belle_sip_udp_channel_t *chan=(belle_sip_udp_channel_t *)obj;
struct sockaddr_storage laddr={0};
socklen_t lslen=sizeof(laddr);
if (obj->local_ip==NULL){
belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*)&laddr,&lslen,obj->local_port);
if (belle_sip_get_src_addr_for(ai->ai_addr,(socklen_t)ai->ai_addrlen,(struct sockaddr*)&laddr,&lslen,obj->local_port) == -BCTBX_ENETUNREACH){
return -1;
}
}
belle_sip_channel_set_ready(obj,(struct sockaddr*)&laddr,lslen);
belle_sip_channel_set_socket(obj, chan->shared_socket, NULL);
belle_sip_channel_set_ready(obj, (struct sockaddr*)&laddr, lslen);
return 0;
}
......@@ -94,7 +101,7 @@ BELLE_SIP_INSTANCIATE_CUSTOM_VPTR_END
belle_sip_channel_t * belle_sip_channel_new_udp(belle_sip_stack_t *stack, int sock, const char *bindip, int localport, const char *dest, int port){
belle_sip_udp_channel_t *obj=belle_sip_object_new(belle_sip_udp_channel_t);
belle_sip_channel_init((belle_sip_channel_t*)obj,stack,bindip,localport,NULL,dest,port);
belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,NULL);
obj->shared_socket = sock;
return (belle_sip_channel_t*)obj;
}
......@@ -103,7 +110,7 @@ belle_sip_channel_t * belle_sip_channel_new_udp_with_addr(belle_sip_stack_t *sta
belle_sip_channel_init_with_addr((belle_sip_channel_t*)obj, stack, bindip, localport, peer->ai_addr, (socklen_t)peer->ai_addrlen);
obj->base.local_port=localport;
belle_sip_channel_set_socket((belle_sip_channel_t*)obj,sock,NULL);
obj->shared_socket = sock;
/*this lookups the local address*/
udp_channel_connect((belle_sip_channel_t*)obj,peer);
return (belle_sip_channel_t*)obj;
......
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