WSARecvMsg can be used instead of WSARecv and WSARecvFrom, but WSARecvMsg is only supported by XP and above. The advantage of WSARecvMsg is that it can provide some information that cannot be (easily?) obtained any other way. For IP version 4, the documentation I think says that The documentation (currently) has errors, but the following works for me.
GUID WSARecvMsg_GUID = WSAID_WSARECVMSG;
LPFN_WSARECVMSG WSARecvMsg;
char ControlBuffer[1024];
DWORD NumberOfBytes;
string ErrorMessage, Address;
WSABUF WSABuf;
WSAMSG Msg;
int nResult;
nResult = WSAIoctl(m_Socket, SIO_GET_EXTENSION_FUNCTION_POINTER,
&WSARecvMsg_GUID, sizeof WSARecvMsg_GUID,
&WSARecvMsg, sizeof WSARecvMsg,
&NumberOfBytes, NULL, NULL);
if (nResult == SOCKET_ERROR) {
m_ErrorCode = WSAGetLastError();
WSARecvMsg = NULL;
return 0;
}
Msg.name = SocketAddress;
Msg.namelen = sizeof sockaddr_in;
WSABuf.buf = (char *)Buffer;
WSABuf.len = Length;
Msg.lpBuffers = &WSABuf;
Msg.dwBufferCount = 1;
Msg.Control.len = sizeof ControlBuffer;
Msg.Control.buf = ControlBuffer;
Msg.dwFlags = nFlags;
nResult = WSARecvMsg(m_Socket, &Msg, &NumberOfBytes, NULL, NULL);
if (nResult == SOCKET_ERROR) {
m_ErrorCode = WSAGetLastError();
return 0;
}
// There can be multiple enties but the following will show only the first.
WSACMSGHDR *pCMsgHdr = WSA_CMSG_FIRSTHDR(&Msg);
if (pCMsgHdr)
switch (pCMsgHdr->cmsg_type) {
case IP_PKTINFO: {
IN_PKTINFO *pPktInfo;
CSocketAddressIn DestinationAddress;
pPktInfo = (IN_PKTINFO *)WSA_CMSG_DATA(pCMsgHdr);
DestinationAddress.SetHostAddress(pPktInfo->ipi_addr.S_un.S_addr);
DestinationAddress.GetAddress(Address);
cout << "Destination address: " << Address
<< ", interface index: " << pPktInfo->ipi_ifindex << '\n';
}
break;
default:
cout << "Unknown message type: " << pCMsgHdr->cmsg_type
<< "; level: " << pCMsgHdr->cmsg_level << '\n';
break;
}
Where:
The option requesting data must be set. Put the following after creating the socket (calling socket).
int nResult, optval(1); nResult = setsockopt(m_Socket, IPPROTO_IP, IP_PKTINFO, (char*)&optval, sizeof(int));
Download UDPio.zip for a sample project using the code above. It is a console program and is not the best-written, but it should be enough to show use of WSARecvMsg.
See my Visual C++ Programmer Stuff page for more C++ stuff.