17 #include "visiontransfer/deviceenumeration.h" 18 #include "visiontransfer/exceptions.h" 19 #include "visiontransfer/networking.h" 20 #include "visiontransfer/internalinformation.h" 30 class DeviceEnumeration::Pimpl {
34 DeviceInfo* getDevicesPointer(
int* numDevices);
37 static constexpr
int RESPONSE_WAIT_TIME_MS = 50;
39 std::vector<DeviceInfo> deviceList;
41 std::vector<sockaddr_in> findBroadcastAddresses();
42 void sendDiscoverBroadcast();
43 DeviceEnumeration::DeviceList collectDiscoverResponses();
48 DeviceEnumeration::DeviceEnumeration():
53 DeviceEnumeration::~DeviceEnumeration() {
57 DeviceInfo* DeviceEnumeration::getDevicesPointer(
int* numDevices) {
58 return pimpl->getDevicesPointer(numDevices);
63 DeviceEnumeration::Pimpl::Pimpl() {
64 Networking::initNetworking();
67 if((sock = ::socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
68 TransferException ex(
"Error creating broadcast socket: " + Networking::getLastErrorString());
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: " + Networking::getLastErrorString());
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::Pimpl::~Pimpl() {
97 DeviceInfo* DeviceEnumeration::Pimpl::getDevicesPointer(
int* numDevices) {
98 sendDiscoverBroadcast();
99 deviceList = collectDiscoverResponses();
102 *numDevices = deviceList.size();
103 return deviceList.data();
106 void DeviceEnumeration::Pimpl::sendDiscoverBroadcast() {
107 std::vector<sockaddr_in> addresses = findBroadcastAddresses();
108 for(sockaddr_in addr: addresses) {
109 addr.sin_port = htons(InternalInformation::DISCOVERY_BROADCAST_PORT);
111 if (sendto(sock, InternalInformation::DISCOVERY_BROADCAST_MSG,
112 sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1, 0,
113 (
struct sockaddr *) &addr,
sizeof(addr))
114 !=
sizeof(InternalInformation::DISCOVERY_BROADCAST_MSG)-1) {
115 throw std::runtime_error(
"Error sending broadcast message");
120 DeviceEnumeration::DeviceList DeviceEnumeration::Pimpl::collectDiscoverResponses() {
125 sockaddr_in senderAddress;
126 socklen_t senderLength =
sizeof(senderAddress);
128 int received = recvfrom(sock, reinterpret_cast<char*>(&msg),
sizeof(msg),
129 0, (sockaddr *)&senderAddress, &senderLength);
136 if((received !=
sizeof(msg)) && !isLegacy ) {
142 char fwVersion[
sizeof(msg.firmwareVersion)+1];
143 memcpy(fwVersion, msg.firmwareVersion,
sizeof(msg.firmwareVersion));
144 fwVersion[
sizeof(msg.firmwareVersion)] =
'\0';
149 status =
DeviceStatus(msg.lastFps, msg.jumboSize, msg.currentCaptureSource);
154 inet_ntoa(senderAddress.sin_addr),
155 msg.useTcp ? DeviceInfo::PROTOCOL_TCP : DeviceInfo::PROTOCOL_UDP,
157 (DeviceInfo::DeviceModel)msg.model,
158 msg.protocolVersion == InternalInformation::CURRENT_PROTOCOL_VERSION,
167 std::vector<sockaddr_in> DeviceEnumeration::Pimpl::findBroadcastAddresses() {
168 std::vector<sockaddr_in> ret;
172 struct ifaddrs * ifap;
173 if (getifaddrs(&ifap) == 0) {
174 struct ifaddrs * p = ifap;
176 if(p->ifa_dstaddr !=
nullptr && p->ifa_dstaddr->sa_family == AF_INET) {
177 ret.push_back(*reinterpret_cast<sockaddr_in*>(p->ifa_dstaddr));
189 MIB_IPADDRTABLE* ipTable =
nullptr;
191 for (
int i=0; i<5; i++) {
192 DWORD ipRet = GetIpAddrTable(ipTable, &bufLen,
false);
193 if (ipRet == ERROR_INSUFFICIENT_BUFFER) {
194 if(ipTable !=
nullptr) {
195 delete []
reinterpret_cast<unsigned char*
>(ipTable);
197 ipTable =
reinterpret_cast<MIB_IPADDRTABLE *
>(
new unsigned char[bufLen]);
198 memset(ipTable, 0, bufLen);
199 }
else if (ipRet == NO_ERROR) {
202 if(ipTable !=
nullptr) {
203 delete []
reinterpret_cast<unsigned char*
>(ipTable);
209 if (ipTable !=
nullptr) {
210 for (DWORD i=0; i<ipTable->dwNumEntries; i++) {
211 const MIB_IPADDRROW & row = ipTable->table[i];
213 uint32_t ipAddr = row.dwAddr;
214 uint32_t netmask = row.dwMask;
215 uint32_t baddr = ipAddr & netmask;
216 if (row.dwBCastAddr) {
221 memset(&addr, 0,
sizeof(addr));
222 addr.sin_family = AF_INET;
223 addr.sin_addr.s_addr = baddr;
227 delete []
reinterpret_cast<unsigned char*
>(ipTable);
Aggregates information about a discovered device.
Representation of the current device status / health. Useful for addressing issues with peripherals o...
Exception class that is used for all transfer exceptions.