How to upgrade WinSock application to support IPv6

How to upgrade WinSock application to support IPv6

tags:
Makoto Ookawa
Microsoft Asia Limited
Developer Support Division
Windows development technology group




Overview of WinSock Applications

Windows XP supports WinSock 1.1 and later. In order to maintain compatibility, API (Application Programming Interface) provided by WinSock 1.1 has functions with the same name as those used by Socket communication in BSD (Berkeley Software Distribution) UNIX. WinSock 2.0 and later provide Windows native API suited for Windows Platform (Windows native WinSock 2.0 also provides extended functions for socket communication, but we will not discuss these extended functions in this article). For developing applications that supports IPv6, we will be using WinSock version 2.0 or later.

WinSock applications communicate using server-client model. WinSock offers two types of transport service, connection-oriented and connectionless. In general, connection-oriented communication is associated with TCP (Transmission Control Protocol) and connectionless communication is associated with UDP (User Datagram Protocol). The rest of the article will explain how to upgrade connection-oriented application from IPv4 to IPv6.


Environment required for the development of WinSock application

In order to use the sample codes mentioned here and develop WinSock application, you will need the following tools.


Compiler and linker

This needs to be a compiler and a linker that supports X86 architecture.
Example: Visual C++, Visual Studio 6.0, and Visual Studio.NET


Platform SDK

Header files and libraries necessary for making WinSock applications are available as Platform SDK. Platform SDK can be installed using CD-ROM/DVD-ROM distributed by MSDN (Microsoft Developer Network), or you can install the latest version via network from the following URL.

Windows SDK (Core SDK)
http://www.microsoft.com/msdownload/
platformsdk/sdkupdate/




Configuration of Connection-Oriented IPv4 application

In a typical WinSock application using server-client model, WinSock functions will be called in a following sequence (See Figure 1).

Figure 1 (in the case of IPv4)
Figure 1 (in the case of IPv4)

Processing at the server side
  1. Load WinSock related DLLs onto the process in order to use WinSock.
    API:FWSAStartup()
  2. Create a socket for the communication
    API:Fsocket()
  3. Bind the socket to the IP address of the server
    AP:Fbind()
  4. Listen for incoming connections from clients
    API:Flisten()
  5. Accept the connection from the client
    API:Faccept()
  6. Send and receive data to/from the client that has established the connection
    API:Fsend() / recv()
  7. Shutdown the communication with the client
    API:Fshutdown()
  8. Close the socket that was used for the communication with the client
    API:Fclosesocket()
  9. Unload WinSock related DLLs from the application
    API:FWSACleanup()
Processing on the client side
  1. Load WinSock related DLLs onto the process in order to use WinSock
    API:FWSAStartup()
  2. Retrieve the name and address of the server you want to connect to.
    API:Fgethostbyname() , or gethostbyaddr()
  3. Create a socket for the communication
    API:Fsocket()
  4. Issue connection request to the server
    API:Fconnect()
  5. Send and receive data to/from the server that established the connection
    API:Fsend() / recv()
  6. Shutdown the communication with the server
    API:Fshutdown()
  7. Close the socket that was used for the communication with the client (server?)
    API:Fclosesocket()
  8. Unload WinSock related DLLs from the application
    API:FWSACleanup()
For the source code, please refer to the sample codes on the following URL Microsoft provides a tool called checkv4.exe, in order to facilitate smooth transformation of IPv4 sample codes, such as those shown in this article, to IPv6 sample codes. This checkv4.exe produces instructions that specify which lines of the source code of the program written for IPv4 need to be fixed, and how it should be fixed. By following the instructions and fixing the code, you can migrate the application from IPv4 to IPv6. Following is a copy of the output produced when checkv4.exe was actually used on the sample server code shown in the above URL (Please see Figure 2). checkv4.exe is included in the latest version of Platform SDK. If you installed Platform SDK on C drive, checkv4.exe tool should be installed in the following folder. (?)

Figure 2
Example of the output of checkv4.exe
simples.c(28) :
INADDR_ANY : use getaddrinfo with nodename=NULL and AI_PASSIVE instead, or use in6addr_any in addition for IPv6 support
simples.c(41) : sockaddr_in : use sockaddr_storage instead, or use sockaddr_in6 in addition for IPv6 support
simples.c(86) : AF_INET : use AF_INET6 in addition for IPv6 support
simples.c(87) : INADDR_ANY : use getaddrinfo with nodename=NULL and AI_PASSIVE instead, or use in6addr_any in addition for IPv6 support
simples.c(87) : inet_addr : use WSAStringToAddress or getaddrinfo with AI_NUMERICHOST instead
simples.c(94) : AF_INET : use AF_INET6 in addition for IPv6 support
simples.c(144) : inet_ntoa : use WSAAddressToString or getnameinfo with NI_NUMERICHOST instead
simples.c(163) : inet_ntoa : use WSAAddressToString or getnameinfo with NI_NUMERICHOST instead

< Explanation >
Line 28:
You can ignore this part since this refers to fprintf’s INADDR_ANY
Line 41: Use sockaddr_storage structure instead of sockaddr_in structure
Line 86: For address family, use AF_INET6 instead of AF_INET
Line 87: Do not use INADDR_ANY. Use getaddrinfo function, and set its first parameter to NULL, and set ai_frags of the third parameter, addrinfo structure, to AI_PASSIVE. Alternatively you can use in6addr_any structure.

Do not use inet_ntoa function. Use WSAStringToAddress function instead. Alternatively, you can use getaddrinfo function, and set ai_flags of the third parameter, addrinfo structure, to AI_NUMERICHOST.
Line 94: For address family, use AF_INET6 instead of AF_INET.
Line 144: Do not use inet_ntoa function. Use WSAStringToAddress function instead. Alternatively, use getaddrinfo function and set ai_flags of the third parameter, addrinfo structure, to AI_NUMBERICHOST.
Line 163: Do not use inet_ntoa function. Use WSAStringToAddress function instead. Alternatively, use getaddrinfo function and set ai_flags of the third parameter, addrinfo structure, to AI_NUMBERICHOST.

The flow of the IPv6 application created by following the instructions produced by checkv4.exe will be as follows. (Please see Figure 3)

Processing on the server side (IPv6)
  1. Load WinSock related DLLs to the process in order to use WinSock.
    API:WSAStartup()
  2. Obtain address information to resolve the IPv6 address
    API:getaddrinfo()
  3. Create a socket for the communication.
    API:socket()
  4. Bind the socket to the IP address of the server
    API:bind()
  5. Listen for incoming connections from clients.
    API:listen()
  6. Free the obtained address information.
    API:freeaddrinfo()
  7. Accept the connection from the client.
    API:accept()
  8. Send and receive data to/from the client that established the connection.
    API:send() / recv()
  9. Shutdown the communication with the client.
    API:shutdown()
  10. Close the socket that was used for the communication with the client.
    API:closesocket()
  11. Unload WinSock related DLLs from the application.
    API:WSACleanup()
Processing on the client side (IPv6)
  1. Load Winsock related DLLs to the process in order to use WinSock.
    API:WSAStartup()
  2. Get address information regarding the server you want to connect.
    API:getaddrinfo()
  3. Build a socket for the communication.
    API:socket()
  4. Issue a connection request to the server.
    API:connect()
  5. Free address information obtained.
    API:Ffreeaddrinfo()
  6. Send and receive data to/from the server that established the connection.
    API:send() / recv()
  7. Shutdown the communication with the server.
    API:shutdown()
  8. Close the socket used for the communication with the client (server?).
    API:closesocket()
  9. Unload WinSock related DLLs from the application.
    API:WSACleanup()
We put up a copy of the server application sample code that we modified according to the instructions produced by checkv4.exe. Please use this sample to verify the usage of the functions that support IPv6 (Please see Figure 6). A copy of the sample code, and the sample code for the client application can be found at the following URL.
Figure 3(In the case of IPv6)
Figure 3(In the case of IPv6)

I hope the above explanations helped you grasp the overall flow of modifying the IPv4 application into IPv6 application.

The readers who are actually planning to write applications are probably thinking of writing ones that can function in both IPv4 and IPv6 environment. So I would like to introduce you a simple sample code that will tell you which protocol stack is installed in the OS. The sample shown in Figure 7 first tries to obtain information regarding the protocol supported by each network interface using IPv6 options. If it fails to obtain protocol information using IPv6, it switches to IPv4 and try to obtain the information. By checking the protocol family of the network interface, it is possible to find out whether IPv6 protocol stack is installed in the Windows XP the application is running on. Putting this type of process inside the application will allow that application to support both protocol stacks smoothly.


Newly registered functions

New functions and data structures were added to support IPv6, and these are used in the sample code shown above. (Please see Figure 4 and 5)

Addrinfo structure obtained using getaddrinfo function must be freed using freeaddrinfo function. Because of this, repeated use of getaddrinfo function in the loop or in multiple threads should be avoided. Every time you call getaddrinfo function, memory for addrinfo structure will be allocated. After the call you must use freeaddrinfo function to free the memory that was allocated.
For the detailed explanation of these functions please refer to MSDN, or the following URLs.

Windows Sockets Functions
http://msdn.microsoft.com/library/default.asp?url=
/library/en-us/winsock/winsock
/windows_sockets_functions_2.asp


Internet Protocol Helper
http://msdn.microsoft.com/library/default.asp?url=
/library/en-us/iphlp/iphlp
/ip_helper_start_page.asp



Summary

As you can see from the IPv6 version of the sample code, you can easily modify IPv4 application to support IPv6 just by changing the name resolution (address resolution) procedures. Furthermore, functions and data structures newly added to support IPv6 can also support IPv4, and it is possible to support both addressing modes by using these functions and data structures. In this article we intentionally avoided the detailed explanations of the implementation of IPv6 at the TCP/IP stack of Windows XP.

The reason for this omission is that actual processing of IPv6 protocol is all performed by TCP/IP driver in the lower layer, and WinSock applications at the higher layer do not need to worry about the details regarding TCP/IP stack. For detailed information on the implementation of IPv6 in Windows XP, please refer to the following URL.

Figure 4
Newly added functions

int getaddrinfo(
const char* nodename,
const char* servname,
const struct addrinfo* hints,
struct addrinfo** res
);
Replaces gethostbyname function used in IPv4 for name resolution. Can support both IPv4 and IPv6.
void freeaddrinfo(
struct addrinfo* ai
);
Free addrinfo structure obtained by getaddrinfo function.
int getnameinfo(
const struct sockaddr* sa,
socklen_t salen,
char* host,
DWORD hostlen,
char* serv,
DWORD servlen,
int flags
);

Replaces gethostbyaddr function used in IPv4 for name resolution. Can support both IPv4 and IPv6.

DWORD WINAPI GetAdaptersAddresses(
ULONG Family,
DWORD Flags,
PVOID Reserved,
PIP_ADAPTER_ADDRESSES pAdapterAddresses,
PULONG pOutBufLen
);

Obtain IP address assigned to network adapters. Can support both IPv4 and IPv6.


Figure 5
Newly added structure

typedef 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;
} addrinfo;
Newly added structures for getaddrinfo function.
typedef struct sockaddr_storage {
short ss_family;
char __ss_pad1[_SS_PAD1SIZE];
__int64 __ss_align;
char __ss_pad2[_SS_PAD2SIZE];
} SOCKADDR_STORAGE, *PSOCKADDR_STORAGE;
Replaces sockaddr_in structure used in IPv4. Can support both IPv4 and IPv6.


Coexistence of IPv4 and IPv6, and migration from IPv4 to IPv6.
http://www.microsoft.com/japan/windowsxp
/pro/techinfo/administration/ipv6/ipv6ipv4.asp


How IPv6 is configured in Windows XP and IPv6 test laboratory
http://www.microsoft.com/japan/windowsxp
/pro/techinfo/administration/ipv6/ipv6configs.asp


Internet protocol version 6: Request for Comments and Internet draft
http://www.microsoft.com/japan/windowsxp
/pro/techinfo/administration/ipv6/ipv6rfc.asp


FAQ regarding Windows XP IPv6 protocol
http://www.microsoft.com/japan/windowsxp
/pro/techinfo/administration/ipv6/default.asp


Networking and Wireless Technologies
http://www.microsoft.com/hwdev/tech/network/default.asp

Finally, the following site is not a Microsoft Web site, but contains various information regarding WinSock application development. Please use it as a reference when developing the application.

Reference site

WinSock Development Information
http://www.sockets.com

Figure 6
Sample server code that supports IPv6

Error processing
#define WIN32_LEAN_AND_MEAN
#include <winsock2.h>
#include <ws2tcpip.h>
#ifndef IPPROTO_IPV6
#include <tpipv6.h> // For IPv6 Tech Preview.
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>#define DEFAULT_FAMILY PF_UNSPEC // Can support both IPv4 and IPv6
#define DEFAULT_SOCKTYPE SOCK_STREAM // TCP
#define DEFAULT_PORT "5001"
#define BUFFER_SIZE 64
void Usage(char *ProgName) {
fprintf(stderr, "¥nSimple socket sample server program.¥n");
fprintf(stderr, "¥n%s [-f family] [-t transport] [-p port] [-a address]¥n¥n",ProgName);
fprintf(stderr, " family¥tOne of PF_INET, PF_INET6 or PF_UNSPEC. (default %s)¥n",
(DEFAULT_FAMILY == PF_UNSPEC) ? "PF_UNSPEC" :
((DEFAULT_FAMILY == PF_INET) ? "PF_INET" : "PF_INET6"));
fprintf(stderr, " transport¥tEither TCP or UDP. (default: %s)¥n",
(DEFAULT_SOCKTYPE == SOCK_STREAM) ? "TCP" : "UDP");
fprintf(stderr, " port¥t¥tPort on which to bind. (default %s)¥n",
DEFAULT_PORT);
fprintf(stderr, " address¥tIP address on which to bind. (default: unspecified address)¥n");
WSACleanup();
exit(1);
}
LPSTR DecodeError(int ErrorCode)
{
static char Message[1024];
// Display error message
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, ErrorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPSTR)Message, 1024, NULL);
return Message;
}

Sample code for the server
Main processing

int main(int argc, char **argv)
{
char Buffer[BUFFER_SIZE], Hostname[NI_MAXHOST];
int Family = DEFAULT_FAMILY;
int SocketType = DEFAULT_SOCKTYPE;
char *Port = DEFAULT_PORT;
char *Address = NULL;
int i, NumSocks, RetVal, FromLen, AmountRead;
SOCKADDR_STORAGE From;
WSADATA wsaData;
ADDRINFO Hints, *AddrInfo, *AI;
SOCKET ServSock[FD_SETSIZE];
fd_set SockSet;
if (argc > 1) {
for(i = 1;i < argc; i++) {
if ((argv[i][0] == '-') || (argv[i][0] == '/') && (argv[i][1] != 0) && (argv[i][2] == 0)) {
switch(tolower(argv[i][1])) {
case 'f':
if (!argv[i+1])
Usage(argv[0]);
if (!stricmp(argv[i+1], "PF_INET"))
Family = PF_INET;
else if (!stricmp(argv[i+1], "PF_INET6"))
Family = PF_INET6;
else if (!stricmp(argv[i+1], "PF_UNSPEC"))
Family = PF_UNSPEC;
else
Usage(argv[0]);
i++;
break;
case 't':
if (!argv[i+1])
Usage(argv[0]);
if (!stricmp(argv[i+1], "TCP"))
SocketType = SOCK_STREAM;
else if (!stricmp(argv[i+1], "UDP"))
SocketType = SOCK_DGRAM;
else
Usage(argv[0]);
i++;
break;
case 'a':
if (argv[i+1]) {
if (argv[i+1][0] != '-') {
Address = argv[++i];
break;
}
}
Usage(argv[0]);
break;
case 'p':
if (argv[i+1]) {
if (argv[i+1][0] != '-') {
Port = argv[++i];
break;
}
}
Usage(argv[0]);
break;
default:
Usage(argv[0]);
break;
}
} else
Usage(argv[0]);
}
}
// WinSock 2.2
if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
fprintf(stderr, "WSAStartup failed with error %d: %s¥n", RetVal, DecodeError(RetVal));
WSACleanup();
return -1;
}
if (Port == NULL) {
Usage(argv[0]);
}
memset(&Hints, 0, sizeof(Hints));
Hints.ai_family = Family;
Hints.ai_socktype = SocketType;
Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
RetVal = getaddrinfo(Address, Port, &Hints, &AddrInfo);
if (RetVal != 0) {
fprintf(stderr, "getaddrinfo failed with error %d: %s¥n", RetVal, gai_strerror(RetVal));
WSACleanup();
return -1;
}
//  Select and sort the obtained address information
for (i = 0, AI = AddrInfo; AI != NULL; AI = AI->ai_next, i++) {
if (i == FD_SETSIZE) {
printf("getaddrinfo returned more addresses than we could use.¥n");
break;
}
// This sample only supports PF_INET and PF_INET6
if ((AI->ai_family != PF_INET) && (AI->ai_family != PF_INET6))
continue;
ServSock[i] = socket(AI->ai_family, AI->ai_socktype, AI->ai_protocol);
if (ServSock[i] == INVALID_SOCKET){
fprintf(stderr, "socket() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
continue;
}
if (bind(ServSock[i], AI->ai_addr, AI->ai_addrlen) == SOCKET_ERROR) {
fprintf(stderr,"bind() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
continue;
}
if (SocketType == SOCK_STREAM) {
// Wait for the connection
if (listen(ServSock[i], 5) == SOCKET_ERROR) {
fprintf(stderr, "listen() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
continue;
}
}
printf("'Listening' on port %s, protocol %s, protocol family %s¥n",
Port, (SocketType == SOCK_STREAM) ? "TCP" : "UDP", (AI->ai_family == PF_INET) ? "PF_INET" : "PF_INET6");
}
 //  Free address structure
 freeaddrinfo(AddrInfo);
if (i == 0) {
fprintf(stderr, "Fatal error: unable to serve on any address.¥n"); WSACleanup();
return -1;
}
NumSocks = i;
FD_ZERO(&SockSet);
while(1) {
FromLen = sizeof(From);
for (i = 0; i < NumSocks; i++){
if (FD_ISSET(ServSock[i], &SockSet))
break;
}
if (i == NumSocks) {
for (i = 0; i < NumSocks; i++)
FD_SET(ServSock[i], &SockSet);
if (select(NumSocks, &SockSet, 0, 0, 0) == SOCKET_ERROR) {
fprintf(stderr, "select() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError())); WSACleanup();
return -1;
}
}
for (i = 0; i < NumSocks; i++){
if (FD_ISSET(ServSock[i], &SockSet)) {
FD_CLR(ServSock[i], &SockSet);
break;
}
}
if (SocketType == SOCK_STREAM) {
SOCKET ConnSock;
   //  Allow connection
ConnSock = accept(ServSock[i], (LPSOCKADDR)&From, &FromLen);
if (ConnSock == INVALID_SOCKET) {
fprintf(stderr, "accept() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
WSACleanup();
return -1;
}
   //  Obtain client name based on the address information
if (getnameinfo((LPSOCKADDR)&From, FromLen, Hostname, sizeof(Hostname), NULL, 0, NI_NUMERICHOST) != 0)
strcpy(Hostname, "<unknown>");
printf("¥nAccepted connection from %s¥n", Hostname);
while (1) {
AmountRead = recv(ConnSock, Buffer, sizeof(Buffer), 0);
if (AmountRead == SOCKET_ERROR) {
fprintf(stderr, "recv() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
closesocket(ConnSock);
break;
}
if (AmountRead == 0) {
printf("Client closed connection¥n");
closesocket(ConnSock);
break;
}
printf("Received %d bytes from client: [%.*s]¥n", AmountRead, AmountRead, Buffer);
printf("Echoing same data back to client¥n");
RetVal = send(ConnSock, Buffer, AmountRead, 0);
if (RetVal == SOCKET_ERROR) {
fprintf(stderr, "send() failed: error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
closesocket(ConnSock);
break;
}
} // end while
} else {
AmountRead = recvfrom(ServSock[i], Buffer, sizeof(Buffer), 0, (LPSOCKADDR)&From, &FromLen);
if (AmountRead == SOCKET_ERROR) {
fprintf(stderr, "recvfrom() failed with error %d: %s¥n",WSAGetLastError(), DecodeError(WSAGetLastError()));
closesocket(ServSock[i]);
break;
}
if (AmountRead == 0) {
printf("recvfrom() returned zero, aborting¥n");
RetVal = shutdown(ServSock[i], SD_BOTH);
if (RetVal == SOCKET_ERROR) {
fprintf(stderr,"shutdown() failed: %d¥n",WSAGetLastError());
}
closesocket(ServSock[i]);
break;
}
   //  Obtain client name based on the address information
RetVal = getnameinfo((LPSOCKADDR)&From, FromLen, Hostname, sizeof(Hostname), NULL, 0, NI_NUMERICHOST);
if (RetVal != 0) {
fprintf(stderr, "getnameinfo() failed with error %d: %s¥n", RetVal, DecodeError(RetVal));
strcpy(Hostname, "<unknown>");
}
printf("Received a %d byte datagram from %s: [%.*s]¥n",AmountRead, Hostname, AmountRead, Buffer);
printf("Echoing same data back to client¥n");
RetVal = sendto(ServSock[i], Buffer, AmountRead, 0,(LPSOCKADDR)&From, FromLen);
if (RetVal == SOCKET_ERROR) {
fprintf(stderr, "send() failed with error %d: %s¥n", WSAGetLastError(), DecodeError(WSAGetLastError()));
}
}
}
return 0;
}

Figure 7
Protocol stack assessment sample

Main function processing

#include <winsock2.h>
#include <ws2tcpip.h>
#include <Iphlpapi.h>
#include <stdio.h>
#include <windows.h>LPSTR DecodeError(int ErrorCode);
DWORD CheckProtocolStack();
void main ()
{
DWORD dwStackType, dwRet;
WSADATA wsaData;
if ((dwRet = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
fprintf(stderr, "WSAStartup failed with error %d: %s¥n", dwRet, DecodeError(dwRet));
WSACleanup();
return;
}
// Check protocol stack
dwStackType = CheckProtocolStack();
if (dwStackType == AF_INET6) {
printf("This PC installed IPv6 stack!¥n");
} else if (dwStackType == AF_INET) {
printf("This PC didn’t have IPv6 stack installed!¥n");
} else {
printf("CheckProtocolStack fail!!¥n");
}
WSACleanup();
}

Processing for assessment of the protocol
DWORD CheckProtocolStack()
{
DWORD dwStackType;
IP_ADAPTER_ADDRESSES *pAdapterAddresses, *AI;
DWORD dwRet, dwSize;
int i;
// Obtain the size of the structure
// Start with IPv6
dwRet = GetAdaptersAddresses(AF_INET6,0,NULL,NULL,&dwSize);
if (dwRet != ERROR_BUFFER_OVERFLOW) {
// Check using IPv4
dwRet = GetAdaptersAddresses(AF_INET,0,NULL,NULL,&dwSize);
if (dwRet != ERROR_BUFFER_OVERFLOW) {
fprintf(stderr, "GetAdaptersAddresses failed with error %d: %s¥n", dwRet, DecodeError(dwRet));
return dwRet;
}
// Allocate memory
pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
if (pAdapterAddresses == NULL) {
fprintf(stderr, "[IPv4] GetAdaptersAddresses failed with error %d: %s¥n", dwRet, DecodeError(GetLastError()));
return dwRet;
}
// Obtain network adapter information (IPv4)
dwRet = GetAdaptersAddresses(AF_INET, 0, NULL, pAdapterAddresses, &dwSize);
if (dwRet != ERROR_SUCCESS) {
LocalFree(pAdapterAddresses);
fprintf(stderr, "[IPv4] GetAdaptersAddresses failed with error %d: %s¥n", dwRet, DecodeError(dwRet));
return dwRet;
} else {
for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++) {
printf("Adapter Name :%s¥n", AI->AdapterName);
if (AI->FirstUnicastAddress != NULL) {
if (AI->FirstUnicastAddress->Address.lpSockaddr->sa_family == AF_INET) {
dwStackType = AF_INET;
}
printf("[%d] UniCast sa_family :%d¥n", i, AI->FirstUnicastAddress->Address.lpSockaddr->sa_family);
} else {
printf("[%d] No unicast address!¥n", i);
}
if (AI->FirstMulticastAddress != NULL) {
if (AI->FirstMulticastAddress->Address.lpSockaddr->sa_family == AF_INET) {
dwStackType = AF_INET;
}
printf("[%d] MultiCast sa_family :%d¥n", i, AI->FirstMulticastAddress->Address.lpSockaddr->sa_family);
} else {
printf("[%d] No multicast address!¥n", i);
}
} // end for
LocalFree(pAdapterAddresses);
}
return dwStackType;
} // end IPv4
// Allocate memory (IPv6)
pAdapterAddresses = (IP_ADAPTER_ADDRESSES *) LocalAlloc(LMEM_ZEROINIT,dwSize);
if (pAdapterAddresses == NULL) {
fprintf(stderr, "[IPv6] GetAdaptersAddresses failed with error %d: %s¥n", dwRet, DecodeError(GetLastError()));
return dwRet;
}
// Obtain network adapter information (IPv6)
dwRet = GetAdaptersAddresses(AF_INET6, 0, NULL, pAdapterAddresses, &dwSize);
if (dwRet != ERROR_SUCCESS) {
LocalFree(pAdapterAddresses);
fprintf(stderr, "[IPv6] GetAdaptersAddresses failed with error %d: %s¥n", dwRet, DecodeError(dwRet));
return dwRet;
} else {
for (i = 0, AI = pAdapterAddresses; AI != NULL; AI = AI->Next, i++) {
printf("[%d] Adapter Name :%s¥n", i, AI->AdapterName);
if (AI->FirstUnicastAddress != NULL) {
if (AI->FirstUnicastAddress->Address.lpSockaddr->sa_family == AF_INET6) {
dwStackType = AF_INET6;
}
printf("[%d] UniCast sa_family :%d¥n",
i, AI->FirstUnicastAddress->Address.lpSockaddr->sa_family);
} else {
printf("[%d] No unicast address!¥n", i);
}
if (AI->FirstMulticastAddress != NULL) {
if (AI->FirstMulticastAddress->Address.lpSockaddr->sa_family == AF_INET6) {
dwStackType = AF_INET6;
}
printf("[%d] MultiCast sa_family :%d¥n", i, AI->FirstMulticastAddress->Address.lpSockaddr->sa_family);
} else {
printf("[%d] No multicast address!¥n", i);
}
} // end for
}
LocalFree(pAdapterAddresses);
return dwStackType;
}

Copied with permission from IPv6 magazine No.4 (published by Impress)

この記事のトラックバックURL

http://www.ipv6style.jp/trackback/603
Ads by Google