discover.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: Heiko Hirschmueller
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 "discover.h"
37 
38 #include "socket_exception.h"
39 #include "gige_request_counter.h"
40 
41 #include <exception>
42 #include <ios>
43 #include <iostream>
44 
45 #ifdef WIN32
46 #include <winsock2.h>
47 #include <iphlpapi.h>
48 #else
49 #include <sys/socket.h>
50 #include <sys/types.h>
51 #include <ifaddrs.h>
52 #include <arpa/inet.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #endif
56 
57 #include <vector>
58 #include <future>
59 #include <string.h>
60 #include <errno.h>
61 #include <algorithm>
62 
63 namespace rcdiscover
64 {
65 
66 #ifdef WIN32
67 typedef SocketWindows SocketImpl;
68 #else
70 #endif
71 
73  sockets_(SocketType::createAndBindForAllInterfaces(3956))
74 {
75  for (auto &socket : sockets_)
76  {
77  socket.enableBroadcast();
78  socket.enableNonBlocking();
79  }
80 }
81 
83 { }
84 
86 {
87  req_nums_.clear();
88 
89  std::vector<uint8_t> discovery_cmd{0x42, 0x11, 0, 0x02, 0, 0, 0, 0};
90 
91  for (auto &socket : sockets_)
92  {
94  std::tie(discovery_cmd[6], discovery_cmd[7]) = req_nums_.back();
95 
96  try
97  {
98  socket.send(discovery_cmd);
99  }
100  catch(const NetworkUnreachableException &)
101  {
102  continue;
103  }
104  }
105 }
106 
107 bool Discover::getResponse(std::vector<DeviceInfo> &info,
108  int timeout_per_socket)
109 {
110  // setup waiting for data to arrive
111 
112  struct timeval tv;
113  tv.tv_sec=timeout_per_socket/1000;
114  tv.tv_usec=(timeout_per_socket%1000)*1000;
115 
116  // try to get a valid package (repeat if an invalid package is received)
117 
118  const auto &req_nums = req_nums_;
119 
120  std::vector<std::future<DeviceInfo>> futures;
121  for (auto &socket : sockets_)
122  {
123  futures.push_back(std::async(std::launch::async, [&socket, &tv, &req_nums]
124  {
125  DeviceInfo device_info(socket.getIfaceName());
126  device_info.clear();
127 
128  int count = 10;
129 
130  auto sock = socket.getHandle<typename SocketType::SocketType>();
131 
132  fd_set fds;
133  FD_ZERO(&fds);
134  FD_SET(sock, &fds);
135 
136  while (!device_info.isValid() && count > 0)
137  {
138  count--;
139 
140  if (select(sock+1, &fds, NULL, NULL, &tv) > 0)
141  {
142  // get package
143 
144  uint8_t p[600];
145 
146  struct sockaddr_in addr;
147 #ifdef WIN32
148  int naddr = sizeof(addr);
149 #else
150  socklen_t naddr = sizeof(addr);
151 #endif
152  memset(&addr, 0, naddr);
153 
154  long n = recvfrom(sock,
155  reinterpret_cast<char *>(p), sizeof(p), 0,
156  reinterpret_cast<struct sockaddr *>(&addr), &naddr);
157 
158  // check if received package is a valid discovery acknowledge
159 
160  if (n >= 8)
161  {
162  if (p[0] == 0 && p[1] == 0 && p[2] == 0 &&
163  p[3] == 0x03)
164  {
165  if (std::find(req_nums.begin(), req_nums.end(),
166  std::make_tuple(p[6], p[7])) != req_nums.end())
167  {
168  size_t len=(static_cast<size_t>(p[4])<<8)|p[5];
169 
170  if (static_cast<size_t>(n) >= len+8)
171  {
172  // extract information and store in list
173 
174  device_info.set(p+8, len);
175  }
176  }
177  }
178  }
179  }
180  else
181  {
182  count=0;
183  }
184  }
185 
186  return device_info;
187  }));
188 
189  }
190 
191  bool ret = false;
192  for (auto &f : futures)
193  {
194  info.push_back(f.get());
195  ret |= info.back().isValid();
196  }
197 
198  return ret;
199 }
200 
201 }
std::vector< SocketType > sockets_
Definition: discover.h:91
Discover()
Initializes a socket ready for broadcasting requests.
Definition: discover.cc:72
void clear()
Clears all information.
Definition: deviceinfo.cc:125
std::vector< std::tuple< std::uint8_t, std::uint8_t > > req_nums_
Definition: discover.h:92
SocketLinux SocketImpl
Definition: discover.cc:69
int SocketType
Type representing the native socket handle type.
Definition: socket_linux.h:59
Exception representing a Network Unreachable error (code 101 on Unix).
void broadcastRequest()
Broadcasts a discovery command request.
Definition: discover.cc:85
bool getResponse(std::vector< DeviceInfo > &info, int timeout_per_socket=1000)
Returns a discovery response.
Definition: discover.cc:107
Socket implementation for Linux.
Definition: socket_linux.h:51
static std::tuple< uint8_t, uint8_t > getNext()
Returns the next request number.


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