VisionaryAutoIPScan.cpp
Go to the documentation of this file.
1 // -- BEGIN LICENSE BLOCK ----------------------------------------------
20 // -- END LICENSE BLOCK ------------------------------------------------
21 
22 #if (_MSC_VER >= 1700)
23 
24 # include <memory>
25 # include <sstream>
26 
27 # include <chrono>
28 # include <random>
29 # include <string>
30 
31 // TinyXML-2 XML DOM parser
33 
36 
37 namespace visionary {
38 
40 
42 
43 std::vector<VisionaryAutoIPScan::DeviceInfo>
44 VisionaryAutoIPScan::doScan(int timeOut, const std::string& broadcastAddress, uint16_t port)
45 {
46  // Init Random generator
47  std::random_device rd;
48  std::default_random_engine mt(rd());
49  unsigned int teleIdCounter = mt();
50  std::vector<VisionaryAutoIPScan::DeviceInfo> deviceList;
51 
52  std::unique_ptr<UdpSocket> pTransport(new UdpSocket());
53 
54  if (pTransport->connect(broadcastAddress, htons(port)) != 0)
55  {
56  return deviceList;
57  }
58 
59  // AutoIP Discover Packet
60  std::vector<uint8_t> autoIpPacket;
61  autoIpPacket.push_back(0x10); // CMD
62  autoIpPacket.push_back(0x0); // reserved
63  // length of datablock
64  autoIpPacket.push_back(0x0);
65  autoIpPacket.push_back(0x0);
66  // Mac address
67  autoIpPacket.push_back(0xFF);
68  autoIpPacket.push_back(0xFF);
69  autoIpPacket.push_back(0xFF);
70  autoIpPacket.push_back(0xFF);
71  autoIpPacket.push_back(0xFF);
72  autoIpPacket.push_back(0xFF);
73  // telgram id
74  autoIpPacket.push_back(0x0);
75  autoIpPacket.push_back(0x0);
76  autoIpPacket.push_back(0x0);
77  autoIpPacket.push_back(0x0);
78  // reserved
79  autoIpPacket.push_back(0x0);
80  autoIpPacket.push_back(0x0);
81 
82  // Replace telegram id in packet
83  unsigned int curtelegramID = teleIdCounter++;
84  memcpy(&autoIpPacket.data()[10], &curtelegramID, 4u);
85 
86  // Send Packet
87  pTransport->send(autoIpPacket);
88 
89  // Check for answers to Discover Packet
90  const std::chrono::steady_clock::time_point startTime(std::chrono::steady_clock::now());
91  while (true)
92  {
93  std::vector<std::uint8_t> receiveBuffer;
94  const std::chrono::steady_clock::time_point now(std::chrono::steady_clock::now());
95  if ((now - startTime) > std::chrono::milliseconds(timeOut))
96  {
97  break;
98  }
99  if (pTransport->recv(receiveBuffer, 1400) > 16) // 16 bytes minsize
100  {
101  unsigned int pos = 0;
102  if (receiveBuffer[pos++] != 0x90) // 0x90 = answer package id and 16 bytes minsize
103  {
104  continue;
105  }
106  pos += 1; // unused byte
107  unsigned int payLoadSize = receiveBuffer[pos] << 8 | receiveBuffer[pos + 1];
108  pos += 2;
109  pos += 6; // Skip mac address(part of xml)
110  unsigned int recvTelegramID = receiveBuffer[pos] | receiveBuffer[pos + 1] << 8 |
111  receiveBuffer[pos + 2] << 16 | receiveBuffer[pos + 3] << 24;
112  pos += 4;
113  // check if it is a response to our scan
114  if (recvTelegramID != curtelegramID)
115  {
116  continue;
117  }
118  pos += 2; // unused
119  // Get XML Payload
120  char xmlPayload[1400];
121  memset(xmlPayload, 0, sizeof(xmlPayload));
122  memcpy(&xmlPayload, &receiveBuffer[pos], payLoadSize);
123  std::stringstream stringStream(xmlPayload);
124  try
125  {
126  DeviceInfo dI = parseAutoIPXml(stringStream);
127  deviceList.push_back(dI);
128  }
129  catch (...)
130  {
131  }
132  }
133  }
134  return deviceList;
135 }
136 
137 VisionaryAutoIPScan::DeviceInfo
138 VisionaryAutoIPScan::parseAutoIPXml(std::stringstream& rStringStream)
139 {
140  // Parse XML string into DOM
142  auto tXMLError = tree.Parse(rStringStream.str());
143  if (tXMLError != tinyxml2::XMLError::XML_SUCCESS)
144  {
145  std::printf("Reading XML tree in AutoIP NetScan result failed.");
146  return false;
147  }
148 
149  DeviceInfo dI;
150  dI.DeviceName = "";
151  dI.IpAddress = "";
152  dI.MacAddress = "";
153  dI.Port = "";
154  dI.SubNet = "";
155 
156  tinyxml2::XMLNode const* const ptDataSetsTree = tree.FirstChildElement("NetScanResult");
157  if (ptDataSetsTree != 0)
158  {
159  // Query XML attributes
160  tinyxml2::XMLAttribute const* ptAttr = 0;
161 
162  ptAttr = ptDataSetsTree->FindAttribute("DeviceType");
163  if (ptAttr != 0)
164  {
165  dI.DeviceName = ptAttr->Value();
166  }
167 
168  ptAttr = ptDataSetsTree->FindAttribute("IPAddress");
169  if (ptAttr != 0)
170  {
171  dI.IpAddress = ptAttr->Value();
172  }
173 
174  ptAttr = ptDataSetsTree->FindAttribute("MACAddr");
175  if (ptAttr != 0)
176  {
177  dI.MacAddress = ptAttr->Value();
178  }
179 
180  ptAttr = ptDataSetsTree->FindAttribute("HostPortNo");
181  if (ptAttr != 0)
182  {
183  dI.Port = ptAttr->Value();
184  }
185 
186  ptAttr = ptDataSetsTree->FindAttribute("IPMask");
187  if (ptAttr != 0)
188  {
189  dI.subNet = ptAttr->Value();
190  }
191  }
192 
193  return dI;
194 }
195 
196 } // namespace visionary
197 #endif
tinyxml2::XMLAttribute::Value
const char * Value() const
The value of the attribute.
Definition: tinyxml2.cpp:1551
visionary
Definition: AuthenticationLegacy.h:25
UdpSocket.h
visionary::VisionaryAutoIPScan::doScan
std::vector< DeviceInfo > doScan(int timeOut, const std::string &broadcastAddress=DEFAULT_BROADCAST_ADDR, uint16_t port=DEFAULT_PORT)
Runs an autoIP scan and returns a list of devices
VisionaryAutoIPScan.h
tinyxml2::XMLAttribute
Definition: tinyxml2.h:1127
tinyxml2::XML_SUCCESS
@ XML_SUCCESS
Definition: tinyxml2.h:559
visionary::VisionaryAutoIPScan::VisionaryAutoIPScan
VisionaryAutoIPScan()
visionary::VisionaryAutoIPScan::parseAutoIPXml
DeviceInfo parseAutoIPXml(std::stringstream &rStringStream)
visionary::VisionaryAutoIPScan::~VisionaryAutoIPScan
~VisionaryAutoIPScan()
tinyxml2::XMLNode
Definition: tinyxml2.h:716
tinyxml2::XMLDocument
Definition: tinyxml2.h:1751
tinyxml2.h
tinyxml2::XMLDocument::Parse
XMLError Parse(const char *xml, size_t nBytes=static_cast< size_t >(-1))
Definition: tinyxml2.cpp:2645
tinyxml2::XMLNode::FirstChildElement
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:1094


sick_safevisionary_base
Author(s):
autogenerated on Sat Oct 21 2023 02:24:26