Commit a29bf180 by zacharyc

Implemented Jim's hdhomerun autodetect for POSIX. Works great.

Windows testing next.


git-svn-id: https://bucket.mit.edu/svn/nilm/acquisition/ethstream@7452 ddd99763-3ecb-0310-9145-efcb8ce7c51f
parent 4cccb783
Showing with 190 additions and 17 deletions
...@@ -15,6 +15,21 @@ ...@@ -15,6 +15,21 @@
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <math.h> #include <math.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/timeb.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <net/if.h>
#include <sys/ioctl.h>
#ifndef _SIZEOF_ADDR_IFREQ
#define _SIZEOF_ADDR_IFREQ(x) sizeof(x)
#endif
#include "netutil.h" #include "netutil.h"
#include "compat.h" #include "compat.h"
...@@ -28,6 +43,7 @@ ...@@ -28,6 +43,7 @@
#define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */ #define NERDJACK_TIMEOUT 5 /* Timeout for connect/send/recv, in seconds */
#define NERD_HEADER_SIZE 8 #define NERD_HEADER_SIZE 8
#define MAX_SOCKETS 32
typedef struct __attribute__ ((__packed__)) typedef struct __attribute__ ((__packed__))
{ {
...@@ -39,6 +55,17 @@ typedef struct __attribute__ ((__packed__)) ...@@ -39,6 +55,17 @@ typedef struct __attribute__ ((__packed__))
signed short data[NERDJACK_NUM_SAMPLES]; signed short data[NERDJACK_NUM_SAMPLES];
} dataPacket; } dataPacket;
struct discovered_socket {
int sock;
uint32_t local_ip;
uint32_t subnet_mask;
};
struct discover_t {
struct discovered_socket socks[MAX_SOCKETS];
unsigned int sock_count;
};
/* Choose the best ScanConfig and ScanInterval parameters for the /* Choose the best ScanConfig and ScanInterval parameters for the
desired scanrate. Returns -1 if no valid config found */ desired scanrate. Returns -1 if no valid config found */
int int
...@@ -65,6 +92,103 @@ nerdjack_choose_scan (double desired_rate, double *actual_rate, ...@@ -65,6 +92,103 @@ nerdjack_choose_scan (double desired_rate, double *actual_rate,
return 0; return 0;
} }
static int discovered_sock_create(struct discover_t *ds, uint32_t local_ip, uint32_t subnet_mask)
{
if (ds->sock_count >= MAX_SOCKETS) {
return 0;
}
/* Create socket. */
int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
return 0;
}
/* Set timeouts. */
//setsocktimeout(sock, SOL_SOCKET, SO_SNDTIMEO, 1000);
//setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
/* Allow broadcast. */
int sock_opt = 1;
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
/* Set nonblocking */
if (soblock (sock, 0) < 0)
{
verb ("can't set nonblocking\n");
return 0;
}
/* Bind socket. */
struct sockaddr_in sock_addr;
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sin_family = AF_INET;
sock_addr.sin_addr.s_addr = htonl(local_ip);
sock_addr.sin_port = htons(0);
if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
close(sock);
return 0;
}
/* Write sock entry. */
struct discovered_socket *dss = &ds->socks[ds->sock_count++];
dss->sock = sock;
dss->local_ip = local_ip;
dss->subnet_mask = subnet_mask;
return 1;
}
static void enumerate_interfaces(struct discover_t *ds) {
int fd = socket(AF_INET, SOCK_DGRAM, 0);
if (fd == -1) {
return;
}
struct ifconf ifc;
uint8_t buf[8192];
//char stringbuffer[INET_ADDRSTRLEN];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = (char *)buf;
memset(buf, 0, sizeof(buf));
if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) {
close(fd);
return;
}
uint8_t *ptr = (uint8_t *)ifc.ifc_req;
uint8_t *end = (uint8_t *)&ifc.ifc_buf[ifc.ifc_len];
while (ptr <= end) {
struct ifreq *ifr = (struct ifreq *)ptr;
ptr += _SIZEOF_ADDR_IFREQ(*ifr);
if (ioctl(fd, SIOCGIFADDR, ifr) != 0) {
continue;
}
struct sockaddr_in *addr_in = (struct sockaddr_in *)&(ifr->ifr_addr);
uint32_t local_ip = ntohl(addr_in->sin_addr.s_addr);
if (local_ip == 0) {
continue;
}
//inet_ntop(AF_INET, &addr_in->sin_addr,
// stringbuffer, INET_ADDRSTRLEN);
//printf("%s\n",stringbuffer);
if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) {
continue;
}
struct sockaddr_in *mask_in = (struct sockaddr_in *)&(ifr->ifr_addr);
uint32_t mask = ntohl(mask_in->sin_addr.s_addr);
discovered_sock_create(ds, local_ip, mask);
}
}
/* Perform autodetection. Returns 0 on success, -1 on error /* Perform autodetection. Returns 0 on success, -1 on error
* Sets ipAddress to the detected address * Sets ipAddress to the detected address
*/ */
...@@ -73,26 +197,49 @@ nerdjack_detect (char *ipAddress) ...@@ -73,26 +197,49 @@ nerdjack_detect (char *ipAddress)
{ {
int32_t sock, receivesock; int32_t sock, receivesock;
struct sockaddr_in sa, receiveaddr, sFromAddr; struct sockaddr_in sa, receiveaddr, sFromAddr;
int bytes_sent, buffer_length; int buffer_length;
char buffer[200]; char buffer[200];
char incomingData[10]; char incomingData[10];
unsigned int lFromLen; unsigned int lFromLen;
//char stringbuffer[INET_ADDRSTRLEN];
sprintf (buffer, "TEST"); sprintf (buffer, "TEST");
buffer_length = strlen (buffer) + 1; buffer_length = strlen (buffer) + 1;
net_init (); net_init ();
sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); struct discover_t *ds = (struct discover_t *)calloc(1, sizeof(struct discover_t));
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP); if (!ds) {
return -1;
}
/* Set nonblocking */ /* Create a routable socket. */
if (soblock (sock, 0) < 0) if (!discovered_sock_create(ds, 0, 0)) {
{ free(ds);
verb ("can't set nonblocking\n");
return -1; return -1;
} }
/* Detect & create local sockets. */
enumerate_interfaces(ds);
//for(i = 0; i < ds->sock_count; i++) {
//inet_ntop(AF_INET, (struct sockaddr_in *) &ds->socks[i].local_ip,
// stringbuffer, INET_ADDRSTRLEN);
//printf("%s\n",stringbuffer);
//}
//return -1;
//sock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
receivesock = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP);
/* Set nonblocking */
//if (soblock (sock, 0) < 0)
// {
// verb ("can't set nonblocking\n");
// return -1;
// }
/* Set nonblocking */ /* Set nonblocking */
if (soblock (receivesock, 0) < 0) if (soblock (receivesock, 0) < 0)
{ {
...@@ -101,10 +248,10 @@ nerdjack_detect (char *ipAddress) ...@@ -101,10 +248,10 @@ nerdjack_detect (char *ipAddress)
} }
int opt = 1; //int opt = 1;
setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (void *) &opt, sizeof (int)); //setsockopt (sock, SOL_SOCKET, SO_BROADCAST, (void *) &opt, sizeof (int));
if ((-1 == sock) || (-1 == receivesock)) /* if socket failed to initialize, exit */ if (-1 == receivesock) /* if socket failed to initialize, exit */
{ {
verb ("Error Creating Socket\n"); verb ("Error Creating Socket\n");
return -1; return -1;
...@@ -120,20 +267,46 @@ nerdjack_detect (char *ipAddress) ...@@ -120,20 +267,46 @@ nerdjack_detect (char *ipAddress)
//Receive from any IP address, Will send to broadcast //Receive from any IP address, Will send to broadcast
receiveaddr.sin_addr.s_addr = INADDR_ANY; receiveaddr.sin_addr.s_addr = INADDR_ANY;
sa.sin_addr.s_addr = INADDR_BROADCAST; //sa.sin_addr.s_addr = INADDR_BROADCAST;
bind (receivesock, (struct sockaddr *) &receiveaddr, bind (receivesock, (struct sockaddr *) &receiveaddr,
sizeof (struct sockaddr_in)); sizeof (struct sockaddr_in));
bytes_sent = //bytes_sent =
sendto (sock, buffer, buffer_length, 0, (struct sockaddr *) &sa, // sendto (sock, buffer, buffer_length, 0, (struct sockaddr *) &sa,
// sizeof (struct sockaddr_in));
//if (bytes_sent < 0)
// {
// info ("Error sending packet: %s\n", strerror (errno));
// return -1;
// }
//int result = 0;
/*
* Send subnet broadcast using each local ip socket.
* This will work with multiple separate 169.254.x.x interfaces.
*/
unsigned int i;
for (i = 0; i < ds->sock_count; i++) {
struct discovered_socket *dss = &ds->socks[i];
uint32_t target_ip = dss->local_ip | ~dss->subnet_mask;
sa.sin_addr.s_addr = htonl(target_ip);
sendto (dss->sock, buffer, buffer_length, 0, (struct sockaddr *) &sa,
sizeof (struct sockaddr_in)); sizeof (struct sockaddr_in));
if (bytes_sent < 0) //result |= hdhomerun_discover_send_internal(ds, dss, target_ip, device_type, device_id);
{
info ("Error sending packet: %s\n", strerror (errno));
return -1;
} }
/*
* If no local ip sockets then fall back to sending a global broadcast letting the OS choose the interface.
*/
//if (!result) {
// struct hdhomerun_discover_sock_t *dss = &ds->socks[0];
// result = hdhomerun_discover_send_internal(ds, dss, 0xFFFFFFFF, device_type, device_id);
//}
//return result;
lFromLen = sizeof (sFromAddr); lFromLen = sizeof (sFromAddr);
if (0 > if (0 >
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment