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:
Address text representation
Types of addresses
Address prefixes
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
There are three types of IPv6 addresses:
Unicast
Anycast
Multicast
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:
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.
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.
Used in mixed IPv4 and IPv6 environments, and can be either of the following:
IPv4-compatible IPv6 address
Used by IPv6 nodes to tunnel IPv6 packets across an IPv4 routing infrastructure. The IPv4 address is carried in the low-order 32-bits. The format of this address is as follows:
IPv4-mapped IPv6 address
Used to represent an IPv4 address and to identify nodes that do not support IPv6 (IPv4-only nodes). It is not used in an IPv6 packet. The format of this address is as follows:
Can be either of the following:
Link-local
Used for addressing on a single link when performing address autoconfiguration, neighbor discovery, or when no routers are present. The format of this address is as follows:
Site-local
Used for sites or organizations that are not connected to the global Internet. The format of this address is as follows:
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.
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.
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 |
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) |
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:
Name changes
Structure changes
Miscellaneous changes
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
Application calls
gethostbyname
and passes
the host name,
host1
.
The search finds
host1
in the hosts database
and
gethostbyname
returns the IPv4 address
1.2.3.4
.
The application opens an
AF_INET
socket.
The application sends information to the
1.2.3.4
address.
The socket layer passes the information and address to the UDP module.
The UDP module puts the
1.2.3.4
address
into the packet header and passes the information to the IPv4 module for transmission.
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
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.
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
.
The application opens an
AF_INET6
socket.
The application sends information to the
::ffff:1.2.3.4
address.
The socket layer passes the information and address to the UDP module.
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
Application calls
getipnodebyname
and passes
the host name,
host1
, the
AF_INET6
address
family, and the
AI_DEFAULT
flag.
The search finds an IPv6 address for
host1
in the hosts database and
getipnodebyname
returns the IPv6
address
3ffe:1200::a00:2bff:fe2d:02b2
.
The application opens an
AF_INET6
socket.
The application sends information to the
3ffe:1200::a00:2bff:fe2d:02b2
address.
The socket layer passes the information and address to the UDP module.
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.
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:
in_addr
sockaddr_in
sockaddr
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:
Change the structure name
in_addr
to
in6_addr
.
[Return to example]
Change the data type from
unsigned
int
to
uint8_t
and the field name
s_addr
to
s6_addr
.
[Return to example]
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:
Change structure name
sockaddr_in
to
sockaddr_in6
.
[Return to example]
Change the data type
unsigned
char
to
uint8_t
and the field name
sin_len
to
sin6_len
.
[Return to example]
Change the field name
sin_family
to
sin6_family
.
[Return to example]
Change the field name
sin_port
to
sin6_port
.
[Return to example]
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:
Change structure name
sockaddr_in
to
sockaddr_in6
.
[Return to example]
Change the field name
sin_family
to
sin6_family
.
[Return to example]
Change the field name
sin_port
to
sin6_port
.
[Return to example]
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.
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:
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 asockaddr
structure.
9.2.4 Making Function Call Changes
You must make changes to applications that use the following library routines:
gethostbyaddr
gethostbyname
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]
|
Make the following changes in your application, as needed:
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]
Add a call to the
freehostent
routine to free the
hostent
structure when your
application is finished using it.
[Return to example]
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]
|
Make the following changes in your application, as needed:
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]
Add a call to the
freehostent
routine to free the
hostent
structure when your
application is finished using it.
[Return to example]
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]
|
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]
|
Change the equality expression to one that
uses the
IN6_ARE_ADDR_EQUAL
macro.
[Return to example]
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]
|
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]
|
Change the equality expression to one that
uses the
memcmp
(memory comparison) function.
[Return to example]
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]
|
struct in6_addr foo; struct in6_addr bar; [1]
|
Change the data type for
bar
from
int
to a
struct in6_addr
.
[Return to example]
Change the assignment statement for
bar
to remove the
s_addr
field reference.
[Return to example]
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]
|
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]
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:
AF_INET sockets programs
Client
Server
AF_INET6 sockets programs
Client
Server
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); }
Declares
sockaddr_in
structures.
[Return to example]
Clears the server address and sets up server variables. [Return to example]
Calls
gethostbyname
to obtain the server
address.
[Return to example]
Creates an AF_INET socket. [Return to example]
Clears the client address and sets up client variables. [Return to example]
Sends a request to the server. [Return to example]
Calls
gethostbyaddr
to retrieve the server
name.
[Return to example]
Calls
inet_ntoa
to convert the server address
to a text string.
[Return to example]
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); }
Declares
sockaddr_in
structures.
[Return to example]
Creates an AF_INET socket. [Return to example]
Clears the server address and sets up server variables. [Return to example]
Calls
gethostbyaddr
to retrieve the client
name.
[Return to example]
Calls
inet_ntoa
to convert the client address
to a text string.
[Return to example]
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); }
Declares
sockaddr_in6
structures, address
string buffer, and error number variable.
[Return to example]
Clears the server address and sets up server variables. [Return to example]
Calls
getipnodebyname
to obtain the server
address.
[Return to example]
Frees the
hostent
structure.
[Return to example]
Creates an AF_INET6 socket. [Return to example]
Clears the client address and sets up client variables. [Return to example]
Sends a request to the server. [Return to example]
Calls
getipnodebyaddr
to obtain the server
name.
[Return to example]
Calls
inet_ntop
to convert the server address
to a text string
[Return to example]
Frees the
hostent
structure.
[Return to example]
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); }
Declares
sockaddr_in6
structures, address
string buffer, and error number variable.
[Return to example]
Creates an AF_INET6 socket. [Return to example]
Clears the server address and sets up the server variables. [Return to example]
Calls
getipnodebyaddr
to retrieve the client
name.
[Return to example]
Calls
inet_ntop
to convert the IPv6 address
to a text string.
[Return to example]
Frees the
hostent
structure.
[Return to example]
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"