socket_linux.cc
Go to the documentation of this file.
1 /*
2  * rcdiscover - the network discovery tool for Roboception devices
3  *
4  * Copyright (c) 2017 Roboception GmbH
5  * All rights reserved
6  *
7  * Author: Raphael Schaller
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. Neither the name of the copyright holder nor the names of its contributors
20  * may be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
27  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  */
35 
36 #include "socket_linux.h"
37 
38 #include "socket_exception.h"
40 #include "utils.h"
41 
42 #include <arpa/inet.h>
43 #include <unistd.h>
44 #include <sys/socket.h>
45 #include <sys/ioctl.h>
46 #include <net/if.h>
47 #include <linux/if_packet.h>
48 #include <netinet/ether.h>
49 #include <ifaddrs.h>
50 #include <fcntl.h>
51 
52 #include <iostream>
53 #include <algorithm>
54 
55 namespace rcdiscover
56 {
57 
59 {
60  static const in_addr_t bcast = htonl(INADDR_BROADCAST);
61  return bcast;
62 }
63 
64 const sockaddr_in& SocketLinux::getDestSockAddr() const
65 {
66  return dst_addr_;
67 }
68 
69 SocketLinux SocketLinux::create(const in_addr_t dst_ip, const uint16_t port,
70  std::string iface_name)
71 {
72  return SocketLinux(AF_INET, SOCK_DGRAM, IPPROTO_UDP, dst_ip, port,
73  std::move(iface_name));
74 }
75 
77  const uint16_t port)
78 {
79  std::vector<SocketLinux> sockets;
80 
81  ifaddrs *addrs;
82  getifaddrs(&addrs);
83 
84  int i = 0;
85 
86  for(ifaddrs *addr = addrs;
87  addr != nullptr;
88  addr = addr->ifa_next)
89  {
90  auto baddr = addr->ifa_ifu.ifu_broadaddr;
91  if (addr->ifa_flags & IFF_UP &&
92  addr->ifa_name != nullptr &&
93  addr->ifa_addr != nullptr &&
94  addr->ifa_addr->sa_family == AF_INET &&
95  baddr != nullptr)
96  {
97  std::string name(addr->ifa_name);
98  if (name.length() != 0 && name != "lo")
99  {
100  const in_addr_t s_addr =
101  reinterpret_cast<struct sockaddr_in *>(addr->ifa_addr)->
102  sin_addr.s_addr;
103 
104  uint16_t local_port = 0;
105 
106  {
107  // limited broadcast
108  sockets.emplace_back(SocketLinux::create(getBroadcastAddr(), port, name));
109 
110  sockaddr_in addr;
111  addr.sin_family = AF_INET;
112  addr.sin_port = 0;
113  addr.sin_addr.s_addr = s_addr;
114  sockets.back().bind(addr);
115  }
116 
117  {
118  // get port to which the limited broadcast socket is bound to
119  struct sockaddr_in local_address;
120  socklen_t address_length = sizeof(local_address);
121  getsockname(sockets.back().sock_,
122  reinterpret_cast<sockaddr *>(&local_address),
123  &address_length);
124  local_port = local_address.sin_port;
125  }
126 
127  {
128  // limited broadcast receiver
129  sockets.emplace_back(SocketLinux::create(htonl(INADDR_ANY), port, name));
130 
131  sockaddr_in addr;
132  addr.sin_family = AF_INET;
133  addr.sin_port = local_port;
134  addr.sin_addr.s_addr = htonl(INADDR_ANY);
135  sockets.back().bind(addr);
136  }
137 
138  {
139  // directed broadcast
140  sockets.emplace_back(
142  reinterpret_cast<struct sockaddr_in *>(baddr)->
143  sin_addr.s_addr, port, name));
144  sockaddr_in addr;
145  addr.sin_family = AF_INET;
146  addr.sin_port = local_port;
147  addr.sin_addr.s_addr = htonl(INADDR_ANY);
148  sockets.back().bind(addr);
149  }
150  }
151  }
152 
153  ++i;
154  }
155 
156  freeifaddrs(addrs);
157  addrs = nullptr;
158 
159  return sockets;
160 }
161 
162 SocketLinux::SocketLinux(int domain, int type, int protocol,
163  in_addr_t dst_ip, uint16_t port,
164  std::string iface_name) :
165  Socket(std::move(iface_name)),
166  sock_(-1),
167  dst_addr_()
168 {
169  sock_ = ::socket(domain, type, protocol);
170  if (sock_ == -1)
171  {
172  if (errno == EPERM)
173  {
174  throw OperationNotPermitted();
175  }
176 
177  throw SocketException("Error while creating socket", errno);
178  }
179 
180  dst_addr_.sin_addr.s_addr = dst_ip;
181  dst_addr_.sin_family = AF_INET;
182  dst_addr_.sin_port = htons(port);
183 
184  const int yes = 1;
185  if (::setsockopt(sock_,
186  SOL_SOCKET,
187  SO_REUSEPORT,
188  reinterpret_cast<const char *>(&yes),
189  sizeof(yes)) == -1)
190  {
191  throw SocketException("Error while setting socket options", errno);
192  }
193 }
194 
196  Socket(std::move(other)),
197  sock_(-1),
198  dst_addr_(std::move(other.dst_addr_))
199 {
200  std::swap(sock_, other.sock_);
201 }
202 
204 {
205  std::swap(sock_, other.sock_);
206  return *this;
207 }
208 
210 {
211  if (sock_ != -1)
212  {
213  ::close(sock_);
214  }
215 }
216 
217 const int &SocketLinux::getHandleImpl() const
218 {
219  return sock_;
220 }
221 
222 void SocketLinux::bindImpl(const ::sockaddr_in& addr)
223 {
224  if (::bind(sock_,
225  reinterpret_cast<const sockaddr *>(&addr),
226  sizeof(sockaddr)) == -1)
227  {
228  throw SocketException("Error while binding to socket", errno);
229  }
230 }
231 
232 void SocketLinux::sendImpl(const std::vector<uint8_t>& sendbuf)
233 {
234  if (::sendto(sock_,
235  static_cast<const void *>(sendbuf.data()),
236  sendbuf.size(),
237  0,
238  reinterpret_cast<const sockaddr *>(&dst_addr_),
239  static_cast<socklen_t>(sizeof(sockaddr_in))) == -1)
240  {
241  if (errno == ENETUNREACH)
242  {
244  "Error while sending data - network unreachable", errno);
245  }
246 
247  throw SocketException("Error while sending data", errno);
248  }
249 }
250 
252 {
253  const int yes = 1;
254  if (::setsockopt(sock_,
255  SOL_SOCKET,
256  SO_BROADCAST,
257  reinterpret_cast<const char *>(&yes),
258  sizeof(yes)) == -1)
259  {
260  throw SocketException("Error while setting socket options", errno);
261  }
262 }
263 
265 {
266  int flags = fcntl(sock_, F_GETFL, 0);
267  if (flags < 0 || fcntl(sock_, F_SETFL, flags | O_RDWR | O_NONBLOCK) == -1)
268  {
269  throw SocketException("Error while setting socket non-blocking", errno);
270  }
271 }
272 
273 void SocketLinux::bindToDevice(const std::string &device)
274 {
275  if (::setsockopt(sock_,
276  SOL_SOCKET,
277  SO_BINDTODEVICE,
278  device.c_str(),
279  static_cast<socklen_t>(device.size())) == -1)
280  {
281  if (errno == 1)
282  {
283  throw OperationNotPermitted();
284  }
285 
286  throw SocketException("Error while binding to device \"" + device + "\"",
287  errno);
288  }
289 }
290 
291 }
void bindToDevice(const std::string &device)
Binds this socket to a specific device (root privileges are required).
const int & getHandleImpl() const
Returns the native socket handle.
static std::vector< SocketLinux > createAndBindForAllInterfaces(uint16_t port)
Creates sockets for all interfaces and binds them to the respective interface.
Definition: socket_linux.cc:76
const sockaddr_in & getDestSockAddr() const
Returns the sockaddr to which the socket is bound.
Definition: socket_linux.cc:64
Exception representing an invalid socket operation.
void sendImpl(const std::vector< uint8_t > &sendbuf)
Sends data.
CRTP class for platform specific socket implementation.
Definition: socket.h:52
Exception representing a Network Unreachable error (code 101 on Unix).
SocketLinux(int domain, int type, int protocol, in_addr_t dst_ip, uint16_t port, std::string iface_name)
Constructor.
void bind(const sockaddr_in &addr)
Binds the socket to an interface.
Definition: socket.h:89
Exception representing an "operation not permitted" error.
static const in_addr_t & getBroadcastAddr()
Returns the broadcast address.
Definition: socket_linux.cc:58
void enableNonBlockingImpl()
Enables non-blocking operation for this socket.
void bindImpl(const sockaddr_in &addr)
Binds the socket to a specific sockaddr.
static SocketLinux create(in_addr_t dst_ip, uint16_t port, std::string iface_name)
Create a new socket.
Definition: socket_linux.cc:69
void enableBroadcastImpl()
Enables broadcast for this socket.
Socket implementation for Linux.
Definition: socket_linux.h:51
SocketLinux & operator=(SocketLinux &&other)


rcdiscover
Author(s): Heiko Hirschmueller , Raphael Schaller
autogenerated on Sun Apr 18 2021 02:16:32