b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | --- a/main.c |
| 2 | +++ b/main.c |
| 3 | @@ -93,6 +93,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>\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 | @@ -285,6 +286,8 @@ int main(int argc, char **argv) { |
| 12 | extern bool user_rates; |
| 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 | @@ -325,6 +328,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 | @@ -332,8 +336,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 | @@ -341,7 +343,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 | "UVO" |
| 45 | #endif |
| 46 | @@ -442,6 +444,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 | @@ -755,6 +760,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 | @@ -798,7 +808,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/slimproto.c |
| 78 | +++ b/slimproto.c |
| 79 | @@ -113,7 +113,7 @@ void send_packet(u8_t *packet, size_t le |
| 80 | } |
| 81 | } |
| 82 | |
| 83 | -static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t mac[6]) { |
| 84 | +static void sendHELO(bool reconnect, const char *fixed_cap, const char *var_cap, u8_t *mac) { |
| 85 | #define BASE_CAP "Model=squeezelite,AccuratePlayPoints=1,HasDigitalOut=1,HasPolarityInversion=1,Firmware=" VERSION |
| 86 | #define SSL_CAP "CanHTTPS=1" |
| 87 | const char *base_cap; |
| 88 | @@ -761,7 +761,7 @@ void wake_controller(void) { |
| 89 | wake_signal(wake_e); |
| 90 | } |
| 91 | |
| 92 | -in_addr_t discover_server(char *default_server) { |
| 93 | +in_addr_t discover_server(char *default_server, in_addr_t bcast_addr) { |
| 94 | struct sockaddr_in d; |
| 95 | struct sockaddr_in s; |
| 96 | char *buf; |
| 97 | @@ -778,7 +778,7 @@ in_addr_t discover_server(char *default_ |
| 98 | memset(&d, 0, sizeof(d)); |
| 99 | d.sin_family = AF_INET; |
| 100 | d.sin_port = htons(PORT); |
| 101 | - d.sin_addr.s_addr = htonl(INADDR_BROADCAST); |
| 102 | + d.sin_addr.s_addr = bcast_addr; |
| 103 | |
| 104 | pollinfo.fd = disc_sock; |
| 105 | pollinfo.events = POLLIN; |
| 106 | @@ -813,7 +813,7 @@ in_addr_t discover_server(char *default_ |
| 107 | #define FIXED_CAP_LEN 256 |
| 108 | #define VAR_CAP_LEN 128 |
| 109 | |
| 110 | -void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate) { |
| 111 | +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) { |
| 112 | struct sockaddr_in serv_addr; |
| 113 | static char fixed_cap[FIXED_CAP_LEN], var_cap[VAR_CAP_LEN] = ""; |
| 114 | bool reconnect = false; |
| 115 | @@ -834,7 +834,7 @@ void slimproto(log_level level, char *se |
| 116 | } |
| 117 | |
| 118 | if (!slimproto_ip) { |
| 119 | - slimproto_ip = discover_server(server); |
| 120 | + slimproto_ip = discover_server(server, bcast_addr); |
| 121 | } |
| 122 | |
| 123 | if (!slimproto_port) { |
| 124 | @@ -915,7 +915,7 @@ void slimproto(log_level level, char *se |
| 125 | |
| 126 | // rediscover server if it was not set at startup |
| 127 | if (!server && ++failed_connect > 5) { |
| 128 | - slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(NULL); |
| 129 | + slimproto_ip = serv_addr.sin_addr.s_addr = discover_server(NULL, bcast_addr); |
| 130 | } |
| 131 | |
| 132 | } else { |
| 133 | --- a/squeezelite.h |
| 134 | +++ b/squeezelite.h |
| 135 | @@ -455,7 +455,7 @@ char* strcasestr(const char *haystack, c |
| 136 | |
| 137 | char *next_param(char *src, char c); |
| 138 | u32_t gettime_ms(void); |
| 139 | -void get_mac(u8_t *mac); |
| 140 | +in_addr_t get_iface_info(log_level level, char *iface, u8_t *mac); |
| 141 | void set_nonblock(sockfd s); |
| 142 | int connect_timeout(sockfd sock, const struct sockaddr *addr, socklen_t addrlen, int timeout); |
| 143 | void server_addr(char *server, in_addr_t *ip_ptr, unsigned *port_ptr); |
| 144 | @@ -511,7 +511,7 @@ void buf_init(struct buffer *buf, size_t |
| 145 | void buf_destroy(struct buffer *buf); |
| 146 | |
| 147 | // slimproto.c |
| 148 | -void slimproto(log_level level, char *server, u8_t mac[6], const char *name, const char *namefile, const char *modelname, int maxSampleRate); |
| 149 | +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); |
| 150 | void slimproto_stop(void); |
| 151 | void wake_controller(void); |
| 152 | |
| 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 | @@ -49,15 +49,11 @@ |
| 171 | #include <ctype.h> |
| 172 | #endif |
| 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 | @@ -119,58 +115,94 @@ 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 | + if (strlen(iface) > sizeof(ifname)) |
| 233 | + return -1; |
| 234 | |
| 235 | + strncpy(ifname, iface, sizeof(ifname) - 1); |
| 236 | + have_ifname = 1; |
| 237 | } |
| 238 | |
| 239 | - mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0; |
| 240 | + if (getifaddrs(&addrs) == 0) { |
| 241 | + //iterate to find corresponding ethernet address |
| 242 | + for (ifa = addrs; ifa; ifa = ifa->ifa_next) { |
| 243 | + // Skip LOOPBACK interfaces, DOWN interfaces and interfaces that |
| 244 | + // don't support BROADCAST. |
| 245 | + if (ifa->ifa_flags & IFF_LOOPBACK |
| 246 | + || !ifa->ifa_flags & IFF_UP |
| 247 | + || !ifa->ifa_flags & IFF_BROADCAST) { |
| 248 | + continue; |
| 249 | + } |
| 250 | |
| 251 | - int s = socket(AF_INET, SOCK_DGRAM, 0); |
| 252 | + if (!have_ifname) { |
| 253 | + // We have found a valid interface name. Keep it. |
| 254 | + strncpy(ifname, ifa->ifa_name, sizeof(ifname) - 1); |
| 255 | + have_ifname = 1; |
| 256 | + } else { |
| 257 | + if (strncmp(ifname, ifa->ifa_name, sizeof(ifname)) != 0) { |
| 258 | + // This is not the interface we're looking for. |
| 259 | + continue; |
| 260 | + } |
| 261 | + } |
| 262 | |
| 263 | - ifc.ifc_len = sizeof(ifs); |
| 264 | - ifc.ifc_req = ifs; |
| 265 | |
| 266 | - if (ioctl(s, SIOCGIFCONF, &ifc) == 0) { |
| 267 | - ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq)); |
| 268 | + // Check address family. |
| 269 | + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET && |
| 270 | + ((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr.s_addr != 0) { |
| 271 | + // Get broadcast address and MAC address |
| 272 | + bcast_addr = ((struct sockaddr_in *)ifa->ifa_broadaddr)->sin_addr.s_addr; |
| 273 | + break; |
| 274 | + } |
| 275 | + else { |
| 276 | + // Address is not IPv4 |
| 277 | + if (iface == NULL) |
| 278 | + have_ifname = 0; |
| 279 | + } |
| 280 | + } |
| 281 | |
| 282 | - for (ifr = ifc.ifc_req; ifr < ifend; ifr++) { |
| 283 | - if (ifr->ifr_addr.sa_family == AF_INET) { |
| 284 | - |
| 285 | - strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1); |
| 286 | - if (ioctl (s, SIOCGIFHWADDR, &ifreq) == 0) { |
| 287 | - memcpy(mac, ifreq.ifr_hwaddr.sa_data, 6); |
| 288 | - if (mac[0]+mac[1]+mac[2] != 0) { |
| 289 | - break; |
| 290 | - } |
| 291 | + // Find MAC address matching interface |
| 292 | + if (!have_mac && bcast_addr != 0) { |
| 293 | + for (ifa = addrs; ifa; ifa = ifa->ifa_next) { |
| 294 | + if (ifa->ifa_addr && ifa->ifa_addr->sa_family == PF_PACKET && |
| 295 | + strncmp(ifname, ifa->ifa_name, sizeof(ifname)) == 0) { |
| 296 | + sdl = (struct sockaddr *)(ifa->ifa_addr); |
| 297 | + ptr = (unsigned char *)sdl->sa_data; |
| 298 | + memcpy(mac, ptr + 10, 6); |
| 299 | + have_mac = 1; |
| 300 | } |
| 301 | } |
| 302 | } |
| 303 | + |
| 304 | + freeifaddrs(addrs); |
| 305 | } |
| 306 | |
| 307 | - close(s); |
| 308 | + LOG_INFO("Interface: %s, broadcast: %08X, macaddr = %02x:%02x:%02x:%02x:%02x:%02x", |
| 309 | + ifname, bcast_addr, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); |
| 310 | + |
| 311 | + return bcast_addr; |
| 312 | } |
| 313 | #endif |
| 314 | |
| 315 | + |
| 316 | #if SUN |
| 317 | void get_mac(u8_t mac[]) { |
| 318 | struct arpreq parpreq; |
| 319 | @@ -237,30 +269,6 @@ void get_mac(u8_t mac[]) { |
| 320 | } |
| 321 | #endif |
| 322 | |
| 323 | -#if OSX || FREEBSD |
| 324 | -void get_mac(u8_t mac[]) { |
| 325 | - struct ifaddrs *addrs, *ptr; |
| 326 | - const struct sockaddr_dl *dlAddr; |
| 327 | - const unsigned char *base; |
| 328 | - |
| 329 | - mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0; |
| 330 | - |
| 331 | - if (getifaddrs(&addrs) == 0) { |
| 332 | - ptr = addrs; |
| 333 | - while (ptr) { |
| 334 | - if (ptr->ifa_addr->sa_family == AF_LINK && ((const struct sockaddr_dl *) ptr->ifa_addr)->sdl_type == IFT_ETHER) { |
| 335 | - dlAddr = (const struct sockaddr_dl *)ptr->ifa_addr; |
| 336 | - base = (const unsigned char*) &dlAddr->sdl_data[dlAddr->sdl_nlen]; |
| 337 | - memcpy(mac, base, min(dlAddr->sdl_alen, 6)); |
| 338 | - break; |
| 339 | - } |
| 340 | - ptr = ptr->ifa_next; |
| 341 | - } |
| 342 | - freeifaddrs(addrs); |
| 343 | - } |
| 344 | -} |
| 345 | -#endif |
| 346 | - |
| 347 | #if WIN |
| 348 | #pragma comment(lib, "IPHLPAPI.lib") |
| 349 | void get_mac(u8_t mac[]) { |