Commit 7fde3a34 authored by Simon Morlat's avatar Simon Morlat

add a wrapper to getaddrinfo() to workaround a bug in android's libc not...

add a wrapper to getaddrinfo() to workaround a bug in android's libc not supporting AI_V4MAPPED flag.
parent 46d14459
......@@ -194,6 +194,9 @@ typedef int belle_sip_fd_t;
#endif
BELLESIP_EXPORT int belle_sip_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
BELLESIP_EXPORT void belle_sip_freeaddrinfo(struct addrinfo *res);
BELLE_SIP_END_DECLS
#endif
......
......@@ -591,7 +591,7 @@ struct addrinfo * belle_sip_ip_address_to_addrinfo(int family, const char *ipadd
if (family==AF_INET6 && strchr(ipaddress,'.')!=NULL) {
hints.ai_flags|=AI_V4MAPPED;
}
err=getaddrinfo(ipaddress,serv,&hints,&res);
err=belle_sip_getaddrinfo(ipaddress,serv,&hints,&res);
if (err!=0){
if (err!=EAI_NONAME)
......
......@@ -1292,16 +1292,6 @@ belle_sip_channel_t *belle_sip_channel_find_from_list_with_addrinfo(belle_sip_li
return NULL;
}
/*
* Horrible bug: glibc seems to ignore AI_NUMERICHOST when hints as AF_INET6 family, resulting in very lengthly getaddrinfo() execution.
* In order to workaround it, we request getaddrinfo() only in cases where the destination we want to lookup is an IP address.*/
static int seems_numeric_ip_address(const char *ip){
int a,b,c,d;
if (strchr(ip,':')) return TRUE; /*should be an IPv6*/
if (sscanf(ip,"%i.%i.%i.%i",&a,&b,&c,&d)==4) return TRUE;
return FALSE;
}
/* search a matching channel from a list according to supplied hop. The ai_family tells which address family is supported by the list of channels*/
belle_sip_channel_t *belle_sip_channel_find_from_list(belle_sip_list_t *l, int ai_family, const belle_sip_hop_t *hop){
......@@ -1310,14 +1300,13 @@ belle_sip_channel_t *belle_sip_channel_find_from_list(belle_sip_list_t *l, int a
char portstr[20];
belle_sip_channel_t *chan;
if (seems_numeric_ip_address(hop->host)){
hints.ai_family=ai_family;
hints.ai_flags=AI_NUMERICHOST|AI_NUMERICSERV;
hints.ai_socktype=SOCK_STREAM; // needed on some platforms that return an error otherwise (QNX)
if (ai_family==AF_INET6) hints.ai_flags=AI_V4MAPPED;
snprintf(portstr,sizeof(portstr),"%i",hop->port);
getaddrinfo(hop->host,portstr,&hints,&res);
}
hints.ai_family=ai_family;
hints.ai_flags=AI_NUMERICHOST|AI_NUMERICSERV;
hints.ai_socktype=SOCK_STREAM; // needed on some platforms that return an error otherwise (QNX)
if (ai_family==AF_INET6) hints.ai_flags|=AI_V4MAPPED|AI_ALL;
snprintf(portstr,sizeof(portstr),"%i",hop->port);
belle_sip_getaddrinfo(hop->host,portstr,&hints,&res);
chan=belle_sip_channel_find_from_list_with_addrinfo(l,hop,res);
if (res) freeaddrinfo(res);
return chan;
......
......@@ -190,7 +190,123 @@ int belle_sip_socket_set_dscp(belle_sip_socket_t sock, int ai_family, int dscp){
#endif
#ifdef ANDROID
/*
* SHAME !!! bionic's getaddrinfo does not implement the AI_V4MAPPED flag !
* It is declared in header file but rejected by the implementation.
* The code below is to emulate a _compliant_ getaddrinfo for android.
**/
struct addrinfo *_belle_sip_alloc_addrinfo(int ai_family, int socktype, int proto){
struct addrinfo *ai=(struct addrinfo*)belle_sip_malloc0(sizeof(struct addrinfo));
ai->ai_family=ai_family;
ai->ai_socktype=socktype;
ai->ai_protocol=proto;
ai->ai_addrlen=AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
ai->ai_addr=(struct sockaddr *) belle_sip_malloc0(ai->ai_addrlen);
return ai;
}
struct addrinfo *convert_to_v4mapped(const struct addrinfo *ai){
struct addrinfo *res=NULL;
const struct addrinfo *it;
struct addrinfo *v4m=NULL;
struct addrinfo *last=NULL;
for (it=ai;it!=NULL;it=it->ai_next){
struct sockaddr_in6 *sin6;
struct sockaddr_in *sin;
v4m=_belle_sip_alloc_addrinfo(AF_INET6, it->ai_socktype, it->ai_protocol);
sin6=(struct sockaddr_in6*)v4m->ai_addr;
sin=(struct sockaddr_in*)it->ai_addr;
sin6->sin6_family=AF_INET6;
((uint8_t*)&sin6->sin6_addr)[10]=0xff;
((uint8_t*)&sin6->sin6_addr)[11]=0xff;
memcpy(((uint8_t*)&sin6->sin6_addr)+12,&sin->sin_addr,4);
sin6->sin6_port=sin->sin_port;
if (last){
last->ai_next=v4m;
}else{
res=v4m;
}
last=v4m;
}
return res;
}
struct addrinfo *addrinfo_concat(struct addrinfo *a1, struct addrinfo *a2){
struct addrinfo *it;
struct addrinfo *last=NULL;
for (it=a1;it!=NULL;it=it->ai_next){
last=it;
}
if (last){
last->ai_next=a2;
return a1;
}else
return a2;
}
int belle_sip_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){
if (hints && hints->ai_family!=AF_INET && hints->ai_flags & AI_V4MAPPED){
struct addrinfo *res6=NULL;
struct addrinfo *res4=NULL;
struct addrinfo lhints={0};
int err;
if (hints) memcpy(&lhints,hints,sizeof(lhints));
lhints.ai_flags &= ~(AI_ALL & AI_V4MAPPED); /*remove the unsupported flags*/
if (hints->ai_flags & AI_ALL){
lhints.ai_family=AF_INET6;
err=getaddrinfo(node, service, &lhints, &res6);
}
lhints.ai_family=AF_INET;
err=getaddrinfo(node, service, &lhints, &res4);
if (err==0){
struct addrinfo *v4m=convert_to_v4mapped(res4);
freeaddrinfo(res4);
res4=v4m;
}
*res=addrinfo_concat(res6,res4);
if (*res) err=0;
return err;
}
return getaddrinfo(node, service, hints, res);
}
void _belle_sip_freeaddrinfo(struct addrinfo *res){
struct addrinfo *it,*next_it;
for(it=res;it!=NULL;it=next_it){
next_it=it->ai_next;
belle_sip_free(it->ai_addr);
belle_sip_free(it);
}
}
void belle_sip_freeaddrinfo(struct addrinfo *res){
struct addrinfo *it,*previt=NULL;
struct addrinfo *allocated_by_belle_sip=NULL;
for(it=res;it!=NULL;it=it->ai_next){
if (it->ai_flags & AI_V4MAPPED){
allocated_by_belle_sip=it;
if (previt) previt->ai_next=NULL;
}
previt=it;
}
freeaddrinfo(res);
if (allocated_by_belle_sip) _belle_sip_freeaddrinfo(allocated_by_belle_sip);
}
#else
int belle_sip_getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res){
return getaddrinfo(node, service, hints, res);
}
void belle_sip_freeaddrinfo(struct addrinfo *res){
freeaddrinfo(res);
}
#endif
......@@ -58,6 +58,9 @@
# ifndef AI_V4MAPPED
# define AI_V4MAPPED 0x00000800
# endif
# ifndef AI_ALL
# define AI_ALL 0x00000000
# endif
#endif
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__)
......
......@@ -26,46 +26,75 @@
#include <string.h>
#include "belle-sip/belle-sip.h"
#include "belle-sip/belle-sdp.h"
int main(int argc, char *argv[]){
char *str;
struct stat st;
int fd;
int i;
const char *filename=NULL;
const char *protocol="sip";
if (argc!=2){
fprintf(stderr,"Usage:\n%s <text file containing messages>\n",argv[0]);
if (argc<2){
fprintf(stderr,"Usage:\n%s [--protocol sip|http|sdp] <text file containing messages>\n",argv[0]);
return -1;
}
if (stat(argv[1],&st)==-1){
fprintf(stderr,"Could not stat %s: %s\n",argv[1],strerror(errno));
for(i=1;i<argc;++i){
if (strcmp(argv[i],"--protocol")==0){
i++;
if (i<argc){
protocol=argv[i];
}else{
fprintf(stderr,"Missing argument for --protocol\n");
return -1;
}
}else filename=argv[i];
}
if (!filename){
fprintf(stderr,"No filename specified\n");
return -1;
}
if (stat(filename,&st)==-1){
fprintf(stderr,"Could not stat %s: %s\n",filename,strerror(errno));
return -1;
}
fd=open(argv[1],O_RDONLY);
fd=open(filename,O_RDONLY);
if (fd==-1){
fprintf(stderr,"Could not open %s: %s\n",argv[1],strerror(errno));
fprintf(stderr,"Could not open %s: %s\n",filename,strerror(errno));
return -1;
}
str=belle_sip_malloc0(st.st_size+1);
if (read(fd,str,st.st_size)==-1){
fprintf(stderr,"Could not open %s: %s\n",argv[1],strerror(errno));
fprintf(stderr,"Could not read %s: %s\n",filename,strerror(errno));
belle_sip_free(str);
close(fd);
return -1;
}
close(fd);
belle_sip_set_log_level(BELLE_SIP_LOG_WARNING);
for (i=0;i<st.st_size;){
size_t read;
belle_sip_message_t *msg=belle_sip_message_parse_raw(str+i,st.st_size-i,&read);
if (msg){
printf("Succesfully parsed message of %i bytes.",(int)read);
}else{
fprintf(stderr,"Failed to parse message.");
if (strcasecmp(protocol,"sip")==0 || strcasecmp(protocol,"http")==0){
belle_sip_message_t *msg=belle_sip_message_parse_raw(str+i,st.st_size-i,&read);
if (msg){
printf("Succesfully parsed %s message of %i bytes.\n",protocol,(int)read);
}else{
fprintf(stderr,"Failed to parse message.");
break;
}
i+=read;
}else if (strcasecmp(protocol,"sdp")==0){
belle_sdp_session_description_t *sdp=belle_sdp_session_description_parse(str);
if (sdp){
printf("Succesfully parsed %s message of %i bytes.\n",protocol,(int)strlen(str));
}else{
fprintf(stderr,"Failed to parse SDP message.");
}
break;
}
i+=read;
}
belle_sip_free(str);
return 0;
......
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