"Fossies" - the Fresh Open Source Software Archive

Member "minidlna-1.3.0/minidlna.c" (24 Nov 2020, 36139 Bytes) of package /linux/privat/minidlna-1.3.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "minidlna.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.2.1_vs_1.3.0.

    1 /* MiniDLNA project
    2  *
    3  * http://sourceforge.net/projects/minidlna/
    4  *
    5  * MiniDLNA media server
    6  * Copyright (C) 2008-2012  Justin Maggard
    7  *
    8  * This file is part of MiniDLNA.
    9  *
   10  * MiniDLNA is free software; you can redistribute it and/or modify
   11  * it under the terms of the GNU General Public License version 2 as
   12  * published by the Free Software Foundation.
   13  *
   14  * MiniDLNA is distributed in the hope that it will be useful,
   15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   17  * GNU General Public License for more details.
   18  *
   19  * You should have received a copy of the GNU General Public License
   20  * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
   21  *
   22  * Portions of the code from the MiniUPnP project:
   23  *
   24  * Copyright (c) 2006-2007, Thomas Bernard
   25  * All rights reserved.
   26  *
   27  * Redistribution and use in source and binary forms, with or without
   28  * modification, are permitted provided that the following conditions are met:
   29  *     * Redistributions of source code must retain the above copyright
   30  *       notice, this list of conditions and the following disclaimer.
   31  *     * Redistributions in binary form must reproduce the above copyright
   32  *       notice, this list of conditions and the following disclaimer in the
   33  *       documentation and/or other materials provided with the distribution.
   34  *     * The name of the author may not be used to endorse or promote products
   35  *       derived from this software without specific prior written permission.
   36  *
   37  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   38  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   39  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   40  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
   41  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   42  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   43  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   44  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   45  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   47  * POSSIBILITY OF SUCH DAMAGE.
   48  */
   49 #include <stdlib.h>
   50 #include <unistd.h>
   51 #include <string.h>
   52 #include <stdio.h>
   53 #include <ctype.h>
   54 #include <sys/types.h>
   55 #include <sys/socket.h>
   56 #include <sys/wait.h>
   57 #include <sys/file.h>
   58 #include <sys/time.h>
   59 #include <sys/param.h>
   60 #include <sys/stat.h>
   61 #include <netinet/in.h>
   62 #include <arpa/inet.h>
   63 #include <fcntl.h>
   64 #include <time.h>
   65 #include <signal.h>
   66 #include <errno.h>
   67 #include <pthread.h>
   68 #include <limits.h>
   69 #include <libgen.h>
   70 #include <pwd.h>
   71 #include <grp.h>
   72 
   73 #include "config.h"
   74 
   75 #ifdef ENABLE_NLS
   76 #include <locale.h>
   77 #include <libintl.h>
   78 #endif
   79 
   80 #include "event.h"
   81 #include "upnpglobalvars.h"
   82 #include "sql.h"
   83 #include "upnphttp.h"
   84 #include "upnpdescgen.h"
   85 #include "minidlnapath.h"
   86 #include "getifaddr.h"
   87 #include "upnpsoap.h"
   88 #include "options.h"
   89 #include "utils.h"
   90 #include "minissdp.h"
   91 #include "minidlnatypes.h"
   92 #include "process.h"
   93 #include "upnpevents.h"
   94 #include "scanner.h"
   95 #include "monitor.h"
   96 #include "libav.h"
   97 #include "log.h"
   98 #include "tivo_beacon.h"
   99 #include "tivo_utils.h"
  100 #include "avahi.h"
  101 
  102 #if SQLITE_VERSION_NUMBER < 3005001
  103 # warning "Your SQLite3 library appears to be too old!  Please use 3.5.1 or newer."
  104 # define sqlite3_threadsafe() 0
  105 #endif
  106 
  107 static LIST_HEAD(httplisthead, upnphttp) upnphttphead;
  108 
  109 /* OpenAndConfHTTPSocket() :
  110  * setup the socket used to handle incoming HTTP connections. */
  111 static int
  112 OpenAndConfHTTPSocket(unsigned short port)
  113 {
  114     int s;
  115     int i = 1;
  116     struct sockaddr_in listenname;
  117 
  118     /* Initialize client type cache */
  119     memset(&clients, 0, sizeof(struct client_cache_s));
  120 
  121     s = socket(PF_INET, SOCK_STREAM, 0);
  122     if (s < 0)
  123     {
  124         DPRINTF(E_ERROR, L_GENERAL, "socket(http): %s\n", strerror(errno));
  125         return -1;
  126     }
  127 
  128     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
  129         DPRINTF(E_WARN, L_GENERAL, "setsockopt(http, SO_REUSEADDR): %s\n", strerror(errno));
  130 
  131     memset(&listenname, 0, sizeof(struct sockaddr_in));
  132     listenname.sin_family = AF_INET;
  133     listenname.sin_port = htons(port);
  134     listenname.sin_addr.s_addr = htonl(INADDR_ANY);
  135 
  136     if (bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
  137     {
  138         DPRINTF(E_ERROR, L_GENERAL, "bind(http): %s\n", strerror(errno));
  139         close(s);
  140         return -1;
  141     }
  142 
  143     if (listen(s, 16) < 0)
  144     {
  145         DPRINTF(E_ERROR, L_GENERAL, "listen(http): %s\n", strerror(errno));
  146         close(s);
  147         return -1;
  148     }
  149 
  150     return s;
  151 }
  152 
  153 /* ProcessListen() :
  154  * accept incoming HTTP connection. */
  155 static void
  156 ProcessListen(struct event *ev)
  157 {
  158     int shttp;
  159     socklen_t clientnamelen;
  160     struct sockaddr_in clientname;
  161     clientnamelen = sizeof(struct sockaddr_in);
  162 
  163     shttp = accept(ev->fd, (struct sockaddr *)&clientname, &clientnamelen);
  164     if (shttp<0)
  165     {
  166         DPRINTF(E_ERROR, L_GENERAL, "accept(http): %s\n", strerror(errno));
  167     }
  168     else
  169     {
  170         struct upnphttp * tmp = 0;
  171         DPRINTF(E_DEBUG, L_GENERAL, "HTTP connection from %s:%d\n",
  172             inet_ntoa(clientname.sin_addr),
  173             ntohs(clientname.sin_port) );
  174         /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
  175             DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK\n");
  176         }*/
  177         /* Create a new upnphttp object and add it to
  178          * the active upnphttp object list */
  179         tmp = New_upnphttp(shttp);
  180         if (tmp)
  181         {
  182             tmp->clientaddr = clientname.sin_addr;
  183             LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
  184         }
  185         else
  186         {
  187             DPRINTF(E_ERROR, L_GENERAL, "New_upnphttp() failed\n");
  188             close(shttp);
  189         }
  190     }
  191 }
  192 
  193 /* Handler for the SIGTERM signal (kill) 
  194  * SIGINT is also handled */
  195 static void
  196 sigterm(int sig)
  197 {
  198     signal(sig, SIG_IGN);   /* Ignore this signal while we are quitting */
  199 
  200     DPRINTF(E_WARN, L_GENERAL, "received signal %d, good-bye\n", sig);
  201 
  202     quitting = 1;
  203 }
  204 
  205 static void
  206 sigusr1(int sig)
  207 {
  208     signal(sig, sigusr1);
  209     DPRINTF(E_WARN, L_GENERAL, "received signal %d, clear cache\n", sig);
  210 
  211     memset(&clients, '\0', sizeof(clients));
  212 }
  213 
  214 static void
  215 sighup(int sig)
  216 {
  217     signal(sig, sighup);
  218     DPRINTF(E_WARN, L_GENERAL, "received signal %d, reloading\n", sig);
  219 
  220     reload_ifaces(1);
  221     log_reopen();
  222 }
  223 
  224 /* record the startup time */
  225 static void
  226 set_startup_time(void)
  227 {
  228     startup_time = time(NULL);
  229 }
  230 
  231 static void
  232 getfriendlyname(char *buf, int len)
  233 {
  234     char *p = NULL;
  235     char hn[63];
  236     int off;
  237 
  238     if (gethostname(hn, sizeof(hn)) == 0)
  239     {
  240         strncpyt(buf, hn, len);
  241         p = strchr(buf, '.');
  242         if (p)
  243             *p = '\0';
  244     }
  245     else
  246         strcpy(buf, "Unknown");
  247 
  248     off = strlen(buf);
  249     off += snprintf(buf+off, len-off, ": ");
  250 #ifdef READYNAS
  251     FILE *info;
  252     char ibuf[64], *key, *val;
  253     snprintf(buf+off, len-off, "ReadyNAS");
  254     info = fopen("/proc/sys/dev/boot/info", "r");
  255     if (!info)
  256         return;
  257     while ((val = fgets(ibuf, 64, info)) != NULL)
  258     {
  259         key = strsep(&val, ": \t");
  260         val = trim(val);
  261         if (strcmp(key, "model") == 0)
  262         {
  263             snprintf(buf+off, len-off, "%s", val);
  264             key = strchr(val, ' ');
  265             if (key)
  266             {
  267                 strncpyt(modelnumber, key+1, MODELNUMBER_MAX_LEN);
  268                 *key = '\0';
  269             }
  270             snprintf(modelname, MODELNAME_MAX_LEN,
  271                 "Windows Media Connect compatible (%s)", val);
  272         }
  273         else if (strcmp(key, "serial") == 0)
  274         {
  275             strncpyt(serialnumber, val, SERIALNUMBER_MAX_LEN);
  276             if (serialnumber[0] == '\0')
  277             {
  278                 char mac_str[13];
  279                 if (getsyshwaddr(mac_str, sizeof(mac_str)) == 0)
  280                     strcpy(serialnumber, mac_str);
  281                 else
  282                     strcpy(serialnumber, "0");
  283             }
  284             break;
  285         }
  286     }
  287     fclose(info);
  288 #else
  289     char * logname;
  290     logname = getenv("USER");
  291     if (!logname)
  292         {
  293         logname = getenv("LOGNAME");
  294 #ifndef STATIC // Disable for static linking
  295         if (!logname)
  296         {
  297             struct passwd *pwent = getpwuid(geteuid());
  298             if (pwent)
  299                 logname = pwent->pw_name;
  300         }
  301 #endif
  302     }
  303     snprintf(buf+off, len-off, "%s", logname?logname:"Unknown");
  304 #endif
  305 }
  306 
  307 static time_t
  308 _get_dbtime(void)
  309 {
  310     char path[PATH_MAX];
  311     struct stat st;
  312 
  313     snprintf(path, sizeof(path), "%s/files.db", db_path);
  314     if (stat(path, &st) != 0)
  315         return 0;
  316     return st.st_mtime;
  317 }
  318 
  319 static int
  320 open_db(sqlite3 **sq3)
  321 {
  322     char path[PATH_MAX];
  323     int new_db = 0;
  324 
  325     snprintf(path, sizeof(path), "%s/files.db", db_path);
  326     if (access(path, F_OK) != 0)
  327     {
  328         new_db = 1;
  329         make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
  330     }
  331     if (sqlite3_open(path, &db) != SQLITE_OK)
  332         DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to open sqlite database!  Exiting...\n");
  333     if (sq3)
  334         *sq3 = db;
  335     sqlite3_busy_timeout(db, 5000);
  336     sql_exec(db, "pragma page_size = 4096");
  337     sql_exec(db, "pragma journal_mode = OFF");
  338     sql_exec(db, "pragma synchronous = OFF;");
  339     sql_exec(db, "pragma default_cache_size = 8192;");
  340 
  341     return new_db;
  342 }
  343 
  344 static void
  345 check_db(sqlite3 *db, int new_db, pid_t *scanner_pid)
  346 {
  347     struct media_dir_s *media_path = NULL;
  348     char cmd[PATH_MAX*2];
  349     char **result;
  350     int i, rows = 0;
  351     int ret;
  352 
  353     if (!new_db)
  354     {
  355         /* Check if any new media dirs appeared */
  356         media_path = media_dirs;
  357         while (media_path)
  358         {
  359             ret = sql_get_int_field(db, "SELECT TIMESTAMP as TYPE from DETAILS where PATH = %Q",
  360                         media_path->path);
  361             if (ret != media_path->types)
  362             {
  363                 ret = 1;
  364                 goto rescan;
  365             }
  366             media_path = media_path->next;
  367         }
  368         /* Check if any media dirs disappeared */
  369         sql_get_table(db, "SELECT VALUE from SETTINGS where KEY = 'media_dir'", &result, &rows, NULL);
  370         for (i=1; i <= rows; i++)
  371         {
  372             media_path = media_dirs;
  373             while (media_path)
  374             {
  375                 if (strcmp(result[i], media_path->path) == 0)
  376                     break;
  377                 media_path = media_path->next;
  378             }
  379             if (!media_path)
  380             {
  381                 ret = 2;
  382                 sqlite3_free_table(result);
  383                 goto rescan;
  384             }
  385         }
  386         sqlite3_free_table(result);
  387     }
  388 
  389     ret = db_upgrade(db);
  390     if (ret != 0)
  391     {
  392 rescan:
  393         CLEARFLAG(RESCAN_MASK);
  394         if (ret < 0)
  395             DPRINTF(E_WARN, L_GENERAL, "Creating new database at %s/files.db\n", db_path);
  396         else if (ret == 1)
  397             DPRINTF(E_WARN, L_GENERAL, "New media_dir detected; rebuilding...\n");
  398         else if (ret == 2)
  399             DPRINTF(E_WARN, L_GENERAL, "Removed media_dir detected; rebuilding...\n");
  400         else
  401             DPRINTF(E_WARN, L_GENERAL, "Database version mismatch (%d => %d); need to recreate...\n",
  402                 ret, DB_VERSION);
  403         sqlite3_close(db);
  404 
  405         snprintf(cmd, sizeof(cmd), "rm -rf %s/files.db %s/art_cache", db_path, db_path);
  406         if (system(cmd) != 0)
  407             DPRINTF(E_FATAL, L_GENERAL, "Failed to clean old file cache!  Exiting...\n");
  408 
  409         open_db(&db);
  410         if (CreateDatabase() != 0)
  411             DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database!  Exiting...\n");
  412     }
  413     if (ret || GETFLAG(RESCAN_MASK))
  414     {
  415 #if USE_FORK
  416         sqlite3_close(db);
  417         *scanner_pid = fork();
  418         open_db(&db);
  419         if (*scanner_pid == 0) /* child (scanner) process */
  420         {
  421             start_scanner();
  422             sqlite3_close(db);
  423             log_close();
  424             freeoptions();
  425             free(children);
  426             exit(EXIT_SUCCESS);
  427         }
  428         else if (*scanner_pid < 0)
  429         {
  430             start_scanner();
  431         }
  432         else
  433             SETFLAG(SCANNING_MASK);
  434 #else
  435         start_scanner();
  436 #endif
  437     }
  438 }
  439 
  440 static int
  441 writepidfile(const char *fname, int pid, uid_t uid)
  442 {
  443     FILE *pidfile;
  444     struct stat st;
  445     char path[PATH_MAX], *dir;
  446     int ret = 0;
  447 
  448     if(!fname || *fname == '\0')
  449         return -1;
  450 
  451     /* Create parent directory if it doesn't already exist */
  452     strncpyt(path, fname, sizeof(path));
  453     dir = dirname(path);
  454     if (stat(dir, &st) == 0)
  455     {
  456         if (!S_ISDIR(st.st_mode))
  457         {
  458             DPRINTF(E_ERROR, L_GENERAL, "Pidfile path is not a directory: %s\n",
  459                 fname);
  460             return -1;
  461         }
  462     }
  463     else
  464     {
  465         if (make_dir(dir, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0)
  466         {
  467             DPRINTF(E_ERROR, L_GENERAL, "Unable to create pidfile directory: %s\n",
  468                 fname);
  469             return -1;
  470         }
  471         if (uid > 0)
  472         {
  473             if (chown(dir, uid, -1) != 0)
  474                 DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile %s ownership: %s\n",
  475                     dir, strerror(errno));
  476         }
  477     }
  478     
  479     pidfile = fopen(fname, "w");
  480     if (!pidfile)
  481     {
  482         DPRINTF(E_ERROR, L_GENERAL, "Unable to open pidfile for writing %s: %s\n",
  483             fname, strerror(errno));
  484         return -1;
  485     }
  486 
  487     if (fprintf(pidfile, "%d\n", pid) <= 0)
  488     {
  489         DPRINTF(E_ERROR, L_GENERAL, 
  490             "Unable to write to pidfile %s: %s\n", fname, strerror(errno));
  491         ret = -1;
  492     }
  493     if (uid > 0)
  494     {
  495         if (fchown(fileno(pidfile), uid, -1) != 0)
  496             DPRINTF(E_WARN, L_GENERAL, "Unable to change pidfile %s ownership: %s\n",
  497                 fname, strerror(errno));
  498     }
  499 
  500     fclose(pidfile);
  501 
  502     return ret;
  503 }
  504 
  505 static int strtobool(const char *str)
  506 {
  507     return ((strcasecmp(str, "yes") == 0) ||
  508         (strcasecmp(str, "true") == 0) ||
  509         (atoi(str) == 1));
  510 }
  511 
  512 static void init_nls(void)
  513 {
  514 #ifdef ENABLE_NLS
  515     const char *messages, *ctype, *locale_dir;
  516 
  517     ctype = setlocale(LC_CTYPE, "");
  518     if (!ctype || !strcmp(ctype, "C"))
  519         ctype = setlocale(LC_CTYPE, "en_US.utf8");
  520     if (!ctype)
  521         DPRINTF(E_WARN, L_GENERAL, "Unset locale\n");
  522     else if (!strstr(ctype, "utf8") && !strstr(ctype, "UTF8") &&
  523          !strstr(ctype, "utf-8") && !strstr(ctype, "UTF-8"))
  524         DPRINTF(E_WARN, L_GENERAL, "Using unsupported non-utf8 locale '%s'\n", ctype);
  525     messages = setlocale(LC_MESSAGES, "");
  526     if (!messages)
  527         messages = "unset";
  528     locale_dir = bindtextdomain("minidlna", getenv("TEXTDOMAINDIR"));
  529     DPRINTF(E_DEBUG, L_GENERAL, "Using locale dir '%s' and locale langauge %s/%s\n", locale_dir, messages, ctype);
  530     textdomain("minidlna");
  531 #endif
  532 }
  533 
  534 /* init phase :
  535  * 1) read configuration file
  536  * 2) read command line arguments
  537  * 3) daemonize
  538  * 4) check and write pid file
  539  * 5) set startup time stamp
  540  * 6) compute presentation URL
  541  * 7) set signal handlers */
  542 static int
  543 init(int argc, char **argv)
  544 {
  545     int i;
  546     int pid;
  547     int debug_flag = 0;
  548     int verbose_flag = 0;
  549     int options_flag = 0;
  550     struct sigaction sa;
  551     const char * presurl = NULL;
  552     const char * optionsfile = "/etc/minidlna.conf";
  553     char mac_str[13];
  554     char *string, *word;
  555     char *path;
  556     char buf[PATH_MAX];
  557     char log_str[75] = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn";
  558     char *log_level = NULL;
  559     struct media_dir_s *media_dir;
  560     int ifaces = 0;
  561     media_types types;
  562     uid_t uid = 0;
  563     gid_t gid = 0;
  564     int error;
  565 
  566     /* first check if "-f" option is used */
  567     for (i=2; i<argc; i++)
  568     {
  569         if (strcmp(argv[i-1], "-f") == 0)
  570         {
  571             optionsfile = argv[i];
  572             options_flag = 1;
  573             break;
  574         }
  575     }
  576 
  577     /* set up uuid based on mac address */
  578     if (getsyshwaddr(mac_str, sizeof(mac_str)) < 0)
  579     {
  580         DPRINTF(E_OFF, L_GENERAL, "No MAC address found.  Falling back to generic UUID.\n");
  581         strcpy(mac_str, "554e4b4e4f57");
  582     }
  583     snprintf(uuidvalue+5, UUIDVALUE_MAX_LEN-5, "4d696e69-444c-164e-9d41-%s", mac_str);
  584 
  585     getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN);
  586     
  587     runtime_vars.port = 8200;
  588     runtime_vars.notify_interval = 895; /* seconds between SSDP announces */
  589     runtime_vars.max_connections = 50;
  590     runtime_vars.root_container = NULL;
  591     runtime_vars.ifaces[0] = NULL;
  592 
  593     /* read options file first since
  594      * command line arguments have final say */
  595     if (readoptionsfile(optionsfile) < 0)
  596     {
  597         /* only error if file exists or using -f */
  598         if(access(optionsfile, F_OK) == 0 || options_flag)
  599             DPRINTF(E_FATAL, L_GENERAL, "Error reading configuration file %s\n", optionsfile);
  600     }
  601 
  602     for (i=0; i<num_options; i++)
  603     {
  604         switch (ary_options[i].id)
  605         {
  606         case UPNPIFNAME:
  607             for (string = ary_options[i].value; (word = strtok(string, ",")); string = NULL)
  608             {
  609                 if (ifaces >= MAX_LAN_ADDR)
  610                 {
  611                     DPRINTF(E_ERROR, L_GENERAL, "Too many interfaces (max: %d), ignoring %s\n",
  612                         MAX_LAN_ADDR, word);
  613                     break;
  614                 }
  615                 while (isspace(*word))
  616                     word++;
  617                 runtime_vars.ifaces[ifaces++] = word;
  618             }
  619             break;
  620         case UPNPPORT:
  621             runtime_vars.port = atoi(ary_options[i].value);
  622             break;
  623         case UPNPPRESENTATIONURL:
  624             presurl = ary_options[i].value;
  625             break;
  626         case UPNPNOTIFY_INTERVAL:
  627             runtime_vars.notify_interval = atoi(ary_options[i].value);
  628             break;
  629         case UPNPSERIAL:
  630             strncpyt(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
  631             break;              
  632         case UPNPMODEL_NAME:
  633             strncpyt(modelname, ary_options[i].value, MODELNAME_MAX_LEN);
  634             break;
  635         case UPNPMODEL_NUMBER:
  636             strncpyt(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
  637             break;
  638         case UPNPFRIENDLYNAME:
  639             strncpyt(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN);
  640             break;
  641         case UPNPMEDIADIR:
  642             types = ALL_MEDIA;
  643             path = ary_options[i].value;
  644             word = strchr(path, ',');
  645             if (word && (access(path, F_OK) != 0))
  646             {
  647                 types = 0;
  648                 while (*path)
  649                 {
  650                     if (*path == ',')
  651                     {
  652                         path++;
  653                         break;
  654                     }
  655                     else if (*path == 'A' || *path == 'a')
  656                         types |= TYPE_AUDIO;
  657                     else if (*path == 'V' || *path == 'v')
  658                         types |= TYPE_VIDEO;
  659                     else if (*path == 'P' || *path == 'p')
  660                         types |= TYPE_IMAGE;
  661                     else
  662                         DPRINTF(E_FATAL, L_GENERAL, "Media directory entry not understood [%s]\n",
  663                             ary_options[i].value);
  664                     path++;
  665                 }
  666             }
  667             path = realpath(path, buf);
  668             if (!path || access(path, F_OK) != 0)
  669             {
  670                 DPRINTF(E_ERROR, L_GENERAL, "Media directory \"%s\" not accessible [%s]\n",
  671                     ary_options[i].value, strerror(errno));
  672                 break;
  673             }
  674             media_dir = calloc(1, sizeof(struct media_dir_s));
  675             media_dir->path = strdup(path);
  676             media_dir->types = types;
  677             if (media_dirs)
  678             {
  679                 struct media_dir_s *all_dirs = media_dirs;
  680                 while( all_dirs->next )
  681                     all_dirs = all_dirs->next;
  682                 all_dirs->next = media_dir;
  683             }
  684             else
  685                 media_dirs = media_dir;
  686             break;
  687         case UPNPALBUMART_NAMES:
  688             for (string = ary_options[i].value; (word = strtok(string, "/")); string = NULL)
  689             {
  690                 struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s));
  691                 int len = strlen(word);
  692                 if (word[len-1] == '*')
  693                 {
  694                     word[len-1] = '\0';
  695                     this_name->wildcard = 1;
  696                 }
  697                 this_name->name = strdup(word);
  698                 if (album_art_names)
  699                 {
  700                     struct album_art_name_s * all_names = album_art_names;
  701                     while( all_names->next )
  702                         all_names = all_names->next;
  703                     all_names->next = this_name;
  704                 }
  705                 else
  706                     album_art_names = this_name;
  707             }
  708             break;
  709         case UPNPDBDIR:
  710             path = realpath(ary_options[i].value, buf);
  711             if (!path)
  712                 path = (ary_options[i].value);
  713             make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
  714             if (access(path, F_OK) != 0)
  715                 DPRINTF(E_FATAL, L_GENERAL, "Database path not accessible! [%s]\n", path);
  716             strncpyt(db_path, path, sizeof(db_path));
  717             break;
  718         case UPNPLOGDIR:
  719             path = realpath(ary_options[i].value, buf);
  720             if (!path)
  721                 path = ary_options[i].value;
  722             if (snprintf(log_path, sizeof(log_path), "%s", path) > sizeof(log_path))
  723                 DPRINTF(E_FATAL, L_GENERAL, "Log path too long! [%s]\n", path);
  724             make_dir(log_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
  725             break;
  726         case UPNPLOGLEVEL:
  727             log_level = ary_options[i].value;
  728             break;
  729         case UPNPINOTIFY:
  730             if (!strtobool(ary_options[i].value))
  731                 CLEARFLAG(INOTIFY_MASK);
  732             break;
  733         case ENABLE_TIVO:
  734             if (strtobool(ary_options[i].value))
  735                 SETFLAG(TIVO_MASK);
  736             break;
  737         case ENABLE_DLNA_STRICT:
  738             if (strtobool(ary_options[i].value))
  739                 SETFLAG(DLNA_STRICT_MASK);
  740             break;
  741         case ROOT_CONTAINER:
  742             switch (ary_options[i].value[0]) {
  743             case '.':
  744                 runtime_vars.root_container = NULL;
  745                 break;
  746             case 'B':
  747             case 'b':
  748                 runtime_vars.root_container = BROWSEDIR_ID;
  749                 break;
  750             case 'M':
  751             case 'm':
  752                 runtime_vars.root_container = MUSIC_ID;
  753                 break;
  754             case 'V':
  755             case 'v':
  756                 runtime_vars.root_container = VIDEO_ID;
  757                 break;
  758             case 'P':
  759             case 'p':
  760                 runtime_vars.root_container = IMAGE_ID;
  761                 break;
  762             default:
  763                 runtime_vars.root_container = ary_options[i].value;
  764                 DPRINTF(E_WARN, L_GENERAL, "Using arbitrary root container [%s]\n",
  765                     ary_options[i].value);
  766                 break;
  767             }
  768             break;
  769         case UPNPMINISSDPDSOCKET:
  770             minissdpdsocketpath = ary_options[i].value;
  771             break;
  772         case UPNPUUID:
  773             strcpy(uuidvalue+5, ary_options[i].value);
  774             break;
  775         case USER_ACCOUNT:
  776             uid = strtoul(ary_options[i].value, &string, 0);
  777             if (*string)
  778             {
  779                 /* Symbolic username given, not UID. */
  780                 struct passwd *entry = getpwnam(ary_options[i].value);
  781                 if (!entry)
  782                     DPRINTF(E_FATAL, L_GENERAL, "Bad user '%s'.\n",
  783                         ary_options[i].value);
  784                 uid = entry->pw_uid;
  785                 if (!gid)
  786                     gid = entry->pw_gid;
  787             }
  788             break;
  789         case FORCE_SORT_CRITERIA:
  790             force_sort_criteria = ary_options[i].value;
  791             if (force_sort_criteria[0] == '!')
  792             {
  793                 SETFLAG(FORCE_ALPHASORT_MASK);
  794                 force_sort_criteria++;
  795             }
  796             break;
  797         case MAX_CONNECTIONS:
  798             runtime_vars.max_connections = atoi(ary_options[i].value);
  799             break;
  800         case MERGE_MEDIA_DIRS:
  801             if (strtobool(ary_options[i].value))
  802                 SETFLAG(MERGE_MEDIA_DIRS_MASK);
  803             break;
  804         case WIDE_LINKS:
  805             if (strtobool(ary_options[i].value))
  806                 SETFLAG(WIDE_LINKS_MASK);
  807             break;
  808         case TIVO_DISCOVERY:
  809             if (strcasecmp(ary_options[i].value, "beacon") == 0)
  810                 CLEARFLAG(TIVO_BONJOUR_MASK);
  811             break;
  812         case ENABLE_SUBTITLES:
  813             if (!strtobool(ary_options[i].value))
  814                 CLEARFLAG(SUBTITLES_MASK);
  815             break;
  816         default:
  817             DPRINTF(E_ERROR, L_GENERAL, "Unknown option in file %s\n",
  818                 optionsfile);
  819         }
  820     }
  821     if (!log_path[0])
  822         strncpyt(log_path, DEFAULT_LOG_PATH, sizeof(log_path));
  823     if (!db_path[0])
  824         strncpyt(db_path, DEFAULT_DB_PATH, sizeof(db_path));
  825 
  826     /* command line arguments processing */
  827     for (i=1; i<argc; i++)
  828     {
  829         if (argv[i][0] != '-')
  830         {
  831             DPRINTF(E_FATAL, L_GENERAL, "Unknown option: %s\n", argv[i]);
  832         }
  833         else if (strcmp(argv[i], "--help") == 0)
  834         {
  835             runtime_vars.port = -1;
  836             break;
  837         }
  838         else switch(argv[i][1])
  839         {
  840         case 't':
  841             if (i+1 < argc)
  842                 runtime_vars.notify_interval = atoi(argv[++i]);
  843             else
  844                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  845             break;
  846         case 's':
  847             if (i+1 < argc)
  848                 strncpyt(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
  849             else
  850                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  851             break;
  852         case 'm':
  853             if (i+1 < argc)
  854                 strncpyt(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
  855             else
  856                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  857             break;
  858         case 'p':
  859             if (i+1 < argc)
  860                 runtime_vars.port = atoi(argv[++i]);
  861             else
  862                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  863             break;
  864         case 'P':
  865             if (i+1 < argc)
  866             {
  867                 if (argv[++i][0] != '/')
  868                     DPRINTF(E_FATAL, L_GENERAL, "Option -%c requires an absolute filename.\n", argv[i-1][1]);
  869                 else
  870                     pidfilename = argv[i];
  871             }
  872             else
  873                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  874             break;
  875         case 'd':
  876             debug_flag = 1;
  877         case 'v':
  878             verbose_flag = 1;
  879             break;
  880         case 'L':
  881             SETFLAG(NO_PLAYLIST_MASK);
  882             break;
  883         case 'w':
  884             if (i+1 < argc)
  885                 presurl = argv[++i];
  886             else
  887                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  888             break;
  889         case 'i':
  890             if (i+1 < argc)
  891             {
  892                 i++;
  893                 if (ifaces >= MAX_LAN_ADDR)
  894                 {
  895                     DPRINTF(E_ERROR, L_GENERAL, "Too many interfaces (max: %d), ignoring %s\n",
  896                         MAX_LAN_ADDR, argv[i]);
  897                     break;
  898                 }
  899                 runtime_vars.ifaces[ifaces++] = argv[i];
  900             }
  901             else
  902                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  903             break;
  904         case 'f':
  905             i++;    /* discarding, the config file is already read */
  906             break;
  907         case 'h':
  908             runtime_vars.port = -1; // triggers help display
  909             break;
  910         case 'r':
  911             SETFLAG(RESCAN_MASK);
  912             break;
  913         case 'R':
  914             snprintf(buf, sizeof(buf), "rm -rf %s/files.db %s/art_cache", db_path, db_path);
  915             if (system(buf) != 0)
  916                 DPRINTF(E_FATAL, L_GENERAL, "Failed to clean old file cache %s. EXITING\n", db_path);
  917             break;
  918         case 'u':
  919             if (i+1 != argc)
  920             {
  921                 i++;
  922                 uid = strtoul(argv[i], &string, 0);
  923                 if (*string)
  924                 {
  925                     /* Symbolic username given, not UID. */
  926                     struct passwd *entry = getpwnam(argv[i]);
  927                     if (!entry)
  928                         DPRINTF(E_FATAL, L_GENERAL, "Bad user '%s'.\n", argv[i]);
  929                     uid = entry->pw_uid;
  930                     if (!gid)
  931                         gid = entry->pw_gid;
  932                 }
  933             }
  934             else
  935                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  936             break;
  937         case 'g':
  938             if (i+1 != argc)
  939             {
  940                 i++;
  941                 gid = strtoul(argv[i], &string, 0);
  942                 if (*string)
  943                 {
  944                     /* Symbolic group given, not GID. */
  945                     struct group *grp = getgrnam(argv[i]);
  946                     if (!grp)
  947                         DPRINTF(E_FATAL, L_GENERAL, "Bad group '%s'.\n", argv[i]);
  948                     gid = grp->gr_gid;
  949                 }
  950             }
  951             else
  952                 DPRINTF(E_FATAL, L_GENERAL, "Option -%c takes one argument.\n", argv[i][1]);
  953             break;
  954 #if defined(__linux__) || defined(__APPLE__)
  955         case 'S':
  956             SETFLAG(SYSTEMD_MASK);
  957             break;
  958 #endif
  959         case 'V':
  960             printf("Version " MINIDLNA_VERSION "\n");
  961             exit(0);
  962             break;
  963         default:
  964             DPRINTF(E_ERROR, L_GENERAL, "Unknown option: %s\n", argv[i]);
  965             runtime_vars.port = -1; // triggers help display
  966         }
  967     }
  968 
  969     if (runtime_vars.port <= 0)
  970     {
  971         printf("Usage:\n\t"
  972             "%s [-d] [-v] [-f config_file] [-p port]\n"
  973             "\t\t[-i network_interface] [-u uid_to_run_as] [-g group_to_run_as]\n"
  974             "\t\t[-t notify_interval] [-P pid_filename]\n"
  975             "\t\t[-s serial] [-m model_number]\n"
  976 #ifdef __linux__
  977             "\t\t[-w url] [-r] [-R] [-L] [-S] [-V] [-h]\n"
  978 #else
  979             "\t\t[-w url] [-r] [-R] [-L] [-V] [-h]\n"
  980 #endif
  981             "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n"
  982             "\tDefault pid file is %s.\n"
  983             "\tWith -d minidlna will run in debug mode (not daemonize).\n"
  984             "\t-w sets the presentation url. Default is http address on port 80\n"
  985             "\t-v enables verbose output\n"
  986             "\t-h displays this text\n"
  987             "\t-r forces a rescan\n"
  988             "\t-R forces a rebuild\n"
  989             "\t-L do not create playlists\n"
  990 #if defined(__linux__) || defined(__APPLE__)
  991             "\t-S changes behaviour for systemd/launchd\n"
  992 #endif
  993             "\t-V print the version number\n",
  994             argv[0], pidfilename);
  995         return 1;
  996     }
  997 
  998     if (verbose_flag)
  999     {
 1000         strcpy(log_str+65, "debug");
 1001         log_level = log_str;
 1002     }
 1003     else if (!log_level)
 1004         log_level = log_str;
 1005 
 1006     /* Set the default log to stdout */
 1007     if (debug_flag)
 1008     {
 1009         pid = getpid();
 1010         strcpy(log_str+65, "maxdebug");
 1011         log_level = log_str;
 1012         log_path[0] = '\0';
 1013     }
 1014     else if (GETFLAG(SYSTEMD_MASK))
 1015     {
 1016         pid = getpid();
 1017         log_path[0] = '\0';
 1018     }
 1019     else
 1020     {
 1021         pid = process_daemonize();
 1022         if (access(db_path, F_OK) != 0)
 1023             make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
 1024     }
 1025     if (log_init(log_level) < 0)
 1026         DPRINTF(E_FATAL, L_GENERAL, "Failed to open log file '%s/" LOGFILE_NAME "': %s\n",
 1027             log_path, strerror(errno));
 1028 
 1029     if (process_check_if_running(pidfilename) < 0)
 1030         DPRINTF(E_FATAL, L_GENERAL, SERVER_NAME " is already running. EXITING.\n");
 1031 
 1032     set_startup_time();
 1033 
 1034     /* presentation url */
 1035     if (presurl)
 1036         strncpyt(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
 1037     else
 1038         strcpy(presentationurl, "/");
 1039 
 1040     /* set signal handlers */
 1041     memset(&sa, 0, sizeof(struct sigaction));
 1042     sa.sa_handler = sigterm;
 1043     if (sigaction(SIGTERM, &sa, NULL))
 1044         DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGTERM");
 1045     if (sigaction(SIGINT, &sa, NULL))
 1046         DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGINT");
 1047     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
 1048         DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGPIPE");
 1049     if (signal(SIGHUP, &sighup) == SIG_ERR)
 1050         DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGHUP");
 1051     if (signal(SIGUSR2, SIG_IGN) == SIG_ERR)
 1052         DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGUSR2");
 1053     signal(SIGUSR1, &sigusr1);
 1054     sa.sa_handler = process_handle_child_termination;
 1055     if (sigaction(SIGCHLD, &sa, NULL))
 1056         DPRINTF(E_FATAL, L_GENERAL, "Failed to set %s handler. EXITING.\n", "SIGCHLD");
 1057 
 1058     if (writepidfile(pidfilename, pid, uid) != 0)
 1059         pidfilename = NULL;
 1060 
 1061     if (uid > 0)
 1062     {
 1063         struct stat st;
 1064         if (stat(db_path, &st) == 0 && st.st_uid != uid && chown(db_path, uid, -1) != 0)
 1065             DPRINTF(E_ERROR, L_GENERAL, "Unable to set db_path [%s] ownership to %d: %s\n",
 1066                 db_path, uid, strerror(errno));
 1067     }
 1068 
 1069     if (gid > 0 && setgid(gid) == -1)
 1070         DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to gid '%d'. [%s] EXITING.\n",
 1071             gid, strerror(errno));
 1072 
 1073     if (uid > 0 && setuid(uid) == -1)
 1074         DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to uid '%d'. [%s] EXITING.\n",
 1075             uid, strerror(errno));
 1076 
 1077     children = calloc(runtime_vars.max_connections, sizeof(struct child));
 1078     if (!children)
 1079     {
 1080         DPRINTF(E_ERROR, L_GENERAL, "Allocation failed\n");
 1081         return 1;
 1082     }
 1083 
 1084     if ((error = event_module.init()) != 0)
 1085         DPRINTF(E_FATAL, L_GENERAL, "Failed to init event module. "
 1086             "[%s] EXITING.\n", strerror(error));
 1087 
 1088     return 0;
 1089 }
 1090 
 1091 /* === main === */
 1092 /* process HTTP or SSDP requests */
 1093 int
 1094 main(int argc, char **argv)
 1095 {
 1096     int ret, i;
 1097     int shttpl = -1;
 1098     int smonitor = -1;
 1099     struct upnphttp * e = 0;
 1100     struct upnphttp * next;
 1101     struct timeval tv, timeofday, lastnotifytime = {0, 0};
 1102     time_t lastupdatetime = 0, lastdbtime = 0;
 1103     u_long timeout; /* in milliseconds */
 1104     int last_changecnt = 0;
 1105     pid_t scanner_pid = 0;
 1106     pthread_t inotify_thread = 0;
 1107     struct event ssdpev, httpev, monev;
 1108 #ifdef TIVO_SUPPORT
 1109     uint8_t beacon_interval = 5;
 1110     int sbeacon = -1;
 1111     struct sockaddr_in tivo_bcast;
 1112     struct timeval lastbeacontime = {0, 0};
 1113     struct event beaconev;
 1114 #endif
 1115 
 1116     for (i = 0; i < L_MAX; i++)
 1117         log_level[i] = E_WARN;
 1118 
 1119     ret = init(argc, argv);
 1120     if (ret != 0)
 1121         return 1;
 1122     init_nls();
 1123 
 1124     DPRINTF(E_WARN, L_GENERAL, "Starting " SERVER_NAME " version " MINIDLNA_VERSION ".\n");
 1125     if (sqlite3_libversion_number() < 3005001)
 1126     {
 1127         DPRINTF(E_WARN, L_GENERAL, "SQLite library is old.  Please use version 3.5.1 or newer.\n");
 1128     }
 1129 
 1130     LIST_INIT(&upnphttphead);
 1131 
 1132     ret = open_db(NULL);
 1133     if (ret == 0)
 1134     {
 1135         updateID = sql_get_int_field(db, "SELECT VALUE from SETTINGS where KEY = 'UPDATE_ID'");
 1136         if (updateID == -1)
 1137             ret = -1;
 1138     }
 1139     check_db(db, ret, &scanner_pid);
 1140     lastdbtime = _get_dbtime();
 1141 #ifdef HAVE_INOTIFY
 1142     if( GETFLAG(INOTIFY_MASK) )
 1143     {
 1144         if (!sqlite3_threadsafe() || sqlite3_libversion_number() < 3005001)
 1145             DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe!  "
 1146                                         "Inotify will be disabled.\n");
 1147         else if (pthread_create(&inotify_thread, NULL, start_inotify, NULL) != 0)
 1148             DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify. EXITING\n");
 1149     }
 1150 #endif /* HAVE_INOTIFY */
 1151 
 1152 #ifdef HAVE_KQUEUE
 1153     if (!GETFLAG(SCANNING_MASK)) {
 1154         lav_register_all();
 1155         kqueue_monitor_start();
 1156     }
 1157 #endif /* HAVE_KQUEUE */
 1158 
 1159     smonitor = OpenAndConfMonitorSocket();
 1160     if (smonitor > 0)
 1161     {
 1162         monev = (struct event ){ .fd = smonitor, .rdwr = EVENT_READ, .process = ProcessMonitorEvent };
 1163         event_module.add(&monev);
 1164     }
 1165 
 1166     sssdp = OpenAndConfSSDPReceiveSocket();
 1167     if (sssdp < 0)
 1168     {
 1169         DPRINTF(E_INFO, L_GENERAL, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd\n");
 1170         reload_ifaces(0);   /* populate lan_addr[0].str */
 1171         if (SubmitServicesToMiniSSDPD(lan_addr[0].str, runtime_vars.port) < 0)
 1172             DPRINTF(E_FATAL, L_GENERAL, "Failed to connect to MiniSSDPd. EXITING");
 1173     }
 1174     else
 1175     {
 1176         ssdpev = (struct event ){ .fd = sssdp, .rdwr = EVENT_READ, .process = ProcessSSDPRequest };
 1177         event_module.add(&ssdpev);
 1178     }
 1179 
 1180     /* open socket for HTTP connections. */
 1181     shttpl = OpenAndConfHTTPSocket(runtime_vars.port);
 1182     if (shttpl < 0)
 1183         DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for HTTP. EXITING\n");
 1184     DPRINTF(E_WARN, L_GENERAL, "HTTP listening on port %d\n", runtime_vars.port);
 1185     httpev = (struct event ){ .fd = shttpl, .rdwr = EVENT_READ, .process = ProcessListen };
 1186     event_module.add(&httpev);
 1187 
 1188 #ifdef TIVO_SUPPORT
 1189     if (GETFLAG(TIVO_MASK))
 1190     {
 1191         DPRINTF(E_WARN, L_GENERAL, "TiVo support is enabled.\n");
 1192         /* Add TiVo-specific randomize function to sqlite */
 1193         ret = sqlite3_create_function(db, "tivorandom", 1, SQLITE_UTF8, NULL, &TiVoRandomSeedFunc, NULL, NULL);
 1194         if (ret != SQLITE_OK)
 1195             DPRINTF(E_ERROR, L_TIVO, "ERROR: Failed to add sqlite randomize function for TiVo!\n");
 1196         if (GETFLAG(TIVO_BONJOUR_MASK))
 1197         {
 1198             tivo_bonjour_register();
 1199         }
 1200         else
 1201         {
 1202             /* open socket for sending Tivo notifications */
 1203             sbeacon = OpenAndConfTivoBeaconSocket();
 1204             if(sbeacon < 0)
 1205                 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify "
 1206                     "messages. EXITING\n");
 1207             beaconev = (struct event ){ .fd = sbeacon, .rdwr = EVENT_READ, .process = ProcessTiVoBeacon };
 1208             event_module.add(&beaconev);
 1209             tivo_bcast.sin_family = AF_INET;
 1210             tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress());
 1211             tivo_bcast.sin_port = htons(2190);
 1212         }
 1213     }
 1214 #endif
 1215 
 1216     reload_ifaces(0);
 1217     lastnotifytime.tv_sec = time(NULL) + runtime_vars.notify_interval;
 1218 
 1219     /* main loop */
 1220     while (!quitting)
 1221     {
 1222         if (gettimeofday(&timeofday, 0) < 0)
 1223             DPRINTF(E_FATAL, L_GENERAL, "gettimeofday(): %s\n", strerror(errno));
 1224         /* Check if we need to send SSDP NOTIFY messages and do it if
 1225          * needed */
 1226         tv = lastnotifytime;
 1227         tv.tv_sec += runtime_vars.notify_interval;
 1228         if (timevalcmp(&timeofday, &tv, >=))
 1229         {
 1230             DPRINTF(E_DEBUG, L_SSDP, "Sending SSDP notifies\n");
 1231             for (i = 0; i < n_lan_addr; i++)
 1232             {
 1233                 SendSSDPNotifies(lan_addr[i].snotify, lan_addr[i].str,
 1234                     runtime_vars.port, runtime_vars.notify_interval);
 1235             }
 1236             lastnotifytime = timeofday;
 1237             timeout = runtime_vars.notify_interval * 1000;
 1238         }
 1239         else
 1240         {
 1241             timevalsub(&tv, &timeofday);
 1242             timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
 1243         }
 1244 #ifdef TIVO_SUPPORT
 1245         if (sbeacon >= 0)
 1246         {
 1247             u_long beacontimeout;
 1248 
 1249             tv = lastbeacontime;
 1250             tv.tv_sec += beacon_interval;
 1251             if (timevalcmp(&timeofday, &tv, >=))
 1252             {
 1253                 sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1);
 1254                 lastbeacontime = timeofday;
 1255                 beacontimeout = beacon_interval * 1000;
 1256                 if (timeout > beacon_interval * 1000)
 1257                     timeout = beacon_interval * 1000;
 1258                 /* Beacons should be sent every 5 seconds or
 1259                  * so for the first minute, then every minute
 1260                  * or so thereafter. */
 1261                 if (beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60)
 1262                     beacon_interval = 60;
 1263             }
 1264             else
 1265             {
 1266                 timevalsub(&tv, &timeofday);
 1267                 beacontimeout = tv.tv_sec * 1000 +
 1268                     tv.tv_usec / 1000;
 1269             }
 1270             if (timeout > beacontimeout)
 1271                 timeout = beacontimeout;
 1272         }
 1273 #endif
 1274 
 1275         if (GETFLAG(SCANNING_MASK) && kill(scanner_pid, 0) != 0) {
 1276             CLEARFLAG(SCANNING_MASK);
 1277             if (_get_dbtime() != lastdbtime)
 1278                 updateID++;
 1279 #ifdef HAVE_KQUEUE
 1280             lav_register_all();
 1281             kqueue_monitor_start();
 1282 #endif /* HAVE_KQUEUE */
 1283         }
 1284 
 1285         event_module.process(timeout);
 1286         if (quitting)
 1287             goto shutdown;
 1288 
 1289         upnpevents_gc();
 1290 
 1291         /* increment SystemUpdateID if the content database has changed,
 1292          * and if there is an active HTTP connection, at most once every 2 seconds */
 1293         if (!LIST_EMPTY(&upnphttphead) &&
 1294             (timeofday.tv_sec >= (lastupdatetime + 2)))
 1295         {
 1296             if (GETFLAG(SCANNING_MASK))
 1297             {
 1298                 time_t dbtime = _get_dbtime();
 1299                 if (dbtime != lastdbtime)
 1300                 {
 1301                     lastdbtime = dbtime;
 1302                     last_changecnt = -1;
 1303                 }
 1304             }
 1305             if (sqlite3_total_changes(db) != last_changecnt)
 1306             {
 1307                 updateID++;
 1308                 last_changecnt = sqlite3_total_changes(db);
 1309                 upnp_event_var_change_notify(EContentDirectory);
 1310                 lastupdatetime = timeofday.tv_sec;
 1311             }
 1312         }
 1313         /* delete finished HTTP connections */
 1314         for (e = upnphttphead.lh_first; e != NULL; e = next)
 1315         {
 1316             next = e->entries.le_next;
 1317             if(e->state >= 100)
 1318             {
 1319                 LIST_REMOVE(e, entries);
 1320                 Delete_upnphttp(e);
 1321             }
 1322         }
 1323     }
 1324 
 1325 shutdown:
 1326     /* kill the scanner */
 1327     if (GETFLAG(SCANNING_MASK) && scanner_pid)
 1328         kill(scanner_pid, SIGKILL);
 1329 
 1330     /* close out open sockets */
 1331     while (upnphttphead.lh_first != NULL)
 1332     {
 1333         e = upnphttphead.lh_first;
 1334         LIST_REMOVE(e, entries);
 1335         Delete_upnphttp(e);
 1336     }
 1337     if (sssdp >= 0)
 1338         close(sssdp);
 1339     if (shttpl >= 0)
 1340         close(shttpl);
 1341 #ifdef TIVO_SUPPORT
 1342     if (sbeacon >= 0)
 1343         close(sbeacon);
 1344 #endif
 1345     if (smonitor >= 0)
 1346         close(smonitor);
 1347     
 1348     for (i = 0; i < n_lan_addr; i++)
 1349     {
 1350         SendSSDPGoodbyes(lan_addr[i].snotify);
 1351         close(lan_addr[i].snotify);
 1352     }
 1353 
 1354     if (inotify_thread)
 1355     {
 1356         pthread_kill(inotify_thread, SIGCHLD);
 1357         pthread_join(inotify_thread, NULL);
 1358     }
 1359 
 1360     /* kill other child processes */
 1361     process_reap_children();
 1362     free(children);
 1363 
 1364     event_module.fini();
 1365 
 1366     sql_exec(db, "UPDATE SETTINGS set VALUE = '%u' where KEY = 'UPDATE_ID'", updateID);
 1367     sqlite3_close(db);
 1368 
 1369     upnpevents_removeSubscribers();
 1370 
 1371     if (pidfilename && unlink(pidfilename) < 0)
 1372         DPRINTF(E_ERROR, L_GENERAL, "Failed to remove pidfile %s: %s\n", pidfilename, strerror(errno));
 1373 
 1374     log_close();
 1375     freeoptions();
 1376 
 1377     exit(EXIT_SUCCESS);
 1378 }
 1379