< Program Examples | Internet Protocol Main | getprotobyname() & getprotobyport() >


 

Winsock2 and Internet Protocol 3 Part 4

 

What do we have in this chapter 3 part 4?

 

  1. The InetNtop()/inet_ntop()

  2. The InetPton()/inet_pton()

  3. Legacy Name Resolution Routines

 

The InetNtop()/inet_ntop()

 

The InetNtop() function converts an IPv4 or IPv6 Internet network address into a string in Internet standard format. The ANSI version of this function is inet_ntop(). The syntax is:

 

PCTSTR WSAAPI InetNtop(

                        INT  Family,

                        PVOID pAddr,

                        PTSTR pStringBuf,

                        size_t StringBufSize

);

 

The Family is the address family. The possible values for the address family are defined in the Ws2def.h header file. Note that the Ws2def.h header file is automatically included in Winsock2.h, and should never be used directly. Note that the values for the AF_ address family and PF_ protocol family constants are identical (for example, AF_INET and PF_INET), so either constant can be used. The values currently supported are AF_INET and AF_INET6.

 

Value

Meaning

AF_INET (2)

The Internet Protocol version 4 (IPv4) address family. When this parameter is specified, this function returns an IPv4 address string.

AF_INET6 (23)

The Internet Protocol version 6 (IPv6) address family. When this parameter is specified, this function returns an IPv6 address string.

 

The pAddr is a pointer to the IP address in network byte to convert to a string. When the Family parameter is AF_INET, then the pAddr parameter must point to an IN_ADDR structure with the IPv4 address to convert. When the Family parameter is AF_INET6, then the pAddr parameter must point to an IN6_ADDR structure with the IPv6 address to convert.

The third parameter, pStringBuf is a pointer to a buffer in which to store the NULL-terminated string representation of the IP address. For an IPv4 address, this buffer should be large enough to hold at least 16 characters and for an IPv6 address, this buffer should be large enough to hold at least 46 characters.

For the StringBufSize, on input, the length, in characters, of the buffer pointed to by the pStringBuf parameter while on output, this parameter contains the number of characters actually written to the buffer pointed to by the pStringBuf parameter.

If no error occurs, InetNtop function returns a pointer to a buffer containing the string representation of IP address in standard format. Otherwise, a value of NULL is returned, and a specific error code can be retrieved by calling the WSAGetLastError() for extended error information. If the function fails, the extended error code returned by WSAGetLastError() can be one of the following values.

 

Error code

Meaning

WSAEAFNOSUPPORT

The address family specified in the Family parameter is not supported. This error is returned if the Family parameter specified was not AF_INET or AF_INET6.

ERROR_INVALID_PARAMETER

An invalid parameter was passed to the function. This error is returned if a NULL pointer is passed in the pStringBuf or the StringBufSize parameter is zero. This error is also returned if the length of the buffer pointed to by the pStringBuf parameter is not large enough to receive the string representation of the IP address.

 

The InetNtop() function is supported on Windows Vista and later which provides a protocol-independent address-to-string translation. It takes an Internet address structure specified by the pAddr parameter and returns a NULL-terminated string that represents the IP address. While the inet_ntoa() function works only with IPv4 addresses, the InetNtop() function works with either IPv4 or IPv6 addresses.

The ANSI version of this function is inet_ntop() as defined in RFC 2553. The InetNtop() function does not require that the Windows Sockets DLL be loaded to perform IP address to string conversion. If the Family parameter specified is AF_INET, then the pAddr parameter must point to an IN_ADDR structure with the IPv4 address to convert. The address string returned in the buffer pointed to by the pStringBuf parameter is in dotted-decimal notation as in "192.168.16.0", an example of an IPv4 address in dotted-decimal notation. If the Family parameter specified is AF_INET6, then the pAddr parameter must point to an IN6_ADDR structure with the IPv6 address to convert. The address string returned in the buffer pointed to by the pStringBuf parameter is in Internet standard format. The basic string representation consists of 8 hexadecimal numbers separated by colons. A string of consecutive zero numbers is replaced with a double-colon. There can only be one double-colon in the string representation of the IPv6 address. The last 32 bits are represented in IPv4-style dotted-octet notation if the address is an IPv4-compatible address.

If the length of the buffer pointed to by the pStringBuf parameter is not large enough to receive the string representation of the IP address, InetNtop returns ERROR_INVALID_PARAMETER.

When UNICODE or _UNICODE is defined, InetNtop() is defined to InetNtopW(), the Unicode version of this function. The pStringBuf parameter is defined to the PSTR data type. When UNICODE or _UNICODE is not defined, InetNtop() is defined to InetNtopA(), the ANSI version of this function. The ANSI version of this function is always defined as inet_ntop(). The pStringBuf parameter is defined to the PWSTR data type.

The IN_ADDR structure is defined in the Inaddr.h header file. The IN6_ADDR structure is defined in the In6addr.h header file. On Windows Vista and later, the RtlIpv4AddressToString() and RtlIpv4AddressToStringEx() functions can be used to convert an IPv4 address represented as an IN_ADDR structure to a string representation of an IPv4 address in Internet standard dotted-decimal notation. Also for the similar Windows platform, the RtlIpv6AddressToString() and RtlIpv6AddressToStringEx() functions can be used to convert an IPv6 address represented as an IN6_ADDR structure to a string representation of an IPv6 address. The RtlIpv6AddressToStringEx() function is more flexible since it also converts an IPv6 address, scope ID, and port to a IPv6 string in standard format.

 

The InetPton()/inet_pton()

 

The InetPton() function converts an IPv4 or IPv6 Internet network address in its standard text presentation form into its numeric binary form. The ANSI version of this function is inet_pton(). The syntax is:

 

PCTSTR WSAAPI inet_pton(

  INT  Family,

  PCTSTR pszAddrString,

  PVOID pAddrBuf

);

 

The Family parameter is the address family. The possible values for the address family are defined in the Ws2def.h header file. Note that the Ws2def.h header file is automatically included in Winsock2.h, and should never be used directly. Note that the values for the AF_ address family and PF_ protocol family constants are identical (for example, AF_INET and PF_INET), so either constant can be used. The values currently supported are AF_INET and AF_INET6.

 

Value

Meaning

AF_INET (2)

The Internet Protocol version 4 (IPv4) address family. When this parameter is specified, the pszAddrString parameter must point to a text representation of an IPv4 address and the pAddrBuf parameter returns a pointer to an IN_ADDR structure that represents the IPv4 address.

AF_INET6 (23)

The Internet Protocol version 6 (IPv6) address family. When this parameter is specified, the pszAddrString parameter must point to a text representation of an IPv6 address and the pAddrBuf parameter returns a pointer to an IN6_ADDR structure that represents the IPv6 address.

 

The pszAddrString is a pointer to the NULL-terminated string that contains the text representation of the IP address to convert to numeric binary form. When the Family parameter is AF_INET, then the pszAddrString parameter must point to a text representation of an IPv6 address in standard notation. When the Family parameter is AF_INET6, then the pszAddrString parameter must point to a text representation of an IPv4 address in standard dotted-decimal notation.

The third parameter, pAddrBuf is a pointer to a buffer in which to store the numeric binary representation of the IP address. The IP address is returned in network byte order. When the Family parameter is AF_INET, this buffer should be large enough to hold an IN_ADDR structure.

When the Family parameter is AF_INET6, this buffer should be large enough to hold an IN6_ADDR structure.

If no error occurs, the InetPton() function returns a value of 1 and the buffer pointed to by the pAddrBuf parameter contains the binary numeric IP address in network byte order. The InetPton() function returns a value of 0 if the pAddrBuf parameter points to a string that is not a valid IPv4 dotted-decimal string or a valid IPv6 address string. Otherwise, a value of -1 is returned, and a specific error code can be retrieved by calling the WSAGetLastError() for extended error information. If the function has an error, the extended error code returned by WSAGetLastError() can be one of the following values.

 

Error code

Meaning

WSAEAFNOSUPPORT

The address family specified in the Family parameter is not supported. This error is returned if the Family parameter specified was not AF_INET or AF_INET6.

WSAEFAULT

The pszAddrString or pAddrBuf parameters are NULL or are not part of the user address space.

 

The InetPton() function is supported on Windows Vista and later which provides a protocol-independent conversion of an Internet network address in its standard text presentation form into its numeric binary form. The InetPton() function takes a text representation of an Internet address pointed to by the pszAddrString parameter and returns a pointer to the numeric binary IP address in the pAddrBuf parameter. While the inet_addr() function works only with IPv4 address strings, the InetPton function works with either IPv4 or IPv6 address strings. The ANSI version of this function is inet_pton() as defined in RFC 2553.

The InetPton() function does not require that the Windows Sockets DLL be loaded to perform conversion of a text string that represents an IP address to a numeric binary IP address. If the Family parameter specified is AF_INET, then the pszAddrString parameter must point a text string of an IPv4 address in dotted-decimal notation as in "192.168.16.0", an example of an IPv4 address in dotted-decimal notation.

If the Family parameter specified is AF_INET6, then the pszAddrString parameter must point a text string of an IPv6 address in Internet standard format. The basic string representation consists of 8 hexadecimal numbers separated by colons. A string of consecutive zero numbers may be replaced with a double-colon. There can only be one double-colon in the string representation of the IPv6 address. The last 32 bits may be represented in IPv4-style dotted-octet notation if the address is an IPv4-compatible address.

When UNICODE or _UNICODE is defined, InetPton() is defined to InetPtonW(), the Unicode version of this function. The pszAddrString parameter is defined to the PCWSTR data type. When UNICODE or _UNICODE is not defined, InetPton() is defined to InetPtonA(), the ANSI version of this function. The ANSI version of this function is always defined as inet_pton(). The pszAddrString parameter is defined to the PCSTR data type. The IN_ADDR structure is defined in the Inaddr.h header file. The IN6_ADDR structure is defined in the In6addr.h header file. The following code snippet shows a sample inet_pton() and inet_ntop() use. Take note that inet_pton() and inet_ntop() functions already available and used in BSD socket long time ago.

 

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdlib.h>

#include <stdio.h>

 

// Minimum system required are

// Windows Server 2008 or Windows Vista

// http://msdn.microsoft.com/en-us/library/aa383745.aspx

// #define _WIN32_WINNT 0x0600

 

int main(int argc, char *argv[])

{

            WSADATA wsaData;

 

            struct addrinfo hints, *res, *p;

            int status;

            // Provide big enough buffer, ipv6 should be the biggest

            char ipstr[INET6_ADDRSTRLEN];

            char ipstr2[INET6_ADDRSTRLEN];

 

            if (argc != 2)

            {

                        printf("Usage: %s <hostname>\n", argv[0]);

                        printf("Example: %s www.yahoo.com\n", argv[0]);

                        return 1;

            }

 

            // Initialization

            if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0)

            {

                        printf("WSAStartup() failed miserably! With error code %ld\n", WSAGetLastError());

                        return 1;

            }

            else

                        printf("WSAStartup() looks fine!\n");

 

            memset(&hints, 0, sizeof hints);

            hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version

            hints.ai_socktype = SOCK_STREAM;

 

            if ((status = getaddrinfo(argv[1], NULL, &hints, &res)) != 0)

            {

                        printf("getaddrinfo() failed lor! with error code %ld\n", WSAGetLastError());

                        WSACleanup();

                        return 1;

            }

 

            printf("The IP addresses for %s:\n", argv[1]);

 

            for(p = res;p != NULL; p = p->ai_next)

            {

                        void *addr;

                        char *ipver;

 

                        // Get the pointer to the address itself, different fields in IPv4 and IPv6

                        if (p->ai_family == AF_INET)

                        {

                                    // IPv4

                                    struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;

                                    addr = &(ipv4->sin_addr);

                                    ipver = "IPv4";

                        }

                        else

                        {

                                    // IPv6

                                    struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)p->ai_addr;

                                    addr = &(ipv6->sin6_addr);

                                    ipver = "IPv6";

                        }

 

                        // Convert the IP to a string and print it

                        printf("String format: ");

                        // InetNtop(address_family, IP_address_in_network_byte_to_convert_to_a_string,

                        //         buffer_to_store_the_IP_address_string, the_IP_string_length_in_character);

                        inet_ntop(p->ai_family, addr, (PSTR)ipstr, sizeof(ipstr));

                        printf(" %s: %s\n", ipver, ipstr);

 

                        printf("Value format: ");

                        // InetPton(address_family, string_to_be_converted, buffer_to_store_the_converted_string);

                        inet_pton(p->ai_family, (PCSTR)ipstr, ipstr2);

                        printf(" %s: %ul\n", ipver, ipstr2);

            }

 

            // Deallocate the resource...

            freeaddrinfo(res);

            // Cleanup the WSA...

            WSACleanup();

            return 0;

}

 

You can compile on the older Windows OS but target the minimum Windows Vista or Server 2008 to run this program. Running on the older platform will generate a message similar to the following crap:

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: The procedure entry point inet_ntop could not be located in the dynamic link library ws2_32.dll

 

Legacy Name Resolution Routines

 

This section covers the legacy name resolution and is included only for the sake of code maintenance, because new applications should be using getaddrinfo() and getnameinfo(). The other feature you will notice is that the two new API calls replace eight legacy functions.

The function inet_addr() converts a dotted IPv4 address to a 32-bit unsigned long integer quantity. The inet_addr() function is defined as:

 

unsigned long inet_addr(const char FAR *cp);

 

The cp field is a null-terminated character string that accepts an IP address in dotted notation. Note that this function returns an IPv4 address as a 32-bit unsigned long integer in network-byte order, which can be assigned into the SOCKADDR_IN field sin_addr. The reverse of inet_addr() is inet_ntoa(), which takes an IPv4 network address and converts it to a string. This function is declared as:

 

char FAR *inet_ntoa(Struct in_addr in);

 

The following code sample demonstrates how to create a SOCKADDR_IN structure using the inet_addr() and htons functions.

 

SOCKADDR_IN InternetAddr;

INT nPortId = 5150;

 

InternetAddr.sin_family = AF_INET;

 

// Convert the proposed dotted Internet address 136.149.3.29

// to a 4-byte integer, and assign it to sin_addr

InternetAddr.sin_addr.s_addr = inet_addr("136.149.3.29");

 

// The nPortId variable is stored in host-byte order. Convert

// nPortId to network-byte order, and assign it to sin_port.

InternetAddr.sin_port = htons(nPortId);

 

The following code example demonstrates the use of the inet_addr() and inet_ntoa() functions.

 

#include <winsock2.h>

#include <stdio.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

    int iResult;

    unsigned long ulAddr = INADDR_NONE;

    ULONG TempBuff = 0;

    struct sockaddr_in saSample;

 

    // Validate the parameters

    if (argc != 2)

    {

        printf("Usage: %s <IPv4 address>\n", argv[0]);

        printf("  inet_addr() converts a string containing an\n");

        printf("  IPv4 address in one of the supported formats\n");

        printf("  to a unsigned long representing an IN_ADDR\n");

                        printf("Example: %s 209.131.36.158\n", argv[0]);

        return 1;

    }

    // Initialize Winsock

    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);

    if (iResult != 0)

    {

        printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());

        return 1;

    }

 

    // Just for demonstration, call inet_addr(). If the call

    // succeeds, the result variable will hold a IN_ADDR structure

    ulAddr = inet_addr(argv[1]);

 

    if ( ulAddr == INADDR_NONE )

    {

        printf("inet_addr() failed and returned INADDR_NONE\n");

        WSACleanup();

        return 1;

    }

 

    if (ulAddr == INADDR_ANY) {

        printf("inet_addr() failed and returned INADDR_ANY\n");

        WSACleanup();

        return 1; 

    }

 

            printf("inet_addr() returned success!\n");

            // Retrieve address and print out the hex/dec/octal bytes

            printf("  Hex:\t\t0X%0X\n", ulAddr);

            printf("  Decimal:\t%ul\n", ulAddr);

            printf("  Octal:\t0%o\n", ulAddr);

 

            // Then, ready to be used

            saSample.sin_family = AF_INET;

            // In typical app. we can be directly use:

            // usesaSample.sin_addr.s_addr = inet_addr(argv[1]);

            saSample.sin_addr.s_addr = ulAddr;

            saSample.sin_port = htons(1234);

 

            // More codes here, create socket, bind, connect etc.

 

            // Revert the process using inet_ntoa() just for the address part

            if(inet_ntoa(saSample.sin_addr) != NULL)

            {

                        printf("inet_ntoa() return success!\n");

                        printf("The IP address is %s\n", inet_ntoa(saSample.sin_addr));

            }

            else

                        printf("inet_ntoa() failed with error code %ld\n", WSAGetLastError());

 

    WSACleanup();

    return 0;

}

 

Build and run the project. The following screenshot shows a sample output.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the inet_addr() and inet_ntoa() functions sample program output

 

The Winsock functions gethostbyname(), WSAAsyncGetHostByName(), gethostbyaddr(), and WSAAsyncGetHostByAddr() retrieve host information corresponding to a host name or host address from a host database. The first two functions translate a hostname to its network IPv4 addresses and the second two do the reverse - map an IPv4 network address back to a hostname. These functions return a HOSTENT structure that is defined as:

 

struct hostent

{

    char FAR *       h_name;

    char FAR * FAR * h_aliases;

    short            h_addrtype;

    short            h_length;

    char FAR * FAR * h_addr_list;

};

 

The h_name field is the official name of the host. If your network uses the DNS, it is the FQDN that causes the name server to return a reply. If your network uses a local “hosts” file, it is the first entry after the IP address. The h_aliases field is a null-terminated array of alternative names for the host. The h_addrtype represents the address family being returned. The h_length field defines the length in bytes of each address in the h_addr_list field, which will be four bytes for IPv4 addresses. The h_addr_list field is a null-terminated array of IP addresses for the host. (A host can have more than one IP address assigned to it.) Each address in the array is returned in network-byte order.

Normally, applications use the first address in the array. However, if more than one address is returned, applications should randomly choose an available address rather than always use the first address. The prototypes for these functions are:

 

struct hostent FAR * gethostbyname (const char FAR * name);

HANDLE WSAAsyncGetHostByName(

    HWND hWnd,

    unsigned int wMsg,

    const char FAR * name,

    char FAR * buf,

    int buflen

);

 

struct HOSTENT FAR * gethostbyaddr(

    const char FAR * addr,

    int len,

    int type

);

 

HANDLE WSAAsyncGetHostByAddr(

                        HWND hWnd,

                        unsigned int wMsg,

                        const char FAR *addr,

                        int len,

                        int type,

                        char FAR *buf,

                        int buflen

);

 

Take note that gethostbyname() and gethostbyaddr() functions considered deprecated, instead use getaddrinfo() function to provide smooth transition to IPv6 compatibility

For the first two functions, the name parameter represents a friendly name of the host you are looking for, and the latter two functions take an IPv4 network address in the addr parameter. The length of the address is specified as len. Also, type indicates the address family of the network address passed, which would be AF_INET. All four functions return the results via a HOSTENT structure. For the two synchronous functions, the HOSTENT is a system-allocated buffer that the application should not rely on being static. The two asynchronous functions will copy the HOSTENT structure to the buffer indicated by the buf parameter. This buffer size should be equal to MAXGETHOSTSTRUCT.

Finally, these and the rest of the asynchronous name and service resolution functions return a HANDLE identifying the operation issued. Upon completion, a window message indicated by wMsg is posted to the window given by hWnd. If at some point the application wishes to cancel the asynchronous request, the WSACancelAsyncRequest() function is used. This function is declared as:

 

int WSACancelAsyncRequest(HANDLE hAsyncTaskHandle);

 

Keep in mind that the synchronous API calls will block until the query completes or times out, which could take several seconds. The following program example demonstrates the use of gethostbyname() and gethostbyaddr() functions.

 

#include <winsock2.h>

#include <ws2tcpip.h>

#include <stdio.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

    DWORD dwError;

    int i = 0;

    struct hostent *remoteHost;

    char *host_name;

    struct in_addr addr;

    char **pAlias;

 

    // Validate the parameters

    if (argc != 2)

    {

        printf("Usage: %s <ipv4address> or <hostname>\n", argv[0]);

        printf("Example: %s 127.0.0.1\n", argv[0]);

        printf("  to return the host\n");

        printf("Example: %s www.palerbutuh.com\n", argv[0]);

        printf("  to return the IP addresses for a host\n");

        return 1;

    }

 

    // Initialize Winsock

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)

    {

        printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());

        return 1;

    }

    else

        printf("WSAStartup() looks fine!\n");

 

            host_name = argv[1];

            // If the user input is an alpha name for the host, use gethostbyname()

            // If not, gethostbyaddr()

            // We are assuming the IPv4 here

            if (isalpha(host_name[0]))    // host address is a name instead og IP

            {

                        printf("Calling gethostbyname() with %s\n", host_name);

                        remoteHost = gethostbyname(host_name);

            }

            else

            {

                        // host address is an IP

                        printf("Calling gethostbyaddr() with %s\n", host_name);

                        addr.s_addr = inet_addr(host_name);

                        if (addr.s_addr == INADDR_NONE)

                        {

                                    printf("The IPv4 address entered must be a legal address!\n");

                                    WSACleanup();

                                    return 1;

                        }

                        else

                        {

                                    // gethostbyaddr() is OK

                                    // Should provide both the Ipv6 and IPv4. Just IPv4 shown here

                                    remoteHost = gethostbyaddr((char *) &addr, 4, AF_INET);

                        }

    }

 

    if (remoteHost == NULL)

    {

                        dwError = WSAGetLastError();

                        if (dwError != 0)

                        {

                                    if (dwError == WSAHOST_NOT_FOUND)

                                    {

                                                printf("Host not found!\n");

                                                WSACleanup();

                                                return 1;

                                    }

                                    else if (dwError == WSANO_DATA)

                                    {

                                                printf("No data record found!\n");

                                                WSACleanup();

                                                return 1;

                                    }

                                    else

                                    {

                                            printf("Function failed with error code %ld\n", dwError);

                                            WSACleanup();

                                            return 1;

                                    }

                         }

    }

    else

    {

        printf("Function returned successfully!\n");

        printf("\tOfficial name: %s\n", remoteHost->h_name);

        // Extract all the cname/aliases if any

        for (pAlias = remoteHost->h_aliases; *pAlias != 0; pAlias++)

        {

            printf("\tAlternate name (if any) #%d: %s\n", ++i, *pAlias);

        }

 

                        // Check the address family type

                        printf("\tAddress type: ");

                        switch (remoteHost->h_addrtype)

                        {

                        case AF_INET:

                                    printf("AF_INET family\n");

                                    break;

                        case AF_INET6:

                                    printf("AF_INET6 family\n");

                                    break;

                        case AF_NETBIOS:

                                    printf("AF_NETBIOS - Windows NetBIOS\n");

                                    break;

                        default:

                                    printf(" %d\n", remoteHost->h_addrtype);

                                    break;

                        }

                        // Check the address family type

                        printf("\tAddress length: %d\n", remoteHost->h_length);

                        // Traverse the hostent address list and print the IP address(s)

                        i = 0; // Reset counter

                        while (remoteHost->h_addr_list[i] != 0)

                        {

                                    addr.s_addr = *(u_long *)remoteHost->h_addr_list[i++];

                                    printf("\tIP Address #%d: %s\n", i, inet_ntoa(addr));

                         }

    }

            WSACleanup();

    return 0;

}

 

The following screenshots show sample outputs using IPv4 and IPv6 addresses as the arguments.

 

---------------------------------------------------

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the gethostbyname() and gethostbyaddr() functions sample program output

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the gethostbyname() and gethostbyaddr() functions sample program output with IPv6 argument

 

The next type of legacy resolution functions provide the capability to retrieve port numbers for well-known services and the reverse. The API functions getservbyname() and WSAAsyncGetServByName() take the name of a well-known service like “FTP” and return the port number that the service uses. The functions getservbyport() and WSAAsyncGetServByPort() perform the reverse operation by taking the port number and returning the service name that uses that port. These functions simply retrieve static information from a file named services. In Windows 95, Windows 98, and Windows Me, the services file is located under %WINDOWS%; in Windows NT, it is located under %WINDOWS%\System32\drivers\etc. These four functions return the service information in a SERVENT structure that is defined as:

 

struct servent {

                        char FAR *        s_name;

                        char FAR * FAR *s_aliases;

                        short                   s_port;

                        char FAR *        s_proto

};

 

The field s_name is the name of the service and s_aliases is a NULL terminated array of string pointers, each containing another name for the service. s_port is the port number used by the service and s_proto is the protocol used by the service, such as the strings “tcp” and “udp.” These functions are defined as follows:

 

struct servent FAR * getservbyname(

    const char FAR * name,

    const char FAR * proto

);

 

HANDLE WSAAsyncGetServByName(

                        HWND hWnd,

                        unsigned int wMsg,

                        const char FAR *name,

                        const char FAR *proto,

                        char FAR *buf,

                        int buflen

);

 

struct servent FAR *getservbyport(

                        int port,

                        const char FAR *proto

);

 

HANDLE WSAAsyncGetServByPort(

                        HWND hWnd,

                        unsigned int wMsg,

                        int port,

                        const char FAR *proto,

                        char FAR *buf,

                        int buflen

);

 

The name parameter represents the name of the service you are looking for. The proto parameter optionally points to a string that indicates the protocol that the service in name is registered under, such as “tcp” or “udp”. The second two functions simply take the port number to match to a service name. The synchronous API functions return a SERVENT structure, which is a system allocated buffer, and the asynchronous ones take an application supplied buffer, which should also be of the size MAXGETHOSTSTRUCT.

The last set of legacy name resolution API functions convert between a protocol string name, such as “tcp”, and its protocol number (“tcp” would resolve to IPPROTO_TCP.). These functions are getprotobyname(), WSAAsyncGetProtoByName(), getprotobynumber(), and WSAAsyncGetProtoByNumber(). The first two convert from the string protocol to the protocol number and the latter two do the opposite, map the protocol number back to its string name. These functions return a PROTOENT structure defined as:

 

struct protoent {

                        char FAR *        p_name;

                        char FAR * FAR *p_aliases;

                        short                   p_proto;

};

 

The first field, p_name, is the string name of the protocol, and p_aliases is a NULL terminated array of string pointers that contain other names the protocol is known by. Finally, p_proto is the protocol number (such as IPPROTO_UDP or IPPROTO_TCP). These function prototypes are:

 

struct protoent FAR *getprotobyname(const char FAR *name);

 

HANDLE WSAAsyncGetProtoByName(

                        HWND hWnd,

                        unsigned int wMsg,

                        const char FAR *name,

                        char FAR *buf,

                        int buflen

);

 

struct protoent FAR *getprotobynumber(int number);

 

HANDLE WSAAsyncGetProtoByNumber(

                        HWND hWnd,

                        unsigned int wMsg,

                        int number,

                        char FAR *buf,

                        int buflen

);

 

 

These functions behave the same way the legacy name resolution functions do described earlier in terms of synchronous and asynchronous functions. The following example demonstrates the use of getservbyname() function.

 

#include <winsock2.h>

#include <stdio.h>

#include <string.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

    char node_name[100] = "";

    struct hostent *hostptr;

    struct servent *servptr;

    // http://www.iana.org/assignments/port-numbers

    char services[12][10] = {"http", "ftp", "ssh", "telnet", "imap4", "smtp", "gopher", "finger", "pop3", "tftp", "mysql"};

    int i;

 

    // Validate the parameters

    if (argc != 2)

    {

        printf("Usage: %s <host_name>\n", argv[0]);

        printf("Example: %s www.yahoo.com\n", argv[0]);

        // Just return with error

        return 1;

    }

 

    // Initialize Winsock

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)

    {

        printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());

        return 1;

    }

    else

        printf("WSAStartup() looks fine!\n");

 

            strcpy_s(node_name, sizeof(node_name), argv[1]);

            // Here, name of server computer is expected, better to add

            // the server IP address functionality...

            hostptr = gethostbyname(node_name);

 

            if (hostptr == NULL)

            {

                        printf("gethostbyname() failed with error code %ld\n", WSAGetLastError());

             }

            else

                        printf("gethostbyname() is OK.\n Host name is %s\n", hostptr->h_name);

 

            for(i=0; i <= 10;i++)

            {

                        // The proto pointer is NULL, the getservbyname() will returns

                        // the first service entry where name matches the s_name member

                        // of the servent struct or the s_aliases member of the servent struct.

                        servptr = getservbyname(services[i], NULL);

                       

                        if (servptr == NULL)

                                    printf ("\ngetservbyname() - %s failed with error code %ld\n", services[i], WSAGetLastError());

                        else

                        {

                                    // Print the related info

                                    printf("\ngetservbyname() is OK - %s\n", services[i]);

                                    printf(" Service name is %s\n", servptr->s_name);

                                    // Need to cast to host-byte order

                                    printf(" Port number is %u\n", ntohs(servptr->s_port));

                                    printf(" Protocol is %s\n", servptr->s_proto);

                        }

            }

            WSACleanup();

    return 0;

}

 

Build and run the project. The following screenshot shows a sample output.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the getservbyname() sample program output

 

The 11004 error code is WSANO_DATA which is defined as “Valid name, no data record of requested type.” This error possibly indicates the requested name is valid and was found in the database, but it does not have the correct associated data being resolved for. In this example case, it is normal. The following example demonstrates the use of getservbyport() function.

 

#include <winsock2.h>

#include <stdio.h>

#include <string.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

    char node_name[100] = "";

    struct hostent *hostptr;

    struct servent *servptr;

    // http://www.iana.org/assignments/port-numbers

    int services[12] = {23, 80, 25, 21, 53, 69, 110, 143, 70, 7, 13};

    int i;

 

    // Validate the parameters

    if (argc != 2)

    {

        printf("Usage: %s <host_name>\n", argv[0]);

        printf("Example: %s www.yahoo.com\n", argv[0]);

        // Just return with error

        return 1;

    }

 

    // Initialize Winsock

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)

    {

        printf("WSAStartup() failed with error code %ld\n", WSAGetLastError());

        return 1;

    }

    else

        printf("WSAStartup() looks fine!\n");

 

            strcpy_s(node_name, sizeof(node_name), argv[1]);

            // Here, name of server computer is expected, it is better

            // to add the server IP address functionality...

            hostptr = gethostbyname(node_name);

 

            if (hostptr == NULL)

            {

                        printf("gethostbyname() failed with error code %ld\n", WSAGetLastError());

            }

            else

                        printf("gethostbyname() is OK.\n Host name is %s\n", hostptr->h_name);

 

            for(i=0; i <= 10;i++)

            {

                        // If this is null, getservbyport returns the first service

                        // entry for which the port matches the s_port of the servent structure.

                        servptr = getservbyport(ntohs(services[i]), NULL);

 

                        if (servptr == NULL)

                                    printf ("\ngetservbyport() - %d failed with error code %ld\n", services[i], WSAGetLastError());

                        else

                        {

                                    // Print the related info

                                    printf("\ngetservbyport() is OK - %d\n", services[i]);

                                    printf(" Service name is %s\n", servptr->s_name);

                                    // Need to cast to host-byte order

                                    printf(" Port number is %u\n", ntohs(servptr->s_port));

                                    printf(" Protocol is %s\n", servptr->s_proto);

                        }

            }

            WSACleanup();

    return 0;

}

 

Build and run the project. The following screenshot shows a sample output.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the getservbyport() function sample program output

 

 

 


< Program Examples | Internet Protocol Main | getprotobyname() & getprotobyport() >