Ejemplo n.º 1
0
void
ProcessSSDPData(int s, const char *bufr, int n,
                const struct sockaddr * sender, unsigned short port) {
	int i, l;
	struct lan_addr_s * lan_addr = NULL;
	const char * st = NULL;
	int st_len = 0;
	char sender_str[64];
	const char * announced_host = NULL;
#ifdef UPNP_STRICT
	char announced_host_buf[64];
#endif

	/* get the string representation of the sender address */
	sockaddr_to_string(sender, sender_str, sizeof(sender_str));

	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		i = 0;
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while((*st == ' ' || *st == '\t') && (st < bufr + n))
					st++;
				while(st[st_len]!='\r' && st[st_len]!='\n'
				     && (st + st_len < bufr + n))
					st_len++;
				/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
				/*j = 0;*/
				/*while(bufr[i+j]!='\r') j++;*/
				/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
			}
		}
		/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s",
	           sender_str );*/
		if(st && (st_len > 0))
		{
			/* TODO : doesnt answer at once but wait for a random time */
			syslog(LOG_INFO, "SSDP M-SEARCH from %s ST: %.*s",
			       sender_str, st_len, st);
			/* find in which sub network the client is */
			if(sender->sa_family == AF_INET)
			{
				for(lan_addr = lan_addrs.lh_first;
				    lan_addr != NULL;
				    lan_addr = lan_addr->list.le_next)
				{
					if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
					   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
						break;
				}
				if (lan_addr == NULL)
				{
					syslog(LOG_ERR, "Can't find in which sub network the client is");
					return;
				}
				announced_host = lan_addr->str;
			}
#ifdef ENABLE_IPV6
			else
			{
				/* IPv6 address with brackets */
#ifdef UPNP_STRICT
				struct in6_addr addr6;
				size_t addr6_len = sizeof(addr6);
				/* retrieve the IPv6 address which
				 * will be used locally to reach sender */
				memset(&addr6, 0, sizeof(addr6));
				if(get_src_for_route_to (sender, &addr6, &addr6_len) < 0) {
					syslog(LOG_WARNING, "get_src_for_route_to() failed, using %s", ipv6_addr_for_http_with_brackets);
					announced_host = ipv6_addr_for_http_with_brackets;
				} else {
					if(inet_ntop(AF_INET6, &addr6,
					             announced_host_buf+1,
					             sizeof(announced_host_buf) - 2)) {
						announced_host_buf[0] = '[';
						i = strlen(announced_host_buf);
						if(i < (int)sizeof(announced_host_buf) - 1) {
							announced_host_buf[i] = ']';
							announced_host_buf[i+1] = '\0';
						} else {
							syslog(LOG_NOTICE, "cannot suffix %s with ']'",
							       announced_host_buf);
						}
						announced_host = announced_host_buf;
					} else {
						syslog(LOG_NOTICE, "inet_ntop() failed %m");
						announced_host = ipv6_addr_for_http_with_brackets;
					}
				}
#else
				announced_host = ipv6_addr_for_http_with_brackets;
#endif
			}
#endif
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i]; i++)
			{
				l = (int)strlen(known_service_types[i]);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
				{
					syslog(LOG_INFO, "Single search found");
					SendSSDPAnnounce2(s, sender,
					                  st, st_len, "",
					                  announced_host, port);
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
				syslog(LOG_INFO, "ssdp:all found");
				for(i=0; known_service_types[i]; i++)
				{
					l = (int)strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sender,
					                  known_service_types[i], l, i==0?"":"1",
					                  announced_host, port);
				}
			}
			/* responds to request by UUID value */
			l = (int)strlen(uuidvalue);
			if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
			{
				syslog(LOG_INFO, "ssdp:uuid found");
				SendSSDPAnnounce2(s, sender, st, st_len, "",
				                  announced_host, port);
			}
		}
		else
		{
			syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s", sender_str);
		}
	}
	else
	{
		syslog(LOG_NOTICE, "Unknown udp packet received from %s", sender_str);
	}
}
Ejemplo n.º 2
0
void ProcessSSDPData(int s, char *bufr, struct sockaddr_in sendername, int n, unsigned short port) {
	int i, l;
	int lan_addr_index = 0;
	char * st = 0;
	int st_len = 0;


	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		i = 0;
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while((*st == ' ' || *st == '\t') && (st < bufr + n))
					st++;
				while(st[st_len]!='\r' && st[st_len]!='\n'
				     && (st + st_len < bufr + n))
					st_len++;
				/*syslog(LOG_INFO, "ST: %.*s", st_len, st);*/
				/*j = 0;*/
				/*while(bufr[i+j]!='\r') j++;*/
				/*syslog(LOG_INFO, "%.*s", j, bufr+i);*/
			}
		}
		/*syslog(LOG_INFO, "SSDP M-SEARCH packet received from %s:%d",
	           inet_ntoa(sendername.sin_addr),
	           ntohs(sendername.sin_port) );*/
		if(st && (st_len > 0))
		{
			/* TODO : doesnt answer at once but wait for a random time */
			syslog(LOG_INFO, "SSDP M-SEARCH from %s:%d ST: %.*s",
	        	   inet_ntoa(sendername.sin_addr),
	           	   ntohs(sendername.sin_port),
				   st_len, st);
			/* find in which sub network the client is */
			for(i = 0; i<n_lan_addr; i++)
			{
				if( (sendername.sin_addr.s_addr & lan_addr[i].mask.s_addr)
				   == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr))
				{
					lan_addr_index = i;
					break;
				}
			}
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i]; i++)
			{
				l = (int)strlen(known_service_types[i]);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
				{
					syslog(LOG_INFO, "Single search found");
					SendSSDPAnnounce2(s, sendername,
					                  st, st_len, "",
					                  lan_addr[lan_addr_index].str, port);
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
				syslog(LOG_INFO, "ssdp:all found");
				for(i=0; known_service_types[i]; i++)
				{
					l = (int)strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sendername,
					                  known_service_types[i], l, i==0?"":"1",
					                  lan_addr[lan_addr_index].str, port);
				}
			}
			/* responds to request by UUID value */
			l = (int)strlen(uuidvalue);
			if(l==st_len && (0 == memcmp(st, uuidvalue, l)))
			{
				syslog(LOG_INFO, "ssdp:uuid found");
				SendSSDPAnnounce2(s, sendername, st, st_len, "",
				                  lan_addr[lan_addr_index].str, port);
			}
		}
		else
		{
			syslog(LOG_INFO, "Invalid SSDP M-SEARCH from %s:%d",
	        	   inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port));
		}
	}
	else
	{
		syslog(LOG_NOTICE, "Unknown udp packet received from %s:%d",
		       inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port));
	}
}
Ejemplo n.º 3
0
void
ProcessSSDPData(int s, const char *bufr, int n,
                const struct sockaddr * sender, unsigned short port) {
	int i, l;
	struct lan_addr_s * lan_addr = NULL;
	const char * st = NULL;
	int st_len = 0;
	char sender_str[64];
	const char * announced_host = NULL;
    /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
    char has_mx = 0;
    /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */

	/* get the string representation of the sender address */
	sockaddr_to_string(sender, sender_str, sizeof(sender_str));

	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		i = 0;
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
            if((i < n - 3) && (0 == strncasecmp(bufr+i, "mx:", 3)))
            {
                has_mx = 1;
            }
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
			if((i < n - 3) && (strncasecmp(bufr+i, "st:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while((*st == ' ' || *st == '\t') && (st < bufr + n))
					st++;
				while(st[st_len]!='\r' && st[st_len]!='\n'
				     && (st + st_len < bufr + n))
					st_len++;
			}
		}
        /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
        if(0 == has_mx)
        {
            NP_UPNP_DEBUG("M-SEARCH, NO MX: RETURN.\n");
            return;
        }
        /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
		if(st && (st_len > 0))
		{
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
            if(strncmp("upnp:rootdevice", st, st_len) 
                    && strncmp("ssdp:all", st, st_len) 
                    && strncmp("urn:schemas-upnp-org:device:InternetGatewayDevice:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:device:WANConnectionDevice:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:device:WANDevice:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:WANCommonInterfaceConfig:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:WANIPConnection:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:Layer3Forwarding:1", st, st_len)
                    && strncmp("urn:schemas-upnp-org:service:WANIPv6FirewallControl:1", st, st_len)
                    && strncmp(uuidvalue_root, st, st_len)
                    && strncmp(uuidvalue_wan, st, st_len)
                    && strncmp(uuidvalue_wan_conn, st, st_len)
              )
            {
                NP_UPNP_DEBUG("ST IS NOT CORRECT, RETURN.\n");
                return;
            }
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
			/* TODO : doesnt answer at once but wait for a random time */
			NP_UPNP_DEBUG("SSDP M-SEARCH from %s ST: %.*s\n",
			       sender_str, st_len, st);
			/* find in which sub network the client is */
			if(sender->sa_family == AF_INET)
			{
				for(lan_addr = lan_addrs.lh_first;
				    lan_addr != NULL;
				    lan_addr = lan_addr->list.le_next)
				{
					if( (((const struct sockaddr_in *)sender)->sin_addr.s_addr & lan_addr->mask.s_addr)
				   == (lan_addr->addr.s_addr & lan_addr->mask.s_addr))
						break;
				}
				if (lan_addr == NULL)
				{
					NP_UPNP_ERROR("Can't find in which sub network the client is\n");
					return;
				}
				announced_host = lan_addr->str;
			}
#ifdef ENABLE_IPV6
			else
			{
				/* IPv6 address with brackets */
				announced_host = ipv6_addr_for_http_with_brackets;
			}
#endif
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i]; i++)
			{
				l = (int)strlen(known_service_types[i]);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
				{
					NP_UPNP_DEBUG("Single search found\n");
					SendSSDPAnnounce2(s, sender,
					                  st, st_len, "",
                                      /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 modified */
					                  announced_host, port, i);
                                      /* END   2082304944 zhoujianchun 00203875 2012.8.29 modified */
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
				NP_UPNP_DEBUG("ssdp:all found\n");
				for(i=0; known_service_types[i]; i++)
				{
					l = (int)strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sender,
                                      /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 modified */
					                  known_service_types[i], l, i==0 ? "" : "1",
					                  announced_host, port, i);
                                      /* END   2082304944 zhoujianchun 00203875 2012.8.29 modified */
				}
                /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
                for(i = 0; i < DEV_NUM; i++)
                {
				    SendSSDPAnnounce2(s, sender, uuid_value[i], st_len, "", announced_host, port, -1);
                }
                /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
			}
			/* responds to request by UUID value */
			l = (int)strlen(uuidvalue);
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 modified */
			if(l==st_len && 0 == memcmp(st, uuidvalue_root, l)) 
			{
				NP_UPNP_DEBUG("ssdp:uuid found\n");
				SendSSDPAnnounce2(s, sender, uuidvalue_root, st_len, "",
				                  announced_host, port, -1);
			}
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 modified */
            /* BEGIN 2082304944 zhoujianchun 00203875 2012.8.29 added */
            else if(l==st_len && 0 == memcmp(st, uuidvalue_wan, l))
            {
				NP_UPNP_DEBUG("ssdp:uuid found\n");
				SendSSDPAnnounce2(s, sender, uuidvalue_wan, st_len, "", announced_host, port, -1);
            }
            else if(l==st_len && 0 == memcmp(st, uuidvalue_wan_conn, l))
            {
				NP_UPNP_DEBUG("ssdp:uuid found\n");
				SendSSDPAnnounce2(s, sender, uuidvalue_wan_conn, st_len, "", announced_host, port, -1);
            }
            /* END   2082304944 zhoujianchun 00203875 2012.8.29 added */
		}
		else
		{
			NP_UPNP_DEBUG("Invalid SSDP M-SEARCH from %s\n", sender_str);
		}
	}
	else
	{
		NP_UPNP_DEBUG("Unknown udp packet received from %s\n", sender_str);
	}
}
Ejemplo n.º 4
0
/* ProcessSSDPRequest()
 * process SSDP M-SEARCH requests and responds to them */
void
ProcessSSDPRequest(int s, unsigned short port)
{
	int n;
	char bufr[1500];
	socklen_t len_r;
	struct sockaddr_in sendername;
	int i;
	char *st = NULL, *mx = NULL, *man = NULL, *mx_end = NULL;
	int man_len = 0;
	len_r = sizeof(struct sockaddr_in);

	n = recvfrom(s, bufr, sizeof(bufr)-1, 0,
	             (struct sockaddr *)&sendername, &len_r);
	if (n < 0)
	{
		DPRINTF(E_ERROR, L_SSDP, "recvfrom(udp): %s\n", strerror(errno));
		return;
	}
	bufr[n] = '\0';
	n -= 2;

	if (memcmp(bufr, "NOTIFY", 6) == 0)
	{
		char *loc = NULL, *srv = NULL, *nts = NULL, *nt = NULL;
		int loc_len = 0;
		//DEBUG DPRINTF(E_DEBUG, L_SSDP, "Received SSDP notify:\n%.*s", n, bufr);
		for (i = 0; i < n; i++)
		{
			if( bufr[i] == '*' )
				break;
		}
		if (strcasestrc(bufr+i, "HTTP/1.1", '\r') == NULL)
			return;
		while (i < n)
		{
			while ((i < n) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if (strncasecmp(bufr+i, "SERVER:", 7) == 0)
			{
				srv = bufr+i+7;
				while (*srv == ' ' || *srv == '\t')
					srv++;
			}
			else if (strncasecmp(bufr+i, "LOCATION:", 9) == 0)
			{
				loc = bufr+i+9;
				while (*loc == ' ' || *loc == '\t')
					loc++;
				while (loc[loc_len]!='\r' && loc[loc_len]!='\n')
					loc_len++;
			}
			else if (strncasecmp(bufr+i, "NTS:", 4) == 0)
			{
				nts = bufr+i+4;
				while (*nts == ' ' || *nts == '\t')
					nts++;
			}
			else if (strncasecmp(bufr+i, "NT:", 3) == 0)
			{
				nt = bufr+i+3;
				while(*nt == ' ' || *nt == '\t')
					nt++;
			}
		}
		if (!loc || !srv || !nt || !nts || (strncmp(nts, "ssdp:alive", 10) != 0) ||
		    (strncmp(nt, "urn:schemas-upnp-org:device:MediaRenderer", 41) != 0))
			return;
		loc[loc_len] = '\0';
		if ((strncmp(srv, "Allegro-Software-RomPlug", 24) == 0) || /* Roku */
		    (strstr(loc, "SamsungMRDesc.xml") != NULL) || /* Samsung TV */
		    (strstrc(srv, "DigiOn DiXiM", '\r') != NULL)) /* Marantz Receiver */
		{
			/* Check if the client is already in cache */
			i = SearchClientCache(sendername.sin_addr, 1);
			if (i >= 0)
			{
				if (clients[i].type < EStandardDLNA150 &&
				    clients[i].type != ESamsungSeriesA)
				{
					clients[i].age = time(NULL);
					return;
				}
			}
			ParseUPnPClient(loc);
		}
	}
	else if (memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		int st_len = 0, mx_len = 0, mx_val = 0;
		//DPRINTF(E_DEBUG, L_SSDP, "Received SSDP request:\n%.*s\n", n, bufr);
		for (i = 0; i < n; i++)
		{
			if (bufr[i] == '*')
				break;
		}
		if (strcasestrc(bufr+i, "HTTP/1.1", '\r') == NULL)
			return;
		while (i < n)
		{
			while ((i < n) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if (strncasecmp(bufr+i, "ST:", 3) == 0)
			{
				st = bufr+i+3;
				st_len = 0;
				while (*st == ' ' || *st == '\t')
					st++;
				while (st[st_len]!='\r' && st[st_len]!='\n')
					st_len++;
			}
			else if (strncasecmp(bufr+i, "MX:", 3) == 0)
			{
				mx = bufr+i+3;
				mx_len = 0;
				while (*mx == ' ' || *mx == '\t')
					mx++;
				while (mx[mx_len]!='\r' && mx[mx_len]!='\n')
					mx_len++;
        			mx_val = strtol(mx, &mx_end, 10);
			}
			else if (strncasecmp(bufr+i, "MAN:", 4) == 0)
			{
				man = bufr+i+4;
				man_len = 0;
				while (*man == ' ' || *man == '\t')
					man++;
				while (man[man_len]!='\r' && man[man_len]!='\n')
					man_len++;
			}
		}
		/*DPRINTF(E_INFO, L_SSDP, "SSDP M-SEARCH packet received from %s:%d\n",
	           inet_ntoa(sendername.sin_addr),
	           ntohs(sendername.sin_port) );*/
		if (GETFLAG(DLNA_STRICT_MASK) && (ntohs(sendername.sin_port) <= 1024 || ntohs(sendername.sin_port) == 1900))
		{
			DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad source port %d]\n",
				inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port));
		}
		else if (!man || (strncmp(man, "\"ssdp:discover\"", 15) != 0))
		{
			DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad %s header '%.*s']\n",
				inet_ntoa(sendername.sin_addr), "MAN", man_len, man);
		}
		else if (!mx || mx == mx_end || mx_val < 0)
		{
			DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad %s header '%.*s']\n",
				inet_ntoa(sendername.sin_addr), "MX", mx_len, mx);
		}
		else if (st && (st_len > 0))
		{
			int l;
			int lan_addr_index = 0;
			/* find in which sub network the client is */
			for (i = 0; i < n_lan_addr; i++)
			{
				if((sendername.sin_addr.s_addr & lan_addr[i].mask.s_addr) ==
				   (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr))
				{
					lan_addr_index = i;
					break;
				}
			}
			if (n_lan_addr == i)
			{
				DPRINTF(E_DEBUG, L_SSDP, "Ignoring SSDP M-SEARCH on other interface [%s]\n",
					inet_ntoa(sendername.sin_addr));
				return;
			}
			DPRINTF(E_INFO, L_SSDP, "SSDP M-SEARCH from %s:%d ST: %.*s, MX: %.*s, MAN: %.*s\n",
				inet_ntoa(sendername.sin_addr),
				ntohs(sendername.sin_port),
				st_len, st, mx_len, mx, man_len, man);
			/* Responds to request with a device as ST header */
			for (i = 0; known_service_types[i]; i++)
			{
				l = strlen(known_service_types[i]);
				if ((l <= st_len) && (memcmp(st, known_service_types[i], l) == 0))
				{
					if (st_len != l)
					{
						/* Check version number - must always be 1 currently. */
						if ((st[l-1] == ':') && (st[l] == '1'))
							l++;
						while (l < st_len)
						{
							if (!isspace(st[l]))
							{
								DPRINTF(E_DEBUG, L_SSDP, "Ignoring SSDP M-SEARCH with bad extra data [%s]\n",
									inet_ntoa(sendername.sin_addr));
								break;
							}
							l++;
						}
						if (l != st_len)
							break;
					}
					_usleep(random()>>20);
					SendSSDPAnnounce2(s, sendername, i,
					                  lan_addr[lan_addr_index].str, port);
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if ((st_len == 8) && (memcmp(st, "ssdp:all", 8) == 0))
			{
				for (i=0; known_service_types[i]; i++)
				{
					l = strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sendername, i,
					                  lan_addr[lan_addr_index].str, port);
				}
			}
		}
Ejemplo n.º 5
0
/* ProcessSSDPRequest()
 * process SSDP M-SEARCH requests and responds to them */
void
ProcessSSDPRequest(int s, unsigned short port)
/*ProcessSSDPRequest(int s, struct lan_addr_s * lan_addr, int n_lan_addr,
                   unsigned short port)*/
{
	int n;
	char bufr[1500];
	socklen_t len_r;
	struct sockaddr_in sendername;
	int i, l;
	int lan_addr_index = 0;
	char * st = NULL, * mx = NULL, * man = NULL, * mx_end = NULL;
	int st_len = 0, mx_len = 0, man_len = 0, mx_val = 0;
	len_r = sizeof(struct sockaddr_in);

	n = recvfrom(s, bufr, sizeof(bufr), 0,
	             (struct sockaddr *)&sendername, &len_r);
	if(n < 0)
	{
		DPRINTF(E_ERROR, L_SSDP, "recvfrom(udp): %s\n", strerror(errno));
		return;
	}

	if(memcmp(bufr, "NOTIFY", 6) == 0)
	{
		/* ignore NOTIFY packets. We could log the sender and device type */
		return;
	}
	else if(memcmp(bufr, "M-SEARCH", 8) == 0)
	{
		//DEBUG DPRINTF(E_DEBUG, L_SSDP, "Received SSDP request:\n%.*s", n, bufr);
		for(i=0; i < n; i++)
		{
			if( bufr[i] == '*' )
				break;
		}
		if( !strcasestr(bufr+i, "HTTP/1.1") )
		{
			return;
		}
		while(i < n)
		{
			while((i < n - 1) && (bufr[i] != '\r' || bufr[i+1] != '\n'))
				i++;
			i += 2;
			if((i < n - 3) && (strncasecmp(bufr+i, "ST:", 3) == 0))
			{
				st = bufr+i+3;
				st_len = 0;
				while(*st == ' ' || *st == '\t') st++;
				while(st[st_len]!='\r' && st[st_len]!='\n') st_len++;
			}
			else if(strncasecmp(bufr+i, "MX:", 3) == 0)
			{
				mx = bufr+i+3;
				mx_len = 0;
				while(*mx == ' ' || *mx == '\t') mx++;
				while(mx[mx_len]!='\r' && mx[mx_len]!='\n') mx_len++;
        			mx_val = strtol(mx, &mx_end, 10);
			}
			else if(strncasecmp(bufr+i, "MAN:", 4) == 0)
			{
				man = bufr+i+4;
				man_len = 0;
				while(*man == ' ' || *man == '\t') man++;
				while(man[man_len]!='\r' && man[man_len]!='\n') man_len++;
			}
		}
		/*DPRINTF(E_INFO, L_SSDP, "SSDP M-SEARCH packet received from %s:%d\n",
	           inet_ntoa(sendername.sin_addr),
	           ntohs(sendername.sin_port) );*/
		if( ntohs(sendername.sin_port) <= 1024 || ntohs(sendername.sin_port) == 1900 )
		{
			DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad source port %d]\n",
			   inet_ntoa(sendername.sin_addr), ntohs(sendername.sin_port));
		}
		else if( !man || (strncmp(man, "\"ssdp:discover\"", 15) != 0) )
		{
			DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad MAN header %.*s]\n",
			   inet_ntoa(sendername.sin_addr), man_len, man);
		}
		else if( !mx || mx == mx_end || mx_val < 0 ) {
			DPRINTF(E_INFO, L_SSDP, "WARNING: Ignoring invalid SSDP M-SEARCH from %s [bad MX header %.*s]\n",
			   inet_ntoa(sendername.sin_addr), mx_len, mx);
		}
		else if( st && (st_len > 0) )
		{
			DPRINTF(E_INFO, L_SSDP, "SSDP M-SEARCH from %s:%d ST: %.*s, MX: %.*s, MAN: %.*s\n",
	        	   inet_ntoa(sendername.sin_addr),
	           	   ntohs(sendername.sin_port),
			   st_len, st, mx_len, mx, man_len, man);
			/* find in which sub network the client is */
			for(i = 0; i<n_lan_addr; i++)
			{
				if( (sendername.sin_addr.s_addr & lan_addr[i].mask.s_addr)
				   == (lan_addr[i].addr.s_addr & lan_addr[i].mask.s_addr))
				{
					lan_addr_index = i;
					break;
				}
			}
			/* Responds to request with a device as ST header */
			for(i = 0; known_service_types[i]; i++)
			{
				l = strlen(known_service_types[i]);
				if(l<=st_len && (0 == memcmp(st, known_service_types[i], l)))
				{
					/* Check version number - must always be 1 currently. */
					if( (st[st_len-2] == ':') && (atoi(st+st_len-1) != 1) )
						break;
					usleep(random()>>20);
					SendSSDPAnnounce2(s, sendername,
					                  i,
					                  lan_addr[lan_addr_index].str, port);
					break;
				}
			}
			/* Responds to request with ST: ssdp:all */
			/* strlen("ssdp:all") == 8 */
			if(st_len==8 && (0 == memcmp(st, "ssdp:all", 8)))
			{
				for(i=0; known_service_types[i]; i++)
				{
					l = (int)strlen(known_service_types[i]);
					SendSSDPAnnounce2(s, sendername,
					                  i,
					                  lan_addr[lan_addr_index].str, port);
				}
			}
		}
		else
		{