// mcastrouter.cpp : compiled and tested under Windows Server 2008 + VS 2008
#include <windows.h>
#include <winsock2.h>
#include <mstcpip.h>
#include <ws2tcpip.h>
#define MULTICASTPORT 5050
#define INPUTMULTICAST_IF "192.168.100.4"
#define OUTPUTMULTICAST_IF "172.16.20.3"
struct iphdr {
BYTE h_len:4;
BYTE version:4;
UCHAR iph_tos;
USHORT iph_length;
USHORT iph_id;
USHORT iph_offset;
UCHAR iph_ttl;
UCHAR ip_p;
USHORT iph_xsum;
in_addr ip_src;
in_addr ip_dst;
}ip;
struct udphdr
{
USHORT source;
USHORT dest;
USHORT len;
USHORT check;
};
int _tmain(int argc, _TCHAR* argv[])
{
SOCKET inSock;
SOCKET outSock;
SOCKADDR_IN inSockAddr = {0};
SOCKADDR_IN outSockAddr = {0};
SOCKADDR_IN iface_addr = {0};
fd_set rdSet;
WSADATA data;
WORD version;
int ret;
int siomode = 1;
int dwBytesReturned;
struct sockaddr_in saddr;
socklen_t saddr_size = sizeof(saddr);
char buf[2000];
struct sockaddr_in sa;
version = (MAKEWORD(2, 2));
ret = WSAStartup(version, &data);
if(ret != 0)
{
printf("WinSock not initialised");
return 1;
}
inSock = WSASocket(AF_INET, SOCK_RAW, IPPROTO_UDP, NULL, 0, 0);
outSock = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);
inSockAddr.sin_family = AF_INET;
inSockAddr.sin_addr.s_addr = inet_addr(INPUTMULTICAST_IF);
inSockAddr.sin_port = htons(5555); //not used because of RAW socket I/O...
ret = bind(inSock, (struct sockaddr*)&inSockAddr, sizeof(inSockAddr));
if(ret == SOCKET_ERROR)
{
printf ("bind1() Err: %d\n", WSAGetLastError());
return 1;
}
outSockAddr.sin_family = AF_INET;
outSockAddr.sin_addr.s_addr = inet_addr(OUTPUTMULTICAST_IF);
outSockAddr.sin_port = htons(5050); //faked, used in output UDP packets as "source port"
ret = bind(outSock, (struct sockaddr*)&outSockAddr, sizeof(outSockAddr));
if(ret == SOCKET_ERROR)
{
printf ("bind2() Err: %d\n", WSAGetLastError());
return 1;
}
iface_addr.sin_addr.s_addr = inet_addr(OUTPUTMULTICAST_IF);
ret = setsockopt(outSock, IPPROTO_IP, IP_MULTICAST_IF, (char *)&iface_addr, sizeof(iface_addr));
if(ret == SOCKET_ERROR)
{
printf("setsockopt() IP_MULTICAST_IF address Err: %d\n", WSAGetLastError());
return 1;
}
unsigned char ttl = 1;
ret = setsockopt(outSock, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl));
if(ret == SOCKET_ERROR)
{
printf("setsockopt() IP_MULTICAST_TTL address Err: %d\n", WSAGetLastError());
return 1;
}
unsigned char loopback = 1;
ret = setsockopt(inSock, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loopback, sizeof(loopback));
if(ret == SOCKET_ERROR)
{
printf("setsockopt() IP_MULTICAST_LOOP address Err: %d\n", WSAGetLastError());
return 1;
}
ret = WSAIoctl(inSock, SIO_RCVALL_MCAST, &siomode, sizeof(siomode), NULL, 0, (LPDWORD)&dwBytesReturned, NULL, NULL);
if(ret == SOCKET_ERROR)
{
printf ("WSAIoctl() Err: %d\n", WSAGetLastError());
return 1;
}
sa.sin_family = AF_INET;
FD_ZERO(&rdSet);
FD_SET(inSock, &rdSet);
while(1)
{
if(select(0, &rdSet, NULL, NULL, NULL) == 1)
{
int packet_len = recvfrom(inSock, buf, sizeof(buf), 0, (struct sockaddr *)&saddr, &saddr_size);
iphdr* hdr = (iphdr*)buf;
if(hdr->ip_p == IPPROTO_UDP)
{
udphdr* hdr2 = (udphdr*)(buf+(hdr->h_len*4));
memcpy((void *)&sa.sin_addr, (void *)&hdr->ip_dst, sizeof(in_addr));
sa.sin_port = hdr2->dest;
if(ntohs(hdr2->dest) == MULTICASTPORT)
sendto(outSock, buf+((hdr->h_len*4)+sizeof(udphdr)), packet_len-(hdr->h_len*4)-sizeof(udphdr), 0, (struct sockaddr *)&sa, sizeof(sa));
}
}
else {
break;
}
}
closesocket(outSock);
closesocket(inSock);
WSACleanup();
return 0;
}