2025-11-28 00:35:46 +09:00

497 lines
13 KiB
C++

/******************************************************************************\
* connectbylist.cpp
*
* This IPv6 sample demonstrates the use of WSAConnectByList and dual IPv4/IPv6
* sockets.
*
* WSAConnectByList is new to Windows Sockets in Windows Vista.
*
*
* This sample requires that TCP/IP version 6 be installed on the system (default
* configuration for Windows Vista).
*
* The client builds a socket address list and connects to the server. This is done
* for IPv4 (IPv6 v4-mapped address) and IPv6.
*
*
* This is a part of the Microsoft Source Code Samples.
* Copyright 1996 - 2006 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/
#ifdef _IA64_
#pragma warning (disable: 4311)
#pragma warning (disable: 4312)
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <winsock2.h>
#include <ws2tcpip.h>
#include <mstcpip.h>
#include <stdio.h>
#include <strsafe.h>
//safe macros
#define MALLOC(x) \
HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,x)
#define FREE(p) \
if(NULL != p) {HeapFree(GetProcessHeap(),0,p); p = NULL;}
#define MSIZE(p) \
HeapSize(GetProcessHeap(),0,p)
#define CLOSESOCK(s) \
if(INVALID_SOCKET != s) {closesocket(s); s = INVALID_SOCKET;}
#define FREEADDRINFO(p) \
if(NULL != p) {freeaddrinfo(p); p = NULL;}
#define ERR(e) \
printf("%s:%s failed: %d [%s@%ld]\n",__FUNCTION__,e,WSAGetLastError(),__FILE__,__LINE__)
//constants
#define WS_VER 0x0202
#define CONNECT_TIMEOUT_VAL 5000
USHORT g_listenPort = 0;
//helper functions
typedef BOOL (WSAAPI * LPFN_WSACONNECTBYLIST) (SOCKET s,
PSOCKET_ADDRESS_LIST SocketAddress,
LPDWORD LocalAddressLength,
LPSOCKADDR LocalAddress,
LPDWORD RemoteAddressLength,
LPSOCKADDR RemoteAddress,
TIMEVAL * timeout,
LPWSAOVERLAPPED Reserved
);
LPFN_WSACONNECTBYLIST GetWSAConnectByListFunctionPointer()
{
LPFN_WSACONNECTBYLIST fnWSAConnectByList = NULL;
HMODULE hWs2_32 = LoadLibraryA("ws2_32");
fnWSAConnectByList = (LPFN_WSACONNECTBYLIST)GetProcAddress(hWs2_32,"WSAConnectByList");
FreeLibrary(hWs2_32);
return fnWSAConnectByList;
}
LPFN_WSACONNECTBYLIST fnWSAConnectByList = GetWSAConnectByListFunctionPointer();
//Dual-stack socket which can be used with either IPv4 or IPv6 addresses
SOCKET DualStackSocket(VOID)
{
SOCKET sock = INVALID_SOCKET;
INT off = 0;
__try
{
if (INVALID_SOCKET == (sock = socket(AF_INET6,SOCK_STREAM,0)))
{
ERR(TEXT("socket"));
__leave;
}
if (SOCKET_ERROR == setsockopt(sock,
IPPROTO_IPV6,
IPV6_V6ONLY,
(char*)&off,
sizeof off
))
{
ERR(TEXT("setsockopt"));
CLOSESOCK(sock);
__leave;
}
}
__finally
{
}
return sock;
}
SOCKET DualStackListenSocket(VOID)
{
SOCKET lsock = INVALID_SOCKET;
SOCKADDR_STORAGE addrAny = {0};
INT addrAny_len = 0;
__try
{
addrAny.ss_family = AF_INET6;
INETADDR_SETANY((SOCKADDR*)&addrAny);
//dual stack listening socket
if (INVALID_SOCKET == (lsock = DualStackSocket()))
{
ERR(TEXT("DualStackSocket"));
__leave;
}
if (SOCKET_ERROR == bind(lsock,(SOCKADDR*)&addrAny,sizeof addrAny))
{
ERR(TEXT("bind"));
CLOSESOCK(lsock);
__leave;
}
if (SOCKET_ERROR == listen(lsock,SOMAXCONN))
{
ERR(TEXT("listen"));
CLOSESOCK(lsock);
__leave;
}
addrAny_len = sizeof addrAny;
if (SOCKET_ERROR == getsockname(lsock,(SOCKADDR*)&addrAny,&addrAny_len))
{
ERR(TEXT("getsockname"));
CLOSESOCK(lsock);
__leave;
}
g_listenPort = htons(INETADDR_PORT((SOCKADDR*)&addrAny));
}
__finally
{
}
return lsock;
}
SOCKADDR_IN6 *pAddr6 = NULL;
PSOCKET_ADDRESS_LIST InitSocketAddressList(ADDRESS_FAMILY Af)
{
BOOL bRet = FALSE;
CHAR szComputerName[MAX_COMPUTERNAME_LENGTH+1] = {0},
szPort[6] = {0};
DWORD dwSize = sizeof szComputerName,
i = 0,
dwAddrCount = 0,
dwBytes = 0;
ADDRINFO hints = {0},
*res = NULL,
*ptr = NULL;
SOCKET sock = INVALID_SOCKET;
SOCKADDR_IN6 *pAddr6 = NULL;
PSOCKET_ADDRESS_LIST SocketAddressList = NULL;
SCOPE_ID scope;
__try
{
if (!GetComputerNameA(szComputerName,&dwSize))
{
ERR("GetComputerName");
__leave;
}
hints.ai_family = (INT)Af;
hints.ai_socktype = SOCK_STREAM;
if (FAILED(StringCbPrintfA(szPort,sizeof szPort,"%d",g_listenPort)))
{
__leave;
}
if (GetAddrInfoA(szComputerName,"",&hints,&res))
{
ERR("getaddrinfo");
__leave;
}
for (ptr = res; ptr; ptr = ptr->ai_next)
dwAddrCount += 1;
dwSize = SIZEOF_SOCKET_ADDRESS_LIST(dwAddrCount)+(dwAddrCount*sizeof SOCKADDR_STORAGE);;
if (NULL == (SocketAddressList = (PSOCKET_ADDRESS_LIST)MALLOC(dwSize)))
{
ERR("HeapAlloc");
__leave;
}
pAddr6 = NULL;
if (NULL == (pAddr6 = (SOCKADDR_IN6*)MALLOC(dwAddrCount*sizeof SOCKADDR_IN6)))
{
ERR("HeapAlloc");
__leave;
}
if (AF_INET == res->ai_family)
{
for (ptr = res,i = 0; ptr, i < dwAddrCount; ptr = ptr->ai_next, i++)
{
scope = INETADDR_SCOPE_ID(ptr->ai_addr);
IN6ADDR_SETV4MAPPED(&pAddr6[i],
&((SOCKADDR_IN*)ptr->ai_addr)->sin_addr,
scope,
((SOCKADDR_IN*)ptr->ai_addr)->sin_port
);
SS_PORT((SOCKADDR*)&pAddr6[i]) = htons(g_listenPort);
SocketAddressList->Address[i].lpSockaddr = (SOCKADDR*)&pAddr6[i];
SocketAddressList->Address[i].iSockaddrLength = sizeof SOCKADDR_IN6;
}
} else
{
for (ptr = res, i = 0; ptr, i < dwAddrCount; ptr = ptr->ai_next, i++)
{
CopyMemory(&pAddr6[i],(SOCKADDR_IN6*)ptr->ai_addr,sizeof SOCKADDR_IN6);
SS_PORT((SOCKADDR*)&pAddr6[i]) = htons(g_listenPort);
SocketAddressList->Address[i].lpSockaddr = (SOCKADDR*)&pAddr6[i];
SocketAddressList->Address[i].iSockaddrLength = sizeof SOCKADDR_IN6;
}
}
SocketAddressList->iAddressCount = dwAddrCount;
if (INVALID_SOCKET == (sock = socket(AF_INET6,
SOCK_STREAM,
0
)))
{
ERR("socket");
__leave;
}
dwSize = (DWORD)MSIZE(SocketAddressList);
if (SOCKET_ERROR == WSAIoctl(sock,
SIO_ADDRESS_LIST_SORT,
SocketAddressList,
dwSize,
SocketAddressList,
dwSize,
&dwBytes,
NULL,
NULL
))
{
ERR("SIO_ADDRESS_LIST_SORT");
__leave;
}
bRet = TRUE;
}
__finally
{
CLOSESOCK(sock);
FREEADDRINFO(res);
}
if (!bRet)
{
FREE(SocketAddressList);
}
return SocketAddressList;
}
VOID PrintSocketAddressList(PSOCKET_ADDRESS_LIST List)
{
CHAR szString[MAX_PATH] = {0};
DWORD dwLen = 0;
INT i=0;
printf("SOCKET_ADDRESS_LIST:\n");
for (i=0; i < List->iAddressCount; i++)
{
dwLen = sizeof szString;
if(SOCKET_ERROR == WSAAddressToStringA(List->Address[i].lpSockaddr,
(DWORD)List->Address[i].iSockaddrLength,
NULL,
szString,
&dwLen
))
{
printf("WSAAddressToString: %d\n",WSAGetLastError());
}
printf("%s\n",szString);
}
}
VOID PrintSockaddr(PSOCKADDR pSockaddr,DWORD dwSize)
{
CHAR szString[MAX_PATH] = {0};
DWORD dwStringSize = sizeof szString;
if (SOCKET_ERROR == WSAAddressToStringA(pSockaddr,dwSize,NULL,szString,&dwStringSize))
{
ERR("WSAAddressToString");
return;
}
printf("%s\n",szString);
return;
}
DWORD WSAConnectByList_Loopback(ADDRESS_FAMILY AddressFamily)
{
WSADATA wsd;
INT nStartup = 0,
nErr = 0,
rc = 0;
SOCKET lsock = INVALID_SOCKET,
asock = INVALID_SOCKET,
csock = INVALID_SOCKET;
TIMEVAL timeval = {CONNECT_TIMEOUT_VAL,0};
PSOCKET_ADDRESS_LIST AddressList = NULL;
CHAR buf = '\0';
SOCKADDR_STORAGE localAddr = {0},
remoteAddr = {0};
DWORD dwLocalAddrLen = sizeof localAddr,
dwRemoteAddrLen = sizeof remoteAddr;
__try
{
nErr = WSAStartup(WS_VER,&wsd);
if (nErr)
{
WSASetLastError(nErr);
ERR("WSAStartup");
__leave;
}
nStartup++;
if (NULL == fnWSAConnectByList)
{
printf("Not supported\n");
__leave;
}
if (INVALID_SOCKET == (lsock = DualStackListenSocket()))
{
ERR("DualStackListenSocket");
__leave;
}
if ((NULL == (AddressList = InitSocketAddressList(AddressFamily))))
{
ERR("InitSocketAddressList");
__leave;
}
if (INVALID_SOCKET == (csock = DualStackSocket()))
{
ERR("DualStackSocket");
__leave;
}
PrintSocketAddressList(AddressList);
if (!fnWSAConnectByList(csock,
AddressList,
&dwLocalAddrLen,
(SOCKADDR*)&localAddr,
&dwRemoteAddrLen,
(SOCKADDR*)&remoteAddr,
&timeval,
NULL
))
{
ERR("WSAConnectByList");
__leave;
}
printf("WSAConnectByList returned\n");
printf("Local address ");
PrintSockaddr((SOCKADDR*)&localAddr,dwLocalAddrLen);
printf("Remote address ");
PrintSockaddr((SOCKADDR*)&remoteAddr,dwRemoteAddrLen);
if (INVALID_SOCKET == (asock = accept(lsock,NULL,NULL)))
{
ERR("accept");
__leave;
}
if (SOCKET_ERROR == shutdown(asock,SD_SEND))
{
ERR("shutdown");
__leave;
}
if (0 != (rc = recv(csock,&buf,sizeof buf,0)))
{
ERR("recv");
__leave;
}
}
__finally
{
CLOSESOCK(csock);
CLOSESOCK(asock);
CLOSESOCK(lsock);
FREE(pAddr6);
FREE(AddressList);
if (nStartup) WSACleanup();
}
return 0;
}
int __cdecl main()
{
ADDRESS_FAMILY Af = AF_UNSPEC;
Af = (ADDRESS_FAMILY)AF_INET;
WSAConnectByList_Loopback(Af);
Af = (ADDRESS_FAMILY)AF_INET6;
WSAConnectByList_Loopback(Af);
return 0;
}