18 #include "visiontransfer/deviceenumeration.h"
19 #include "visiontransfer/exceptions.h"
20 #include "visiontransfer/internal/networking.h"
21 #include "visiontransfer/internal/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 = (int) 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);
138 if(!(isLegacy||isLegacyWithStatusInfo)) {
148 char fwVersion[
sizeof(msg.firmwareVersion)+1];
149 memcpy(fwVersion, msg.firmwareVersion,
sizeof(msg.firmwareVersion));
150 fwVersion[
sizeof(msg.firmwareVersion)] =
'\0';
155 status =
DeviceStatus(msg.lastFps, msg.jumboSize, msg.currentCaptureSource);
159 std::string serial =
"N/A";
161 if (!(isLegacy||isLegacyWithStatusInfo)) {
163 if (msg.discoveryExtensionVersion >= 0x01) {
164 serial = std::string(msg.serialNumber);
168 if (msg.discoveryExtensionVersion > InternalInformation::CURRENT_DISCOVERY_EXTENSION_VERSION) {
175 char* ip_addr = inet_ntoa(senderAddress.sin_addr);
179 msg.useTcp ? DeviceInfo::PROTOCOL_TCP : DeviceInfo::PROTOCOL_UDP,
181 (DeviceInfo::DeviceModel)msg.model,
182 msg.protocolVersion == InternalInformation::CURRENT_PROTOCOL_VERSION,
192 std::vector<sockaddr_in> DeviceEnumeration::Pimpl::findBroadcastAddresses() {
193 std::vector<sockaddr_in> ret;
197 struct ifaddrs * ifap;
198 if (getifaddrs(&ifap) == 0) {
199 struct ifaddrs * p = ifap;
201 if(p->ifa_dstaddr !=
nullptr && p->ifa_dstaddr->sa_family == AF_INET) {
202 ret.push_back(*
reinterpret_cast<sockaddr_in*
>(p->ifa_dstaddr));
214 MIB_IPADDRTABLE* ipTable =
nullptr;
216 for (
int i=0; i<5; i++) {
217 DWORD ipRet = GetIpAddrTable(ipTable, &bufLen,
false);
218 if (ipRet == ERROR_INSUFFICIENT_BUFFER) {
219 if(ipTable !=
nullptr) {
220 delete []
reinterpret_cast<unsigned char*
>(ipTable);
222 ipTable =
reinterpret_cast<MIB_IPADDRTABLE *
>(
new unsigned char[bufLen]);
223 memset(ipTable, 0, bufLen);
224 }
else if (ipRet == NO_ERROR) {
227 if(ipTable !=
nullptr) {
228 delete []
reinterpret_cast<unsigned char*
>(ipTable);
234 if (ipTable !=
nullptr) {
235 for (DWORD i=0; i<ipTable->dwNumEntries; i++) {
236 const MIB_IPADDRROW & row = ipTable->table[i];
238 uint32_t ipAddr = row.dwAddr;
239 uint32_t netmask = row.dwMask;
240 uint32_t baddr = ipAddr & netmask;
241 if (row.dwBCastAddr) {
246 memset(&addr, 0,
sizeof(addr));
247 addr.sin_family = AF_INET;
248 addr.sin_addr.s_addr = baddr;
252 delete []
reinterpret_cast<unsigned char*
>(ipTable);