Beispiel #1
0
static void
SendSSDPNotify(int s, const struct sockaddr * dest, socklen_t dest_len,
               const char * dest_str,
               const char * host, unsigned short http_port,
#ifdef ENABLE_HTTPS
               unsigned short https_port,
#endif
               const char * nt, const char * suffix,
               const char * usn1, const char * usn2, const char * usn3,
               unsigned int lifetime)
{
	char bufr[SSDP_PACKET_MAX_LEN];
	int n, l;

	l = snprintf(bufr, sizeof(bufr),
		"NOTIFY * HTTP/1.1\r\n"
		"HOST: %s:%d\r\n"
		"CACHE-CONTROL: max-age=%u\r\n"
		"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
#ifdef ENABLE_HTTPS
		"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
#endif
		"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
		"NT: %s%s\r\n"
		"USN: %s%s%s%s\r\n"
		"NTS: ssdp:alive\r\n"
		"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
		"01-NLS: %u\r\n" /* same as BOOTID field. UDA v1.1 */
		"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"\r\n",
		dest_str, SSDP_PORT,			/* HOST: */
		lifetime,						/* CACHE-CONTROL: */
		host, (unsigned int)http_port,	/* LOCATION: */
#ifdef ENABLE_HTTPS
		host, (unsigned int)https_port,	/* SECURE-LOCATION: */
#endif
		nt, suffix,						/* NT: */
		usn1, usn2, usn3, suffix,		/* USN: */
		upnp_bootid,					/* 01-NLS: */
		upnp_bootid,					/* BOOTID.UPNP.ORG: */
		upnp_configid );				/* CONFIGID.UPNP.ORG: */
	if(l<0)
	{
		syslog(LOG_ERR, "%s: snprintf error", "SendSSDPNotify()");
		return;
	}
	else if((unsigned int)l >= sizeof(bufr))
	{
		syslog(LOG_WARNING, "%s: truncated output (%u>=%u)",
		       "SendSSDPNotify()", (unsigned)l, (unsigned)sizeof(bufr));
		l = sizeof(bufr) - 1;
	}
	n = sendto_or_schedule(s, bufr, l, 0, dest, dest_len);
	if(n < 0)
	{
		syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
		       host ? host : "NULL");
	}
	else if(n != l)
	{
		syslog(LOG_NOTICE, "sendto() sent %d out of %d bytes", n, l);
	}
	/* Due to the unreliable nature of UDP, devices SHOULD send the entire
	 * set of discovery messages more than once with some delay between
	 * sets e.g. a few hundred milliseconds. To avoid network congestion
	 * discovery messages SHOULD NOT be sent more than three times. */
	n = sendto_schedule(s, bufr, l, 0, dest, dest_len, 250);
	if(n < 0)
	{
		syslog(LOG_ERR, "sendto(udp_notify=%d, %s): %m", s,
		       host ? host : "NULL");
	}
}
Beispiel #2
0
/* try to send at once, and queue the packet if needed */
ssize_t
sendto_or_schedule(int sockfd, const void *buf, size_t len, int flags,
                   const struct sockaddr *dest_addr, socklen_t addrlen)
{
	return sendto_schedule(sockfd, buf, len, flags, dest_addr, addrlen, 0);
}
Beispiel #3
0
/* Responds to a SSDP "M-SEARCH"
 * s :          socket to use
 * addr :       peer
 * st, st_len : ST: header
 * suffix :     suffix for USN: header
 * host, port : our HTTP host, port
 * delay :      in milli-seconds
 */
static void
SendSSDPResponse(int s, const struct sockaddr * addr,
                 const char * st, int st_len, const char * suffix,
                 const char * host, unsigned short http_port,
#ifdef ENABLE_HTTPS
                 unsigned short https_port,
#endif
                 const char * uuidvalue, unsigned int delay)
{
	int l, n;
	char buf[SSDP_PACKET_MAX_LEN];
	char addr_str[64];
	socklen_t addrlen;
	int st_is_uuid;
#ifdef ENABLE_HTTP_DATE
	char http_date[64];
	time_t t;
	struct tm tm;

	time(&t);
	gmtime_r(&t, &tm);
	strftime(http_date, sizeof(http_date),
		    "%a, %d %b %Y %H:%M:%S GMT", &tm);
#endif

	st_is_uuid = (st_len == (int)strlen(uuidvalue)) &&
	              (memcmp(uuidvalue, st, st_len) == 0);
	/*
	 * follow guideline from document "UPnP Device Architecture 1.0"
	 * uppercase is recommended.
	 * DATE: is recommended
	 * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0
	 * - check what to put in the 'Cache-Control' header
	 *
	 * have a look at the document "UPnP Device Architecture v1.1 */
	l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n"
		"CACHE-CONTROL: max-age=120\r\n"
#ifdef ENABLE_HTTP_DATE
		"DATE: %s\r\n"
#endif
		"ST: %.*s%s\r\n"
		"USN: %s%s%.*s%s\r\n"
		"EXT:\r\n"
		"SERVER: " MINIUPNPD_SERVER_STRING "\r\n"
		"LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n"
#ifdef ENABLE_HTTPS
		"SECURELOCATION.UPNP.ORG: https://%s:%u" ROOTDESC_PATH "\r\n"
#endif
		"OPT: \"http://schemas.upnp.org/upnp/1/0/\"; ns=01\r\n" /* UDA v1.1 */
		"01-NLS: %u\r\n" /* same as BOOTID. UDA v1.1 */
		"BOOTID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"CONFIGID.UPNP.ORG: %u\r\n" /* UDA v1.1 */
		"\r\n",
#ifdef ENABLE_HTTP_DATE
		http_date,
#endif
		st_len, st, suffix,
		uuidvalue, st_is_uuid ? "" : "::",
		st_is_uuid ? 0 : st_len, st, suffix,
		host, (unsigned int)http_port,
#ifdef ENABLE_HTTPS
		host, (unsigned int)https_port,
#endif
		upnp_bootid, upnp_bootid, upnp_configid);
	if(l<0)
	{
		syslog(LOG_ERR, "%s: snprintf failed %m",
		       "SendSSDPResponse()");
		return;
	}
	else if((unsigned)l>=sizeof(buf))
	{
		syslog(LOG_WARNING, "%s: truncated output (%u>=%u)",
		       "SendSSDPResponse()", (unsigned)l, (unsigned)sizeof(buf));
		l = sizeof(buf) - 1;
	}
	addrlen = (addr->sa_family == AF_INET6)
	          ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
	n = sendto_schedule(s, buf, l, 0,
	                    addr, addrlen, delay);
	sockaddr_to_string(addr, addr_str, sizeof(addr_str));
	syslog(LOG_DEBUG, "%s: %d bytes to %s ST: %.*s",
	       "SendSSDPResponse()",
	       n, addr_str, l, buf);
	if(n < 0)
	{
		syslog(LOG_ERR, "%s: sendto(udp): %m",
		       "SendSSDPResponse()");
	}
}
Beispiel #4
0
int test(void)
{
	int s;
	ssize_t n;
	int i;
	struct sockaddr_in addr;
	struct sockaddr_in dest_addr;
	struct timeval next_send;
	if( (s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
		syslog(LOG_ERR, "socket(): %m");
		return 1;
	}
	set_non_blocking(s);
	memset(&addr, 0, sizeof(struct sockaddr_in));
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		syslog(LOG_ERR, "bind(): %m");
		close(s);
		return 1;
	}
	memset(&dest_addr, 0, sizeof(struct sockaddr_in));
	dest_addr.sin_family = AF_INET;
	dest_addr.sin_addr.s_addr = inet_addr(DEST_IP);
	dest_addr.sin_port =  htons(DEST_PORT);
	n = sendto_or_schedule(s, "1234", 4, 0,
	                       (struct sockaddr *)&dest_addr, sizeof(dest_addr));
	syslog(LOG_DEBUG, "sendto_or_schedule : %d", (int)n);
	n = sendto_schedule(s, "1234", 4, 0,
	                    (struct sockaddr *)&dest_addr, sizeof(dest_addr),
	                    4400);
	syslog(LOG_DEBUG, "sendto_schedule : %d", (int)n);
	n = sendto_schedule(s, "1234", 4, 0,
	                    (struct sockaddr *)&dest_addr, sizeof(dest_addr),
	                    3000);
	syslog(LOG_DEBUG, "sendto_schedule : %d", (int)n);
	while ((i = get_next_scheduled_send(&next_send)) > 0) {
		fd_set writefds;
		int max_fd;
		struct timeval timeout;
		struct timeval now;
		syslog(LOG_DEBUG, "get_next_scheduled_send : %d next_send=%ld.%06ld",
		       i, (long)next_send.tv_sec, (long)next_send.tv_usec);
		FD_ZERO(&writefds);
		max_fd = 0;
		gettimeofday(&now, NULL);
		i = get_sendto_fds(&writefds, &max_fd, &now);
		if(now.tv_sec > next_send.tv_sec ||
		   (now.tv_sec == next_send.tv_sec && now.tv_usec >= next_send.tv_usec)) {
			if(i > 0) {
				/* dont wait */
				timeout.tv_sec = 0;
			} else {
				/* wait 10sec :) */
				timeout.tv_sec = 10;
			}
			timeout.tv_usec = 0;
		} else {
			/* ... */
			timeout.tv_sec = (next_send.tv_sec - now.tv_sec);
			timeout.tv_usec = (next_send.tv_usec - now.tv_usec);
			if(timeout.tv_usec < 0) {
				timeout.tv_usec += 1000000;
				timeout.tv_sec--;
			}
		}
		syslog(LOG_DEBUG, "get_sendto_fds() returned %d", i);
		syslog(LOG_DEBUG, "select(%d, NULL, xx, NULL, %ld.%06ld)",
		       max_fd, (long)timeout.tv_sec, (long)timeout.tv_usec);
		i = select(max_fd, NULL, &writefds, NULL, &timeout);
		if(i < 0) {
			syslog(LOG_ERR, "select: %m");
			if(errno != EINTR)
				break;
		} else if(try_sendto(&writefds) < 0) {
			syslog(LOG_ERR, "try_sendto: %m");
			break;
		}
	}
	close(s);
	return 0;
}