Winsock2
and Internet Protocol 3
Part 3

What do we have in this chapter 3 part 3?

Program Example Using
AI_NUMERICHOST

Simple Address Conversion

WSAAddressToString()
and WSAStringToAddress() Program Examples

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(

conststruct 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:

NI_NOFQDN indicates that only the relative distinguished
name (RDN) returned. For example, with this flag set the host named “mist.microsoft.com”
would return only “mist”.

NI_NUMERICHOST indicates to return the string representation
of the address and not the hostname.

NI_NAMEREQD indicates if the address cannot be resolved
to a FQDN to return an error.

NI_NUMERICSERV indicates to return the port information
as a string instead of resolving to a well-known service name, such as “ftp.”
Note that if the serv buffer is supplied with this flag absent and the port
number cannot be resolved to a well-known service, genameinfo() will fail
with error WSANO_DATA (11004).

NI_DGRAM is used to differentiate datagram services from
stream services. This is necessary for those few services that define different
port numbers for UDP and TCP.

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

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.

Simple
Address Conversion

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.

WSAAddressToString()
and WSAStringToAddress() Program Examples

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.