in libs/libc/netdb/lib_getaddrinfo.c [133:442]
int getaddrinfo(FAR const char *hostname, FAR const char *servname,
FAR const struct addrinfo *hint, FAR struct addrinfo **res)
{
int family = AF_UNSPEC;
int port = 0;
int flags = 0;
int proto = 0;
int socktype = 0;
FAR char *hostbuffer;
FAR struct hostent_s host;
FAR struct ai_s *ai;
FAR struct ai_s *prev_ai = NULL;
const int valid_flags = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
AI_NUMERICSERV | AI_V4MAPPED | AI_ALL |
AI_ADDRCONFIG;
int ret = OK;
int i;
if (hostname == NULL && servname == NULL)
{
return EAI_NONAME;
}
if (hint)
{
family = hint->ai_family;
flags = hint->ai_flags;
proto = hint->ai_protocol;
socktype = hint->ai_socktype;
if ((flags & valid_flags) != flags)
{
return EAI_BADFLAGS;
}
if (family != AF_INET &&
family != AF_INET6 &&
family != AF_LOCAL &&
family != AF_RPMSG &&
family != AF_VSOCK &&
family != AF_UNSPEC)
{
return EAI_FAMILY;
}
}
if (servname != NULL)
{
struct servent ent;
FAR struct servent *sp;
FAR char *endp;
port = strtol(servname, &endp, 10);
if (port >= 0 && port <= 65535 && *endp == '\0')
{
/* Force network byte order */
port = HTONS(port);
}
else if ((flags & AI_NUMERICSERV) != 0)
{
return EAI_NONAME;
}
else if (getservbyname_r(servname, NULL, &ent, NULL, 0, &sp) == OK)
{
/* The s_port field of struct servent is required to
* be in network byte order (per OpenGroup.org)
*/
port = sp->s_port;
}
else
{
return EAI_SERVICE;
}
}
*res = NULL;
/* If hostname is not NULL, then the AI_PASSIVE flag is ignored. */
if ((flags & AI_PASSIVE) != 0 && hostname == NULL)
{
#ifdef CONFIG_NET_IPv4
if (family == AF_INET || family == AF_UNSPEC)
{
struct in_addr addr;
memset(&addr, 0, sizeof(struct in_addr));
ai = alloc_ai(AF_INET, socktype, proto, port, &addr);
if (ai != NULL)
{
*res = (FAR struct addrinfo *)ai;
}
}
#endif
#ifdef CONFIG_NET_IPv6
if (family == AF_INET6 || family == AF_UNSPEC)
{
struct in6_addr addr;
memset(&addr, 0, sizeof(struct in6_addr));
ai = alloc_ai(AF_INET6, socktype, proto, port, &addr);
if (ai != NULL)
{
/* Can return both IPv4 and IPv6 loopback. */
if (*res != NULL)
{
(*res)->ai_next = (FAR struct addrinfo *)ai;
}
else
{
*res = (FAR struct addrinfo *)ai;
}
}
}
#endif
#if defined(CONFIG_NET_RPMSG)
if (family == AF_RPMSG || family == AF_UNSPEC)
{
ai = alloc_ai(AF_RPMSG, socktype, proto, port, "");
if (ai != NULL)
{
if (*res != NULL)
{
(*res)->ai_next = (FAR struct addrinfo *)ai;
}
else
{
*res = (FAR struct addrinfo *)ai;
}
}
}
#endif
#if defined(CONFIG_NET_VSOCK)
if (family == AF_VSOCK || family == AF_UNSPEC)
{
/* "-1" <--> VMADDR_CID_ANY */
ai = alloc_ai(AF_VSOCK, socktype, proto, port, "-1");
if (ai != NULL)
{
if (*res != NULL)
{
(*res)->ai_next = (FAR struct addrinfo *)ai;
}
else
{
*res = (FAR struct addrinfo *)ai;
}
}
}
#endif
return (*res != NULL) ? OK : EAI_MEMORY;
}
if (hostname == NULL)
{
#ifdef CONFIG_NET_LOOPBACK
/* Local service. */
#ifdef CONFIG_NET_IPv4
if (family == AF_INET || family == AF_UNSPEC)
{
ai = alloc_ai(AF_INET, socktype, proto, port,
&g_lo_ipv4addr);
if (ai != NULL)
{
*res = (FAR struct addrinfo *)ai;
}
}
#endif
#ifdef CONFIG_NET_IPv6
if (family == AF_INET6 || family == AF_UNSPEC)
{
ai = alloc_ai(AF_INET6, socktype, proto, port,
&g_lo_ipv6addr);
if (ai != NULL)
{
/* Can return both IPv4 and IPv6 loopback. */
if (*res != NULL)
{
(*res)->ai_next = (FAR struct addrinfo *)ai;
}
else
{
*res = (FAR struct addrinfo *)ai;
}
}
}
#endif
#endif
#if defined(CONFIG_NET_VSOCK)
if (family == AF_VSOCK || family == AF_UNSPEC)
{
/* "1" <--> VMADDR_CID_LOCAL */
ai = alloc_ai(AF_VSOCK, socktype, proto, port, "1");
if (ai != NULL)
{
if (*res != NULL)
{
(*res)->ai_next = (FAR struct addrinfo *)ai;
}
else
{
*res = (FAR struct addrinfo *)ai;
}
}
}
#endif
#if defined(CONFIG_NET_LOOPBACK) || defined(CONFIG_NET_VSOCK)
return (*res != NULL) ? OK : EAI_MEMORY;
#else
/* Local service, but no loopback so cannot succeed. */
return EAI_FAIL;
#endif
}
#if defined(CONFIG_NET_LOCAL) || defined(CONFIG_NET_RPMSG) || defined(CONFIG_NET_VSOCK)
if (family == AF_LOCAL || family == AF_RPMSG || family == AF_VSOCK)
{
ai = alloc_ai(family, socktype, proto, port, hostname);
if (ai != NULL)
{
*res = (FAR struct addrinfo *)ai;
if (flags & AI_CANONNAME)
{
ai->ai.ai_canonname = (FAR char *)hostname;
}
}
return (*res != NULL) ? OK : EAI_MEMORY;
}
#endif
hostbuffer = lib_malloc(CONFIG_NETDB_BUFSIZE);
if (hostbuffer == NULL)
{
return EAI_MEMORY;
}
gethostentbyname_r(hostname, &host,
hostbuffer, CONFIG_NETDB_BUFSIZE, &ret, flags);
if (ret != OK)
{
lib_free(hostbuffer);
return ret;
}
for (i = 0; host.h_addr_list[i]; i++)
{
if (family != AF_UNSPEC && host.h_addrtypes[i] != family)
{
/* Filter by protocol family. */
continue;
}
/* REVISIT: filter by socktype and protocol not implemented. */
ai = alloc_ai(host.h_addrtypes[i], socktype, proto, port,
host.h_addr_list[i]);
if (ai == NULL)
{
if (*res)
{
freeaddrinfo(*res);
}
lib_free(hostbuffer);
return EAI_MEMORY;
}
/* REVISIT: grok canonical name.
*
* OpenGroup: "if the canonical name is not available, then
* ai_canonname shall refer to the hostname argument or a string
* with the same contents."
*/
ai->ai.ai_canonname = (FAR char *)hostname;
/* Add result to linked list.
* TODO: RFC 3484/6724 destination address sort not implemented.
*/
if (prev_ai != NULL)
{
prev_ai->ai.ai_next = (FAR struct addrinfo *)ai;
}
else
{
*res = (FAR struct addrinfo *)ai;
}
prev_ai = ai;
}
lib_free(hostbuffer);
return (*res != NULL) ? OK : EAI_FAMILY;
}