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