Função GetAddrInfoExW (ws2tcpip.h)
A função GetAddrInfoEx fornece resolução de nome independente de protocolo com parâmetros adicionais para qualificar quais provedores de namespace devem lidar com a solicitação.
Sintaxe
INT WSAAPI GetAddrInfoExW(
[in, optional] PCWSTR pName,
[in, optional] PCWSTR pServiceName,
[in] DWORD dwNameSpace,
[in, optional] LPGUID lpNspId,
[in, optional] const ADDRINFOEXW *hints,
[out] PADDRINFOEXW *ppResult,
[in, optional] timeval *timeout,
[in, optional] LPOVERLAPPED lpOverlapped,
[in, optional] LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
[out, optional] LPHANDLE lpHandle
);
Parâmetros
[in, optional] pName
Um ponteiro para uma cadeia de caracteres terminada em NULL que contém um nome de host (nó) ou uma cadeia de caracteres de endereço de host numérico. Para o protocolo da Internet, a cadeia de caracteres de endereço de host numérico é um endereço IPv4 decimal pontilhado ou um endereço hex IPv6.
[in, optional] pServiceName
Um ponteiro para uma cadeia de caracteres terminada em NULL opcional que contém um nome de serviço ou um número de porta representado como uma cadeia de caracteres.
Um nome de serviço é um alias de cadeia de caracteres para um número de porta. Por exemplo, "http" é um alias para a porta 80 definido pelo IETF (Internet Engineering Task Force) como a porta padrão usada pelos servidores Web para o protocolo HTTP. Os valores possíveis para o parâmetro pServiceName quando um número de porta não é especificado são listados no seguinte arquivo:
%WINDIR%\system32\drivers\etc\services
[in] dwNameSpace
Um identificador de namespace opcional que determina quais provedores de namespace são consultados. Passar um identificador de namespace específico resultará apenas em provedores de namespace que dão suporte ao namespace especificado que está sendo consultado. Especificar NS_ALL resultará na consulta de todos os provedores de namespace instalados e ativos.
As opções para o parâmetro dwNameSpace estão listadas no arquivo de inclusão Winsock2.h . Vários provedores de namespace são adicionados ao Windows Vista e posteriores. Outros provedores de namespace podem ser instalados, portanto, os valores possíveis a seguir são apenas aqueles comumente disponíveis. Muitos outros valores são possíveis.
[in, optional] lpNspId
Um ponteiro para um GUID opcional de um provedor de namespace específico para consultar no caso em que vários provedores de namespace são registrados em um único namespace, como NS_DNS. Passar o GUID para um provedor de namespace específico resultará apenas no provedor de namespace especificado sendo consultado. A função WSAEnumNameSpaceProviders pode ser chamada para recuperar o GUID de um provedor de namespace.
[in, optional] hints
Um ponteiro para uma estrutura addrinfoex que fornece dicas sobre o tipo de soquete que o chamador dá suporte.
Os membros ai_addrlen, ai_canonname, ai_addr e ai_next da estrutura addrinfoex apontada pelo parâmetro pHints devem ser zero ou NULL. Caso contrário, a função GetAddrInfoEx falhará com WSANO_RECOVERY.
Confira os Comentários para obter mais detalhes.
[out] ppResult
Um ponteiro para uma lista vinculada de uma ou mais estruturas addrinfoex que contém informações de resposta sobre o host.
[in, optional] timeout
Um parâmetro opcional que indica o tempo, em milissegundos, para aguardar uma resposta do provedor de namespace antes de anular a chamada.
Esse parâmetro só tem suporte quando a macro UNICODE ou _UNICODE foi definida nas fontes antes de chamar a função GetAddrInfoEx . Caso contrário, esse parâmetro está reservado no momento e deve ser definido como NULL , pois não há suporte para uma opção de tempo limite .
[in, optional] lpOverlapped
Um ponteiro opcional para uma estrutura sobreposta usada para operação assíncrona.
Esse parâmetro só tem suporte quando a macro UNICODE ou _UNICODE foi definida nas fontes antes de chamar a função GetAddrInfoEx .
No Windows 8 e no Windows Server 2012, se nenhum parâmetro lpCompletionRoutine for especificado, o membro hEvent da estrutura OVERLAPPED deverá ser definido como um evento de redefinição manual a ser chamado após a conclusão de uma chamada assíncrona. Se uma rotina de conclusão tiver sido especificada, o membro hEvent deverá ser NULL. Quando o evento especificado por hEvent tiver sido definido, o resultado da operação poderá ser recuperado chamando a função GetAddrInfoExOverlappedResult .
No Windows 8 e no Windows Server 2012 sempre que a macro UNICODE ou _UNICODE não estiver definida, esse parâmetro está reservado no momento e deve ser definido como NULL.
No Windows 7 e no Windows Server 2008 R2 ou anterior, esse parâmetro está reservado no momento e deve ser definido como NULL , pois não há suporte para operações assíncronas.
[in, optional] lpCompletionRoutine
Um ponteiro opcional para uma função a ser invocada após a conclusão bem-sucedida para operações assíncronas.
Esse parâmetro só tem suporte quando a macro UNICODE ou _UNICODE foi definida nas fontes antes de chamar a função GetAddrInfoEx .
Se esse parâmetro for especificado, ele deverá ser um ponteiro para uma função com a seguinte assinatura:
typedef
void
(CALLBACK * LPLOOKUPSERVICE_COMPLETION_ROUTINE)(
__in DWORD dwError,
__in DWORD dwBytes,
__in LPWSAOVERLAPPED lpOverlapped
);
Quando a operação assíncrona for concluída, a rotina de conclusão será invocada com o parâmetro lpOverlapped definido como o valor do parâmetro lpOverlapped passado para GetAddrInfoEx. O membro Pointer da estrutura OVERLAPPED será definido como o valor do parâmetro ppResult da chamada original. Se o membro Pointer apontar para um ponteiro não NULL para a estrutura addrinfoex , é responsabilidade do chamador chamar FreeAddrInfoEx para liberar a estrutura addrinfoex . O parâmetro dwError passado para a rotina de conclusão será definido como um código de erro Winsock. O parâmetro dwBytes é reservado para uso futuro e deve ser ignorado.
No Windows 8 e no Windows Server 2012 sempre que a macro UNICODE ou _UNICODE não estiver definida, esse parâmetro está reservado no momento e deve ser definido como NULL.
No Windows 7 e no Windows Server 2008 R2 ou anterior, esse parâmetro está reservado no momento e deve ser definido como NULL , pois não há suporte para operações assíncronas.
[out, optional] lpHandle
Um ponteiro opcional usado apenas para operações assíncronas.
Esse parâmetro só tem suporte quando a macro UNICODE ou _UNICODE foi definida nas fontes antes de chamar a função GetAddrInfoEx .
No Windows 8 e no Windows Server 2012, se a função GetAddrInfoEx for concluída de forma assíncrona, o ponteiro retornado neste campo poderá ser usado com a função GetAddrInfoExCancel . O identificador retornado é válido quando GetAddrInfoEx retorna até que a rotina de conclusão seja chamada, o evento seja disparado ou a função GetAddrInfoExCancel seja chamada com esse identificador.
No Windows 8 e no Windows Server 2012 sempre que a macro UNICODE ou _UNICODE não estiver definida, esse parâmetro está reservado no momento e deve ser definido como NULL.
No Windows 7 e no Windows Server 2008 R2 ou anterior, esse parâmetro está reservado no momento e deve ser definido como NULL , pois não há suporte para operações assíncronas.
Retornar valor
Com êxito, GetAddrInfoEx retorna NO_ERROR (0). Falha retorna um código de erro diferente de zero do Windows Sockets, conforme encontrado nos Códigos de Erro do Windows Sockets.
A maioria dos códigos de erro não zero retornados pelo mapa de funções GetAddrInfoEx para o conjunto de erros descrito pelas recomendações da IETF (Internet Engineering Task Force). A tabela a seguir mostra esses códigos de erro e seus equivalentes do WSA. É recomendável que os códigos de erro do WSA sejam usados, pois oferecem informações de erro familiares e abrangentes para programadores Winsock.
Valor do erro | Equivalente a WSA | Descrição |
---|---|---|
EAI_AGAIN | WSATRY_AGAIN | Ocorreu uma falha temporária na resolução de nomes. |
EAI_BADFLAGS | WSAEINVAL | Um parâmetro inválido foi fornecido. Esse erro será retornado se qualquer um dos parâmetros reservados não for NULL. Esse erro também será retornado se um valor inválido tiver sido fornecido para o membro ai_flags do parâmetro pHints . |
EAI_FAIL | WSANO_RECOVERY | Ocorreu uma falha não recuperável na resolução de nomes. |
EAI_FAMILY | WSAEAFNOSUPPORT | Não há suporte para o membro ai_family do parâmetro pHints . |
EAI_MEMORY | WSA_NOT_ENOUGH_MEMORY | Ocorreu uma falha de alocação de memória. |
EAI_NONAME | WSAHOST_NOT_FOUND | O nome não é resolvido para os parâmetros fornecidos ou os parâmetros pName e pServiceName não foram fornecidos. |
EAI_SERVICE | WSATYPE_NOT_FOUND | Não há suporte para o parâmetro pServiceName para o membro ai_socktype especificado do parâmetro pHints . |
EAI_SOCKTYPE | WSAESOCKTNOSUPPORT | Não há suporte para o membro ai_socktype do parâmetro pHints . |
Use a função gai_strerror para imprimir mensagens de erro com base nos códigos EAI retornados pela função GetAddrInfoEx . A função gai_strerror é fornecida para conformidade com as recomendações de IETF, mas não é thread-safe. Portanto, o uso de funções tradicionais do Windows Sockets, como WSAGetLastError , é recomendado.
Código do erro | Significado |
---|---|
Não havia memória suficiente para executar a operação. | |
Um endereço incompatível com o protocolo solicitado foi usado. Esse erro será retornado se não houver suporte para o membro ai_family da estrutura addrinfoex apontada pelo parâmetro pHints . | |
Foi fornecido um argumento inválido. Esse erro será retornado se um valor inválido tiver sido fornecido para o membro ai_flags da estrutura addrinfoex apontada pelo parâmetro pHints . Esse erro também é retornado quando o parâmetro dwNameSpace é NS_PNRPNAME ou NS_PNRPCLOUD e o serviço de nome ponto a ponto não está operando. | |
O suporte para o tipo de soquete especificado não existe nessa família de endereços. Esse erro será retornado se não houver suporte para o membro ai_socktype da estrutura addrinfoex apontada pelo parâmetro pHints . | |
Esse host não é conhecido. Esse erro será retornado se o nome não for resolvido para os parâmetros fornecidos ou se os parâmetros pName e pServiceName não forem fornecidos. | |
O nome solicitado é válido, mas nenhum dado do tipo solicitado foi encontrado. | |
Ocorreu um erro irrecuperável durante uma pesquisa no banco de dados. Esse erro será retornado se ocorrer um erro não recuperável na resolução de nomes. | |
Uma chamada WSAStartup bem-sucedida deve ocorrer antes de usar essa função. | |
Nenhum serviço desse tipo é conhecido. O serviço não pode ser encontrado no namespace especificado. Esse erro será retornado se o parâmetro pName ou pServiceName não for encontrado para o namespace especificado no parâmetro dwNameSpace ou se o namespace especificado no parâmetro dwNameSpace não estiver instalado. | |
Esse é geralmente um erro temporário durante a resolução do nome do host e significa que o servidor local não recebeu uma resposta de um servidor autorizado. Esse erro é retornado quando ocorreu uma falha temporária na resolução de nomes. | |
A classe especificada não foi encontrada. Não há suporte para o parâmetro pServiceName para o membro ai_socktype especificado da estrutura addrinfoex apontada pelo parâmetro pHints . |
Comentários
A função GetAddrInfoEx fornece tradução independente de protocolo do nome do host para o endereço e do nome do serviço para o número da porta. A função GetAddrInfoEx é uma versão aprimorada das funções getaddrinfo e GetAddrInfoW . A função GetAddrInfoEx permite especificar o provedor de namespace para resolver a consulta.
A função GetAddrInfoEx agrega e retorna resultados de vários provedores de namespace, a menos que um provedor de namespace específico seja especificado. Para uso com o protocolo IPv6 e IPv4, a resolução de nomes pode ser pelo DNS (Sistema de Nomes de Domínio), um arquivo de hosts local, um provedor de email (o namespace NS_EMAIL ) ou por outros mecanismos de nomenclatura.
Quando UNICODE ou _UNICODE é definido, GetAddrInfoEx é definido como GetAddrInfoExW, a versão Unicode dessa função. Os parâmetros de cadeia de caracteres são definidos para o tipo de dados PWSTR e a estrutura ADDRINFOEXW é usada. No Windows 8 e no Windows Server 2012, os parâmetros timeout, lpOverlapped, lpCompletionRoutine e lpHandle podem ser usados para chamar a função GetAddrInfoEx para que ela possa ser concluída de forma assíncrona.
Quando UNICODE ou _UNICODE não estiver definido, GetAddrInfoEx será definido como GetAddrInfoExA, a versão ANSI dessa função. Os parâmetros de cadeia de caracteres são do tipo de dados PCSTR e a estrutura ADDRINFOEXA é usada. Os parâmetros timeout, lpOverlapped, lpCompletionRoutine e lpHandle devem ser definidos como NULL.
Um ou ambos os parâmetros pName ou pServiceName devem apontar para uma cadeia de caracteres terminada em NULL. Geralmente, ambos são fornecidos.
Após o êxito, uma lista vinculada de estruturas addrinfoex é retornada no parâmetro ppResult . A lista pode ser processada seguindo o ponteiro fornecido no membro ai_next de cada estrutura addrinfoex retornada até que um ponteiro NULL seja encontrado. Em cada estrutura addrinfoex retornada, os membros ai_family, ai_socktype e ai_protocol correspondem aos respectivos argumentos em uma chamada de função de soquete ou WSASocket . Além disso, o membro ai_addr em cada estrutura addrinfoex retornada aponta para uma estrutura de endereço de soquete preenchida, cujo comprimento é especificado em seu membro ai_addrlen .
Se o parâmetro pName apontar para um nome de computador, todos os endereços permanentes do computador que podem ser usados como um endereço de origem serão retornados. No Windows Vista e posterior, esses endereços incluem todos os endereços IP unicast retornados pelas funções GetUnicastIpAddressTable ou GetUnicastIpAddressEntry nas quais o membro SkipAsSource é definido como false na estrutura MIB_UNICASTIPADDRESS_ROW .
Se o parâmetro pName apontar para uma cadeia de caracteres igual a "localhost", todos os endereços de loopback no computador local serão retornados.
Se o parâmetro pName contiver uma cadeia de caracteres vazia, todos os endereços registrados no computador local serão retornados.
No Windows Server 2003 e posterior se o parâmetro pName apontar para uma cadeia de caracteres igual a ".. localmachine", todos os endereços registrados no computador local são retornados.
Se o parâmetro pName se referir a um nome de servidor virtual de cluster, somente endereços de servidor virtual serão retornados. No Windows Vista e posterior, esses endereços incluem todos os endereços IP unicast retornados pelas funções GetUnicastIpAddressTable ou GetUnicastIpAddressEntry nas quais o membro SkipAsSource é definido como true na estrutura MIB_UNICASTIPADDRESS_ROW . Consulte Clustering do Windows para obter mais informações sobre clustering.
O Windows 7 com Service Pack 1 (SP1) e o Windows Server 2008 R2 com Service Pack 1 (SP1) adicionam suporte a Netsh.exe para definir o atributo SkipAsSource em um endereço IP. Isso também altera o comportamento de modo que, se o membro SkipAsSource na estrutura MIB_UNICASTIPADDRESS_ROW estiver definido como false, o endereço IP será registrado no DNS. Se o membro SkipAsSource estiver definido como true, o endereço IP não será registrado no DNS.
Um hotfix está disponível para Windows 7 e Windows Server 2008 R2 que adiciona suporte a Netsh.exe para definir o atributo SkipAsSource em um endereço IP. Esse hotfix também altera o comportamento de modo que, se o membro SkipAsSource na estrutura MIB_UNICASTIPADDRESS_ROW estiver definido como false, o endereço IP será registrado no DNS. Se o membro SkipAsSource estiver definido como true, o endereço IP não será registrado no DNS. Para obter mais informações, consulte Base de Dados de Conhecimento (KB) 2386184.
Um hotfix semelhante também está disponível para Windows Vista com Service Pack 2 (SP2) e Windows Server 2008 com Service Pack 2 (SP2) que adiciona suporte a Netsh.exe para definir o atributo SkipAsSource em um endereço IP. Esse hotfix também altera o comportamento de modo que, se o membro SkipAsSource na estrutura MIB_UNICASTIPADDRESS_ROW estiver definido como false, o endereço IP será registrado no DNS. Se o membro SkipAsSource estiver definido como true, o endereço IP não será registrado no DNS.
Os chamadores da função GetAddrInfoEx podem fornecer dicas sobre o tipo de soquete com suporte por meio de uma estrutura addrinfoex apontada pelo parâmetro pHints . Quando o parâmetro pHints é usado, as seguintes regras se aplicam à estrutura addrinfoex associada:
- Um valor de AF_UNSPEC para ai_family indica que o chamador aceitará apenas as famílias de endereços AF_INET e AF_INET6 . Observe que AF_UNSPEC e PF_UNSPEC são iguais.
- Um valor zero para ai_socktype indica que o chamador aceitará qualquer tipo de soquete.
- Um valor zero para ai_protocol indica que o chamador aceitará qualquer protocolo.
- O membro ai_addrlen deve ser definido como zero.
- O membro ai_canonname deve ser definido como NULL.
- O membro ai_addr deve ser definido como NULL.
- O membro ai_next deve ser definido como NULL.
Outros valores na estrutura addrinfoex fornecida no parâmetro pHints indicam requisitos específicos. Por exemplo, se o chamador manipular apenas IPv4 e não manipular IPv6, o membro ai_family deverá ser definido como AF_INET. Para outro exemplo, se o chamador manipular apenas TCP e não manipular UDP, o membro ai_socktype deverá ser definido como SOCK_STREAM.
Se o parâmetro pHints for um ponteiro NULL , a função GetAddrInfoEx o tratará como se a estrutura addrinfoex em pHints fosse inicializada com seu membro ai_family definido como AF_UNSPEC e todos os outros membros definidos como NULL ou zero.
Quando GetAddrInfoEx é chamado de um serviço, se a operação for o resultado de um processo de usuário chamando o serviço, o serviço deverá representar o usuário. Isso é para permitir que a segurança seja aplicada corretamente.
A função GetAddrInfoEx pode ser usada para converter uma representação de cadeia de caracteres de texto de um endereço IP em uma estrutura addrinfoex que contém uma estrutura sockaddr para o endereço IP e outras informações. Para ser usada dessa forma, a cadeia de caracteres apontada pelo parâmetro pName deve conter uma representação de texto de um endereço IP e a estrutura addrinfoex apontada pelo parâmetro pHints deve ter o sinalizador AI_NUMERICHOST definido no membro ai_flags . A cadeia de caracteres apontada pelo parâmetro pName pode conter uma representação de texto de um endereço IPv4 ou IPv6. O endereço IP de texto é convertido em uma estrutura addrinfoex apontada pelo parâmetro ppResult . A estrutura addrinfoex retornada contém uma estrutura sockaddr para o endereço IP, juntamente com informações adicionais sobre o endereço IP.
Vários provedores de namespace podem ser instalados em um computador local para o mesmo namespace. Por exemplo, o software de rede TCP/IP base do Windows registra para o namespace NS_DNS. O TMG (Microsoft Forefront Threat Management Gateway) e o servidor ISA (Segurança e Aceleração da Internet) mais antigo da Microsoft incluem software cliente de firewall que também se registra para o namespace NS_DNS. Quando o parâmetro dwNameSpace é definido como um valor (NS_DNS, por exemplo) e o parâmetro lpNspId é NULL, os resultados retornados pela função GetAddrInfoEx são os resultados mesclados de todos os provedores de namespace que se registram para o namespace especificado com resultados duplicados eliminados. O parâmetro lpNspId deverá ser definido como o GUID do provedor de namespace específico se apenas um provedor de namespace for consultado.
Se o parâmetro pNameSpace for definido como NS_ALL, os resultados da consulta a todos os provedores de namespace serão mesclados e retornados. Nesse caso, as respostas duplicadas poderão ser retornadas nos resultados apontados pelo parâmetro ppResult se vários provedores de namespace retornarem as mesmas informações.
No Windows 8 e no Windows Server 2012, se a função GetAddrInfoEx for concluída de forma assíncrona, o ponteiro retornado no parâmetro lpHandle poderá ser usado com a função GetAddrInfoExCancel . O identificador retornado é válido quando GetAddrInfoEx retorna até que a rotina de conclusão seja chamada, o evento seja disparado ou a função GetAddrInfoExCancel seja chamada com esse identificador.
Liberando informações de endereço da alocação dinâmica
Todas as informações retornadas pela função GetAddrInfoEx apontadas pelo parâmetro ppResult são alocadas dinamicamente, incluindo todas as estruturas addrinfoex , estruturas de endereço de soquete e cadeias de caracteres de nome de host canônico apontadas por estruturas addrinfoex . A memória alocada por uma chamada bem-sucedida para essa função deve ser liberada com uma chamada subsequente para FreeAddrInfoEx.Código de exemplo
O exemplo a seguir demonstra o uso da função GetAddrInfoEx .#ifndef UNICODE
#define UNICODE
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <objbase.h>
#include <stdio.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
// Need to link with Ole32.lib to print GUID
#pragma comment(lib, "ole32.lib")
int __cdecl wmain(int argc, wchar_t ** argv)
{
//-----------------------------------------
// Declare and initialize variables
WSADATA wsaData;
int iResult;
DWORD dwRetval;
int i = 1;
DWORD dwNamespace = NS_ALL;
LPGUID lpNspid = NULL;
ADDRINFOEX *result = NULL;
ADDRINFOEX *ptr = NULL;
ADDRINFOEX hints;
// LPSOCKADDR sockaddr_ip;
struct sockaddr_in *sockaddr_ipv4;
struct sockaddr_in6 *sockaddr_ipv6;
// DWORD ipbufferlength = 46;
wchar_t ipstringbuffer[46];
// variables needed to print namespace provider GUID
int iRet = 0;
WCHAR GuidString[40] = { 0 };
// Validate the parameters
if (argc != 4) {
wprintf(L"usage: %ws <hostname> <servicename> <namespace>\n", argv[0]);
wprintf(L"getaddrinfoex provides protocol-independent translation\n");
wprintf(L" from a host name to an IP address\n");
wprintf(L"%ws example usage\n", argv[0]);
wprintf(L" %ws www.contoso.com 0 12\n", argv[0]);
wprintf(L" looks up the www.contoso.com in the NS_DNS namespace\n",
argv[0]);
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0) {
wprintf(L"WSAStartup failed: %d\n", iResult);
return 1;
}
//--------------------------------
// Setup the hints address info structure
// which is passed to the getaddrinfo() function
ZeroMemory(&hints, sizeof (hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
dwNamespace = (DWORD) _wtoi(argv[3]);
wprintf(L"Calling GetAddrInfoEx with following parameters:\n");
wprintf(L"\tName = %ws\n", argv[1]);
wprintf(L"\tServiceName (or port) = %ws\n", argv[2]);
wprintf(L"\tNamespace = %s (", argv[3]);
switch (dwNamespace) {
case NS_ALL:
wprintf(L"(NS_ALL)\n");
break;
case NS_DNS:
wprintf(L"(NS_DNS)\n");
break;
case NS_NETBT:
wprintf(L"NS_NETBT");
break;
case NS_WINS:
wprintf(L"NS_WINS");
break;
case NS_NLA:
wprintf(L"NS_NLA");
break;
case NS_BTH:
wprintf(L"NS_BTH");
break;
case NS_NTDS:
wprintf(L"NS_NTDS");
break;
case NS_EMAIL:
wprintf(L"NS_EMAIL");
break;
case NS_PNRPNAME:
wprintf(L"NS_PNRPNAME");
break;
case NS_PNRPCLOUD:
wprintf(L"NS_PNRPCLOUD");
break;
default:
wprintf(L"Other");
break;
}
wprintf(L")\n\n");
//--------------------------------
// Call getaddrinfoex(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response
// information
dwRetval =
GetAddrInfoEx(argv[1], argv[2], dwNamespace, lpNspid, &hints, &result,
NULL, NULL, NULL, NULL);
if (dwRetval != 0) {
wprintf(L"GetAddrInfoEx failed with error: %d\n", dwRetval);
WSACleanup();
return 1;
}
wprintf(L"GetAddrInfoEx returned success\n");
// Retrieve each address and print out the hex bytes
for (ptr = result; ptr != NULL; ptr = ptr->ai_next) {
wprintf(L"GetAddrInfoEx response %d\n", i++);
wprintf(L"\tFlags: 0x%x\n", ptr->ai_flags);
wprintf(L"\tFamily: ");
switch (ptr->ai_family) {
case AF_UNSPEC:
wprintf(L"Unspecified\n");
break;
case AF_INET:
wprintf(L"AF_INET (IPv4)\n");
// the InetNtop function is available on Windows Vista and later
sockaddr_ipv4 = (struct sockaddr_in *) ptr->ai_addr;
wprintf(L"\tIPv4 address %ws\n",
InetNtop(AF_INET, &sockaddr_ipv4->sin_addr, ipstringbuffer,
46));
// We could also use the WSAAddressToString function
// sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
// The buffer length is changed by each call to WSAAddresstoString
// So we need to set it for each iteration through the loop for safety
// ipbufferlength = 46;
// iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL,
// ipstringbuffer, &ipbufferlength );
// if (iRetval)
// wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
// else
// wprintf(L"\tIPv4 address %ws\n", ipstringbuffer);
break;
case AF_INET6:
wprintf(L"AF_INET6 (IPv6)\n");
// the InetNtop function is available on Windows Vista and later
sockaddr_ipv6 = (struct sockaddr_in6 *) ptr->ai_addr;
wprintf(L"\tIPv6 address %ws\n",
InetNtop(AF_INET6, &sockaddr_ipv6->sin6_addr,
ipstringbuffer, 46));
// We could also use WSAAddressToString which also returns the scope ID
// sockaddr_ip = (LPSOCKADDR) ptr->ai_addr;
// The buffer length is changed by each call to WSAAddresstoString
// So we need to set it for each iteration through the loop for safety
// ipbufferlength = 46;
//iRetval = WSAAddressToString(sockaddr_ip, (DWORD) ptr->ai_addrlen, NULL,
// ipstringbuffer, &ipbufferlength );
//if (iRetval)
// wprintf(L"WSAAddressToString failed with %u\n", WSAGetLastError() );
//else
// wprintf(L"\tIPv6 address %ws\n", ipstringbuffer);
break;
default:
wprintf(L"Other %ld\n", ptr->ai_family);
break;
}
wprintf(L"\tSocket type: ");
switch (ptr->ai_socktype) {
case 0:
wprintf(L"Unspecified\n");
break;
case SOCK_STREAM:
wprintf(L"SOCK_STREAM (stream)\n");
break;
case SOCK_DGRAM:
wprintf(L"SOCK_DGRAM (datagram) \n");
break;
case SOCK_RAW:
wprintf(L"SOCK_RAW (raw) \n");
break;
case SOCK_RDM:
wprintf(L"SOCK_RDM (reliable message datagram)\n");
break;
case SOCK_SEQPACKET:
wprintf(L"SOCK_SEQPACKET (pseudo-stream packet)\n");
break;
default:
wprintf(L"Other %ld\n", ptr->ai_socktype);
break;
}
wprintf(L"\tProtocol: ");
switch (ptr->ai_protocol) {
case 0:
wprintf(L"Unspecified\n");
break;
case IPPROTO_TCP:
wprintf(L"IPPROTO_TCP (TCP)\n");
break;
case IPPROTO_UDP:
wprintf(L"IPPROTO_UDP (UDP) \n");
break;
default:
wprintf(L"Other %ld\n", ptr->ai_protocol);
break;
}
wprintf(L"\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
wprintf(L"\tCanonical name: %s\n", ptr->ai_canonname);
if (ptr->ai_blob == NULL)
wprintf(L"\tBlob: (null)\n");
else
wprintf(L"\tLength of the blob: %u\n",
(DWORD) ptr->ai_bloblen);
if (ptr->ai_provider == NULL)
wprintf(L"\tNamespace provider GUID: (null)\n");
else {
iRet =
StringFromGUID2(*(ptr->ai_provider), (LPOLESTR) & GuidString,
39);
// For c rather than C++ source code, the above line needs to be
// iRet = StringFromGUID2(&ptr.ai_provider, (LPOLESTR) &GuidString, 39);
if (iRet == 0)
wprintf(L"StringFromGUID2 failed\n");
else {
wprintf(L"\tNamespace provider: %ws\n", GuidString);
}
}
}
FreeAddrInfoEx(result);
WSACleanup();
return 0;
}
O exemplo a seguir demonstra como usar a função GetAddrInfoEx assíncrona para resolver um nome para um endereço IP.
//
// This sample demonstrates how to use asynchronous GetAddrInfoEx to
// resolve a name to an IP address.
//
// ResolveName <QueryName>
//
#ifndef UNICODE
#define UNICODE
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
// Need to link with Ws2_32.lib
#pragma comment(lib, "ws2_32.lib")
#define MAX_ADDRESS_STRING_LENGTH 64
//
// Asynchronous query context structure.
//
typedef struct _QueryContext
{
OVERLAPPED QueryOverlapped;
PADDRINFOEX QueryResults;
HANDLE CompleteEvent;
}QUERY_CONTEXT, *PQUERY_CONTEXT;
VOID
WINAPI
QueryCompleteCallback(
_In_ DWORD Error,
_In_ DWORD Bytes,
_In_ LPOVERLAPPED Overlapped
);
int
__cdecl
wmain(
_In_ int Argc, PWCHAR Argv[]
)
{
INT Error = ERROR_SUCCESS;
WSADATA wsaData;
BOOL IsWSAStartupCalled = FALSE;
ADDRINFOEX Hints;
QUERY_CONTEXT QueryContext;
HANDLE CancelHandle = NULL;
DWORD QueryTimeout = 5 * 1000; // 5 seconds
ZeroMemory(&QueryContext, sizeof(QueryContext));
//
// Validate the parameters
//
if (Argc != 2)
{
wprintf(L"Usage: ResolveName <QueryName>\n");
goto exit;
}
//
// All Winsock functions require WSAStartup() to be called first
//
Error = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (Error != 0)
{
wprintf(L"WSAStartup failed with %d\n", Error);
goto exit;
}
IsWSAStartupCalled = TRUE;
ZeroMemory(&Hints, sizeof(Hints));
Hints.ai_family = AF_UNSPEC;
//
// Note that this is a simple sample that waits/cancels a single
// asynchronous query. The reader may extend this to support
// multiple asynchronous queries.
//
QueryContext.CompleteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (QueryContext.CompleteEvent == NULL)
{
Error = GetLastError();
wprintf(L"Failed to create completion event: Error %d\n", Error);
goto exit;
}
//
// Initiate asynchronous GetAddrInfoExW.
//
// Note GetAddrInfoEx can also be invoked asynchronously using an event
// in the overlapped object (Just set hEvent in the Overlapped object
// and set NULL as completion callback.)
//
// This sample uses the completion callback method.
//
Error = GetAddrInfoExW(Argv[1],
NULL,
NS_DNS,
NULL,
&Hints,
&QueryContext.QueryResults,
NULL,
&QueryContext.QueryOverlapped,
QueryCompleteCallback,
&CancelHandle);
//
// If GetAddrInfoExW() returns WSA_IO_PENDING, GetAddrInfoExW will invoke
// the completion routine. If GetAddrInfoExW returned anything else we must
// invoke the completion directly.
//
if (Error != WSA_IO_PENDING)
{
QueryCompleteCallback(Error, 0, &QueryContext.QueryOverlapped);
goto exit;
}
//
// Wait for query completion for 5 seconds and cancel the query if it has
// not yet completed.
//
if (WaitForSingleObject(QueryContext.CompleteEvent,
QueryTimeout) == WAIT_TIMEOUT )
{
//
// Cancel the query: Note that the GetAddrInfoExCancelcancel call does
// not block, so we must wait for the completion routine to be invoked.
// If we fail to wait, WSACleanup() could be called while an
// asynchronous query is still in progress, possibly causing a crash.
//
wprintf(L"The query took longer than %d seconds to complete; "
L"cancelling the query...\n", QueryTimeout/1000);
GetAddrInfoExCancel(&CancelHandle);
WaitForSingleObject(QueryContext.CompleteEvent,
INFINITE);
}
exit:
if (IsWSAStartupCalled)
{
WSACleanup();
}
if (QueryContext.CompleteEvent)
{
CloseHandle(QueryContext.CompleteEvent);
}
return Error;
}
//
// Callback function called by Winsock as part of asynchronous query complete
//
VOID
WINAPI
QueryCompleteCallback(
_In_ DWORD Error,
_In_ DWORD Bytes,
_In_ LPOVERLAPPED Overlapped
)
{
PQUERY_CONTEXT QueryContext = NULL;
PADDRINFOEX QueryResults = NULL;
WCHAR AddrString[MAX_ADDRESS_STRING_LENGTH];
DWORD AddressStringLength;
UNREFERENCED_PARAMETER(Bytes);
QueryContext = CONTAINING_RECORD(Overlapped,
QUERY_CONTEXT,
QueryOverlapped);
if (Error != ERROR_SUCCESS)
{
wprintf(L"ResolveName failed with %d\n", Error);
goto exit;
}
wprintf(L"ResolveName succeeded. Query Results:\n");
QueryResults = QueryContext->QueryResults;
while(QueryResults)
{
AddressStringLength = MAX_ADDRESS_STRING_LENGTH;
WSAAddressToString(QueryResults->ai_addr,
(DWORD)QueryResults->ai_addrlen,
NULL,
AddrString,
&AddressStringLength);
wprintf(L"Ip Address: %s\n", AddrString);
QueryResults = QueryResults->ai_next;
}
exit:
if (QueryContext->QueryResults)
{
FreeAddrInfoEx(QueryContext->QueryResults);
}
//
// Notify caller that the query completed
//
SetEvent(QueryContext->CompleteEvent);
return;
}
Nomes de domínio internacionalizados
Os nomes de host da Internet normalmente consistem em um conjunto muito restrito de caracteres:- Letras maiúsculas e minúsculas ASCII do alfabeto inglês.
- Dígitos de 0 a 9.
- Caracteres de hífen ASCII.
Com o crescimento da Internet, há uma necessidade crescente de identificar nomes de host da Internet para outros idiomas não representados pelo conjunto de caracteres ASCII. Identificadores que facilitam essa necessidade e permitem que caracteres não ASCII (Unicode) sejam representados como cadeias de caracteres ASCII especiais são conhecidos como IDNs (Nomes de Domínio Internacionalizados). Um mecanismo chamado IDNA (Internationalizing Domain Names in Applications) é usado para lidar com IDNs de maneira padrão. As especificações para IDNs e IDNA estão documentadas em RFC 3490, RTF 5890 e RFC 6365 publicados pela IETF (Internet Engineering Task Force).
No Windows 8 e no Windows Server 2012, a função GetAddrInfoEx dá suporte à análise de IDN (Nome de Domínio Internacionalizado) aplicada ao nome passado no parâmetro pName . O Winsock executa a codificação e a conversão de Punycode/IDN. Esse comportamento pode ser desabilitado usando o sinalizador AI_DISABLE_IDN_ENCODING discutido abaixo.
No Windows 7 e no Windows Server 2008 R2 ou anterior, a função GetAddrInfoEx atualmente não dá suporte à análise de IDN aplicada ao nome passado no parâmetro pName . A versão de caractere largo da função GetAddrInfoEx não usa Punycode para converter um formato Punycode de IDN de acordo com RFC 3490. A versão de caractere largo da função GetAddrInfoEx ao consultar o DNS codifica o nome Unicode no formato UTF-8, o formato usado pelos servidores DNS da Microsoft em um ambiente corporativo.
Várias funções no Windows Vista e posteriores dão suporte à conversão entre rótulos Unicode em um IDN para seus equivalentes ASCII. A representação resultante de cada rótulo Unicode contém apenas caracteres ASCII e começa com o prefixo xn-- se o rótulo Unicode contiver caracteres não ASCII. O motivo para isso é dar suporte a servidores DNS existentes na Internet, já que algumas ferramentas e servidores DNS dão suporte apenas a caracteres ASCII (consulte RFC 3490).
A função IdnToAscii usa Punycode para converter um IDN na representação ASCII da cadeia de caracteres Unicode original usando o algoritmo padrão definido no RFC 3490. A função IdnToUnicode converte a forma ASCII de um IDN para a sintaxe de codificação UTF-16 unicode normal. Para obter mais informações e links para padrões de rascunho relacionados, consulte Manipulando IDNs (nomes de domínio internacionalizados).
A função IdnToAscii pode ser usada para converter um nome IDN em um formulário ASCII que, em seguida, pode ser passado no parâmetro pName para a função GetAddrInfoEx quando a versão ASCII dessa função é usada (quando UNICODE e _UNICODE não são definidos). Para passar esse nome IDN para a função GetAddrInfoEx quando a versão de caractere largo dessa função for usada (quando UNICODE ou _UNICODE for definido), você pode usar a função MultiByteToWideChar para converter a cadeia de caracteres CHAR em uma cadeia de caracteres WCHAR .
Uso de ai_flags no parâmetro hints
Sinalizadores no membro ai_flags da estrutura addrinfoex opcional fornecida no parâmetro hints modificam o comportamento da função.
Esses bits de sinalizador são definidos no arquivo de cabeçalho Ws2def.h no Microsoft Windows Software Development Kit (SDK) para Windows 7. Esses bits de sinalizador são definidos no arquivo de cabeçalho Ws2tcpip.h no SDK do Windows para Windows Server 2008 e Windows Vista. Esses bits de sinalizador são definidos no arquivo de cabeçalho Ws2tcpip.h no SDK (Platform Software Development Kit) para Windows Server 2003 e Windows XP.
Os bits de sinalizador podem ser uma combinação do seguinte:
Bits de sinalizador | Descrição |
---|---|
AI_PASSIVE |
Definir o sinalizador AI_PASSIVE indica que o chamador pretende usar a estrutura de endereço de soquete retornada em uma chamada para a função de associação . Quando o sinalizador AI_PASSIVE é definido e pName é um ponteiro NULL , a parte do endereço IP da estrutura de endereços de soquete é definida como INADDR_ANY para endereços IPv4 e IN6ADDR_ANY_INIT para endereços IPv6.
Quando o sinalizador AI_PASSIVE não estiver definido, a estrutura de endereços de soquete retornada estará pronta para uma chamada para a função de conexão para um protocolo orientado a conexão ou estará pronta para uma chamada para as funções connect, sendto ou send para um protocolo sem conexão. Se o parâmetro pName for um ponteiro NULL nesse caso, a parte do endereço IP da estrutura de endereços de soquete será definida como o endereço de loopback. |
AI_CANONNAME |
Se nem AI_CANONNAME nem AI_NUMERICHOST forem usados, a função GetAddrInfoEx tentará a resolução. Se uma cadeia de caracteres literal for passada , GetAddrInfoEx tentará converter a cadeia de caracteres e, se um nome de host for passado, a função GetAddrInfoEx tentará resolver o nome para um endereço ou vários endereços.
Quando o bit AI_CANONNAME é definido, o parâmetro pName não pode ser NULL. Caso contrário, a função GetAddrInfoEx falhará com WSANO_RECOVERY. Quando o bit AI_CANONNAME é definido e a função GetAddrInfoEx retorna êxito, o membro ai_canonname no parâmetro ppResult aponta para uma cadeia de caracteres terminada em NULL que contém o nome canônico do nó especificado. Nota A função GetAddrInfoEx pode retornar êxito quando o sinalizador AI_CANONNAME está definido, mas o membro ai_canonname na estrutura addrinfo associada é NULL. Portanto, o uso recomendado do sinalizador AI_CANONNAME inclui testar se o membro ai_canonname na estrutura addrinfoex associada é NULL.
|
AI_NUMERICHOST | Quando o bit AI_NUMERICHOST é definido, o parâmetro pName deve conter uma cadeia de caracteres de endereço de host numérico não NULL ; caso contrário, o erro EAI_NONAME será retornado. Esse sinalizador impede que um serviço de resolução de nomes seja chamado. |
AI_NUMERICSERV |
Quando o bit AI_NUMERICSERV é definido, o parâmetro pServiceName deve conter um número de porta numérica não NULL ; caso contrário, o erro EAI_NONAME será retornado. Esse sinalizador impede que um serviço de resolução de nomes seja chamado.
O sinalizador AI_NUMERICSERV é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_NUMERICSERV não tem suporte dos provedores da Microsoft. |
AI_ALL |
Se o bit AI_ALL estiver definido, uma solicitação será feita para endereços IPv6 e endereços IPv4 com AI_V4MAPPED.
O sinalizador AI_ALL é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_ALL tem suporte no Windows Vista e posterior. |
AI_ADDRCONFIG |
Se o AI_ADDRCONFIG bit estiver definido, GetAddrInfoEx será resolvido somente se um endereço global estiver configurado. Se AI_ADDRCONFIG sinalizador for especificado, os endereços IPv4 serão retornados somente se um endereço IPv4 estiver configurado no sistema local, e os endereços IPv6 serão retornados somente se um endereço IPv6 estiver configurado no sistema local. O endereço de loopback IPv4 ou IPv6 não é considerado um endereço global válido.
O sinalizador AI_ADDRCONFIG é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_ADDRCONFIG tem suporte no Windows Vista e posterior. |
AI_V4MAPPED |
Se o bit AI_V4MAPPED estiver definido e uma solicitação para endereços IPv6 falhar, uma solicitação de serviço de nome será feita para endereços IPv4 e esses endereços serão convertidos no formato de endereço IPv6 mapeado por IPv4.
O sinalizador AI_V4MAPPED é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_V4MAPPED tem suporte no Windows Vista e posterior. |
AI_NON_AUTHORITATIVE |
Se o bit AI_NON_AUTHORITATIVE estiver definido, o provedor de namespace NS_EMAIL retornará resultados autoritativos e não autoritativos. Se o bit AI_NON_AUTHORITATIVE não estiver definido, o provedor de namespace NS_EMAIL retornará apenas resultados autoritativos.
O sinalizador AI_NON_AUTHORITATIVE é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_NON_AUTHORITATIVE tem suporte no Windows Vista e posterior e se aplica apenas ao namespace NS_EMAIL . |
AI_SECURE |
Se o bit AI_SECURE estiver definido, o provedor de namespace NS_EMAIL retornará os resultados obtidos com segurança aprimorada para minimizar possíveis falsificações.
O sinalizador AI_SECURE é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_SECURE tem suporte no Windows Vista e posterior e se aplica apenas ao namespace NS_EMAIL . |
AI_RETURN_PREFERRED_NAMES |
Se o AI_RETURN_PREFERRED_NAMES estiver definido, nenhum nome deverá ser fornecido no parâmetro pName . O provedor de namespace NS_EMAIL retornará nomes preferenciais para publicação.
O sinalizador AI_RETURN_PREFERRED_NAMES é definido no SDK do Windows para Windows Vista e posterior. O sinalizador AI_RETURN_PREFERRED_NAMES tem suporte no Windows Vista e posterior e se aplica apenas ao namespace NS_EMAIL . |
AI_FQDN |
Se o AI_FQDN estiver definido e um nome simples (rótulo único) for especificado, GetAddrInfoEx retornará o nome de domínio totalmente qualificado para o qual o nome acabou sendo resolvido. O nome de domínio totalmente qualificado é retornado no membro ai_canonname na estrutura addrinfoex associada. Isso é diferente de AI_CANONNAME sinalizador de bit que retorna o nome canônico registrado no DNS que pode ser diferente do nome de domínio totalmente qualificado para o qual o nome simples foi resolvido.
Quando o bit AI_FQDN é definido, o parâmetro pName não pode ser NULL. Caso contrário, a função GetAddrInfoEx falhará com WSANO_RECOVERY. No Windows 8 e no Windows Server 2012, os bits AI_FQDN e AI_CANONNAME podem ser definidos. Se a função GetAddrInfoEx for chamada com os bits AI_FQDN e AI_CANONNAME , o parâmetro ppResult retornará um ponteiro para uma estrutura addrinfoex2 , não uma estrutura addrinfoex . No Windows 7 e no Windows Server 2008 R2, apenas um dos bits AI_FQDN e AI_CANONNAME pode ser definido. A função GetAddrInfoEx falhará se ambos os sinalizadores estiverem presentes com EAI_BADFLAGS. Windows 7: O sinalizador AI_FQDN é definido no SDK do Windows para Windows 7 e posterior. O sinalizador AI_FQDN tem suporte no Windows 7 e posterior. |
AI_FILESERVER |
Se o AI_FILESERVER estiver definido, essa será uma dica para o provedor de namespace que o nome do host que está sendo consultado está sendo usado no cenário de compartilhamento de arquivos. O provedor de namespace pode ignorar essa dica.
Windows 7: O sinalizador AI_FILESERVER é definido no SDK do Windows para Windows 7 e posterior. O sinalizador AI_FILESERVER tem suporte no Windows 7 e posterior. |
AI_DISABLE_IDN_ENCODING |
Se o AI_DISABLE_IDN_ENCODING estiver definido, isso desabilita a codificação automática de Nome de Domínio Internacional usando Punycode nas funções de resolução de nomes chamadas pela função GetAddrInfoEx .
Windows 8: O sinalizador AI_DISABLE_IDN_ENCODING é definido no SDK do Windows para Windows 8 e posterior. O sinalizador AI_DISABLE_IDN_ENCODING tem suporte no Windows 8 e posterior. |
Observação
O cabeçalho ws2tcpip.h define GetAddrInfoEx como um alias que seleciona automaticamente a versão ANSI ou Unicode dessa função com base na definição da constante de pré-processador UNICODE. Misturar o uso do alias neutro de codificação com código que não seja neutro em codificação pode levar a incompatibilidades que resultam em erros de compilação ou de runtime. Para obter mais informações, consulte Convenções para protótipos de função.
Requisitos
Requisito | Valor |
---|---|
Cliente mínimo com suporte | Windows XP [aplicativos da área de trabalho | aplicativos UWP] |
Servidor mínimo com suporte | Windows Server 2008 [aplicativos da área de trabalho | Aplicativos UWP] |
Plataforma de Destino | Windows |
Cabeçalho | ws2tcpip.h |
Biblioteca | Ws2_32.lib |
DLL | Ws2_32.dll |