#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include<string>
#include <Winsock2.h>
#include <ws2tcpip.h>
#include<vector>
using namespace std;
void ErrorCheck(int lcond, int rcond, string msg) {
if (lcond != rcond)cout << "unexpected " << lcond << " " << msg << " failed!" << endl;
}
#pragma comment(lib, "Ws2_32.lib")
void init() {
WSADATA wsaData;
(void)WSAStartup(MAKEWORD(2, 2), &wsaData);
}
void init_sockaddr(void* addrin, int len,string family, string addr, short port) {
memset(addrin, 0, len);
if (family == "ipv4") {
sockaddr_in* tmp = (sockaddr_in*)addrin;
tmp->sin_family = AF_INET;
tmp->sin_port = htons(port);
inet_pton(AF_INET, addr.c_str(), &tmp->sin_addr);
}
else {
sockaddr_in6* tmp = (sockaddr_in6*)addrin;
tmp->sin6_family = AF_INET6;
tmp->sin6_port = htons(port);
inet_pton(AF_INET6, addr.c_str(), &tmp->sin6_addr);
}
}
class multicast {
public:
SOCKET sock;
ADDRESS_FAMILY family;
int iface;
char buf[1024];
union {
sockaddr_in in4;
sockaddr_in6 in6;
}nicaddr, groupaddr,srcaddr,senderaddr;
multicast(string family, string nic, string group, short srcprt, short dstprt, int iface) {
init_sockaddr(&nicaddr, sizeof nicaddr, family, nic, srcprt);
init_sockaddr(&groupaddr, sizeof groupaddr, family, group, dstprt);
this->family = family=="ipv4" ? AF_INET : AF_INET6;
this->iface = iface;
sock = socket(this->family, SOCK_DGRAM, IPPROTO_UDP);
int tmp = 1;
ErrorCheck(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&tmp, sizeof(int)),0,"reuseaddr");
ErrorCheck(bind(sock, (sockaddr*)&nicaddr, sizeof nicaddr),0,"bind");
}
void includeGroupSource(vector<string> srcs) {
for (auto& i : srcs) {
group_source_req req;
req.gsr_interface = iface;
memcpy(&req.gsr_group, &groupaddr, sizeof groupaddr);
init_sockaddr(&srcaddr, sizeof srcaddr, this->family == AF_INET ? "ipv4" : "ipv6",i, 0);
memcpy(&req.gsr_source, &srcaddr, sizeof srcaddr);
ErrorCheck(setsockopt(sock, this->family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
MCAST_JOIN_SOURCE_GROUP,
(const char*)&req, sizeof req), 0, "join src");
cout << "\tjoin src " << i<<" "<< "include " << endl;
}
}
void excludeGroupSource(vector<string> srcs) {
for (auto& i : srcs) {
group_source_req req;
req.gsr_interface = iface;
memcpy(&req.gsr_group, &groupaddr, sizeof groupaddr);
init_sockaddr(&srcaddr, sizeof srcaddr, this->family == AF_INET ? "ipv4" : "ipv6", i, 0);
memcpy(&req.gsr_source, &srcaddr, sizeof srcaddr);
group_req greq;
greq.gr_interface = iface;
memcpy(&greq.gr_group, &groupaddr, sizeof groupaddr);
cout << "join group " << endl;
static int flag= 0;
if(!flag)
ErrorCheck(setsockopt(sock, this->family==AF_INET?IPPROTO_IP:IPPROTO_IPV6, MCAST_JOIN_GROUP,
(const char*)&greq, sizeof greq),0,"join group");
flag = 1;
ErrorCheck(setsockopt(sock, this->family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6,
MCAST_BLOCK_SOURCE,
(const char*)&req, sizeof req), 0, "join src");
cout << "\tjoin src " << i << " " << "exclude " << endl;
}
}
void recv() {
memset(buf, 0, sizeof buf);
memset(&senderaddr, 0, sizeof senderaddr);
int sendlen = sizeof senderaddr;
int length = recvfrom(sock, buf, sizeof buf, 0, (sockaddr*)&senderaddr, &sendlen);
cout << WSAGetLastError() << endl;
char addr[256];
memset(addr, 0, sizeof addr);
if (length > 0) {
int port = 0;
if (family == AF_INET) {
inet_ntop(family, &senderaddr.in4.sin_addr, addr, sizeof addr);
port = htons(senderaddr.in4.sin_port);
}
else {
inet_ntop(family, &senderaddr.in6.sin6_addr, addr, sizeof addr);
port = htons(senderaddr.in6.sin6_port);
}
printf("received from (%s %d) %d %s\n", addr, port, length, buf);
}
}
~multicast() {
closesocket(sock);
}
};
int main(int argc, char* argv[]) {
init();
multicast b("ipv6", "fe80::d5f3:f3bf:119a:5c3f", "ff3e::10",1234,1234,11);
b.excludeGroupSource({ "2001::1","2001::2"});
while(1)
b.recv();
return 0;
}