010-select_broadcast_interface.patch (10478B)
1 --- a/main.c 2 +++ b/main.c 3 @@ -78,6 +78,7 @@ static void usage(const char *argv0) { 4 #if IR 5 " -i [<filename>]\tEnable lirc remote control support (lirc config file ~/.lircrc used if filename not specified)\n" 6 #endif 7 + " -I <interface>\t\tNetwork interface used to send discovery\n" 8 " -m <mac addr>\t\tSet mac address, format: ab:cd:ef:12:34:56\n" 9 " -M <modelname>\tSet the squeezelite player model name sent to the server (default: " MODEL_NAME_STRING ")\n" 10 " -n <name>\t\tSet the player name\n" 11 @@ -233,6 +234,8 @@ int main(int argc, char **argv) { 12 extern bool pcm_check_header; 13 char *logfile = NULL; 14 u8_t mac[6]; 15 + char *iface = NULL; 16 + in_addr_t bcast_addr = 0; 17 unsigned stream_buf_size = STREAMBUF_SIZE; 18 unsigned output_buf_size = 0; // set later 19 unsigned rates[MAX_SUPPORTED_SAMPLERATES] = { 0 }; 20 @@ -271,6 +274,7 @@ int main(int argc, char **argv) { 21 22 int maxSampleRate = 0; 23 24 + memset(mac, 0, sizeof(mac)); 25 char *optarg = NULL; 26 int optind = 1; 27 int i; 28 @@ -278,8 +282,6 @@ int main(int argc, char **argv) { 29 #define MAXCMDLINE 512 30 char cmdline[MAXCMDLINE] = ""; 31 32 - get_mac(mac); 33 - 34 for (i = 0; i < argc && (strlen(argv[i]) + strlen(cmdline) + 2 < MAXCMDLINE); i++) { 35 strcat(cmdline, argv[i]); 36 strcat(cmdline, " "); 37 @@ -287,7 +289,7 @@ int main(int argc, char **argv) { 38 39 while (optind < argc && strlen(argv[optind]) >= 2 && argv[optind][0] == '-') { 40 char *opt = argv[optind] + 1; 41 - if (strstr("oabcCdefmMnNpPrs" 42 + if (strstr("oabcCdefImMnNpPrs" 43 #if ALSA 44 "UV" 45 #endif 46 @@ -382,6 +384,9 @@ int main(int argc, char **argv) { 47 case 'f': 48 logfile = optarg; 49 break; 50 + case 'I': 51 + iface = optarg; 52 + break; 53 case 'm': 54 { 55 int byte = 0; 56 @@ -667,6 +672,11 @@ int main(int argc, char **argv) { 57 winsock_init(); 58 #endif 59 60 + if (!(bcast_addr = get_iface_info(log_slimproto, iface, mac))) { 61 + fprintf(stderr, "Error binding to network or none given\n"); 62 + exit(1); 63 + } 64 + 65 stream_init(log_stream, stream_buf_size); 66 67 if (!strcmp(output_device, "-")) { 68 @@ -710,7 +720,7 @@ int main(int argc, char **argv) { 69 exit(1); 70 } 71 72 - slimproto(log_slimproto, server, mac, name, namefile, modelname, maxSampleRate); 73 + slimproto(log_slimproto, server, bcast_addr, mac, name, namefile, modelname, maxSampleRate); 74 75 decode_close(); 76 stream_close(); 77 --- a/squeezelite.h 78 +++ b/squeezelite.h 79 @@ -403,7 +403,7 @@ typedef enum { EVENT_TIMEOUT = 0, EVENT_ 80 81 char *next_param(char *src, char c); 82 u32_t gettime_ms(void); 83 -void get_mac(u8_t *mac); 84 +in_addr_t get_iface_info(log_level level, char *iface, u8_t *mac); 85 void set_nonblock(sockfd s); 86 int connect_timeout(sockfd sock, const struct sockaddr *addr, socklen_t addrlen, int timeout); 87 void server_addr(char *server, in_addr_t *ip_ptr, unsigned *port_ptr); 88 @@ -459,7 +459,7 @@ void buf_init(struct buffer *buf, size_t 89 void buf_destroy(struct buffer *buf); 90 91 // slimproto.c 92 -void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate); 93 +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); 94 void slimproto_stop(void); 95 void wake_controller(void); 96 97 --- a/slimproto.c 98 +++ b/slimproto.c 99 @@ -119,7 +119,7 @@ void send_packet(u8_t *packet, size_t le 100 } 101 } 102 103 -static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t mac[6]) { 104 +static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t *mac) { 105 const char *base_cap = "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION; 106 struct HELO_packet pkt; 107 108 @@ -782,7 +782,7 @@ void wake_controller(void) { 109 wake_signal(wake_e); 110 } 111 112 -in_addr_t discover_server(void) { 113 +in_addr_t discover_server(in_addr_t bcast_addr) { 114 struct sockaddr_in d; 115 struct sockaddr_in s; 116 char *buf; 117 @@ -798,7 +798,7 @@ in_addr_t discover_server(void) { 118 memset(&d, 0, sizeof(d)); 119 d.sin_family = AF_INET; 120 d.sin_port = htons(PORT); 121 - d.sin_addr.s_addr = htonl(INADDR_BROADCAST); 122 + d.sin_addr.s_addr = bcast_addr; 123 124 pollinfo.fd = disc_sock; 125 pollinfo.events = POLLIN; 126 @@ -829,7 +829,7 @@ in_addr_t discover_server(void) { 127 #define FIXED_CAP_LEN 256 128 #define VAR_CAP_LEN 128 129 130 -void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate) { 131 +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) { 132 struct sockaddr_in serv_addr; 133 static char fixed_cap[FIXED_CAP_LEN], var_cap[VAR_CAP_LEN] = ""; 134 bool reconnect = false; 135 @@ -849,7 +849,7 @@ void slimproto(log_level level, char *se 136 } 137 138 if (!slimproto_ip) { 139 - slimproto_ip = discover_server(); 140 + slimproto_ip = discover_server(bcast_addr); 141 } 142 143 if (!slimproto_port) { 144 @@ -924,7 +924,7 @@ void slimproto(log_level level, char *se 145 146 // rediscover server if it was not set at startup 147 if (!server && ++failed_connect > 5) { 148 - slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(); 149 + slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(bcast_addr); 150 } 151 152 } else { 153 --- a/utils.c 154 +++ b/utils.c 155 @@ -22,11 +22,11 @@ 156 #include "squeezelite.h" 157 158 #if LINUX || OSX || FREEBSD 159 -#include <sys/ioctl.h> 160 +#include <sys/types.h> 161 #include <net/if.h> 162 -#include <netdb.h> 163 -#if FREEBSD 164 #include <ifaddrs.h> 165 +#include <netdb.h> 166 +#if FREEBSD || OSX 167 #include <net/if_dl.h> 168 #include <net/if_types.h> 169 #endif 170 @@ -44,15 +44,11 @@ 171 #if WIN 172 #include <iphlpapi.h> 173 #endif 174 -#if OSX 175 -#include <net/if_dl.h> 176 -#include <net/if_types.h> 177 -#include <ifaddrs.h> 178 -#include <netdb.h> 179 -#endif 180 181 #include <fcntl.h> 182 183 +static log_level loglevel; 184 + 185 // logging functions 186 const char *logtime(void) { 187 static char buf[100]; 188 @@ -114,58 +110,101 @@ u32_t gettime_ms(void) { 189 #endif 190 } 191 192 -// mac address 193 -#if LINUX && !defined(SUN) 194 -// search first 4 interfaces returned by IFCONF 195 -void get_mac(u8_t mac[]) { 196 - char *utmac; 197 - struct ifconf ifc; 198 - struct ifreq *ifr, *ifend; 199 - struct ifreq ifreq; 200 - struct ifreq ifs[4]; 201 +// Get broadcast address for interface (given or first available) 202 +// Return MAC address if none given 203 +#if LINUX || OSX || FREEBSD 204 205 - utmac = getenv("UTMAC"); 206 - if (utmac) 207 - { 208 - if ( strlen(utmac) == 17 ) 209 - { 210 - if (sscanf(utmac,"%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx", 211 - &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) == 6) 212 - { 213 - return; 214 - } 215 - } 216 +in_addr_t get_iface_info(log_level level, char *iface, u8_t *mac) { 217 + struct ifaddrs *addrs, *ifa; 218 + struct sockaddr *sdl; 219 + char ifname[16]; 220 + unsigned char *ptr; 221 + in_addr_t bcast_addr = 0; 222 + int have_mac = 0, have_ifname = 0; 223 + 224 + loglevel = level; 225 + 226 + // Check for non-zero MAC 227 + if ((mac[0] | mac[1] | mac[2]) != 0) 228 + have_mac = 1; 229 + 230 + // Copy interface name, if it was provided. 231 + if (iface != NULL) 232 + { 233 + if( strlen(iface) > sizeof(ifname) ) 234 + return -1; 235 236 + strncpy(ifname, iface, sizeof(ifname)); 237 + have_ifname = 1; 238 } 239 240 - mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0; 241 + if (getifaddrs(&addrs) == 0) { 242 + //iterate to find corresponding ethernet address 243 + for (ifa = addrs; ifa; ifa = ifa->ifa_next) { 244 + // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that 245 + // don't support BROADCAST. 246 + if ((ifa->ifa_flags & IFF_LOOPBACK) 247 + || !(ifa->ifa_flags & IFF_UP) 248 + || !(ifa->ifa_flags & IFF_BROADCAST)) 249 + { 250 + continue; 251 + } 252 253 - int s = socket(AF_INET, SOCK_DGRAM, 0); 254 + if (!have_ifname) 255 + { 256 + // We have found a valid interface name. Keep it. 257 + strncpy(ifname, ifa->ifa_name, sizeof(ifname)); 258 + have_ifname = 1; 259 + } else { 260 + if (strncmp(ifname, ifa->ifa_name, sizeof(ifname)) != 0) 261 + { 262 + // This is not the interface we're looking for. 263 + continue; 264 + } 265 + } 266 267 - ifc.ifc_len = sizeof(ifs); 268 - ifc.ifc_req = ifs; 269 270 - if (ioctl(s, SIOCGIFCONF, &ifc) == 0) { 271 - ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); 272 + // Check address family. 273 + if ((ifa->ifa_addr->sa_family == AF_INET) && 274 + (((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr.s_addr != 0)) 275 + { 276 + // Get broadcast address and MAC address 277 + bcast_addr = ((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr.s_addr; 278 + break; 279 + } 280 + else 281 + { 282 + // Address is not IPv4 283 + if (iface == NULL) 284 + have_ifname = 0; 285 + } 286 + 287 + } 288 289 - for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { 290 - if (ifr->ifr_addr.sa_family == AF_INET) { 291 - 292 - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); 293 - if (ioctl (s, SIOCGIFHWADDR, &ifreq) == 0) { 294 - memcpy(mac, ifreq.ifr_hwaddr.sa_data, 6); 295 - if (mac[0]+mac[1]+mac[2] != 0) { 296 - break; 297 - } 298 + // Find MAC address matching interface 299 + if (!have_mac && (bcast_addr != 0)) { 300 + for (ifa = addrs; ifa; ifa = ifa->ifa_next) { 301 + if ((ifa->ifa_addr->sa_family == PF_PACKET) && 302 + (strncmp(ifname, ifa->ifa_name, sizeof(ifname)) == 0)) { 303 + sdl = (struct sockaddr *)(ifa->ifa_addr); 304 + ptr = (unsigned char *)sdl->sa_data; 305 + memcpy(mac, ptr + 10, 6); 306 + have_mac = 1; 307 } 308 } 309 } 310 + 311 + freeifaddrs(addrs); 312 } 313 314 - close(s); 315 + LOG_INFO("Interface: %s, broadcast: %08X, macaddr = %02x:%02x:%02x:%02x:%02x:%02x", 316 + ifname, bcast_addr, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 317 + 318 + return bcast_addr; 319 } 320 #endif 321 322 + 323 #if SUN 324 void get_mac(u8_t mac[]) { 325 struct arpreq parpreq; 326 @@ -232,30 +271,6 @@ void get_mac(u8_t mac[]) { 327 } 328 #endif 329 330 -#if OSX || FREEBSD 331 -void get_mac(u8_t mac[]) { 332 - struct ifaddrs *addrs, *ptr; 333 - const struct sockaddr_dl *dlAddr; 334 - const unsigned char *base; 335 - 336 - mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0; 337 - 338 - if (getifaddrs(&addrs) == 0) { 339 - ptr = addrs; 340 - while (ptr) { 341 - if (ptr->ifa_addr->sa_family == AF_LINK && ((const struct sockaddr_dl *) ptr->ifa_addr)->sdl_type == IFT_ETHER) { 342 - dlAddr = (const struct sockaddr_dl *)ptr->ifa_addr; 343 - base = (const unsigned char*) &dlAddr->sdl_data[dlAddr->sdl_nlen]; 344 - memcpy(mac, base, min(dlAddr->sdl_alen, 6)); 345 - break; 346 - } 347 - ptr = ptr->ifa_next; 348 - } 349 - freeifaddrs(addrs); 350 - } 351 -} 352 -#endif 353 - 354 #if WIN 355 #pragma comment(lib, "IPHLPAPI.lib") 356 void get_mac(u8_t mac[]) {