17 #include "visiontransfer/deviceenumeration.h" 18 #include "visiontransfer/exceptions.h" 19 #include "visiontransfer/networking.h" 20 #include "visiontransfer/internalinformation.h" 28 class DeviceEnumeration::Pimpl {
31 DeviceInfo* getDevicesPointer(
int* numDevices);
34 static constexpr
int RESPONSE_WAIT_TIME_MS = 50;
36 std::vector<DeviceInfo> deviceList;
38 std::vector<sockaddr_in> findBroadcastAddresses();
39 void sendDiscoverBroadcast();
40 DeviceEnumeration::DeviceList collectDiscoverResponses();
45 DeviceEnumeration::DeviceEnumeration():
50 DeviceEnumeration::~DeviceEnumeration() {
54 DeviceInfo* DeviceEnumeration::getDevicesPointer(
int* numDevices) {
55 return pimpl->getDevicesPointer(numDevices);
60 DeviceEnumeration::Pimpl::Pimpl() {
61 Networking::initNetworking();
64 if((sock = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
65 TransferException ex(
"Error creating broadcast socket: " +
string(strerror(errno)));
70 int broadcastPermission = 1;
71 if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST, reinterpret_cast<char*>(&broadcastPermission),
72 sizeof(broadcastPermission)) < 0) {
73 TransferException ex(
"Error setting socket broadcast flag: " +
string(strerror(errno)));
79 unsigned int timeout = RESPONSE_WAIT_TIME_MS;
81 struct timeval timeout;
83 timeout.tv_usec = RESPONSE_WAIT_TIME_MS*1000;
86 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&timeout),
sizeof(timeout));
87 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, reinterpret_cast<char*>(&timeout),
sizeof(timeout));
90 DeviceInfo* DeviceEnumeration::Pimpl::getDevicesPointer(
int* numDevices) {
91 sendDiscoverBroadcast();
92 deviceList = collectDiscoverResponses();
95 *numDevices = deviceList.size();
96 return &deviceList[0];
99 void DeviceEnumeration::Pimpl::sendDiscoverBroadcast() {
100 std::vector<sockaddr_in> addresses = findBroadcastAddresses();
101 for(sockaddr_in addr: addresses) {
102 addr.sin_port = htons(InternalInformation::DISCOVERY_BROADCAST_PORT);
104 if (sendto(sock, InternalInformation::DISCOVERY_BROADCAST_MSG,
105 sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1, 0,
106 (
struct sockaddr *) &addr,
sizeof(addr))
107 !=
sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1) {
108 throw std::runtime_error(
"Error sending broadcast message");
113 DeviceEnumeration::DeviceList DeviceEnumeration::Pimpl::collectDiscoverResponses() {
118 sockaddr_in senderAddress;
119 socklen_t senderLength =
sizeof(senderAddress);
121 int received = recvfrom(sock, reinterpret_cast<char*>(&msg),
sizeof(msg),
122 0, (sockaddr *)&senderAddress, &senderLength);
127 }
else if(received !=
sizeof(msg)) {
133 char fwVersion[
sizeof(msg.firmwareVersion)+1];
134 memcpy(fwVersion, msg.firmwareVersion,
sizeof(msg.firmwareVersion));
135 fwVersion[
sizeof(msg.firmwareVersion)] =
'\0';
139 inet_ntoa(senderAddress.sin_addr),
140 msg.useTcp ? DeviceInfo::PROTOCOL_TCP : DeviceInfo::PROTOCOL_UDP,
142 msg.proVersion ? DeviceInfo::SCENESCAN_PRO : DeviceInfo::SCENESCAN,
143 msg.protocolVersion == InternalInformation::CURRENT_PROTOCOL_VERSION
151 std::vector<sockaddr_in> DeviceEnumeration::Pimpl::findBroadcastAddresses() {
152 std::vector<sockaddr_in> ret;
156 struct ifaddrs * ifap;
157 if (getifaddrs(&ifap) == 0) {
158 struct ifaddrs * p = ifap;
160 if(p->ifa_dstaddr !=
nullptr && p->ifa_dstaddr->sa_family == AF_INET) {
161 ret.push_back(*reinterpret_cast<sockaddr_in*>(p->ifa_dstaddr));
173 MIB_IPADDRTABLE* ipTable =
nullptr;
175 for (
int i=0; i<5; i++) {
176 DWORD ipRet = GetIpAddrTable(ipTable, &bufLen,
false);
177 if (ipRet == ERROR_INSUFFICIENT_BUFFER) {
178 if(ipTable !=
nullptr) {
179 delete []
reinterpret_cast<unsigned char*
>(ipTable);
181 ipTable =
reinterpret_cast<MIB_IPADDRTABLE *
>(
new unsigned char[bufLen]);
182 memset(ipTable, 0, bufLen);
183 }
else if (ipRet == NO_ERROR) {
186 if(ipTable !=
nullptr) {
187 delete []
reinterpret_cast<unsigned char*
>(ipTable);
193 if (ipTable !=
nullptr) {
194 for (DWORD i=0; i<ipTable->dwNumEntries; i++) {
195 const MIB_IPADDRROW & row = ipTable->table[i];
197 uint32_t ipAddr = row.dwAddr;
198 uint32_t netmask = row.dwMask;
199 uint32_t baddr = ipAddr & netmask;
200 if (row.dwBCastAddr) {
205 memset(&addr, 0,
sizeof(addr));
206 addr.sin_family = AF_INET;
207 addr.sin_addr.s_addr = baddr;
211 delete []
reinterpret_cast<unsigned char*
>(ipTable);
Aggregates information about a discovered device.
Exception class that is used for all transfer exceptions.