| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606 | 
							- /*
 
-  * AirConnect: Chromecast & UPnP to AirPlay
 
-  *
 
-  * (c) Philippe 2016-2017, philippe_44@outlook.com
 
-  *
 
-  * This software is released under the MIT License.
 
-  * https://opensource.org/licenses/MIT
 
-  *
 
-  */
 
- #include "platform.h"
 
- #ifdef WIN32
 
- #include <iphlpapi.h>
 
- #else
 
- #include "tcpip_adapter.h"
 
- // IDF-V4++ #include "esp_netif.h"
 
- #include <ctype.h>
 
- #endif
 
- #include <stdarg.h>
 
- #include "pthread.h"
 
- #include "util.h"
 
- #include "log_util.h"
 
- /*----------------------------------------------------------------------------*/
 
- /* globals */
 
- /*----------------------------------------------------------------------------*/
 
- extern log_level	util_loglevel;
 
- /*----------------------------------------------------------------------------*/
 
- /* locals */
 
- /*----------------------------------------------------------------------------*/
 
- static log_level 		*loglevel = &util_loglevel;
 
- static char *ltrim(char *s);
 
- static int read_line(int fd, char *line, int maxlen, int timeout);
 
- /*----------------------------------------------------------------------------*/
 
- /* 																			  */
 
- /* NETWORKING utils															  */
 
- /* 																			  */
 
- /*----------------------------------------------------------------------------*/
 
- /*---------------------------------------------------------------------------*/
 
- #define MAX_INTERFACES 256
 
- #define DEFAULT_INTERFACE 1
 
- #if !defined(WIN32)
 
- #define INVALID_SOCKET (-1)
 
- #endif
 
- in_addr_t get_localhost(char **name)
 
- {
 
- #ifdef WIN32
 
- 	char buf[256];
 
- 	struct hostent *h = NULL;
 
- 	struct sockaddr_in LocalAddr;
 
- 	memset(&LocalAddr, 0, sizeof(LocalAddr));
 
- 	gethostname(buf, 256);
 
- 	h = gethostbyname(buf);
 
- 	if (name) *name = strdup(buf);
 
- 	if (h != NULL) {
 
- 		memcpy(&LocalAddr.sin_addr, h->h_addr_list[0], 4);
 
- 		return LocalAddr.sin_addr.s_addr;
 
- 	}
 
- 	else return INADDR_ANY;
 
- #else
 
- 	tcpip_adapter_ip_info_t ipInfo; 
 
- 	tcpip_adapter_if_t if_type = TCPIP_ADAPTER_IF_STA;
 
- 	// then get IP address
 
-  	tcpip_adapter_get_ip_info(if_type, &ipInfo);
 
- 	
 
- 	// we might be in AP mode
 
- 	if (ipInfo.ip.addr == INADDR_ANY) {
 
- 		if_type = TCPIP_ADAPTER_IF_AP;
 
- 		tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_AP, &ipInfo);
 
- 	}
 
- 	// get hostname if required
 
- 	if (name) {
 
- 		const char *hostname;
 
- 		tcpip_adapter_get_hostname(if_type, &hostname);
 
- 		*name = strdup(hostname);
 
- 	}	
 
- 	return ipInfo.ip.addr;
 
- #endif
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- #ifdef WIN32
 
- void winsock_init(void) {
 
- 	WSADATA wsaData;
 
- 	WORD wVersionRequested = MAKEWORD(2, 2);
 
- 	int WSerr = WSAStartup(wVersionRequested, &wsaData);
 
- 	if (WSerr != 0) {
 
- 		LOG_ERROR("Bad winsock version", NULL);
 
- 		exit(1);
 
- 	}
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- void winsock_close(void) {
 
- 	WSACleanup();
 
- }
 
- #endif
 
- /*----------------------------------------------------------------------------*/
 
- int shutdown_socket(int sd)
 
- {
 
- 	if (sd <= 0) return -1;
 
- #ifdef WIN32
 
- 	shutdown(sd, SD_BOTH);
 
- #else
 
- 	shutdown(sd, SHUT_RDWR);
 
- #endif
 
- 	LOG_DEBUG("closed socket %d", sd);
 
- 	return closesocket(sd);
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- int bind_socket(unsigned short *port, int mode)
 
- {
 
- 	int sock;
 
- 	socklen_t len = sizeof(struct sockaddr);
 
- 	struct sockaddr_in addr;
 
- 	if ((sock = socket(AF_INET, mode, 0)) < 0) {
 
- 		LOG_ERROR("cannot create socket %d", sock);
 
- 		return sock;
 
- 	}
 
- 	/*  Populate socket address structure  */
 
- 	memset(&addr, 0, sizeof(addr));
 
- 	addr.sin_family      = AF_INET;
 
- 	addr.sin_addr.s_addr = htonl(INADDR_ANY);
 
- 	addr.sin_port        = htons(*port);
 
- #ifdef SIN_LEN
 
- 	si.sin_len = sizeof(si);
 
- #endif
 
- 	if (bind(sock, (struct sockaddr*) &addr, sizeof(addr)) < 0) {
 
- 		closesocket(sock);
 
- 		LOG_ERROR("cannot bind socket %d", sock);
 
- 		return -1;
 
- 	}
 
- 	if (!*port) {
 
- 		getsockname(sock, (struct sockaddr *) &addr, &len);
 
- 		*port = ntohs(addr.sin_port);
 
- 	}
 
- 	LOG_DEBUG("socket binding %d on port %d", sock, *port);
 
- 	return sock;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- int conn_socket(unsigned short port)
 
- {
 
- 	struct sockaddr_in addr;
 
- 	int sd;
 
- 	sd = socket(AF_INET, SOCK_STREAM, 0);
 
- 	addr.sin_family = AF_INET;
 
- 	addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
 
- 	addr.sin_port = htons(port);
 
- 	if (sd < 0 || connect(sd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
 
- 		close(sd);
 
- 		return -1;
 
- 	}
 
- 	LOG_DEBUG("created socket %d", sd);
 
- 	return sd;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- /* 																			  */
 
- /* SYSTEM utils															 	  */
 
- /* 																			  */
 
- /*----------------------------------------------------------------------------*/
 
- #ifdef WIN32
 
- /*----------------------------------------------------------------------------*/
 
- void *dlopen(const char *filename, int flag) {
 
- 	SetLastError(0);
 
- 	return LoadLibrary((LPCTSTR)filename);
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- void *dlsym(void *handle, const char *symbol) {
 
- 	SetLastError(0);
 
- 	return (void *)GetProcAddress(handle, symbol);
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- char *dlerror(void) {
 
- 	static char ret[32];
 
- 	int last = GetLastError();
 
- 	if (last) {
 
- 		sprintf(ret, "code: %i", last);
 
- 		SetLastError(0);
 
- 		return ret;
 
- 	}
 
- 	return NULL;
 
- }
 
- #endif
 
- /*----------------------------------------------------------------------------*/
 
- /* 																			  */
 
- /* STDLIB extensions													 	  */
 
- /* 																			  */
 
- /*----------------------------------------------------------------------------*/
 
- #ifdef WIN32
 
- /*---------------------------------------------------------------------------*/
 
- char *strcasestr(const char *haystack, const char *needle) {
 
- 	size_t length_needle;
 
- 	size_t length_haystack;
 
- 	size_t i;
 
- 	if (!haystack || !needle)
 
- 		return NULL;
 
- 	length_needle = strlen(needle);
 
- 	length_haystack = strlen(haystack);
 
- 	if (length_haystack < length_needle) return NULL;
 
- 	length_haystack -= length_needle - 1;
 
- 	for (i = 0; i < length_haystack; i++)
 
- 	{
 
- 		size_t j;
 
- 		for (j = 0; j < length_needle; j++)
 
- 		{
 
- 			unsigned char c1;
 
- 			unsigned char c2;
 
- 			c1 = haystack[i+j];
 
- 			c2 = needle[j];
 
- 			if (toupper(c1) != toupper(c2))
 
- 				goto next;
 
- 		}
 
- 		return (char *) haystack + i;
 
- 		next:
 
- 			;
 
- 	}
 
- 	return NULL;
 
- }
 
- /*---------------------------------------------------------------------------*/
 
- char* strsep(char** stringp, const char* delim)
 
- {
 
-   char* start = *stringp;
 
-   char* p;
 
-   p = (start != NULL) ? strpbrk(start, delim) : NULL;
 
-   if (p == NULL)  {
 
- 	*stringp = NULL;
 
-   } else {
 
- 	*p = '\0';
 
- 	*stringp = p + 1;
 
-   }
 
-   return start;
 
- }
 
- /*---------------------------------------------------------------------------*/
 
- char *strndup(const char *s, size_t n) {
 
- 	char *p = malloc(n + 1);
 
- 	strncpy(p, s, n);
 
- 	p[n] = '\0';
 
- 	return p;
 
- }
 
- #endif
 
- /*----------------------------------------------------------------------------*/
 
- char* strextract(char *s1, char *beg, char *end)
 
- {
 
- 	char *p1, *p2, *res;
 
- 	p1 = strcasestr(s1, beg);
 
- 	if (!p1) return NULL;
 
- 	p1 += strlen(beg);
 
- 	p2 = strcasestr(p1, end);
 
- 	if (!p2) return strdup(p1);
 
- 	res = malloc(p2 - p1 + 1);
 
- 	memcpy(res, p1, p2 - p1);
 
- 	res[p2 - p1] = '\0';
 
- 	return res;
 
- }
 
- #ifdef WIN32
 
- /*----------------------------------------------------------------------------*/
 
- int asprintf(char **strp, const char *fmt, ...)
 
- {
 
- 	va_list args, cp;
 
- 	int len, ret = 0;
 
- 	va_start(args, fmt);
 
- 	len = vsnprintf(NULL, 0, fmt, args);
 
- 	*strp = malloc(len + 1);
 
- 	if (*strp) ret = vsprintf(*strp, fmt, args);
 
- 	va_end(args);
 
- 	return ret;
 
- }
 
- #endif
 
- /*---------------------------------------------------------------------------*/
 
- static char *ltrim(char *s)
 
- {
 
- 	while(isspace((int) *s)) s++;
 
- 	return s;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- /* 																			  */
 
- /* HTTP management														 	  */
 
- /* 																			  */
 
- /*----------------------------------------------------------------------------*/
 
- /*----------------------------------------------------------------------------*/
 
- bool http_parse(int sock, char *method, key_data_t *rkd, char **body, int *len)
 
- {
 
- 	char line[256], *dp;
 
- 	unsigned j;
 
- 	int i, timeout = 100;
 
- 	rkd[0].key = NULL;
 
- 	if ((i = read_line(sock, line, sizeof(line), timeout)) <= 0) {
 
- 		if (i < 0) {
 
- 			LOG_ERROR("cannot read method", NULL);
 
- 		}
 
- 		return false;
 
- 	}
 
- 	if (!sscanf(line, "%s", method)) {
 
- 		LOG_ERROR("missing method", NULL);
 
- 		return false;
 
- 	}
 
- 	i = *len = 0;
 
- 	while (read_line(sock, line, sizeof(line), timeout) > 0) {
 
- 		LOG_SDEBUG("sock: %u, received %s", line);
 
- 		// line folding should be deprecated
 
- 		if (i && rkd[i].key && (line[0] == ' ' || line[0] == '\t')) {
 
- 			for(j = 0; j < strlen(line); j++) if (line[j] != ' ' && line[j] != '\t') break;
 
- 			rkd[i].data = realloc(rkd[i].data, strlen(rkd[i].data) + strlen(line + j) + 1);
 
- 			strcat(rkd[i].data, line + j);
 
- 			continue;
 
- 		}
 
- 		dp = strstr(line,":");
 
- 		if (!dp){
 
- 			LOG_ERROR("Request failed, bad header", NULL);
 
- 			kd_free(rkd);
 
- 			return false;
 
- 		}
 
- 		*dp = 0;
 
- 		rkd[i].key = strdup(line);
 
- 		rkd[i].data = strdup(ltrim(dp + 1));
 
- 		if (!strcasecmp(rkd[i].key, "Content-Length")) *len = atol(rkd[i].data);
 
- 		i++;
 
- 		rkd[i].key = NULL;
 
- 	}
 
- 	if (*len) {
 
- 		int size = 0;
 
- 		*body = malloc(*len + 1);
 
- 		while (*body && size < *len) {
 
- 			int bytes = recv(sock, *body + size, *len - size, 0);
 
- 			if (bytes <= 0) break;
 
- 			size += bytes;
 
- 		}
 
- 		(*body)[*len] = '\0';
 
- 		if (!*body || size != *len) {
 
- 			LOG_ERROR("content length receive error %d %d", *len, size);
 
- 		}
 
- 	}
 
- 	return true;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- static int read_line(int fd, char *line, int maxlen, int timeout)
 
- {
 
- 	int i,rval;
 
- 	int count=0;
 
- 	struct pollfd pfds;
 
- 	char ch;
 
- 	*line = 0;
 
- 	pfds.fd = fd;
 
- 	pfds.events = POLLIN;
 
- 	for(i = 0; i < maxlen; i++){
 
- 		if (poll(&pfds, 1, timeout)) rval=recv(fd, &ch, 1, 0);
 
- 		else return 0;
 
- 		if (rval == -1) {
 
- 			if (errno == EAGAIN) return 0;
 
- 			LOG_ERROR("fd: %d read error: %s", fd, strerror(errno));
 
- 			return -1;
 
- 		}
 
- 		if (rval == 0) {
 
- 			LOG_INFO("disconnected on the other end %u", fd);
 
- 			return 0;
 
- 		}
 
- 		if (ch == '\n') {
 
- 			*line=0;
 
- 			return count;
 
- 		}
 
- 		if (ch=='\r') continue;
 
- 		*line++=ch;
 
- 		count++;
 
- 		if (count >= maxlen-1) break;
 
- 	}
 
- 	*line = 0;
 
- 	return count;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- char *http_send(int sock, char *method, key_data_t *rkd)
 
- {
 
- 	unsigned sent, len;
 
- 	char *resp = kd_dump(rkd);
 
- 	char *data = malloc(strlen(method) + 2 + strlen(resp) + 2 + 1);
 
- 	len = sprintf(data, "%s\r\n%s\r\n", method, resp);
 
- 	NFREE(resp);
 
- 	sent = send(sock, data, len, 0);
 
- 	if (sent != len) {
 
- 		LOG_ERROR("HTTP send() error:%s %u (strlen=%u)", data, sent, len);
 
- 		NFREE(data);
 
- 	}
 
- 	return data;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- char *kd_lookup(key_data_t *kd, char *key)
 
- {
 
- 	int i = 0;
 
- 	while (kd && kd[i].key){
 
- 		if (!strcasecmp(kd[i].key, key)) return kd[i].data;
 
- 		i++;
 
- 	}
 
- 	return NULL;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- bool kd_add(key_data_t *kd, char *key, char *data)
 
- {
 
- 	int i = 0;
 
- 	while (kd && kd[i].key) i++;
 
- 	kd[i].key = strdup(key);
 
- 	kd[i].data = strdup(data);
 
- 	kd[i+1].key = NULL;
 
- 	return NULL;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- void kd_free(key_data_t *kd)
 
- {
 
- 	int i = 0;
 
- 	while (kd && kd[i].key){
 
- 		free(kd[i].key);
 
- 		if (kd[i].data) free(kd[i].data);
 
- 		i++;
 
- 	}
 
- 	kd[0].key = NULL;
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- char *kd_dump(key_data_t *kd)
 
- {
 
- 	int i = 0;
 
- 	int pos = 0, size = 0;
 
- 	char *str = NULL;
 
- 	if (!kd || !kd[0].key) return strdup("\r\n");
 
- 	while (kd && kd[i].key) {
 
- 		char *buf;
 
- 		int len;
 
- 		len = asprintf(&buf, "%s: %s\r\n", kd[i].key, kd[i].data);
 
- 		while (pos + len >= size) {
 
- 			void *p = realloc(str, size + 1024);
 
- 			size += 1024;
 
- 			if (!p) {
 
- 				free(str);
 
- 				return NULL;
 
- 			}
 
- 			str = p;
 
- 		}
 
- 		memcpy(str + pos, buf, len);
 
- 		pos += len;
 
- 		free(buf);
 
- 		i++;
 
- 	}
 
- 	str[pos] = '\0';
 
- 	return str;
 
- }
 
- /*--------------------------------------------------------------------------*/
 
- void free_metadata(struct metadata_s *metadata)
 
- {
 
- 	NFREE(metadata->artist);
 
- 	NFREE(metadata->album);
 
- 	NFREE(metadata->title);
 
- 	NFREE(metadata->genre);
 
- 	NFREE(metadata->path);
 
- 	NFREE(metadata->artwork);
 
- 	NFREE(metadata->remote_title);
 
- }
 
- /*----------------------------------------------------------------------------*/
 
- int _fprintf(FILE *file, ...)
 
- {
 
- 	va_list args;
 
- 	char *fmt;
 
- 	int n;
 
- 	va_start(args, file);
 
- 	fmt = va_arg(args, char*);
 
- 	n = vfprintf(file, fmt, args);
 
- 	va_end(args);
 
- 	return n;
 
- }
 
 
  |