mavlink: adapt network detection for Mac, use heap

It seems that Mac does not support the ioctl to check how big the ifconf
buffer needs to be. Therefore we just have to make a guess.
Alos, instead of allocating the variable size array on the stack, it's
probably safer to use the heap.
This commit is contained in:
Julian Oes
2016-04-08 09:41:10 +02:00
parent 20cd5f3e76
commit ae2c28677d

View File

@@ -998,35 +998,47 @@ Mavlink::init_udp()
} }
_src_addr.sin_port = htons(_remote_port); _src_addr.sin_port = htons(_remote_port);
// Find out the required size of the buffer first.
// We can get the number by providing NULL to ifc_req.
struct ifconf ifconf; struct ifconf ifconf;
int ret;
#if defined(__APPLE__) && defined(__MACH__)
// On Mac, we can't determine the required buffer
// size in advance, so we just use what tends to work.
ifconf.ifc_len = 1024;
#else
// On Linux, we can determine the required size of the
// buffer first by providing NULL to ifc_req.
ifconf.ifc_req = NULL; ifconf.ifc_req = NULL;
ifconf.ifc_len = 0; ifconf.ifc_len = 0;
int ret = ioctl(_socket_fd, SIOCGIFCONF, &ifconf); ret = ioctl(_socket_fd, SIOCGIFCONF, &ifconf);
if (ret != 0) { if (ret != 0) {
PX4_WARN("getting required buffer size failed"); PX4_WARN("getting required buffer size failed");
return; return;
} }
#endif
PX4_DEBUG("need to allocate %d bytes", ifconf.ifc_len); PX4_DEBUG("need to allocate %d bytes", ifconf.ifc_len);
// Allocate buffer as long as needed. // Allocate buffer.
uint8_t ifreqs_buf[ifconf.ifc_len]; ifconf.ifc_req = (struct ifreq *)(new uint8_t[ifconf.ifc_len]);
memset(ifreqs_buf, 0, ifconf.ifc_len); if (ifconf.ifc_req == nullptr) {
ifconf.ifc_req = (struct ifreq *)ifreqs_buf; PX4_ERR("Could not allocate ifconf buffer");
return;
}
memset(ifconf.ifc_req, 0, ifconf.ifc_len);
ret = ioctl(_socket_fd, SIOCGIFCONF, &ifconf); ret = ioctl(_socket_fd, SIOCGIFCONF, &ifconf);
if (ret != 0) { if (ret != 0) {
PX4_WARN("getting network config failed"); PX4_ERR("getting network config failed");
delete[] ifconf.ifc_req;
return; return;
} }
size_t offset = 0; size_t offset = 0;
// Later used to point to next network interface in buffer. // Later used to point to next network interface in buffer.
struct ifreq *cur_ifreq = (struct ifreq *)&ifreqs_buf[offset]; struct ifreq *cur_ifreq = (struct ifreq *)&(((uint8_t *)ifconf.ifc_req)[offset]);
// The ugly `for` construct is used because it allows to use // The ugly `for` construct is used because it allows to use
// `continue` and `break`. // `continue` and `break`.
@@ -1038,8 +1050,7 @@ Mavlink::init_udp()
// sizeof sockaddr or ifr_addr.sa_len. // sizeof sockaddr or ifr_addr.sa_len.
offset += IF_NAMESIZE offset += IF_NAMESIZE
+ (sizeof(struct sockaddr) > cur_ifreq->ifr_addr.sa_len ? + (sizeof(struct sockaddr) > cur_ifreq->ifr_addr.sa_len ?
sizeof(struct sockaddr) : sizeof(struct sockaddr) : cur_ifreq->ifr_addr.sa_len)
cur_ifreq->ifr_addr.sa_len)
#else #else
// On Linux, it's much easier to traverse the buffer, every entry // On Linux, it's much easier to traverse the buffer, every entry
// has the constant length. // has the constant length.
@@ -1048,14 +1059,7 @@ Mavlink::init_udp()
) { ) {
// Point to next network interface in buffer. // Point to next network interface in buffer.
cur_ifreq = (struct ifreq *)&ifreqs_buf[offset]; cur_ifreq = (struct ifreq *)&(((uint8_t *)ifconf.ifc_req)[offset]);
#if defined(__APPLE__) && defined(__MACH__)
if (cur_ifreq->ifr_addr.sa_len == 0) {
// The current entry seems zero, we're probably through.
break;
}
#endif
PX4_DEBUG("looking at %s", cur_ifreq->ifr_name); PX4_DEBUG("looking at %s", cur_ifreq->ifr_name);
@@ -1073,7 +1077,7 @@ Mavlink::init_udp()
strncpy(bc_ifreq.ifr_name, cur_ifreq->ifr_name, IF_NAMESIZE); strncpy(bc_ifreq.ifr_name, cur_ifreq->ifr_name, IF_NAMESIZE);
ret = ioctl(_socket_fd, SIOCGIFBRDADDR, &bc_ifreq); ret = ioctl(_socket_fd, SIOCGIFBRDADDR, &bc_ifreq);
if (ret != 0) { if (ret != 0) {
PX4_INFO("getting broadcast address failed for %s", cur_ifreq->ifr_name); PX4_DEBUG("getting broadcast address failed for %s", cur_ifreq->ifr_name);
continue; continue;
} }
@@ -1105,13 +1109,14 @@ Mavlink::init_udp()
} }
} }
if (!_broadcast_address_found) { if (_broadcast_address_found) {
PX4_WARN("no broadcasting address found");
return;
}
_bcast_addr.sin_port = htons(_remote_port); _bcast_addr.sin_port = htons(_remote_port);
} else {
PX4_WARN("no broadcasting address found");
}
delete[] ifconf.ifc_req;
#endif #endif
} }