MulticastSocketProtocol.cc
Go to the documentation of this file.
1 //
2 // Copyright (c) 2020 Fraunhofer Institute for Applied Information Technology (FIT)
3 // Network Research Group (NET)
4 // Schloss Birlinghoven, 53754 Sankt Augustin, GERMANY
5 // Contact: support@wiback.org
6 //
7 // This file is part of the SENF code tree.
8 // It is licensed under the 3-clause BSD License (aka New BSD License).
9 // See LICENSE.txt in the top level directory for details or visit
10 // https://opensource.org/licenses/BSD-3-Clause
11 //
12 
13 
18 //#include "MulticastSocketProtocol.ih"
19 
20 // Custom includes
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <net/if.h> // for if_nametoindex
24 #include <senf/Utils/Exception.hh>
25 
26 //#include "MulticastSocketProtocol.mpp"
27 #define prefix_
28 //-/////////////////////////////////////////////////////////////////////////////////////////////////
29 
30 //-/////////////////////////////////////////////////////////////////////////////////////////////////
31 // senf::MulticastSocketProtocol
32 
34  const
35 {
36  int ivalue (v);
37  if (::setsockopt(fd(), SOL_SOCKET, SO_BROADCAST, &ivalue, sizeof(ivalue)) < 0)
38  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SO_BROADCAST)");
39 }
40 
42  const
43 {
44  int value (0);
45  ::socklen_t len (sizeof(value));
46  if (::getsockopt(fd(), SOL_SOCKET, SO_BROADCAST, &value, &len) < 0)
47  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(SO_BROADCAST)");
48  return value;
49 }
50 
52  const
53 {
54  int value (0);
55  socklen_t len (sizeof(value));
56  if (::getsockopt(fd(),SOL_IP,IP_MULTICAST_LOOP,&value,&len) < 0)
57  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(IP_MULTICAST_LOOP)");
58  return value;
59 }
60 
62  const
63 {
64  int ivalue (value);
65  if (::setsockopt(fd(),SOL_IP,IP_MULTICAST_LOOP,&ivalue,sizeof(ivalue)) < 0)
66  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(IP_MULTICAST_LOOP)");
67 }
68 
69 prefix_ void senf::MulticastSocketProtocol::mcIface(std::string const & iface)
70  const
71 {
72  struct ip_mreqn mreqn;
73  ::memset(&mreqn, 0, sizeof(mreqn));
74  if (!iface.empty()) {
75  mreqn.imr_ifindex = if_nametoindex(iface.c_str());
76  if (mreqn.imr_ifindex == 0)
77  throw SystemException(EINVAL SENF_EXC_DEBUGINFO);
78  }
79  if (::setsockopt(fd(),SOL_IP,IP_MULTICAST_IF,&mreqn,sizeof(mreqn)) < 0)
80  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(IP_MULTICAST_IF)");
81 }
82 
84  const
85 {
86  int value (0);
87  socklen_t len (sizeof(value));
88  if (::getsockopt(fd(),SOL_IP,IP_MULTICAST_TTL,&value,&len) < 0)
89  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(IP_MULTICAST_TTL)");
90  return value;
91 }
92 
94  const
95 {
96  if (::setsockopt(fd(),SOL_IP,IP_MULTICAST_TTL,&value,sizeof(value)) < 0)
97  SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(IP_MULTICAST_TTL");
98 }
99 
100 //-/////////////////////////////////////////////////////////////////////////////////////////////////
101 // senf::INet4MulticastSocketProtocol
102 
104  const
105 {
106  struct ip_mreqn mreqn;
107  mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
108  mreqn.imr_address.s_addr = htons(INADDR_ANY);
109  mreqn.imr_ifindex = 0;
110  if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
111  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP)");
112 }
113 
115  INet4Address const & localAddr)
116  const
117 {
118  struct ip_mreqn mreqn;
119  mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
120  mreqn.imr_address.s_addr = localAddr.inaddr();
121  mreqn.imr_ifindex = 0;
122  if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
123  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
124 }
125 
127  std::string const & iface)
128  const
129 {
130  struct ip_mreqn mreqn;
131  mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
132  mreqn.imr_address.s_addr = htons(INADDR_ANY);
133  mreqn.imr_ifindex = if_nametoindex(iface.c_str());
134  if (mreqn.imr_ifindex == 0)
135  throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
136  if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
137  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
138 }
139 
141  const
142 {
143  struct ip_mreqn mreqn;
144  mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
145  mreqn.imr_address.s_addr = htons(INADDR_ANY);
146  mreqn.imr_ifindex = 0;
147  if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
148  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_DROP_MEMBERSHIP");
149 }
150 
152  INet4Address const & localAddr)
153  const
154 {
155  struct ip_mreqn mreqn;
156  mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
157  mreqn.imr_address.s_addr = localAddr.inaddr();
158  mreqn.imr_ifindex = 0;
159  if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
160  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_DROP_MEMBERSHIP");
161 }
162 
164  std::string const & iface)
165  const
166 {
167  struct ip_mreqn mreqn;
168  mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
169  mreqn.imr_address.s_addr = htons(INADDR_ANY);
170  mreqn.imr_ifindex = if_nametoindex(iface.c_str());
171  if (mreqn.imr_ifindex == 0)
172  throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
173  if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
174  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_DROP_MEMBERSHIP");
175 }
176 
177 namespace {
178  void mc4SSMSourceRequest(int operation, int fd, senf::INet4Address const & group,
179  senf::INet4Address const & source, std::string const & iface)
180  {
181  struct group_source_req req;
182  ::memset(&req, 0, sizeof(req));
183  req.gsr_interface = if_nametoindex(iface.c_str());
184  if (req.gsr_interface == 0)
185  throw senf::SystemException("::if_nametoindex()", ENOENT SENF_EXC_DEBUGINFO);
186  req.gsr_group.ss_family = AF_INET;
187  reinterpret_cast<struct sockaddr_in&>(req.gsr_group).sin_addr.s_addr = group.inaddr();
188  req.gsr_source.ss_family = AF_INET;
189  reinterpret_cast<struct sockaddr_in&>(req.gsr_source).sin_addr.s_addr = source.inaddr();
190  if (::setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) < 0)
191  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt()");
192  }
193 }
194 
196  INet4Address const & source,
197  std::string const & iface)
198  const
199 {
200  mc4SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, iface);
201 }
202 
204  INet4Address const & source,
205  std::string const & iface)
206  const
207 {
208  mc4SSMSourceRequest(MCAST_LEAVE_SOURCE_GROUP, fd(), group, source, iface);
209 }
210 
211 //-/////////////////////////////////////////////////////////////////////////////////////////////////
212 // senf::INet6MulticastSocketProtocol
213 
215  const
216 {
217  if (mcAddr.inet4Mapped()) {
218  struct ip_mreqn mreqn;
219  mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
220  mreqn.imr_address.s_addr = htons(INADDR_ANY);
221  mreqn.imr_ifindex = 0;
222  if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
223  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP)");
224  }
225  else {
226  struct ipv6_mreq mreqn;
227  std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
228  mreqn.ipv6mr_interface = 0;
229  if (::setsockopt(fd(),SOL_IPV6,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
230  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
231  }
232 }
233 
235  std::string const & iface)
236  const
237 {
238  if (mcAddr.inet4Mapped()) {
239  struct ip_mreqn mreqn;
240  mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
241  mreqn.imr_address.s_addr = htons(INADDR_ANY);
242  mreqn.imr_ifindex = if_nametoindex(iface.c_str());
243  if (mreqn.imr_ifindex == 0)
244  throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
245  if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
246  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
247  }
248  else {
249  struct ipv6_mreq mreqn;
250  std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
251  mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
252  if (mreqn.ipv6mr_interface == 0)
253  throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
254  if (::setsockopt(fd(),SOL_IPV6,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
255  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
256  }
257 }
258 
260  const
261 {
262  if (mcAddr.inet4Mapped()) {
263  struct ip_mreqn mreqn;
264  mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
265  mreqn.imr_address.s_addr = htons(INADDR_ANY);
266  mreqn.imr_ifindex = 0;
267  if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
268  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_DROP_MEMBERSHIP");
269  }
270  else {
271  struct ipv6_mreq mreqn;
272  std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
273  mreqn.ipv6mr_interface = 0;
274  if (::setsockopt(fd(),SOL_IPV6,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
275  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_DROP_MEMBERSHIP");
276  }
277 }
278 
279 prefix_ void
281  std::string const & iface)
282  const
283 {
284  if (mcAddr.inet4Mapped()) {
285  struct ip_mreqn mreqn;
286  mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
287  mreqn.imr_address.s_addr = htons(INADDR_ANY);
288  mreqn.imr_ifindex = if_nametoindex(iface.c_str());
289  if (mreqn.imr_ifindex == 0)
290  throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
291  if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
292  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_DROP_MEMBERSHIP");
293  }
294  else {
295  struct ipv6_mreq mreqn;
296  std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
297  mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
298  if (mreqn.ipv6mr_interface == 0)
299  throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
300  if (::setsockopt(fd(),SOL_IPV6,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
301  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_DROP_MEMBERSHIP");
302  }
303 }
304 
305 namespace {
306 
307  void mc6SSMSourceRequest(int operation, int fd, senf::INet6Address const & group,
308  senf::INet6Address const & source, int ifacei)
309  {
310  struct group_source_req req;
311  ::memset(&req, 0, sizeof(req));
312  req.gsr_interface = ifacei;
313  req.gsr_group.ss_family = AF_INET6;
314  std::copy(group.begin(), group.end(),
315  reinterpret_cast<struct sockaddr_in6&>(req.gsr_group).sin6_addr.s6_addr);
316  req.gsr_source.ss_family = AF_INET6;
317  std::copy(source.begin(), source.end(),
318  reinterpret_cast<struct sockaddr_in6&>(req.gsr_source).sin6_addr.s6_addr);
319  if (::setsockopt(fd, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) < 0)
320  SENF_THROW_SYSTEM_EXCEPTION("::setsockopt()");
321  }
322 
323  void mc6SSMSourceRequest(int operation, int fd, senf::INet6Address const & group,
324  senf::INet6Address const & source, std::string const & iface)
325  {
326  int ifacei (0);
327  if (! iface.empty()) {
328  ifacei = if_nametoindex(iface.c_str());
329  if (ifacei == 0)
330  throw senf::SystemException("::if_nametoindex()", ENOENT SENF_EXC_DEBUGINFO);
331  }
332  mc6SSMSourceRequest(operation, fd, group, source, ifacei);
333  }
334 
335 }
336 
338  INet6Address const & source,
339  std::string const & iface)
340  const
341 {
342  mc6SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, iface);
343 }
344 
346  INet6Address const & source,
347  int ifacei)
348  const
349 {
350  mc6SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, ifacei);
351 }
352 
354  INet6Address const & source,
355  std::string const & iface)
356  const
357 {
358  mc6SSMSourceRequest(MCAST_LEAVE_SOURCE_GROUP, fd(), group, source, iface);
359 }
360 
361 
362 //-/////////////////////////////////////////////////////////////////////////////////////////////////
363 #undef prefix_
364 //#include "MulticastSocketProtocol.mpp"
365 
366 
367 // Local Variables:
368 // mode: c++
369 // fill-column: 100
370 // comment-column: 40
371 // c-file-style: "senf"
372 // indent-tabs-mode: nil
373 // ispell-local-dictionary: "american"
374 // compile-command: "scons -u test"
375 // End:
void mcAddMembership(INet6Address const &mcAddr) const
Join multicast group on default interface.
INet4Address inet4address() const
Return embedded INet4 address.
#define SENF_THROW_SYSTEM_EXCEPTION(desc)
void mcDropMembership(INet4Address const &mcAddr) const
Leave multicast group.
void mcAddMembership(INet4Address const &mcAddr) const
Join multicast group on default interface.
void mcIface(std::string const &iface=std::string()) const
Set multicast send interface of the socket.
int fd() const
Get file descriptor.
void mcJoinSSMSource(INet6Address const &group, INet6Address const &source, std::string const &iface) const
join SSM multicast group
MulticastSocketProtocol public header.
void mcDropMembership(INet6Address const &mcAddr) const
Leave multicast group.
void mcLeaveSSMSource(INet4Address const &group, INet4Address const &source, std::string const &iface) const
leave SSM multicast group
bool mcLoop() const
Return current multicast loopback state.
bool inet4Mapped() const
true, if address is INet4 mapped
INet6 network address.
void mcJoinSSMSource(INet4Address const &group, INet4Address const &source, std::string const &iface) const
join SSM multicast group
#define prefix_
void mcLeaveSSMSource(INet6Address const &group, INet6Address const &source, std::string const &iface) const
leave SSM multicast group
#define SENF_EXC_DEBUGINFO
inaddr_type inaddr() const
Return the raw network byte order address.
unsigned mcTTL() const
Return current multicast TTL.
IPv4 Internet address.
Definition: INet4Address.hh:78
bool broadcastEnabled() const
Get broadcast send/receive state.