< inetntop() & inetpton() | Internet Protocol Main | IPv4 & IPv6 Server Examples >


 

Winsock2 and Internet Protocol 3 Part 5

 

What do we have in this chapter 3 part 5?

 

  1. The getprotobyname() Program Example

  2. The getprotobyport() Program Example

  3. Writing IP Version–Independent Program Example

  4. The Client Example

 

The getprotobyname() Program Example

 

The following program example tries to demonstrate the getprotobyname() function. Create a new empty Win32 console mode application and add the project/solution name.

 

#include <winsock2.h>

#include <stdio.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

    struct protoent *servptr;

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

    char protocol[12][10] = {"ip","icmp","ggp","tcp", "egp","pup","udp","hmp","xns-idp", "rdp","rvd" };

    int i;

 

    // 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");

 

            // Traverse the array content...

            // Be careful with the array index...

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

            {

                        servptr = getprotobyname(protocol[i]);

                       

                        if (servptr == NULL)

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

                        else

                        {

                                    // Print the related info

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

                                    printf(" Official name is %s\n", servptr->p_name);

                                    printf(" Protocol number is %d\n", servptr->p_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 getprotobyname() sample program output

 

The getprotobyport() Program Example

 

The following program example tries to demonstrate the getprotobyport() function.

 

#include <winsock2.h>

#include <stdio.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

    struct protoent *servptr;

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

    // A sample of protocol numbers

    int protocol[12] = {1,2,3,11,30,20,22,27,8,17,12};

    int i;

 

    // 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");

 

            // Traverse the array content...

            // Be careful with the array index...

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

            {

                        servptr = getprotobynumber(protocol[i]);

 

                        if (servptr == NULL)

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

                        else

                        {

                                    // Print the related info

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

                                    printf(" Official name is %s\n", servptr->p_name);

                                    printf(" Protocol number is %d\n", servptr->p_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 getprotobyport() sample program output

 

As discussed previously, if you are curious where those protocol names and numbers are extracted in the local system, the files containing the information are under the %system32/driver/etc folder (Windows XP Pro SP2). You can open those files in text editor.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the protocol and services files which contain the protocol to service/port mapping and etc.

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the services file content

 

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the protocol file content

 

Writing IP Version–Independent Program Example

 

In this section, we'll cover how to develop applications that work seamlessly over IPv4 and IPv6. This method requires using the new name resolution APIs getaddrinfo() and getnameinfo() and requires a bit of rearranging Winsock calls from what you are probably used to.

Before we get into the specifics, let's cover some of the basic practices that you should follow. First, applications should not allocate the socket address structures specific to each protocol (such as SOCKADDR_IN and SOCKADDR_IN6 for IPv4 and IPv6, respectively) because they can be different sizes. Instead, a new socket address structure SOCKADDR_STORAGE has been introduced that is as large as the largest possible protocol specific address structure and includes padding for 64-bit alignment issues. The following code uses a SOCKADDR_STORAGE structure to store the destination IPv6 address.

 

SOCKADDR_STORAGE                saDestination;

SOCKET                                            s;

int                                                        addrlen, rc;

 

s = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);

 

if (s == INVALID_SOCKET)

{

            // socket failed

}

addrlen = sizeof(saDestination);

 

rc = WSAStringToAddress(

                                    "3ffe:2900:d005:f28d:250:8bff:fea0:92ed",

                                    AF_INET6,

                                    NULL,

                                    (SOCKADDR *)&saDestination,

                                    &addrlen

                                    );

if (rc == SOCKET_ERROR)

{

            // conversion failed

}

 

rc = connect(s, (SOCKADDR *)&saDestination, sizeof(saDestination));

 

if (rc == SOCKET_ERROR)

{

            // connect failed

}

 

Second, functions that take an address as a parameter should pass the entire socket address structure and not the protocol specific types like struct in_addr or struct in6_addr. This is important for IPv6, which might require the scope ID information to successfully connect. The SOCKADDR_STORAGE structure containing the address should be passed instead.

Third, avoid hardcode addresses regardless of whether they are IPv4 or IPv6. The Winsock header files define constants for all the address that are hard coded such as the loopback address and the wildcard address used for binding.

Now that some of the basic issues are out of the way, let's move to discussing how an application should be structured to be IP independent. We will divide our discussion into two sections: the client and the server.

 

The Client Example

 

For both TCP and UDP clients, the application typically possesses the server (or recipient's) IP address or hostname. Whether it resolves to an IPv4 address or IPv6 address doesn't matter. The client should follow these three steps:

 

  1. Resolve the address using the getaddrinfo() function. The hints should contain AF_UNSPEC as well as the socket type and protocol depending on whether the client uses TCP or UDP to communicate.
  2. Create the socket using the ai_family, ai_socktype, and ai_protocol fields from the addrinfo structure returned in step 1.
  3. Call connect() or sendto() with the ai_addr member of the addrinfo structure.

 

The following code sample illustrates these principles.

 

SOCKET                    s;

struct addrinfo            hints, *res=NULL;

char                             *szRemoteAddress=NULL, *szRemotePort=NULL;

int                                rc;

 

// Parse the command line to obtain the remote server's

// hostname or address along with the port number, which are contained

// in szRemoteAddress and szRemotePort.

memset(&hints, 0, sizeof(hints));

hints.ai_family = AF_UNSPEC;

hints.ai_socktype = SOCK_STREAM;

hints.ai_protocol = IPPROTO_TCP;

 

// first resolve assuming string is a string literal address

rc = getaddrinfo(szRemoteAddress, szRemotePort, &hints, &res);

if (rc == WSANO_DATA)

{

            // Unable to resolve name - bail out

}

 

s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

 

if (s == INVALID_SOCKET)

{

            // socket failed

}

 

rc = connect(s, res->ai_addr, res->ai_addrlen);

 

if (rc == SOCKET_ERROR)

{

            // connect failed

}

freeaddrinfo(res);

 

First, you will notice that there are no explicit references to AF_INET or AF_INET6. Also, there's no need to manipulate the underlying SOCKADDR_IN or SOCKADDR_IN6 addresses. The getaddrinfo() call fully initializes the returned socket address structure with all the required information - address family, binary address, etc., that is necessary for connecting or sending datagrams.

If the client application needs to explicitly bind the socket to a local port after socket creation but before connect() or sendto(), then another getaddrinfo() call can be made. This call would specify the address family, socket type, and protocol returned from the first call along with the AI_PASSIVE flag and desired local port, which will return another socket address structure initialized to the necessary bind address (such as 0.0.0.0 for IPv4 and :: for IPv6). The following program example shows the working version.

 

#include <winsock2.h>

#include <Ws2tcpip.h>

#include <stdio.h>

#include <string.h>

 

int main(int argc, char **argv)

{

    // Declare and initialize variables

    WSADATA wsaData;

            SOCKET                    s;

            struct addrinfo            hints, *res=NULL;

            char                             *szRemoteAddress=NULL, *szRemotePort=NULL;

            int                                rc;

            char                             sendbuf[1024] = "This is a test string from client!";

            int                                BytesSent;

 

    // Validate the parameters

    if (argc != 3)

    {

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

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

        // Just return with error

        return 1;

    }

 

    // Initialize Winsock

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

    {

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

        return 1;

    }

            else

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

 

            // Parse the command line to obtain the remote server's hostname

            // or IP address along with the port number, which are contained

            // in szRemoteAddress and szRemotePort.

            memset(&hints, 0, sizeof(hints));

            hints.ai_family = AF_UNSPEC;

            hints.ai_socktype = SOCK_STREAM;

            hints.ai_protocol = IPPROTO_TCP;

 

            szRemoteAddress = argv[1];

            szRemotePort = argv[2];

 

            // first resolve assuming string is a string literal address

            // The addrinfo structure is used by the ANSI getaddrinfo()

            // function to hold host address information. The addrinfoW()

            // structure is the version of this structure used by the

            // Unicode GetAddrInfoW() function

            // res struct contains info of the remote response

            rc = getaddrinfo(szRemoteAddress, szRemotePort, &hints, &res);

            if (rc != 0)

            {

                        printf("Client: getaddrinfo() failed miserably with error code %ld\n", WSAGetLastError());

                        WSACleanup();

                        return 1;

            }

            else

                        printf("Client: getaddrinfo() seems fine!\n");

 

            // The res struct info

            // http://msdn.microsoft.com/en-us/library/ms737530(VS.85).aspx

            printf("\n The getaddrinfo() options used: %d\n", res->ai_flags);

            printf(" The address family: %d\n", res->ai_family);

            printf(" The socket type: %d\n", res->ai_socktype);

            printf(" The protocol type: %d\n", res->ai_protocol);

 

            // The hints struct info

            printf("\n The hints.ai_family: %d\n", hints.ai_family);

            printf(" The hints.ai_socktype: %d\n", hints.ai_socktype);

            printf(" The hints.ai_protocol: %d\n", hints.ai_protocol);

 

            // Use the res info to create a socket

            s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

            if (s == INVALID_SOCKET)

            {

                        printf("\nClient: socket() failed miserably with error code %ld\n", WSAGetLastError());

                        WSACleanup();

                        return 1;

            }

            else

                        printf("\nClient: socket() is OK\n");

 

            // Then use the res to connect

            rc = connect(s, res->ai_addr, res->ai_addrlen);

 

            if (rc == SOCKET_ERROR)

            {

                        printf("Client: connect() failed miserably with error code %ld\n", WSAGetLastError());

                        WSACleanup();

                        return 1;

            }

            else

                        printf("Client: connect() is OK\n");

 

            printf("Client: I\'m ready to send or receive data...\n");

            // Sends some data to server/receiver...

            printf(" Sending: \"%s\"\n", sendbuf);

            BytesSent = send(s, sendbuf, strlen(sendbuf), 0);

 

            if(BytesSent == SOCKET_ERROR)

            {

                        printf("Client: send() failed with error code %ld.\n", WSAGetLastError());

                        closesocket(s);

                        WSACleanup();

                        return 1;

            }

            else

                        printf("Client: send() is OK - bytes sent: %ld\n", BytesSent);

           

            // If the socket type is TCP - IPPROTO_TCP, do the shutdown

            if(res->ai_protocol == 6)

            {

                        if(shutdown(s, SD_SEND) != 0)

                        {

                                    printf("Client: shutdown() failed with error code: %ld\n", WSAGetLastError());

                                    WSACleanup();

                                    return 1;

                        }

                        else

                                    printf("Client: shutdown() the sending part...\n");

            }

 

            // Deallocate resource

            freeaddrinfo(res);

            // Close socket

            if(closesocket(s) != 0)

            {

                        printf("Client: Cannot close s socket. Error code: %ld\n", WSAGetLastError());

                        WSACleanup();

                        return 1;

            }

            else

                        printf("Client: Closing s socket...\n");

 

            // Clean up the WSA

            if(WSACleanup() != 0)

            {

                        printf("Client: WSACleanup() failed!...\n");

                        return 1;

            }

            else

                        printf("Client: WSACleanup() is OK...\n");

    return 0;

}

 

The following screenshot shows a sample output using the following arguments:

IPindependentClientexample www.yahoo.com 80

IPindependentClientexample 216.239.61.104 80

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

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the IPv4 and IPv6 client sample program output

 

The following screenshot shows a sample output using the following arguments:

IPindependentClientexample ipv6.internet2.edu 80

IPindependentClientexample 2001:1888:0:1:2d0:b7ff:fe7d:bed6 80

The Windows socket/winsock2 IPv4, IPv6 Internet Protocol programming: the IPv4 and IPv6 client program sample output with IPv6 address argument

 

 

 


< inetntop() & inetpton() | Internet Protocol Main | IPv4 & IPv6 Server Examples >