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

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