Пример #1
0
void
SendSSDPNotifies2(int * sockets,
                  unsigned short http_port,
#ifdef ENABLE_HTTPS
                  unsigned short https_port,
#endif
                  unsigned int lifetime)
{
	int i;
	struct lan_addr_s * lan_addr;
	for(i=0, lan_addr = lan_addrs.lh_first;
	    lan_addr != NULL;
	    lan_addr = lan_addr->list.le_next)
	{
		SendSSDPNotifies(sockets[i], lan_addr->str, http_port,
#ifdef ENABLE_HTTPS
		                 https_port,
#endif
		                 lifetime, 0);
		i++;
#ifdef ENABLE_IPV6
		if(sockets[i] >= 0)
		{
			SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, http_port,
#ifdef ENABLE_HTTPS
			                 https_port,
#endif
			                 lifetime, 1);
		}
		i++;
#endif
	}
}
Пример #2
0
void
SendSSDPNotifies2(int * sockets,
                  unsigned short port,
                  unsigned int lifetime)
{
	int i;
	struct lan_addr_s * lan_addr;
	for(i=0, lan_addr = lan_addrs.lh_first; lan_addr != NULL; lan_addr = lan_addr->list.le_next, i++)
	{
		SendSSDPNotifies(sockets[i], lan_addr->str, port, lifetime);
	}
}
Пример #3
0
void
SendSSDPNotifies2(int *sockets,
                  unsigned short port,
                  unsigned int lifetime)
{
	int i;

	DPRINTF(E_DEBUG, L_SSDP, "Sending SSDP notifies\n");
	for (i = 0; i < n_lan_addr; i++)
	{
		SendSSDPNotifies(sockets[i], lan_addr[i].str, port, lifetime);
	}
}
Пример #4
0
void
SendSSDPNotifies2(int * sockets,
                  unsigned short port,
                  unsigned int lifetime)
/*SendSSDPNotifies2(int * sockets, struct lan_addr_s * lan_addr, int n_lan_addr,
                  unsigned short port,
                  unsigned int lifetime)*/
{
	int i;
	for(i=0; i<n_lan_addr; i++)
	{
		SendSSDPNotifies(sockets[i], lan_addr[i].str, port, lifetime);
	}
}
Пример #5
0
/* process HTTP or SSDP requests */
int
main(int argc, char **argv)
{
	int ret, i;
	int shttpl = -1;
	int smonitor = -1;
	LIST_HEAD(httplisthead, upnphttp) upnphttphead;
	struct upnphttp * e = 0;
	struct upnphttp * next;
	fd_set readset;	/* for select() */
	fd_set writeset;
	struct timeval timeout, timeofday, lastnotifytime = {0, 0};
	time_t lastupdatetime = 0;
	int max_fd = -1;
	int last_changecnt = 0;
	pid_t scanner_pid = 0;
	pthread_t inotify_thread = 0;
#ifdef TIVO_SUPPORT
	uint8_t beacon_interval = 5;
	int sbeacon = -1;
	struct sockaddr_in tivo_bcast;
	struct timeval lastbeacontime = {0, 0};
#endif

	for (i = 0; i < L_MAX; i++)
		log_level[i] = E_WARN;
	init_nls();

	ret = init(argc, argv);
	if (ret != 0)
		return 1;

#if (!defined(RTN66U) && !defined(RTN56U))
	init_icon(PATH_ICON_PNG_SM);
	init_icon(PATH_ICON_PNG_LRG);
	init_icon(PATH_ICON_JPEG_SM);
	init_icon(PATH_ICON_JPEG_LRG);
#endif

	DPRINTF(E_WARN, L_GENERAL, "Starting " SERVER_NAME " version " MINIDLNA_VERSION ".\n");
	if (sqlite3_libversion_number() < 3005001)
	{
		DPRINTF(E_WARN, L_GENERAL, "SQLite library is old.  Please use version 3.5.1 or newer.\n");
	}

	LIST_INIT(&upnphttphead);

	ret = open_db(NULL);
	if (ret == 0)
	{
		updateID = sql_get_int_field(db, "SELECT VALUE from SETTINGS where KEY = 'UPDATE_ID'");
		if (updateID == -1)
			ret = -1;
	}
	check_db(db, ret, &scanner_pid);
#ifdef HAVE_INOTIFY
	if( GETFLAG(INOTIFY_MASK) )
	{
		if (!sqlite3_threadsafe() || sqlite3_libversion_number() < 3005001)
			DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe!  "
			                            "Inotify will be disabled.\n");
		else if (pthread_create(&inotify_thread, NULL, start_inotify, NULL) != 0)
			DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify. EXITING\n");
	}
#endif
	smonitor = OpenAndConfMonitorSocket();

	sssdp = OpenAndConfSSDPReceiveSocket();
	if (sssdp < 0)
	{
		DPRINTF(E_INFO, L_GENERAL, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd\n");
		if (SubmitServicesToMiniSSDPD(lan_addr[0].str, runtime_vars.port) < 0)
			DPRINTF(E_FATAL, L_GENERAL, "Failed to connect to MiniSSDPd. EXITING");
	}
	/* open socket for HTTP connections. */
	shttpl = OpenAndConfHTTPSocket(runtime_vars.port);
	if (shttpl < 0)
		DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for HTTP. EXITING\n");
	DPRINTF(E_WARN, L_GENERAL, "HTTP listening on port %d\n", runtime_vars.port);

#ifdef TIVO_SUPPORT
	if (GETFLAG(TIVO_MASK))
	{
		DPRINTF(E_WARN, L_GENERAL, "TiVo support is enabled.\n");
		/* Add TiVo-specific randomize function to sqlite */
		ret = sqlite3_create_function(db, "tivorandom", 1, SQLITE_UTF8, NULL, &TiVoRandomSeedFunc, NULL, NULL);
		if (ret != SQLITE_OK)
			DPRINTF(E_ERROR, L_TIVO, "ERROR: Failed to add sqlite randomize function for TiVo!\n");
		/* open socket for sending Tivo notifications */
		sbeacon = OpenAndConfTivoBeaconSocket();
		if(sbeacon < 0)
			DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify "
				"messages. EXITING\n");
		tivo_bcast.sin_family = AF_INET;
		tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress());
		tivo_bcast.sin_port = htons(2190);
	}
#endif

	reload_ifaces(0);
	lastnotifytime.tv_sec = time(NULL) + runtime_vars.notify_interval;

	/* main loop */
	while (!quitting)
	{
		/* Check if we need to send SSDP NOTIFY messages and do it if
		 * needed */
		if (gettimeofday(&timeofday, 0) < 0)
		{
			DPRINTF(E_ERROR, L_GENERAL, "gettimeofday(): %s\n", strerror(errno));
			timeout.tv_sec = runtime_vars.notify_interval;
			timeout.tv_usec = 0;
		}
		else
		{
			/* the comparison is not very precise but who cares ? */
			if (timeofday.tv_sec >= (lastnotifytime.tv_sec + runtime_vars.notify_interval))
			{
				DPRINTF(E_DEBUG, L_SSDP, "Sending SSDP notifies\n");
				for (i = 0; i < n_lan_addr; i++)
				{
					SendSSDPNotifies(lan_addr[i].snotify, lan_addr[i].str,
						runtime_vars.port, runtime_vars.notify_interval);
				}
				memcpy(&lastnotifytime, &timeofday, sizeof(struct timeval));
				timeout.tv_sec = runtime_vars.notify_interval;
				timeout.tv_usec = 0;
			}
			else
			{
				timeout.tv_sec = lastnotifytime.tv_sec + runtime_vars.notify_interval
				                 - timeofday.tv_sec;
				if (timeofday.tv_usec > lastnotifytime.tv_usec)
				{
					timeout.tv_usec = 1000000 + lastnotifytime.tv_usec
					                  - timeofday.tv_usec;
					timeout.tv_sec--;
				}
				else
					timeout.tv_usec = lastnotifytime.tv_usec - timeofday.tv_usec;
			}
#ifdef TIVO_SUPPORT
			if (sbeacon >= 0)
			{
				if (timeofday.tv_sec >= (lastbeacontime.tv_sec + beacon_interval))
				{
					sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1);
					memcpy(&lastbeacontime, &timeofday, sizeof(struct timeval));
					if (timeout.tv_sec > beacon_interval)
					{
						timeout.tv_sec = beacon_interval;
						timeout.tv_usec = 0;
					}
					/* Beacons should be sent every 5 seconds or so for the first minute,
					 * then every minute or so thereafter. */
					if (beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60)
						beacon_interval = 60;
				}
				else if (timeout.tv_sec > (lastbeacontime.tv_sec + beacon_interval + 1 - timeofday.tv_sec))
					timeout.tv_sec = lastbeacontime.tv_sec + beacon_interval - timeofday.tv_sec;
			}
#endif
		}

		if (scanning)
		{
			if (!scanner_pid || kill(scanner_pid, 0) != 0)
			{
				scanning = 0;
				updateID++;
			}
		}

		/* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
		FD_ZERO(&readset);

		if (sssdp >= 0) 
		{
			FD_SET(sssdp, &readset);
			max_fd = MAX(max_fd, sssdp);
		}
		
		if (shttpl >= 0) 
		{
			FD_SET(shttpl, &readset);
			max_fd = MAX(max_fd, shttpl);
		}
#ifdef TIVO_SUPPORT
		if (sbeacon >= 0) 
		{
			FD_SET(sbeacon, &readset);
			max_fd = MAX(max_fd, sbeacon);
		}
#endif
		if (smonitor >= 0) 
		{
			FD_SET(smonitor, &readset);
			max_fd = MAX(max_fd, smonitor);
		}

		i = 0;	/* active HTTP connections count */
		for (e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
		{
			if ((e->socket >= 0) && (e->state <= 2))
			{
				FD_SET(e->socket, &readset);
				max_fd = MAX(max_fd, e->socket);
				i++;
			}
		}
		FD_ZERO(&writeset);
		upnpevents_selectfds(&readset, &writeset, &max_fd);

		ret = select(max_fd+1, &readset, &writeset, 0, &timeout);
		if (ret < 0)
		{
			if(quitting) goto shutdown;
			if(errno == EINTR) continue;
			DPRINTF(E_ERROR, L_GENERAL, "select(all): %s\n", strerror(errno));
			DPRINTF(E_FATAL, L_GENERAL, "Failed to select open sockets. EXITING\n");
		}
		upnpevents_processfds(&readset, &writeset);
		/* process SSDP packets */
		if (sssdp >= 0 && FD_ISSET(sssdp, &readset))
		{
			/*DPRINTF(E_DEBUG, L_GENERAL, "Received SSDP Packet\n");*/
			ProcessSSDPRequest(sssdp, (unsigned short)runtime_vars.port);
		}
#ifdef TIVO_SUPPORT
		if (sbeacon >= 0 && FD_ISSET(sbeacon, &readset))
		{
			/*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
			ProcessTiVoBeacon(sbeacon);
		}
#endif
		if (smonitor >= 0 && FD_ISSET(smonitor, &readset))
		{
			ProcessMonitorEvent(smonitor);
		}
		/* increment SystemUpdateID if the content database has changed,
		 * and if there is an active HTTP connection, at most once every 2 seconds */
		if (i && (timeofday.tv_sec >= (lastupdatetime + 2)))
		{
			if (scanning || sqlite3_total_changes(db) != last_changecnt)
			{
				updateID++;
				last_changecnt = sqlite3_total_changes(db);
				upnp_event_var_change_notify(EContentDirectory);
				lastupdatetime = timeofday.tv_sec;
			}
		}
		/* process active HTTP connections */
		for (e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
		{
			if ((e->socket >= 0) && (e->state <= 2) && (FD_ISSET(e->socket, &readset)))
				Process_upnphttp(e);
		}
		/* process incoming HTTP connections */
		if (shttpl >= 0 && FD_ISSET(shttpl, &readset))
		{
			int shttp;
			socklen_t clientnamelen;
			struct sockaddr_in clientname;
			clientnamelen = sizeof(struct sockaddr_in);
			shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
			if (shttp<0)
			{
				DPRINTF(E_ERROR, L_GENERAL, "accept(http): %s\n", strerror(errno));
			}
			else
			{
				struct upnphttp * tmp = 0;
				DPRINTF(E_DEBUG, L_GENERAL, "HTTP connection from %s:%d\n",
					inet_ntoa(clientname.sin_addr),
					ntohs(clientname.sin_port) );
				/*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
					DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK\n");
				}*/
				/* Create a new upnphttp object and add it to
				 * the active upnphttp object list */
				tmp = New_upnphttp(shttp);
				if (tmp)
				{
					tmp->clientaddr = clientname.sin_addr;
					LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
				}
				else
				{
					DPRINTF(E_ERROR, L_GENERAL, "New_upnphttp() failed\n");
					close(shttp);
				}
			}
		}
		/* delete finished HTTP connections */
		for (e = upnphttphead.lh_first; e != NULL; e = next)
		{
			next = e->entries.le_next;
			if(e->state >= 100)
			{
				LIST_REMOVE(e, entries);
				Delete_upnphttp(e);
			}
		}
	}

shutdown:
	/* kill the scanner */
	if (scanning && scanner_pid)
		kill(scanner_pid, SIGKILL);

	/* kill other child processes */
	process_reap_children();
	free(children);

	/* close out open sockets */
	while (upnphttphead.lh_first != NULL)
	{
		e = upnphttphead.lh_first;
		LIST_REMOVE(e, entries);
		Delete_upnphttp(e);
	}
	if (sssdp >= 0)
		close(sssdp);
	if (shttpl >= 0)
		close(shttpl);
#ifdef TIVO_SUPPORT
	if (sbeacon >= 0)
		close(sbeacon);
#endif
	
	for (i = 0; i < n_lan_addr; i++)
	{
		SendSSDPGoodbyes(lan_addr[i].snotify);
		close(lan_addr[i].snotify);
	}

	if (inotify_thread)
		pthread_join(inotify_thread, NULL);

	sql_exec(db, "UPDATE SETTINGS set VALUE = '%u' where KEY = 'UPDATE_ID'", updateID);
	sqlite3_close(db);

	upnpevents_removeSubscribers();

	if (pidfilename && unlink(pidfilename) < 0)
		DPRINTF(E_ERROR, L_GENERAL, "Failed to remove pidfile %s: %s\n", pidfilename, strerror(errno));

	log_close();
	freeoptions();

	exit(EXIT_SUCCESS);
}
Пример #6
0
static void
SendSSDPNotifies(int s, const char * host, unsigned short http_port,
                 unsigned int lifetime, int ipv6)
#endif
{
#ifdef ENABLE_IPV6
	struct sockaddr_storage sockname;
	/* UDA 1.1 AnnexA and UDA 2.0 only allow/define the use of
	 * Link-Local and Site-Local multicast scopes */
	static struct { const char * p1, * p2; } const mcast_addrs[] =
		{ { LL_SSDP_MCAST_ADDR, "[" LL_SSDP_MCAST_ADDR "]" },	/* Link Local */
		  { SL_SSDP_MCAST_ADDR, "[" SL_SSDP_MCAST_ADDR "]" },	/* Site Local */
#ifndef UPNP_STRICT
		  { GL_SSDP_MCAST_ADDR, "[" GL_SSDP_MCAST_ADDR "]" },	/* Global */
#endif /* ! UPNP_STRICT */
		  { NULL, NULL } };
	int j;
#else /* ENABLE_IPV6 */
	struct sockaddr_in sockname;
#endif /* ENABLE_IPV6 */
	socklen_t sockname_len;
	const char * dest_str;
	int i;
	char ver_str[4];
#ifndef ENABLE_IPV6
	UNUSED(ipv6);
#endif /* ENABLE_IPV6 */

	memset(&sockname, 0, sizeof(sockname));
#ifdef ENABLE_IPV6
	/* first iterate destinations for this LAN interface (only 1 for IPv4) */
	for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) {
		if(ipv6) {
			struct sockaddr_in6 * p = (struct sockaddr_in6 *)&sockname;
			sockname_len = sizeof(struct sockaddr_in6);
			p->sin6_family = AF_INET6;
			p->sin6_port = htons(SSDP_PORT);
			inet_pton(AF_INET6, mcast_addrs[j].p1, &(p->sin6_addr));
			dest_str = mcast_addrs[j].p2;
			/* UPnP Device Architecture 1.1 :
			 * Devices MUST multicast SSDP messages for each of the UPnP-enabled
			 * interfaces. The scope of multicast SSDP messages MUST be
			 * link local FF02::C if the message is sent from a link local address.
			 * If the message is sent from a global address it MUST be multicast
			 * using either global scope FF0E::C or site local scope FF05::C.
			 * In networks with complex topologies and overlapping sites, use of
			 * global scope is RECOMMENDED. */
		} else {
#else /* ENABLE_IPV6 */
		{
#endif /* ENABLE_IPV6 */
			/* IPv4 */
			struct sockaddr_in *p = (struct sockaddr_in *)&sockname;
			sockname_len = sizeof(struct sockaddr_in);
			p->sin_family = AF_INET;
			p->sin_port = htons(SSDP_PORT);
			p->sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
			dest_str = SSDP_MCAST_ADDR;
		}

		/* iterate all services / devices */
		for(i = 0; known_service_types[i].s; i++) {
			if(i==0)
				ver_str[0] = '\0';
			else
				snprintf(ver_str, sizeof(ver_str), "%d", known_service_types[i].version);
			SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str,
			               host, http_port,
#ifdef ENABLE_HTTPS
			               https_port,
#endif
			               known_service_types[i].s, ver_str,	/* NT: */
			               known_service_types[i].uuid, "::",
			               known_service_types[i].s, /* ver_str,	USN: */
			               lifetime);
			/* for devices, also send NOTIFY on the uuid */
			if(0==memcmp(known_service_types[i].s,
			             "urn:schemas-upnp-org:device", sizeof("urn:schemas-upnp-org:device")-1)) {
				SendSSDPNotify(s, (struct sockaddr *)&sockname, sockname_len, dest_str,
				               host, http_port,
#ifdef ENABLE_HTTPS
				               https_port,
#endif
				               known_service_types[i].uuid, "",	/* NT: */
				               known_service_types[i].uuid, "", "", /* ver_str,	USN: */
				               lifetime);
			}
		} /* for(i = 0; known_service_types[i].s; i++) */
#ifdef ENABLE_IPV6
	} /* for(j = 0; (mcast_addrs[j].p1 != 0 && ipv6) || j < 1; j++) */
#endif /* ENABLE_IPV6 */
}

/* SendSSDPNotifies2() sends SSDP NOTIFY packets on all interfaces
 * for all destinations, all devices / services */
void
SendSSDPNotifies2(int * sockets,
                  unsigned short http_port,
#ifdef ENABLE_HTTPS
                  unsigned short https_port,
#endif
                  unsigned int lifetime)
{
	int i;
	struct lan_addr_s * lan_addr;
	for(i = 0, lan_addr = lan_addrs.lh_first;
	    lan_addr != NULL;
	    lan_addr = lan_addr->list.le_next) {
		SendSSDPNotifies(sockets[i], lan_addr->str, http_port,
#ifdef ENABLE_HTTPS
		                 https_port,
#endif
		                 lifetime, 0);
		i++;
#ifdef ENABLE_IPV6
		if(sockets[i] >= 0) {
			SendSSDPNotifies(sockets[i], ipv6_addr_for_http_with_brackets, http_port,
#ifdef ENABLE_HTTPS
			                 https_port,
#endif
			                 lifetime, 1);
		}
		i++;
#endif	/* ENABLE_IPV6 */
	}
}