-
Notifications
You must be signed in to change notification settings - Fork 0
/
joinch.c
88 lines (77 loc) · 2.65 KB
/
joinch.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*
* Copyright (C) 2005 Stig Venaas <[email protected]>
* $Id:$
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*/
#include "ssmping.h"
#ifndef MCAST_JOIN_SOURCE_GROUP
#ifdef WIN32 /* Only useful on Vista */
#define MCAST_JOIN_SOURCE_GROUP 45
#endif
#ifdef linux
#define MCAST_JOIN_SOURCE_GROUP 46
#endif
struct group_source_req {
uint32_t gsr_interface; /* interface index */
struct sockaddr_storage gsr_group; /* group address */
struct sockaddr_storage gsr_source; /* source address */
};
#endif
void joinchannel(int s, struct sockaddr *src, struct sockaddr *grp, uint32_t intface, struct sockaddr *ifaddr) {
#ifdef MCAST_JOIN_SOURCE_GROUP
int level;
socklen_t addrlen;
#ifdef WIN32
struct ip_mreq_source imsr;
#endif
struct group_source_req gsreq;
if (src->sa_family != grp->sa_family) {
fprintf(stderr, "joinchannel failed, source and group must be of same address family\n");
exit(1);
}
if (ifaddr && ifaddr->sa_family != grp->sa_family) {
fprintf(stderr, "joinchannel failed, group and interface must be of same address family\n");
exit(1);
}
switch (grp->sa_family) {
case AF_INET:
addrlen = sizeof(struct sockaddr_in);
level = IPPROTO_IP;
break;
case AF_INET6:
addrlen = sizeof(struct sockaddr_in6);
level = IPPROTO_IPV6;
break;
default:
fprintf(stderr, "joinchannel failed, unsupported address family\n");
exit(1);
}
memset(&gsreq, 0, sizeof(gsreq));
memcpy(&gsreq.gsr_source, src, addrlen);
memcpy(&gsreq.gsr_group, grp, addrlen);
gsreq.gsr_interface = intface;
#ifndef WIN32
if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) < 0)
errx("Failed to join multicast channel");
#else
if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) >= 0)
return;
if (level != IPPROTO_IP)
errx("Failed to join multicast channel");
/* For Windows XP the above setsockopt fails, below works for IPv4
* While for Windows Vista the above should work
*/
memset(&imsr, 0, sizeof(imsr));
imsr.imr_sourceaddr = ((struct sockaddr_in *)src)->sin_addr;
imsr.imr_multiaddr = ((struct sockaddr_in *)grp)->sin_addr;
imsr.imr_interface = ((struct sockaddr_in *)ifaddr)->sin_addr;
if (setsockopt(s, level, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imsr, sizeof(imsr)) < 0)
errx("Failed to join multicast channel");
#endif
#else
errx("Not built with SSM support, failed to join multicast channel");
#endif
}