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