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:
Name changes
Structure changes
Miscellaneous changes
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
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 (Send)
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.
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.
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.
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)
The application opens an
AF_INET6
socket
, binds to it, and listens on it.
An IPv4 packet arrives and passes through the IPv4 module.
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.
The application calls
accept
and retrieves
the information from the socket.
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.
The search finds the host name for the
1.2.3.4
address in the
hosts
database and
getnameinfo
returns the host name.
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
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.
The search finds an IPv6 address for
host1
in the hosts database and
getaddrinfo
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.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:
in_addr
sockaddr_in
sockaddr
hostent
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:
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, 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:
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, 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:
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_in6structure 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 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]
|
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]
|
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_in6andsockaddr_storagestructures are larger than asockaddrstructure.
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:
Change the structure name
hostent
to
addrinfo.
[Return to example]
You must make changes, as needed, to applications that use the following library routines:
gethostbyaddr
gethostbyname
inet_ntoa
inet_addr
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:
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]
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]
|
Make the following changes in your application, as needed:
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]
Add a call to the
freeaddrinfo
routine to free the
addrinfo
structure or structures
when your application is finished using them.
[Return to example]
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:
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]
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]
|
Make the following changes in your application, as needed:
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]
Add a call to the
freeaddrinfo
routine to free the
addrinfo
structure or structures
when your application is finished using them.
[Return to example]
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]
|
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.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]
|
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.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]
|
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.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]
|
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.2 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
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);
}
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]
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, 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);
}
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.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);
}
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]
Clears the
hints
structure and sets up hints
variables.
[Return to example]
Calls
getaddrinfo
to obtain the server address.
[Return to example]
Creates an AF_INET6 socket. [Return to example]
Frees all
addrinfo
structures.
[Return to example]
Sends a request to the server. [Return to example]
Calls
getnameinfo
to obtain the server name.
[Return to example]
Calls
getnameinfo
to obtain the server's
numeric address and message data.
[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, 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);
}
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]
Clears the client address. [Return to example]
Calls
getnameinfo
to retrieve the client
name.
[Return to example]
Calls
getnameinfo
to obtain the client's
address.
port, and message data.
[Return to example]
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 hosta6Response 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>./serverRequest 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 hostaResponse 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>./serverRequest 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 hostaResponse 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>./serverRequest received from hostc.corp.example (::ffff:10.10.10.63) port 7739 "this is the client's request"