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(&lt);
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