cli_utils.cc
Go to the documentation of this file.
1 /*
2  * rcdiscover - the network discovery tool for Roboception devices
3  *
4  * Copyright (c) 2018 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 "cli_utils.h"
37 
38 #include <rcdiscover/utils.h>
39 #include <rcdiscover/discover.h>
40 
41 #include <stdexcept>
42 #include <array>
43 #include <chrono>
44 
45 #ifdef WIN32
46 #undef min
47 #undef max
48 #endif
49 
50 int parseFilterArguments(int argc, char **argv, DeviceFilter &filter)
51 {
52  if (argc == 0)
53  {
54  throw std::invalid_argument("-f expects an option");
55  }
56 
57  const std::string p = argv[0];
58 
59  if (p.compare(0, 5, "name=") == 0)
60  {
61  filter.name.push_back(p.substr(5));
62  }
63  else if (p.compare(0, 7, "serial=") == 0)
64  {
65  filter.serial.push_back(p.substr(7));
66  }
67  else if (p.compare(0, 4, "mac=") == 0)
68  {
69  filter.mac.push_back(p.substr(4));
70  }
71  else if (p.compare(0, 6, "iface=") == 0)
72  {
73  filter.iface.push_back(p.substr(6));
74  }
75  else if (p.compare(0, 6, "model=") == 0)
76  {
77  filter.model.push_back(p.substr(6));
78  }
79  else
80  {
81  throw std::invalid_argument("Unknown option for parameter -f: " + p);
82  }
83 
84  return 1;
85 }
86 
87 bool filterDevice(const rcdiscover::DeviceInfo &device_info,
88  const DeviceFilter &filter)
89 {
90  const auto matches_filter = [](const std::string &str,
91  const std::vector<std::string> &filter)
92  {
93  return filter.empty() ||
94  std::any_of(filter.begin(), filter.end(),
95  [&str](const std::string &f)
96  {
97  return wildcardMatch(str.begin(), str.end(),
98  f.begin(), f.end());
99  });
100  };
101  const std::string &name = device_info.getUserName().empty()
102  ? device_info.getModelName()
103  : device_info.getUserName();
104  if (!matches_filter(name, filter.name)) return false;
105  const auto &serial = device_info.getSerialNumber();
106  if (!matches_filter(serial, filter.serial)) return false;
107  const auto &mac = mac2string(device_info.getMAC());
108  if (!matches_filter(mac, filter.mac)) return false;
109  const auto &iface = device_info.getIfaceName();
110  if (!matches_filter(iface, filter.iface)) return false;
111  const auto &model = device_info.getModelName();
112  if (!matches_filter(model, filter.model)) return false;
113  return true;
114 }
115 
116 std::vector<rcdiscover::DeviceInfo> discoverWithFilter(
117  const DeviceFilter &filter)
118 {
119  rcdiscover::Discover discover;
120  discover.broadcastRequest();
121 
122  std::chrono::steady_clock::time_point tstart=std::chrono::steady_clock::now();
123  std::chrono::steady_clock::time_point tend=tstart;
124 
125  std::vector<rcdiscover::DeviceInfo> infos;
126  while (discover.getResponse(infos, 100) ||
127  std::chrono::duration<double, std::milli>(tend-tstart).count() < 1000)
128  {
129  tend=std::chrono::steady_clock::now();
130  }
131 
132  std::sort(infos.begin(), infos.end());
133  infos.erase(std::unique(infos.begin(), infos.end(),
134  [](const rcdiscover::DeviceInfo &lhs,
135  const rcdiscover::DeviceInfo &rhs)
136  {
137  return lhs.getMAC() == rhs.getMAC() &&
138  lhs.getIfaceName() == rhs.getIfaceName();
139  }), infos.end());
140 
141  std::vector<rcdiscover::DeviceInfo> filtered_devices;
142  for (const auto &info : infos)
143  {
144  if (filterDevice(info, filter))
145  {
146  filtered_devices.push_back(info);
147  }
148  }
149  return filtered_devices;
150 }
151 
152 void printTable(std::ostream &oss,
153  const std::vector<std::vector<std::string>> &to_be_printed)
154 {
155  std::size_t max_columns = 0;
156  for (const auto &row : to_be_printed)
157  {
158  max_columns = std::max(max_columns, row.size());
159  }
160 
161  std::vector<std::size_t> column_width(max_columns, 0);
162  for (const auto &row : to_be_printed)
163  {
164  for (std::size_t col = 0; col < row.size(); ++col)
165  {
166  column_width[col] = std::max(column_width[col], row[col].size());
167  }
168  }
169 
170  for (const auto &row : to_be_printed)
171  {
172  for (std::size_t col = 0; col < row.size(); ++col)
173  {
174  std::string s = row[col];
175  if (col < row.size() - 1)
176  {
177  s.append(column_width[col] - s.length(), ' ');
178  s += '\t';
179  }
180  oss << s;
181  }
182  oss << '\n';
183  }
184 }
185 
186 void printDeviceTable(std::ostream &oss,
187  const std::vector<rcdiscover::DeviceInfo> &devices,
188  bool print_header,
189  bool iponly, bool serialonly)
190 {
191  std::vector<std::vector<std::string>> to_be_printed;
192 
193  if (print_header)
194  {
195  to_be_printed.push_back({"Name", "Serial Number", "IP", "MAC", "Model", "Interface(s)"});
196  }
197 
198  const rcdiscover::DeviceInfo *last_info = nullptr;
199  for (const auto &info : devices)
200  {
201  if (last_info)
202  {
203  if (info.getMAC() == last_info->getMAC() && !iponly && !serialonly)
204  {
205  // append this interface to the existing interface list
206  to_be_printed.back().back() += "," + info.getIfaceName();
207  continue;
208  }
209  }
210 
211  to_be_printed.emplace_back();
212  auto &print = to_be_printed.back();
213 
214  if (iponly)
215  {
216  print.push_back(ip2string(info.getIP()));
217  }
218  else if (serialonly)
219  {
220  print.push_back(info.getSerialNumber());
221  }
222  else
223  {
224  const std::string &name = info.getUserName().empty()
225  ? info.getModelName()
226  : info.getUserName();
227 
228  print.push_back(name);
229  print.push_back(info.getSerialNumber());
230  print.push_back(ip2string(info.getIP()));
231  print.push_back(mac2string(info.getMAC()));
232  print.push_back(info.getModelName());
233  print.push_back(info.getIfaceName());
234  }
235 
236  last_info = &info;
237  }
238 
239  printTable(oss, to_be_printed);
240 }
discoverWithFilter
std::vector< rcdiscover::DeviceInfo > discoverWithFilter(const DeviceFilter &filter)
Definition: cli_utils.cc:116
cli_utils.h
rcdiscover::Discover::broadcastRequest
void broadcastRequest()
Broadcasts a discovery command request.
Definition: discover.cc:85
DeviceFilter::iface
std::vector< std::string > iface
Definition: cli_utils.h:50
discover.h
rcdiscover::DeviceInfo::getIfaceName
const std::string & getIfaceName() const
Returns the name of the interface on which this device was found.
Definition: deviceinfo.h:180
filterDevice
bool filterDevice(const rcdiscover::DeviceInfo &device_info, const DeviceFilter &filter)
Definition: cli_utils.cc:87
ip2string
std::string ip2string(const uint32_t ip)
Definition: utils.h:58
rcdiscover::Discover::getResponse
bool getResponse(std::vector< DeviceInfo > &info, int timeout_per_socket=1000)
Returns a discovery response.
Definition: discover.cc:107
utils.h
DeviceFilter
Definition: cli_utils.h:45
rcdiscover::DeviceInfo::getSerialNumber
const std::string & getSerialNumber() const
Returns the serial number.
Definition: deviceinfo.h:160
rcdiscover::DeviceInfo::getMAC
uint64_t getMAC() const
Returns 6 bytes with the MAC address of the device.
Definition: deviceinfo.h:96
DeviceFilter::name
std::vector< std::string > name
Definition: cli_utils.h:47
parseFilterArguments
int parseFilterArguments(int argc, char **argv, DeviceFilter &filter)
Definition: cli_utils.cc:50
DeviceFilter::model
std::vector< std::string > model
Definition: cli_utils.h:51
rcdiscover::Discover
Definition: discover.h:50
rcdiscover::DeviceInfo::getModelName
const std::string & getModelName() const
Returns the model name.
Definition: deviceinfo.h:136
printTable
void printTable(std::ostream &oss, const std::vector< std::vector< std::string >> &to_be_printed)
Definition: cli_utils.cc:152
rcdiscover::DeviceInfo::getUserName
const std::string & getUserName() const
Returns the user name.
Definition: deviceinfo.h:168
DeviceFilter::mac
std::vector< std::string > mac
Definition: cli_utils.h:49
mac2string
std::string mac2string(const uint64_t mac)
Definition: utils.h:46
rcdiscover::DeviceInfo
Definition: deviceinfo.h:46
DeviceFilter::serial
std::vector< std::string > serial
Definition: cli_utils.h:48
printDeviceTable
void printDeviceTable(std::ostream &oss, const std::vector< rcdiscover::DeviceInfo > &devices, bool print_header, bool iponly, bool serialonly)
Definition: cli_utils.cc:186


rcdiscover
Author(s): Heiko Hirschmueller , Raphael Schaller
autogenerated on Thu Aug 1 2024 02:55:56