February 28, 2021
Hot Topics:

Running IPv6 Code in Multiple Windows Environments

  • By Sanjay Narang
  • Send Email »
  • More Articles »


IPv6, or "Internet protocol Version 6," has been around for a long time now. It took a long time to reach the level of acceptance it has reached today, but its growth in terms of acceptance and popularity has been phenomenal. Many vendors are already supporting IPv6 in their products. Microsoft has been a little late in entering this field. There is no IPv6 support in older versions of Windows, such as Windows NT 4 or Windows 98. There is some support for Windows 2000, but that is just for experiments and is not a production quality implementation. But, Microsoft has started providing full support for IPv6 in its operating systems from Windows XP SP1 and Windows Server 2003 onwards.

This different level of support has created problems for vendors who support their IPv6 enabled products on multiple Windows environments. To make your code IPv6 enabled, you need to use new function calls and data structures introduced in Window Sockets v2 API. But, implementation of these new programming elements is available only in Windows XP SP1 or Windows Server 2003. Then, how can you run the same code on Windows 2000 platform?

This article addresses the above problem. It tells you how to use new IPv6 function calls in your code and run the same code seamlessly on Windows 2000, Windows XP, and Windows Server 2003. Microsoft handles this backward compatibility of newly introduced function calls in a very cryptic way that a normal programmer doesn't understand easily. In this article, I will show you what happens behind the scenes that makes the new function calls work even on platforms where these are not available.

Different Levels of IPv6 Support

As mentioned earlier, Microsoft does not provide support for IPv6 on all Windows platforms. The support in different versions of OS is given here:

  • Windows 95/98/Me/NT: no support
  • Windows 2000: non-production-quality support with IPv6 Technology Preview
  • Windows XP (SP1), Windows Server 2003, and later: Full support

Even in the supported platforms, IPv6 is not installed by default. If required, administrators need to install the IPv6 protocol manually on the system.

On Windows 2000 (with the IPv6 technology preview installed), the IPv6 routines are available in wship6.dll whereas on Windows XP (SP1) and Windows Server 2003 all the IPv6 routines are available in ws2_32.dll along with legacy winsock routines.

Newly Added Programming Elements

There are many implementations of sockets API available, but the two extensively used implementations across the industry are Windows Sockets and BSD sockets. The two implementations have very similar API and are compatible with each other to a great extent. But, we will not delve into that area and will concentrate only on Microsoft's implementation or Windows Sockets.

Also, I'll assume that you are using Visual C++ 7.0 or later to build your code for all the samples here. The header and library files of Visual C++ 6 environment do not contain the new function calls. So, you can not compile the code containing new function calls in a default VC6 environment. Although it is possible to compile the code in VC6 by including the newer header files, I'll not discuss that here.

Totally, there are nine new function calls and five new data structures that have been added to Windows Sockets for IPv6. You can see the list of these in the MSDN library. The purpose of this article is not to show you how to code for IPv6, but to show how the code written for IPv6 can also run on non-supported systems. So, I'll take an example of an often-used function call (among the newly added calls) and explain the solution with that.

This function call is getaddrinfo(). The official documentation describes this call as this: "The getaddrinfo function provides protocol-independent translation from host name to address." This call should be used in place of the gethostbyname() function call when writing IPv6 code. Apart from retrieving host information corresponding to a host name, the new getaddrinfo() call also performs the processing work of many functions. The lines of code necessary to perform the usual work of creating, opening, and then binding a socket can be significantly reduced by using this new call.

Building a Simple Program

To explain the process, I'll take following very simple program that only has a Winsock function, namely getaddrinfo():

Listing 1: Simple Program

#include <winsock2.h>
#include <ws2tcpip.h>
void main()
   char* serverName  = "server.domain.com";
   char* serviceName = "service_name";
   int retVal = getaddrinfo(serverName, serviceName, NULL, &AI);

The above program translates the given host name and service name to a protocol-independent network address and puts that information into an ADDRINFO structure. This structure then can be used to create a socket and perform operations such as connect. But, I will not show that here to keep the program simple.

Now, let us compile and link this program. To get it compiled, we included the header file ws2tcpip.h, which has the declaration of the getaddrinfo() call. To get it linked, we need to add the additional library ws2_32.lib to the linker list to resolve the getaddrinfo symbol.

Now, let us perform a dumpbin/imports on resulting executable. It shows the following output given in Listing 2 below. For simplicity sake I'm showing imports for WS2_32.dll only, but actual dumpbin ouput also has quite a few imports from KERNEL32.dll.

Listing 2: Output of dumpbin/imports (shortened)

Microsoft (R) COFF/PE Dumper Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file IPv6Article.exe


  Section contains the following imports:

                42D348 Import Address Table
                42D194 Import Name Table
                     0 time date stamp
                     0 Index of first forwarder reference

                      Ordinal    15
                      Ordinal    56
                      Ordinal    51
                      Ordinal    52
                      Ordinal   111
                      Ordinal    11
                      Ordinal     9
                      Ordinal    55
                      Ordinal     8
                      Ordinal    12

You will notice that there are total 10 imports from WS2_32.dll. Ten imports for just one function call—getaddrinfo()! How's that possible? To get the answer, let's first see what these functions are. As these are imported by ordinal numbers, we need to see the dumpbin exports of WS2_32.dll. They are shown in Listing 3. Again, for simplicity, I'm not showing calls with the WSA prefix, except just one call, WSAGetLastError, that is being used in our program.

Listing 3: Output of dumpbin/exports of WS2_32.dll (shortened)

Microsoft (R) COFF/PE Dumper Version 7.10.3077
Copyright (C) Microsoft Corporation.  All rights reserved.

Dump of file c:\windows\system32\ws2_32.dll

File Type: DLL

  Section contains the following exports for WS2_32.dll

    00000000 characteristics
    3B7DE11B time date stamp Sat Aug 18 08:59:31 2001
        0.00 version
           1 ordinal base
         500 number of functions
         114 number of names

    ordinal hint RVA      name
        111   1A 00001740 WSAGetLastError
          1   51 0000868D accept
          2   52 00003ECE bind
          3   53 00001A6D closesocket
          4   54 00003E5D connect
         94   55 00003A2C freeaddrinfo
         95   56 000033DF getaddrinfo
         51   57 0000D755 gethostbyaddr
         52   58 00002BBF gethostbyname
         57   59 000032CA gethostname
         96   5A 0000C076 getnameinfo
          5   5B 0000F628 getpeername
         53   5C 0000D24E getprotobyname
         54   5D 0000D1A2 getprotobynumber
         55   5E 0000D969 getservbyname
         56   5F 0000D850 getservbyport
          6   60 0000157E getsockname
          7   61 00004122 getsockopt
          8   62 000012A7 htonl
          9   63 00001746 htons
         11   64 000012F8 inet_addr
         12   65 0000401C inet_ntoa
         10   66 0000155A ioctlsocket
         13   67 00005DE2 listen
         14   68 000012A7 ntohl
         15   69 00001746 ntohs
         16   6A 00005690 recv
         17   6B 00001444 recvfrom
         18   6C 00001890 select
         19   6D 00001AF4 send
         20   6E 00001ED3 sendto
         21   6F 00003F8D setsockopt
         22   70 00008629 shutdown
         23   71 00003C22 socket

Now, matching the ordinal numbers from Listing 2 with those in Listing 3, we can find that our program uses the following functions:

Function Ordinal Number
ntohs 15
getservbyport 56
gethostbyaddr 51
bind 52
WSAGetLastError 111
inet_addr 11
htons 9
getservbyname 55
htonl 8
inet_ntoa 12

So, although we used a new function call that is introduced for IPv6, the linker is mapping that call to the legacy Winsock function calls that also were available for IPv4. How does this happen? We'll see that in later section. For now, we will find out the way to prevent it. In the next section, let's see how we target an IPv6 environment explicitly so that new IPv6 calls don't get mapped to legacy IPv4 calls.

Page 1 of 2

This article was originally published on July 19, 2004

Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Thanks for your registration, follow us on our social networks to keep up-to-date