Función GetAddrInfoExA (ws2tcpip.h)
La función GetAddrInfoEx proporciona resolución de nombres independiente del protocolo con parámetros adicionales para calificar qué proveedores de espacios de nombres deben controlar la solicitud.
Sintaxis
INT WSAAPI GetAddrInfoExA(
[in, optional] PCSTR pName,
[in, optional] PCSTR pServiceName,
[in] DWORD dwNameSpace,
[in, optional] LPGUID lpNspId,
[in, optional] const ADDRINFOEXA *hints,
[out] PADDRINFOEXA *ppResult,
[in, optional] timeval *timeout,
[in, optional] LPOVERLAPPED lpOverlapped,
[in, optional] LPLOOKUPSERVICE_COMPLETION_ROUTINE lpCompletionRoutine,
[out, optional] LPHANDLE lpNameHandle
);
Parámetros
[in, optional] pName
Puntero a una cadena terminada en NULL que contiene un nombre de host (nodo) o una cadena de dirección de host numérica. Para el protocolo de Internet, la cadena de dirección de host numérica es una dirección IPv4 con puntos decimales o una dirección hexadecimal IPv6.
[in, optional] pServiceName
Puntero a una cadena opcional terminada en NULL que contiene un nombre de servicio o un número de puerto representados como una cadena.
Un nombre de servicio es un alias de cadena para un número de puerto. Por ejemplo, "http" es un alias para el puerto 80 definido por el Grupo de tareas de ingeniería de Internet (IETF) como el puerto predeterminado que usan los servidores web para el protocolo HTTP. Los valores posibles para el parámetro pServiceName cuando no se especifica un número de puerto se enumeran en el siguiente archivo:
%WINDIR%\system32\drivers\etc\services
[in] dwNameSpace
Identificador de espacio de nombres opcional que determina qué proveedores de espacios de nombres se consultan. Si se pasa un identificador de espacio de nombres específico, solo se producirán proveedores de espacios de nombres que admitan el espacio de nombres especificado que se consulta. Si se especifica NS_ALL , se consultarán todos los proveedores de espacios de nombres instalados y activos.
Las opciones del parámetro dwNameSpace se muestran en el archivo de inclusión Winsock2.h . Se agregan varios proveedores de espacios de nombres en Windows Vista y versiones posteriores. Se pueden instalar otros proveedores de espacios de nombres, por lo que los siguientes valores posibles son solo los disponibles con frecuencia. Muchos otros valores son posibles.
[in, optional] lpNspId
Puntero a un GUID opcional de un proveedor de espacios de nombres específico para consultar en el caso de que varios proveedores de espacios de nombres se registren en un único espacio de nombres, como NS_DNS. Si se pasa el GUID para un proveedor de espacio de nombres específico, solo se consultará el proveedor de espacio de nombres especificado. Se puede llamar a la función WSAEnumNameSpaceProviders para recuperar el GUID de un proveedor de espacios de nombres.
[in, optional] hints
Puntero a una estructura addrinfoex que proporciona sugerencias sobre el tipo de socket que admite el autor de la llamada.
Los miembros ai_addrlen, ai_canonname, ai_addr y ai_next de la estructura addrinfoex a la que apunta el parámetro pHints deben ser cero o NULL. De lo contrario, se producirá un error en la función GetAddrInfoEx con WSANO_RECOVERY.
Consulte los comentarios para obtener más detalles.
[out] ppResult
Puntero a una lista vinculada de una o varias estructuras addrinfoex que contiene información de respuesta sobre el host.
[in, optional] timeout
Parámetro opcional que indica el tiempo, en milisegundos, para esperar una respuesta del proveedor de espacio de nombres antes de anular la llamada.
Este parámetro solo se admite cuando se ha definido la macro UNICODE o _UNICODE en los orígenes antes de llamar a la función GetAddrInfoEx . De lo contrario, este parámetro está reservado actualmente y debe establecerse en NULL , ya que no se admite una opción de tiempo de espera .
[in, optional] lpOverlapped
Puntero opcional a una estructura superpuesta utilizada para la operación asincrónica.
Este parámetro solo se admite cuando se ha definido la macro UNICODE o _UNICODE en los orígenes antes de llamar a la función GetAddrInfoEx .
En Windows 8 y Windows Server 2012, si no se especifica ningún parámetro lpCompletionRoutine , el miembro hEvent de la estructura SUPERPUESTA debe establecerse en un evento de restablecimiento manual al que se llamará al finalizar una llamada asincrónica. Si se ha especificado una rutina de finalización, el miembro hEvent debe ser NULL. Cuando se ha establecido el evento especificado por hEvent , el resultado de la operación se puede recuperar llamando a la función GetAddrInfoExOverlappedResult .
En Windows 8 y Windows Server 2012 cada vez que no se define la macro UNICODE o _UNICODE , este parámetro está reservado actualmente y debe establecerse en NULL.
En Windows 7 y Windows Server 2008 R2 o versiones anteriores, este parámetro está reservado actualmente y debe establecerse en NULL , ya que no se admiten operaciones asincrónicas.
[in, optional] lpCompletionRoutine
Puntero opcional a una función que se va a invocar tras completarse correctamente para las operaciones asincrónicas.
Este parámetro solo se admite cuando se ha definido la macro UNICODE o _UNICODE en los orígenes antes de llamar a la función GetAddrInfoEx .
Si se especifica este parámetro, debe ser un puntero a una función con la siguiente firma:
typedef
void
(CALLBACK * LPLOOKUPSERVICE_COMPLETION_ROUTINE)(
__in DWORD dwError,
__in DWORD dwBytes,
__in LPWSAOVERLAPPED lpOverlapped
);
Cuando se haya completado la operación asincrónica, se invocará la rutina de finalización con el parámetro lpOverlapped establecido en el valor del parámetro lpOverlapped pasado a GetAddrInfoEx. El miembro Puntero de la estructura SUPERPUESTA se establecerá en el valor del parámetro ppResult de la llamada original. Si el miembro Puntero apunta a un puntero distinto de NULL a la estructura addrinfoex , es responsabilidad del autor de la llamada llamar a FreeAddrInfoEx para liberar la estructura addrinfoex . El parámetro dwError pasado a la rutina de finalización se establecerá en un código de error de Winsock. El parámetro dwBytes está reservado para uso futuro y se debe omitir.
En Windows 8 y Windows Server 2012 cada vez que no se define la macro UNICODE o _UNICODE , este parámetro está reservado actualmente y debe establecerse en NULL.
En Windows 7 y Windows Server 2008 R2 o versiones anteriores, este parámetro está reservado actualmente y debe establecerse en NULL , ya que no se admiten operaciones asincrónicas.
[out, optional] lpNameHandle
Puntero opcional que solo se usa para las operaciones asincrónicas.
Este parámetro solo se admite cuando se ha definido la macro UNICODE o _UNICODE en los orígenes antes de llamar a la función GetAddrInfoEx .
En Windows 8 y Windows Server 2012, si la función GetAddrInfoEx se completará de forma asincrónica, el puntero devuelto en este campo se puede usar con la función GetAddrInfoExCancel . El identificador devuelto es válido cuando GetAddrInfoEx devuelve hasta que se llama a la rutina de finalización, se desencadena el evento o se llama a la función GetAddrInfoExCancel con este identificador.
En Windows 8 y Windows Server 2012 cada vez que no se define la macro UNICODE o _UNICODE , este parámetro está reservado actualmente y debe establecerse en NULL.
En Windows 7 y Windows Server 2008 R2 o versiones anteriores, este parámetro está reservado actualmente y debe establecerse en NULL , ya que no se admiten operaciones asincrónicas.
Valor devuelto
Si se ejecuta correctamente, GetAddrInfoEx devuelve NO_ERROR (0). Error devuelve un código de error de Windows Sockets distinto de cero, como se encuentra en los códigos de error de Windows Sockets.
La mayoría de los códigos de error distintos de cero devueltos por la función GetAddrInfoEx se asignan al conjunto de errores descritos por las recomendaciones del Grupo de tareas de ingeniería de Internet (IETF). En la tabla siguiente se muestran estos códigos de error y sus equivalentes de WSA. Se recomienda usar los códigos de error de WSA, ya que ofrecen información de errores familiar y completa para los programadores de Winsock.
Valor de error | WSA equivalente | Descripción |
---|---|---|
EAI_AGAIN | WSATRY_AGAIN | Error temporal en la resolución de nombres. |
EAI_BADFLAGS | WSAEINVAL | Se proporcionó un parámetro no válido. Este error se devuelve si alguno de los parámetros reservados no es NULL. Este error también se devuelve si se proporcionó un valor no válido para el miembro ai_flags del parámetro pHints . |
EAI_FAIL | WSANO_RECOVERY | Error irrecuperable en la resolución de nombres. |
EAI_FAMILY | WSAEAFNOSUPPORT | No se admite el miembro ai_family del parámetro pHints . |
EAI_MEMORY | WSA_NOT_ENOUGH_MEMORY | Error de asignación de memoria. |
EAI_NONAME | WSAHOST_NOT_FOUND | El nombre no se resuelve para los parámetros proporcionados o no se proporcionaron los parámetros pName y pServiceName . |
EAI_SERVICE | WSATYPE_NOT_FOUND | El parámetro pServiceName no se admite para el miembro ai_socktype especificado del parámetro pHints . |
EAI_SOCKTYPE | WSAESOCKTNOSUPPORT | No se admite el miembro ai_socktype del parámetro pHints . |
Use la función gai_strerror para imprimir mensajes de error basados en los códigos EAI devueltos por la función GetAddrInfoEx . La función gai_strerror se proporciona para cumplir las recomendaciones de IETF, pero no es segura para subprocesos. Por lo tanto, se recomienda el uso de funciones tradicionales de Windows Sockets, como WSAGetLastError .
Código de error | Significado |
---|---|
No había memoria suficiente para realizar la operación. | |
Se ha usado una dirección incompatible con el protocolo solicitado. Este error se devuelve si no se admite el miembro ai_family de la estructura addrinfoex a la que apunta el parámetro pHints . | |
Se ha proporcionado un argumento no válido. Este error se devuelve si se proporcionó un valor no válido para el miembro ai_flags de la estructura addrinfoex a la que apunta el parámetro pHints . Este error también se devuelve cuando el parámetro dwNameSpace está NS_PNRPNAME o NS_PNRPCLOUD y el servicio de nombre punto a punto no funciona. | |
Esta familia de direcciones no es compatible con el tipo de socket especificado. Este error se devuelve si no se admite el miembro ai_socktype de la estructura addrinfoex a la que apunta el parámetro pHints . | |
Se desconoce el host. Este error se devuelve si el nombre no se resuelve para los parámetros proporcionados o no se proporcionaron los parámetros pName y pServiceName . | |
El nombre solicitado es válido, pero no se ha encontrado ningún dato del tipo solicitado. | |
Se produjo un error no recuperable durante una búsqueda de base de datos. Este error se devuelve si se produjo un error irrecuperable en la resolución de nombres. | |
Debe producirse una llamada de WSAStartup correcta antes de usar esta función. | |
No se conoce este servicio. No se encuentra el servicio en el espacio de nombres especificado. Este error se devuelve si no se encuentra el parámetro pName o pServiceName para el espacio de nombres especificado en el parámetro dwNameSpace o el espacio de nombres especificado en el parámetro dwNameSpace no está instalado. | |
Éste es normalmente un error temporal durante la resolución de nombres de host y significa que el servidor local no recibió una respuesta de un servidor autorizado. Este error se devuelve cuando se produjo un error temporal en la resolución de nombres. | |
No se encontró la clase especificada. El parámetro pServiceName no se admite para el miembro ai_socktype especificado de la estructura addrinfoex a la que apunta el parámetro pHints . |
Comentarios
La función GetAddrInfoEx proporciona una traducción independiente del protocolo del nombre de host a la dirección y del nombre del servicio al número de puerto. La función GetAddrInfoEx es una versión mejorada de las funciones getaddrinfo y GetAddrInfoW . La función GetAddrInfoEx permite especificar el proveedor de espacios de nombres para resolver la consulta.
La función GetAddrInfoEx agrega y devuelve resultados de varios proveedores de espacios de nombres, a menos que se especifique un proveedor de espacio de nombres específico. Para su uso con el protocolo IPv6 e IPv4, la resolución de nombres puede ser por el Sistema de nombres de dominio (DNS), un archivo de hosts local, un proveedor de correo electrónico (el espacio de nombres NS_EMAIL ) o por otros mecanismos de nomenclatura.
Cuando se define UNICODE o _UNICODE, GetAddrInfoEx se define en GetAddrInfoExW, la versión Unicode de esta función. Los parámetros de cadena se definen en el tipo de datos PWSTR y se usa la estructura ADDRINFOEXW . En Windows 8 y Windows Server 2012, los parámetros timeout, lpOverlapped, lpCompletionRoutine y lpNameHandle se pueden usar para llamar a la función GetAddrInfoEx para que pueda completarse de forma asincrónica.
Cuando no se define UNICODE o _UNICODE, GetAddrInfoEx se define en GetAddrInfoExA, la versión ANSI de esta función. Los parámetros de cadena son del tipo de datos PCSTR y se usa la estructura ADDRINFOEXA . Los parámetros timeout, lpOverlapped, lpCompletionRoutine y lpNameHandle deben establecerse en NULL.
Uno o ambos parámetros pName o pServiceName deben apuntar a una cadena terminada en NULL. Por lo general, ambos se proporcionan.
Tras la operación correcta, se devuelve una lista vinculada de estructuras addrinfoex en el parámetro ppResult . La lista se puede procesar siguiendo el puntero proporcionado en el miembro ai_next de cada estructura addrinfoex devuelta hasta que se encuentre un puntero NULL . En cada estructura addrinfoex devuelta, los miembros ai_family, ai_socktype y ai_protocol corresponden a los argumentos respectivos en una llamada de función WSASocket o socket. Además, el miembro ai_addr en cada estructura addrinfoex devuelta apunta a una estructura de direcciones de socket rellenada, la longitud de la cual se especifica en su miembro ai_addrlen .
Si el parámetro pName apunta a un nombre de equipo, se devuelven todas las direcciones permanentes del equipo que se pueden usar como dirección de origen. En Windows Vista y versiones posteriores, estas direcciones incluirían todas las direcciones IP de unidifusión devueltas por las funciones GetUnicastIpAddressTable o GetUnicastIpAddressEntry en las que el miembro SkipAsSource se establece en false en la estructura MIB_UNICASTIPADDRESS_ROW .
Si el parámetro pName apunta a una cadena igual a "localhost", se devuelven todas las direcciones de bucle invertido en el equipo local.
Si el parámetro pName contiene una cadena vacía, se devuelven todas las direcciones registradas en el equipo local.
En Windows Server 2003 y versiones posteriores, si el parámetro pName apunta a una cadena igual a ".. localmachine", se devuelven todas las direcciones registradas en el equipo local.
Si el parámetro pName hace referencia a un nombre de servidor virtual de clúster, solo se devuelven las direcciones del servidor virtual. En Windows Vista y versiones posteriores, estas direcciones incluirían todas las direcciones IP de unidifusión devueltas por las funciones GetUnicastIpAddressTable o GetUnicastIpAddressEntry en las que el miembro SkipAsSource se establece en true en la estructura MIB_UNICASTIPADDRESS_ROW . Consulte Clústeres de Windows para obtener más información sobre la agrupación en clústeres.
Windows 7 con Service Pack 1 (SP1) y Windows Server 2008 R2 con Service Pack 1 (SP1) agregan compatibilidad con Netsh.exe para establecer el atributo SkipAsSource en una dirección IP. Esto también cambia el comportamiento de modo que si el miembro SkipAsSource de la estructura MIB_UNICASTIPADDRESS_ROW está establecido en false, la dirección IP se registrará en DNS. Si el miembro SkipAsSource se establece en true, la dirección IP no se registra en DNS.
Hay disponible una revisión para Windows 7 y Windows Server 2008 R2 que agrega compatibilidad a Netsh.exe para establecer el atributo SkipAsSource en una dirección IP. Esta revisión también cambia el comportamiento de forma que si el miembro SkipAsSource de la estructura MIB_UNICASTIPADDRESS_ROW está establecido en false, la dirección IP se registrará en DNS. Si el miembro SkipAsSource se establece en true, la dirección IP no se registra en DNS. Para obtener más información, vea Knowledge Base (KB) 2386184.
También hay disponible una revisión similar para Windows Vista con Service Pack 2 (SP2) y Windows Server 2008 con Service Pack 2 (SP2) que agrega compatibilidad a Netsh.exe para establecer el atributo SkipAsSource en una dirección IP. Esta revisión también cambia el comportamiento de forma que si el miembro SkipAsSource de la estructura MIB_UNICASTIPADDRESS_ROW está establecido en false, la dirección IP se registrará en DNS. Si el miembro SkipAsSource se establece en true, la dirección IP no se registra en DNS.
Los autores de llamadas de la función GetAddrInfoEx pueden proporcionar sugerencias sobre el tipo de socket admitido a través de una estructura addrinfoex a la que apunta el parámetro pHints . Cuando se usa el parámetro pHints , las reglas siguientes se aplican a su estructura addrinfoex asociada:
- Un valor de AF_UNSPEC para ai_family indica que el autor de la llamada aceptará solo las familias de direcciones AF_INET y AF_INET6 . Tenga en cuenta que AF_UNSPEC y PF_UNSPEC son los mismos.
- Un valor de cero para ai_socktype indica que el autor de la llamada aceptará cualquier tipo de socket.
- Un valor de cero para ai_protocol indica que el autor de la llamada aceptará cualquier protocolo.
- El miembro ai_addrlen debe establecerse en cero.
- El miembro ai_canonname debe establecerse en NULL.
- El miembro ai_addr debe establecerse en NULL.
- El miembro ai_next debe establecerse en NULL.
Otros valores de la estructura addrinfoex proporcionada en el parámetro pHints indican requisitos específicos. Por ejemplo, si el autor de la llamada solo controla IPv4 y no controla IPv6, el miembro ai_family debe establecerse en AF_INET. Por otro ejemplo, si el autor de la llamada solo controla TCP y no controla UDP, el miembro ai_socktype debe establecerse en SOCK_STREAM.
Si el parámetro pHints es un puntero NULL , la función GetAddrInfoEx la trata como si la estructura addrinfoex de pHints se inicializara con su miembro ai_family establecido en AF_UNSPEC y todos los demás miembros establecidos en NULL o cero.
Cuando se llama a GetAddrInfoEx desde un servicio, si la operación es el resultado de un proceso de usuario que llama al servicio, el servicio debe suplantar al usuario. Esto es para permitir que la seguridad se aplique correctamente.
La función GetAddrInfoEx se puede usar para convertir una representación de cadena de texto de una dirección IP en una estructura addrinfoex que contiene una estructura sockaddr para la dirección IP y otra información. Para usarse de esta manera, la cadena a la que apunta el parámetro pName debe contener una representación de texto de una dirección IP y la estructura addrinfoex a la que apunta el parámetro pHints debe tener la marca AI_NUMERICHOST establecida en el miembro ai_flags . La cadena a la que apunta el parámetro pName puede contener una representación de texto de una dirección IPv4 o IPv6. La dirección IP de texto se convierte en una estructura addrinfoex a la que apunta el parámetro ppResult . La estructura addrinfoex devuelta contiene una estructura sockaddr para la dirección IP junto con información adicional sobre la dirección IP.
Se pueden instalar varios proveedores de espacios de nombres en un equipo local para el mismo espacio de nombres. Por ejemplo, el software de red TCP/IP base de Windows se registra para el espacio de nombres NS_DNS. Microsoft Forefront Threat Management Gateway (TMG) y el servidor de aceleración y seguridad de Internet (ISA) anterior incluyen software cliente de firewall que también se registra para el espacio de nombres NS_DNS. Cuando el parámetro dwNameSpace se establece en un valor (NS_DNS, por ejemplo) y el parámetro lpNspId es NULL, los resultados devueltos por la función GetAddrInfoEx son los resultados combinados de todos los proveedores de espacios de nombres que se registran para el espacio de nombres especificado con resultados duplicados eliminados. El parámetro lpNspId debe establecerse en el GUID del proveedor de espacios de nombres específico si solo se va a consultar un único proveedor de espacios de nombres.
Si el parámetro pNameSpace se establece en NS_ALL, los resultados de la consulta de todos los proveedores de espacios de nombres se combinan y devuelven. En este caso, se pueden devolver respuestas duplicadas en los resultados a los que apunta el parámetro ppResult si varios proveedores de espacios de nombres devuelven la misma información.
En Windows 8 y Windows Server 2012, si la función GetAddrInfoEx se completará de forma asincrónica, el puntero devuelto en el parámetro lpNameHandle se puede usar con la función GetAddrInfoExCancel . El identificador devuelto es válido cuando GetAddrInfoEx devuelve hasta que se llama a la rutina de finalización, se desencadena el evento o se llama a la función GetAddrInfoExCancel con este identificador.
Liberar información de direcciones de la asignación dinámica
Toda la información devuelta por la función GetAddrInfoEx a la que apunta el parámetro ppResult se asigna dinámicamente, incluidas todas las estructuras addrinfoex , las estructuras de direcciones de socket y las cadenas de nombre de host canónicas a las que apuntan las estructuras addrinfoex . La memoria asignada por una llamada correcta a esta función debe liberarse con una llamada posterior a FreeAddrInfoEx.Código de ejemplo
En el ejemplo siguiente se muestra el uso de la función 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;
}
En el ejemplo siguiente se muestra cómo usar la función GetAddrInfoEx asincrónica para resolver un nombre en una dirección 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;
}
Nombres de dominio internacionalizados
Los nombres de host de Internet normalmente constan de un conjunto de caracteres muy restringido:- Letras ASCII mayúsculas y minúsculas del alfabeto inglés.
- Dígitos del 0 al 9.
- Caracteres de guion ASCII.
Con el crecimiento de Internet, hay una creciente necesidad de identificar los nombres de host de Internet para otros idiomas no representados por el juego de caracteres ASCII. Los identificadores que facilitan esta necesidad y permiten representar caracteres no ASCII (Unicode) como cadenas de caracteres ASCII especiales se conocen como nombres de dominio internacionalizados (IDN). Un mecanismo denominado Internationalizing Domain Names in Applications (IDNA) se usa para controlar los IDN de forma estándar. Las especificaciones de IDN e IDNA se documentan en RFC 3490, RTF 5890 y RFC 6365 publicados por el Grupo de tareas de ingeniería de Internet (IETF).
En Windows 8 y Windows Server 2012, la función GetAddrInfoEx proporciona compatibilidad con el análisis de nombres de dominio internacionalizados (IDN) aplicado al nombre pasado en el parámetro pName . Winsock realiza la codificación y conversión de Punycode/IDN. Este comportamiento se puede deshabilitar con la marca AI_DISABLE_IDN_ENCODING que se describe a continuación.
En Windows 7 y Windows Server 2008 R2 o versiones anteriores, la función GetAddrInfoEx no proporciona actualmente compatibilidad con el análisis de IDN aplicado al nombre pasado en el parámetro pName . La versión de caracteres anchos de la función GetAddrInfoEx no usa Punycode para convertir un formato idN Punycode según RFC 3490. La versión de caracteres anchos de la función GetAddrInfoEx al consultar DNS codifica el nombre Unicode en formato UTF-8, el formato que usan los servidores DNS de Microsoft en un entorno empresarial.
Varias funciones en Windows Vista y versiones posteriores admiten la conversión entre etiquetas Unicode en un IDN a sus equivalentes ASCII. La representación resultante de cada etiqueta Unicode contiene solo caracteres ASCII y comienza con el prefijo xn-- si la etiqueta Unicode contenía caracteres no ASCII. El motivo es admitir servidores DNS existentes en Internet, ya que algunas herramientas y servidores DNS solo admiten caracteres ASCII (consulte RFC 3490).
La función IdnToAscii usa Punycode para convertir un IDN en la representación ASCII de la cadena Unicode original mediante el algoritmo estándar definido en RFC 3490. La función IdnToUnicode convierte la forma ASCII de un IDN en la sintaxis normal de codificación UTF-16 de Unicode. Para obtener más información y vínculos a estándares de borrador relacionados, consulte Control de nombres de dominio internacionalizados (IDN).
La función IdnToAscii se puede usar para convertir un nombre IDN en un formulario ASCII que, a continuación, se puede pasar en el parámetro pName a la función GetAddrInfoEx cuando se usa la versión ASCII de esta función (cuando no se definen UNICODE y _UNICODE). Para pasar este nombre IDN a la función GetAddrInfoEx cuando se usa la versión de caracteres anchos de esta función (cuando se define UNICODE o _UNICODE), puede usar la función MultiByteToWideChar para convertir la cadena CHAR en una cadena WCHAR .
Uso de ai_flags en el parámetro hints
Las marcas del miembro ai_flags de la estructura addrinfoex opcional proporcionada en el parámetro hints modifican el comportamiento de la función.
Estos bits de marca se definen en el archivo de encabezado Ws2def.h en el Kit de desarrollo de software (SDK) de Microsoft Windows para Windows 7. Estos bits de marca se definen en el archivo de encabezado Ws2tcpip.h en windows SDK para Windows Server 2008 y Windows Vista. Estos bits de marca se definen en el archivo de encabezado Ws2tcpip.h en el Kit de desarrollo de software de plataforma (SDK) para Windows Server 2003 y Windows XP.
Los bits de marca pueden ser una combinación de lo siguiente:
Bits de marca | Descripción |
---|---|
AI_PASSIVE |
Establecer la marca AI_PASSIVE indica que el autor de la llamada pretende usar la estructura de direcciones de socket devuelta en una llamada a la función bind . Cuando se establece la marca de AI_PASSIVE y pName es un puntero NULL , la parte de la dirección IP de la estructura de direcciones de socket se establece en INADDR_ANY para las direcciones IPv4 y IN6ADDR_ANY_INIT para las direcciones IPv6.
Cuando no se establece la marca de AI_PASSIVE , la estructura de direcciones de socket devuelta está lista para una llamada a la función connect para un protocolo orientado a la conexión o lista para una llamada a las funciones connect, sendto o send para un protocolo sin conexión. Si el parámetro pName es un puntero NULL en este caso, la parte de la dirección IP de la estructura de direcciones de socket se establece en la dirección de bucle invertido. |
AI_CANONNAME |
Si no se usa ni AI_CANONNAME ni AI_NUMERICHOST , la función GetAddrInfoEx intenta la resolución. Si se pasa una cadena literal GetAddrInfoEx intenta convertir la cadena y, si se pasa un nombre de host, la función GetAddrInfoEx intenta resolver el nombre en una dirección o en varias direcciones.
Cuando se establece el bit de AI_CANONNAME , el parámetro pName no puede ser NULL. De lo contrario, se producirá un error en la función GetAddrInfoEx con WSANO_RECOVERY. Cuando se establece el bit de AI_CANONNAME y la función GetAddrInfoEx devuelve correctamente, el miembro ai_canonname del parámetro ppResult apunta a una cadena terminada en NULL que contiene el nombre canónico del nodo especificado. Nota La función GetAddrInfoEx puede devolver éxito cuando se establece la marca de AI_CANONNAME , pero el miembro ai_canonname de la estructura addrinfo asociada es NULL. Por lo tanto, el uso recomendado de la marca AI_CANONNAME incluye probar si el miembro ai_canonname de la estructura addrinfoex asociada es NULL.
|
AI_NUMERICHOST | Cuando se establece el bit de AI_NUMERICHOST , el parámetro pName debe contener una cadena de dirección de host numérica que no sea NULL ; de lo contrario, se devuelve el error EAI_NONAME . Esta marca impide que se llame a un servicio de resolución de nombres. |
AI_NUMERICSERV |
Cuando se establece el bit de AI_NUMERICSERV , el parámetro pServiceName debe contener un número de puerto numérico distinto de NULL ; de lo contrario, se devuelve el error de EAI_NONAME . Esta marca impide que se llame a un servicio de resolución de nombres.
La marca AI_NUMERICSERV se define en Windows SDK para Windows Vista y versiones posteriores. Los proveedores de Microsoft no admiten la marca AI_NUMERICSERV . |
AI_ALL |
Si se establece el bit de AI_ALL , se realiza una solicitud para las direcciones IPv6 y las direcciones IPv4 con AI_V4MAPPED.
La marca AI_ALL se define en Windows SDK para Windows Vista y versiones posteriores. La marca AI_ALL se admite en Windows Vista y versiones posteriores. |
AI_ADDRCONFIG |
Si se establece el bit de AI_ADDRCONFIG , GetAddrInfoEx solo se resolverá si se configura una dirección global. Si se especifica AI_ADDRCONFIG marca, las direcciones IPv4 solo se devolverán si se configura una dirección IPv4 en el sistema local y las direcciones IPv6 solo se devolverán si se configura una dirección IPv6 en el sistema local. La dirección de bucle invertido IPv4 o IPv6 no se considera una dirección global válida.
La marca AI_ADDRCONFIG se define en Windows SDK para Windows Vista y versiones posteriores. La marca AI_ADDRCONFIG se admite en Windows Vista y versiones posteriores. |
AI_V4MAPPED |
Si se establece el bit de AI_V4MAPPED y se produce un error en una solicitud de direcciones IPv6, se realiza una solicitud de servicio de nombre para las direcciones IPv4 y estas direcciones se convierten en formato de dirección IPv6 asignado a IPv4.
La marca AI_V4MAPPED se define en Windows SDK para Windows Vista y versiones posteriores. La marca AI_V4MAPPED se admite en Windows Vista y versiones posteriores. |
AI_NON_AUTHORITATIVE |
Si se establece el bit de AI_NON_AUTHORITATIVE , el proveedor de espacio de nombres NS_EMAIL devuelve resultados autoritativos y no autoritativos. Si no se establece el bit de AI_NON_AUTHORITATIVE , el proveedor de espacio de nombres NS_EMAIL devuelve solo los resultados autoritativos.
La marca AI_NON_AUTHORITATIVE se define en Windows SDK para Windows Vista y versiones posteriores. La marca AI_NON_AUTHORITATIVE se admite en Windows Vista y versiones posteriores y solo se aplica al espacio de nombres NS_EMAIL . |
AI_SECURE |
Si se establece el bit de AI_SECURE , el proveedor de espacio de nombres NS_EMAIL devolverá los resultados obtenidos con seguridad mejorada para minimizar la posible suplantación de identidad.
La marca AI_SECURE se define en Windows SDK para Windows Vista y versiones posteriores. La marca AI_SECURE se admite en Windows Vista y versiones posteriores y solo se aplica al espacio de nombres NS_EMAIL . |
AI_RETURN_PREFERRED_NAMES |
Si se establece el AI_RETURN_PREFERRED_NAMES , no se debe proporcionar ningún nombre en el parámetro pName . El proveedor de espacio de nombres NS_EMAIL devolverá nombres preferidos para la publicación.
La marca AI_RETURN_PREFERRED_NAMES se define en Windows SDK para Windows Vista y versiones posteriores. La marca AI_RETURN_PREFERRED_NAMES se admite en Windows Vista y versiones posteriores y solo se aplica al espacio de nombres NS_EMAIL . |
AI_FQDN |
Si se establece el AI_FQDN y se especifica un nombre plano (etiqueta única), GetAddrInfoEx devolverá el nombre de dominio completo al que el nombre finalmente se resolvió. El nombre de dominio completo se devuelve en el miembro ai_canonname de la estructura addrinfoex asociada. Esto es diferente de AI_CANONNAME marca de bits que devuelve el nombre canónico registrado en DNS, que puede ser diferente del nombre de dominio completo al que se resolvió el nombre plano.
Cuando se establece el bit de AI_FQDN , el parámetro pName no puede ser NULL. De lo contrario, se producirá un error en la función GetAddrInfoEx con WSANO_RECOVERY. En Windows 8 y Windows Server 2012, se pueden establecer los bits de AI_FQDN y AI_CANONNAME . Si se llama a la función GetAddrInfoEx con los bits AI_FQDN y AI_CANONNAME , el parámetro ppResult devuelve un puntero a una estructura addrinfoex2 , no con una estructura addrinfoex . En Windows 7 y Windows Server 2008 R2, solo se puede establecer uno de los bits de AI_FQDN y AI_CANONNAME . Se producirá un error en la función GetAddrInfoEx si ambas marcas están presentes con EAI_BADFLAGS. Windows 7: La marca AI_FQDN se define en Windows SDK para Windows 7 y versiones posteriores. La marca AI_FQDN se admite en Windows 7 y versiones posteriores. |
AI_FILESERVER |
Si se establece el AI_FILESERVER , se trata de una sugerencia para el proveedor de espacios de nombres que se está consultando el nombre de host que se está consultando en el escenario del recurso compartido de archivos. El proveedor de espacios de nombres puede omitir esta sugerencia.
Windows 7: La marca AI_FILESERVER se define en Windows SDK para Windows 7 y versiones posteriores. La marca AI_FILESERVER se admite en Windows 7 y versiones posteriores. |
AI_DISABLE_IDN_ENCODING |
Si se establece el AI_DISABLE_IDN_ENCODING , se deshabilita la codificación automática de nombres de dominio internacionales mediante Punycode en las funciones de resolución de nombres a las que llama la función GetAddrInfoEx .
Windows 8: La marca AI_DISABLE_IDN_ENCODING se define en Windows SDK para Windows 8 y versiones posteriores. La marca AI_DISABLE_IDN_ENCODING se admite en Windows 8 y versiones posteriores. |
Nota
El encabezado ws2tcpip.h define GetAddrInfoEx como alias que selecciona automáticamente la versión ANSI o Unicode de esta función en función de la definición de la constante de preprocesador UNICODE. La combinación del uso del alias neutral de codificación con código que no es neutral de codificación puede dar lugar a errores de coincidencia que dan lugar a errores de compilación o tiempo de ejecución. Para obtener más información, vea Convenciones para prototipos de función.
Requisitos
Requisito | Value |
---|---|
Cliente mínimo compatible | Windows XP [aplicaciones de escritorio | aplicaciones para UWP] |
Servidor mínimo compatible | Windows Server 2008 [aplicaciones de escritorio | aplicaciones para UWP] |
Plataforma de destino | Windows |
Encabezado | ws2tcpip.h |
Library | Ws2_32.lib |
Archivo DLL | Ws2_32.dll |