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


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