< Name Resolution Routines | Internet Protocol Main | inetntop() & inetpton() >


 

Winsock2 and Internet Protocol 3 Part 3

 

What do we have in this chapter 3 part 3?

 

  1. Program Example Using AI_NUMERICHOST

  2. Simple Address Conversion

  3. 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.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: another new getaddrinfo() project

 

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 Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the getaddrinfo() sample outputs for IPv6 and IPv4 addresses

 

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:

 

  1. 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”.
  2. NI_NUMERICHOST indicates to return the string representation of the address and not the hostname.
  3. NI_NAMEREQD indicates if the address cannot be resolved to a FQDN to return an error.
  4. 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).
  5. 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.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: new getnameinfo() project creation

 

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 Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: a sample getnameinfo() 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.

 

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.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: new Win32 console project for WSAAddressToString() and WSAStringToAddress() functions

 

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 Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: a sample output for WSAAddressToString() and WSAStringToAddress() functions

 

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.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: another sample output for WSAAddressToString() and WSAStringToAddress() functions

 

 

 


< Name Resolution Routines | Internet Protocol Main | inetntop() & inetpton() >