else canonlen = 0;
gaih_inet (const char *name, const struct gaih_service *service,	   const struct addrinfo *req, struct addrinfo **pai){  const struct gaih_typeproto *tp = gaih_inet_typeproto;  struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv;  struct gaih_addrtuple *at = NULL;  int rc;  bool got_ipv6 = false;  const char *canon = NULL;  if (req->ai_protocol || req->ai_socktype)    {      ++tp;      while (tp->name[0]	     && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype)		 || (req->ai_protocol != 0		     && !(tp->protoflag & GAI_PROTO_PROTOANY)		     && req->ai_protocol != tp->protocol)))	++tp;      if (! tp->name[0])	{	  if (req->ai_socktype)	    return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);	  else	    return (GAIH_OKIFUNSPEC | -EAI_SERVICE);	}    }  if (service != NULL)    {      if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)	return (GAIH_OKIFUNSPEC | -EAI_SERVICE);      if (service->num < 0)	{	  if (tp->name[0])	    {	      st = (struct gaih_servtuple *)		__alloca (sizeof (struct gaih_servtuple));	      if ((rc = gaih_inet_serv (service->name, tp, req, st)))		return rc;	    }	  else	    {	      struct gaih_servtuple **pst = &st;	      for (tp++; tp->name[0]; tp++)		{		  struct gaih_servtuple *newp;		  if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0)		    continue;		  if (req->ai_socktype != 0		      && req->ai_socktype != tp->socktype)		    continue;		  if (req->ai_protocol != 0		      && !(tp->protoflag & GAI_PROTO_PROTOANY)		      && req->ai_protocol != tp->protocol)		    continue;		  newp = (struct gaih_servtuple *)		    __alloca (sizeof (struct gaih_servtuple));		  if ((rc = gaih_inet_serv (service->name, tp, req, newp)))		    {		      if (rc & GAIH_OKIFUNSPEC)			continue;		      return rc;		    }		  *pst = newp;		  pst = &(newp->next);		}	      if (st == (struct gaih_servtuple *) &nullserv)		return (GAIH_OKIFUNSPEC | -EAI_SERVICE);	    }	}      else	{	  st = __alloca (sizeof (struct gaih_servtuple));	  st->next = NULL;	  st->socktype = tp->socktype;	  st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)			  ? req->ai_protocol : tp->protocol);	  st->port = htons (service->num);	}    }  else if (req->ai_socktype || req->ai_protocol)    {      st = __alloca (sizeof (struct gaih_servtuple));      st->next = NULL;      st->socktype = tp->socktype;      st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY)		      ? req->ai_protocol : tp->protocol);      st->port = 0;    }  else    {      /* Neither socket type nor protocol is set.  Return all socket types	 we know about.  */      struct gaih_servtuple **lastp = &st;      for (++tp; tp->name[0]; ++tp)	{	  struct gaih_servtuple *newp;	  newp = __alloca (sizeof (struct gaih_servtuple));	  newp->next = NULL;	  newp->socktype = tp->socktype;	  newp->protocol = tp->protocol;	  newp->port = 0;	  *lastp = newp;	  lastp = &newp->next;	}    }  if (name != NULL)    {      at = __alloca (sizeof (struct gaih_addrtuple));      at->family = AF_UNSPEC;      at->scopeid = 0;      at->next = NULL;#ifdef HAVE_LIBIDN      if (req->ai_flags & AI_IDN)	{	  int idn_flags = 0;	  if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)	    idn_flags |= IDNA_ALLOW_UNASSIGNED;	  if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)	    idn_flags |= IDNA_USE_STD3_ASCII_RULES;	  char *p = NULL;	  rc = __idna_to_ascii_lz (name, &p, idn_flags);	  if (rc != IDNA_SUCCESS)	    {	      if (rc == IDNA_MALLOC_ERROR)		return -EAI_MEMORY;	      if (rc == IDNA_DLOPEN_ERROR)		return -EAI_SYSTEM;	      return -EAI_IDN_ENCODE;	    }	  /* In case the output string is the same as the input string	     no new string has been allocated.  */	  if (p != name)	    {	      name = strdupa (p);	      free (p);	    }	}#endif      if (__inet_aton (name, (struct in_addr *) at->addr) != 0)	{	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)	    at->family = AF_INET;	  else if (req->ai_family == AF_INET6 && req->ai_flags & AI_V4MAPPED)	    {	      at->addr[3] = at->addr[0];	      at->addr[2] = htonl (0xffff);	      at->addr[1] = 0;	      at->addr[0] = 0;	      at->family = AF_INET6;	    }	  else	    return -EAI_ADDRFAMILY;	}      if (at->family == AF_UNSPEC)	{	  char *namebuf = strdupa (name);	  char *scope_delim;	  scope_delim = strchr (namebuf, SCOPE_DELIMITER);	  if (scope_delim != NULL)	    *scope_delim = '\0';	  if (inet_pton (AF_INET6, namebuf, at->addr) > 0)	    {	      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)		at->family = AF_INET6;	      else if (req->ai_family == AF_INET		       && IN6_IS_ADDR_V4MAPPED (at->addr))		{		  at->addr[0] = at->addr[3];		  at->family = AF_INET;		}	      else		return -EAI_ADDRFAMILY;	      if (scope_delim != NULL)		{		  int try_numericscope = 0;		  if (IN6_IS_ADDR_LINKLOCAL (at->addr)		      || IN6_IS_ADDR_MC_LINKLOCAL (at->addr))		    {		      at->scopeid = if_nametoindex (scope_delim + 1);		      if (at->scopeid == 0)			try_numericscope = 1;		    }		  else		    try_numericscope = 1;		  if (try_numericscope != 0)		    {		      char *end;		      assert (sizeof (uint32_t) <= sizeof (unsigned long));		      at->scopeid = (uint32_t) strtoul (scope_delim + 1, &end,							10);		      if (*end != '\0')			return GAIH_OKIFUNSPEC | -EAI_NONAME;		    }		}	    }	}      if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0)	{	  struct hostent *h;	  struct gaih_addrtuple **pat = &at;	  int no_data = 0;	  int no_inet6_data = 0;	  service_user *nip = NULL;	  enum nss_status inet6_status = NSS_STATUS_UNAVAIL;	  enum nss_status status = NSS_STATUS_UNAVAIL;	  int no_more;	  nss_gethostbyname2_r fct;	  int old_res_options;	  size_t tmpbuflen = 512;	  char *tmpbuf = alloca (tmpbuflen);	  if (__nss_hosts_database != NULL)	    {	      no_more = 0;	      nip = __nss_hosts_database;	    }	  else	    no_more = __nss_database_lookup ("hosts", NULL,					     "dns [!UNAVAIL=return] files",					     &nip);	  if (__res_maybe_init (&_res, 0) == -1)	    no_more = 1;	  /* If we are looking for both IPv4 and IPv6 address we don't	     want the lookup functions to automatically promote IPv4	     addresses to IPv6 addresses.  Currently this is decided	     by setting the RES_USE_INET6 bit in _res.options.  */	  old_res_options = _res.options;	  _res.options &= ~RES_USE_INET6;	  while (!no_more)	    {	      fct = __nss_lookup_function (nip, "gethostbyname2_r");	      if (fct != NULL)		{		  if (req->ai_family == AF_INET6		      || req->ai_family == AF_UNSPEC)		    {		      gethosts (AF_INET6, struct in6_addr);		      no_inet6_data = no_data;		      inet6_status = status;		    }		  if (req->ai_family == AF_INET		      || req->ai_family == AF_UNSPEC		      || (req->ai_family == AF_INET6			  && (req->ai_flags & AI_V4MAPPED)			  /* Avoid generating the mapped addresses if we			     know we are not going to need them.  */			  && ((req->ai_flags & AI_ALL) || !got_ipv6)))		    {		      gethosts (AF_INET, struct in_addr);		      if (req->ai_family == AF_INET)			{			  no_inet6_data = no_data;			  inet6_status = status;			}		    }		  /* If we found one address for AF_INET or AF_INET6,		     don't continue the search.  */		  if (inet6_status == NSS_STATUS_SUCCESS		      || status == NSS_STATUS_SUCCESS)		    {		      /* If we need the canonical name, get it from the same			 service as the result.  */		      nss_getcanonname_r cfct;		      int herrno;		      cfct = __nss_lookup_function (nip, "getcanonname_r");		      if (cfct != NULL)			{			  const size_t max_fqdn_len = 256;			  char *buf = alloca (max_fqdn_len);			  char *s;			  if (DL_CALL_FCT (cfct, (name, buf, max_fqdn_len,						  &s, &rc, &herrno))			      == NSS_STATUS_SUCCESS)			    canon = s;			  else			    /* Set to name now to avoid using			       gethostbyaddr.  */			    canon = name;			}		      break;		    }		  /* We can have different states for AF_INET and		     AF_INET6.  Try to find a useful one for both.  */		  if (inet6_status == NSS_STATUS_TRYAGAIN)		    status = NSS_STATUS_TRYAGAIN;		  else if (status == NSS_STATUS_UNAVAIL &&			   inet6_status != NSS_STATUS_UNAVAIL)		    status = inet6_status;		}	      if (nss_next_action (nip, status) == NSS_ACTION_RETURN)		break;	      if (nip->next == NULL)		no_more = -1;	      else		nip = nip->next;	    }	  _res.options = old_res_options;	  if (no_data != 0 && no_inet6_data != 0)	    {	      /* If both requests timed out report this.  */	      if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN)		return -EAI_AGAIN;	      /* We made requests but they turned out no data.  The name		 is known, though.  */	      return (GAIH_OKIFUNSPEC | -EAI_NODATA);	    }	}      if (at->family == AF_UNSPEC)	return (GAIH_OKIFUNSPEC | -EAI_NONAME);    }  else    {      struct gaih_addrtuple *atr;      atr = at = __alloca (sizeof (struct gaih_addrtuple));      memset (at, '\0', sizeof (struct gaih_addrtuple));      if (req->ai_family == AF_UNSPEC)	{	  at->next = __alloca (sizeof (struct gaih_addrtuple));	  memset (at->next, '\0', sizeof (struct gaih_addrtuple));	}      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6)	{	  at->family = AF_INET6;	  if ((req->ai_flags & AI_PASSIVE) == 0)	    memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr));	  atr = at->next;	}      if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)	{	  atr->family = AF_INET;	  if ((req->ai_flags & AI_PASSIVE) == 0)	    atr->addr[0] = htonl (INADDR_LOOPBACK);	}    }  if (pai == NULL)    return 0;  {    struct gaih_servtuple *st2;    struct gaih_addrtuple *at2 = at;    size_t socklen;    size_t canonlen;    sa_family_t family;    /*      buffer is the size of an unformatted IPv6 address in printable format.     */    while (at2 != NULL)      {	/* Only the first entry gets the canonical name.  */	if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0)	  {	    if (canon == NULL)	      {		struct hostent *h = NULL;		int herrno;		struct hostent th;		size_t tmpbuflen = 512;		char *tmpbuf = NULL;		do		  {		    tmpbuf = extend_alloca (tmpbuf, tmpbuflen, tmpbuflen * 2);		    rc = __gethostbyaddr_r (at2->addr,					    ((at2->family == AF_INET6)					     ? sizeof (struct in6_addr)					     : sizeof (struct in_addr)),					    at2->family, &th, tmpbuf,					    tmpbuflen, &h, &herrno);		  }		while (rc == ERANGE && herrno == NETDB_INTERNAL);		if (rc != 0 && herrno == NETDB_INTERNAL)		  {		    __set_h_errno (herrno);		    return -EAI_SYSTEM;		  }		if (h != NULL)		  canon = h->h_name;		else		  {		    assert (name != NULL);		    /* If the canonical name cannot be determined, use		       the passed in string.  */		    canon = name;		  }	      }#ifdef HAVE_LIBIDN	    if (req->ai_flags & AI_CANONIDN)	      {		int idn_flags = 0;		if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED)		  idn_flags |= IDNA_ALLOW_UNASSIGNED;		if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES)		  idn_flags |= IDNA_USE_STD3_ASCII_RULES;		char *out;		int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags);		if (rc != IDNA_SUCCESS)		  {		    if (rc == IDNA_MALLOC_ERROR)		      return -EAI_MEMORY;		    if (rc == IDNA_DLOPEN_ERROR)		      return -EAI_SYSTEM;		    return -EAI_IDN_ENCODE;		  }		/* In case the output string is the same as the input		   string no new string has been allocated.  */		if (out != canon)		  {		    canon = strdupa (out);		    free (out);		  }	      }#endif	    canonlen = strlen (canon) + 1;	  }	else	  canonlen = 0;	if (at2->family == AF_INET6)	  {	    family = AF_INET6;	    socklen = sizeof (struct sockaddr_in6);	    /* If we looked up IPv4 mapped address discard them here if	       the caller isn't interested in all address and we have	       found at least one IPv6 address.  */	    if (got_ipv6		&& (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED		&& IN6_IS_ADDR_V4MAPPED (at2->addr))	      goto ignore;	  }	else	  {	    family = AF_INET;	    socklen = sizeof (struct sockaddr_in);	  }	for (st2 = st; st2 != NULL; st2 = st2->next)	  {	    *pai = malloc (sizeof (struct addrinfo) + socklen + canonlen);	    if (*pai == NULL)	      return -EAI_MEMORY;	    (*pai)->ai_flags = req->ai_flags;	    (*pai)->ai_family = family;	    (*pai)->ai_socktype = st2->socktype;	    (*pai)->ai_protocol = st2->protocol;	    (*pai)->ai_addrlen = socklen;	    (*pai)->ai_addr = (void *) (*pai + 1);#if SALEN	    (*pai)->ai_addr->sa_len = socklen;#endif /* SALEN */	    (*pai)->ai_addr->sa_family = family;	    if (family == AF_INET6)	      {		struct sockaddr_in6 *sin6p =		  (struct sockaddr_in6 *) (*pai)->ai_addr;		sin6p->sin6_port = st2->port;		sin6p->sin6_flowinfo = 0;		memcpy (&sin6p->sin6_addr,			at2->addr, sizeof (struct in6_addr));		sin6p->sin6_scope_id = at2->scopeid;	      }	    else	      {		struct sockaddr_in *sinp =		  (struct sockaddr_in *) (*pai)->ai_addr;		sinp->sin_port = st2->port;		memcpy (&sinp->sin_addr,			at2->addr, sizeof (struct in_addr));		memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));	      }	    if (canonlen != 0)	      {		(*pai)->ai_canonname = ((void *) (*pai) +					sizeof (struct addrinfo) + socklen);		strcpy ((*pai)->ai_canonname, canon);		/* We do not need to allocate the canonical name anymore.  */		canonlen = 0;	      }	    else	      (*pai)->ai_canonname = NULL;	    (*pai)->ai_next = NULL;	    pai = &((*pai)->ai_next);	  }      ignore:	at2 = at2->next;      }  }  return 0;}