Don't require a configured network interface to start up, and add network interface monitoring support on Linux.

This commit is contained in:
Justin Maggard 2013-05-08 23:52:02 -07:00
parent 1e4cf74436
commit 62b6e235b1
10 changed files with 249 additions and 360 deletions

2
NEWS
View File

@ -12,6 +12,8 @@
- Add some logging and forking tweaks to work better with systemd.
- Validate or escape user input to prevent SQL injection.
- Add forced sorting support for Panasonic devices.
- Add network interface monitoring support on Linux.
- Don't require a configured network interface to start up.
1.0.25 - Released 13-July-2012
--------------------------------

View File

@ -83,24 +83,27 @@ esac
AC_CHECK_HEADERS(syscall.h sys/syscall.h mach/mach_time.h)
AC_MSG_CHECKING([for __NR_clock_gettime syscall])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[
#include <asm/unistd.h>
],
[
#ifndef __NR_clock_gettime
#error
#endif
]
)],
[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_CLOCK_GETTIME_SYSCALL], [1], [Whether the __NR_clock_gettime syscall is defined])
],
[
AC_MSG_RESULT([no])
AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [use clock_gettime])],)
])
[AC_LANG_PROGRAM(
[
#include <asm/unistd.h>
],
[
#ifndef __NR_clock_gettime
#error
#endif
]
)],
[
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_CLOCK_GETTIME_SYSCALL], [1], [Whether the __NR_clock_gettime syscall is defined])
],
[
AC_MSG_RESULT([no])
AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [use clock_gettime])],)
])
AC_CHECK_HEADER(linux/netlink.h,
[AC_DEFINE([HAVE_NETLINK],[1],[Support for Linux netlink])])
################################################################################################################
### Library checks

View File

@ -53,35 +53,18 @@
#include <net/if_dl.h>
#endif
#endif
#ifdef HAVE_NETLINK
#include <linux/rtnetlink.h>
#include <linux/netlink.h>
#endif
#include "upnpglobalvars.h"
#include "getifaddr.h"
#include "minissdp.h"
#include "log.h"
static uint32_t
get_netmask(struct sockaddr_in *netmask)
static int
getifaddr(const char *ifname)
{
uint32_t mask;
int i;
if (!netmask)
return 0;
mask = ntohl(netmask->sin_addr.s_addr);
for (i = 0; i < 32; i++)
{
if ((mask >> i) & 1)
break;
}
mask = 32 - i;
return mask;
}
int
getifaddr(const char * ifname, char * buf, int len)
{
/* SIOCGIFADDR struct ifreq * */
uint32_t mask = 0;
int i;
#if HAVE_GETIFADDRS
struct ifaddrs *ifap, *p;
struct sockaddr_in *addr_in;
@ -91,106 +74,40 @@ getifaddr(const char * ifname, char * buf, int len)
DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
return -1;
}
for (p = ifap; p != NULL; p = p->ifa_next)
{
if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET)
if (!p->ifa_addr || p->ifa_addr->sa_family != AF_INET)
continue;
if (ifname && strcmp(p->ifa_name, ifname) != 0)
continue;
addr_in = (struct sockaddr_in *)p->ifa_addr;
if (!ifname && (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE)))
continue;
memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
{
if (strcmp(p->ifa_name, ifname) != 0)
continue;
addr_in = (struct sockaddr_in *)p->ifa_addr;
if (!inet_ntop(AF_INET, &addr_in->sin_addr, buf, len))
{
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
break;
}
addr_in = (struct sockaddr_in *)p->ifa_netmask;
mask = get_netmask(addr_in);
break;
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
continue;
}
addr_in = (struct sockaddr_in *)p->ifa_netmask;
memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(lan_addr[n_lan_addr].addr.s_addr);
if (lan_addr[n_lan_addr].snotify >= 0)
{
SendSSDPNotifies(lan_addr[n_lan_addr].snotify, lan_addr[n_lan_addr].str,
runtime_vars.port, runtime_vars.notify_interval);
n_lan_addr++;
}
if (ifname || n_lan_addr >= MAX_LAN_ADDR)
break;
}
freeifaddrs(ifap);
if (!p)
if (ifname && !p)
{
DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
return -1;
}
#else
int s;
struct ifreq ifr;
int ifrlen;
struct sockaddr_in * addr;
ifrlen = sizeof(ifr);
s = socket(PF_INET, SOCK_DGRAM, 0);
if (s < 0)
{
DPRINTF(E_ERROR, L_GENERAL, "socket(PF_INET, SOCK_DGRAM): %s\n", strerror(errno));
return -1;
}
strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFADDR, &ifr, &ifrlen) < 0)
{
DPRINTF(E_ERROR, L_GENERAL, "ioctl(s, SIOCGIFADDR, ...): %s\n", strerror(errno));
close(s);
return -1;
}
addr = (struct sockaddr_in *)&ifr.ifr_addr;
if (!inet_ntop(AF_INET, &addr->sin_addr, buf, len))
{
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
close(s);
return -1;
}
if (ioctl(s, SIOCGIFNETMASK, &ifr, &ifrlen) == 0)
{
addr = (struct sockaddr_in *)&ifr.ifr_netmask;
mask = get_netmask(addr);
}
else
DPRINTF(E_ERROR, L_GENERAL, "ioctl(s, SIOCGIFNETMASK, ...): %s\n", strerror(errno));
close(s);
#endif
if (mask)
{
i = strlen(buf);
snprintf(buf+i, len-i, "/%u", mask);
}
return 0;
}
int
getsysaddrs(void)
{
#if HAVE_GETIFADDRS
struct ifaddrs *ifap, *p;
struct sockaddr_in *addr_in;
if (getifaddrs(&ifap) != 0)
{
DPRINTF(E_ERROR, L_GENERAL, "getifaddrs(): %s\n", strerror(errno));
return -1;
}
for (p = ifap; p != NULL; p = p->ifa_next)
{
if (p->ifa_addr && p->ifa_addr->sa_family == AF_INET)
{
addr_in = (struct sockaddr_in *)p->ifa_addr;
if (p->ifa_flags & (IFF_LOOPBACK | IFF_SLAVE))
continue;
memcpy(&lan_addr[n_lan_addr].addr, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].addr));
if (!inet_ntop(AF_INET, &addr_in->sin_addr, lan_addr[n_lan_addr].str, sizeof(lan_addr[0].str)) )
{
DPRINTF(E_ERROR, L_GENERAL, "inet_ntop(): %s\n", strerror(errno));
continue;
}
addr_in = (struct sockaddr_in *)p->ifa_netmask;
memcpy(&lan_addr[n_lan_addr].mask, &addr_in->sin_addr, sizeof(lan_addr[n_lan_addr].mask));
n_lan_addr++;
if (n_lan_addr >= MAX_LAN_ADDR)
break;
}
}
freeifaddrs(ifap);
#else
int s = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr;
@ -211,11 +128,13 @@ getsysaddrs(void)
}
n = ifc.ifc_len / sizeof(struct ifreq);
for (i=0; i < n; i++)
for (i = 0; i < n; i++)
{
ifr = &ifc.ifc_req[i];
if (ioctl(s, SIOCGIFFLAGS, ifr) < 0 ||
ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK)
if (ifname && strcmp(ifr->ifr_name, ifname) != 0)
continue;
if (!ifname &&
(ioctl(s, SIOCGIFFLAGS, ifr) < 0 || ifr->ifr_ifru.ifru_flags & IFF_LOOPBACK))
continue;
if (ioctl(s, SIOCGIFADDR, ifr) < 0)
continue;
@ -231,11 +150,22 @@ getsysaddrs(void)
continue;
memcpy(&addr, &(ifr->ifr_addr), sizeof(addr));
memcpy(&lan_addr[n_lan_addr].mask, &addr.sin_addr, sizeof(addr));
n_lan_addr++;
if (n_lan_addr >= MAX_LAN_ADDR)
lan_addr[n_lan_addr].snotify = OpenAndConfSSDPNotifySocket(lan_addr[i].addr.s_addr);
if (lan_addr[n_lan_addr].snotify >= 0)
{
SendSSDPNotifies(lan_addr[n_lan_addr].snotify, lan_addr[n_lan_addr].str,
runtime_vars.port, runtime_vars.notify_interval);
n_lan_addr++;
}
if (ifname || n_lan_addr >= MAX_LAN_ADDR)
break;
}
close(s);
if (ifname && i == n)
{
DPRINTF(E_ERROR, L_GENERAL, "Network interface %s not found\n", ifname);
return -1;
}
#endif
return n_lan_addr;
}
@ -245,7 +175,7 @@ getsyshwaddr(char *buf, int len)
{
unsigned char mac[6];
int ret = -1;
#if HAVE_GETIFADDRS
#if defined(HAVE_GETIFADDRS) && !defined (__linux__)
struct ifaddrs *ifap, *p;
struct sockaddr_in *addr_in;
uint8_t a;
@ -367,3 +297,91 @@ get_remote_mac(struct in_addr ip_addr, unsigned char *mac)
return 0;
}
void
reload_ifaces(void)
{
int i;
for (i = 0; i < n_lan_addr; i++)
{
close(lan_addr[i].snotify);
}
n_lan_addr = 0;
if (runtime_vars.ifaces[0])
{
for (i = 0; runtime_vars.ifaces[i]; i++)
{
getifaddr(runtime_vars.ifaces[i]);
}
}
else
getifaddr(NULL);
for (i = 0; i < n_lan_addr; i++)
{
DPRINTF(E_INFO, L_GENERAL, "Enabled interface %s/%s\n",
lan_addr[i].str, inet_ntoa(lan_addr[i].mask));
}
}
int
OpenAndConfMonitorSocket(void)
{
#ifdef HAVE_NETLINK
struct sockaddr_nl addr;
int s;
int ret;
s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (s < 0)
{
perror("couldn't open NETLINK_ROUTE socket");
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_groups = RTMGRP_IPV4_IFADDR;
ret = bind(s, (struct sockaddr*)&addr, sizeof(addr));
if (ret < 0)
{
perror("couldn't bind");
return -1;
}
return s;
#else
return -1;
#endif
}
void
ProcessMonitorEvent(int s)
{
#ifdef HAVE_NETLINK
int len;
char buf[4096];
struct nlmsghdr *nlh;
int changed = 0;
nlh = (struct nlmsghdr*)buf;
len = recv(s, nlh, sizeof(buf), 0);
if (len <= 0)
return;
while ((NLMSG_OK(nlh, len)) && (nlh->nlmsg_type != NLMSG_DONE))
{
if (nlh->nlmsg_type == RTM_NEWADDR ||
nlh->nlmsg_type == RTM_DELADDR)
{
changed = 1;
}
nlh = NLMSG_NEXT(nlh, len);
}
if (changed)
reload_ifaces();
#endif
}

View File

@ -38,21 +38,12 @@
(x[4] == 0x00) && \
(x[5] == 0x00))
/* getifaddr()
* take a network interface name and write the
* ip v4 address as text in the buffer
* returns: 0 success, -1 failure */
int
getifaddr(const char * ifname, char * buf, int len);
int getsyshwaddr(char *buf, int len);
int get_remote_mac(struct in_addr ip_addr, unsigned char *mac);
void reload_ifaces(void);
int
getsysaddrs(void);
int
getsyshwaddr(char * buf, int len);
int
get_remote_mac(struct in_addr ip_addr, unsigned char * mac);
int OpenAndConfMonitorSocket();
void ProcessMonitorEvent(int s);
#endif

View File

@ -148,13 +148,11 @@ OpenAndConfHTTPSocket(unsigned short port)
static void
sigterm(int sig)
{
/*int save_errno = errno;*/
signal(sig, SIG_IGN); /* Ignore this signal while we are quitting */
DPRINTF(E_WARN, L_GENERAL, "received signal %d, good-bye\n", sig);
quitting = 1;
/*errno = save_errno;*/
}
static void
@ -165,6 +163,15 @@ sigchld(int sig)
waitpid(-1, NULL, WNOHANG);
}
static void
sighup(int sig)
{
signal(sig, sighup);
DPRINTF(E_WARN, L_GENERAL, "received signal %d, re-read\n", sig);
reload_ifaces();
}
/* record the startup time */
static void
set_startup_time(void)
@ -172,44 +179,6 @@ set_startup_time(void)
startup_time = time(NULL);
}
/* parselanaddr()
* parse address with mask
* ex: 192.168.1.1/24
* return value :
* 0 : ok
* -1 : error */
static int
parselanaddr(struct lan_addr_s *lan_addr, const char *str)
{
const char * p;
int nbits = 24;
int n;
p = str;
while(*p && *p != '/' && !isspace(*p))
p++;
n = p - str;
if(*p == '/')
{
nbits = atoi(++p);
while(*p && !isspace(*p))
p++;
}
if(n>15)
{
DPRINTF(E_OFF, L_GENERAL, "Error parsing address/mask: %s\n", str);
return -1;
}
memcpy(lan_addr->str, str, n);
lan_addr->str[n] = '\0';
if(!inet_aton(lan_addr->str, &lan_addr->addr))
{
DPRINTF(E_OFF, L_GENERAL, "Error parsing address: %s\n", str);
return -1;
}
lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);
return 0;
}
static void
getfriendlyname(char *buf, int len)
{
@ -504,10 +473,10 @@ init(int argc, char **argv)
char *string, *word;
char *path;
char buf[PATH_MAX];
char ip_addr[INET_ADDRSTRLEN + 3] = {'\0'};
char log_str[75] = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn";
char *log_level = NULL;
struct media_dir_s *media_dir;
int ifaces = 0;
media_types types;
uid_t uid = -1;
@ -533,9 +502,10 @@ init(int argc, char **argv)
getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN);
runtime_vars.port = -1;
runtime_vars.port = 8200;
runtime_vars.notify_interval = 895; /* seconds between SSDP announces */
runtime_vars.root_container = NULL;
runtime_vars.ifaces[0] = NULL;
/* read options file first since
* command line arguments have final say */
@ -553,30 +523,15 @@ init(int argc, char **argv)
case UPNPIFNAME:
for (string = ary_options[i].value; (word = strtok(string, ",")); string = NULL)
{
if (n_lan_addr < MAX_LAN_ADDR)
if (ifaces >= MAX_LAN_ADDR)
{
if (getifaddr(word, ip_addr, sizeof(ip_addr)) >= 0)
{
if (*ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0)
if (n_lan_addr < MAX_LAN_ADDR)
n_lan_addr++;
}
DPRINTF(E_ERROR, L_GENERAL, "Too many interfaces (max: %d), ignoring %s\n",
MAX_LAN_ADDR, word);
break;
}
else
DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n",
MAX_LAN_ADDR, word);
runtime_vars.ifaces[ifaces++] = word;
}
break;
case UPNPLISTENING_IP:
if (n_lan_addr < MAX_LAN_ADDR)
{
if (parselanaddr(&lan_addr[n_lan_addr], ary_options[i].value) == 0)
n_lan_addr++;
}
else
DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n",
MAX_LAN_ADDR, ary_options[i].value);
break;
case UPNPPORT:
runtime_vars.port = atoi(ary_options[i].value);
break;
@ -821,59 +776,17 @@ init(int argc, char **argv)
else
DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
break;
case 'a':
if (i+1 < argc)
{
int address_already_there = 0;
int j;
i++;
for (j=0; j<n_lan_addr; j++)
{
struct lan_addr_s tmpaddr;
parselanaddr(&tmpaddr, argv[i]);
if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
address_already_there = 1;
}
if (address_already_there)
break;
if (n_lan_addr < MAX_LAN_ADDR)
{
if (parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
n_lan_addr++;
}
else
DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n",
MAX_LAN_ADDR, argv[i]);
}
else
DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
break;
case 'i':
if (i+1 < argc)
{
int address_already_there = 0;
int j;
i++;
if (getifaddr(argv[i], ip_addr, sizeof(ip_addr)) < 0)
DPRINTF(E_FATAL, L_GENERAL, "Required network interface '%s' not found.\n",
argv[i]);
for (j=0; j<n_lan_addr; j++)
if (ifaces >= MAX_LAN_ADDR)
{
struct lan_addr_s tmpaddr;
parselanaddr(&tmpaddr, ip_addr);
if(strcmp(lan_addr[j].str, tmpaddr.str) == 0)
address_already_there = 1;
}
if (address_already_there)
DPRINTF(E_ERROR, L_GENERAL, "Too many interfaces (max: %d), ignoring %s\n",
MAX_LAN_ADDR, argv[i]);
break;
if (n_lan_addr < MAX_LAN_ADDR)
{
if(parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0)
n_lan_addr++;
}
else
DPRINTF(E_ERROR, L_GENERAL, "Too many listening ips (max: %d), ignoring %s\n",
MAX_LAN_ADDR, argv[i]);
runtime_vars.ifaces[ifaces++] = argv[i];
}
else
DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
@ -920,18 +833,11 @@ init(int argc, char **argv)
DPRINTF(E_ERROR, L_GENERAL, "Unknown option: %s\n", argv[i]);
}
}
/* If no IP was specified, try to detect one */
if (n_lan_addr < 1)
{
if (getsysaddrs() <= 0)
DPRINTF(E_FATAL, L_GENERAL, "No IP address automatically detected!\n");
}
if (!n_lan_addr || runtime_vars.port <= 0)
if (runtime_vars.port <= 0)
{
DPRINTF(E_ERROR, L_GENERAL, "Usage:\n\t"
"%s [-d] [-v] [-f config_file]\n"
"\t\t[-a listening_ip] [-p port]\n"
printf("Usage:\n\t"
"%s [-d] [-v] [-f config_file] [-p port]\n"
/*"[-l logfile] " not functionnal */
"\t\t[-s serial] [-m model_number] \n"
"\t\t[-t notify_interval] [-P pid_filename]\n"
@ -994,6 +900,7 @@ init(int argc, char **argv)
}
set_startup_time();
reload_ifaces();
/* presentation url */
if (presurl)
@ -1005,11 +912,13 @@ init(int argc, char **argv)
memset(&sa, 0, sizeof(struct sigaction));
sa.sa_handler = sigterm;
if (sigaction(SIGTERM, &sa, NULL))
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", SIGTERM);
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGTERM");
if (sigaction(SIGINT, &sa, NULL))
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", SIGINT);
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGINT");
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", SIGPIPE);
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGPIPE");
if (signal(SIGHUP, &sighup) == SIG_ERR)
DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGHUP");
if (writepidfile(pidfilename, pid, uid) != 0)
pidfilename = NULL;
@ -1028,7 +937,7 @@ main(int argc, char **argv)
{
int ret, i;
int sudp = -1, shttpl = -1;
int snotify[MAX_LAN_ADDR];
int smonitor = -1;
LIST_HEAD(httplisthead, upnphttp) upnphttphead;
struct upnphttp * e = 0;
struct upnphttp * next;
@ -1087,11 +996,7 @@ main(int argc, char **argv)
DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify. EXITING\n");
}
#endif
for (i = 0; i < n_lan_addr; i++)
{
DPRINTF(E_INFO, L_GENERAL, "Enabled interface %s/%s\n",
lan_addr[i].str, inet_ntoa(lan_addr[i].mask));
}
smonitor = OpenAndConfMonitorSocket();
sudp = OpenAndConfSSDPReceiveSocket();
if (sudp < 0)
@ -1100,17 +1005,12 @@ main(int argc, char **argv)
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. Listen on the 1st LAN address */
/* 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);
/* open socket for sending notifications */
if (OpenAndConfSSDPNotifySockets(snotify) < 0)
DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending SSDP notify "
"messages. EXITING\n");
#ifdef TIVO_SUPPORT
if (GETFLAG(TIVO_MASK))
{
@ -1132,7 +1032,7 @@ main(int argc, char **argv)
sbeacon = -1;
#endif
SendSSDPGoodbye(snotify, n_lan_addr);
SendSSDPGoodbyes();
/* main loop */
while (!quitting)
@ -1150,9 +1050,12 @@ main(int argc, char **argv)
/* the comparison is not very precise but who cares ? */
if (timeofday.tv_sec >= (lastnotifytime.tv_sec + runtime_vars.notify_interval))
{
SendSSDPNotifies2(snotify,
(unsigned short)runtime_vars.port,
(runtime_vars.notify_interval << 1)+10);
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;
@ -1223,6 +1126,12 @@ main(int argc, char **argv)
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)
{
@ -1263,6 +1172,10 @@ main(int argc, char **argv)
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)))
@ -1350,11 +1263,13 @@ shutdown:
close(sbeacon);
#endif
if (SendSSDPGoodbye(snotify, n_lan_addr) < 0)
if (SendSSDPGoodbyes() < 0)
DPRINTF(E_ERROR, L_GENERAL, "Failed to broadcast good-bye notifications\n");
for (i=0; i < n_lan_addr; i++)
close(snotify[i]);
for (i = 0; i < n_lan_addr; i++)
{
close(lan_addr[i].snotify);
}
if (inotify_thread)
pthread_join(inotify_thread, NULL);

View File

@ -31,21 +31,24 @@
#include "config.h"
#include "clients.h"
//#include <netinet/in.h>
#include <time.h>
#include <fcntl.h>
#define MAX_LAN_ADDR 4
/* structure for storing lan addresses
* with ascii representation and mask */
struct lan_addr_s {
char str[16]; /* example: 192.168.0.1 */
struct in_addr addr, mask; /* ip/mask */
struct in_addr addr; /* ip */
struct in_addr mask; /* netmask */
int snotify; /* notify socket */
};
struct runtime_vars_s {
int port; /* HTTP Port */
int notify_interval; /* seconds between SSDP announces */
char *root_container; /* root ObjectID (instead of "0") */
char *ifaces[MAX_LAN_ADDR]; /* list of configured network interfaces */
};
struct string_s {

View File

@ -123,7 +123,7 @@ OpenAndConfSSDPReceiveSocket(void)
/* open the UDP socket used to send SSDP notifications to
* the multicast group reserved for them */
static int
int
OpenAndConfSSDPNotifySocket(in_addr_t addr)
{
int s;
@ -179,26 +179,6 @@ OpenAndConfSSDPNotifySocket(in_addr_t addr)
return s;
}
int
OpenAndConfSSDPNotifySockets(int *sockets)
{
int i, j;
for (i = 0; i < n_lan_addr; i++)
{
sockets[i] = OpenAndConfSSDPNotifySocket(lan_addr[i].addr.s_addr);
if (sockets[i] < 0)
{
for (j = 0; j < i; j++)
{
close(sockets[j]);
sockets[j] = -1;
}
return -1;
}
}
return 0;
}
static const char * const known_service_types[] =
{
uuidvalue,
@ -223,7 +203,7 @@ _usleep(long usecs)
/* not really an SSDP "announce" as it is the response
* to a SSDP "M-SEARCH" */
static void
SendSSDPAnnounce2(int s, struct sockaddr_in sockname, int st_no,
SendSSDPResponse(int s, struct sockaddr_in sockname, int st_no,
const char *host, unsigned short port)
{
int l, n;
@ -265,18 +245,20 @@ SendSSDPAnnounce2(int s, struct sockaddr_in sockname, int st_no,
DPRINTF(E_ERROR, L_SSDP, "sendto(udp): %s\n", strerror(errno));
}
static void
void
SendSSDPNotifies(int s, const char *host, unsigned short port,
unsigned int lifetime)
unsigned int interval)
{
struct sockaddr_in sockname;
int l, n, dup, i=0;
unsigned int lifetime;
char bufr[512];
memset(&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(SSDP_PORT);
sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR);
lifetime = (interval << 1) + 10;
for (dup = 0; dup < 2; dup++)
{
@ -319,20 +301,6 @@ SendSSDPNotifies(int s, const char *host, unsigned short port,
}
}
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);
}
}
void
ParseUPnPClient(char *location)
{
@ -697,7 +665,7 @@ ProcessSSDPRequest(int s, unsigned short port)
break;
}
_usleep(random()>>20);
SendSSDPAnnounce2(s, sendername, i,
SendSSDPResponse(s, sendername, i,
lan_addr[lan_addr_index].str, port);
break;
}
@ -709,7 +677,7 @@ ProcessSSDPRequest(int s, unsigned short port)
for (i=0; known_service_types[i]; i++)
{
l = strlen(known_service_types[i]);
SendSSDPAnnounce2(s, sendername, i,
SendSSDPResponse(s, sendername, i,
lan_addr[lan_addr_index].str, port);
}
}
@ -730,7 +698,7 @@ ProcessSSDPRequest(int s, unsigned short port)
/* This will broadcast ssdp:byebye notifications to inform
* the network that UPnP is going down. */
int
SendSSDPGoodbye(int *sockets, int n_sockets)
SendSSDPGoodbyes(void)
{
struct sockaddr_in sockname;
int n, l;
@ -745,7 +713,7 @@ SendSSDPGoodbye(int *sockets, int n_sockets)
for (dup = 0; dup < 2; dup++)
{
for (j = 0; j < n_sockets; j++)
for (j = 0; j < n_lan_addr; j++)
{
for (i = 0; known_service_types[i]; i++)
{
@ -760,11 +728,11 @@ SendSSDPGoodbye(int *sockets, int n_sockets)
known_service_types[i], (i>1?"1":""),
uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") );
//DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr);
n = sendto(sockets[j], bufr, l, 0,
n = sendto(lan_addr[j].snotify, bufr, l, 0,
(struct sockaddr *)&sockname, sizeof(struct sockaddr_in) );
if (n < 0)
{
DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno));
DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", lan_addr[j].snotify, strerror(errno));
ret = -1;
break;
}

View File

@ -29,25 +29,16 @@
#ifndef __MINISSDP_H__
#define __MINISSDP_H__
int
OpenAndConfSSDPReceiveSocket();
int OpenAndConfSSDPReceiveSocket(void);
int
OpenAndConfSSDPNotifySockets(int * sockets);
int OpenAndConfSSDPNotifySocket(in_addr_t addr);
void
SendSSDPNotifies2(int * sockets,
unsigned short port,
unsigned int lifetime);
void SendSSDPNotifies(int s, const char *host, unsigned short port, unsigned int lifetime);
void
ProcessSSDPRequest(int s, unsigned short port);
void ProcessSSDPRequest(int s, unsigned short port);
int
SendSSDPGoodbye(int * sockets, int n);
int SendSSDPGoodbyes(void);
int
SubmitServicesToMiniSSDPD(const char * host, unsigned short port);
int SubmitServicesToMiniSSDPD(const char *host, unsigned short port);
#endif

View File

@ -43,7 +43,6 @@ static const struct {
const char * name;
} optionids[] = {
{ UPNPIFNAME, "network_interface" },
{ UPNPLISTENING_IP, "listening_ip" },
{ UPNPPORT, "port" },
{ UPNPPRESENTATIONURL, "presentation_url" },
{ UPNPNOTIFY_INTERVAL, "notify_interval" },

View File

@ -198,16 +198,16 @@ extern const char *pidfilename;
extern char uuidvalue[];
#define MODELNAME_MAX_LEN (64)
#define MODELNAME_MAX_LEN 64
extern char modelname[];
#define MODELNUMBER_MAX_LEN (16)
#define MODELNUMBER_MAX_LEN 16
extern char modelnumber[];
#define SERIALNUMBER_MAX_LEN (16)
#define SERIALNUMBER_MAX_LEN 16
extern char serialnumber[];
#define PRESENTATIONURL_MAX_LEN (64)
#define PRESENTATIONURL_MAX_LEN 64
extern char presentationurl[];
#if PNPX
@ -217,7 +217,6 @@ extern char pnpx_hwid[];
/* lan addresses */
/* MAX_LAN_ADDR : maximum number of interfaces
* to listen to SSDP traffic */
#define MAX_LAN_ADDR (4)
extern int n_lan_addr;
extern struct lan_addr_s lan_addr[];
@ -225,7 +224,7 @@ extern const char * minissdpdsocketpath;
/* UPnP-A/V [DLNA] */
extern sqlite3 *db;
#define FRIENDLYNAME_MAX_LEN (64)
#define FRIENDLYNAME_MAX_LEN 64
extern char friendly_name[];
extern char db_path[];
extern char log_path[];