Beispiel #1
0
struct client_cache_s *
SearchClientCache(struct in_addr addr, int quiet)
{
	int i;

	for (i = 0; i < CLIENT_CACHE_SLOTS; i++)
	{
		if (clients[i].addr.s_addr == addr.s_addr)
		{
			/* Invalidate this client cache if it's older than 1 hour */
			if ((time(NULL) - clients[i].age) > 3600)
			{
				unsigned char mac[6];
				if (get_remote_mac(addr, mac) == 0 &&
				    memcmp(mac, clients[i].mac, 6) == 0)
				{
					/* Same MAC as last time when we were able to identify the client,
					 * so extend the timeout by another hour. */
					clients[i].age = time(NULL);
				}
				else
				{
					memset(&clients[i], 0, sizeof(struct client_cache_s));
					return NULL;
				}
			}
			if (!quiet)
				DPRINTF(E_DEBUG, L_HTTP, "Client found in cache. [%s/entry %d]\n",
					clients[i].type->name, i);
			return &clients[i];
		}
	}

	return NULL;
}
Beispiel #2
0
struct client_cache_s *
AddClientCache(struct in_addr addr, int type)
{
	int i;

	for (i = 0; i < CLIENT_CACHE_SLOTS; i++)
	{
		if (clients[i].addr.s_addr)
			continue;
		get_remote_mac(addr, clients[i].mac);
		clients[i].addr = addr;
		clients[i].type = &client_types[type];
		clients[i].age = time(NULL);
		DPRINTF(E_DEBUG, L_HTTP, "Added client [%s/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n",
					client_types[type].name, inet_ntoa(clients[i].addr),
					clients[i].mac[0], clients[i].mac[1], clients[i].mac[2],
					clients[i].mac[3], clients[i].mac[4], clients[i].mac[5], i);
		return &clients[i];
	}

	return NULL;
}
Beispiel #3
0
void
ParseUPnPClient(char *location)
{
	char buf[8192];
	struct sockaddr_in dest;
	int s, n, do_headers = 0, nread = 0;
	struct timeval tv;
	char *addr, *path, *port_str;
	long port = 80;
	char *off = NULL, *p;
	int content_len = sizeof(buf);
	struct NameValueParserData xml;
	int client;
	enum client_types type = 0;
	uint32_t flags = 0;
	char *model, *serial, *name;

	if (strncmp(location, "http://", 7) != 0)
		return;
	path = location + 7;
	port_str = strsep(&path, "/");
	if (!path)
		return;
	addr = strsep(&port_str, ":");
	if (port_str)
	{
		port = strtol(port_str, NULL, 10);
		if (!port)
			port = 80;
	}

	memset(&dest, '\0', sizeof(dest));
	if (!inet_aton(addr, &dest.sin_addr))
		return;
	/* Check if the client is already in cache */
	dest.sin_family = AF_INET;
	dest.sin_port = htons(port);

	s = socket(PF_INET, SOCK_STREAM, 0);
	if( s < 0 )
		return;

	tv.tv_sec = 0;
	tv.tv_usec = 500000;
	setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
	setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv));

	if( connect(s, (struct sockaddr*)&dest, sizeof(struct sockaddr_in)) < 0 )
		goto close;

	n = snprintf(buf, sizeof(buf), "GET /%s HTTP/1.0\r\n"
	                               "HOST: %s:%ld\r\n\r\n",
	                               path, addr, port);
	if( write(s, buf, n) < 1 )
		goto close;

	while( (n = read(s, buf+nread, sizeof(buf)-nread-1)) > 0 )
	{
		nread += n;
		buf[nread] = '\0';
		n = nread;
		p = buf;

		while( !off && n-- > 0 )
		{
			if(p[0]=='\r' && p[1]=='\n' && p[2]=='\r' && p[3]=='\n')
			{
				off = p + 4;
				do_headers = 1;
			}
			p++;
		}
		if( !off )
			continue;

		if( do_headers )
		{
			p = buf;
			if( strncmp(p, "HTTP/", 5) != 0 )
				goto close;
			while(*p != ' ' && *p != '\t') p++;
			/* If we don't get a 200 status, ignore it */
			if( strtol(p, NULL, 10) != 200 )
				goto close;
			if( (p = strcasestr(p, "Content-Length:")) )
				content_len = strtol(p+15, NULL, 10);
			do_headers = 0;
		}
		if( buf + nread - off >= content_len )
			break;
	}
close:
	close(s);
	if( !off )
		return;
	nread -= off - buf;
	ParseNameValue(off, nread, &xml);
	model = GetValueFromNameValueList(&xml, "modelName");
	serial = GetValueFromNameValueList(&xml, "serialNumber");
	name = GetValueFromNameValueList(&xml, "friendlyName");
	if( model )
	{
		DPRINTF(E_DEBUG, L_SSDP, "Model: %s\n", model);
		if( strstr(model, "Roku SoundBridge") )
		{
			type = ERokuSoundBridge;
			flags |= FLAG_MS_PFS;
			flags |= FLAG_AUDIO_ONLY;
			flags |= FLAG_MIME_WAV_WAV;
		}
		else if( strcmp(model, "Samsung DTV DMR") == 0 && serial )
		{
			DPRINTF(E_DEBUG, L_SSDP, "Serial: %s\n", serial);
			/* The Series B I saw was 20081224DMR.  Series A should be older than that. */
			if( atoi(serial) > 20081200 )
			{
				type = ESamsungSeriesB;
				flags |= FLAG_SAMSUNG;
				flags |= FLAG_DLNA;
				flags |= FLAG_NO_RESIZE;
			}
		}
		else
		{
			if( name && (strcmp(name, "marantz DMP") == 0) )
			{
				type = EMarantzDMP;
				flags |= FLAG_DLNA;
				flags |= FLAG_MIME_WAV_WAV;
			}
		}
	}
	ClearNameValueList(&xml);
	if( !type )
		return;
	/* Add this client to the cache if it's not there already. */
	client = SearchClientCache(dest.sin_addr, 1);
	if( client < 0 )
	{
		for( client=0; client<CLIENT_CACHE_SLOTS; client++ )
		{
			if( clients[client].addr.s_addr )
				continue;
			get_remote_mac(dest.sin_addr, clients[client].mac);
			clients[client].addr = dest.sin_addr;
			DPRINTF(E_DEBUG, L_SSDP, "Added client [%d/%s/%02X:%02X:%02X:%02X:%02X:%02X] to cache slot %d.\n",
			                         type, inet_ntoa(clients[client].addr),
			                         clients[client].mac[0], clients[client].mac[1], clients[client].mac[2],
			                         clients[client].mac[3], clients[client].mac[4], clients[client].mac[5], client);
			break;
		}
	}
	clients[client].type = type;
	clients[client].flags = flags;
	clients[client].age = time(NULL);
}