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.

338 lines
9.7 KiB

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