-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmcast.cpp
111 lines (89 loc) · 2.67 KB
/
mcast.cpp
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#include <unistd.h>
#include <syslog.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string>
#include <vector>
#include <limits>
#include "server.h"
class MulticastRefCount {
public:
ipaddr_t addr;
uint32_t refCount;
MulticastRefCount() : refCount(0) { }
MulticastRefCount(ipaddr_t addr) : addr(addr), refCount(1) { }
};
typedef std::vector<MulticastRefCount> MulticastRefVector;
static MulticastRefVector mcRef;
uint32_t countMulticastGroup(ipaddr_t addr)
{
auto ii = mcRef.begin();
while (ii != mcRef.end()) {
if ((*ii).addr == addr)
return (*ii).refCount;
else
ii++;
}
return 0;
}
bool joinMulticastGroup(int socket, ipaddr_t addr)
{
auto ii = mcRef.begin();
// See if we are already a member of the multicast group 'addr'
// and just increment the reference count if we are
while (ii != mcRef.end()) {
if ((*ii).addr == addr) {
if ((*ii).refCount < (uint32_t) std::numeric_limits<uint32_t>::max()) {
(*ii).refCount++;
return true;
} else
return false;
} else
ii++;
}
// At this point we know we are the first task to request this
// multicast group so we add the multicast address to the
// reference count vector and then join the group
ip_mreq mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_multiaddr.s_addr = htonl(addr.value());
if (-1 == setsockopt(socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)))
syslog(LOG_ERR, "Couldn't join multicast group: %s -- %m", addr.str().c_str());
else {
MulticastRefCount mcRefTmp(addr);
mcRef.push_back(mcRefTmp);
#ifdef DEBUG
syslog(LOG_DEBUG, "Joined multicast group: %s", addr.str().c_str());
#endif
return true;
}
return false;
}
void dropMulticastGroup(int socket, ipaddr_t addr)
{
auto ii = mcRef.begin();
while (ii != mcRef.end()) {
if ((*ii).addr == addr) {
// When we decrement the reference count to zero then no
// other tasks need to be part of this group so we drop
// member ship and remove the multicast address from the
// reference count vector
if ((*ii).refCount)
(*ii).refCount--;
if ((*ii).refCount == 0) {
ip_mreq mreq;
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
mreq.imr_multiaddr.s_addr = htonl(addr.value());
if (-1 == setsockopt(socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)))
syslog(LOG_ERR, "Couldn't drop multicast group: %s -- %m", addr.str().c_str());
#ifdef DEBUG
else
syslog(LOG_DEBUG, "Dropped multicast group: %s", addr.str().c_str());
#endif
mcRef.erase(ii);
}
return;
} else
ii++;
}
}