Index: cpukit/ChangeLog
===================================================================
--- cpukit/ChangeLog	(revision e1d578d8bc2c30751e08effd7801af413250f81b)
+++ cpukit/ChangeLog	(revision 068c3ee1df9be23ee252428b87cfcf2c43cda3cf)
@@ -1,2 +1,16 @@
+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>
 
Index: cpukit/libnetworking/libc/gethostbyht.c
===================================================================
--- cpukit/libnetworking/libc/gethostbyht.c	(revision e1d578d8bc2c30751e08effd7801af413250f81b)
+++ cpukit/libnetworking/libc/gethostbyht.c	(revision 068c3ee1df9be23ee252428b87cfcf2c43cda3cf)
@@ -68,4 +68,5 @@
 #include <arpa/nameser.h>	/* XXX */
 #include <resolv.h>		/* XXX */
+#include <sys/fcntl.h>
 
 #define	MAXALIASES	35
@@ -78,4 +79,8 @@
 static char *h_addr_ptrs[2];
 static int stayopen = 0;
+
+static char* hostmap = NULL;
+static unsigned int hostlen = 0; 
+static char *cur;
 
 void
@@ -201,2 +206,114 @@
 	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
Index: cpukit/libnetworking/libc/gethostnamadr.c
===================================================================
--- cpukit/libnetworking/libc/gethostnamadr.c	(revision e1d578d8bc2c30751e08effd7801af413250f81b)
+++ cpukit/libnetworking/libc/gethostnamadr.c	(revision 068c3ee1df9be23ee252428b87cfcf2c43cda3cf)
@@ -188,25 +188,4 @@
 }
 
-#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)
@@ -223,2 +202,210 @@
 	_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
+
Index: cpukit/libnetworking/netdb.h
===================================================================
--- cpukit/libnetworking/netdb.h	(revision e1d578d8bc2c30751e08effd7801af413250f81b)
+++ cpukit/libnetworking/netdb.h	(revision 068c3ee1df9be23ee252428b87cfcf2c43cda3cf)
@@ -161,4 +161,14 @@
 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
