17 #include "visiontransfer/deviceenumeration.h" 18 #include "visiontransfer/exceptions.h" 19 #include "visiontransfer/networking.h" 20 #include "visiontransfer/internalinformation.h" 26 class DeviceEnumeration::Pimpl {
29 DeviceEnumeration::DeviceList discoverDevices();
32 static constexpr
int RESPONSE_WAIT_TIME_MS = 50;
35 std::vector<sockaddr_in> findBroadcastAddresses();
36 void sendDiscoverBroadcast();
37 DeviceEnumeration::DeviceList collectDiscoverResponses();
42 DeviceEnumeration::DeviceEnumeration():
47 DeviceEnumeration::~DeviceEnumeration() {
52 return pimpl->discoverDevices();
57 DeviceEnumeration::Pimpl::Pimpl() {
61 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
67 if((sock = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
68 TransferException ex(
"Error creating broadcast socket: " +
string(strerror(errno)));
73 int broadcastPermission = 1;
74 if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&broadcastPermission),
75 sizeof(broadcastPermission)) < 0) {
76 TransferException ex(
"Error setting socket broadcast flag: " +
string(strerror(errno)));
82 unsigned int timeout = RESPONSE_WAIT_TIME_MS;
84 struct timeval timeout;
86 timeout.tv_usec = RESPONSE_WAIT_TIME_MS*1000;
89 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout),
sizeof(timeout));
90 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout),
sizeof(timeout));
93 DeviceEnumeration::DeviceList DeviceEnumeration::Pimpl::discoverDevices() {
94 sendDiscoverBroadcast();
95 return collectDiscoverResponses();
98 void DeviceEnumeration::Pimpl::sendDiscoverBroadcast() {
99 std::vector<sockaddr_in> addresses = findBroadcastAddresses();
100 for(sockaddr_in addr: addresses) {
101 addr.sin_port = htons(InternalInformation::DISCOVERY_BROADCAST_PORT);
103 if (sendto(sock, InternalInformation::DISCOVERY_BROADCAST_MSG,
104 sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1, 0,
105 (
struct sockaddr *) &addr,
sizeof(addr))
106 !=
sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1) {
107 throw std::runtime_error(
"Error sending broadcast message");
112 DeviceEnumeration::DeviceList DeviceEnumeration::Pimpl::collectDiscoverResponses() {
117 sockaddr_in senderAddress;
118 socklen_t senderLength =
sizeof(senderAddress);
120 int received = recvfrom(sock, reinterpret_cast<char*>(&msg),
sizeof(msg),
121 0, (sockaddr *)&senderAddress, &senderLength);
126 }
else if(received !=
sizeof(msg)) {
132 char fwVersion[
sizeof(msg.firmwareVersion)+1];
133 memcpy(fwVersion, msg.firmwareVersion,
sizeof(msg.firmwareVersion));
134 fwVersion[
sizeof(msg.firmwareVersion)] =
'\0';
138 inet_ntoa(senderAddress.sin_addr),
139 msg.useTcp ? DeviceInfo::PROTOCOL_TCP : DeviceInfo::PROTOCOL_UDP,
141 msg.proVersion ? DeviceInfo::SCENESCAN_PRO : DeviceInfo::SCENESCAN,
142 msg.protocolVersion == InternalInformation::CURRENT_PROTOCOL_VERSION
150 std::vector<sockaddr_in> DeviceEnumeration::Pimpl::findBroadcastAddresses() {
151 std::vector<sockaddr_in> ret;
155 struct ifaddrs * ifap;
156 if (getifaddrs(&ifap) == 0) {
157 struct ifaddrs * p = ifap;
159 if(p->ifa_dstaddr !=
nullptr && p->ifa_dstaddr->sa_family == AF_INET) {
160 ret.push_back(*reinterpret_cast<sockaddr_in*>(p->ifa_dstaddr));
172 MIB_IPADDRTABLE* ipTable =
nullptr;
174 for (
int i=0; i<5; i++) {
175 DWORD ipRet = GetIpAddrTable(ipTable, &bufLen,
false);
176 if (ipRet == ERROR_INSUFFICIENT_BUFFER) {
177 if(ipTable !=
nullptr) {
178 delete []
reinterpret_cast<unsigned char*
>(ipTable);
180 ipTable =
reinterpret_cast<MIB_IPADDRTABLE *
>(
new unsigned char[bufLen]);
181 memset(ipTable, 0, bufLen);
182 }
else if (ipRet == NO_ERROR) {
185 if(ipTable !=
nullptr) {
186 delete []
reinterpret_cast<unsigned char*
>(ipTable);
192 if (ipTable !=
nullptr) {
193 for (DWORD i=0; i<ipTable->dwNumEntries; i++) {
194 const MIB_IPADDRROW & row = ipTable->table[i];
196 uint32_t ipAddr = row.dwAddr;
197 uint32_t netmask = row.dwMask;
198 uint32_t baddr = ipAddr & netmask;
199 if (row.dwBCastAddr) {
204 memset(&addr, 0,
sizeof(addr));
205 addr.sin_family = AF_INET;
206 addr.sin_addr.s_addr = baddr;
210 delete []
reinterpret_cast<unsigned char*
>(ipTable);
Exception class that is used for all transfer exceptions.
DeviceList discoverDevices()
Discovers new devices and returns the list of all devices that have been found.
Aggregates information about a discovered device.