The module “discover_netsdr” in “rfspace_source_c.cc” failed everywhere that I tried it,
except for MacOS 10.6. Here is a drop in replacement that was tested and found to work on
10.6, 10.11, 10.12, 10.13 and ubuntu 16.04 LTS.
#include <net/if.h>
#include <ifaddrs.h>
class interfaceInformation{
public:
std::string name;
std::string address;
std::string broadcast;
};
std::vector<interfaceInformation> interfaceList();
static std::vector < unit_t > discover_netsdr()
{
std::vector < unit_t > units;
std::vector<interfaceInformation> list=interfaceList();
for(int pass=0;pass<2;++pass){
for(size_t n=0;n<list.size();++n){
if(pass == 1){
list[n].broadcast="255.255.255.255";
}
//std::cout << "name " << list[n].name << std::endl;
//std::cout << "address " << list[n].address <<
std::endl;
//std::cout << "broadcast " << list[n].broadcast <<
std::endl;
int sockTx;
int sockRx;
if ( (sockTx = socket(AF_INET, SOCK_DGRAM, 0)) < 0 )
continue;
if ( (sockRx = socket(AF_INET, SOCK_DGRAM, 0)) < 0 ){
close(sockTx);
continue;
}
int sockoptval = 1;
setsockopt(sockTx, SOL_SOCKET, SO_REUSEADDR, &sockoptval, sizeof(int));
sockoptval = 1;
setsockopt(sockTx, SOL_SOCKET, SO_BROADCAST, &sockoptval, sizeof(int));
struct sockaddr_in host_sa; /* local address */
struct sockaddr_in peer_sa; /* remote address */
struct sockaddr_in peer_sa2; /* remote address */
/* fill in the server's address and data */
memset((char*)&peer_sa, 0, sizeof(peer_sa));
peer_sa.sin_family = AF_INET;
peer_sa.sin_addr.s_addr = htonl(inet_network(list[n].address.c_str()));
peer_sa.sin_port = htons(DISCOVER_SERVER_PORT);
/* fill in the server's address and data */
memset((char*)&peer_sa2, 0, sizeof(peer_sa2));
peer_sa2.sin_family = AF_INET;
peer_sa2.sin_addr.s_addr = htonl(inet_network(list[n].broadcast.c_str()));
peer_sa2.sin_port = htons(DISCOVER_SERVER_PORT);
/* fill in the hosts's address and data */
memset(&host_sa, 0, sizeof(host_sa));
host_sa.sin_family = AF_INET;
host_sa.sin_addr.s_addr = htonl(INADDR_ANY);
host_sa.sin_port = htons(DISCOVER_CLIENT_PORT);
if ( bind(sockTx, (struct sockaddr *)&peer_sa, sizeof(peer_sa)) < 0 )
{
close(sockTx);
close(sockRx);
continue;
}
if ( bind(sockRx, (struct sockaddr *)&host_sa, sizeof(host_sa)) < 0 )
{
perror("binding datagram sock2");
printf("errno %d DISCOVER_SERVER_PORT %d\n",errno,DISCOVER_SERVER_PORT);
close(sockTx);
close(sockRx);
continue;
}
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 100000;
if ( setsockopt(sockRx, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0 )
{
close(sockRx);
close(sockTx);
continue;
}
discover_common_msg_t tx_msg;
memset( (void *)&tx_msg, 0, sizeof(discover_common_msg_t) );
tx_msg.length[0] = sizeof(discover_common_msg_t);
tx_msg.length[1] = sizeof(discover_common_msg_t) >> 8;
tx_msg.key[0] = KEY0;
tx_msg.key[1] = KEY1;
tx_msg.op = MSG_REQ;
sendto(sockTx, &tx_msg, sizeof(tx_msg), 0, (struct sockaddr *)&peer_sa,
sizeof(peer_sa));
sendto(sockTx, &tx_msg, sizeof(tx_msg), 0, (struct sockaddr *)&peer_sa2,
sizeof(peer_sa2));
while ( 1 )
{
size_t rx_bytes = 0;
unsigned char data[1024*2];
socklen_t addrlen = sizeof(host_sa); /* length of addresses */
int nbytes = recvfrom(sockRx, data, sizeof(data), 0, (struct sockaddr *)&host_sa,
&addrlen);
if ( nbytes <= 0 )
break;
rx_bytes = nbytes;
if ( rx_bytes >= sizeof(discover_common_msg_t) )
{
discover_common_msg_t *rx_msg = (discover_common_msg_t *)data;
if ( KEY0 == rx_msg->key[0] && KEY1 == rx_msg->key[1] &&
MSG_RESP == rx_msg->op )
{
void *temp = rx_msg->port;
uint16_t port = *((uint16_t *)temp);
std::stringstream buffer;
buffer << int(rx_msg->ipaddr[3]) << "."
<< int(rx_msg->ipaddr[2]) << "."
<< int(rx_msg->ipaddr[1]) << "."
<< int(rx_msg->ipaddr[0]);
std::string addr=buffer.str();
//std::cout << "addr " << addr << std::endl;
unit_t unit;
unit.name = rx_msg->name;
unit.sn = rx_msg->sn;
unit.addr = addr;
unit.port = port;
units.push_back( unit );
}
}
}
close(sockTx);
close(sockRx);
}
}
return units;
}
std::vector<interfaceInformation> interfaceList()
{
std::vector<interfaceInformation> list;
interfaceInformation c1;
struct ifaddrs *addrs,*iloop;
char buf[64],buf2[64];
struct sockaddr_in *s4;
getifaddrs(&addrs);
for (iloop = addrs; iloop != NULL; iloop = iloop->ifa_next)
{
s4 = (struct sockaddr_in *)(iloop->ifa_addr);
buf[0]=0;
if(s4){
inet_ntop(iloop->ifa_addr->sa_family, (void *)&(s4->sin_addr), buf,
sizeof(buf));
}else{
continue;
}
s4 = (struct sockaddr_in *)(iloop->ifa_dstaddr);
buf2[0]=0;
if(s4){
inet_ntop(iloop->ifa_dstaddr->sa_family, (void *)&(s4->sin_addr), buf2,
sizeof(buf2));
}else{
continue;
}
if(!(iloop->ifa_flags & IFF_UP) || !(iloop->ifa_flags &
IFF_BROADCAST))continue;
c1.name = iloop->ifa_name;
c1.address = buf;
c1.broadcast = buf2;
list.push_back(c1);
}
freeifaddrs(addrs);
return list;
}