< Name Resolution Routines | Internet Protocol Main | inetntop() & inetpton() >
What do we have in this chapter 3 part 3?
|
Program Example Using AI_NUMERICHOST
The following code example shows how to use the getaddrinfo() function to convert a text string representation of an IP address to an addrinfo structure that contains a sockaddr structure for the IP address and other information. Create a new empty Win32 console mode application and add the project/solution name.
|
Add the following code.
// link with Ws2_32.lib
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
int main(int argc, char **argv)
{
// Declare and initialize variables
WSADATA wsaData;
int iResult;
DWORD dwRetval;
int i = 1;
struct addrinfo *result = NULL;
struct addrinfo *ptr = NULL;
struct addrinfo hints;
// Validate the parameters
if (argc != 2) {
printf("Usage: %s <IP Address String>\n", argv[0]);
printf(" getaddrinfo() determines the IP binary network address\n");
printf("Example: %s 206.190.60.37\n", argv[0]);
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup() failed with error code %d\n", iResult);
return 1;
}
printf("WSAStartup() looks OK!\n");
// Setup the hints address info structure which is passed to the getaddrinfo() function
ZeroMemory( &hints, sizeof(hints) );
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = AF_UNSPEC;
// Call getaddrinfo(). If the call succeeds,
// the result variable will hold a linked list
// of addrinfo structures containing response information
dwRetval = getaddrinfo(argv[1], NULL, &hints, &result);
if ( dwRetval != 0 )
{
printf("getaddrinfo failed with error: %d\n", dwRetval);
WSACleanup();
return 1;
}
printf("getaddrinfo() returned success!\n");
// Retrieve each address and print out the hex bytes
for(ptr=result; ptr != NULL ;ptr=ptr->ai_next)
{
printf("getaddrinfo() response %d\n", i++);
printf("\tFlags: 0x%x\n", ptr->ai_flags);
printf("\tFamily: ");
switch (ptr->ai_family)
{
case AF_UNSPEC:
printf("Unspecified\n");
break;
case AF_INET:
printf("AF_INET (IPv4)\n");
break;
case AF_INET6:
printf("AF_INET6 (IPv6)\n");
break;
case AF_NETBIOS:
printf("AF_NETBIOS (NetBIOS)\n");
break;
default:
printf("Other %ld\n", ptr->ai_family);
break;
}
printf("\tSocket type: ");
switch (ptr->ai_socktype)
{
case 0:
printf("Unspecified\n");
break;
case SOCK_STREAM:
printf("SOCK_STREAM (stream)\n");
break;
case SOCK_DGRAM:
printf("SOCK_DGRAM (datagram) \n");
break;
case SOCK_RAW:
printf("SOCK_RAW (raw) \n");
break;
case SOCK_RDM:
printf("SOCK_RDM (reliable message datagram)\n");
break;
case SOCK_SEQPACKET:
printf("SOCK_SEQPACKET (pseudo-stream packet)\n");
break;
default:
printf("Other %ld\n", ptr->ai_socktype);
break;
}
printf("\tProtocol: ");
switch (ptr->ai_protocol)
{
case 0:
printf("Unspecified\n");
break;
case IPPROTO_TCP:
printf("IPPROTO_TCP (TCP)\n");
break;
case IPPROTO_UDP:
printf("IPPROTO_UDP (UDP) \n");
break;
default:
printf("Other %ld\n", ptr->ai_protocol);
break;
}
printf("\tLength of this sockaddr: %d\n", ptr->ai_addrlen);
printf("\tCanonical name: %s\n", ptr->ai_canonname);
}
// Release the allocated resource
freeaddrinfo(result);
// WSA clean up
WSACleanup();
return 0;
}
The following screenshot shows a sample output.
The other new name resolution API is getnameinfo(), which performs the reverse of the getaddrinfo() function. It takes a socket address structure already initialized and returns the host and service name corresponding to the address and port information. The getnameinfo() function is prototyped as the following:
int getnameinfo(
const struct sockaddr FAR *sa,
socklen_t salen,
char FAR *host,
DWORD hostlen,
char FAR *serv,
DWORD servlen,
int flags
);
The parameters are fairly self-explanatory. sa is the socket address structure on which the name information will be obtained for and salen is the size of that structure. host is the character buffer to receive the host's name. By default, the fully qualified domain name (FQDN) will be returned. hostlen simply indicates the size of the host buffer. serv is the character buffer to receive the service/port information and servlen is the length of that buffer. Finally, the flags parameter indicates how the socket address should be resolved. The possible flag values are the following:
The following code example shows how to use the getnameinfo() function. Create a new empty Win32 console mode application and add the project/solution name.
Add the following code.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
int main(int argc, char **argv)
{
// Declare and initialize variables
WSADATA wsaData;
int iResult;
DWORD dwRetval;
struct sockaddr_in saGNI;
char hostname[NI_MAXHOST]; // Set to the max value
char servInfo[NI_MAXSERV]; // Set to the max value
// Assume we plan to use TCP port 7777
u_short port = 7777;
// Validate the parameters
if (argc != 2)
{
printf("Usage: %s <IPv4 address>\n", argv[0]);
printf(" This program return hostname\n");
printf("Example: %s 127.0.0.1\n", argv[0]);
return 1;
}
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup() failed with error code %d\n", iResult);
return 1;
}
printf("WSAStartup() looks OK...\n");
// Set up sockaddr_in structure which is passed to the getnameinfo function
saGNI.sin_family = AF_INET; // AF_INET6
saGNI.sin_addr.s_addr = inet_addr(argv[1]);
saGNI.sin_port = htons(port);
// Call getnameinfo()
dwRetval = getnameinfo((struct sockaddr *) &saGNI,
sizeof (struct sockaddr),
hostname,
NI_MAXHOST, servInfo,
NI_MAXSERV, NI_NUMERICSERV);
if (dwRetval != 0)
{
printf("getnameinfo() failed with error code %ld\n", WSAGetLastError());
}
else
{
printf("getnameinfo() returned hostname \"%s\"\n", hostname);
}
// Terminate the use of Winsock
WSACleanup();
if (dwRetval != 0)
return 1;
else
return 0;
}
The following screenshot shows a sample output.
----------------------------------------------------------
The getnameinfoW() function is the Unicode version of getnameinfo(). The getnameinfoW() function was added to the Ws2_32.dll in Windows XP with SP2 and function cannot be used on versions of Windows earlier than Windows XP with SP2.
getaddrinfo() and getnameinfo() are address independent variant that hides the detail in name-to-address translation, or vice versa. It implements functionalities for the following functions: gethostbyname(), gethostbyaddr(), inet_ntop(), inet_pton(), getservbyname(), getservbyport() and many more.
The rfc2553 has proposed the struct sockaddr_storage which is a placeholder for all sockaddr-variant structures. This RFC has been adopted by implementers including Microsoft. The SOCKADDR structure is large enough to contain a transport address for most address families. For a structure that is guaranteed to be large enough to contain a transport address for all possible address families. This is implemented like follows:
struct sockaddr_storage {
short ss_family;
char __ss_pad1[_SS_PAD1SIZE];
__int64 __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
};
You should use this structure to hold any of sockaddr-variant structures.
When an application needs only to convert between string literal addresses and socket address structures, the WSAStringToAddress() and WSAAddressToString() helper APIs are available. WSAStringToAddress() is not as “smart” as getaddrinfo() because you must specify the address family that the string address belongs to. The API syntax is:
INT WSAStringToAddress(
LPTSTR AddressString,
INT AddressFamily,
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPSOCKADDR lpAddress,
LPINT lpAddressLength
);
The first parameter is the string to convert and the second indicates the address family the string belongs to (such as AF_INET, AF_INET6, or AF_IPX). The third parameter, lpProtocolInfo, is an optional pointer to the WSAPROTOCOL_INFO structure that defines the protocol provider to use when performing the conversion. If there are multiple providers implementing a protocol, this parameter can be used to specify an explicit provider. The fourth parameter is the appropriate socket address structure to which the string address will be converted and assigned into.
Note that this API will convert string addresses that contain port numbers. For example, the IPv4 string notation allows a colon followed by the port number at the end of the address. For example, “157.54.126.42:1200” indicates the IPv4 address using port 1200. In IPv6, the IPv6 address string must be enclosed in square brackets after which the colon and port notation may be used. For example, [fe80::250:8bff:fea0:92ed%5]:80 indicates a link-local address with its scope ID followed by port 80. Note that only port numbers will be resolved and not service names (such as “ftp”). For both these examples, if these strings were converted with WSAStringToAddress(), then the returned socket address structure will be initialized with the appropriate binary IP address, port number, and address family. For IPv6, the scope ID field will also be initialized if the string address contains “%scope_ID” after the address portion. The WSAAddressToString() provides a mapping from a socket address structure to a string representation of that address. The prototype is:
INT WSAAddressToString(
LPSOCKADDR lpsaAddress,
DWORD dwAddressLength,
LPWSAPROTOCOL_INFO lpProtocolInfo,
LPTSTR lpszAddressString,
LPDWORD lpdwAddressStringLength
);
This function takes a SOCKADDR structure and formats the binary address to a string indicated by the buffer lpszAddressString. Again, if there is more than one transport provider for a given protocol, a specific one may be selected by passing its WSAPROTOCOL_INFO structure as lpProtocolInfo. Note that the address family is a field of the SOCKADDR structure passed as lpsaAddress. Support for IPv6 addresses using the WSAAddressToString() function was added on Windows XP with Service Pack 1 (SP1) and later. IPv6 must also be installed on the local computer for the WSAAddressToString() function to support IPv6 addresses. While the inet_ntoa() function works only with IPv4 addresses, the WSAAddressToString() function works with any socket address supported by a Winsock provider on the local computer including IPv6 addresses.
The following program example tries to demonstrate the use of WSAAddressToString() and WSAStringToAddress() functions. Create a new empty Win32 console mode application and add the project/solution name.
Add the following code.
// All in wide character/Unicode and IPv6
// Uninitialized socket parameters will be assigned the
// default values. The comment parts are for IPv4
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
int main(int argc, char **argv)
{
WSADATA wsaData;
int iResult, RetVal, RetVal2;
// SOCKADDR_IN MyAddr;
SOCKADDR_IN6 MyAddrValue;
// Storage buffer, using LPWSTR pointer failed lor!
// WCHAR MyAddrString[256] = L"For IPv4...";
WCHAR MyAddrString[256] = L"Some dummy initializer";
// Take note that if the address is in FQDN/Name/hostname
// we need to convert it to a dotted IP address. For example:
// WCHAR IPAddr[256] = L"localhost"; // this should fail lor!
// WCHAR IPAddr[256] = L"209.131.36.158";
WCHAR IPAddr[256] = L"2a01:48:1:0:2e0:81ff:fe05:4658";
// These buffer sizes must be allocated properly else
// the WSAStringToAddress() and WSAAddressToString() will
// fail miserably!
// int MyAddrSize = sizeof(struct sockaddr_storage);
int MyAddrSize = sizeof(struct sockaddr_storage);
// DWORD MyAddrSize2 = sizeof(struct sockaddr_storage);
DWORD MyAddrSize2 = sizeof(struct sockaddr_storage);
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup() failed with error code %d\n", WSAGetLastError());
// Exit with error
return 1;
}
else
printf("WSAStartup() is OK...\n");
// Initialize the address family
// MyAddrValue.sin_family = AF_INET;
MyAddrValue.sin6_family = AF_INET6;
// This part should convert the server/hostname/FQDN to a standard dotted IP address
// string first (if any) using other helper functions such as getaddressinfo()
// ==============Convert address string to value using WSAStringToAddress()==============
printf("\nWSAStringToAddress() - string to address value\n");
RetVal = WSAStringToAddress(
IPAddr, // Pointer to address string to be converted
AF_INET6 /* AF_INET*/, // address family
NULL, // Protocol info structure, not useable here
(LPSOCKADDR)&MyAddrValue, // Socket address string buffer [out]
&MyAddrSize // Length of socket structure
);
// Something wrong
if( RetVal != 0)
{
printf("WSAStringToAddress() failed with error code %ld\n", WSAGetLastError());
// Clean-up
WSACleanup();
// Exit with error
return 1;
}
else
printf("WSAStringToAddress() looks fine! Return value is %ld\n", RetVal);
// printf("The IP Address part of the buffer filled with %ul\n", MyAddr.sin_addr);
printf("The IP address value is %ul\n", MyAddrValue.sin6_addr);
// and other info
printf("The address family value is %ul\n", MyAddrValue.sin6_family);
printf("The port value is %ul\n", MyAddrValue.sin6_port);
printf("The scopeID is %ul\n", MyAddrValue.sin6_scope_id);
// =========Do the re-conversion using WSAAddressToString()===============
printf("\nWSAAddressToString() - address value to string\n");
RetVal2 = WSAAddressToString(
(LPSOCKADDR)&MyAddrValue, // Pointer to address value to be converted
MyAddrSize, // Length of pointer to address value, in bytes
NULL, // A pointer to the WSAPROTOCOL_INFO structure for a particular provider
MyAddrString, // A pointer to the buffer that receives the human-readable address string
&MyAddrSize2 // length of the buffer pointed to by the MyAddrString parameter
);
// Something wrong
if( RetVal2 != 0)
{
printf("WSAAddressToString() failed with error code %ld\n", WSAGetLastError());
// Clean-up
WSACleanup();
// Exit with error
return 1;
}
else
printf("WSAAddressToString() looks fine! Return value is %ld\n", RetVal2);
// printf("The IP Address is %ul\n", MyAddr.sin_addr);
printf("The address string is %S\n", MyAddrString);
// and other info
printf("The address family is %ul\n", MyAddrValue.sin6_family);
printf("The port value is %ul\n", MyAddrValue.sin6_port);
printf("The scopeID is %ul\n", MyAddrValue.sin6_scope_id);
// Call WSACleanup for WSA* cleanup
if(WSACleanup() != 0)
printf("\nWSACleanup() failed!...\n");
else
printf("\nWSACleanup() is OK...\n");
return 0;
}
Build and run the project. The following screenshot shows a sample output.
The following is another simple example for WSAAddressToString() and WSAStringToAddress() functions.
#include <winsock2.h>
#include <stdio.h>
int main(void)
{
WSADATA wsaData;
SOCKADDR_IN addr;
char AddrValue[256] = "216.239.61.104";
char AddrString[256] = "Some dummy value";
DWORD dwSizeOfStr = sizeof(AddrValue);
int nSizeOfInput = sizeof(AddrString), iResult;
// Initialize Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (iResult != 0)
{
printf("WSAStartup() failed with error code %d\n", WSAGetLastError());
// Exit with error
return 1;
}
else
printf("WSAStartup() is OK...\n");
// Initialize address family
addr.sin_family = AF_INET;
if(WSAStringToAddressA(AddrValue, AF_INET, NULL, (LPSOCKADDR)&addr, &nSizeOfInput) != 0)
{
printf("\nWSAStringToAddressA failed with error num %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
else
{
printf("\nAddress in value = %ul\n", addr.sin_addr);
}
if(WSAAddressToStringA((LPSOCKADDR)&addr, sizeof(addr), NULL, AddrString, &dwSizeOfStr) != 0)
{
printf("WSAAddressToStringA() failed miserably with error code %ld\n", WSAGetLastError());
WSACleanup();
return 1;
}
else
printf("Address string = %s\n", AddrString);
// Do the WSACleanup...
if(WSACleanup() != 0)
printf("\nWSACleanup() failed!...\n");
else
printf("\nWSACleanup() is OK...\n");
return 0;
}
Build and run the project. The following screenshot shows a sample output.
< Name Resolution Routines | Internet Protocol Main | inetntop() & inetpton() >