* libnetworking/netdb.h, libnetworking/libc/gethostbyht.c,
	libnetworking/libc/gethostnamadr.c: This patch adds a functional
	gethostbyname_r to RTEMS. We were having problems with multiple
	threads calling gethostbyname, so we decided the best way to deal
	with it was to do it properly, rather than kludge up our code to make
	gethostbyname safe. We have found several slightly different
	parameter lists for this function, it does not seem to be standard.
	The one we used has the linux interface. In RTEMS there was an
	existing gethostbyname_r inside a #ifdef _THREAD_SAFE which was NOT
	Threadsafe, as this just called gethostbyname. So we have placed all
	of the additional code inside the #ifdef _THREAD_SAFE.
This commit is contained in:
Joel Sherrill
2006-11-02 21:48:41 +00:00
parent e1d578d8bc
commit 068c3ee1df
4 changed files with 349 additions and 21 deletions
+14
View File
@@ -1,3 +1,17 @@
2006-11-02 Steven Johnson <sjohnson@sakuraindustries.com>
* libnetworking/netdb.h, libnetworking/libc/gethostbyht.c,
libnetworking/libc/gethostnamadr.c: This patch adds a functional
gethostbyname_r to RTEMS. We were having problems with multiple
threads calling gethostbyname, so we decided the best way to deal
with it was to do it properly, rather than kludge up our code to make
gethostbyname safe. We have found several slightly different
parameter lists for this function, it does not seem to be standard.
The one we used has the linux interface. In RTEMS there was an
existing gethostbyname_r inside a #ifdef _THREAD_SAFE which was NOT
Threadsafe, as this just called gethostbyname. So we have placed all
of the additional code inside the #ifdef _THREAD_SAFE.
2006-10-30 Joel Sherrill <joel@OARcorp.com>
PR 841/rtems
+117
View File
@@ -67,6 +67,7 @@ static char rcsid[] = "$Id$";
#include <string.h>
#include <arpa/nameser.h> /* XXX */
#include <resolv.h> /* XXX */
#include <sys/fcntl.h>
#define MAXALIASES 35
@@ -78,6 +79,10 @@ static u_char host_addr[16]; /* IPv4 or IPv6 */
static char *h_addr_ptrs[2];
static int stayopen = 0;
static char* hostmap = NULL;
static unsigned int hostlen = 0;
static char *cur;
void
_sethosthtent(f)
int f;
@@ -200,3 +205,115 @@ _gethostbyhtaddr(addr, len, af)
endhostent();
return (p);
}
#ifdef _THREAD_SAFE
static int isblank ( int ch )
{
return ch == ' ' || ch == '\t';
}
struct hostent* gethostent_r(char* buf, int len)
{
char *dest;
struct hostent* pe=(struct hostent*)buf;
char* last;
char* max=buf+len;
int aliasidx;
int curlen;
if (hostf<0) return 0;
fseek(hostf,0,SEEK_END);
curlen=ftell(hostf);
fseek(hostf,0,SEEK_SET);
if (curlen > hostlen) {
if (hostmap) {
hostmap = realloc(hostmap,curlen);
}
else {
hostmap = malloc(curlen);
}
}
hostlen = curlen;
if (hostmap) {
if (fread(hostmap,hostlen,1,hostf) != hostlen) {
hostmap=0; goto error;
}
cur=hostmap;
}
last=hostmap+hostlen;
again:
if ((size_t)len<sizeof(struct hostent)+11*sizeof(char*)) goto nospace;
dest=buf+sizeof(struct hostent);
pe->h_name=0;
pe->h_aliases=(char**)dest; pe->h_aliases[0]=0; dest+=10*sizeof(char*);
pe->h_addr_list=(char**)dest; dest+=2*sizeof(char**);
if (cur>=last) return 0;
if (*cur=='#' || *cur=='\n') goto parseerror;
/* first, the ip number */
pe->h_name=cur;
while (cur<last && !isspace(*cur)) cur++;
if (cur>=last) return 0;
if (*cur=='\n') goto parseerror;
{
char save=*cur;
*cur=0;
pe->h_addr_list[0]=dest;
pe->h_addr_list[1]=0;
if (max-dest<16) goto nospace;
if (inet_pton(AF_INET6,pe->h_name,dest)>0) {
pe->h_addrtype=AF_INET6;
pe->h_length=16;
dest+=16;
} else if (inet_pton(AF_INET,pe->h_name,dest)>0) {
pe->h_addrtype=AF_INET;
pe->h_length=4;
dest+=4;
} else {
*cur=save;
goto parseerror;
}
*cur=save;
}
++cur;
/* now the aliases */
for (aliasidx=0;aliasidx<9;++aliasidx) {
while (cur<last && isblank(*cur)) ++cur;
pe->h_aliases[aliasidx]=cur;
while (cur<last && !isspace(*cur)) ++cur;
{
char *from=pe->h_aliases[aliasidx];
int len=cur-from;
if (max-dest<len+2) goto nospace;
pe->h_aliases[aliasidx]=dest;
memmove(dest,from,(size_t)(cur-from));
dest+=len;
*dest=0; ++dest;
}
if (*cur=='\n') { ++cur; ++aliasidx; break; }
if (cur>=last || !isblank(*cur)) break;
cur++;
}
pe->h_aliases[aliasidx]=0;
pe->h_name=pe->h_aliases[0];
pe->h_aliases++;
return pe;
parseerror:
while (cur<last && *cur!='\n') cur++;
cur++;
goto again;
nospace:
errno=ERANGE;
goto __error;
error:
errno=ENOMEM;
__error:
if (hostmap!=NULL) free(hostmap);
hostmap=NULL;
return 0;
}
#endif
+208 -21
View File
@@ -187,27 +187,6 @@ gethostbyaddr(const char *addr, int len, int type)
return hp;
}
#ifdef _THREAD_SAFE
struct hostent_data;
/*
* Temporary function (not thread safe)
*/
int gethostbyaddr_r(const char *addr, int len, int type,
struct hostent *result, struct hostent_data *buffer)
{
struct hostent *hp;
int ret;
if ((hp = gethostbyaddr(addr, len, type)) == NULL) {
ret = -1;
} else {
memcpy(result, hp, sizeof(struct hostent));
ret = 0;
}
return(ret);
}
#endif
void
sethostent(stayopen)
int stayopen;
@@ -222,3 +201,211 @@ endhostent()
_endhosthtent();
_endhostdnsent();
}
#ifdef _THREAD_SAFE
/* return length of decoded data or -1 */
static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest,
unsigned int maxlen,unsigned char* behindpacket) {
unsigned char *tmp;
unsigned char *max=dest+maxlen;
unsigned char *after=packet+offset;
int ok=0;
for (tmp=after; maxlen>0&&*tmp; ) {
if (tmp>=behindpacket) return -1;
if ((*tmp>>6)==3) { /* goofy DNS decompression */
unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1);
if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */
if (after<tmp+2) after=tmp+2;
tmp=packet+ofs;
ok=0;
} else {
unsigned int duh;
if (dest+*tmp+1>max) return -1;
if (tmp+*tmp+1>=behindpacket) return -1;
for (duh=*tmp; duh>0; --duh)
*dest++=*++tmp;
*dest++='.'; ok=1;
++tmp;
if (tmp>after) { after=tmp; if (!*tmp) ++after; }
}
}
if (ok) --dest;
*dest=0;
return after-packet;
}
static int __dns_gethostbyx_r(const char* name, struct hostent* result,
char *buf, size_t buflen,
struct hostent **RESULT, int *h_errnop, int lookfor) {
int names,ips;
unsigned char *cur;
unsigned char *max;
unsigned char inpkg[1500];
char* tmp;
int size;
if (lookfor==1) {
result->h_addrtype=AF_INET;
result->h_length=4;
} else {
result->h_addrtype=AF_INET6;
result->h_length=16;
}
result->h_aliases=(char**)(buf+8*sizeof(char*));
result->h_addr_list=(char**)buf;
result->h_aliases[0]=0;
cur=buf+16*sizeof(char*);
max=buf+buflen;
names=ips=0;
if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) {
invalidpacket:
*h_errnop=HOST_NOT_FOUND;
return -1;
}
{
tmp=inpkg+12;
{
char Name[257];
unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5];
while (q>0) {
if (tmp>(char*)inpkg+size) goto invalidpacket;
while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; }
tmp+=5;
--q;
}
if (tmp>(char*)inpkg+size) goto invalidpacket;
q=((unsigned short)inpkg[6]<<8)+inpkg[7];
if (q<1) goto nodata;
while (q>0) {
int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
if (decofs<0) break;
tmp=inpkg+decofs;
--q;
if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */
tmp[2]!=0 || tmp[3]!=1) { /* CLASS != IN */
if (tmp[1]==5) { /* CNAME */
tmp+=10;
decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
if (decofs<0) break;
tmp=inpkg+decofs;
} else
break;
continue;
}
tmp+=10; /* skip type, class, TTL and length */
{
int slen;
if (lookfor==1 || lookfor==28) /* A or AAAA*/ {
slen=strlen(Name);
if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; }
} else if (lookfor==12) /* PTR */ {
decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
if (decofs<0) break;
tmp=inpkg+decofs;
slen=strlen(Name);
} else
slen=strlen(Name);
strcpy(cur,Name);
if (names==0)
result->h_name=cur;
else
result->h_aliases[names-1]=cur;
result->h_aliases[names]=0;
if (names<8) ++names;
/* cur+=slen+1; */
cur+=(slen|3)+1;
result->h_addr_list[ips++] = cur;
if (lookfor==1) /* A */ {
*(int*)cur=*(int*)tmp;
cur+=4;
result->h_addr_list[ips]=0;
} else if (lookfor==28) /* AAAA */ {
{
int k;
for (k=0; k<16; ++k) cur[k]=tmp[k];
}
cur+=16;
result->h_addr_list[ips]=0;
}
}
/* puts(Name); */
}
}
}
if (!names) {
nodata:
*h_errnop=NO_DATA;
return -1;
}
*h_errnop=0;
*RESULT=result;
return 0;
}
int gethostbyname_r(const char* name,
struct hostent* result,
char *buf,
int buflen,
struct hostent **RESULT,
int *h_errnop)
{
size_t L=strlen(name);
result->h_name=buf;
if (buflen<L) { *h_errnop=ERANGE; return 1; }
strcpy(buf,name);
result->h_addr_list=(char**)(buf+strlen(name)+1);
result->h_addr_list+=sizeof(unsigned long)-((unsigned long)(result->h_addr_list)&(sizeof(unsigned long)-1));
result->h_addr_list[0]=(char*)&result->h_addr_list[2];
if (inet_pton(AF_INET,name,result->h_addr_list[0])) {
result->h_addrtype=AF_INET;
result->h_length=4;
commonip:
result->h_aliases=result->h_addr_list+2*sizeof(char**);
result->h_aliases[0]=0;
result->h_addr_list[1]=0;
*RESULT=result;
*h_errnop=0;
return 0;
} else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) {
result->h_addrtype=AF_INET6;
result->h_length=16;
goto commonip;
}
{
struct hostent* r;
sethostent(0);
while ((r=gethostent_r(buf,buflen))) {
int i;
if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) { /* found it! */
found:
memmove(result,r,sizeof(struct hostent));
*RESULT=result;
*h_errnop=0;
endhostent();
return 0;
}
for (i=0; i<16; ++i) {
if (r->h_aliases[i]) {
if (!strcasecmp(r->h_aliases[i],name)) goto found;
} else break;
}
}
endhostent();
}
return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1);
}
#endif
+10
View File
@@ -160,6 +160,16 @@ void setnetent(int);
void setprotoent(int);
void setservent(int);
#ifdef _THREAD_SAFE
struct hostent* gethostent_r(char* buf, int len);
int gethostbyname_r(const char* name,
struct hostent* result,
char *buf,
int buflen,
struct hostent **RESULT,
int *h_errnop) ;
#endif
/*
* PRIVATE functions specific to the FreeBSD implementation
*/