diff --git a/NEWS b/NEWS index 88c388c..5a11b05 100644 --- a/NEWS +++ b/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 -------------------------------- diff --git a/configure.ac b/configure.ac index 6f7dde8..7103465 100644 --- a/configure.ac +++ b/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 - ], - [ - #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 + ], + [ + #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 diff --git a/getifaddr.c b/getifaddr.c index 9c437b7..704be9f 100644 --- a/getifaddr.c +++ b/getifaddr.c @@ -53,35 +53,18 @@ #include #endif #endif +#ifdef HAVE_NETLINK +#include +#include +#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 +} diff --git a/getifaddr.h b/getifaddr.h index 016985c..1592fc2 100644 --- a/getifaddr.h +++ b/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 diff --git a/minidlna.c b/minidlna.c index efa18a2..32cb0fd 100644 --- a/minidlna.c +++ b/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= 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); diff --git a/minidlnatypes.h b/minidlnatypes.h index addb754..8dff040 100644 --- a/minidlnatypes.h +++ b/minidlnatypes.h @@ -31,21 +31,24 @@ #include "config.h" #include "clients.h" -//#include #include #include +#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 { diff --git a/minissdp.c b/minissdp.c index 59267e5..92634b2 100644 --- a/minissdp.c +++ b/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; } diff --git a/minissdp.h b/minissdp.h index 38f67dc..5f93d24 100644 --- a/minissdp.h +++ b/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 - diff --git a/options.c b/options.c index 1ae6680..842335b 100644 --- a/options.c +++ b/options.c @@ -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" }, diff --git a/upnpglobalvars.h b/upnpglobalvars.h index 9360312..24eed45 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -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[];