cc5ffc9f73d22630957766f63e30a3e16e5ea079
[senf.git] / senf / Socket / Protocols / INet / MulticastSocketProtocol.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief MulticastSocketProtocol non-inline non-template implementation */
30
31 #include "MulticastSocketProtocol.hh"
32 //#include "MulticastSocketProtocol.ih"
33
34 // Custom includes
35 #include <sys/socket.h>
36 #include <netinet/in.h>
37 #include <net/if.h> // for if_nametoindex
38 #include <senf/Utils/Exception.hh>
39
40 //#include "MulticastSocketProtocol.mpp"
41 #define prefix_
42 //-/////////////////////////////////////////////////////////////////////////////////////////////////
43
44 //-/////////////////////////////////////////////////////////////////////////////////////////////////
45 // senf::MulticastSocketProtocol
46
47 prefix_ void senf::MulticastSocketProtocol::broadcastEnabled(bool v)
48     const
49 {
50     int ivalue (v);
51     if (::setsockopt(fd(), SOL_SOCKET, SO_BROADCAST, &ivalue, sizeof(ivalue)) < 0)
52         SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(SO_BROADCAST)");
53 }
54
55 prefix_ bool senf::MulticastSocketProtocol::broadcastEnabled()
56     const
57 {
58     int value (0);
59     ::socklen_t len (sizeof(value));
60     if (::getsockopt(fd(), SOL_SOCKET, SO_BROADCAST, &value, &len) < 0)
61         SENF_THROW_SYSTEM_EXCEPTION("::getsockopt(SO_BROADCAST)");
62     return value;
63 }
64
65 prefix_ bool senf::MulticastSocketProtocol::mcLoop()
66     const
67 {
68     int value (0);
69     socklen_t len (sizeof(value));
70     if (::getsockopt(fd(),SOL_IP,IP_MULTICAST_LOOP,&value,&len) < 0)
71         SENF_THROW_SYSTEM_EXCEPTION("");
72     return value;
73 }
74
75 prefix_ void senf::MulticastSocketProtocol::mcLoop(bool value)
76     const
77 {
78     int ivalue (value);
79     if (::setsockopt(fd(),SOL_IP,IP_MULTICAST_LOOP,&ivalue,sizeof(ivalue)) < 0)
80         SENF_THROW_SYSTEM_EXCEPTION("");
81 }
82
83 prefix_ void senf::MulticastSocketProtocol::mcIface(std::string const & iface)
84     const
85 {
86     struct ip_mreqn mreqn;
87     ::memset(&mreqn, 0, sizeof(mreqn));
88     if (!iface.empty()) {
89         mreqn.imr_ifindex = if_nametoindex(iface.c_str());
90         if (mreqn.imr_ifindex == 0)
91             throw SystemException(EINVAL SENF_EXC_DEBUGINFO);
92     }
93     if (::setsockopt(fd(),SOL_IP,IP_MULTICAST_IF,&mreqn,sizeof(mreqn)) < 0)
94         SENF_THROW_SYSTEM_EXCEPTION("");
95 }
96
97 prefix_ unsigned senf::MulticastSocketProtocol::mcTTL()
98     const
99 {
100     int value (0);
101     socklen_t len (sizeof(value));
102     if (::getsockopt(fd(),SOL_IP,IP_MULTICAST_TTL,&value,&len) < 0)
103         SENF_THROW_SYSTEM_EXCEPTION("");
104     return value;
105 }
106
107 prefix_ void senf::MulticastSocketProtocol::mcTTL(unsigned value)
108     const
109 {
110     if (::setsockopt(fd(),SOL_IP,IP_MULTICAST_TTL,&value,sizeof(value)) < 0)
111         SENF_THROW_SYSTEM_EXCEPTION("");
112 }
113
114 //-/////////////////////////////////////////////////////////////////////////////////////////////////
115 // senf::INet4MulticastSocketProtocol
116
117 prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address const & mcAddr)
118     const
119 {
120     struct ip_mreqn mreqn;
121     mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
122     mreqn.imr_address.s_addr = htons(INADDR_ANY);
123     mreqn.imr_ifindex = 0;
124     if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
125         SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP)");
126 }
127
128 prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address const & mcAddr,
129                                                                  INet4Address const & localAddr)
130     const
131 {
132     struct ip_mreqn mreqn;
133     mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
134     mreqn.imr_address.s_addr = localAddr.inaddr();
135     mreqn.imr_ifindex = 0;
136     if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
137         SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
138 }
139
140 prefix_ void senf::INet4MulticastSocketProtocol::mcAddMembership(INet4Address const & mcAddr,
141                                                                  std::string const & iface)
142     const
143 {
144     struct ip_mreqn mreqn;
145     mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
146     mreqn.imr_address.s_addr = htons(INADDR_ANY);
147     mreqn.imr_ifindex = if_nametoindex(iface.c_str());
148     if (mreqn.imr_ifindex == 0)
149         throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
150     if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
151         SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
152 }
153
154 prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address const & mcAddr)
155     const
156 {
157     struct ip_mreqn mreqn;
158     mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
159     mreqn.imr_address.s_addr = htons(INADDR_ANY);
160     mreqn.imr_ifindex = 0;
161     if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
162         SENF_THROW_SYSTEM_EXCEPTION("");
163 }
164
165 prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address const & mcAddr,
166                                                                   INet4Address const & localAddr)
167     const
168 {
169     struct ip_mreqn mreqn;
170     mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
171     mreqn.imr_address.s_addr = localAddr.inaddr();
172     mreqn.imr_ifindex = 0;
173     if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
174         SENF_THROW_SYSTEM_EXCEPTION("");
175 }
176
177 prefix_ void senf::INet4MulticastSocketProtocol::mcDropMembership(INet4Address const & mcAddr,
178                                                                   std::string const & iface)
179     const
180 {
181     struct ip_mreqn mreqn;
182     mreqn.imr_multiaddr.s_addr = mcAddr.inaddr();
183     mreqn.imr_address.s_addr = htons(INADDR_ANY);
184     mreqn.imr_ifindex = if_nametoindex(iface.c_str());
185     if (mreqn.imr_ifindex == 0)
186         throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
187     if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
188         SENF_THROW_SYSTEM_EXCEPTION("");
189 }
190
191 namespace {
192     void mc4SSMSourceRequest(int operation, int fd, senf::INet4Address const & group,
193                               senf::INet4Address const & source, std::string const & iface)
194     {
195         struct group_source_req req;
196         ::memset(&req, 0, sizeof(req));
197         req.gsr_interface = if_nametoindex(iface.c_str());
198         if (req.gsr_interface == 0)
199             throw senf::SystemException("::if_nametoindex()", ENOENT SENF_EXC_DEBUGINFO);
200         req.gsr_group.ss_family = AF_INET;
201         reinterpret_cast<struct sockaddr_in&>(req.gsr_group).sin_addr.s_addr = group.inaddr();
202         req.gsr_source.ss_family = AF_INET;
203         reinterpret_cast<struct sockaddr_in&>(req.gsr_source).sin_addr.s_addr = source.inaddr();
204         if (::setsockopt(fd, SOL_IP, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) < 0)
205             SENF_THROW_SYSTEM_EXCEPTION("::setsockopt()");
206     }
207 }
208
209 prefix_ void senf::INet4MulticastSocketProtocol::mcJoinSSMSource(INet4Address const & group,
210                                                                  INet4Address const & source,
211                                                                  std::string const & iface)
212     const
213 {
214     mc4SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, iface);
215 }
216
217 prefix_ void senf::INet4MulticastSocketProtocol::mcLeaveSSMSource(INet4Address const & group,
218                                                                   INet4Address const & source,
219                                                                   std::string const & iface)
220     const
221 {
222     mc4SSMSourceRequest(MCAST_LEAVE_SOURCE_GROUP, fd(), group, source, iface);
223 }
224
225 //-/////////////////////////////////////////////////////////////////////////////////////////////////
226 // senf::INet6MulticastSocketProtocol
227
228 prefix_ void senf::INet6MulticastSocketProtocol::mcAddMembership(INet6Address const & mcAddr)
229     const
230 {
231     if (mcAddr.inet4Mapped()) {
232         struct ip_mreqn mreqn;
233         mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
234         mreqn.imr_address.s_addr = htons(INADDR_ANY);
235         mreqn.imr_ifindex = 0;
236         if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
237             SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP)");
238     }
239     else {
240         struct ipv6_mreq mreqn;
241         std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
242         mreqn.ipv6mr_interface = 0;
243         if (::setsockopt(fd(),SOL_IPV6,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
244             SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
245     }
246 }
247
248 prefix_ void senf::INet6MulticastSocketProtocol::mcAddMembership(INet6Address const & mcAddr,
249                                                                  std::string const & iface)
250     const
251 {
252     if (mcAddr.inet4Mapped()) {
253         struct ip_mreqn mreqn;
254         mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
255         mreqn.imr_address.s_addr = htons(INADDR_ANY);
256         mreqn.imr_ifindex = if_nametoindex(iface.c_str());
257         if (mreqn.imr_ifindex == 0)
258             throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
259         if (::setsockopt(fd(),SOL_IP,IP_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
260             SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IP_ADD_MEMBERSHIP");
261     }
262     else {
263         struct ipv6_mreq mreqn;
264         std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
265         mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
266         if (mreqn.ipv6mr_interface == 0)
267             throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
268         if (::setsockopt(fd(),SOL_IPV6,IPV6_ADD_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
269             SENF_THROW_SYSTEM_EXCEPTION("::setsockopt(IPV6_ADD_MEMBERSHIP");
270     }
271 }
272
273 prefix_ void senf::INet6MulticastSocketProtocol::mcDropMembership(INet6Address const & mcAddr)
274     const
275 {
276     if (mcAddr.inet4Mapped()) {
277         struct ip_mreqn mreqn;
278         mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
279         mreqn.imr_address.s_addr = htons(INADDR_ANY);
280         mreqn.imr_ifindex = 0;
281         if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
282             SENF_THROW_SYSTEM_EXCEPTION("");
283     }
284     else {
285         struct ipv6_mreq mreqn;
286         std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
287         mreqn.ipv6mr_interface = 0;
288         if (::setsockopt(fd(),SOL_IPV6,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
289             SENF_THROW_SYSTEM_EXCEPTION("");
290     }
291 }
292
293 prefix_ void
294 senf::INet6MulticastSocketProtocol::mcDropMembership(INet6Address const & mcAddr,
295                                                      std::string const & iface)
296     const
297 {
298     if (mcAddr.inet4Mapped()) {
299         struct ip_mreqn mreqn;
300         mreqn.imr_multiaddr.s_addr = mcAddr.inet4address().inaddr();
301         mreqn.imr_address.s_addr = htons(INADDR_ANY);
302         mreqn.imr_ifindex = if_nametoindex(iface.c_str());
303         if (mreqn.imr_ifindex == 0)
304             throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
305         if (::setsockopt(fd(),SOL_IP,IP_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
306             SENF_THROW_SYSTEM_EXCEPTION("");
307     }
308     else {
309         struct ipv6_mreq mreqn;
310         std::copy(mcAddr.begin(), mcAddr.end(), mreqn.ipv6mr_multiaddr.s6_addr);
311         mreqn.ipv6mr_interface = if_nametoindex(iface.c_str());
312         if (mreqn.ipv6mr_interface == 0)
313             throw SystemException("::if_nametoindex()",ENOENT SENF_EXC_DEBUGINFO);
314         if (::setsockopt(fd(),SOL_IPV6,IPV6_DROP_MEMBERSHIP,&mreqn,sizeof(mreqn)) < 0)
315             SENF_THROW_SYSTEM_EXCEPTION("");
316     }
317 }
318
319 namespace {
320
321     void mc6SSMSourceRequest(int operation, int fd, senf::INet6Address const & group,
322                              senf::INet6Address const & source, int ifacei)
323     {
324         struct group_source_req req;
325         ::memset(&req, 0, sizeof(req));
326         req.gsr_interface = ifacei;
327         req.gsr_group.ss_family = AF_INET6;
328         std::copy(group.begin(), group.end(),
329                   reinterpret_cast<struct sockaddr_in6&>(req.gsr_group).sin6_addr.s6_addr);
330         req.gsr_source.ss_family = AF_INET6;
331         std::copy(source.begin(), source.end(),
332                   reinterpret_cast<struct sockaddr_in6&>(req.gsr_source).sin6_addr.s6_addr);
333         if (::setsockopt(fd, SOL_IPV6, MCAST_JOIN_SOURCE_GROUP, &req, sizeof(req)) < 0)
334             SENF_THROW_SYSTEM_EXCEPTION("::setsockopt()");
335     }
336
337     void mc6SSMSourceRequest(int operation, int fd, senf::INet6Address const & group,
338                              senf::INet6Address const & source, std::string const & iface)
339     {
340         int ifacei (0);
341         if (! iface.empty()) {
342             ifacei = if_nametoindex(iface.c_str());
343             if (ifacei == 0)
344                 throw senf::SystemException("::if_nametoindex()", ENOENT SENF_EXC_DEBUGINFO);
345         }
346         mc6SSMSourceRequest(operation, fd, group, source, ifacei);
347     }
348
349 }
350
351 prefix_ void senf::INet6MulticastSocketProtocol::mcJoinSSMSource(INet6Address const & group,
352                                                                  INet6Address const & source,
353                                                                  std::string const & iface)
354     const
355 {
356     mc6SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, iface);
357 }
358
359 prefix_ void senf::INet6MulticastSocketProtocol::mcJoinSSMSource(INet6Address const & group,
360                                                                  INet6Address const & source,
361                                                                  int ifacei)
362     const
363 {
364     mc6SSMSourceRequest(MCAST_JOIN_SOURCE_GROUP, fd(), group, source, ifacei);
365 }
366
367 prefix_ void senf::INet6MulticastSocketProtocol::mcLeaveSSMSource(INet6Address const & group,
368                                                                   INet6Address const & source,
369                                                                   std::string const & iface)
370     const
371 {
372     mc6SSMSourceRequest(MCAST_LEAVE_SOURCE_GROUP, fd(), group, source, iface);
373 }
374
375
376 //-/////////////////////////////////////////////////////////////////////////////////////////////////
377 #undef prefix_
378 //#include "MulticastSocketProtocol.mpp"
379
380 \f
381 // Local Variables:
382 // mode: c++
383 // fill-column: 100
384 // comment-column: 40
385 // c-file-style: "senf"
386 // indent-tabs-mode: nil
387 // ispell-local-dictionary: "american"
388 // compile-command: "scons -u test"
389 // End: