18 #include "visiontransfer/deviceenumeration.h"
19 #include "visiontransfer/exceptions.h"
20 #include "visiontransfer/networking.h"
21 #include "visiontransfer/internalinformation.h"
24 using namespace visiontransfer;
25 using namespace visiontransfer::internal;
27 namespace visiontransfer {
31 class DeviceEnumeration::Pimpl {
35 DeviceInfo* getDevicesPointer(
int* numDevices);
38 static constexpr
int RESPONSE_WAIT_TIME_MS = 50;
40 std::vector<DeviceInfo> deviceList;
42 std::vector<sockaddr_in> findBroadcastAddresses();
43 void sendDiscoverBroadcast();
44 DeviceEnumeration::DeviceList collectDiscoverResponses();
49 DeviceEnumeration::DeviceEnumeration():
54 DeviceEnumeration::~DeviceEnumeration() {
58 DeviceInfo* DeviceEnumeration::getDevicesPointer(
int* numDevices) {
59 return pimpl->getDevicesPointer(numDevices);
64 DeviceEnumeration::Pimpl::Pimpl() {
65 Networking::initNetworking();
68 if((sock = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
69 TransferException ex(
"Error creating broadcast socket: " + Networking::getLastErrorString());
74 int broadcastPermission = 1;
75 if(setsockopt(sock, SOL_SOCKET, SO_BROADCAST,
reinterpret_cast<char*
>(&broadcastPermission),
76 sizeof(broadcastPermission)) < 0) {
77 TransferException ex(
"Error setting socket broadcast flag: " + Networking::getLastErrorString());
83 unsigned int timeout = RESPONSE_WAIT_TIME_MS;
85 struct timeval timeout;
87 timeout.tv_usec = RESPONSE_WAIT_TIME_MS*1000;
90 setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO,
reinterpret_cast<char*
>(&timeout),
sizeof(timeout));
91 setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,
reinterpret_cast<char*
>(&timeout),
sizeof(timeout));
94 DeviceEnumeration::Pimpl::~Pimpl() {
98 DeviceInfo* DeviceEnumeration::Pimpl::getDevicesPointer(
int* numDevices) {
99 sendDiscoverBroadcast();
100 deviceList = collectDiscoverResponses();
103 *numDevices = deviceList.size();
104 return deviceList.data();
107 void DeviceEnumeration::Pimpl::sendDiscoverBroadcast() {
108 std::vector<sockaddr_in> addresses = findBroadcastAddresses();
109 for(sockaddr_in addr: addresses) {
110 addr.sin_port = htons(InternalInformation::DISCOVERY_BROADCAST_PORT);
112 if (sendto(sock, InternalInformation::DISCOVERY_BROADCAST_MSG,
113 sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1, 0,
114 (
struct sockaddr *) &addr,
sizeof(addr))
115 !=
sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1) {
116 throw std::runtime_error(
"Error sending broadcast message");
121 DeviceEnumeration::DeviceList DeviceEnumeration::Pimpl::collectDiscoverResponses() {
126 sockaddr_in senderAddress;
127 socklen_t senderLength =
sizeof(senderAddress);
129 int received = recvfrom(sock,
reinterpret_cast<char*
>(&msg),
sizeof(msg),
130 0, (sockaddr *)&senderAddress, &senderLength);
137 if((received !=
sizeof(msg)) && !isLegacy ) {
143 char fwVersion[
sizeof(msg.firmwareVersion)+1];
144 memcpy(fwVersion, msg.firmwareVersion,
sizeof(msg.firmwareVersion));
145 fwVersion[
sizeof(msg.firmwareVersion)] =
'\0';
150 status =
DeviceStatus(msg.lastFps, msg.jumboSize, msg.currentCaptureSource);
155 inet_ntoa(senderAddress.sin_addr),
156 msg.useTcp ? DeviceInfo::PROTOCOL_TCP : DeviceInfo::PROTOCOL_UDP,
158 (DeviceInfo::DeviceModel)msg.model,
159 msg.protocolVersion == InternalInformation::CURRENT_PROTOCOL_VERSION,
168 std::vector<sockaddr_in> DeviceEnumeration::Pimpl::findBroadcastAddresses() {
169 std::vector<sockaddr_in> ret;
173 struct ifaddrs * ifap;
174 if (getifaddrs(&ifap) == 0) {
175 struct ifaddrs * p = ifap;
177 if(p->ifa_dstaddr !=
nullptr && p->ifa_dstaddr->sa_family == AF_INET) {
178 ret.push_back(*
reinterpret_cast<sockaddr_in*
>(p->ifa_dstaddr));
190 MIB_IPADDRTABLE* ipTable =
nullptr;
192 for (
int i=0; i<5; i++) {
193 DWORD ipRet = GetIpAddrTable(ipTable, &bufLen,
false);
194 if (ipRet == ERROR_INSUFFICIENT_BUFFER) {
195 if(ipTable !=
nullptr) {
196 delete []
reinterpret_cast<unsigned char*
>(ipTable);
198 ipTable =
reinterpret_cast<MIB_IPADDRTABLE *
>(
new unsigned char[bufLen]);
199 memset(ipTable, 0, bufLen);
200 }
else if (ipRet == NO_ERROR) {
203 if(ipTable !=
nullptr) {
204 delete []
reinterpret_cast<unsigned char*
>(ipTable);
210 if (ipTable !=
nullptr) {
211 for (DWORD i=0; i<ipTable->dwNumEntries; i++) {
212 const MIB_IPADDRROW & row = ipTable->table[i];
214 uint32_t ipAddr = row.dwAddr;
215 uint32_t netmask = row.dwMask;
216 uint32_t baddr = ipAddr & netmask;
217 if (row.dwBCastAddr) {
222 memset(&addr, 0,
sizeof(addr));
223 addr.sin_family = AF_INET;
224 addr.sin_addr.s_addr = baddr;
228 delete []
reinterpret_cast<unsigned char*
>(ipTable);