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. Although the current version of the operating system does not include an IPv6 network layer, your AF_INET6 applications will continue to communicate with IPv4 nodes and be ready to communicate with IPv6 nodes after the IPv6 network layer is available and installed.

This chapter describes IPv6 addresses, 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    IPv6 Addresses

The most noticeable feature of IPv6 is the IPv6 address itself. The address size is increased from 32 bits to 128 bits. This section describes the following:

9.1.1    Address Text Representation

You can use the following syntax to represent IPv6 addresses as text strings:

x:x:x:x:x:x:x:x

The x is a hexadecimal value of a 16-bit piece of the address. For example, the following addresses are IPv6 addresses:

FEDC:BA98:7654:3210:FEDC:BA98:7654:3210
 
1070:0:0:0:0:800:200C:417B

IPv6 addresses can contain long strings of zero (0) bits. To make it easier to write these addresses, you can use the double colon characters (::) one time in an address to represent 1 or more 16-bit groups of zeros. For example, you can compress the second IPv6 address example as follows:

1070::800:200C:417B

Alternatively, you can use the following syntax to represent IPv6 addresses in an environment of both IPv4 and IPv6 nodes:

x:x:x:x:x:x:d.d.d.d

In this case, x is a hexadecimal value of a 16-bit piece of the address (six high-order pieces) and d is a decimal value of an 8-bit piece of address (four low-order pieces) in standard, dotted-quad IPv4 form. For example, the following addresses are IPv6 addresses:

0:0:0:0:0:0:13.1.68.3
 
0:0:0:0:0:FFFF:129.144.52.38

When compressed, these addresses are as follows:

::13.1.68.3
 
::FFFF:129.144.52.38

Like IPv4 address prefixes, IPv6 address prefixes are represented using the Classless Inter-Domain Routing (CIDR) notation. This notation has the following format:

ipv6-address/prefix-length

For example, you can represent the 60-bit hexadecimal prefix 12AB00000000CD3 in any of the following ways:

12AB:0000:0000:CD30:0000:0000:0000:0000/60
12AB::CD30:0:0:0:0/60
12AB:0:0:CD30::/60

9.1.2    Types of Addresses

There are three types of IPv6 addresses:

Note

Unlike IPv4, IPv6 does not define a broadcast address. To get the function of a broadcast address, use a multicast address (see Section 9.1.2.2).

The following sections describe the unicast and multicast address types only and provide examples.

9.1.2.1    Unicast Address

A unicast address is an identifier for an interface. Packets sent to a unicast address are delivered to the node containing the interface identified by the address.

Unicast addresses typically have the following format:

This address typically consists of a 64-bit prefix followed by a 64-bit interface ID as follows:

An interface ID identifies an interface on a link. The interface ID is required to be unique on a link, but may also be unique over a broader scope. In many cases, an interface's ID is derived from its link-layer address. The same interface ID may be used on multiple interfaces on a single node.

The following list describes commonly used unicast addresses and their values:

Unspecified address

Indicates the absence of an address, and is never assigned to an interface. The unspecified address has the value 0:0:0:0:0:0:0:0 in the normal form or :: in the compressed form.

Loopback address

Used by a node to send IP datagrams to itself, and is typically assigned to the loopback interface. The IPv6 loopback address has the value 0:0:0:0:0:0:0:1 in the normal form or ::1 in the compressed form.

IPv6 addresses with embedded IPv4 addresses

Used in mixed IPv4 and IPv6 environments, and can be either of the following:

Local-use IPv6 unicast addresses

Can be either of the following:

9.1.2.2    Multicast Address

A multicast address is an identifier for a group of nodes, similar to an IPv4 multicast address. Multicast addresses have the following format:

In the preceding address format, the fields have the following definition:

11111111

Identifies the address as multicast.

Flags

Can be either of the following values: 0000, which indicates a permanently-assigned (well-known) multicast address, or 0001, which indicates a nonpermanently-assigned (transient) multicast address.

Scope

Indicates the scope of the multicast group. The following table lists the scope values:

Value (Hex) Scope
1 Node-local
2 Link-local
5 Site-local
8 Organization-local
E Global

Group ID

Identifies the multicast group within the specified scope.

Table 9-1 lists some well-known multicast addresses.

Table 9-1:  Well-known Multicast Addresses

Multicast Address Meaning
FF02::1 All nodes (link-local)
FF02::2 All routers (link-local)
FF02::9 All RIPng routers (link-local)

9.1.3    Address Prefixes

Each IPv6 address has a unique pattern of leading bits that indicates its address type. These leading bits are named the Format Prefix. Table 9-2 lists some of the IPv6 address types and their prefixes.

Table 9-2:  IPv6 Address Types and Prefixes

Address Type Prefix
Aggregatable Global Unicast 2000::/3
Link-local FE80::/10
Site-local FEC0::/10
Multicast FF00::/8

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

  1. Application calls getipnodebyname and passes the host name, host1, the AF_INET6 address family, and the AI_DEFAULT flag. The flag tells the function that if an IPv4 address is found for host1, return it as an IPv4-mapped IPv6 address.

  2. The search finds an IPv4 address, 1.2.3.4, for host1 in the hosts database and getipnodebyname 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.

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-3 shows the sequence of events for an application that uses an AF_INET6 socket to send IPv6 packets.

Note

IPv6 communications is not currently supported. Any application that uses AF_INET6 sockets will be ready to communicate using IPv6 when it is supported.

Figure 9-3:  Using AF_INET6 Socket for IPv6 Communications

  1. Application calls getipnodebyname and passes the host name, host1, the AF_INET6 address family, and the AI_DEFAULT flag.

  2. The search finds an IPv6 address for host1 in the hosts database and getipnodebyname 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.3.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.2.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-3 summarizes the changes to make to your application's code:

Table 9-3:  Name Changes

Search file for: Replace with:
AF_INET AF_INET6
PF_INET PF_INET6
INADDR_ANY in6addr_any
inet_ntoa() inet_ntop()
inet_addr() inet_pton()

9.2.3    Making Structure Changes

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

The following sections discuss these changes.

9.2.3.1    in_addr Structure

Applications that use the in_addr structure must be changed 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.2.3.2    sockaddr_in Structure

Applications that use the 4.4 BSD sockaddr_in structure must be changed 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 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.2.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 the AF_INET6 sockaddr_in6 structure, as shown in the following examples:

AF_INET Structure AF_INET6 Structure

struct sockaddr [1]

struct sockaddr_in6 [1]

Make the following change in your application, as needed:

  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]

Note

A sockaddr_in6 structure is larger than a sockaddr structure.

9.2.4    Making Function Call Changes

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

The following sections discuss these changes.

9.2.4.1    gethostbyaddr Function Call

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

AF_INET Call

gethostbyaddr(xxx,4,AF_INET) [1]

AF_INET6 Call

hp=getipnodebyaddr(xxx,16,AF_INET6,&error_num[1]

.
.
.
freehostent(hp); [2]

Make the following changes in your application, as needed:

  1. Change the function name from gethostbyaddr to getipnodebyaddr, change the Internet address length parameter from 4 to 16, change the Internet domain address format from AF_INET to AF_INET6, and provide a pointer to an integer for the returned error number as the routine is thread safe. [Return to example]

  2. Add a call to the freehostent routine to free the hostent structure when your application is finished using it. [Return to example]

9.2.4.2    gethostbyname Function Call

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

AF_INET Call

gethostbyname(name) [1]

AF_INET6 Call

hp=getipnodebyname(name,AF_INET6,AI_DEFAULT,&error_num[1]

.
.
.
freehostent(hp); [2]

Make the following changes in your application, as needed:

  1. Change the function name from gethostbyname to getipnodebyname, provide the Internet domain address format AF_INET6, provide the flags parameter AI_DEFAULT, and provide a pointer to an integer for the returned error number as the routine is thread safe. [Return to example]

  2. Add a call to the freehostent routine to free the hostent structure when your application is finished using it. [Return to example]

9.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.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.2.5.5    Changing Socket Options

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

9.3    Sample Client/Server Programs

This section contains the following client and server code examples:

In addition, this section also contains sample output from the two programs.

9.3.1    Programs Using AF_INET Sockets

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

9.3.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, 1991, 1999      *
 * *                                                               *
 * *   All Rights Reserved.  Unpublished rights  reserved  under   *
 * *   the copyright laws of the United States.                    *
 * *                                                               *
 * *   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 ((serveraddr.sin_addr.s_addr = inet_addr(server)) == (u_int)-1) {
        if ((hp = gethostbyname(server)) == NULL) {  [3]
            printf("unknown host: %s\n", server);
            exit(2);
        }
        memcpy(&serveraddr.sin_addr.s_addr, hp->h_addr, hp->h_length);
    }
    serveraddr.sin_port = htons(SERVER_PORT);
    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { [4]
        perror("socket");
        exit(3);
    }
    bzero((char *)&clientaddr, sizeof(struct sockaddr_in)); [5]
    clientaddr.sin_family = AF_INET;
    clientaddr.sin_addr.s_addr = INADDR_ANY;
    clientaddr.sin_port = htons(CLIENT_PORT);
 
    if (bind(s, (struct sockaddr *)&clientaddr, sizeof(clientaddr)) < 0) {
        perror("bind");
        exit(4);
    }
    if (sendto(s, request, strlen(request), 0,
        (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { [6]
        perror("sendto");
        exit(5);
    }
    serveraddrlen = sizeof(serveraddr);
    dcount = recvfrom(s, databuf, sizeof(databuf), 0,
        (struct sockaddr *)&serveraddr, &serveraddrlen);
    if (dcount < 0) {
        perror("recvfrom");
        exit(6);
    }
    databuf[dcount] = '\0';
 
    hp = gethostbyaddr((char *)&serveraddr.sin_addr.s_addr, [7]
        sizeof(serveraddr.sin_addr.s_addr), AF_INET);
    ap = inet_ntoa(serveraddr.sin_addr);  [8]
    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. Clears the client address and sets up client variables. [Return to example]

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

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

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

9.3.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, 1991, 1999     *
 * *                                                               *
 * *   All Rights Reserved.  Unpublished rights  reserved  under   *
 * *   the copyright laws of the United States.                    *
 * *                                                               *
 * *   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_DGRAM, 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);
    }
 
    while (1) {
        clientaddrlen = sizeof(clientaddr);
        dcount = recvfrom(s, databuf, sizeof(databuf), 0,
            (struct sockaddr *)&clientaddr, &clientaddrlen);
        if (dcount <= 0) {
            perror("recvfrom");
            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 (sendto(s, response, strlen(response), 0, 
            (struct sockaddr *)&clientaddr, clientaddrlen) < 0) {
            perror("sendto");
            continue;
        }
    }
 
    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.3.2    Programs Using AF_INET6 Sockets

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

9.3.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, 1991, 1999      *
 * *                                                               *
 * *   All Rights Reserved.  Unpublished rights  reserved  under   *
 * *   the copyright laws of the United States.                    *
 * *                                                               *
 * *   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 sockaddr_in6    clientaddr;
    char                   addrbuf[INET6_ADDRSTRLEN];
    int                    error_num;
    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_in6)); [2]
    serveraddr.sin6_family = AF_INET6;
    if (inet_pton(AF_INET6, server, &serveraddr.sin6_addr) <= 0) {
        if ((hp = getipnodebyname(server,AF_INET6,AI_DEFAULT,&error_num)) == NULL) { [3]
            printf("unknown host: %s\n", server);
            exit(2);
        }
        memcpy(&serveraddr.sin6_addr, hp->h_addr, hp->h_length);
        freehostent(hp); [4]
    }
    serveraddr.sin6_port = htons(SERVER_PORT);
 
    if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { [5]
        perror("socket");
        exit(3);
    }
    bzero((char *)&clientaddr, sizeof(struct sockaddr_in6)); [6]
    clientaddr.sin6_family = AF_INET6;
    clientaddr.sin6_addr = in6addr_any;
    clientaddr.sin6_port = htons(CLIENT_PORT);
    if (bind(s, (struct sockaddr *)&clientaddr, sizeof(clientaddr)) < 0) {
        perror("bind");
        exit(4);
    }
    if (sendto(s, request, strlen(request), 0, 
        (struct sockaddr *)&serveraddr, sizeof(serveraddr)) < 0) { [7]
        perror("sendto");
        exit(5);
    }
    serveraddrlen = sizeof(serveraddr);
    dcount = recvfrom(s, databuf, sizeof(databuf), 0,
        (struct sockaddr *)&serveraddr, &serveraddrlen);
    if (dcount < 0) {
        perror("recvfrom");
        exit(6);
    }
    databuf[dcount] = '\0';
    hp = getipnodebyaddr((char *)&serveraddr.sin6_addr, [8]
        sizeof(serveraddr.sin6_addr), AF_INET6, &err);
    ap = inet_ntop(AF_INET6, (void *)&serveraddr.sin6_addr, [9]
        addrbuf, sizeof(addrbuf));
    printf("Response received from");
    if (hp != NULL)
        printf(" %s", hp->h_name);
    if (ap != NULL)
        printf(" (%s)", ap);
    printf(": %s\n", databuf);
 
    if (hp != NULL)
        freehostent(hp); [10]
    close(s);
}
 
 

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

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

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

  4. Frees the hostent structure. [Return to example]

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

  6. Clears the client address and sets up client variables. [Return to example]

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

  8. Calls getipnodebyaddr to obtain the server name. [Return to example]

  9. Calls inet_ntop to convert the server address to a text string [Return to example]

  10. Frees the hostent structure. [Return to example]

9.3.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, 1991, 1999      *
 * *                                                               *
 * *   All Rights Reserved.  Unpublished rights  reserved  under   *
 * *   the copyright laws of the United States.                    *
 * *                                                               *
 * *   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 sockaddr_in6   clientaddr;
    char                  addrbuf[INET6_ADDRSTRLEN];
    int                   error_num
    int                   clientaddrlen;
    struct hostent        *hp;
    const char            *ap;
    const char            *response = "this is the server's response";
    u_short               port;
 
    if ((s = socket(AF_INET6, SOCK_DGRAM, 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);
    }
 
    while (1) {
        clientaddrlen = sizeof(clientaddr);
        dcount = recvfrom(s, databuf, sizeof(databuf), 0,
            (struct sockaddr *)&clientaddr, &clientaddrlen);
        if (dcount <= 0) {
            perror("recvfrom");
            continue;
        }
        databuf[dcount] = '\0';
 
        hp = getipnodebyaddr((char *)&clientaddr.sin6_addr, [4]
            sizeof(clientaddr.sin6_addr), AF_INET6, &error_num);
        ap = inet_ntop(AF_INET6, (void *)&clientaddr.sin6_addr,
            addrbuf, sizeof(addrbuf));  [5]
        port = ntohs(clientaddr.sin6_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 (sendto(s, response, strlen(response), 0, 
            (struct sockaddr *)&clientaddr, clientaddrlen) < 0) {
            perror("sendto");
            continue;
        }
        if (hp != NULL)
            freehostent(hp); [6]
    }
 
    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. Calls getipnodebyaddr to retrieve the client name. [Return to example]

  5. Calls inet_ntop to convert the IPv6 address to a text string. [Return to example]

  6. Frees the hostent structure. [Return to example]

9.3.3    Sample Program Output

This section contains sample output from the server and client programs. The server program makes and receives all requests are 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"