in demo_example/asio/asio/detail/impl/socket_ops.ipp [3335:3534]
inline int getaddrinfo_emulation(const char* host, const char* service,
const addrinfo_type* hintsp, addrinfo_type** result)
{
// Set up linked list of addrinfo structures.
addrinfo_type* aihead = 0;
addrinfo_type** ainext = &aihead;
char* canon = 0;
// Supply default hints if not specified by caller.
addrinfo_type hints = addrinfo_type();
hints.ai_family = ASIO_OS_DEF(AF_UNSPEC);
if (hintsp)
hints = *hintsp;
// If the resolution is not specifically for AF_INET6, remove the AI_V4MAPPED
// and AI_ALL flags.
#if defined(AI_V4MAPPED)
if (hints.ai_family != ASIO_OS_DEF(AF_INET6))
hints.ai_flags &= ~AI_V4MAPPED;
#endif
#if defined(AI_ALL)
if (hints.ai_family != ASIO_OS_DEF(AF_INET6))
hints.ai_flags &= ~AI_ALL;
#endif
// Basic error checking.
int rc = gai_echeck(host, service, hints.ai_flags, hints.ai_family,
hints.ai_socktype, hints.ai_protocol);
if (rc != 0)
{
freeaddrinfo_emulation(aihead);
return rc;
}
gai_search search[2];
int search_count = gai_nsearch(host, &hints, search);
for (gai_search* sptr = search; sptr < search + search_count; ++sptr)
{
// Check for IPv4 dotted decimal string.
in4_addr_type inaddr;
asio::error_code ec;
if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET),
sptr->host, &inaddr, 0, ec) == 1)
{
if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
&& hints.ai_family != ASIO_OS_DEF(AF_INET))
{
freeaddrinfo_emulation(aihead);
gai_free(canon);
return EAI_FAMILY;
}
if (sptr->family == ASIO_OS_DEF(AF_INET))
{
rc = gai_aistruct(&ainext, &hints, &inaddr, ASIO_OS_DEF(AF_INET));
if (rc != 0)
{
freeaddrinfo_emulation(aihead);
gai_free(canon);
return rc;
}
}
continue;
}
// Check for IPv6 hex string.
in6_addr_type in6addr;
if (socket_ops::inet_pton(ASIO_OS_DEF(AF_INET6),
sptr->host, &in6addr, 0, ec) == 1)
{
if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
&& hints.ai_family != ASIO_OS_DEF(AF_INET6))
{
freeaddrinfo_emulation(aihead);
gai_free(canon);
return EAI_FAMILY;
}
if (sptr->family == ASIO_OS_DEF(AF_INET6))
{
rc = gai_aistruct(&ainext, &hints, &in6addr,
ASIO_OS_DEF(AF_INET6));
if (rc != 0)
{
freeaddrinfo_emulation(aihead);
gai_free(canon);
return rc;
}
}
continue;
}
// Look up hostname.
hostent hent;
char hbuf[8192] = "";
hostent* hptr = socket_ops::gethostbyname(sptr->host,
sptr->family, &hent, hbuf, sizeof(hbuf), hints.ai_flags, ec);
if (hptr == 0)
{
if (search_count == 2)
{
// Failure is OK if there are multiple searches.
continue;
}
freeaddrinfo_emulation(aihead);
gai_free(canon);
if (ec == asio::error::host_not_found)
return EAI_NONAME;
if (ec == asio::error::host_not_found_try_again)
return EAI_AGAIN;
if (ec == asio::error::no_recovery)
return EAI_FAIL;
if (ec == asio::error::no_data)
return EAI_NONAME;
return EAI_NONAME;
}
// Check for address family mismatch if one was specified.
if (hints.ai_family != ASIO_OS_DEF(AF_UNSPEC)
&& hints.ai_family != hptr->h_addrtype)
{
freeaddrinfo_emulation(aihead);
gai_free(canon);
socket_ops::freehostent(hptr);
return EAI_FAMILY;
}
// Save canonical name first time.
if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0]
&& (hints.ai_flags & AI_CANONNAME) && canon == 0)
{
std::size_t canon_len = strlen(hptr->h_name) + 1;
canon = gai_alloc<char>(canon_len);
if (canon == 0)
{
freeaddrinfo_emulation(aihead);
socket_ops::freehostent(hptr);
return EAI_MEMORY;
}
gai_strcpy(canon, hptr->h_name, canon_len);
}
// Create an addrinfo structure for each returned address.
for (char** ap = hptr->h_addr_list; *ap; ++ap)
{
rc = gai_aistruct(&ainext, &hints, *ap, hptr->h_addrtype);
if (rc != 0)
{
freeaddrinfo_emulation(aihead);
gai_free(canon);
socket_ops::freehostent(hptr);
return EAI_FAMILY;
}
}
socket_ops::freehostent(hptr);
}
// Check if we found anything.
if (aihead == 0)
{
gai_free(canon);
return EAI_NONAME;
}
// Return canonical name in first entry.
if (host != 0 && host[0] != '\0' && (hints.ai_flags & AI_CANONNAME))
{
if (canon)
{
aihead->ai_canonname = canon;
canon = 0;
}
else
{
std::size_t canonname_len = strlen(search[0].host) + 1;
aihead->ai_canonname = gai_alloc<char>(canonname_len);
if (aihead->ai_canonname == 0)
{
freeaddrinfo_emulation(aihead);
return EAI_MEMORY;
}
gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len);
}
}
gai_free(canon);
// Process the service name.
if (service != 0 && service[0] != '\0')
{
rc = gai_serv(aihead, &hints, service);
if (rc != 0)
{
freeaddrinfo_emulation(aihead);
return rc;
}
}
// Return result to caller.
*result = aihead;
return 0;
}