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


rcdiscover
Author(s): Heiko Hirschmueller , Raphael Schaller
autogenerated on Sat Oct 22 2022 02:52:17