Program Listing for File DiscoveryManager.cpp¶
↰ Return to documentation for file (src/DiscoveryManager.cpp)
//
// Created by Aleksey Timin on 12/17/19.
//
#include <system_error>
#include "eip/EncapsPacketFactory.h"
#include "eip/CommonPacket.h"
#include "sockets/UDPSocket.h"
#include "utils/Logger.h"
#include "utils/Buffer.h"
#include "DiscoveryManager.h"
#include "sockets/Platform.h"
#if defined (__unix__) || defined(__APPLE__)
#define DISCOVERY_SOCKET_RECEIVE_END_ERROR_CODE (EIPSCANNER_SOCKET_ERROR(EAGAIN))
#elif defined(_WIN32) || defined(WIN32) || defined(_WIN64)
#define DISCOVERY_SOCKET_RECEIVE_END_ERROR_CODE (EIPSCANNER_SOCKET_ERROR(ETIMEDOUT))
#endif
namespace eipScanner {
using namespace cip;
using eip::EncapsPacketFactory;
using eip::EncapsPacket;
using eip::EncapsStatusCodes;
using eip::EncapsCommands;
using eip::CommonPacket;
using sockets::EndPoint;
using sockets::UDPSocket;
using utils::LogLevel;
using utils::Logger;
using utils::Buffer;
DiscoveryManager::DiscoveryManager(const std::string& broadCastAddress, int port,
std::chrono::milliseconds receiveTimout)
: _broadCastAddress(broadCastAddress, port)
, _receiveTimout(receiveTimout) {
}
DiscoveryManager::~DiscoveryManager() = default;
IdentityItem::Vec DiscoveryManager::discover() const {
eipScanner::IdentityItem::Vec devices;
auto socket = makeSocket();
socket->Send(EncapsPacketFactory().createListIdentityPacket().pack());
try {
for(;;) {
const size_t EIP_MAX_PACKET_SIZE = 504;
auto data = socket->Receive(EIP_MAX_PACKET_SIZE);
CommonPacket commonPacket;
commonPacket.expand(std::vector<uint8_t>(data.begin()+EncapsPacket::HEADER_SIZE, data.end()));
for (int i=0; i < commonPacket.getItems().size(); ++i) {
Buffer buffer(commonPacket.getItems()[i].getData());
CipUint ignore;
sockets::EndPoint socketAddr("", 0);
buffer >> ignore >> socketAddr;
CipUint vendorId, deviceType, productCode;
CipRevision revision;
CipWord status;
CipUdint serialNumber;
CipShortString productName;
buffer >> vendorId >> deviceType >> productCode
>> revision >> status
>> serialNumber >> productName;
IdentityObject identityObject(i);
identityObject.setVendorId(vendorId);
identityObject.setDeviceType(deviceType);
identityObject.setProductCode(productCode);
identityObject.setRevision(revision);
identityObject.setStatus(status);
identityObject.setSerialNumber(serialNumber);
identityObject.setProductName(productName.toStdString());
devices.push_back(IdentityItem{.identityObject=identityObject, .socketAddress=socketAddr});
}
}
} catch (std::system_error& er) {
if (er.code().value() != DISCOVERY_SOCKET_RECEIVE_END_ERROR_CODE) {
throw er;
}
}
return devices;
}
sockets::BaseSocket::SPtr DiscoveryManager::makeSocket() const {
auto socket = std::make_shared<UDPSocket>(_broadCastAddress);
socket->setRecvTimeout(_receiveTimout);
int broadcast = 1;
if(setsockopt(socket->getSocketFd(), SOL_SOCKET, SO_BROADCAST, (char*)&broadcast, sizeof(broadcast)) < 0) {
throw std::system_error(sockets::BaseSocket::getLastError(), sockets::BaseSocket::getErrorCategory());
}
return socket;
}
}