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