EMANE  1.2.1
multicastsocket.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 - Adjacent Link LLC, Bridgewater, New Jersey
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in
13  * the documentation and/or other materials provided with the
14  * distribution.
15  * * Neither the name of Adjacent Link LLC nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include "multicastsocket.h"
34 #include "socketexception.h"
35 #include <cstring>
36 #include <arpa/inet.h>
37 #include <sys/ioctl.h>
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 
42 
44  bool bReuseAddress,
45  const std::string & sDevice,
46  std::uint8_t u8TTL,
47  bool bLoop)
48 {
49  open(address,
50  bReuseAddress,
51  sDevice,
52  u8TTL,
53  bLoop);
54 }
55 
57  bool bReuseAddress,
58  const std::string & sDevice,
59  std::uint8_t u8TTL,
60  bool bLoop)
61 {
62  if(iSock_ != -1)
63  {
64  close();
65  }
66 
67  addr_ = address;
68 
69  if((iSock_ = socket(address.getFamily(),
70  SOCK_DGRAM,
71  0)) == -1)
72  {
73  throw SocketException(strerror(errno));
74  }
75 
76  // set ipv4 or ipv6 options
77  if(address.isIPv4())
78  {
79  if(setsockopt(iSock_,
80  IPPROTO_IP,IP_MULTICAST_TTL,
81  (void*)&u8TTL,
82  sizeof(u8TTL)) < 0)
83  {
84  throw makeException<SocketException>("setsockopt IP_MULTICAST_TTL: %s",
85  strerror(errno));
86  }
87 
88 
89  if(bLoop)
90  {
91  std::uint8_t u8Option = 1;
92 
93  // set the multicast loopback
94  if(setsockopt(iSock_,IPPROTO_IP,IP_MULTICAST_LOOP,
95  &u8Option,
96  sizeof(u8Option)) < 0)
97  {
98  throw makeException<SocketException>("setsockopt IP_MULTICAST_LOOP: %s",
99  strerror(errno));
100  }
101  }
102 
103  // multicast group info used for join
104  ip_mreq mreq;
105 
106  memset(&mreq,0,sizeof(mreq));
107 
108  memcpy(&mreq.imr_multiaddr,
109  &reinterpret_cast<sockaddr_in *>(address.getSockAddr())->sin_addr,
110  sizeof(mreq.imr_multiaddr));
111 
112  if(!sDevice.empty())
113  {
114  ifreq ifr;
115  memset(&ifr,0,sizeof(ifr));
116  strncpy(ifr.ifr_name,sDevice.c_str(),IFNAMSIZ);
117 
118  // get the ip address
119  if(ioctl(iSock_,SIOCGIFADDR,&ifr) < 0)
120  {
121  throw makeException<SocketException>("ioctl SIOCGIFADDR: %s",
122  strerror(errno));
123  }
124 
125  // set the multicast interface
126  if(setsockopt(iSock_,
127  IPPROTO_IP,
128  IP_MULTICAST_IF,
129  &reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr,
130  sizeof(in_addr)) < 0)
131  {
132  throw makeException<SocketException>("setsockopt IP_MULTICAST_IF: %s",
133  strerror(errno));
134  }
135 
136  mreq.imr_interface.s_addr =
137  reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr)->sin_addr.s_addr;
138  }
139  else
140  {
141  mreq.imr_interface.s_addr = INADDR_ANY;
142  }
143 
144  if(setsockopt(iSock_,
145  IPPROTO_IP,
146  IP_ADD_MEMBERSHIP,
147  reinterpret_cast<void*>(&mreq),
148  sizeof(mreq)) < 0)
149  {
150  throw makeException<SocketException>("setsockopt IP_ADD_MEMBERSHIP: %s",
151  strerror(errno));
152  }
153  }
154 
155  else if(address.isIPv6())
156  {
157  int iOption{u8TTL};
158 
159  if(setsockopt(iSock_,
160  IPPROTO_IPV6,
161  IPV6_MULTICAST_HOPS,
162  &iOption,
163  sizeof(iOption)) < 0)
164  {
165  throw makeException<SocketException>("setsockopt IPV6_MULTICAST_HOPS: %s",
166  strerror(errno));
167  }
168 
169  if(bLoop)
170  {
171  iOption = 1;
172 
173  if(setsockopt(iSock_,
174  IPPROTO_IPV6,
175  IPV6_MULTICAST_LOOP,
176  &iOption,
177  sizeof(iOption)) < 0)
178  {
179  throw makeException<SocketException>("setsockopt IPV6_MULTICAST_LOOP: %s",
180  strerror(errno));
181  }
182  }
183 
184  ipv6_mreq mreq6;
185 
186  memset(&mreq6,0,sizeof(mreq6));
187 
188  memcpy(&mreq6.ipv6mr_multiaddr,
189  &reinterpret_cast<sockaddr_in6 *>(address.getSockAddr())->sin6_addr,
190  sizeof(mreq6.ipv6mr_multiaddr));
191 
192  mreq6.ipv6mr_interface = 0;
193 
194  if(!sDevice.empty())
195  {
196  unsigned int iIndex{if_nametoindex(sDevice.c_str())};
197 
198  if(setsockopt(iSock_,
199  IPPROTO_IPV6,
200  IPV6_MULTICAST_IF,
201  &iIndex,
202  sizeof(iIndex)) < 0)
203  {
204  throw makeException<SocketException>("setsockopt IPV6_MULTICAST_IF: %s",
205  strerror(errno));
206  }
207 
208  mreq6.ipv6mr_interface = iIndex;
209  }
210 
211  if(setsockopt(iSock_,
212  IPPROTO_IPV6,
213  IPV6_ADD_MEMBERSHIP,
214  reinterpret_cast<void *>(&mreq6),
215  sizeof(mreq6)) < 0)
216  {
217  throw makeException<SocketException>("setsockopt IPV6_ADD_MEMBERSHIP: %s",
218  strerror(errno));
219  }
220  }
221  else
222  {
223  throw makeException<SocketException>("Unknown address family");
224  }
225 
226  if(bReuseAddress)
227  {
228  int iOption{1};
229 
230  if(setsockopt(iSock_,
231  SOL_SOCKET,
232  SO_REUSEADDR,
233  reinterpret_cast<void*>(&iOption),
234  sizeof(iOption)) < 0)
235  {
236  throw makeException<SocketException>("setsockopt SO_REUSEADDR: %s",
237  strerror(errno));
238 
239  }
240  }
241 
242 
243  if(bind(iSock_,addr_.getSockAddr(),addr_.getAddrLength()) < 0)
244  {
245  throw makeException<SocketException>("bind: %s",
246  strerror(errno));
247  }
248 
249 }
250 
252 
253 
254 ssize_t EMANE::MulticastSocket::send(const iovec *iov, int iovcnt, int flags) const
255 {
256  msghdr msg;
257  memset(&msg,0,sizeof(msg));
258 
259  msg.msg_iov = const_cast<iovec *>(iov);
260  msg.msg_iovlen = iovcnt;
261 
262  msg.msg_name = addr_.getSockAddr();
263  msg.msg_namelen = addr_.getAddrLength();
264 
265  return sendmsg(iSock_,&msg,flags);
266 }
267 
268 ssize_t EMANE::MulticastSocket::recv(void * buf,
269  size_t len,
270  int flags)
271 {
272  return ::recv(iSock_,buf,len,flags);
273 }
ssize_t recv(void *buf, size_t len, int flags=0)
void close()
Definition: socket.cc:40
socklen_t getAddrLength() const
Definition: inetaddr.cc:404
bool isIPv6() const
Definition: inetaddr.cc:379
sockaddr * getSockAddr() const
Definition: inetaddr.cc:399
bool isIPv4() const
Definition: inetaddr.cc:384
struct in_addr sin_addr
Definition: tuntap.h:544
ssize_t send(const iovec *iov, int iovcnt, int flags=0) const
int getFamily() const
Definition: inetaddr.cc:394
int iSock_
Definition: socket.h:55
void open(const INETAddr &address, bool bReuseAddress=false, const std::string &sDevice="", std::uint8_t u8TTL=1, bool bLoop=false)