z/OS Communications Server: IPv6 Network and Application Design Guide
Previous topic | Next topic | Contents | Contact z/OS | Library | PDF


Application awareness of whether system is IPv6 enabled

z/OS Communications Server: IPv6 Network and Application Design Guide
SC27-3663-00

A z/OS® system might or might not be enabled for IPv6 communications. Enabling a z/OS system for IPv6 support requires explicit configuration by the system administrator to allow AF_INET6 sockets to be created. As a result, an application cannot typically assume that IPv6 is enabled on the systems where the application is running. Some exceptions do exist. For example, applications can run on a limited number of systems that are known to be IPv6 enabled. However, in general, most applications that are being enhanced to support IPv6 must first perform a runtime test to determine whether IPv6 is enabled on the system where they are executing. If the system is not enabled for IPv6, the application should proceed with its existing IPv4 logic. If the system is enabled for IPv6, the application can now use AF_INET6 sockets and features to communicate with both IPv4 and IPv6 applications.

Determine if a system is enabled for IPv6 by attempting to create an AF_INET6 socket. If this operation is successful, the application can assume that IPv6 is enabled. If the operation fails (with return code EAFNOSUPPORT) the application should revert to its IPv4 logic and create an AF_INET socket.
Table 1. Using socket() to determine IPv6 enablement
Affected socket API call Required changes
socket() Specify AF_INET6 as the Address Family (or domain) parameter. This API call fails if the system is not enabled for IPv6.
The getaddrinfo() API is an alternative mechanism that can be used by TCP/IP client applications to determine whether IPv6 is enabled. This API is a replacement for the gethostbyname() API and is typically used by TCP/IP client programs to resolve a host name to an IP address. For example, a client application that receives the server application's host name or IP address (such as FTP) as input can invoke the getaddrinfo() function before opening up a socket with a selected set of options. This allows the application to receive a list of addrinfo structures (one for each IP address of the destination host) that contain the following information:
  • The address family of the IP address (AF_INET or AF_INET6)
  • A pointer to a socket address structure of the appropriate type (sockaddr_in or sockaddr_in6) that is fully initialized (including the IP address and Port fields)
  • The length of the socket address structure

A client application can be coded with this information in a manner that allows it to be protocol-independent without having to perform specific runtime checks to determine whether IPv6 is enabled and without having to have dual-path logic (IPv4 versus IPv6). The following application is an example of this approach:

Figure 1. Example of protocol-independent client application
int
myconnect(char *hostname)
{
  struct addrinfo *res, *aip;
  struct addrinfo hints;
  char buf[INET6_ADDRSTRLEN];
  static char *servicename = "21";
  int sock = -1;
  int error;

  /* Initialize the hints structure for getaddrinfo() call.
     This application can deal with either IPv4 or IPv6 addresses.
     It relies on getaddrinfo to return the most appropriate IP address
     and socket address structure based on the current configuration */

  bzero(&hints, sizeof (hints));
  hints.ai_socktype = SOCK_STREAM; /* Interested in streams sockets
                                      only                           */
  /* Note that we are asking for all IP addresses to be returned (IPv4
     or IPv6) based on the system connectivity.  Also, note that we
     would prefer all addresses to be returned in sockaddr_in6 format
     if the system is enabled for IPv6.  In addition, we also specify
     a numeric port using AI_NUMERICSERV so that the returned socket
     address structures are primed with our port number.    */

  hints.ai_flags = AI_ALL | AI_V4MAPPED | AI_ADDRCONFIG |
                   AI_NUMERICSERV;
  hints.ai_family = AF_UNSPEC;
  error = getaddrinfo(hostname, servicename, &hints, &res);
  if (error != 0) {
    (void) fprintf(stderr,
    "getaddrinfo: %s for host %s service %s\n",
    gai_strerror(error), hostname, servicename);
  return (-1);
  }
for (aip = res; aip != NULL; aip = aip->ai_next) {
/*
* Loop through list of addresses returned, opening sockets
* and attempting to connect()until successful.  The
* The address type depends on what getaddrinfo()
* gave us.
*/
  sock = socket(aip->ai_family, aip->ai_socktype,
              aip->ai_protocol);
  if (sock == -1) {
    printf("Socket failed: 
    freeaddrinfo(res);
    return (-1);
  }
  /* Connect to the host. */
  if (connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) {
    printf("Connect failed, errno=%d, errno2=%08x\n",
    errno, __errno2());
    (void) close(sock);
    sock = -1;
    continue;
  }
  break;
}
  freeaddrinfo(res);
  return (sock);
}

When this example executes on a system where IPv6 is not enabled, only IPv4 addresses are returned in AF_INET format (in sockaddr_in structures). When this identical example executes on an IPv6-enabled system, both IPv4 and IPv6 addresses are returned, and the IPv4 addresses are returned in IPv4-mapped IPv6 address format (in sockaddr_in6 structures). Note that an AF_INET6 socket can be used for the connection even when the address returned by getaddrinfo() is an IPv4-mapped IPv6 address.

Go to the previous page Go to the next page




Copyright IBM Corporation 1990, 2014