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

448 lines
12 KiB
C++

/******************************************************************************\
* sendmsg.cpp
*
* This IPv6 sample demonstrates the use of WSASendMsg() and the IPV6_PKTINFO option
* and WSARecvMsg to retrieve the source address of a datagram.
*
* WSASendMsg 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).
*
* A IPv6 datagram socket is created and bound and the IPV6_PKTINFO option is set.
* Overlapped WSARecvMsg is posted, and data is sent on the socket via sendto.
* Upon completion, the received message is sent again via WSASendMsg.
* The data is received again via WSARecvMsg.
*
*
* 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 <ws2ipdef.h>
#include <ws2tcpip.h>
#include <mstcpip.h>
#include <mswsock.h>
#include <stdio.h>
#include <stdlib.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 CLOSESOCKEVENT(h) \
if(WSA_INVALID_EVENT != h) {WSACloseEvent(h); h = WSA_INVALID_EVENT;}
#define ERR(e) \
{ \
printf("%s:%s failed: %d [%s@%ld]\n",__FUNCTION__,e,WSAGetLastError(),__FILE__,__LINE__); \
}
// Constants
#define WS_VER 0x0202
#define DEFAULT_PORT 12345
#define DEFAULT_WAIT 5000
#define DATA_SIZE 100
#define TST_MSG "Hello\0"
#define IN6_ADDR_STRING_LEN 65
// Helper functions
VOID SET_PORT(PSOCKADDR pAddr,USHORT port)
{
if (AF_INET6 == pAddr->sa_family)
{
((SOCKADDR_IN6*)pAddr)->sin6_port = port;
}
else
{
((SOCKADDR_IN*)pAddr)->sin_port = port;
}
}
VOID InitOverlap(LPWSAOVERLAPPED pOver)
{
CLOSESOCKEVENT(pOver->hEvent);
ZeroMemory(pOver,sizeof(WSAOVERLAPPED));
if (WSA_INVALID_EVENT == (pOver->hEvent = WSACreateEvent()))
{
ERR("WSACreateEvent");
}
}
BOOL SetIpv6PktInfoOption(SOCKET sock)
{
DWORD dwEnableOption = 1;
if (SOCKET_ERROR == setsockopt(sock,
IPPROTO_IPV6,
IPV6_PKTINFO,
(CHAR*)&dwEnableOption,
sizeof dwEnableOption
))
{
ERR("setsockopt IPV6_PKTINFO");
return FALSE;
}
return TRUE;
}
BOOL AllocAndInitIpv6PktInfo(LPWSAMSG pWSAMsg)
{
PBYTE CtrlBuf = (PBYTE)MALLOC(WSA_CMSG_SPACE(sizeof IN6_PKTINFO)); //caller frees heap allocated CtrlBuf
if (NULL == CtrlBuf)
{
ERR("HeapAlloc");
return FALSE;
}
pWSAMsg->Control.buf = (CHAR*)CtrlBuf;
pWSAMsg->Control.len = (ULONG)MSIZE(CtrlBuf);
return TRUE;
}
VOID SockaddrToString(PSOCKADDR pSockaddr,DWORD dwSize,LPSTR szString,DWORD dwStringSize)
{
if (SOCKET_ERROR == WSAAddressToStringA(pSockaddr,dwSize,NULL,szString,&dwStringSize))
{
ERR("WSAAddressToString");
return;
}
return;
}
INT ProcessIpv6Msg(LPWSAMSG pWSAMsg)
{
PWSACMSGHDR pCtrlInfo = NULL;
PIN6_PKTINFO pPktInfo = NULL;
CHAR szAddr[IN6_ADDR_STRING_LEN] = {0};
SOCKADDR_STORAGE addr = {0};
DWORD dwAddrStrSize = 0;
INT rc = SOCKET_ERROR;
pCtrlInfo = WSA_CMSG_FIRSTHDR(pWSAMsg);
if ((IPPROTO_IPV6 == pCtrlInfo->cmsg_level) &&
(IPV6_PKTINFO == pCtrlInfo->cmsg_type))
{
pPktInfo = (PIN6_PKTINFO)WSA_CMSG_DATA(pCtrlInfo);
((SOCKADDR_IN6*)&addr)->sin6_family = AF_INET6;
((SOCKADDR_IN6*)&addr)->sin6_addr = pPktInfo->ipi6_addr;
dwAddrStrSize = sizeof szAddr;
if(SOCKET_ERROR == (rc = WSAAddressToStringA((SOCKADDR*)&addr,
sizeof addr,
NULL,
szAddr,
&dwAddrStrSize
)))
{
ERR("WSAAddressToString");
}
printf("ProcessIpv6Msg: \npPktInfo->ipi6_addr: %s\npPktInfo->ipi6_ifindex: %d\n",
szAddr,pPktInfo->ipi6_ifindex);
return rc;
}
return rc;
}
LPFN_WSARECVMSG GetWSARecvMsgFunctionPointer()
{
LPFN_WSARECVMSG lpfnWSARecvMsg = NULL;
GUID guidWSARecvMsg = WSAID_WSARECVMSG;
SOCKET sock = INVALID_SOCKET;
DWORD dwBytes = 0;
sock = socket(AF_INET,SOCK_DGRAM,0);
if(SOCKET_ERROR == WSAIoctl(sock,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&guidWSARecvMsg,
sizeof(guidWSARecvMsg),
&lpfnWSARecvMsg,
sizeof(lpfnWSARecvMsg),
&dwBytes,
NULL,
NULL
))
{
ERR("WSAIoctl SIO_GET_EXTENSION_FUNCTION_POINTER");
return NULL;
}
return lpfnWSARecvMsg;
}
LPFN_WSASENDMSG GetWSASendMsgFunctionPointer()
{
LPFN_WSASENDMSG lpfnWSASendMsg = NULL;
GUID guidWSASendMsg = WSAID_WSASENDMSG;
SOCKET sock = INVALID_SOCKET;
DWORD dwBytes = 0;
sock = socket(AF_INET,SOCK_DGRAM,0);
if(SOCKET_ERROR == WSAIoctl(sock,
SIO_GET_EXTENSION_FUNCTION_POINTER,
&guidWSASendMsg,
sizeof(guidWSASendMsg),
&lpfnWSASendMsg,
sizeof(lpfnWSASendMsg),
&dwBytes,
NULL,
NULL
))
{
ERR("WSAIoctl SIO_GET_EXTENSION_FUNCTION_POINTER");
CLOSESOCK(sock);
return NULL;
}
CLOSESOCK(sock);
return lpfnWSASendMsg;
}
int __cdecl main()
{
WSADATA wsd = {0};
INT nErr = 0,
nStartup = 0,
nRet = 0;
SOCKET sock = INVALID_SOCKET;
SOCKADDR_STORAGE localaddr = {0},
destaddr = {0},
remoteaddr = {0};
WSAOVERLAPPED over = {0};
WSABUF wsabuf = {0};
WSAMSG wsamsg = {0};
DWORD dwBytes = 0,
dwFlags = 0;
LPFN_WSARECVMSG WSARecvMsg = NULL;
LPFN_WSASENDMSG WSASendMsg = NULL;
__try
{
nErr = WSAStartup(WS_VER,&wsd);
if (nErr)
{
WSASetLastError(nErr);
ERR("WSAStartup");
__leave;
}
else
nStartup++;
if (INVALID_SOCKET == (sock = socket(AF_INET6,SOCK_DGRAM,0)))
{
ERR("socket");
__leave;
}
localaddr.ss_family = AF_INET6;
SET_PORT((SOCKADDR*)&localaddr,DEFAULT_PORT);
if (SOCKET_ERROR == bind(sock,(SOCKADDR*)&localaddr,sizeof localaddr))
{
ERR("bind");
__leave;
}
// PktInfo
if (!SetIpv6PktInfoOption(sock))
{
ERR("SetIpv6PktInfoOption");
__leave;
}
if(!AllocAndInitIpv6PktInfo(&wsamsg))
{
ERR("AllocAndInitIpv6PktInfo");
__leave;
}
// data buffer
wsabuf.buf = (CHAR*)MALLOC(DATA_SIZE);
if (NULL == wsabuf.buf)
{
ERR("HeapAlloc");
__leave;
}
wsabuf.len = (ULONG)MSIZE(wsabuf.buf);
wsamsg.lpBuffers = &wsabuf;
wsamsg.dwBufferCount = 1;
// source address of packet
wsamsg.name = (SOCKADDR*)&remoteaddr;
wsamsg.namelen = sizeof remoteaddr;
//Post overlapped RcvMsg
InitOverlap(&over);
if (NULL == (WSARecvMsg = GetWSARecvMsgFunctionPointer()))
{
ERR("GetWSARecvMsgFunctionPointer");
__leave;
}
if (SOCKET_ERROR == WSARecvMsg(sock,
&wsamsg,
&dwBytes,
&over,
NULL
))
{
if (WSA_IO_PENDING != WSAGetLastError())
{
ERR("WSARecvMsg");
__leave;
}
}
//set destination address
destaddr.ss_family = AF_INET6;
INETADDR_SETLOOPBACK((SOCKADDR*)&destaddr);
SET_PORT((SOCKADDR*)&destaddr,DEFAULT_PORT);
//send some data
if (SOCKET_ERROR == (nRet = sendto(sock,
TST_MSG,
lstrlen(TST_MSG),
0,
(SOCKADDR*)&destaddr,
sizeof destaddr
)))
{
ERR("sendto");
__leave;
}
//check RecvMsg result
if (SOCKET_ERROR == WSAGetOverlappedResult(sock,&over,&dwBytes,TRUE,&dwFlags))
{
ERR("WSAGetOverlappedResult");
__leave;
}
printf("WSARecvMsg %d bytes\n",dwBytes);
//Display address
if(SOCKET_ERROR == ProcessIpv6Msg(&wsamsg))
{
printf("Coult not process IPv6 message.\n");
}
//SendMsg with WSAMSG returned from RecvMsg
if (NULL == (WSASendMsg = GetWSASendMsgFunctionPointer()))
{
ERR("GetWSARecvMsgFunctionPointer");
__leave;
}
if (SOCKET_ERROR == (nRet = WSASendMsg(sock,
&wsamsg,
0,
&dwBytes,
NULL,
NULL
)))
{
ERR("WSASendMsg");
__leave;
}
printf("WSASendMsg %d bytes\n",dwBytes);
//RecvMsg to consume SendMsg data
if (SOCKET_ERROR == WSARecvMsg(sock,
&wsamsg,
&dwBytes,
NULL,
NULL
))
{
ERR("WSARecvMsg");
__leave;
}
printf("WSARecvMsg %d bytes\n",dwBytes);
}
__finally
{
CLOSESOCK(sock);
FREE(wsabuf.buf);
FREE(wsamsg.Control.buf);
CLOSESOCKEVENT(over.hEvent);
if(nStartup) WSACleanup();
}
return 0;
}