Don't require a configured network interface to start up, and add network interface monitoring support on Linux.
This commit is contained in:
parent
1e4cf74436
commit
62b6e235b1
2
NEWS
2
NEWS
@ -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
|
||||
--------------------------------
|
||||
|
39
configure.ac
39
configure.ac
@ -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
|
||||
|
258
getifaddr.c
258
getifaddr.c
@ -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
|
||||
}
|
||||
|
19
getifaddr.h
19
getifaddr.h
@ -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
|
||||
|
||||
|
195
minidlna.c
195
minidlna.c
@ -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);
|
||||
|
@ -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 {
|
||||
|
56
minissdp.c
56
minissdp.c
@ -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;
|
||||
}
|
||||
|
21
minissdp.h
21
minissdp.h
@ -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
|
||||
|
||||
|
@ -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" },
|
||||
|
@ -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[];
|
||||
|
Loading…
x
Reference in New Issue
Block a user