1 /*
2 * Squeezelite - lightweight headless squeezebox emulator
3 *
4 * (c) Adrian Smith 2012-2015, triode1@btinternet.com
5 * Ralph Irving 2015-2017, ralph_irving@hotmail.com
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22 #include "squeezelite.h"
23
24 #if LINUX || OSX || FREEBSD
25 #include <sys/ioctl.h>
26 #include <net/if.h>
27 #include <netdb.h>
28 #if FREEBSD
29 #include <ifaddrs.h>
30 #include <net/if_dl.h>
31 #include <net/if_types.h>
32 #endif
33 #endif
34 #if SUN
35 #include <sys/socket.h>
36 #include <sys/sockio.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <net/if.h>
40 #include <net/if_arp.h>
41 #include <net/if_dl.h>
42 #include <net/if_types.h>
43 #endif
44 #if WIN
45 #include <iphlpapi.h>
46 #if USE_SSL
47 #include <stdlib.h>
48 #include <string.h>
49 #include <ctype.h>
50 #endif
51 #endif
52 #if OSX
53 #include <net/if_dl.h>
54 #include <net/if_types.h>
55 #include <ifaddrs.h>
56 #include <netdb.h>
57 #endif
58
59 #include <fcntl.h>
60
61 // logging functions
logtime(void)62 const char *logtime(void) {
63 static char buf[100];
64 #if WIN
65 SYSTEMTIME lt;
66 GetLocalTime(<);
67 sprintf(buf, "[%02d:%02d:%02d.%03d]", lt.wHour, lt.wMinute, lt.wSecond, lt.wMilliseconds);
68 #else
69 struct timeval tv;
70 gettimeofday(&tv, NULL);
71 strftime(buf, sizeof(buf), "[%T.", localtime(&tv.tv_sec));
72 sprintf(buf+strlen(buf), "%06ld]", (long)tv.tv_usec);
73 #endif
74 return buf;
75 }
76
logprint(const char * fmt,...)77 void logprint(const char *fmt, ...) {
78 va_list args;
79 va_start(args, fmt);
80 vfprintf(stderr, fmt, args);
81 va_end(args);
82 fflush(stderr);
83 }
84
85 // cmdline parsing
next_param(char * src,char c)86 char *next_param(char *src, char c) {
87 static char *str = NULL;
88 char *ptr, *ret;
89 if (src) str = src;
90 if (str && (ptr = strchr(str, c))) {
91 ret = str;
92 *ptr = '\0';
93 str = ptr + 1;
94 } else {
95 ret = str;
96 str = NULL;
97 }
98
99 return ret && ret[0] ? ret : NULL;
100 }
101
102 // clock
gettime_ms(void)103 u32_t gettime_ms(void) {
104 #if WIN
105 return GetTickCount();
106 #else
107 #if LINUX || FREEBSD
108 struct timespec ts;
109 #ifdef CLOCK_MONOTONIC
110 if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
111 #else
112 if (!clock_gettime(CLOCK_REALTIME, &ts)) {
113 #endif
114 return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
115 }
116 #endif
117 struct timeval tv;
118 gettimeofday(&tv, NULL);
119 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
120 #endif
121 }
122
123 // mac address
124 #if LINUX && !defined(SUN)
125 // search first 4 interfaces returned by IFCONF
126 void get_mac(u8_t mac[]) {
127 char *utmac;
128 struct ifconf ifc;
129 struct ifreq *ifr, *ifend;
130 struct ifreq ifreq;
131 struct ifreq ifs[4];
132
133 utmac = getenv("UTMAC");
134 if (utmac)
135 {
136 if ( strlen(utmac) == 17 )
137 {
138 if (sscanf(utmac,"%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
139 &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) == 6)
140 {
141 return;
142 }
143 }
144
145 }
146
147 mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
148
149 int s = socket(AF_INET, SOCK_DGRAM, 0);
150
151 ifc.ifc_len = sizeof(ifs);
152 ifc.ifc_req = ifs;
153
154 if (ioctl(s, SIOCGIFCONF, &ifc) == 0) {
155 ifend = ifs + (ifc.ifc_len / sizeof(struct ifreq));
156
157 for (ifr = ifc.ifc_req; ifr < ifend; ifr++) {
158 if (ifr->ifr_addr.sa_family == AF_INET) {
159
160 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name) - 1);
161 if (ioctl (s, SIOCGIFHWADDR, &ifreq) == 0) {
162 memcpy(mac, ifreq.ifr_hwaddr.sa_data, 6);
163 if (mac[0]+mac[1]+mac[2] != 0) {
164 break;
165 }
166 }
167 }
168 }
169 }
170
171 close(s);
172 }
173 #endif
174
175 #if SUN
176 void get_mac(u8_t mac[]) {
177 struct arpreq parpreq;
178 struct sockaddr_in *psa;
179 struct in_addr inaddr;
180 struct hostent *phost;
181 char hostname[MAXHOSTNAMELEN];
182 char **paddrs;
183 char *utmac;
184 int sock;
185 int status=0;
186
187 utmac = getenv("UTMAC");
188 if (utmac)
189 {
190 if ( strlen(utmac) == 17 )
191 {
192 if (sscanf(utmac,"%2hhx:%2hhx:%2hhx:%2hhx:%2hhx:%2hhx",
193 &mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]) == 6)
194 {
195 return;
196 }
197 }
198
199 }
200
201 mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
202
203 gethostname(hostname, MAXHOSTNAMELEN);
204
205 phost = gethostbyname(hostname);
206
207 paddrs = phost->h_addr_list;
208 memcpy(&inaddr.s_addr, *paddrs, sizeof(inaddr.s_addr));
209
210 sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
211
212 if(sock == -1)
213 {
214 mac[5] = 1;
215 return;
216 }
217
218 memset(&parpreq, 0, sizeof(struct arpreq));
219 psa = (struct sockaddr_in *) &parpreq.arp_pa;
220 memset(psa, 0, sizeof(struct sockaddr_in));
221 psa->sin_family = AF_INET;
222 memcpy(&psa->sin_addr, *paddrs, sizeof(struct in_addr));
223
224 status = ioctl(sock, SIOCGARP, &parpreq);
225
226 if(status == -1)
227 {
228 mac[5] = 2;
229 return;
230 }
231
232 mac[0] = (unsigned char) parpreq.arp_ha.sa_data[0];
233 mac[1] = (unsigned char) parpreq.arp_ha.sa_data[1];
234 mac[2] = (unsigned char) parpreq.arp_ha.sa_data[2];
235 mac[3] = (unsigned char) parpreq.arp_ha.sa_data[3];
236 mac[4] = (unsigned char) parpreq.arp_ha.sa_data[4];
237 mac[5] = (unsigned char) parpreq.arp_ha.sa_data[5];
238 }
239 #endif
240
241 #if OSX || FREEBSD
242 void get_mac(u8_t mac[]) {
243 struct ifaddrs *addrs, *ptr;
244 const struct sockaddr_dl *dlAddr;
245 const unsigned char *base;
246
247 mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
248
249 if (getifaddrs(&addrs) == 0) {
250 ptr = addrs;
251 while (ptr) {
252 if (ptr->ifa_addr->sa_family == AF_LINK && ((const struct sockaddr_dl *) ptr->ifa_addr)->sdl_type == IFT_ETHER) {
253 dlAddr = (const struct sockaddr_dl *)ptr->ifa_addr;
254 base = (const unsigned char*) &dlAddr->sdl_data[dlAddr->sdl_nlen];
255 memcpy(mac, base, min(dlAddr->sdl_alen, 6));
256 break;
257 }
258 ptr = ptr->ifa_next;
259 }
260 freeifaddrs(addrs);
261 }
262 }
263 #endif
264
265 #if WIN
266 #pragma comment(lib, "IPHLPAPI.lib")
267 void get_mac(u8_t mac[]) {
268 IP_ADAPTER_INFO AdapterInfo[16];
269 DWORD dwBufLen = sizeof(AdapterInfo);
270 DWORD dwStatus = GetAdaptersInfo(AdapterInfo, &dwBufLen);
271
272 mac[0] = mac[1] = mac[2] = mac[3] = mac[4] = mac[5] = 0;
273
274 if (GetAdaptersInfo(AdapterInfo, &dwBufLen) == ERROR_SUCCESS) {
275 memcpy(mac, AdapterInfo[0].Address, 6);
276 }
277 }
278 #endif
279
280 void set_nonblock(sockfd s) {
281 #if WIN
282 u_long iMode = 1;
283 ioctlsocket(s, FIONBIO, &iMode);
284 #else
285 int flags = fcntl(s, F_GETFL,0);
286 fcntl(s, F_SETFL, flags | O_NONBLOCK);
287 #endif
288 }
289
290 // connect for socket already set to non blocking with timeout in seconds
291 int connect_timeout(sockfd sock, const struct sockaddr *addr, socklen_t addrlen, int timeout) {
292 fd_set w, e;
293 struct timeval tval;
294
295 if (connect(sock, addr, addrlen) < 0) {
296 #if !WIN
297 if (last_error() != EINPROGRESS) {
298 #else
299 if (last_error() != WSAEWOULDBLOCK) {
300 #endif
301 return -1;
302 }
303 }
304
305 FD_ZERO(&w);
306 FD_SET(sock, &w);
307 e = w;
308 tval.tv_sec = timeout;
309 tval.tv_usec = 0;
310
311 // only return 0 if w set and sock error is zero, otherwise return error code
312 if (select(sock + 1, NULL, &w, &e, timeout ? &tval : NULL) == 1 && FD_ISSET(sock, &w)) {
313 int error = 0;
314 socklen_t len = sizeof(error);
315 getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&error, &len);
316 return error;
317 }
318
319 return -1;
320 }
321
322 void server_addr(char *server, in_addr_t *ip_ptr, unsigned *port_ptr) {
323 struct addrinfo *res = NULL;
324 struct addrinfo hints;
325 const char *port = NULL;
326
327 if (strtok(server, ":")) {
328 port = strtok(NULL, ":");
329 if (port) {
330 *port_ptr = atoi(port);
331 }
332 }
333
334 memset(&hints, 0, sizeof(struct addrinfo));
335 hints.ai_family = AF_INET;
336
337 getaddrinfo(server, NULL, &hints, &res);
338
339 if (res && res->ai_addr) {
340 *ip_ptr = ((struct sockaddr_in*)res->ai_addr)->sin_addr.s_addr;
341 }
342
343 if (res) {
344 freeaddrinfo(res);
345 }
346 }
347
348 void set_readwake_handles(event_handle handles[], sockfd s, event_event e) {
349 #if WINEVENT
350 handles[0] = WSACreateEvent();
351 handles[1] = e;
352 WSAEventSelect(s, handles[0], FD_READ | FD_CLOSE);
353 #elif SELFPIPE
354 handles[0].fd = s;
355 handles[1].fd = e.fds[0];
356 handles[0].events = POLLIN;
357 handles[1].events = POLLIN;
358 #else
359 handles[0].fd = s;
360 handles[1].fd = e;
361 handles[0].events = POLLIN;
362 handles[1].events = POLLIN;
363 #endif
364 }
365
366 event_type wait_readwake(event_handle handles[], int timeout) {
367 #if WINEVENT
368 int wait = WSAWaitForMultipleEvents(2, handles, FALSE, timeout, FALSE);
369 if (wait == WSA_WAIT_EVENT_0) {
370 WSAResetEvent(handles[0]);
371 return EVENT_READ;
372 } else if (wait == WSA_WAIT_EVENT_0 + 1) {
373 return EVENT_WAKE;
374 } else {
375 return EVENT_TIMEOUT;
376 }
377 #else
378 if (poll(handles, 2, timeout) > 0) {
379 if (handles[0].revents) {
380 return EVENT_READ;
381 }
382 if (handles[1].revents) {
383 wake_clear(handles[1].fd);
384 return EVENT_WAKE;
385 }
386 }
387 return EVENT_TIMEOUT;
388 #endif
389 }
390
391 // pack/unpack to network byte order
392 void packN(u32_t *dest, u32_t val) {
393 u8_t *ptr = (u8_t *)dest;
394 *(ptr) = (val >> 24) & 0xFF; *(ptr+1) = (val >> 16) & 0xFF; *(ptr+2) = (val >> 8) & 0xFF; *(ptr+3) = val & 0xFF;
395 }
396
397 void packn(u16_t *dest, u16_t val) {
398 u8_t *ptr = (u8_t *)dest;
399 *(ptr) = (val >> 8) & 0xFF; *(ptr+1) = val & 0xFF;
400 }
401
402 u32_t unpackN(u32_t *src) {
403 u8_t *ptr = (u8_t *)src;
404 return *(ptr) << 24 | *(ptr+1) << 16 | *(ptr+2) << 8 | *(ptr+3);
405 }
406
407 u16_t unpackn(u16_t *src) {
408 u8_t *ptr = (u8_t *)src;
409 return *(ptr) << 8 | *(ptr+1);
410 }
411
412 #if OSX
413 void set_nosigpipe(sockfd s) {
414 int set = 1;
415 setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
416 }
417 #endif
418
419 #if WIN
420 void winsock_init(void) {
421 WSADATA wsaData;
422 WORD wVersionRequested = MAKEWORD(2, 2);
423 int WSerr = WSAStartup(wVersionRequested, &wsaData);
424 if (WSerr != 0) {
425 LOG_ERROR("Bad winsock version");
426 exit(1);
427 }
428 }
429
430 void winsock_close(void) {
431 WSACleanup();
432 }
433
434 void *dlopen(const char *filename, int flag) {
435 SetLastError(0);
436 return LoadLibrary((LPCTSTR)filename);
437 }
438
439 void *dlsym(void *handle, const char *symbol) {
440 SetLastError(0);
441 return (void *)GetProcAddress(handle, symbol);
442 }
443
444 char *dlerror(void) {
445 static char ret[32];
446 int last = GetLastError();
447 if (last) {
448 sprintf(ret, "code: %i", last);
449 SetLastError(0);
450 return ret;
451 }
452 return NULL;
453 }
454
455 // this only implements numfds == 1
456 int poll(struct pollfd *fds, unsigned long numfds, int timeout) {
457 fd_set r, w;
458 struct timeval tv;
459 int ret;
460
461 FD_ZERO(&r);
462 FD_ZERO(&w);
463
464 if (fds[0].events & POLLIN) FD_SET(fds[0].fd, &r);
465 if (fds[0].events & POLLOUT) FD_SET(fds[0].fd, &w);
466
467 tv.tv_sec = timeout / 1000;
468 tv.tv_usec = 1000 * (timeout % 1000);
469
470 ret = select(fds[0].fd + 1, &r, &w, NULL, &tv);
471
472 if (ret < 0) return ret;
473
474 fds[0].revents = 0;
475 if (FD_ISSET(fds[0].fd, &r)) fds[0].revents |= POLLIN;
476 if (FD_ISSET(fds[0].fd, &w)) fds[0].revents |= POLLOUT;
477
478 return ret;
479 }
480
481 #endif
482
483 #if LINUX || FREEBSD
484 void touch_memory(u8_t *buf, size_t size) {
485 u8_t *ptr;
486 for (ptr = buf; ptr < buf + size; ptr += sysconf(_SC_PAGESIZE)) {
487 *ptr = 0;
488 }
489 }
490 #endif
491
492 #if WIN && USE_SSL
493 char *strcasestr(const char *haystack, const char *needle) {
494 size_t length_needle;
495 size_t length_haystack;
496 size_t i;
497
498 if (!haystack || !needle)
499 return NULL;
500
501 length_needle = strlen(needle);
502 length_haystack = strlen(haystack) - length_needle + 1;
503
504 for (i = 0; i < length_haystack; i++)
505 {
506 size_t j;
507
508 for (j = 0; j < length_needle; j++)
509 {
510 unsigned char c1;
511 unsigned char c2;
512
513 c1 = haystack[i+j];
514 c2 = needle[j];
515 if (toupper(c1) != toupper(c2))
516 goto next;
517 }
518 return (char *) haystack + i;
519 next:
520 ;
521 }
522
523 return NULL;
524 }
525 #endif
526