--- a/minidlna.c
+++ b/minidlna.c
@@ -1,50 +1,12 @@
 /* MiniDLNA project
  *
  * http://sourceforge.net/projects/minidlna/
+ * (c) 2008 Justin Maggard
+ * This software is subject to the conditions detailed
+ * in the LICENCE file provided within the distribution
  *
- * MiniDLNA media server
- * Copyright (C) 2008-2012  Justin Maggard
- *
- * This file is part of MiniDLNA.
- *
- * MiniDLNA is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * MiniDLNA is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
- *
- * Portions of the code from the MiniUPnP project:
- *
- * Copyright (c) 2006-2007, Thomas Bernard
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *     * Redistributions of source code must retain the above copyright
- *       notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above copyright
- *       notice, this list of conditions and the following disclaimer in the
- *       documentation and/or other materials provided with the distribution.
- *     * The name of the author may not be used to endorse or promote products
- *       derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
- * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
+ * Portions of the code (c) Thomas Bernard, subject to
+ * the conditions detailed in the LICENSE.miniupnpd file.
  */
 #include <stdlib.h>
 #include <unistd.h>
@@ -53,55 +15,47 @@
 #include <ctype.h>
 #include <sys/types.h>
 #include <sys/socket.h>
-#include <sys/wait.h>
-#include <sys/file.h>
-#include <sys/time.h>
-#include <sys/param.h>
-#include <sys/stat.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <fcntl.h>
+#include <sys/file.h>
+#include <syslog.h>
+#include <sys/time.h>
 #include <time.h>
 #include <signal.h>
-#include <errno.h>
-#include <pthread.h>
-#include <limits.h>
-#include <libgen.h>
-#include <pwd.h>
-#include <grp.h>
-
+#include <sys/param.h>
+#if defined(sun)
+#include <kstat.h>
+#else
+/* for BSD's sysctl */
+#include <sys/sysctl.h>
+#endif
+
+#include <sqlite3.h>
+
+/* unix sockets */
 #include "config.h"
 
-#ifdef ENABLE_NLS
-#include <locale.h>
-#include <libintl.h>
-#endif
-
 #include "upnpglobalvars.h"
-#include "sql.h"
 #include "upnphttp.h"
 #include "upnpdescgen.h"
-#include "minidlnapath.h"
+#include "miniupnpdpath.h"
 #include "getifaddr.h"
 #include "upnpsoap.h"
 #include "options.h"
-#include "utils.h"
 #include "minissdp.h"
-#include "minidlnatypes.h"
-#include "process.h"
+#include "miniupnpdtypes.h"
+#include "daemonize.h"
 #include "upnpevents.h"
 #include "scanner.h"
-#include "monitor.h"
-#include "log.h"
-#include "tivo_beacon.h"
-#include "tivo_utils.h"
-#include "avahi.h"
-
-#if SQLITE_VERSION_NUMBER < 3005001
-# warning "Your SQLite3 library appears to be too old!  Please use 3.5.1 or newer."
-# define sqlite3_threadsafe() 0
-#endif
- 
+#include "commonrdr.h"
+
+/* MAX_LAN_ADDR : maximum number of interfaces
+ * to listen to SSDP traffic */
+/*#define MAX_LAN_ADDR (4)*/
+
+static volatile int quitting = 0;
+
 /* OpenAndConfHTTPSocket() :
  * setup the socket used to handle incoming HTTP connections. */
 static int
@@ -111,34 +65,32 @@
 	int i = 1;
 	struct sockaddr_in listenname;
 
-	/* Initialize client type cache */
-	memset(&clients, 0, sizeof(struct client_cache_s));
-
-	s = socket(PF_INET, SOCK_STREAM, 0);
-	if (s < 0)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, "socket(http): %s\n", strerror(errno));
+	if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
+	{
+		syslog(LOG_ERR, "socket(http): %m");
 		return -1;
 	}
 
-	if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
-		DPRINTF(E_WARN, L_GENERAL, "setsockopt(http, SO_REUSEADDR): %s\n", strerror(errno));
+	if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
+	{
+		syslog(LOG_WARNING, "setsockopt(http, SO_REUSEADDR): %m");
+	}
 
 	memset(&listenname, 0, sizeof(struct sockaddr_in));
 	listenname.sin_family = AF_INET;
 	listenname.sin_port = htons(port);
 	listenname.sin_addr.s_addr = htonl(INADDR_ANY);
 
-	if (bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, "bind(http): %s\n", strerror(errno));
+	if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
+	{
+		syslog(LOG_ERR, "bind(http): %m");
 		close(s);
 		return -1;
 	}
 
-	if (listen(s, 16) < 0)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, "listen(http): %s\n", strerror(errno));
+	if(listen(s, 6) < 0)
+	{
+		syslog(LOG_ERR, "listen(http): %m");
 		close(s);
 		return -1;
 	}
@@ -151,372 +103,137 @@
 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);
+	syslog(LOG_NOTICE, "received signal %d, good-bye", sig);
 
 	quitting = 1;
+	/*errno = save_errno;*/
 }
 
+/* record the startup time, for returning uptime */
 static void
-sigusr1(int sig)
-{
-	signal(sig, sigusr1);
-	DPRINTF(E_WARN, L_GENERAL, "received signal %d, clear cache\n", sig);
-
-	memset(&clients, '\0', sizeof(clients));
-}
-
-static void
-sighup(int sig)
-{
-	signal(sig, sighup);
-	DPRINTF(E_WARN, L_GENERAL, "received signal %d, re-read\n", sig);
-
-	reload_ifaces(1);
-}
-
-/* record the startup time */
-static void
-set_startup_time(void)
+set_startup_time(int sysuptime)
 {
 	startup_time = time(NULL);
+	if(sysuptime)
+	{
+		/* use system uptime instead of daemon uptime */
+		char buff[64];
+		int uptime, fd;
+		fd = open("/proc/uptime", O_RDONLY);
+		if(fd < 0)
+		{
+			syslog(LOG_ERR, "open(\"/proc/uptime\" : %m");
+		}
+		else
+		{
+			memset(buff, 0, sizeof(buff));
+			read(fd, buff, sizeof(buff) - 1);
+			uptime = atoi(buff);
+			syslog(LOG_INFO, "system uptime is %d seconds", uptime);
+			close(fd);
+			startup_time -= uptime;
+		}
+	}
 }
 
-static void
-getfriendlyname(char *buf, int len)
+/* structure containing variables used during "main loop"
+ * that are filled during the init */
+struct runtime_vars {
+	/* LAN IP addresses for SSDP traffic and HTTP */
+	/* moved to global vars */
+	/*int n_lan_addr;*/
+	/*struct lan_addr_s lan_addr[MAX_LAN_ADDR];*/
+	int port;	/* HTTP Port */
+	int notify_interval;	/* seconds between SSDP announces */
+	/* unused rules cleaning related variables : */
+	int clean_ruleset_threshold;	/* threshold for removing unused rules */
+	int clean_ruleset_interval;		/* (minimum) interval between checks */
+};
+
+/* 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)
 {
-	char *p = NULL;
-	char hn[256];
-	int off;
-
-	if (gethostname(hn, sizeof(hn)) == 0)
-	{
-		strncpyt(buf, hn, len);
-		p = strchr(buf, '.');
-		if (p)
-			*p = '\0';
-	}
-	else
-		strcpy(buf, "Unknown");
-
-	off = strlen(buf);
-	off += snprintf(buf+off, len-off, ": ");
-#ifdef READYNAS
-	FILE *info;
-	char ibuf[64], *key, *val;
-	snprintf(buf+off, len-off, "ReadyNAS");
-	info = fopen("/proc/sys/dev/boot/info", "r");
-	if (!info)
-		return;
-	while ((val = fgets(ibuf, 64, info)) != NULL)
-	{
-		key = strsep(&val, ": \t");
-		val = trim(val);
-		if (strcmp(key, "model") == 0)
-		{
-			snprintf(buf+off, len-off, "%s", val);
-			key = strchr(val, ' ');
-			if (key)
-			{
-				strncpyt(modelnumber, key+1, MODELNUMBER_MAX_LEN);
-				*key = '\0';
-			}
-			snprintf(modelname, MODELNAME_MAX_LEN,
-				"Windows Media Connect compatible (%s)", val);
-		}
-		else if (strcmp(key, "serial") == 0)
-		{
-			strncpyt(serialnumber, val, SERIALNUMBER_MAX_LEN);
-			if (serialnumber[0] == '\0')
-			{
-				char mac_str[13];
-				if (getsyshwaddr(mac_str, sizeof(mac_str)) == 0)
-					strcpy(serialnumber, mac_str);
-				else
-					strcpy(serialnumber, "0");
-			}
-			break;
-		}
-	}
-	fclose(info);
-#else
-	char * logname;
-	logname = getenv("LOGNAME");
-#ifndef STATIC // Disable for static linking
-	if (!logname)
-	{
-		struct passwd * pwent;
-		pwent = getpwuid(getuid());
-		if (pwent)
-			logname = pwent->pw_name;
-	}
-#endif
-	snprintf(buf+off, len-off, "%s", logname?logname:"Unknown");
-#endif
-}
-
-static time_t
-_get_dbtime(void)
-{
-	char path[PATH_MAX];
-	struct stat st;
-
-	snprintf(path, sizeof(path), "%s/files.db", db_path);
-	if (stat(path, &st) != 0)
-		return 0;
-	return st.st_mtime;
-}
-
-static int
-open_db(sqlite3 **sq3)
-{
-	char path[PATH_MAX];
-	int new_db = 0;
-
-	snprintf(path, sizeof(path), "%s/files.db", db_path);
-	if (access(path, F_OK) != 0)
-	{
-		new_db = 1;
-		make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
-	}
-	if (sqlite3_open(path, &db) != SQLITE_OK)
-		DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to open sqlite database!  Exiting...\n");
-	if (sq3)
-		*sq3 = db;
-	sqlite3_busy_timeout(db, 5000);
-	sql_exec(db, "pragma page_size = 4096");
-	sql_exec(db, "pragma journal_mode = OFF");
-	sql_exec(db, "pragma synchronous = OFF;");
-	sql_exec(db, "pragma default_cache_size = 8192;");
-
-	return new_db;
-}
-
-static void
-check_db(sqlite3 *db, int new_db, pid_t *scanner_pid)
-{
-	struct media_dir_s *media_path = NULL;
-	char cmd[PATH_MAX*2];
-	char **result;
-	int i, rows = 0;
-	int ret;
-
-	if (!new_db)
-	{
-		/* Check if any new media dirs appeared */
-		media_path = media_dirs;
-		while (media_path)
-		{
-			ret = sql_get_int_field(db, "SELECT TIMESTAMP as TYPE from DETAILS where PATH = %Q",
-						media_path->path);
-			if (ret != media_path->types)
-			{
-				ret = 1;
-				goto rescan;
-			}
-			media_path = media_path->next;
-		}
-		/* Check if any media dirs disappeared */
-		sql_get_table(db, "SELECT VALUE from SETTINGS where KEY = 'media_dir'", &result, &rows, NULL);
-		for (i=1; i <= rows; i++)
-		{
-			media_path = media_dirs;
-			while (media_path)
-			{
-				if (strcmp(result[i], media_path->path) == 0)
-					break;
-				media_path = media_path->next;
-			}
-			if (!media_path)
-			{
-				ret = 2;
-				sqlite3_free_table(result);
-				goto rescan;
-			}
-		}
-		sqlite3_free_table(result);
-	}
-
-	ret = db_upgrade(db);
-	if (ret != 0)
-	{
-rescan:
-		CLEARFLAG(RESCAN_MASK);
-		if (ret < 0)
-			DPRINTF(E_WARN, L_GENERAL, "Creating new database at %s/files.db\n", db_path);
-		else if (ret == 1)
-			DPRINTF(E_WARN, L_GENERAL, "New media_dir detected; rebuilding...\n");
-		else if (ret == 2)
-			DPRINTF(E_WARN, L_GENERAL, "Removed media_dir detected; rebuilding...\n");
-		else
-			DPRINTF(E_WARN, L_GENERAL, "Database version mismatch (%d => %d); need to recreate...\n",
-				ret, DB_VERSION);
-		sqlite3_close(db);
-
-		snprintf(cmd, sizeof(cmd), "rm -rf %s/files.db %s/art_cache", db_path, db_path);
-		if (system(cmd) != 0)
-			DPRINTF(E_FATAL, L_GENERAL, "Failed to clean old file cache!  Exiting...\n");
-
-		open_db(&db);
-		if (CreateDatabase() != 0)
-			DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database!  Exiting...\n");
-	}
-	if (ret || GETFLAG(RESCAN_MASK))
-	{
-#if USE_FORK
-		SETFLAG(SCANNING_MASK);
-		sqlite3_close(db);
-		*scanner_pid = fork();
-		open_db(&db);
-		if (*scanner_pid == 0) /* child (scanner) process */
-		{
-			start_scanner();
-			sqlite3_close(db);
-			log_close();
-			freeoptions();
-			free(children);
-			exit(EXIT_SUCCESS);
-		}
-		else if (*scanner_pid < 0)
-		{
-			start_scanner();
-		}
-#else
-		start_scanner();
-#endif
-	}
-}
-
-static int
-writepidfile(const char *fname, int pid, uid_t uid)
-{
-	FILE *pidfile;
-	struct stat st;
-	char path[PATH_MAX], *dir;
-	int ret = 0;
-
-	if(!fname || *fname == '\0')
+	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)
+	{
+		fprintf(stderr, "Error parsing address/mask : %s\n", str);
 		return -1;
-
-	/* Create parent directory if it doesn't already exist */
-	strncpyt(path, fname, sizeof(path));
-	dir = dirname(path);
-	if (stat(dir, &st) == 0)
-	{
-		if (!S_ISDIR(st.st_mode))
-		{
-			DPRINTF(E_ERROR, L_GENERAL, "Pidfile path is not a directory: %s\n",
-				fname);
-			return -1;
-		}
-	}
-	else
-	{
-		if (make_dir(dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0)
-		{
-			DPRINTF(E_ERROR, L_GENERAL, "Unable to create pidfile directory: %s\n",
-				fname);
-			return -1;
-		}
-		if (uid > 0)
-		{
-			if (chown(dir, uid, -1) != 0)
-				DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile %s ownership: %s\n",
-					dir, strerror(errno));
-		}
-	}
-	
-	pidfile = fopen(fname, "w");
-	if (!pidfile)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, "Unable to open pidfile for writing %s: %s\n",
-			fname, strerror(errno));
+	}
+	memcpy(lan_addr->str, str, n);
+	lan_addr->str[n] = '\0';
+	if(!inet_aton(lan_addr->str, &lan_addr->addr))
+	{
+		fprintf(stderr, "Error parsing address/mask : %s\n", str);
 		return -1;
 	}
-
-	if (fprintf(pidfile, "%d\n", pid) <= 0)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, 
-			"Unable to write to pidfile %s: %s\n", fname, strerror(errno));
-		ret = -1;
-	}
-	if (uid > 0)
-	{
-		if (fchown(fileno(pidfile), uid, -1) != 0)
-			DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile %s ownership: %s\n",
-				fname, strerror(errno));
-	}
-
-	fclose(pidfile);
-
-	return ret;
-}
-
-static int strtobool(const char *str)
-{
-	return ((strcasecmp(str, "yes") == 0) ||
-		(strcasecmp(str, "true") == 0) ||
-		(atoi(str) == 1));
-}
-
-static void init_nls(void)
-{
-#ifdef ENABLE_NLS
-	const char *messages, *ctype, *locale_dir;
-
-	ctype = setlocale(LC_CTYPE, "");
-	if (!ctype || !strcmp(ctype, "C"))
-		ctype = setlocale(LC_CTYPE, "en_US.utf8");
-	if (!ctype)
-		DPRINTF(E_WARN, L_GENERAL, "Unset locale\n");
-	else if (!strstr(ctype, "utf8") && !strstr(ctype, "UTF8") &&
-		 !strstr(ctype, "utf-8") && !strstr(ctype, "UTF-8"))
-		DPRINTF(E_WARN, L_GENERAL, "Using unsupported non-utf8 locale '%s'\n", ctype);
-	messages = setlocale(LC_MESSAGES, "");
-	if (!messages)
-		messages = "unset";
-	locale_dir = bindtextdomain("minidlna", getenv("TEXTDOMAINDIR"));
-	DPRINTF(E_DEBUG, L_GENERAL, "Using locale dir '%s' and locale langauge %s/%s\n", locale_dir, messages, ctype);
-	textdomain("minidlna");
-#endif
+	lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);
+#ifdef MULTIPLE_EXTERNAL_IP
+	while(*p && isspace(*p))
+		p++;
+	if(*p) {
+		n = 0;
+		while(p[n] && !isspace(*p))
+			n++;
+		if(n<=15) {
+			memcpy(lan_addr->ext_ip_str, p, n);
+			lan_addr->ext_ip_str[n] = '\0';
+			if(!inet_aton(lan_addr->ext_ip_str, &lan_addr->ext_ip_addr)) {
+				/* error */
+				fprintf(stderr, "Error parsing address : %s\n", lan_addr->ext_ip_str);
+			}
+		}
+	}
+#endif
+	return 0;
 }
 
 /* init phase :
  * 1) read configuration file
  * 2) read command line arguments
  * 3) daemonize
- * 4) check and write pid file
- * 5) set startup time stamp
- * 6) compute presentation URL
- * 7) set signal handlers */
+ * 4) open syslog
+ * 5) check and write pid file
+ * 6) set startup time stamp
+ * 7) compute presentation URL
+ * 8) set signal handlers */
 static int
-init(int argc, char **argv)
+init(int argc, char * * argv, struct runtime_vars * v)
 {
 	int i;
 	int pid;
 	int debug_flag = 0;
-	int verbose_flag = 0;
 	int options_flag = 0;
+	int openlog_option;
 	struct sigaction sa;
-	const char * presurl = NULL;
+	/*const char * logfilename = 0;*/
+	const char * presurl = 0;
 	const char * optionsfile = "/etc/minidlna.conf";
-	char mac_str[13];
-	char *string, *word;
-	char *path;
-	char buf[PATH_MAX];
-	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 = 0;
-	gid_t gid = 0;
 
 	/* first check if "-f" option is used */
-	for (i=2; i<argc; i++)
-	{
-		if (strcmp(argv[i-1], "-f") == 0)
+	for(i=2; i<argc; i++)
+	{
+		if(0 == strcmp(argv[i-1], "-f"))
 		{
 			optionsfile = argv[i];
 			options_flag = 1;
@@ -524,515 +241,378 @@
 		}
 	}
 
-	/* set up uuid based on mac address */
-	if (getsyshwaddr(mac_str, sizeof(mac_str)) < 0)
-	{
-		DPRINTF(E_OFF, L_GENERAL, "No MAC address found.  Falling back to generic UUID.\n");
-		strcpy(mac_str, "554e4b4e4f57");
-	}
-	strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-");
-	strncat(uuidvalue, mac_str, 12);
-
-	getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN);
-	
-	runtime_vars.port = 8200;
-	runtime_vars.notify_interval = 895;	/* seconds between SSDP announces */
-	runtime_vars.max_connections = 50;
-	runtime_vars.root_container = NULL;
-	runtime_vars.ifaces[0] = NULL;
+	/*v->n_lan_addr = 0;*/
+	char ext_ip_addr[INET_ADDRSTRLEN];
+	if( (getifaddr("eth0", ext_ip_addr, INET_ADDRSTRLEN) < 0) &&
+	    (getifaddr("eth1", ext_ip_addr, INET_ADDRSTRLEN) < 0) )
+	{
+		printf("No IP!\n");
+		return 1;
+	}
+	if( parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 )
+		n_lan_addr++;
+	v->port = -1;
+	v->notify_interval = 30;	/* seconds between SSDP announces */
+	v->clean_ruleset_threshold = 20;
+	v->clean_ruleset_interval = 0;	/* interval between ruleset check. 0=disabled */
 
 	/* read options file first since
 	 * command line arguments have final say */
-	if (readoptionsfile(optionsfile) < 0)
+	if(readoptionsfile(optionsfile) < 0)
 	{
 		/* only error if file exists or using -f */
 		if(access(optionsfile, F_OK) == 0 || options_flag)
-			DPRINTF(E_FATAL, L_GENERAL, "Error reading configuration file %s\n", optionsfile);
-	}
-
-	for (i=0; i<num_options; i++)
-	{
-		switch (ary_options[i].id)
-		{
-		case UPNPIFNAME:
-			for (string = ary_options[i].value; (word = strtok(string, ",")); string = NULL)
-			{
-				if (ifaces >= MAX_LAN_ADDR)
+			fprintf(stderr, "Error reading configuration file %s\n", optionsfile);
+	}
+	else
+	{
+		for(i=0; i<num_options; i++)
+		{
+			switch(ary_options[i].id)
+			{
+			case UPNPEXT_IFNAME:
+				ext_if_name = ary_options[i].value;
+				break;
+			case UPNPEXT_IP:
+				use_ext_ip_addr = ary_options[i].value;
+				break;
+			case UPNPLISTENING_IP:
+				if(n_lan_addr < MAX_LAN_ADDR)/* if(v->n_lan_addr < MAX_LAN_ADDR)*/
 				{
-					DPRINTF(E_ERROR, L_GENERAL, "Too many interfaces (max: %d), ignoring %s\n",
-						MAX_LAN_ADDR, word);
-					break;
-				}
-				while (isspace(*word))
-					word++;
-				runtime_vars.ifaces[ifaces++] = word;
-			}
-			break;
-		case UPNPPORT:
-			runtime_vars.port = atoi(ary_options[i].value);
-			break;
-		case UPNPPRESENTATIONURL:
-			presurl = ary_options[i].value;
-			break;
-		case UPNPNOTIFY_INTERVAL:
-			runtime_vars.notify_interval = atoi(ary_options[i].value);
-			break;
-		case UPNPSERIAL:
-			strncpyt(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
-			break;				
-		case UPNPMODEL_NAME:
-			strncpyt(modelname, ary_options[i].value, MODELNAME_MAX_LEN);
-			break;
-		case UPNPMODEL_NUMBER:
-			strncpyt(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
-			break;
-		case UPNPFRIENDLYNAME:
-			strncpyt(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN);
-			break;
-		case UPNPMEDIADIR:
-			types = ALL_MEDIA;
-			path = ary_options[i].value;
-			word = strchr(path, ',');
-			if (word && (access(path, F_OK) != 0))
-			{
-				types = 0;
-				while (*path)
-				{
-					if (*path == ',')
-					{
-						path++;
-						break;
-					}
-					else if (*path == 'A' || *path == 'a')
-						types |= TYPE_AUDIO;
-					else if (*path == 'V' || *path == 'v')
-						types |= TYPE_VIDEO;
-					else if (*path == 'P' || *path == 'p')
-						types |= TYPE_IMAGE;
-					else
-						DPRINTF(E_FATAL, L_GENERAL, "Media directory entry not understood [%s]\n",
-							ary_options[i].value);
-					path++;
-				}
-			}
-			path = realpath(path, buf);
-			if (!path || access(path, F_OK) != 0)
-			{
-				DPRINTF(E_ERROR, L_GENERAL, "Media directory \"%s\" not accessible [%s]\n",
-					ary_options[i].value, strerror(errno));
-				break;
-			}
-			media_dir = calloc(1, sizeof(struct media_dir_s));
-			media_dir->path = strdup(path);
-			media_dir->types = types;
-			if (media_dirs)
-			{
-				struct media_dir_s *all_dirs = media_dirs;
-				while( all_dirs->next )
-					all_dirs = all_dirs->next;
-				all_dirs->next = media_dir;
-			}
-			else
-				media_dirs = media_dir;
-			break;
-		case UPNPALBUMART_NAMES:
-			for (string = ary_options[i].value; (word = strtok(string, "/")); string = NULL)
-			{
-				struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s));
-				int len = strlen(word);
-				if (word[len-1] == '*')
-				{
-					word[len-1] = '\0';
-					this_name->wildcard = 1;
-				}
-				this_name->name = strdup(word);
-				if (album_art_names)
-				{
-					struct album_art_name_s * all_names = album_art_names;
-					while( all_names->next )
-						all_names = all_names->next;
-					all_names->next = this_name;
+					/*if(parselanaddr(&v->lan_addr[v->n_lan_addr],*/
+					if(parselanaddr(&lan_addr[n_lan_addr],
+					             ary_options[i].value) == 0)
+						n_lan_addr++; /*v->n_lan_addr++; */
 				}
 				else
-					album_art_names = this_name;
-			}
-			break;
-		case UPNPDBDIR:
-			path = realpath(ary_options[i].value, buf);
-			if (!path)
-				path = (ary_options[i].value);
-			make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
-			if (access(path, F_OK) != 0)
-				DPRINTF(E_FATAL, L_GENERAL, "Database path not accessible! [%s]\n", path);
-			strncpyt(db_path, path, PATH_MAX);
-			break;
-		case UPNPLOGDIR:
-			path = realpath(ary_options[i].value, buf);
-			if (!path)
-				path = (ary_options[i].value);
-			make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
-			if (access(path, F_OK) != 0)
-				DPRINTF(E_FATAL, L_GENERAL, "Log path not accessible! [%s]\n", path);
-			strncpyt(log_path, path, PATH_MAX);
-			break;
-		case UPNPLOGLEVEL:
-			log_level = ary_options[i].value;
-			break;
-		case UPNPINOTIFY:
-			if (!strtobool(ary_options[i].value))
-				CLEARFLAG(INOTIFY_MASK);
-			break;
-		case ENABLE_TIVO:
-			if (strtobool(ary_options[i].value))
-				SETFLAG(TIVO_MASK);
-			break;
-		case ENABLE_DLNA_STRICT:
-			if (strtobool(ary_options[i].value))
-				SETFLAG(DLNA_STRICT_MASK);
-			break;
-		case ROOT_CONTAINER:
-			switch (ary_options[i].value[0]) {
-			case '.':
-				runtime_vars.root_container = NULL;
-				break;
-			case 'B':
-			case 'b':
-				runtime_vars.root_container = BROWSEDIR_ID;
-				break;
-			case 'M':
-			case 'm':
-				runtime_vars.root_container = MUSIC_ID;
-				break;
-			case 'V':
-			case 'v':
-				runtime_vars.root_container = VIDEO_ID;
-				break;
-			case 'P':
-			case 'p':
-				runtime_vars.root_container = IMAGE_ID;
+				{
+					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
+			    		    MAX_LAN_ADDR, ary_options[i].value);
+				}
+				break;
+			case UPNPPORT:
+				v->port = atoi(ary_options[i].value);
+				break;
+			case UPNPBITRATE_UP:
+				upstream_bitrate = strtoul(ary_options[i].value, 0, 0);
+				break;
+			case UPNPBITRATE_DOWN:
+				downstream_bitrate = strtoul(ary_options[i].value, 0, 0);
+				break;
+			case UPNPPRESENTATIONURL:
+				presurl = ary_options[i].value;
+				break;
+			case UPNPNOTIFY_INTERVAL:
+				v->notify_interval = atoi(ary_options[i].value);
+				break;
+			case UPNPSYSTEM_UPTIME:
+				if(strcmp(ary_options[i].value, "yes") == 0)
+					SETFLAG(SYSUPTIMEMASK);	/*sysuptime = 1;*/
+				break;
+			case UPNPPACKET_LOG:
+				if(strcmp(ary_options[i].value, "yes") == 0)
+					SETFLAG(LOGPACKETSMASK);	/*logpackets = 1;*/
+				break;
+			case UPNPUUID:
+				strncpy(uuidvalue+5, ary_options[i].value,
+				        strlen(uuidvalue+5) + 1);
+				break;
+			case UPNPSERIAL:
+				strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
+				serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
+				break;				
+			case UPNPMODEL_NUMBER:
+				strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
+				modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
+				break;
+			case UPNPCLEANTHRESHOLD:
+				v->clean_ruleset_threshold = atoi(ary_options[i].value);
+				break;
+			case UPNPCLEANINTERVAL:
+				v->clean_ruleset_interval = atoi(ary_options[i].value);
+				break;
+#ifdef USE_PF
+			case UPNPQUEUE:
+				queue = ary_options[i].value;
+				break;
+			case UPNPTAG:
+				tag = ary_options[i].value;
+				break;
+#endif
+#ifdef PF_ENABLE_FILTER_RULES
+			case UPNPQUICKRULES:
+				if(strcmp(ary_options[i].value, "no") == 0)
+					SETFLAG(PFNOQUICKRULESMASK);
+				break;
+#endif
+			case UPNPSECUREMODE:
+				if(strcmp(ary_options[i].value, "yes") == 0)
+					SETFLAG(SECUREMODEMASK);
+				break;
+#ifdef ENABLE_LEASEFILE
+			case UPNPLEASEFILE:
+				lease_file = ary_options[i].value;
+				remove(lease_file);
+				break;
+#endif
+			case UPNPMEDIADIR:
+				strncpy(media_dir, ary_options[i].value, MEDIADIR_MAX_LEN);
+				media_dir[MEDIADIR_MAX_LEN-1] = '\0';
 				break;
 			default:
-				runtime_vars.root_container = ary_options[i].value;
-				DPRINTF(E_WARN, L_GENERAL, "Using arbitrary root container [%s]\n",
-					ary_options[i].value);
-				break;
-			}
-			break;
-		case UPNPMINISSDPDSOCKET:
-			minissdpdsocketpath = ary_options[i].value;
-			break;
-		case UPNPUUID:
-			strcpy(uuidvalue+5, ary_options[i].value);
-			break;
-		case USER_ACCOUNT:
-			uid = strtoul(ary_options[i].value, &string, 0);
-			if (*string)
-			{
-				/* Symbolic username given, not UID. */
-				struct passwd *entry = getpwnam(ary_options[i].value);
-				if (!entry)
-					DPRINTF(E_FATAL, L_GENERAL, "Bad user '%s'.\n",
-						ary_options[i].value);
-				uid = entry->pw_uid;
-				if (!gid)
-					gid = entry->pw_gid;
-			}
-			break;
-		case FORCE_SORT_CRITERIA:
-			force_sort_criteria = ary_options[i].value;
-			break;
-		case MAX_CONNECTIONS:
-			runtime_vars.max_connections = atoi(ary_options[i].value);
-			break;
-		case MERGE_MEDIA_DIRS:
-			if (strtobool(ary_options[i].value))
-				SETFLAG(MERGE_MEDIA_DIRS_MASK);
-			break;
-		case WIDE_LINKS:
-			if (strtobool(ary_options[i].value))
-				SETFLAG(WIDE_LINKS_MASK);
-			break;
-		case TIVO_DISCOVERY:
-			if (strcasecmp(ary_options[i].value, "beacon") == 0)
-				CLEARFLAG(TIVO_BONJOUR_MASK);
-			break;
-		default:
-			DPRINTF(E_ERROR, L_GENERAL, "Unknown option in file %s\n",
-				optionsfile);
-		}
-	}
-	if (log_path[0] == '\0')
-	{
-		if (db_path[0] == '\0')
-			strncpyt(log_path, DEFAULT_LOG_PATH, PATH_MAX);
-		else
-			strncpyt(log_path, db_path, PATH_MAX);
-	}
-	if (db_path[0] == '\0')
-		strncpyt(db_path, DEFAULT_DB_PATH, PATH_MAX);
+				fprintf(stderr, "Unknown option in file %s\n",
+				        optionsfile);
+			}
+		}
+	}
 
 	/* command line arguments processing */
-	for (i=1; i<argc; i++)
-	{
-		if (argv[i][0] != '-')
-		{
-			DPRINTF(E_FATAL, L_GENERAL, "Unknown option: %s\n", argv[i]);
-		}
-		else if (strcmp(argv[i], "--help") == 0)
-		{
-			runtime_vars.port = -1;
-			break;
+	for(i=1; i<argc; i++)
+	{
+		if(argv[i][0]!='-')
+		{
+			fprintf(stderr, "Unknown option: %s\n", argv[i]);
 		}
 		else switch(argv[i][1])
 		{
+		case 'o':
+			if(i+1 < argc)
+				use_ext_ip_addr = argv[++i];
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			break;
 		case 't':
-			if (i+1 < argc)
-				runtime_vars.notify_interval = atoi(argv[++i]);
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
+			if(i+1 < argc)
+				v->notify_interval = atoi(argv[++i]);
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			break;
+		case 'u':
+			if(i+1 < argc)
+				strncpy(uuidvalue+5, argv[++i], strlen(uuidvalue+5) + 1);
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
 			break;
 		case 's':
-			if (i+1 < argc)
-				strncpyt(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
+			if(i+1 < argc)
+				strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
 			break;
 		case 'm':
-			if (i+1 < argc)
-				strncpyt(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
-			break;
+			if(i+1 < argc)
+				strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
+			break;
+		case 'U':
+			/*sysuptime = 1;*/
+			SETFLAG(SYSUPTIMEMASK);
+			break;
+		/*case 'l':
+			logfilename = argv[++i];
+			break;*/
+		case 'L':
+			/*logpackets = 1;*/
+			SETFLAG(LOGPACKETSMASK);
+			break;
+		case 'S':
+			SETFLAG(SECUREMODEMASK);
+			break;
+		case 'i':
+			if(i+1 < argc)
+				ext_if_name = argv[++i];
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			break;
+#ifdef USE_PF
+		case 'q':
+			if(i+1 < argc)
+				queue = argv[++i];
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			break;
+		case 'T':
+			if(i+1 < argc)
+				tag = argv[++i];
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			break;
+#endif
 		case 'p':
-			if (i+1 < argc)
-				runtime_vars.port = atoi(argv[++i]);
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
+			if(i+1 < argc)
+				v->port = atoi(argv[++i]);
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
 			break;
 		case 'P':
-			if (i+1 < argc)
-			{
-				if (argv[++i][0] != '/')
-					DPRINTF(E_FATAL, L_GENERAL, "Option -%c requires an absolute filename.\n", argv[i-1][1]);
-				else
-					pidfilename = argv[i];
-			}
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
+			if(i+1 < argc)
+				pidfilename = argv[++i];
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
 			break;
 		case 'd':
 			debug_flag = 1;
-		case 'v':
-			verbose_flag = 1;
-			break;
-		case 'L':
-			SETFLAG(NO_PLAYLIST_MASK);
 			break;
 		case 'w':
-			if (i+1 < argc)
+			if(i+1 < argc)
 				presurl = argv[++i];
 			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
-			break;
-		case 'i':
-			if (i+1 < argc)
-			{
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
+			break;
+		case 'B':
+			if(i+2<argc)
+			{
+				downstream_bitrate = strtoul(argv[++i], 0, 0);
+				upstream_bitrate = strtoul(argv[++i], 0, 0);
+			}
+			else
+				fprintf(stderr, "Option -%c takes two arguments.\n", argv[i][1]);
+			break;
+		case 'a':
+			if(i+1 < argc)
+			{
+				int address_already_there = 0;
+				int j;
 				i++;
-				if (ifaces >= MAX_LAN_ADDR)
+				for(j=0; j<n_lan_addr; j++)/* for(j=0; j<v->n_lan_addr; j++)*/
 				{
-					DPRINTF(E_ERROR, L_GENERAL, "Too many interfaces (max: %d), ignoring %s\n",
-						MAX_LAN_ADDR, argv[i]);
+					struct lan_addr_s tmpaddr;
+					parselanaddr(&tmpaddr, argv[i]);
+					/*if(0 == strcmp(v->lan_addr[j].str, tmpaddr.str))*/
+					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(v->n_lan_addr < MAX_LAN_ADDR)*/
+				{
+					/*v->lan_addr[v->n_lan_addr++] = argv[i];*/
+					/*if(parselanaddr(&v->lan_addr[v->n_lan_addr], argv[i]) == 0)*/
+					if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
+						n_lan_addr++; /*v->n_lan_addr++;*/
 				}
-				runtime_vars.ifaces[ifaces++] = argv[i];
-			}
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
+				else
+				{
+					fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
+				    	    MAX_LAN_ADDR, argv[i]);
+				}
+			}
+			else
+				fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
 			break;
 		case 'f':
 			i++;	/* discarding, the config file is already read */
 			break;
-		case 'h':
-			runtime_vars.port = -1; // triggers help display
-			break;
-		case 'r':
-			SETFLAG(RESCAN_MASK);
-			break;
-		case 'R':
-			snprintf(buf, sizeof(buf), "rm -rf %s/files.db %s/art_cache", db_path, db_path);
-			if (system(buf) != 0)
-				DPRINTF(E_FATAL, L_GENERAL, "Failed to clean old file cache %s. EXITING\n", db_path);
-			break;
-		case 'u':
-			if (i+1 != argc)
-			{
-				i++;
-				uid = strtoul(argv[i], &string, 0);
-				if (*string)
-				{
-					/* Symbolic username given, not UID. */
-					struct passwd *entry = getpwnam(argv[i]);
-					if (!entry)
-						DPRINTF(E_FATAL, L_GENERAL, "Bad user '%s'.\n", argv[i]);
-					uid = entry->pw_uid;
-					if (!gid)
-						gid = entry->pw_gid;
-				}
-			}
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
-			break;
-		case 'g':
-			if (i+1 != argc)
-			{
-				i++;
-				gid = strtoul(argv[i], &string, 0);
-				if (*string)
-				{
-					/* Symbolic group given, not GID. */
-					struct group *grp = getgrnam(argv[i]);
-					if (!grp)
-						DPRINTF(E_FATAL, L_GENERAL, "Bad group '%s'.\n", argv[i]);
-					gid = grp->gr_gid;
-				}
-			}
-			else
-				DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
-			break;
-#ifdef __linux__
-		case 'S':
-			SETFLAG(SYSTEMD_MASK);
-			break;
-#endif
-		case 'V':
-			printf("Version " MINIDLNA_VERSION "\n");
-			exit(0);
-			break;
 		default:
-			DPRINTF(E_ERROR, L_GENERAL, "Unknown option: %s\n", argv[i]);
-			runtime_vars.port = -1; // triggers help display
-		}
-	}
-
-	if (runtime_vars.port <= 0)
-	{
-		printf("Usage:\n\t"
-			"%s [-d] [-v] [-f config_file] [-p port]\n"
-			"\t\t[-i network_interface] [-u uid_to_run_as] [-g group_to_run_as]\n"
-			"\t\t[-t notify_interval] [-P pid_filename]\n"
-			"\t\t[-s serial] [-m model_number]\n"
-#ifdef __linux__
-			"\t\t[-w url] [-r] [-R] [-L] [-S] [-V] [-h]\n"
+			fprintf(stderr, "Unknown option: %s\n", argv[i]);
+		}
+	}
+	if(!ext_if_name || (/*v->*/n_lan_addr==0) || v->port<=0)
+	{
+		fprintf(stderr, "Usage:\n\t"
+		        "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n"
+				"\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n"
+				/*"[-l logfile] " not functionnal */
+				"\t\t[-u uuid] [-s serial] [-m model_number] \n"
+				"\t\t[-t notify_interval] [-P pid_filename]\n"
+#ifdef USE_PF
+				"\t\t[-B down up] [-w url] [-q queue] [-T tag]\n"
 #else
-			"\t\t[-w url] [-r] [-R] [-L] [-V] [-h]\n"
-#endif
-			"\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n"
-			"\tDefault pid file is %s.\n"
-			"\tWith -d minidlna will run in debug mode (not daemonize).\n"
-			"\t-w sets the presentation url. Default is http address on port 80\n"
-			"\t-v enables verbose output\n"
-			"\t-h displays this text\n"
-			"\t-r forces a rescan\n"
-			"\t-R forces a rebuild\n"
-			"\t-L do not create playlists\n"
-#ifdef __linux__
-			"\t-S changes behaviour for systemd\n"
-#endif
-			"\t-V print the version number\n",
-			argv[0], pidfilename);
+				"\t\t[-B down up] [-w url]\n"
+#endif
+		        "\nNotes:\n\tThere can be one or several listening_ips.\n"
+		        "\tNotify interval is in seconds. Default is 30 seconds.\n"
+				"\tDefault pid file is %s.\n"
+				"\tWith -d miniupnpd will run as a standard program.\n"
+				"\t-L sets packet log in pf and ipf on.\n"
+				"\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n"
+				"\t-U causes miniupnpd to report system uptime instead "
+				"of daemon uptime.\n"
+				"\t-B sets bitrates reported by daemon in bits per second.\n"
+				"\t-w sets the presentation url. Default is http address on port 80\n"
+#ifdef USE_PF
+				"\t-q sets the ALTQ queue in pf.\n"
+				"\t-T sets the tag name in pf.\n"
+#endif
+		        "", argv[0], pidfilename);
 		return 1;
 	}
 
-	if (verbose_flag)
-	{
-		strcpy(log_str+65, "debug");
-		log_level = log_str;
-	}
-	else if (!log_level)
-		log_level = log_str;
-
-	/* Set the default log file path to NULL (stdout) */
-	path = NULL;
-	if (debug_flag)
+	if(debug_flag)
 	{
 		pid = getpid();
-		strcpy(log_str+65, "maxdebug");
-		log_level = log_str;
-	}
-	else if (GETFLAG(SYSTEMD_MASK))
-	{
+	}
+	else
+	{
+#ifdef USE_DAEMON
+		if(daemon(0, 0)<0) {
+			perror("daemon()");
+		}
 		pid = getpid();
-	}
-	else
-	{
-		pid = process_daemonize();
-		#ifdef READYNAS
-		unlink("/ramfs/.upnp-av_scan");
-		path = "/var/log/upnp-av.log";
-		#else
-		if (access(db_path, F_OK) != 0)
-			make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
-		snprintf(buf, sizeof(buf), "%s/minidlna.log", log_path);
-		path = buf;
-		#endif
-	}
-	log_init(path, log_level);
-
-	if (process_check_if_running(pidfilename) < 0)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, SERVER_NAME " is already running. EXITING.\n");
+#else
+		pid = daemonize();
+#endif
+	}
+
+	openlog_option = LOG_PID|LOG_CONS;
+	if(debug_flag)
+	{
+		openlog_option |= LOG_PERROR;	/* also log on stderr */
+	}
+
+	openlog("miniupnpd", openlog_option, LOG_MINIUPNPD);
+
+	if(!debug_flag)
+	{
+		/* speed things up and ignore LOG_INFO and LOG_DEBUG */
+		setlogmask(LOG_UPTO(LOG_NOTICE));
+	}
+
+	if(checkforrunning(pidfilename) < 0)
+	{
+		syslog(LOG_ERR, "MiniUPnPd is already running. EXITING");
 		return 1;
 	}	
 
-	set_startup_time();
+	set_startup_time(GETFLAG(SYSUPTIMEMASK)/*sysuptime*/);
 
 	/* presentation url */
-	if (presurl)
-		strncpyt(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
+	if(presurl)
+	{
+		strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
+		presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';
+	}
 	else
-		strcpy(presentationurl, "/");
-
-	/* set signal handlers */
+	{
+		snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
+		         "http://%s/", lan_addr[0].str);
+		         /*"http://%s:%d/", lan_addr[0].str, 80);*/
+		         /*"http://%s:%d/", v->lan_addr[0].str, 80);*/
+	}
+
+	/* set signal handler */
 	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");
+	{
+		syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGTERM");
+		return 1;
+	}
 	if (sigaction(SIGINT, &sa, NULL))
-		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");
-	if (signal(SIGHUP, &sighup) == SIG_ERR)
-		DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGHUP");
-	signal(SIGUSR1, &sigusr1);
-	sa.sa_handler = process_handle_child_termination;
-	if (sigaction(SIGCHLD, &sa, NULL))
-		DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGCHLD");
-
-	if (writepidfile(pidfilename, pid, uid) != 0)
-		pidfilename = NULL;
-
-	if (uid > 0)
-	{
-		struct stat st;
-		if (stat(db_path, &st) == 0 && st.st_uid != uid && chown(db_path, uid, -1) != 0)
-			DPRINTF(E_ERROR, L_GENERAL, "Unable to set db_path [%s] ownership to %d: %s\n",
-				db_path, uid, strerror(errno));
-	}
-
-	if (gid > 0 && setgid(gid) == -1)
-		DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to gid '%d'. [%s] EXITING.\n",
-			gid, strerror(errno));
-
-	if (uid > 0 && setuid(uid) == -1)
-		DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to uid '%d'. [%s] EXITING.\n",
-			uid, strerror(errno));
-
-	children = calloc(runtime_vars.max_connections, sizeof(struct child));
-	if (!children)
-	{
-		DPRINTF(E_ERROR, L_GENERAL, "Allocation failed\n");
+	{
+		syslog(LOG_ERR, "Failed to set %s handler. EXITING", "SIGINT");
 		return 1;
 	}
+
+	if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
+		syslog(LOG_ERR, "Failed to ignore SIGPIPE signals");
+	}
+
+	writepidfile(pidfilename, pid);
 
 	return 0;
 }
@@ -1040,312 +620,213 @@
 /* === main === */
 /* process HTTP or SSDP requests */
 int
-main(int argc, char **argv)
+main(int argc, char * * argv)
 {
-	int ret, i;
-	int shttpl = -1;
-	int smonitor = -1;
+	int i;
+	int sudp = -1, shttpl = -1;
+	int snotify[MAX_LAN_ADDR];
 	LIST_HEAD(httplisthead, upnphttp) upnphttphead;
 	struct upnphttp * e = 0;
 	struct upnphttp * next;
 	fd_set readset;	/* for select() */
+#ifdef ENABLE_EVENTS
 	fd_set writeset;
-	struct timeval timeout, timeofday, lastnotifytime = {0, 0};
-	time_t lastupdatetime = 0, lastdbtime = 0;
+#endif
+	struct timeval timeout, timeofday, lasttimeofday = {0, 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;
-
-	ret = init(argc, argv);
-	if (ret != 0)
+	struct runtime_vars v;
+
+	if(init(argc, argv, &v) != 0)
 		return 1;
-	init_nls();
-
-	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);
-	lastdbtime = _get_dbtime();
-#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");
-		reload_ifaces(0);	/* populate lan_addr[0].str */
-		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");
-		if (GETFLAG(TIVO_BONJOUR_MASK))
-		{
-			tivo_bonjour_register();
-		}
-		else
-		{
-			/* 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;
+	if( access("/tmp/files.db", F_OK) )
+	{
+		sqlite3_open("/tmp/files.db", &db);
+		ScanDirectory(media_dir, NULL);
+		return 0;
+	}
+	else
+	{
+		sqlite3_open("/tmp/files.db", &db);
+	}
+
+
+	/* open socket for SSDP connections */
+	/*sudp = OpenAndConfSSDPReceiveSocket(v.n_lan_addr, v.lan_addr);*/
+	sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);
+	if(sudp < 0)
+	{
+		syslog(LOG_ERR, "Failed to open socket for receiving SSDP. EXITING");
+		return 1;
+	}
+	/* open socket for HTTP connections. Listen on the 1st LAN address */
+	shttpl = OpenAndConfHTTPSocket(v.port);
+	if(shttpl < 0)
+	{
+		syslog(LOG_ERR, "Failed to open socket for HTTP. EXITING");
+		return 1;
+	}
+	syslog(LOG_NOTICE, "HTTP listening on port %d", v.port);
+
+	/* open socket for sending notifications */
+	if(OpenAndConfSSDPNotifySockets(snotify) < 0)
+	{
+		syslog(LOG_ERR, "Failed to open sockets for sending SSDP notify "
+	                "messages. EXITING");
+		return 1;
+	}
+
+	SendSSDPGoodbye(snotify, n_lan_addr);
 
 	/* main loop */
-	while (!quitting)
+	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;
+		if(gettimeofday(&timeofday, 0) < 0)
+		{
+			syslog(LOG_ERR, "gettimeofday(): %m");
+			timeout.tv_sec = v.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++)
+			/* the comparaison is not very precise but who cares ? */
+			if(timeofday.tv_sec >= (lasttimeofday.tv_sec + v.notify_interval))
+			{
+				SendSSDPNotifies2(snotify,
+			                  (unsigned short)v.port,
+			                  (v.notify_interval << 1)+10);
+				memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval));
+				timeout.tv_sec = v.notify_interval;
+				timeout.tv_usec = 0;
+			}
+			else
+			{
+				timeout.tv_sec = lasttimeofday.tv_sec + v.notify_interval
+				                 - timeofday.tv_sec;
+				if(timeofday.tv_usec > lasttimeofday.tv_usec)
 				{
-					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
+					timeout.tv_usec = 1000000 + lasttimeofday.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;
+					timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec;
 				}
-				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 (GETFLAG(SCANNING_MASK))
-		{
-			if (!scanner_pid || kill(scanner_pid, 0) != 0)
-			{
-				CLEARFLAG(SCANNING_MASK);
-				if (_get_dbtime() != lastdbtime)
-					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 (sudp >= 0) 
+		{
+			FD_SET(sudp, &readset);
+			max_fd = MAX( max_fd, sudp);
 		}
 		
 		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);
+			max_fd = MAX( max_fd, shttpl);
 		}
 
 		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))
+		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);
+				max_fd = MAX( max_fd, e->socket);
 				i++;
 			}
 		}
+		/* for debug */
+#ifdef DEBUG
+		if(i > 1)
+		{
+			syslog(LOG_DEBUG, "%d active incoming HTTP connections", i);
+		}
+#endif
+
+#ifdef ENABLE_EVENTS
 		FD_ZERO(&writeset);
 		upnpevents_selectfds(&readset, &writeset, &max_fd);
-
-		ret = select(max_fd+1, &readset, &writeset, 0, &timeout);
-		if (ret < 0)
+#endif
+
+#ifdef ENABLE_EVENTS
+		if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
+#else
+		if(select(max_fd+1, &readset, 0, 0, &timeout) < 0)
+#endif
 		{
 			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");
-		}
+			syslog(LOG_ERR, "select(all): %m");
+			syslog(LOG_ERR, "Failed to select open sockets. EXITING");
+			return 1;	/* very serious cause of error */
+		}
+#ifdef ENABLE_EVENTS
 		upnpevents_processfds(&readset, &writeset);
+#endif
 		/* 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 (GETFLAG(SCANNING_MASK))
-			{
-				time_t dbtime = _get_dbtime();
-				if (dbtime != lastdbtime)
-				{
-					lastdbtime = dbtime;
-					last_changecnt = -1;
-				}
-			}
-			if (sqlite3_total_changes(db) != last_changecnt)
-			{
-				updateID++;
-				last_changecnt = sqlite3_total_changes(db);
-				upnp_event_var_change_notify(EContentDirectory);
-				lastupdatetime = timeofday.tv_sec;
-			}
+		if(sudp >= 0 && FD_ISSET(sudp, &readset))
+		{
+			/*syslog(LOG_INFO, "Received UDP Packet");*/
+			/*ProcessSSDPRequest(sudp, v.lan_addr, v.n_lan_addr,*/
+			ProcessSSDPRequest(sudp, (unsigned short)v.port);
 		}
 		/* 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)))
+		/* LIST_FOREACH macro is not available under linux */
+		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))
+		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));
+			if(shttp<0)
+			{
+				syslog(LOG_ERR, "accept(http): %m");
 			}
 			else
 			{
 				struct upnphttp * tmp = 0;
-				DPRINTF(E_DEBUG, L_GENERAL, "HTTP connection from %s:%d\n",
+				syslog(LOG_INFO, "HTTP connection from %s:%d",
 					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");
+					syslog(LOG_ERR, "fcntl F_SETFL, O_NONBLOCK");
 				}*/
 				/* Create a new upnphttp object and add it to
 				 * the active upnphttp object list */
 				tmp = New_upnphttp(shttp);
-				if (tmp)
+				if(tmp)
 				{
 					tmp->clientaddr = clientname.sin_addr;
 					LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
 				}
 				else
 				{
-					DPRINTF(E_ERROR, L_GENERAL, "New_upnphttp() failed\n");
+					syslog(LOG_ERR, "New_upnphttp() failed");
 					close(shttp);
 				}
 			}
 		}
 		/* delete finished HTTP connections */
-		for (e = upnphttphead.lh_first; e != NULL; e = next)
+		for(e = upnphttphead.lh_first; e != NULL; )
 		{
 			next = e->entries.le_next;
 			if(e->state >= 100)
@@ -1353,59 +834,39 @@
 				LIST_REMOVE(e, entries);
 				Delete_upnphttp(e);
 			}
+			e = next;
 		}
 	}
 
 shutdown:
-	/* kill the scanner */
-	if (GETFLAG(SCANNING_MASK) && scanner_pid)
-		kill(scanner_pid, SIGKILL);
-
 	/* close out open sockets */
-	while (upnphttphead.lh_first != NULL)
+	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
-	if (smonitor >= 0)
-		close(smonitor);
+
+	if (sudp >= 0) close(sudp);
+	if (shttpl >= 0) close(shttpl);
 	
-	for (i = 0; i < n_lan_addr; i++)
-	{
-		SendSSDPGoodbyes(lan_addr[i].snotify);
-		close(lan_addr[i].snotify);
-	}
-
-	if (inotify_thread)
-	{
-		pthread_kill(inotify_thread, SIGCHLD);
-		pthread_join(inotify_thread, NULL);
-	}
-
-	/* kill other child processes */
-	process_reap_children();
-	free(children);
-
-	sql_exec(db, "UPDATE SETTINGS set VALUE = '%u' where KEY = 'UPDATE_ID'", updateID);
+	if(SendSSDPGoodbye(snotify, n_lan_addr) < 0)
+	{
+		syslog(LOG_ERR, "Failed to broadcast good-bye notifications");
+	}
+	for(i=0; i<n_lan_addr; i++)/* for(i=0; i<v.n_lan_addr; i++)*/
+		close(snotify[i]);
+
 	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();
+	if(unlink(pidfilename) < 0)
+	{
+		syslog(LOG_ERR, "Failed to remove pidfile %s: %m", pidfilename);
+	}
+
+	closelog();	
 	freeoptions();
-
-	exit(EXIT_SUCCESS);
+	
+	return 0;
 }