Ignore:
Timestamp:
Nov 2, 2006, 9:48:41 PM (15 years ago)
Author:
Joel Sherrill <joel.sherrill@…>
Branches:
4.10, 4.11, 4.8, 4.9, 5, master
Children:
918b7a9
Parents:
e1d578d8
Message:

2006-11-02 Steven Johnson <sjohnson@…>

  • 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.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libnetworking/libc/gethostnamadr.c

    re1d578d8 r068c3ee1  
    188188}
    189189
    190 #ifdef _THREAD_SAFE
    191 struct hostent_data;
    192 
    193 /*
    194  * Temporary function (not thread safe)
    195  */
    196 int gethostbyaddr_r(const char *addr, int len, int type,
    197         struct hostent *result, struct hostent_data *buffer)
    198 {
    199         struct hostent *hp;
    200         int ret;
    201         if ((hp = gethostbyaddr(addr, len, type)) == NULL) {
    202                 ret = -1;
    203         } else {
    204                 memcpy(result, hp, sizeof(struct hostent));
    205                 ret = 0;
    206         }
    207         return(ret);
    208 }
    209 #endif
    210 
    211190void
    212191sethostent(stayopen)
     
    223202        _endhostdnsent();
    224203}
     204
     205#ifdef _THREAD_SAFE
     206
     207/* return length of decoded data or -1 */
     208static int __dns_decodename(unsigned char *packet,unsigned int offset,unsigned char *dest,
     209         unsigned int maxlen,unsigned char* behindpacket) {
     210  unsigned char *tmp;
     211  unsigned char *max=dest+maxlen;
     212  unsigned char *after=packet+offset;
     213  int ok=0;
     214  for (tmp=after; maxlen>0&&*tmp; ) {
     215    if (tmp>=behindpacket) return -1;
     216    if ((*tmp>>6)==3) {   /* goofy DNS decompression */
     217      unsigned int ofs=((unsigned int)(*tmp&0x3f)<<8)|*(tmp+1);
     218      if (ofs>=(unsigned int)offset) return -1; /* RFC1035: "pointer to a _prior_ occurrance" */
     219      if (after<tmp+2) after=tmp+2;
     220      tmp=packet+ofs;
     221      ok=0;
     222    } else {
     223      unsigned int duh;
     224      if (dest+*tmp+1>max) return -1;
     225      if (tmp+*tmp+1>=behindpacket) return -1;
     226      for (duh=*tmp; duh>0; --duh)
     227  *dest++=*++tmp;
     228      *dest++='.'; ok=1;
     229      ++tmp;
     230      if (tmp>after) { after=tmp; if (!*tmp) ++after; }
     231    }
     232  }
     233  if (ok) --dest;
     234  *dest=0;
     235  return after-packet;
     236}
     237
     238static int __dns_gethostbyx_r(const char* name, struct hostent* result,
     239      char *buf, size_t buflen,
     240      struct hostent **RESULT, int *h_errnop, int lookfor) {
     241
     242  int names,ips;
     243  unsigned char *cur;
     244  unsigned char *max;
     245  unsigned char inpkg[1500];
     246  char* tmp;
     247  int size;
     248
     249  if (lookfor==1) {
     250    result->h_addrtype=AF_INET;
     251    result->h_length=4;
     252  } else {
     253    result->h_addrtype=AF_INET6;
     254    result->h_length=16;
     255  }
     256  result->h_aliases=(char**)(buf+8*sizeof(char*));
     257  result->h_addr_list=(char**)buf;
     258  result->h_aliases[0]=0;
     259
     260  cur=buf+16*sizeof(char*);
     261  max=buf+buflen;
     262  names=ips=0;
     263
     264  if ((size=res_query(name,C_IN,lookfor,inpkg,512))<0) {
     265invalidpacket:
     266    *h_errnop=HOST_NOT_FOUND;
     267    return -1;
     268  }
     269  {
     270    tmp=inpkg+12;
     271    {
     272      char Name[257];
     273      unsigned short q=((unsigned short)inpkg[4]<<8)+inpkg[5];
     274      while (q>0) {
     275  if (tmp>(char*)inpkg+size) goto invalidpacket;
     276  while (*tmp) { tmp+=*tmp+1; if (tmp>(char*)inpkg+size) goto invalidpacket; }
     277  tmp+=5;
     278  --q;
     279      }
     280      if (tmp>(char*)inpkg+size) goto invalidpacket;
     281      q=((unsigned short)inpkg[6]<<8)+inpkg[7];
     282      if (q<1) goto nodata;
     283      while (q>0) {
     284  int decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
     285  if (decofs<0) break;
     286  tmp=inpkg+decofs;
     287  --q;
     288  if (tmp[0]!=0 || tmp[1]!=lookfor || /* TYPE != A */
     289      tmp[2]!=0 || tmp[3]!=1) {   /* CLASS != IN */
     290    if (tmp[1]==5) {  /* CNAME */
     291      tmp+=10;
     292      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
     293      if (decofs<0) break;
     294      tmp=inpkg+decofs;
     295    } else
     296      break;
     297    continue;
     298  }
     299  tmp+=10;  /* skip type, class, TTL and length */
     300  {
     301    int slen;
     302    if (lookfor==1 || lookfor==28) /* A or AAAA*/ {
     303      slen=strlen(Name);
     304      if (cur+slen+8+(lookfor==28?12:0)>=max) { *h_errnop=NO_RECOVERY; return -1; }
     305    } else if (lookfor==12) /* PTR */ {
     306      decofs=__dns_decodename(inpkg,(size_t)(tmp-(char*)inpkg),Name,256,inpkg+size);
     307      if (decofs<0) break;
     308      tmp=inpkg+decofs;
     309      slen=strlen(Name);
     310    } else
     311      slen=strlen(Name);
     312    strcpy(cur,Name);
     313    if (names==0)
     314      result->h_name=cur;
     315    else
     316      result->h_aliases[names-1]=cur;
     317    result->h_aliases[names]=0;
     318    if (names<8) ++names;
     319/*    cur+=slen+1; */
     320    cur+=(slen|3)+1;
     321    result->h_addr_list[ips++] = cur;
     322    if (lookfor==1) /* A */ {
     323      *(int*)cur=*(int*)tmp;
     324      cur+=4;
     325      result->h_addr_list[ips]=0;
     326    } else if (lookfor==28) /* AAAA */ {
     327      {
     328        int k;
     329        for (k=0; k<16; ++k) cur[k]=tmp[k];
     330      }
     331      cur+=16;
     332      result->h_addr_list[ips]=0;
     333    }
     334  }
     335/*        puts(Name); */
     336      }
     337    }
     338  }
     339  if (!names) {
     340nodata:
     341    *h_errnop=NO_DATA;
     342    return -1;
     343  }
     344  *h_errnop=0;
     345  *RESULT=result;
     346  return 0;
     347}
     348
     349
     350
     351
     352int gethostbyname_r(const char*      name,
     353        struct hostent*  result,
     354        char            *buf,
     355        int              buflen,
     356        struct hostent **RESULT,
     357        int             *h_errnop)
     358{
     359       
     360  size_t L=strlen(name);
     361  result->h_name=buf;
     362  if (buflen<L) { *h_errnop=ERANGE; return 1; }
     363  strcpy(buf,name);
     364
     365  result->h_addr_list=(char**)(buf+strlen(name)+1);
     366  result->h_addr_list+=sizeof(unsigned long)-((unsigned long)(result->h_addr_list)&(sizeof(unsigned long)-1));
     367  result->h_addr_list[0]=(char*)&result->h_addr_list[2];
     368  if (inet_pton(AF_INET,name,result->h_addr_list[0])) {
     369    result->h_addrtype=AF_INET;
     370    result->h_length=4;
     371commonip:
     372    result->h_aliases=result->h_addr_list+2*sizeof(char**);
     373    result->h_aliases[0]=0;
     374    result->h_addr_list[1]=0;
     375    *RESULT=result;
     376    *h_errnop=0;
     377    return 0;
     378  } else if (inet_pton(AF_INET6,name,result->h_addr_list[0])) {
     379    result->h_addrtype=AF_INET6;
     380    result->h_length=16;
     381    goto commonip;
     382  }
     383
     384
     385  {
     386    struct hostent* r;
     387    sethostent(0);
     388    while ((r=gethostent_r(buf,buflen))) {
     389      int i;
     390      if (r->h_addrtype==AF_INET && !strcasecmp(r->h_name,name)) {  /* found it! */
     391found:
     392  memmove(result,r,sizeof(struct hostent));
     393  *RESULT=result;
     394  *h_errnop=0;
     395  endhostent();
     396  return 0;
     397      }
     398      for (i=0; i<16; ++i) {
     399  if (r->h_aliases[i]) {
     400    if (!strcasecmp(r->h_aliases[i],name)) goto found;
     401  } else break;
     402      }
     403    }
     404    endhostent();
     405  }
     406
     407  return __dns_gethostbyx_r(name,result,buf+L,buflen-L,RESULT,h_errnop,1);
     408}
     409
     410#endif
     411
Note: See TracChangeset for help on using the changeset viewer.