You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

349 lines
10 KiB

--- a/main.c
+++ b/main.c
@@ -93,6 +93,7 @@ static void usage(const char *argv0) {
#if IR
" -i [<filename>]\tEnable lirc remote control support (lirc config file ~/.lircrc used if filename not specified)\n"
#endif
+ " -I <interface>\tNetwork interface used to send discovery\n"
" -m <mac addr>\t\tSet mac address, format: ab:cd:ef:12:34:56\n"
" -M <modelname>\tSet the squeezelite player model name sent to the server (default: " MODEL_NAME_STRING ")\n"
" -n <name>\t\tSet the player name\n"
@@ -292,6 +293,8 @@ int main(int argc, char **argv) {
extern bool user_rates;
char *logfile = NULL;
u8_t mac[6];
+ char *iface = NULL;
+ in_addr_t bcast_addr = 0;
unsigned stream_buf_size = STREAMBUF_SIZE;
unsigned output_buf_size = 0; // set later
unsigned rates[MAX_SUPPORTED_SAMPLERATES] = { 0 };
@@ -332,6 +335,7 @@ int main(int argc, char **argv) {
int maxSampleRate = 0;
+ memset(mac, 0, sizeof(mac));
char *optarg = NULL;
int optind = 1;
int i;
@@ -339,8 +343,6 @@ int main(int argc, char **argv) {
#define MAXCMDLINE 512
char cmdline[MAXCMDLINE] = "";
- get_mac(mac);
-
for (i = 0; i < argc && (strlen(argv[i]) + strlen(cmdline) + 2 < MAXCMDLINE); i++) {
strcat(cmdline, argv[i]);
strcat(cmdline, " ");
@@ -348,7 +350,7 @@ int main(int argc, char **argv) {
while (optind < argc && strlen(argv[optind]) >= 2 && argv[optind][0] == '-') {
char *opt = argv[optind] + 1;
- if (strstr("oabcCdefmMnNpPrsZ"
+ if (strstr("oabcCdefImMnNpPrsZ"
#if ALSA
"UVO"
#endif
@@ -442,6 +444,9 @@ int main(int argc, char **argv) {
case 'f':
logfile = optarg;
break;
+ case 'I':
+ iface = optarg;
+ break;
case 'm':
{
int byte = 0;
@@ -755,6 +760,11 @@ int main(int argc, char **argv) {
winsock_init();
#endif
+ if (!(bcast_addr = get_iface_info(log_slimproto, iface, mac))) {
+ fprintf(stderr, "Error binding to network or none given\n");
+ exit(1);
+ }
+
stream_init(log_stream, stream_buf_size);
if (!strcmp(output_device, "-")) {
@@ -801,7 +811,7 @@ int main(int argc, char **argv) {
exit(1);
}
- slimproto(log_slimproto, server, mac, name, namefile, modelname, maxSampleRate);
+ slimproto(log_slimproto, server, bcast_addr, mac, name, namefile, modelname, maxSampleRate);
decode_close();
stream_close();
--- a/slimproto.c
+++ b/slimproto.c
@@ -119,7 +119,7 @@ void send_packet(u8_t *packet, size_t le
}
}
-static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t mac[6]) {
+static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t *mac) {
#define BASE_CAP "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Balance=1,Firmware=" VERSION
#define SSL_CAP "CanHTTPS=1"
const char *base_cap;
@@ -768,7 +768,7 @@ void wake_controller(void) {
wake_signal(wake_e);
}
-in_addr_t discover_server(char *default_server) {
+in_addr_t discover_server(char *default_server, in_addr_t bcast_addr) {
struct sockaddr_in d;
struct sockaddr_in s;
char *buf;
@@ -785,7 +785,7 @@ in_addr_t discover_server(char *default_
memset(&d, 0, sizeof(d));
d.sin_family = AF_INET;
d.sin_port = htons(PORT);
- d.sin_addr.s_addr = htonl(INADDR_BROADCAST);
+ d.sin_addr.s_addr = bcast_addr;
pollinfo.fd = disc_sock;
pollinfo.events = POLLIN;
@@ -820,7 +820,7 @@ in_addr_t discover_server(char *default_
#define FIXED_CAP_LEN 256
#define VAR_CAP_LEN 128
-void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate) {
+void slimproto(log_level level, char *server, in_addr_t bcast_addr, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate) {
struct sockaddr_in serv_addr;
static char fixed_cap[FIXED_CAP_LEN], var_cap[VAR_CAP_LEN] = "";
bool reconnect = false;
@@ -841,7 +841,7 @@ void slimproto(log_level level, char *se
}
if (!slimproto_ip) {
- slimproto_ip = discover_server(server);
+ slimproto_ip = discover_server(server, bcast_addr);
}
if (!slimproto_port) {
@@ -926,7 +926,7 @@ void slimproto(log_level level, char *se
// rediscover server if it was not set at startup
if (!server && ++failed_connect > 5) {
- slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(NULL);
+ slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(NULL, bcast_addr);
}
} else {
--- a/squeezelite.h
+++ b/squeezelite.h
@@ -456,7 +456,7 @@ char* strcasestr(const char *haystack, c
char *next_param(char *src, char c);
u32_t gettime_ms(void);
-void get_mac(u8_t *mac);
+in_addr_t get_iface_info(log_level level, char *iface, u8_t *mac);
void set_nonblock(sockfd s);
int connect_timeout(sockfd sock, const struct sockaddr *addr, socklen_t addrlen, int timeout);
void server_addr(char *server, in_addr_t *ip_ptr, unsigned *port_ptr);
@@ -513,7 +513,7 @@ void buf_init(struct buffer *buf, size_t
void buf_destroy(struct buffer *buf);
// slimproto.c
-void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate);
+void slimproto(log_level level, char *server, in_addr_t bcast_addr, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate);
void slimproto_stop(void);
void wake_controller(void);
--- a/utils.c
+++ b/utils.c
@@ -22,11 +22,11 @@
#include "squeezelite.h"
#if LINUX || OSX || FREEBSD
-#include <sys/ioctl.h>
+#include <sys/types.h>
#include <net/if.h>
-#include <netdb.h>
-#if FREEBSD
#include <ifaddrs.h>
+#include <netdb.h>
+#if FREEBSD || OSX
#include <net/if_dl.h>
#include <net/if_types.h>
#endif
@@ -49,15 +49,11 @@
#include <ctype.h>
#endif
#endif
-#if OSX
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <ifaddrs.h>
-#include <netdb.h>
-#endif
#include <fcntl.h>
+static log_level loglevel;
+
// logging functions
const char *logtime(void) {
static char buf[100];
@@ -120,58 +116,94 @@ u32_t gettime_ms(void) {
#endif
}
-// mac address
-#if LINUX && !defined(SUN)
-// search first 4 interfaces returned by IFCONF
-void get_mac(u8_t mac[]) {
- char *utmac;
- struct ifconf ifc;
- struct ifreq *ifr, *ifend;
- struct ifreq ifreq;
- struct ifreq ifs[4];
+// Get broadcast address for interface (given or first available)
+// Return MAC address if none given
+#if LINUX || OSX || FREEBSD
- utmac = getenv("UTMAC");
- if (utmac)
- {
- if ( strlen(utmac) == 17 )
- {
- if (sscanf(utmac,"%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
- &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) == 6)
- {
- return;
- }
- }
+in_addr_t get_iface_info(log_level level, char *iface, u8_t *mac) {
+ struct ifaddrs *addrs, *ifa;
+ struct sockaddr *sdl;
+ char ifname[16];
+ unsigned char *ptr;
+ in_addr_t bcast_addr = 0;
+ int have_mac = 0, have_ifname = 0;
+
+ loglevel = level;
+
+ // Check for non-zero MAC
+ if (mac[0] | mac[1] | mac[2] != 0)
+ have_mac = 1;
+
+ // Copy interface name, if it was provided.
+ if (iface != NULL) {
+ if (strlen(iface) > sizeof(ifname))
+ return -1;
+ strncpy(ifname, iface, sizeof(ifname) - 1);
+ have_ifname = 1;
}
- mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
+ if (getifaddrs(&addrs) == 0) {
+ //iterate to find corresponding ethernet address
+ for (ifa = addrs; ifa; ifa = ifa->ifa_next) {
+ // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that
+ // don't support BROADCAST.
+ if (ifa->ifa_flags & IFF_LOOPBACK
+ || !ifa->ifa_flags & IFF_UP
+ || !ifa->ifa_flags & IFF_BROADCAST) {
+ continue;
+ }
- int s = socket(AF_INET, SOCK_DGRAM, 0);
+ if (!have_ifname) {
+ // We have found a valid interface name. Keep it.
+ strncpy(ifname, ifa->ifa_name, sizeof(ifname) - 1);
+ have_ifname = 1;
+ } else {
+ if (strncmp(ifname, ifa->ifa_name, sizeof(ifname)) != 0) {
+ // This is not the interface we're looking for.
+ continue;
+ }
+ }
- ifc.ifc_len = sizeof(ifs);
- ifc.ifc_req = ifs;
- if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
- ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
+ // Check address family.
+ if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET &&
+ ((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr.s_addr != 0) {
+ // Get broadcast address and MAC address
+ bcast_addr = ((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr.s_addr;
+ break;
+ }
+ else {
+ // Address is not IPv4
+ if (iface == NULL)
+ have_ifname = 0;
+ }
+ }
- for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
- if (ifr->ifr_addr.sa_family == AF_INET) {
-
- strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
- if (ioctl (s, SIOCGIFHWADDR, &ifreq) == 0) {
- memcpy(mac, ifreq.ifr_hwaddr.sa_data, 6);
- if (mac[0]+mac[1]+mac[2] != 0) {
- break;
- }
+ // Find MAC address matching interface
+ if (!have_mac && bcast_addr != 0) {
+ for (ifa = addrs; ifa; ifa = ifa->ifa_next) {
+ if (ifa->ifa_addr && ifa->ifa_addr->sa_family == PF_PACKET &&
+ strncmp(ifname, ifa->ifa_name, sizeof(ifname)) == 0) {
+ sdl = (struct sockaddr *)(ifa->ifa_addr);
+ ptr = (unsigned char *)sdl->sa_data;
+ memcpy(mac, ptr + 10, 6);
+ have_mac = 1;
}
}
}
+
+ freeifaddrs(addrs);
}
- close(s);
+ LOG_INFO("Interface: %s, broadcast: %08X, macaddr = %02x:%02x:%02x:%02x:%02x:%02x",
+ ifname, bcast_addr, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ return bcast_addr;
}
#endif
+
#if SUN
void get_mac(u8_t mac[]) {
struct arpreq parpreq;
@@ -238,30 +270,6 @@ void get_mac(u8_t mac[]) {
}
#endif
-#if OSX || FREEBSD
-void get_mac(u8_t mac[]) {
- struct ifaddrs *addrs, *ptr;
- const struct sockaddr_dl *dlAddr;
- const unsigned char *base;
-
- mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
-
- if (getifaddrs(&addrs) == 0) {
- ptr = addrs;
- while (ptr) {
- if (ptr->ifa_addr->sa_family == AF_LINK && ((const struct sockaddr_dl *) ptr->ifa_addr)->sdl_type == IFT_ETHER) {
- dlAddr = (const struct sockaddr_dl *)ptr->ifa_addr;
- base = (const unsigned char*) &dlAddr->sdl_data[dlAddr->sdl_nlen];
- memcpy(mac, base, min(dlAddr->sdl_alen, 6));
- break;
- }
- ptr = ptr->ifa_next;
- }
- freeifaddrs(addrs);
- }
-}
-#endif
-
#if WIN
#pragma comment(lib, "IPHLPAPI.lib")
void get_mac(u8_t mac[]) {