9    AF_INET6 Sockets

Internet Protocol Version 6 (IPv6), as defined in RFC 2460, is both a completely new network layer protocol and a major revision of the current Internet architecture. As such, it builds upon and incorporates experiences gained with Internet Protocol Version 4 (IPv4). IPv6 also specifies a new address family, AF_INET6.

The operating system provides the basic application programming interfaces (APIs) as defined in RFC 2553. You can use the APIs and the AF_INET6 sockets in your existing applications (or in new applications) to communicate with IPv4 nodes today.

This chapter provides guidelines for developing applications that use AF_INET6 sockets (either porting existing applications or developing new applications), and provides client and server code examples that compare the use of AF_INET and AF_INET6 sockets to perform the same task.

9.1    Developing Applications to Use AF_INET6 Sockets

This section describes the following changes that you must make in your existing application code in order to be ready to operate in an IPv6 networking environment:

You can also use this information as guidelines for creating new, IPv6-ready applications. See Chapter 4 for additional information on AF_INET and AF_INET6 sockets.

See RFC 2553, Basic Socket Interface Extensions for IPv6, for complete information on the changes to the BSD socket Applications Programming Interface (API). The basic syntax of socket functions remains the same. Existing IPv4 applications will continue to operate as before, and IPv6 applications can interoperate with IPv4 applications.

9.1.1    Using AF_INET6 Sockets

At present, applications use AF_INET sockets for IPv4 communications. Figure 9-1 shows an sample sequence of events for an application that uses an AF_INET socket to send IPv4 packets.

Figure 9-1:  Using AF_INET Socket for IPv4 Communications

  1. Application calls gethostbyname and passes the host name, host1.

  2. The search finds host1 in the hosts database and gethostbyname returns the IPv4 address 1.2.3.4.

  3. The application opens an AF_INET socket.

  4. The application sends information to the 1.2.3.4 address.

  5. The socket layer passes the information and address to the UDP module.

  6. The UDP module puts the 1.2.3.4 address into the packet header and passes the information to the IPv4 module for transmission.

Section 9.2.1.1 contains sample program code that demonstrates these steps.

You can use the AF_INET6 socket for both IPv6 and IPv4 communications. For IPv4 communications, create an AF_INET6 socket and pass it a sockaddr_in6 structure that contains an IPv4-mapped IPv6 address (for example, ::ffff:1.2.3.4). Figure 9-2 shows the sequence of events for an application that uses an AF_INET6 socket to send IPv4 packets.

Figure 9-2:  Using AF_INET6 Socket for IPv4 Communications (Send)

  1. Application calls getaddrinfo and passes the host name (host1), the AF_INET6 address family hint, and the AI_DEFAULT flag hint. The flag hint tells the function that if an IPv4 address is found for host1, return it as an IPv4-mapped IPv6 address. See getaddrinfo(3) for a description of hints fields and values.

  2. The search finds an IPv4 address, 1.2.3.4, for host1 in the hosts database and getaddrinfo returns the IPv4-mapped IPv6 address ::ffff:1.2.3.4.

  3. The application opens an AF_INET6 socket.

  4. The application sends information to the ::ffff:1.2.3.4 address.

  5. The socket layer passes the information and address to the UDP module.

  6. The UDP module identifies the IPv4-mapped IPv6 address and puts the 1.2.3.4 address into the packet header and passes the information to the IPv4 module for transmission.

AF_INET6 sockets can receive messages sent to either IPv4 or IPv6 addresses on the system. An AF_INET6 socket uses the IPv4-mapped IPv6 address format to represent IPv4 addresses. Figure 9-3 shows the sequence of events for an application that uses an AF_INET6 socket to receive IPv4 packets.

Figure 9-3:  Using AF_INET6 Socket for IPv4 Communications (Receive)

  1. The application opens an AF_INET6 socket , binds to it, and listens on it.

  2. An IPv4 packet arrives and passes through the IPv4 module.

  3. The TCP layer strips off the packet header and passes the information and the IPv4-mapped IPv6 address (::ffff:1.2.3.4) to the socket layer.

  4. The application calls accept and retrieves the information from the socket.

  5. The application calls getnameinfo and passes the ::ffff:1.2.3.4 address and the NI_NAMEREQD flag. The flag tells the function to return the host name for the address. See getnameinfo(3) for a description of the flags bits and their meanings.

  6. The search finds the host name for the 1.2.3.4 address in the hosts database and getnameinfo returns the host name.

Section 9.2.2.2 contains sample program code that demonstrates these steps.

For IPv6 communications, create an AF_INET6 socket and pass it a sockaddr_in6 structure that contains an IPv6 address that is not an IPv4-mapped IPv6 address (for example, 3ffe:1200::a00:2bff:fe2d:02b2). Figure 9-4 shows the sequence of events for an application that uses an AF_INET6 socket to send IPv6 packets.

Figure 9-4:  Using AF_INET6 Socket for IPv6 Communications

  1. Application calls getaddrinfo and passes the host name (host1), the AF_INET6 address family hint, and the AI_DEFAULT flag hint. The flag hint tells the function that if an IPv6 address is found for host1, return it. See getaddrinfo(3) for a description of hints fields and values.

  2. The search finds an IPv6 address for host1 in the hosts database and getaddrinfo returns the IPv6 address 3ffe:1200::a00:2bff:fe2d:02b2.

  3. The application opens an AF_INET6 socket.

  4. The application sends information to the 3ffe:1200::a00:2bff:fe2d:02b2 address.

  5. The socket layer passes the information and address to the UDP module.

  6. The UDP module identifies the IPv6 address and puts the 3ffe:1200::a00:2bff:fe2d:02b2 address into the packet header and passes the information to the IPv6 module for transmission.

Section 9.2.2.1 contains sample program code that demonstrates these steps.

The following sections show how to convert an existing AF_INET application to an AF_INET6 application that is capable of communicating over both IPv4 and IPv6.

9.1.2    Making Name Changes

Most of the changes required are straightforward and mechanical, some may require a bit of code restructuring (for example, a routine that returns an int datatype holding an IPv4 address may need to be modified to take as an extra parameter a pointer to an in6_addr into which it writes the IPv6 address). Table 9-1 summarizes the changes to make to your application's code:

Table 9-1:  Name Changes

Search file for: Replace with:
AF_INET AF_INET6
PF_INET PF_INET6
INADDR_ANY in6addr_any

9.1.3    Making Structure Changes

The structure names and field names have changed for the following structures:

The following sections discuss these changes.

9.1.3.1    in_addr Structure

Applications that use the in_addr structure must be changed, as needed, to use the in6_addr structure, as shown in the following examples:

AF_INET Structure AF_INET6 Structure

struct in_addr [1]
  unsigned int s_addr [2]

struct in6_addr [1]
  uint8_t s6_addr [16] [2]

Make the following changes in your application, as needed:

  1. Change the structure name in_addr to in6_addr. [Return to example]

  2. Change the data type from unsigned int to uint8_t and the field name s_addr to s6_addr. [Return to example]

9.1.3.2    sockaddr_in Structure

Applications that use the 4.4 BSD sockaddr_in structure must be changed, as needed, to use the sockaddr_in6 structure, as shown in the following examples:

AF_INET Structure AF_INET6 Structure

struct sockaddr_in [1]
  unsigned char sin_len [2]
  sa_family_t sin_family [3]
  in_port_t sin_port [4]
  struct in_addr sin_addr [5]

struct sockaddr_in6 [1]
  uint8_t sin6_len [2]
  sa_family_t sin6_family [3]
  int_port_t sin6_port [4]
  struct in6_addr sin6_addr [5]

Make the following change in your application, as needed:

  1. Change structure name sockaddr_in to sockaddr_in6. [Return to example]

  2. Change the data type unsigned char to uint8_t and the field name sin_len to sin6_len. [Return to example]

  3. Change the field name sin_family to sin6_family. [Return to example]

  4. Change the field name sin_port to sin6_port. [Return to example]

  5. Change the field name sin_addr to sin6_addr. [Return to example]

Applications that use the 4.3 BSD sockaddr_in structure must be changed, as needed, to use the sockaddr_in6 structure, as shown in the following examples:

AF_INET Structure AF_INET6 Structure

struct sockaddr_in [1]
  u_short sin_family [2]
  in_port_t sin_port [3]
  struct in_addr sin_addr [4]

struct sockaddr_in6 [1]
  u_short sin6_family [2]
  in_port_t sin6_port [3]
  struct in6_addr sin6_addr [4]

Make the following change in your application, as needed:

  1. Change structure name sockaddr_in to sockaddr_in6. [Return to example]

  2. Change the field name sin_family to sin6_family. [Return to example]

  3. Change the field name sin_port to sin6_port. [Return to example]

  4. Change the field name sin_addr to sin6_addr. [Return to example]

Note

In both cases, you should initialize the entire sockaddr_in6 structure to zero after your structure declarations.

9.1.3.3    sockaddr Structure

Applications that use the generic socket address structure (sockaddr) to hold an AF_INET socket address (sockaddr_in) must be changed to use either the AF_INET6 sockaddr_in6 structure or the sockaddr_storage structure.

If your application is to manipulate IPv6 addresses only, make the following changes in your application, as needed:

AF_INET Structure AF_INET6 Structure

struct sockaddr [1]

struct sockaddr_in6 [1]

  1. Change structure name sockaddr to sockaddr_in6 for those cases where it should be struct sockaddr_in. For example, sizeof(struct sockaddr). [Return to example]

If your application is to manipulate addresses from both IPv4 and IPv6, make the following changes in your application, as needed:

AF_INET Structure AF_INET6 Structure

struct sockaddr [1]

struct sockaddr_storage [1]

  1. Change structure name sockaddr to sockaddr_storage for those cases where it should be struct sockaddr_in. For example, sizeof(struct sockaddr). [Return to example]

Note

Both the sockaddr_in6 and sockaddr_storage structures are larger than a sockaddr structure.

9.1.3.4    hostent Structure

Applications that use the hostent structure must be changed, as needed, to use the addrinfo structure, as shown in the following examples:

AF_INET Structure AF_INET6 Structure

struct hostent [1]

struct addrinfo [1]

Make the following changes in your application, as needed:

  1. Change the structure name hostent to addrinfo. [Return to example]

9.1.4    Making Function Call Changes

You must make changes, as needed, to applications that use the following library routines:

The following sections discuss these changes.

9.1.4.1    gethostbyaddr Function Call

Applications that use the gethostbyaddr function call must be changed to use the getnameinfo function call, as shown in the following examples:

AF_INET Call

gethostbyaddr(xxx,4,AF_INET) [1]

AF_INET6 Call

err=getnameinfo(&sockaddr,sockaddr_len, node_name, name_len,
 service, service_len, flags); [1]

Make the following changes in your application, as needed:

  1. Change the function name from gethostbyaddr to getnameinfo and provide a pointer to the socket address structure, a character string for the returned node name, an integer for the length of the returned node name, a character string to receive the returned service name, an integer for the length of the returned service name, and an integer that specifies the type of address processing to be performed. See getnameinfo(3) for a description of the flags bits and their meanings. [Return to example]

9.1.4.2    gethostbyname Function Call

Applications that use the gethostbyname function call must be changed to use the getaddrinfo function call, as shown in the following examples:

AF_INET Call

gethostbyname(name) [1]

AF_INET6 Call

err=getaddrinfo(node_name, service_name, &hints, &result); [1]

.
.
.
freeaddrinfo(&result); [2]

Make the following changes in your application, as needed:

  1. Change the function name from gethostbyname to getaddrinfo and provide a character string that contains the node name, a character string that contains the service name to use, a pointer to a hints structure that contains processing options, and a pointer to an addrinfo structure or structures for the returned address information. See getaddrinfo(3) for a description of hints fields and values. [Return to example]

  2. Add a call to the freeaddrinfo routine to free the addrinfo structure or structures when your application is finished using them. [Return to example]

9.1.4.3    inet_ntoa Function Call

Applications that use the inet_ntoa function call must be changed to use the getnameinfo function call, as shown in the following examples:

AF_INET Call

inet_ntoa(addr) [1]

AF_INET6 Call

err=getnameinfo(&sockaddr,sockaddr_len, node_name, name_len,
 service, service_len, NI_NUMERICHOST); [1]
 
 

Make the following changes in your application, as needed:

  1. Change the function name from gethostbyaddr to getnameinfo and provide a pointer to the socket address structure, a character string for the returned node name, an integer for the length of the returned node name, a character string to receive the returned service name, an integer for the length of the returned service name, and the NI_NUMERICHOST flag. See getnameinfo(3) for a description of the flags bits and their meanings. [Return to example]

9.1.4.4    inet_addr Function Call

Applications that use the inet_addr function call must be changed to use the getaddrinfo function call, as shown in the following examples:

AF_INET Call

result=inet_addr(&string); [1]

AF_INET6 Call

err=getaddrinfo(node_name, service_name, &hints, &result); [1]

.
.
.
freeaddrinfo(&result); [2]

Make the following changes in your application, as needed:

  1. Change the function name from gethostbyname to getaddrinfo and provide a character string that contains the node name, a character string that contains the service name to use, a pointer to a hints structure that contains the AI_NUMERICHOST option, and a pointer to an addrinfo structure or structures for the returned address information. See getaddrinfo(3) for a description of hints fields and values. [Return to example]

  2. Add a call to the freeaddrinfo routine to free the addrinfo structure or structures when your application is finished using them. [Return to example]

9.1.5    Making Other Application Changes

In addition to the name changes, you should review your code for specific uses of IP address information and variables.

9.1.5.1    Comparing IP Addresses

If your application compares IP addresses or tests IP addresses for equality, the in6_addr structure changes you made in Section 9.1.3.1 change the comparison of int quantities to a comparison of structures. This will break the code and cause compiler errors.

Make either of the following changes to your application, as needed:

AF_INET Code

(addr1->s_addr == addr2->s_addr) [1]

AF_INET6 Code

(memcmp(addr1, addr2, sizeof(struct in6_addr)) == 0) [1]

  1. Change the equality expression to one that uses the memcmp (memory comparison) function. [Return to example]

AF_INET Code AF_INET6 Code

(addr1->s_addr == addr2->s_addr) [1]

IN6_ARE_ADDR_EQUAL(addr1, addr2) [1]

  1. Change the equality expression to one that uses the IN6_ARE_ADDR_EQUAL macro. [Return to example]

9.1.5.2    Comparing an IP Address to the Wildcard Address

If your application compares an IP address to the wildcard address, the in6_addr structure changes you made in Section 9.1.3.1 change the comparison of int quantities to a comparison of structures. This will break the code and cause compiler errors.

Make either of the following changes to your application, as needed:

AF_INET Code AF_INET6 Code

(addr->s_addr == INADDR_ANY) [1]

IN6_IS_ADDR_UNSPECIFIED(addr) [1]

  1. Change the equality expression to one that uses the IN6_IS_ADDR_UNSPECIFIED macro. [Return to example]

AF_INET Code

(addr->s_addr == INADDR_ANY) [1]

AF_INET6 Code

(memcmp(addr, in6addr_any, sizeof(struct in6_addr)) == 0) [1]

  1. Change the equality expression to one that uses the memcmp (memory comparison) function. [Return to example]

9.1.5.3    Using int Data Types to Hold IP Addresses

If your application uses int data types to hold IP addresses, the in6_addr structure changes you made in Section 9.1.3.1 changes the assignment. This will break the code and cause compiler errors.

Make the following changes to your application, as needed:

AF_INET Code AF_INET6 Code

struct in_addr foo;
int bar; [1]

.
.
.
bar = foo.s_addr; [2]

struct in6_addr foo;
struct in6_addr bar; [1]

.
.
.
bar = foo; [2]

  1. Change the data type for bar from int to a struct in6_addr. [Return to example]

  2. Change the assignment statement for bar to remove the s_addr field reference. [Return to example]

9.1.5.4    Using Functions that Return IP Addresses

If your application uses functions that return IP addresses as int data types, the in6_addr structure changes you made in Section 9.1.3.1 changes the destination of the return value from an int to an array of char. This will break the code and cause compiler errors.

Make the following changes to your application, as needed:

AF_INET Code AF_INET6 Code

struct in_addr *addr;
addr->s_addr = foo(xxx); [1]

struct in6_addr *addr;
foo(xxx, addr); [1]

  1. Restructure the function to enable you to pass the address of the structure in the call. In addition, modify the function to write the return value into the structure pointed to by addr. [Return to example]

9.1.5.5    Changing Socket Options

If your application uses IPv4 IP-level socket options, change them to the corresponding IPv6 options.

9.2    Sample Client/Server Programs

This section contains the following client and server code examples:

You can find these programs and two protocol-independent versions of these programs in the/usr/examples/ipv6/network_programming directory. In addition, this section also contains sample output from these programs.

9.2.1    Programs Using AF_INET Sockets

This section contains a client and server program that use AF_INET sockets.

9.2.1.1    Client Program Using AF_INET Sockets

Example 9-1 shows a sample client program that you can build, compile, and run on your system. The program sends a request to and receives a response from the system specified on the command line.

Example 9-1:  Client Stub Routine

/*
 * *****************************************************************
 * *                                                               *
 * *    Copyright (c) Compaq Computer Corporation, 2000            *
 * *                                                               *
 * *   The software contained on this media  is  proprietary  to   *
 * *   and  embodies  the  confidential  technology  of  Compaq    *
 * *   Computer  Corporation.  Possession, use,  duplication  or   *
 * *   dissemination of the software and media is authorized only  *
 * *   pursuant to a valid written license from Compaq Computer    *
 * *   Corporation.                                                *
 * *                                                               *
 * *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
 * *   by the U.S. Government is subject to restrictions  as  set  *
 * *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
 * *   or  in  FAR 52.227-19, as applicable.                       *
 * *                                                               *
 * *****************************************************************
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <arpa/inet.h>
 
#define SERVER_PORT	7639
#define CLIENT_PORT	7739
 
#define MAXBUFSIZE 4096
 
int main (
    int argc,
    char **argv )
{
    int             s;
    char            databuf[MAXBUFSIZE];
    int             dcount;
    struct sockaddr_in     serveraddr; [1]
    struct sockaddr_in     clientaddr;
    int             serveraddrlen;
    const char      *ap;
    const char      *request = "this is the client's request";
    struct hostent  *hp;
    char            *server;
 
    if (argc < 2) {
        printf("Usage: client <server>\n");
        exit(1);
    }
    server = argv[1];
 
    bzero((char *) &serveraddr, sizeof(struct sockaddr_in)); [2]
    serveraddr.sin_family = AF_INET;
    if ((hp = gethostbyname(server)) == NULL) {  [3]
        printf("unknown host: %s\n", server);
        exit(2);
    }
    serveraddr.sin_port = htons(SERVER_PORT);
 
    while (hp->h_addr_list[0] != NULL) {
        if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { [4]
            perror("socket");
            exit(3);
        }
        memcpy(&serveraddr.sin_addr.s_addr, hp->h_addr_list[0],
                         hp->h_length);
 
        if (connect(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
            perror("connect");
            close(s);
            hp->h_addr_list++;
            continue;
        }
        break;
    }
    if (send(s, request, strlen(request), 0) < 0) { [5]
        perror("send");
        exit(5);
    }
    dcount = recv(s, databuf, sizeof(databuf), 0);
    if (dcount < 0) {
        perror("recv");
        exit(6);
    }
    databuf[dcount] = '\0';
 
    hp = gethostbyaddr((char *)&serveraddr.sin_addr.s_addr, [6]
        sizeof(serveraddr.sin_addr.s_addr), AF_INET);
    ap = inet_ntoa(serveraddr.sin_addr);  [7]
    printf("Response received from");
    if (hp != NULL)
        printf(" %s", hp->h_name);
    if (ap != NULL)
        printf(" (%s)", ap);
    printf(": %s\n", databuf);
 
    close(s);
}
 
 

  1. Declares sockaddr_in structures. [Return to example]

  2. Clears the server address and sets up server variables. [Return to example]

  3. Calls gethostbyname to obtain the server address. [Return to example]

  4. Creates an AF_INET socket. [Return to example]

  5. Sends a request to the server. [Return to example]

  6. Calls gethostbyaddr to retrieve the server name. [Return to example]

  7. Calls inet_ntoa to convert the server address to a text string. [Return to example]

9.2.1.2    Server Program Using AF_INET Sockets

Example 9-2 shows a sample server program that you can build, compile, and run on your system. The program receives requests from and sends responses to client programs on other systems.

Example 9-2:  Server Stub Routine

/*
 * *****************************************************************
 * *                                                               *
 * *    Copyright (c) Compaq Computer  Corporation, 2000           *
 * *                                                               *
 * *   The software contained on this media  is  proprietary  to   *
 * *   and  embodies  the  confidential  technology  of  Compaq    *
 * *   Computer  Corporation.  Possession, use,  duplication  or   *
 * *   dissemination of the software and media is authorized only  *
 * *   pursuant to a valid written license from Compaq Computer    *
 * *   Corporation.                                                *
 * *                                                               *
 * *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
 * *   by the U.S. Government is subject to restrictions  as  set  *
 * *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
 * *   or  in  FAR 52.227-19, as applicable.                       *
 * *                                                               *
 * *****************************************************************
 */
 
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <arpa/inet.h>
 
#define SERVER_PORT	7639
#define CLIENT_PORT	7739
 
#define MAXBUFSIZE 4096
 
int main (
    int argc,
    char **argv )
{
    int             s;
    char            databuf[MAXBUFSIZE];
    int             dcount;
    struct sockaddr_in    serveraddr; [1]
    struct sockaddr_in    clientaddr;
    int                   clientaddrlen;
    struct hostent        *hp;
    const char            *ap;
    const char            *response = "this is the server's response";
    u_short               port;
 
    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { [2]
        perror("socket");
        exit(1);
    }
 
    bzero((char *) &serveraddr, sizeof(struct sockaddr_in)); [3]
    serveraddr.sin_family      = AF_INET;
    serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
    serveraddr.sin_port        = htons(SERVER_PORT);
 
    if (bind(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
        perror("bind");
        exit(2);
    }
    if (listen(s, SOMAXCONN) < 0) {
        perror("Listen");
        close(s);
        exit(3);
 
    while (1) {
        int new_s;
        clientaddrlen = sizeof(clientaddr);
        new_s = accept(s, (Struct sockaddr*)&clientaddr, &clientaddrlen);
 
        dcount = recv(new_s, databuf, sizeof(databuf), 0);
        if (dcount <= 0) {
            perror("recv");
            close(new_s);
            continue;
        }
        databuf[dcount] = '\0';
        hp = gethostbyaddr((char *)&clientaddr.sin_addr.s_addr, [4]
            sizeof(clientaddr.sin_addr.s_addr), AF_INET);
        ap = inet_ntoa(clientaddr.sin_addr); [5]
        port = ntohs(clientaddr.sin_port);
        printf("Request received from");
        if (hp != NULL)
            printf(" %s", hp->h_name);
        if (ap != NULL)
            printf(" (%s)", ap);
        printf(" port %d \"%s\"\n", port, databuf);
 
        if (send(new_s, response, strlen(response), 0) < 0) {
            perror("send");
            continue;
        }
        close(new_s);
    }
    close(s);
}
 
 

  1. Declares sockaddr_in structures. [Return to example]

  2. Creates an AF_INET socket. [Return to example]

  3. Clears the server address and sets up server variables. [Return to example]

  4. Calls gethostbyaddr to retrieve the client name. [Return to example]

  5. Calls inet_ntoa to convert the client address to a text string. [Return to example]

9.2.2    Programs Using AF_INET6 Sockets

This section contains a client and server program that use AF_INET6 sockets.

9.2.2.1    Client Program Using AF_INET6 Sockets

Example 9-3 shows a sample client program that you can build, compile, and run on your system. The program sends a request to and receives a response from the system specified on the command line.

Example 9-3:  Client Stub Routine

/*
 * *****************************************************************
 * *                                                               *
 * *    Copyright (c) Compaq Computer Corporation, 2000            *
 * *                                                               *
 * *   The software contained on this media  is  proprietary  to   *
 * *   and  embodies  the  confidential  technology  of  Compaq    *
 * *   Computer Corporation.  Possession, use,  duplication  or    *
 * *   dissemination of the software and media is authorized only  *
 * *   pursuant to a valid written license from Compaq Computer    *
 * *   Corporation.                                                *
 * *                                                               *
 * *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
 * *   by the U.S. Government is subject to restrictions  as  set  *
 * *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
 * *   or  in  FAR 52.227-19, as applicable.                       *
 * *                                                               *
 * *****************************************************************
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <arpa/inet.h>
 
#define SERVER_PORT	7639
#define CLIENT_PORT	7739
 
#define MAXBUFSIZE 4096
 
int main (
    int argc,
    char **argv )
{
    int             s;
    char            databuf[MAXBUFSIZE];
    int             dcount;
    struct addrinfo *server_info;  [1]
    struct addrinfo *cur_info;
    struct addrinfo hints;
    struct sockaddr_in6    serveraddr;
    char            addrbuf[INET6_ADDRSTRLEN];
    char            node[MAXDNAME];
    char            service[MAXDNAME];
    int             ni;
    int             err;
    int             serveraddrlen;
    const char      *request = "this is the client's request";
    char            *server;
 
    if (argc < 2) {
        printf("Usage: client <server>\n");
        exit(1);
    }
    server = argv[1];
    bzero((char *) &hints, sizeof(hints)); [2]
    hints.ai_family = AF_INET6;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_DEFAULT;
 
    sprintf(service, "%d", SERVER_PORT);
 
    err = getaddrinfo(server, service, &hints, &server_info);  [3]
    if (err != 0) {
        if (err == EAI_SYSTEM)
            perror("getaddrinfo");
        else
            printf("%s", gai_strerror(err0));
        exit(2);
    }
    cur_info = server_info;
 
    while (cur_info != NULL) {
        if ((s = socket(cur_info->ai_family, cur_info->ai_socktype, 0)) < 0) { [4]
            perror("socket");
            exit(3);
        }
        if (connect(s, cur_info->ai_addr, cur_info->ai_addrlen) <0 {
            close(s);
            cur_info = cur_info->ai_next;
            continue;
        }
        break;
    }
    freeaddrinfo(server_info); [5]
 
    if (send(s, request, strlen(request), 0) < 0) { [6]
        perror("send");
        exit(5);
    }
    dcount = recv(s, databuf, sizeof(databuf), 0);
    if (dcount < 0) {
        perror("recv");
        exit(6);
    }
    databuf[dcount] = '\0';
    serveraddrlen = sizeof(serveraddr);
    if (getpeername(s, (struct sockaddr*) &serveraddr, &serveraddrlen) < 0 {
        perror("getpeername");
        exit(7);
    }
    printf("Response received from");
    ni = getnameinfo((struct sockaddr*)&serveraddr, serveraddrlen, [7]
                        node, sizeof(node), NULL, 0, NI_NAMEREQD);
    if (ni == 0)
        printf(" %s", node);
    ni = getnameinfo((struct sockaddr*)&serveraddr, serveraddrlen, [8]
                        addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST);
    if (ni == 0)
        printf(" (%s)", addrbuf);
 
    printf(": %s\n", databuf);
 
    close(s);
}
 
 

  1. Declares addrinfo structures, hints structure, sockaddr_in6 structure, address string buffer, node name string buffer, service name string buffer, error number variable, and server address length variable. [Return to example]

  2. Clears the hints structure and sets up hints variables. [Return to example]

  3. Calls getaddrinfo to obtain the server address. [Return to example]

  4. Creates an AF_INET6 socket. [Return to example]

  5. Frees all addrinfo structures. [Return to example]

  6. Sends a request to the server. [Return to example]

  7. Calls getnameinfo to obtain the server name. [Return to example]

  8. Calls getnameinfo to obtain the server's numeric address and message data. [Return to example]

9.2.2.2    Server Program Using AF_INET6 Sockets

Example 9-4 shows a sample server program that you can build, compile, and run on your system. The program receives requests from and sends responses to client programs on other systems.

Example 9-4:  Server Stub Routine

/*
 * *****************************************************************
 * *                                                               *
 * *    Copyright (c) Compaq Computer Corporation, 2000            *
 * *                                                               *
 * *   The software contained on this media  is  proprietary  to   *
 * *   and  embodies  the  confidential  technology  of  Compaq    *
 * *   Computer Corporation.  Possession, use,  duplication  or    *
 * *   dissemination of the software and media is authorized only  *
 * *   pursuant to a valid written license from Compaq Computer    *
 * *   Corporation.                                                *
 * *                                                               *
 * *   RESTRICTED RIGHTS LEGEND   Use, duplication, or disclosure  *
 * *   by the U.S. Government is subject to restrictions  as  set  *
 * *   forth in Subparagraph (c)(1)(ii)  of  DFARS  252.227-7013,  *
 * *   or  in  FAR 52.227-19, as applicable.                       *
 * *                                                               *
 * *****************************************************************
 */
 
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <arpa/inet.h>
 
#define SERVER_PORT	7639
#define CLIENT_PORT	7739
 
#define MAXBUFSIZE 4096
 
int main (
    int argc,
    char **argv )
{
    int             s;
    char            databuf[MAXBUFSIZE];
    int             dcount;
    struct sockaddr_in6   serveraddr; [1]
    struct storage        clientaddr;
    char                  addrbuf[INET6_ADDRSTRLEN];
    char                  node[MAXDNAME];
    char                  port[MAXDNAME];
    int                   err;
    int                   ni;
    int                   clientaddrlen;
    const char            *response = "this is the server's response";
 
    if ((s = socket(AF_INET6, SOCK_STREAM, 0)) < 0) { [2]
        perror("socket");
        exit(1);
    }
 
    bzero((char *) &serveraddr, sizeof(struct sockaddr_in6)); [3]
    serveraddr.sin6_family      = AF_INET6;
    serveraddr.sin6_addr        = in6addr_any;
    serveraddr.sin6_port        = htons(SERVER_PORT);
 
    if (bind(s, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) {
        perror("bind");
        exit(2);
    }
    if (listen(s, SOMAXCONN) < 0) {
        perror("listen");
        close(s);
        exit(3);
    }
    while (1) {
        int new_s;
        clientaddrlen = sizeof(clientaddr);
        bzero((char *)&clientaddr, clientaddrlen); [4]
        new_s = accept(s, (struct sockaddr*)&clientaddr, &clientaddrlen);
        if (new_s < 0) {
            perror("accept");
            continue;
        }
        dcount = recv(s, databuf, sizeof(databuf), 0);
        if (dcount <= 0) {
            perror("recv");
            close(new_s);
            continue;
        }
        databuf[dcount] = '\0';
 
        printf("Request received from");
        ni = getnameinfo((struct sockaddr *)&clientaddr, [5]
            clientaddrlen, node, sizeof(node), NULL, 0, NI_NAMEREQD);
        if (ni == 0)
            printf(" %s", node);
        ni = getnameinfo((struct sockaddr *)&clientaddr, [6]
            clientaddrlen, addrbuf, sizeof(addrbuf), port, sizeof(port),
            NI_NUMERICHOST|NI_NUMERICSERV);
        if (ni == 0)
            printf(" (%s) port %d, addrbuf, port);
        printf(" \"%s\"\n", port, databuf);
 
        if (send(new_s, response, strlen(response), 0) < 0) {
            perror("send");
            close(new_s);
            continue;
        }
        close(new_s);
    }
    close(s);
}
 
 

  1. Declares sockaddr_in6 structures, address string buffer, and error number variable. [Return to example]

  2. Creates an AF_INET6 socket. [Return to example]

  3. Clears the server address and sets up the server variables. [Return to example]

  4. Clears the client address. [Return to example]

  5. Calls getnameinfo to retrieve the client name. [Return to example]

  6. Calls getnameinfo to obtain the client's address. port, and message data. [Return to example]

9.2.3    Sample Program Output

This section contains sample output from the server and client programs. The server program makes and receives all requests on an AF_INET6 socket using sockaddr_in6. For requests received over IPv4, sockaddr_in6 contains an IPv4-mapped IPv6 address.

The following example shows the client program running on node hostb6 and sending a request to node hosta6. The program uses an AF_INET6 socket. The hosta6 node has the IPv6 address 3ffe:1200::a00:2bff:fe97:7be0 in the Domain Name System (DNS).

user2@hostb6> ./client hosta6
Response received from hosta6.ipv6.corp.example (3ffe:1200::a00:2bff:fe97:7be0):
 this is the server's response

On the server node, the following example shows the server program invocation and the request received from the client node hostb6:


user1@hosta6> ./server
Request received from hostb6.ipv6.corp.example (3ffe:1200::a00:2bff:fe2d:02b2
 port 7739 "this is the client's request"
 
 

The following example shows the client program running on node hostb and sending a request to node hosta. The program uses an AF_INET6 socket. The hosta node has the IPv4 address 10.10.10.13 in the DNS.

user2@hostb> ./client hosta
Response received from hosta.corp.example (::ffff:10.10.10.13): this is the
 server's response

On the server node, the following example shows the server program invocation and the request received from the client node hostb:

user1@hosta6> ./server
Request received from hostb.corp.example (::ffff:10.10.10.251) port 7739
 "this is the client's request"
 
 

The following example shows the client program running on node hostc and sending a request to node hosta. The program was built and run on an IPv4-only system using an AF_INET socket.


user3@hostc> ./client hosta
Response received from hosta.corp.example (10.10.10.13): this is the
 server's response

On the server node, the following example shows the server program invocation and the request received from the client node hostc:

user1@hosta6> ./server
Request received from hostc.corp.example (::ffff:10.10.10.63) port 7739
 "this is the client's request"