组播文章:http://www.docin.com/p-271100049.html
http://blog.csdn.net/luohai859/article/details/37819113
#include <net/if_arp.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <strings.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#if 0
# include <linux/in.h>
#endif
#include <netinet/in.h>
#include <net/if.h>
#include <netinet/if_ether.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <linux/sockios.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#ifdef linux
# define NEWSOCKET() socket(AF_INET, SOCK_PACKET, htons(ETH_P_RARP))
#else
# define NEWSOCKET() socket(SOL_SOCKET, SOCK_RAW, ETHERTYPE_REVARP)
#endif
#define MAC_ADDR_LEN 6
#define IP_ADDR_LEN 4
#define ARP_FRAME_TYPE 0x0806
#define IP_FRAME_TYPE 0x0800
#define ETHER_HW_TYPE 1
#define IP_PROTO_TYPE 0x0800
#define OP_ARP_REQUEST 1
#define OP_ARP_REPLY 2
char usage[]={"Usage: send_arp <ifname>\n\tExample:\tsend_arp eth0\n\t\t\tsend_arp eth1:1"};
typedef struct igmphdr{
unsigned char type;
unsigned char code;
unsigned short csum;
struct in_addr group;
}igmphdr;
struct arp_packet {
u_char targ_hw_addr[MAC_ADDR_LEN];
u_char src_hw_addr[MAC_ADDR_LEN];
//u_short vlan; //always 0x8100
//u_short vlan_id; //0x43
u_short frame_type;
u_char padding[32];
};
void die(const char *);
void get_ip_addr(struct in_addr*,char*);
void get_hw_addr(u_char*,char*);
int ioctl_sock;
int opt_d = 0;
#define IGMP_MINLEN 8
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
char igmpbuf[8];
static unsigned short
lwip_standard_chksum(void *dataptr, int lenarg)
{
int len = lenarg;
unsigned char *pb = (unsigned char *)dataptr;
unsigned short *ps, t = 0;
unsigned int *pl;
unsigned int sum = 0, tmp;
/* starts at odd byte address? */
int odd = ((unsigned int )pb & 1);
printf(" odd %d %d %d\n",odd,sizeof(ps),len);
if (odd && len > 0) {
((unsigned char *)&t)[1] = *pb++;
len--;
}
printf(" odd %d %d %d\n",odd,sizeof(ps),len);
ps = (unsigned short *)pb;
printf(" if %d\n" , ((unsigned int )ps &3));
if (((unsigned int )ps & 3) && len > 1) {
sum += *ps++;
len -= 2;
}
printf(" ps:%d sum:%d len%d\n",ps,sum,len);
pl = (unsigned int *)ps;
while (len > 7) {
tmp = sum + *pl++; /* ping */
if (tmp < sum) {
tmp++; /* add back carry */
}
printf(" %d %d %d\n" , len , tmp, sum);
sum = tmp + *pl++; /* pong */
printf(" %d %d %d\n" , len , tmp, sum);
if (sum < tmp) {
sum++; /* add back carry */
}
printf(" %d %d %d\n" , len , tmp, sum);
len -= 8;
}
printf(" sum0 %d\n",sum);
/* make room in upper bits */
sum = FOLD_U32T(sum);
printf(" sum1 %d\n",sum);
ps = (unsigned short *)pl;
/* 16-bit aligned word remaining? */
while (len > 1) {
sum += *ps++;
len -= 2;
}
printf(" sum2 %d\n",sum);
/* dangling tail byte remaining? */
if (len > 0) { /* include odd byte */
((unsigned char *)&t)[0] = *(unsigned char *)ps;
}
sum += t; /* add end bytes */
printf(" sum2 %d\n",sum);
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
printf(" sum2 %d\n",sum);
if (odd) {
sum = SWAP_BYTES_IN_WORD(sum);
}
return (unsigned short)sum;
}
#if 0
static unsigned short
lwip_standard_chksum(void *dataptr, int len)
{
unsigned char *pb = (unsigned char *)dataptr;
unsigned short *ps, t = 0;
unsigned int *pl;
unsigned int sum = 0, tmp;
/* starts at odd byte address? */
int odd = ((unsigned int )pb & 1);
if (odd && len > 0) {
((unsigned char *)&t)[1] = *pb++;
len--;
}
ps = (unsigned short *)pb;
if (((unsigned int )ps & 3) && len > 1) {
sum += *ps++;
len -= 2;
}
pl = (unsigned int *)ps;
while (len > 7) {
tmp = sum + *pl++; /* ping */
if (tmp < sum) {
tmp++; /* add back carry */
}
sum = tmp + *pl++; /* pong */
if (sum < tmp) {
sum++; /* add back carry */
}
len -= 8;
}
/* make room in upper bits */
sum = FOLD_U32T(sum);
ps = (unsigned short *)pl;
/* 16-bit aligned word remaining? */
while (len > 1) {
sum += *ps++;
len -= 2;
}
/* dangling tail byte remaining? */
if (len > 0) { /* include odd byte */
((unsigned char *)&t)[0] = *(unsigned char *)ps;
}
sum += t; /* add end bytes */
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
if (odd) {
sum = SWAP_BYTES_IN_WORD(sum);
}
return (unsigned short)sum;
}
#endif
unsigned short checksum(unsigned short *buf, int nword)
{
unsigned long sum;
for(sum = 0; nword > 0; nword--)
sum += (*buf++);
sum = (sum>>16) + (sum&0xffff);
sum += (sum>>16);
return ~sum;
}
void
igmpjoinreport (char *interface, char* destip)
{
struct in_addr my_in_addr;
struct arp_packet pkt;
struct sockaddr sa;
int optypes [] = {OP_ARP_REQUEST, OP_ARP_REPLY, 0};
int sock;
u_char hwaddr[MAC_ADDR_LEN];
int j, i;
char *ifname, *ifsend, *cindex;
char ch;
struct sockaddr_in target,host;
bzero(&target , sizeof(struct sockaddr_in ) );
target.sin_family = AF_INET;
target.sin_port= htons(8888);
if(!inet_aton((const char*)destip ,&target.sin_addr))
printf("inet_aton error\n");
printf("%s %p\n",destip, &target.sin_addr);
sock=NEWSOCKET();
ioctl_sock = NEWSOCKET();
if ((sock < 0) || (ioctl_sock < 0)) {
perror("Unable to create socket");
exit(1);
}
if (!(ifname = strdup(interface)) || !(ifsend = strdup(interface)))
die("Cannot duplicate interface name\n");
if (cindex = strchr(ifsend, ':'))
*cindex = '\0';
if (opt_d) {
printf("Interface: %s\n", ifname);
}
get_hw_addr(hwaddr, interface);
get_ip_addr(&my_in_addr, ifname);
memset(&pkt, '0', sizeof(pkt));
pkt.frame_type = htons(IP_FRAME_TYPE);
pkt.targ_hw_addr[0]=0x01;
pkt.targ_hw_addr[1]=0x00;
pkt.targ_hw_addr[2]=0x5e;
unsigned int addr = (unsigned int)target.sin_addr.s_addr;
printf("mac is %x\n", addr);
unsigned char temp = (addr&0x00007F00)>>8 ;
pkt.targ_hw_addr[3]=temp;
printf("mac is %x\n", temp);
temp = (addr&0x00FF0000)>>16 ;
printf("mac is %x", temp);
pkt.targ_hw_addr[4]=temp;
temp = (addr&0xFF000000)>>24 ;
printf("mac is %x", temp);
pkt.targ_hw_addr[5]=temp;
//pkt.vlan= 0x8100;
//pkt.vlan_id=0x43;
for (i = 0; i < MAC_ADDR_LEN; i++)
pkt.src_hw_addr[i] = hwaddr[i];
memset(pkt.padding,0, 18);
strcpy(sa.sa_data, ifsend);
printf ("**********%d\n",sizeof(struct ip ));
struct ip *ip;
struct igmphdr *igmp , *igmp2;
unsigned short ip_len;
ip_len = sizeof(struct ip ) + sizeof(struct igmphdr)+4;
ip=(struct ip*)pkt.padding;
ip->ip_v= IPVERSION;
ip->ip_hl = (sizeof(struct ip ) +4)>>2;
ip->ip_tos = 0xc0;
ip->ip_len = htons(ip_len);
ip->ip_id=0x00;
ip->ip_off= 0x0040;
ip->ip_ttl = 1;
ip->ip_p= IPPROTO_IGMP;
ip->ip_dst = target.sin_addr;
ip->ip_src = my_in_addr ;/* host.sin_addr;*/
char * option = ((void*)(pkt.padding)+ sizeof(struct ip ));
option[0]=0x94;
option [1]= 0x04;
option [2]= 0x00;
option [3]= 0x00;
ip->ip_sum=checksum( ip , (sizeof(struct ip ) +4)/2 );
igmp =(struct igmphdr*)((void*)(pkt.padding)+ sizeof(struct ip )+4);
igmp->type=0x16;
igmp->code=0;
igmp->group=target.sin_addr;
igmp2=(struct igmphdr*)igmpbuf;
igmp2->type=0x16;
igmp2->code=0;
igmp2->group=target.sin_addr;
igmp->csum=~lwip_standard_chksum(igmp2,IGMP_MINLEN );
printf ("**********%p %p igmpchecksum %x\n",ip , igmp, igmp->csum);
int tmp =1;
const int *val = &tmp;
setsockopt (sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(tmp));
if (sendto(sock, (const void *)&pkt, sizeof(pkt), 0,&sa,sizeof(sa)) < 0) {
perror("Unable to send");
exit(1);
}
close(sock);
close(ioctl_sock);
if(ifname != NULL)
free(ifname);
if(ifsend != NULL)
free(ifsend);
}
void die(const char* str)
{
fprintf(stderr,"Error: %s\n",str);
exit(1);
}
void get_ip_addr(struct in_addr* in_addr,char* str)
{
struct ifreq ifr;
struct sockaddr_in sin;
strcpy(ifr.ifr_name, str);
ifr.ifr_addr.sa_family = AF_INET;
if (ioctl(ioctl_sock, SIOCGIFADDR, &ifr))
{ // die("Failed to get IP address for the interface");
printf(" failed to get ipt addre ");
}
memcpy(&sin, &ifr.ifr_addr, sizeof(struct sockaddr_in));
in_addr->s_addr = sin.sin_addr.s_addr;
if (opt_d)
printf("IP address: %s\n", inet_ntoa(*in_addr));
}
void get_hw_addr(u_char* buf,char* str)
{
int i;
struct ifreq ifr;
char c,val = 0;
strcpy(ifr.ifr_name, str);
if (ioctl(ioctl_sock, SIOCGIFHWADDR, &ifr))
{ } // die("Failed to get MAC address for the interface");
memcpy(buf, ifr.ifr_hwaddr.sa_data, 8);
if (opt_d)
printf("MAC address: %2X:%2X:%2X:%2X:%2X:%2X\n", *(buf), *(buf+1), *(buf+2), *(buf+3),*(buf+4), *(buf+5));
}
#define LINENUM 256
int
getMajor(char *path, char *node)
{
FILE *file = fopen(path, "r");
char buf[LINENUM];
int index = -1;
if(file == NULL)
{
perror ("File open error!\n");
return -1;
}
while ((fgets (buf, LINENUM, file)) != NULL)
{
if(strstr(buf, node) != NULL)
{
char *p = strchr(buf, 0x20);
*p = '\0';
return atoi(buf);
}
memset(buf, 0, LINENUM);
}
return -1;
}
int
main(int argc, char **argv)
{
if (argc < 3) {
die(usage);
}
igmpjoinreport(argv[1], argv[2]);
int res = 0;
time_t currenttime;
int fd = open("/dev/iptvdev", O_RDWR|O_NONBLOCK);
if(fd < 0)
{
int major = getMajor("/proc/devices", "iptvdev");
if(major < 0)
{
perror ("get major failed pls check /proc/devices!\n");
goto startloop;
}
dev_t dev = makedev(major, 1);
int res = mknod("/dev/iptvdev", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH|S_IFCHR, dev);
if(res != 0)
{
perror ("mknod failed pls check major or minjor!\n");
goto startloop;
}
fd = open("/dev/iptvdev", O_RDWR|O_NONBLOCK);
if(fd < 0)
{
perror ("fd create failed!\n");
goto startloop;
}
}
startloop:
if(fd < 0)
{
fd = 2;
struct timeval tv;
while(1)
{
tv.tv_sec = 120;
tv.tv_usec = 0;
if( (res = select(fd, NULL, NULL, NULL, &tv) ) == 0)
{
currenttime = time(NULL);
fprintf(stderr, "time out %s\n", ctime(¤ttime));
igmpjoinreport(argv[1], argv[2]);
}
}
}
else
{
int val= fcntl(fd, F_GETFL, 0);
char buf[32];
fcntl(fd, F_SETFL, val | O_NONBLOCK);
fd_set rset;
fd_set wset;
fd_set eset;
while(1)
{
FD_ZERO(&rset);
FD_CLR(fd,&rset);
FD_SET(fd, &rset);
res = 0;
fprintf(stderr, "\n===================================== \n");
// here add timeout
struct timeval tv;
tv.tv_sec = 120;
tv.tv_usec = 0;
if( ( res = select(fd + 1, &rset, NULL, NULL, &tv) ) <= 0)
{
printf("select error\n");
continue;
}
res = FD_ISSET(fd, &rset);
read(fd, buf, 32);
if(res > 0)
igmpjoinreport(argv[1], argv[2]);
fprintf(stderr, "===================================== \n");
}
close(fd);
}
return 0;
}