Appendix B
This appendix includes information on changes that have been made to the Windows Sockets API to support IPv6 applications. The following topics are discussed:
Examples of how and when to utilize these changes in an application are discussed. Additional details can be found on the Microsoft Developer Network web site at http://msdn.microsoft.com.
A new address family name for IPv6 is required so that the address structure can be correctly identified and parsed. Similarly, a new protocol family name (with the same value as the address family name) must be defined so that a socket is created using the appropriate protocol. The address family name and protocol family name constants for IPv6 are:
The term sockets defines a protocol-specific data structure that holds elements of a socket address. For IPv4, this structure is sockaddr_in. Sockets also defines a protocol-independent structure (sockaddr) for the protocol-specific structures to be cast into. The identifying field (the address family) in the protocol-specific structure overlays the family field in the generic structure. Because IPv6 addresses are different than IPv4 addresses, a new protocol-specific structure for IPv6 is required.
The data structures sockaddr and sockaddr_in are the same size which could lead one into making incorrect assumptions about the size of their related address structures. The IPv6 address structure, sockaddr_in6, is larger by necessity. For example, the sockaddr structure cannot be used to allocate storage for sockaddr_in6. This is discussed in more detail below.
struct in6_addr { union { u_char Byte[16]; ushort Word[8]; } u; };
The socket address structure contains information above and beyond the address for the socket. One portion of the structure, however, must be the address. In IPv4's address structure, this address is contained in in_addr. A larger structure, in6_addr, has been defined to hold the larger IPv6 address.
In addition to the larger address size, there are other members that must be represented in the socket address structure for IPv6. Although the IPv4 sockaddr_in structure has unused space, it is not enough to contain this additional information. The sockaddr_in6 structure is used to contain an IPv6 address.
struct sockaddr_in6 { sa_family_t sin6_family; in_port_t sin6_port; uint32_t sin6_flowinfo; struct in6_addr sin6_addr; uint32_t sin6_scope_id; };
In addition to the family, port, and address information, this structure contains sin6_flowinfo and sin6_scope_id members. sin6_flowinfo is intended to contain the traffic class and flow label from and for the IPv6 header. sin6_flowinfo is not supported in Windows XP and the Windows .NET Server 2003 family. sin6_scope_id contains the scope ID, which is used to identify a set of interfaces that are appropriate for the address carried in the address field.
As mentioned earlier, sockaddr and sockaddr_in6 have different sizes. Because of this, struct sockaddr cannot be used to allocate storage and then be cast to a sockaddr_in6 pointer. If static allocation of storage for sockaddr_in6 (or even sockaddr_in) structures is needed, struct sockaddr_storage should be used. Here is an example:
struct sockaddr_storage newaddr; ... msgsock = accept(listen_socket,(struct sockaddr*)&newaddr, &newaddrlen);
In addition to being large enough to accommodate all known protocol-specific socket address structures (including sockaddr_in6), sockaddr_storage is aligned at an appropriate boundary so that protocol-specific socket address data-structure pointers can be cast to it, enabling it to access fields without experiencing alignment problems.
To allow the protocol implementation to choose the source address for a connection or datagram with IPv4, a constant of INADDR_ANY (the wildcard address) is used as the address in the bind() call.
The IPv6 address type (in6_addr) is a structure. A constant cannot be used in an assignment for this variable, but can be used to initialize the structure. Thus, we end up with two possible ways to provide the wildcard address.
The global variable, in6addr_any, can be used in an assignment. For example:
sin6.sin6_addr = in6addr_any;
Or the constant, IN6ADDR_ANY_INIT, can be used to initialize the address structure (at declaration time only). For example:
struct in6_addr anyaddr = IN6ADDR_ANY_INIT;
Similarly, the INADDR_LOOPBACK constant is used in IPv4 connect(), send(), and sendmsg() calls to communicate with services that reside on the local node. For IPv6 loopback, a global variable (in6addr_loopback) is used for assignment and a constant (IN6ADDR_LOOPBACK_INIT) is used for initialization at declaration time.
The IPv4 INADDR_XXX constants were defined in host-byte order. The IPv6 equivalents are defined in network-byte order.
An address is passed in core Sockets functions as an opaque address pointer and length. Because of this, changes need not be made to these core Sockets functions for IPv6. The application developer needs simply to supply the appropriate IPv6 address structure and family constants.
Sockets functions that pass addresses are the following:
Sockets functions that return addresses are the following:
To resolve a host name to one or more IP addresses in IPv4, the application might use gethostbyname(). This API does not allow the caller to specify anything about the types of addresses wanted and the structure contains only enough space to store an IPv4 address. To address these issues, a new API named getaddrinfo() is introduced with IPv6. This API is protocol-independent and can be used for both IPv4 and IPv6 name-to-address resolutions. The return from this call is in the form of addrinfo structures that can subsequently be used to both open and use a socket.
The function prototype for getaddrinfo() is the following:
int getaddrinfo( IN const char FAR *nodename, IN const char FAR *servname, IN const struct addrinfo FAR *hints, OUT struct addrinfo FAR *FAR *res ); struct addrinfo { int ai_flags; int ai_family; int ai_socktype; int ai_protocol; size_t ai_addrlen; char *ai_canonname; struct sockaddr *ai_addr; struct addrinfo *ai_next; };
As arguments, either a node name or service name (or both) are provided. The node name can (optionally) be a numeric address string and the service name can (optionally) be a decimal port number. An addrinfo structure can be provided (optionally) to provide hints for the type of socket that the caller supports. The addrinfo structure pointed to by this hints parameter can specify a preferred socket type, family and protocol, and the following flags:
This flag indicates that the caller plans to use the returned address structure in a bind() call when set, or a connect() call when not set. Setting the node name to NULL has additional meaning depending on this flag. If the node name in the hints is NULL, and this flag is set, the returned addresses will be wildcard addresses. If the node name in the hints is NULL, and this flag is not set, the returned addresses will be loopback addresses.
The AI_CANONNAME flag indicates (when set) that the first addrinfo structure returned should contain a null-terminated string that contains the canonical name of the node name in the ai_canonname member.
This flag indicates that the nodename in the call is a numeric address string.
If the address family specified is AF_INET6, the caller will accept IPv4-mapped IPv6 addresses. The IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support the use of IPv4-mapped addresses.
Used with the AI_V4MAPPED flag to indicate that the caller would like all addresses, both true IPv6 addresses and IPv4-mapped IPv6 addresses. The address family specified must be AF_INET6. The IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support the use of this flag.
The AI_ADDRCONFIG flag controls whether the query requests AAAA DNS records or A records, based on the locally configured source addresses. AAAA records will be queried only if the node has at least one IPv6 source address. A records will be queried only if the node has at least one IPv4 source address.
A pointer to a linked list of addrinfo structures is returned. The order of the addresses is in decreasing order of desirability.
The addrinfo structures (and structures contained as members within those structures) are dynamically allocated and must be released by calling freeaddrinfo() with a pointer to the linked list of addrinfo structures.
The function prototype for freeaddrinfo() is the following:
void freeaddrinfo( struct addrinfo FAR *ai );
A reverse lookup can be performed by using another new Sockets function, getnameinfo(). To use this API, a socket address structure is provided. The function prototype for getnameinfo() is the following:
int getnameinfo( IN const struct sockaddr FAR *sa, IN socklen_t salen, OUT char FAR *host, IN size_t hostlen, OUT char FAR *serv, IN size_t servlen, IN int flags );
It contains the address and port in question. This can be either an IPv4 or IPv6 socket address structure because the length is also provided.
Additionally, buffers are provided to receive the node name and service name associated with that address, and the flags field can be used to change the default behavior of the API. The lengths of these buffers are provided in the call, and constants are defined (NI_MAXHOST, NI_MAXSERV) to aid the application in allocating buffers of the maximum size required.
The flags adjust the behavior as follows:
Setting the NI_NOFQDN flag results in returning only the node name (not the fully qualified domain name, or FQDN) for local hosts.
Setting this flag results in returning the numeric form of the host's address instead of its name.
Setting the NI_NAMEREQD flag results in returning an error if the name cannot be located.
Setting NI_NUMERICSERV results in returning the numeric port number instead of the service name.
Setting this flag specifies that the service is a datagram service, causing a search for a UDP service (instead of a TCP service).
Here is an example of a client application using getaddrinfo() to connect to a specific server:
{/* Client Side...*/} if (getaddrinfo(service_name, port, NULL, &ai) != 0) {/* Error Handling */} conn_socket = socket(ai->ai_family, ai->ai_socktype,ai->ai_protocol); if (conn_socket <0 ) {/* Error Handling */} if (connect(conn_socket,ai->ai_addr,ai->ai_addrlen) == SOCKET_ERROR) {/* Error Handling */} freeaddrinfo(ai);
For an example of an application that checks each address returned, see the white paper titled "Adding IPv6 Capability to Windows Sockets Applications" in the \White_Papers folder on the companion CD-ROM.
Here is an example of the corresponding server application using getaddrinfo() to resolve the address information for the socket creation and bind calls:
{/* Server Side... */} hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE; retval = getaddrinfo(interface, port, &hints, &ai); if (retval != 0) {/* Error Handling */} listen_socket = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (listen_socket == INVALID_SOCKET){/* Error Handling */} if (bind(listen_socket,ai->ai_addr,ai->ai_addrlen )== SOCKET_ERROR) {/* Error Handling */} freeaddrinfo(ai);
The interface parameter in this call could be NULL, or could be set to a numeric string.
The inet_addr() and inet_ntoa() functions are provided to convert IPv4 addresses between binary and text formats. The IETF defined the similar functions, inet_pton() and inet_ntop(), to convert both IPv4 and IPv6 addresses. These functions contain an additional address family argument to make them protocol-independent.
Because getaddrinfo() and getnameinfo() provide the same functionality, the IETF is in the process of deprecating the inet_pton() and the inet_ntop() functions. As a result, the IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support the inet_pton() and the inet_ntop() functions.
A new socket option level, IPPROTO_IPV6, has been defined for IPv6-specific socket options. Although an application can send multicast UDP packets by specifying a multicast address in sendto(), most of the new socket options currently defined for IPv6 are intended to adjust multicast behavior. New socket options are the following:
This option sets the default interface to use for outgoing multicast traffic to the interface indicated by the index specified in the argument (0 indicates that the system chooses the interface).
This option sets the hop limit for outgoing multicast packets based on the argument. Valid values are either 0 to 255 inclusive or -1 (to use the system default).
This option controls whether outgoing multicast packets addressed to a group, of which the interface is a member, is looped back.
For reception of multicast traffic, new options are defined to join and leave multicast groups. These options take an argument of an ipv6_mreq structure:
struct ipv6_mreq { struct in6_addr ipv6mr_multiaddr; unsigned int ipv6mr_interface; };
This structure contains the multicast address of the group to be joined or left, and an interface index to use for this join or leave.
New multicast socket options are:
This option is used to join the specified multicast group on the interface indicated (0 indicates that the system chooses the interface).
The IPV6_LEAVE_GROUP option is used to leave the specified group on the interface indicated.
In addition, another socket option, IPV6_UNICAST_HOPS, is defined to control the hop limit for outgoing unicast packets.
The additions to Windows Sockets that support IPv6 include the following set of macros to test addresses and determine whether they are special IPv6addresses:
The first seven macros return a true value if the address is of the specified type. The last five test the scope of a multicast address, returning a true value if the address is a multicast address of the specified scope and a false value if the address is either not a multicast address or is not of the specified scope.
The IN6_IS_ADDR_V4MAPPED macro can be use to determine whether the destination address for a socket is an IPv4 node. IPv4-mapped addresses are not supported by the IPv6 protocol for Windows XP and the Windows .NET Server 2003 family.
The following are APIs that are currently specified in RFC 2553 or RFC 2292 that the IPv6 protocol for Windows XP and the Windows .NET Server 2003 family does not support:
RFC 2553 - "Basic Socket Interface Extensions for IPv6"
RFC 2292 - "Advanced Sockets API for IPv6"