1/* MiniDLNA project 2 * 3 * http://sourceforge.net/projects/minidlna/ 4 * (c) 2008-2009 Justin Maggard 5 * This software is subject to the conditions detailed 6 * in the LICENCE file provided within the distribution 7 * 8 * Portions of the code (c) Thomas Bernard, subject to 9 * the conditions detailed in the LICENSE.miniupnpd file. 10 */ 11#include <stdlib.h> 12#include <unistd.h> 13#include <string.h> 14#include <stdio.h> 15#include <ctype.h> 16#include <sys/types.h> 17#include <sys/socket.h> 18#include <netinet/in.h> 19#include <arpa/inet.h> 20#include <fcntl.h> 21#include <sys/file.h> 22#include <sys/time.h> 23#include <time.h> 24#include <signal.h> 25#include <sys/param.h> 26#include <errno.h> 27#include <pthread.h> 28#include <pwd.h> 29 30/* unix sockets */ 31#include "config.h" 32 33#include "upnpglobalvars.h" 34#include "sql.h" 35#include "upnphttp.h" 36#include "upnpdescgen.h" 37#include "minidlnapath.h" 38#include "getifaddr.h" 39#include "upnpsoap.h" 40#include "options.h" 41#include "utils.h" 42#include "minissdp.h" 43#include "minidlnatypes.h" 44#include "daemonize.h" 45#include "upnpevents.h" 46#include "scanner.h" 47#include "inotify.h" 48#include "log.h" 49#ifdef TIVO_SUPPORT 50#include "tivo_beacon.h" 51#include "tivo_utils.h" 52#endif 53 54#if SQLITE_VERSION_NUMBER < 3005001 55# warning "Your SQLite3 library appears to be too old! Please use 3.5.1 or newer." 56# define sqlite3_threadsafe() 0 57#endif 58 59/* OpenAndConfHTTPSocket() : 60 * setup the socket used to handle incoming HTTP connections. */ 61static int 62OpenAndConfHTTPSocket(unsigned short port) 63{ 64 int s; 65 int i = 1; 66 struct sockaddr_in listenname; 67 68 /* Initialize client type cache */ 69 memset(&clients, 0, sizeof(struct client_cache_s)); 70 71 if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0) 72 { 73 DPRINTF(E_ERROR, L_GENERAL, "socket(http): %s\n", strerror(errno)); 74 return -1; 75 } 76 77 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0) 78 { 79 DPRINTF(E_WARN, L_GENERAL, "setsockopt(http, SO_REUSEADDR): %s\n", strerror(errno)); 80 } 81 82 memset(&listenname, 0, sizeof(struct sockaddr_in)); 83 listenname.sin_family = AF_INET; 84 listenname.sin_port = htons(port); 85 listenname.sin_addr.s_addr = htonl(INADDR_ANY); 86 87 if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0) 88 { 89 DPRINTF(E_ERROR, L_GENERAL, "bind(http): %s\n", strerror(errno)); 90 close(s); 91 return -1; 92 } 93 94 if(listen(s, 6) < 0) 95 { 96 DPRINTF(E_ERROR, L_GENERAL, "listen(http): %s\n", strerror(errno)); 97 close(s); 98 return -1; 99 } 100 101 return s; 102} 103 104/* Handler for the SIGTERM signal (kill) 105 * SIGINT is also handled */ 106static void 107sigterm(int sig) 108{ 109 /*int save_errno = errno;*/ 110 signal(sig, SIG_IGN); /* Ignore this signal while we are quitting */ 111 112 DPRINTF(E_WARN, L_GENERAL, "received signal %d, good-bye\n", sig); 113 114 quitting = 1; 115 /*errno = save_errno;*/ 116} 117 118/* record the startup time, for returning uptime */ 119static void 120set_startup_time(void) 121{ 122 startup_time = time(NULL); 123} 124 125/* parselanaddr() 126 * parse address with mask 127 * ex: 192.168.1.1/24 128 * return value : 129 * 0 : ok 130 * -1 : error */ 131static int 132parselanaddr(struct lan_addr_s * lan_addr, const char * str) 133{ 134 const char * p; 135 int nbits = 24; 136 int n; 137 p = str; 138 while(*p && *p != '/' && !isspace(*p)) 139 p++; 140 n = p - str; 141 if(*p == '/') 142 { 143 nbits = atoi(++p); 144 while(*p && !isspace(*p)) 145 p++; 146 } 147 if(n>15) 148 { 149 DPRINTF(E_OFF, L_GENERAL, "Error parsing address/mask: %s\n", str); 150 return -1; 151 } 152 memcpy(lan_addr->str, str, n); 153 lan_addr->str[n] = '\0'; 154 if(!inet_aton(lan_addr->str, &lan_addr->addr)) 155 { 156 DPRINTF(E_OFF, L_GENERAL, "Error parsing address/mask: %s\n", str); 157 return -1; 158 } 159 lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0); 160 return 0; 161} 162 163void 164getfriendlyname(char * buf, int len) 165{ 166 char * dot = NULL; 167 char * hn = calloc(1, 256); 168 if( gethostname(hn, 256) == 0 ) 169 { 170 strncpy(buf, hn, len-1); 171 buf[len] = '\0'; 172 dot = index(buf, '.'); 173 if( dot ) 174 *dot = '\0'; 175 } 176 else 177 { 178 strcpy(buf, "Unknown"); 179 } 180 free(hn); 181 strcat(buf, ": "); 182 #ifdef READYNAS 183 strncat(buf, "ReadyNAS", len-strlen(buf)-1); 184 #else 185 char * logname; 186 logname = getenv("LOGNAME"); 187#if 1 // Disable for static linking 188 if( !logname ) 189 { 190 struct passwd * pwent; 191 pwent = getpwuid(getuid()); 192 if( pwent ) 193 logname = pwent->pw_name; 194 } 195#endif 196 strncat(buf, logname?logname:"Unknown", len-strlen(buf)-1); 197 #endif 198} 199 200int 201open_db(void) 202{ 203 char path[PATH_MAX]; 204 int new_db = 0; 205 206 snprintf(path, sizeof(path), "%s/files.db", db_path); 207 if( access(path, F_OK) != 0 ) 208 { 209 new_db = 1; 210 make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); 211 } 212 if( sqlite3_open(path, &db) != SQLITE_OK ) 213 { 214 DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to open sqlite database! Exiting...\n"); 215 } 216 sqlite3_busy_timeout(db, 5000); 217 sql_exec(db, "pragma page_size = 4096"); 218 sql_exec(db, "pragma journal_mode = OFF"); 219 sql_exec(db, "pragma synchronous = OFF;"); 220 sql_exec(db, "pragma default_cache_size = 8192;"); 221 return new_db; 222} 223 224/* init phase : 225 * 1) read configuration file 226 * 2) read command line arguments 227 * 3) daemonize 228 * 4) check and write pid file 229 * 5) set startup time stamp 230 * 6) compute presentation URL 231 * 7) set signal handlers */ 232static int 233init(int argc, char * * argv) 234{ 235 int i; 236 int pid; 237 int debug_flag = 0; 238 int options_flag = 0; 239 struct sigaction sa; 240 /*const char * logfilename = 0;*/ 241 const char * presurl = 0; 242 const char * optionsfile = "/etc/minidlna.conf"; 243 char mac_str[13]; 244 char * string, * word; 245 enum media_types type; 246 char * path; 247 char real_path[PATH_MAX]; 248 char ext_ip_addr[INET_ADDRSTRLEN] = {'\0'}; 249 250 /* first check if "-f" option is used */ 251 for(i=2; i<argc; i++) 252 { 253 if(0 == strcmp(argv[i-1], "-f")) 254 { 255 optionsfile = argv[i]; 256 options_flag = 1; 257 break; 258 } 259 } 260 261 /* set up uuid based on mac address */ 262 if( getsyshwaddr(mac_str, sizeof(mac_str)) < 0 ) 263 { 264 DPRINTF(E_OFF, L_GENERAL, "No MAC address found. Falling back to generic UUID.\n"); 265 strcpy(mac_str, "554e4b4e4f57"); 266 } 267 strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-"); 268 strncat(uuidvalue, mac_str, 12); 269 270 getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN); 271 272 runtime_vars.port = -1; 273 runtime_vars.notify_interval = 895; /* seconds between SSDP announces */ 274 275 /* read options file first since 276 * command line arguments have final say */ 277 if(readoptionsfile(optionsfile) < 0) 278 { 279 /* only error if file exists or using -f */ 280 if(access(optionsfile, F_OK) == 0 || options_flag) 281 fprintf(stderr, "Error reading configuration file %s\n", optionsfile); 282 } 283 else 284 { 285 for(i=0; i<num_options; i++) 286 { 287 switch(ary_options[i].id) 288 { 289 case UPNPIFNAME: 290 if(getifaddr(ary_options[i].value, ext_ip_addr, INET_ADDRSTRLEN) >= 0) 291 { 292 if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) 293 n_lan_addr++; 294 } 295 else 296 fprintf(stderr, "Interface %s not found, ignoring.\n", ary_options[i].value); 297 break; 298 case UPNPLISTENING_IP: 299 if(n_lan_addr < MAX_LAN_ADDR) 300 { 301 if(parselanaddr(&lan_addr[n_lan_addr], 302 ary_options[i].value) == 0) 303 n_lan_addr++; 304 } 305 else 306 { 307 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", 308 MAX_LAN_ADDR, ary_options[i].value); 309 } 310 break; 311 case UPNPPORT: 312 runtime_vars.port = atoi(ary_options[i].value); 313 break; 314 case UPNPPRESENTATIONURL: 315 presurl = ary_options[i].value; 316 break; 317 case UPNPNOTIFY_INTERVAL: 318 runtime_vars.notify_interval = atoi(ary_options[i].value); 319 break; 320 case UPNPSERIAL: 321 strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); 322 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; 323 break; 324 case UPNPMODEL_NUMBER: 325 strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN); 326 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; 327 break; 328 case UPNPFRIENDLYNAME: 329 strncpy(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN); 330 friendly_name[FRIENDLYNAME_MAX_LEN-1] = '\0'; 331 break; 332 case UPNPMEDIADIR: 333 type = ALL_MEDIA; 334 char * myval = NULL; 335 switch( ary_options[i].value[0] ) 336 { 337 case 'A': 338 case 'a': 339 if( ary_options[i].value[0] == 'A' || ary_options[i].value[0] == 'a' ) 340 type = AUDIO_ONLY; 341 case 'V': 342 case 'v': 343 if( ary_options[i].value[0] == 'V' || ary_options[i].value[0] == 'v' ) 344 type = VIDEO_ONLY; 345 case 'P': 346 case 'p': 347 if( ary_options[i].value[0] == 'P' || ary_options[i].value[0] == 'p' ) 348 type = IMAGES_ONLY; 349 myval = index(ary_options[i].value, '/'); 350 case '/': 351 path = realpath(myval ? myval:ary_options[i].value, real_path); 352 if( !path ) 353 path = (myval ? myval:ary_options[i].value); 354 if( access(path, F_OK) != 0 ) 355 { 356 fprintf(stderr, "Media directory not accessible! [%s]\n", 357 path); 358 break; 359 } 360 struct media_dir_s * this_dir = calloc(1, sizeof(struct media_dir_s)); 361 this_dir->path = strdup(path); 362 this_dir->type = type; 363 if( !media_dirs ) 364 { 365 media_dirs = this_dir; 366 } 367 else 368 { 369 struct media_dir_s * all_dirs = media_dirs; 370 while( all_dirs->next ) 371 all_dirs = all_dirs->next; 372 all_dirs->next = this_dir; 373 } 374 break; 375 default: 376 fprintf(stderr, "Media directory entry not understood! [%s]\n", 377 ary_options[i].value); 378 break; 379 } 380 break; 381 case UPNPALBUMART_NAMES: 382 for( string = ary_options[i].value; (word = strtok(string, "/")); string = NULL ) { 383 struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s)); 384 this_name->name = strdup(word); 385 if( !album_art_names ) 386 { 387 album_art_names = this_name; 388 } 389 else 390 { 391 struct album_art_name_s * all_names = album_art_names; 392 while( all_names->next ) 393 all_names = all_names->next; 394 all_names->next = this_name; 395 } 396 } 397 break; 398 case UPNPDBDIR: 399 path = realpath(ary_options[i].value, real_path); 400 if( !path ) 401 path = (ary_options[i].value); 402 make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); 403 if( access(path, F_OK) != 0 ) 404 { 405 DPRINTF(E_FATAL, L_GENERAL, "Database path not accessible! [%s]\n", path); 406 break; 407 } 408 strncpy(db_path, path, PATH_MAX); 409 break; 410 case UPNPINOTIFY: 411 if( (strcmp(ary_options[i].value, "yes") != 0) && !atoi(ary_options[i].value) ) 412 CLEARFLAG(INOTIFY_MASK); 413 break; 414 case ENABLE_TIVO: 415 if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) 416 SETFLAG(TIVO_MASK); 417 break; 418 case ENABLE_DLNA_STRICT: 419 if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) ) 420 SETFLAG(DLNA_STRICT_MASK); 421 break; 422 default: 423 fprintf(stderr, "Unknown option in file %s\n", 424 optionsfile); 425 } 426 } 427 } 428 429 /* command line arguments processing */ 430 for(i=1; i<argc; i++) 431 { 432 if(argv[i][0]!='-') 433 { 434 fprintf(stderr, "Unknown option: %s\n", argv[i]); 435 } 436 else if(strcmp(argv[i], "--help")==0) 437 { 438 runtime_vars.port = 0; 439 break; 440 } 441 else switch(argv[i][1]) 442 { 443 case 't': 444 if(i+1 < argc) 445 runtime_vars.notify_interval = atoi(argv[++i]); 446 else 447 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 448 break; 449 case 's': 450 if(i+1 < argc) 451 strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN); 452 else 453 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 454 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; 455 break; 456 case 'm': 457 if(i+1 < argc) 458 strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN); 459 else 460 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 461 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; 462 break; 463 /*case 'l': 464 logfilename = argv[++i]; 465 break;*/ 466 case 'p': 467 if(i+1 < argc) 468 runtime_vars.port = atoi(argv[++i]); 469 else 470 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 471 break; 472 case 'P': 473 if(i+1 < argc) 474 pidfilename = argv[++i]; 475 else 476 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 477 break; 478 case 'd': 479 debug_flag = 1; 480 break; 481 case 'w': 482 if(i+1 < argc) 483 presurl = argv[++i]; 484 else 485 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 486 break; 487 case 'a': 488 if(i+1 < argc) 489 { 490 int address_already_there = 0; 491 int j; 492 i++; 493 for(j=0; j<n_lan_addr; j++) 494 { 495 struct lan_addr_s tmpaddr; 496 parselanaddr(&tmpaddr, argv[i]); 497 if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) 498 address_already_there = 1; 499 } 500 if(address_already_there) 501 break; 502 if(n_lan_addr < MAX_LAN_ADDR) 503 { 504 if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0) 505 n_lan_addr++; 506 } 507 else 508 { 509 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", 510 MAX_LAN_ADDR, argv[i]); 511 } 512 } 513 else 514 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 515 break; 516 case 'i': 517 if(i+1 < argc) 518 { 519 int address_already_there = 0; 520 int j; 521 i++; 522 if( getifaddr(argv[i], ext_ip_addr, INET_ADDRSTRLEN) < 0 ) 523 { 524 fprintf(stderr, "Network interface '%s' not found.\n", 525 argv[i]); 526 exit(-1); 527 } 528 for(j=0; j<n_lan_addr; j++) 529 { 530 struct lan_addr_s tmpaddr; 531 parselanaddr(&tmpaddr, ext_ip_addr); 532 if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) 533 address_already_there = 1; 534 } 535 if(address_already_there) 536 break; 537 if(n_lan_addr < MAX_LAN_ADDR) 538 { 539 if(parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0) 540 n_lan_addr++; 541 } 542 else 543 { 544 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", 545 MAX_LAN_ADDR, argv[i]); 546 } 547 } 548 else 549 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); 550 break; 551 case 'f': 552 i++; /* discarding, the config file is already read */ 553 break; 554 case 'h': 555 runtime_vars.port = 0; // triggers help display 556 break; 557 case 'R': 558 snprintf(real_path, sizeof(real_path), "rm -rf %s", db_path); 559 system(real_path); 560 break; 561 case 'V': 562 printf("Version " MINIDLNA_VERSION "\n"); 563 exit(0); 564 break; 565 default: 566 fprintf(stderr, "Unknown option: %s\n", argv[i]); 567 } 568 } 569 /* If no IP was specified, try to detect one */ 570 if( n_lan_addr < 1 ) 571 { 572 if( (getsysaddr(ext_ip_addr, INET_ADDRSTRLEN) < 0) && 573 (getifaddr("eth0", ext_ip_addr, INET_ADDRSTRLEN) < 0) && 574 (getifaddr("eth1", ext_ip_addr, INET_ADDRSTRLEN) < 0) ) 575 { 576 DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); 577 } 578 if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) 579 { 580 n_lan_addr++; 581 } 582 } 583 584 if( (n_lan_addr==0) || (runtime_vars.port<=0) ) 585 { 586 fprintf(stderr, "Usage:\n\t" 587 "%s [-d] [-f config_file]\n" 588 "\t\t[-a listening_ip] [-p port]\n" 589 /*"[-l logfile] " not functionnal */ 590 "\t\t[-s serial] [-m model_number] \n" 591 "\t\t[-t notify_interval] [-P pid_filename]\n" 592 "\t\t[-w url] [-R] [-V] [-h]\n" 593 "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n" 594 "\tDefault pid file is %s.\n" 595 "\tWith -d minidlna will run in debug mode (not daemonize).\n" 596 "\t-w sets the presentation url. Default is http address on port 80\n" 597 "\t-h displays this text\n" 598 "\t-R forces a full rescan\n" 599 "\t-V print the version number\n", 600 argv[0], pidfilename); 601 return 1; 602 } 603 604 if(debug_flag) 605 { 606 pid = getpid(); 607 log_init(NULL, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=debug"); 608 } 609 else 610 { 611#ifdef USE_DAEMON 612 if(daemon(0, 0)<0) { 613 perror("daemon()"); 614 } 615 pid = getpid(); 616#else 617 pid = daemonize(); 618#endif 619 #ifdef READYNAS 620 log_init("/var/log/upnp-av.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"); 621 #else 622 if( access(db_path, F_OK) != 0 ) 623 make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); 624 sprintf(real_path, "%s/minidlna.log", db_path); 625 log_init(real_path, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"); 626 #endif 627 } 628 629 if(checkforrunning(pidfilename) < 0) 630 { 631 DPRINTF(E_ERROR, L_GENERAL, "MiniDLNA is already running. EXITING.\n"); 632 return 1; 633 } 634 635 set_startup_time(); 636 637 /* presentation url */ 638 if(presurl) 639 { 640 strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN); 641 presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0'; 642 strncpy(device_url, presurl, PRESENTATIONURL_MAX_LEN); 643 device_url[PRESENTATIONURL_MAX_LEN-1] = '\0'; 644 } 645 else 646 { 647#ifdef READYNAS 648 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, 649 "http://%s/admin/", lan_addr[0].str); 650#else 651 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, 652 "http://%s:%d", lan_addr[0].str, runtime_vars.port); 653 snprintf(device_url, PRESENTATIONURL_MAX_LEN, 654 "http://%s", lan_addr[0].str); 655#endif 656 } 657 658 /* set signal handler */ 659 signal(SIGCLD, SIG_IGN); 660 memset(&sa, 0, sizeof(struct sigaction)); 661 sa.sa_handler = sigterm; 662 if (sigaction(SIGTERM, &sa, NULL)) 663 { 664 DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGTERM handler. EXITING.\n"); 665 } 666 if (sigaction(SIGINT, &sa, NULL)) 667 { 668 DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGINT handler. EXITING.\n"); 669 } 670 671 if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 672 DPRINTF(E_FATAL, L_GENERAL, "Failed to ignore SIGPIPE signals. EXITING.\n"); 673 } 674 675 writepidfile(pidfilename, pid); 676 677 return 0; 678} 679 680/* === main === */ 681/* process HTTP or SSDP requests */ 682int 683main(int argc, char * * argv) 684{ 685 int i; 686 int sudp = -1, shttpl = -1; 687 int snotify[MAX_LAN_ADDR]; 688 LIST_HEAD(httplisthead, upnphttp) upnphttphead; 689 struct upnphttp * e = 0; 690 struct upnphttp * next; 691 fd_set readset; /* for select() */ 692 fd_set writeset; 693 struct timeval timeout, timeofday, lastnotifytime = {0, 0}, lastupdatetime = {0, 0}; 694 int max_fd = -1; 695 int last_changecnt = 0; 696 short int new_db = 0; 697 pid_t scanner_pid = 0; 698 pthread_t inotify_thread = 0; 699#ifdef TIVO_SUPPORT 700 unsigned short int beacon_interval = 5; 701 int sbeacon = -1; 702 struct sockaddr_in tivo_bcast; 703 struct timeval lastbeacontime = {0, 0}; 704#endif 705 706 if(init(argc, argv) != 0) 707 return 1; 708 709#ifdef READYNAS 710 DPRINTF(E_WARN, L_GENERAL, "Starting ReadyDLNA version " MINIDLNA_VERSION ".\n"); 711 unlink("/ramfs/.upnp-av_scan"); 712#else 713 DPRINTF(E_WARN, L_GENERAL, "Starting MiniDLNA version " MINIDLNA_VERSION " [SQLite %s].\n", sqlite3_libversion()); 714 if( !sqlite3_threadsafe() ) 715 { 716 DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe! " 717 "Scanning must be finished before file serving can begin, " 718 "and inotify will be disabled.\n"); 719 } 720 if( sqlite3_libversion_number() < 3005001 ) 721 { 722 DPRINTF(E_WARN, L_GENERAL, "SQLite library is old. Please use version 3.5.1 or newer.\n"); 723 } 724#endif 725 LIST_INIT(&upnphttphead); 726 727 new_db = open_db(); 728 if( !new_db ) 729 { 730 updateID = sql_get_int_field(db, "SELECT UPDATE_ID from SETTINGS"); 731 } 732 if( sql_get_int_field(db, "pragma user_version") != DB_VERSION ) 733 { 734 if( new_db ) 735 { 736 DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n"); 737 } 738 else 739 { 740 DPRINTF(E_WARN, L_GENERAL, "Database version mismatch; need to recreate...\n"); 741 } 742 sqlite3_close(db); 743 char *cmd; 744 asprintf(&cmd, "rm -rf %s/files.db %s/art_cache", db_path, db_path); 745 system(cmd); 746 free(cmd); 747 open_db(); 748 if( CreateDatabase() != 0 ) 749 { 750 DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n"); 751 } 752#if USE_FORK 753 scanning = 1; 754 sqlite3_close(db); 755 scanner_pid = fork(); 756 open_db(); 757 if( !scanner_pid ) // child (scanner) process 758 { 759 start_scanner(); 760 sqlite3_close(db); 761 exit(EXIT_SUCCESS); 762 } 763#else 764 start_scanner(); 765#endif 766 } 767 if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 && 768 GETFLAG(INOTIFY_MASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) ) 769 { 770 DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify.\n"); 771 } 772 773 sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr); 774 if(sudp < 0) 775 { 776 DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for receiving SSDP. EXITING\n"); 777 } 778 /* open socket for HTTP connections. Listen on the 1st LAN address */ 779 shttpl = OpenAndConfHTTPSocket(runtime_vars.port); 780 if(shttpl < 0) 781 { 782 DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for HTTP. EXITING\n"); 783 } 784 DPRINTF(E_WARN, L_GENERAL, "HTTP listening on port %d\n", runtime_vars.port); 785 786 /* open socket for sending notifications */ 787 if(OpenAndConfSSDPNotifySockets(snotify) < 0) 788 { 789 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending SSDP notify " 790 "messages. EXITING\n"); 791 } 792 793#ifdef TIVO_SUPPORT 794 if( GETFLAG(TIVO_MASK) ) 795 { 796 DPRINTF(E_WARN, L_GENERAL, "TiVo support is enabled.\n"); 797 /* Add TiVo-specific randomize function to sqlite */ 798 if( sqlite3_create_function(db, "tivorandom", 1, SQLITE_UTF8, NULL, &TiVoRandomSeedFunc, NULL, NULL) != SQLITE_OK ) 799 { 800 DPRINTF(E_ERROR, L_TIVO, "ERROR: Failed to add sqlite randomize function for TiVo!\n"); 801 } 802 /* open socket for sending Tivo notifications */ 803 sbeacon = OpenAndConfTivoBeaconSocket(); 804 if(sbeacon < 0) 805 { 806 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify " 807 "messages. EXITING\n"); 808 } 809 tivo_bcast.sin_family = AF_INET; 810 tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress()); 811 tivo_bcast.sin_port = htons(2190); 812 } 813 else 814 { 815 sbeacon = -1; 816 } 817#endif 818 819 SendSSDPGoodbye(snotify, n_lan_addr); 820 821 /* main loop */ 822 while(!quitting) 823 { 824 /* Check if we need to send SSDP NOTIFY messages and do it if 825 * needed */ 826 if(gettimeofday(&timeofday, 0) < 0) 827 { 828 DPRINTF(E_ERROR, L_GENERAL, "gettimeofday(): %s\n", strerror(errno)); 829 timeout.tv_sec = runtime_vars.notify_interval; 830 timeout.tv_usec = 0; 831 } 832 else 833 { 834 /* the comparaison is not very precise but who cares ? */ 835 if(timeofday.tv_sec >= (lastnotifytime.tv_sec + runtime_vars.notify_interval)) 836 { 837 SendSSDPNotifies2(snotify, 838 (unsigned short)runtime_vars.port, 839 (runtime_vars.notify_interval << 1)+10); 840 memcpy(&lastnotifytime, &timeofday, sizeof(struct timeval)); 841 timeout.tv_sec = runtime_vars.notify_interval; 842 timeout.tv_usec = 0; 843 } 844 else 845 { 846 timeout.tv_sec = lastnotifytime.tv_sec + runtime_vars.notify_interval 847 - timeofday.tv_sec; 848 if(timeofday.tv_usec > lastnotifytime.tv_usec) 849 { 850 timeout.tv_usec = 1000000 + lastnotifytime.tv_usec 851 - timeofday.tv_usec; 852 timeout.tv_sec--; 853 } 854 else 855 { 856 timeout.tv_usec = lastnotifytime.tv_usec - timeofday.tv_usec; 857 } 858 } 859#ifdef TIVO_SUPPORT 860 if( GETFLAG(TIVO_MASK) ) 861 { 862 if(timeofday.tv_sec >= (lastbeacontime.tv_sec + beacon_interval)) 863 { 864 sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1); 865 memcpy(&lastbeacontime, &timeofday, sizeof(struct timeval)); 866 if( timeout.tv_sec > beacon_interval ) 867 { 868 timeout.tv_sec = beacon_interval; 869 timeout.tv_usec = 0; 870 } 871 /* Beacons should be sent every 5 seconds or so for the first minute, 872 * then every minute or so thereafter. */ 873 if( beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60 ) 874 { 875 beacon_interval = 60; 876 } 877 } 878 else if( timeout.tv_sec > (lastbeacontime.tv_sec + beacon_interval + 1 - timeofday.tv_sec) ) 879 { 880 timeout.tv_sec = lastbeacontime.tv_sec + beacon_interval - timeofday.tv_sec; 881 } 882 } 883#endif 884 } 885 886 if( scanning ) 887 { 888 if( !scanner_pid || kill(scanner_pid, 0) ) 889 scanning = 0; 890 } 891 892 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ 893 FD_ZERO(&readset); 894 895 if (sudp >= 0) 896 { 897 FD_SET(sudp, &readset); 898 max_fd = MAX( max_fd, sudp); 899 } 900 901 if (shttpl >= 0) 902 { 903 FD_SET(shttpl, &readset); 904 max_fd = MAX( max_fd, shttpl); 905 } 906 907 i = 0; /* active HTTP connections count */ 908 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) 909 { 910 if((e->socket >= 0) && (e->state <= 2)) 911 { 912 FD_SET(e->socket, &readset); 913 max_fd = MAX( max_fd, e->socket); 914 i++; 915 } 916 } 917 /* for debug */ 918#ifdef DEBUG 919 if(i > 1) 920 { 921 DPRINTF(E_DEBUG, L_GENERAL, "%d active incoming HTTP connections\n", i); 922 } 923#endif 924 925 FD_ZERO(&writeset); 926 upnpevents_selectfds(&readset, &writeset, &max_fd); 927 928 if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0) 929 { 930 if(quitting) goto shutdown; 931 DPRINTF(E_ERROR, L_GENERAL, "select(all): %s\n", strerror(errno)); 932 DPRINTF(E_FATAL, L_GENERAL, "Failed to select open sockets. EXITING\n"); 933 } 934 upnpevents_processfds(&readset, &writeset); 935 /* process SSDP packets */ 936 if(sudp >= 0 && FD_ISSET(sudp, &readset)) 937 { 938 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/ 939 ProcessSSDPRequest(sudp, (unsigned short)runtime_vars.port); 940 } 941 /* increment SystemUpdateID if the content database has changed, 942 * and if there is an active HTTP connection, at most once every 2 seconds */ 943 if( i && (time(NULL) >= (lastupdatetime.tv_sec + 2)) ) 944 { 945 if( sqlite3_total_changes(db) != last_changecnt ) 946 { 947 updateID++; 948 last_changecnt = sqlite3_total_changes(db); 949 upnp_event_var_change_notify(EContentDirectory); 950 memcpy(&lastupdatetime, &timeofday, sizeof(struct timeval)); 951 } 952 } 953 /* process active HTTP connections */ 954 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) 955 { 956 if( (e->socket >= 0) && (e->state <= 2) 957 &&(FD_ISSET(e->socket, &readset)) ) 958 { 959 Process_upnphttp(e); 960 } 961 } 962 /* process incoming HTTP connections */ 963 if(shttpl >= 0 && FD_ISSET(shttpl, &readset)) 964 { 965 int shttp; 966 socklen_t clientnamelen; 967 struct sockaddr_in clientname; 968 clientnamelen = sizeof(struct sockaddr_in); 969 shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); 970 if(shttp<0) 971 { 972 DPRINTF(E_ERROR, L_GENERAL, "accept(http): %s\n", strerror(errno)); 973 } 974 else 975 { 976 struct upnphttp * tmp = 0; 977 DPRINTF(E_DEBUG, L_GENERAL, "HTTP connection from %s:%d\n", 978 inet_ntoa(clientname.sin_addr), 979 ntohs(clientname.sin_port) ); 980 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) { 981 DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK"); 982 }*/ 983 /* Create a new upnphttp object and add it to 984 * the active upnphttp object list */ 985 tmp = New_upnphttp(shttp); 986 if(tmp) 987 { 988 tmp->clientaddr = clientname.sin_addr; 989 LIST_INSERT_HEAD(&upnphttphead, tmp, entries); 990 } 991 else 992 { 993 DPRINTF(E_ERROR, L_GENERAL, "New_upnphttp() failed\n"); 994 close(shttp); 995 } 996 } 997 } 998 /* delete finished HTTP connections */ 999 for(e = upnphttphead.lh_first; e != NULL; ) 1000 { 1001 next = e->entries.le_next; 1002 if(e->state >= 100) 1003 { 1004 LIST_REMOVE(e, entries); 1005 Delete_upnphttp(e); 1006 } 1007 e = next; 1008 } 1009 } 1010 1011shutdown: 1012 /* kill the scanner */ 1013 if( scanning && scanner_pid ) 1014 { 1015 kill(scanner_pid, 9); 1016 } 1017 /* close out open sockets */ 1018 while(upnphttphead.lh_first != NULL) 1019 { 1020 e = upnphttphead.lh_first; 1021 LIST_REMOVE(e, entries); 1022 Delete_upnphttp(e); 1023 } 1024 1025 if (sudp >= 0) close(sudp); 1026 if (shttpl >= 0) close(shttpl); 1027 #ifdef TIVO_SUPPORT 1028 if (sbeacon >= 0) close(sbeacon); 1029 #endif 1030 1031 if(SendSSDPGoodbye(snotify, n_lan_addr) < 0) 1032 { 1033 DPRINTF(E_ERROR, L_GENERAL, "Failed to broadcast good-bye notifications\n"); 1034 } 1035 for(i=0; i<n_lan_addr; i++) 1036 close(snotify[i]); 1037 1038 if( inotify_thread ) 1039 pthread_join(inotify_thread, NULL); 1040 1041 sql_exec(db, "UPDATE SETTINGS set UPDATE_ID = %u", updateID); 1042 sqlite3_close(db); 1043 1044 struct media_dir_s * media_path = media_dirs; 1045 struct media_dir_s * last_path; 1046 while( media_path ) 1047 { 1048 free(media_path->path); 1049 last_path = media_path; 1050 media_path = media_path->next; 1051 free(last_path); 1052 } 1053 struct album_art_name_s * art_names = album_art_names; 1054 struct album_art_name_s * last_name; 1055 while( art_names ) 1056 { 1057 free(art_names->name); 1058 last_name = art_names; 1059 art_names = art_names->next; 1060 free(last_name); 1061 } 1062 1063 if(unlink(pidfilename) < 0) 1064 { 1065 DPRINTF(E_ERROR, L_GENERAL, "Failed to remove pidfile %s: %s\n", pidfilename, strerror(errno)); 1066 } 1067 1068 freeoptions(); 1069 1070 exit(EXIT_SUCCESS); 1071} 1072 1073