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 if(debug_flag) 634 { 635 pid = getpid(); 636 log_init(NULL, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=debug"); 637 } 638 else 639 { 640#ifdef USE_DAEMON 641 if(daemon(0, 0)<0) { 642 perror("daemon()"); 643 } 644 pid = getpid(); 645#else 646 pid = daemonize(); 647#endif 648 #ifdef READYNAS 649 log_init("/var/log/upnp-av.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"); 650 #else 651 if( access(db_path, F_OK) != 0 ) 652 make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO); 653 sprintf(real_path, "%s/minidlna.log", db_path); 654 log_init(real_path, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn"); 655 #endif 656 } 657 658 if(checkforrunning(pidfilename) < 0) 659 { 660 DPRINTF(E_ERROR, L_GENERAL, "MiniDLNA is already running. EXITING.\n"); 661 return 1; 662 } 663 664 set_startup_time(); 665 666 /* presentation url */ 667 if(presurl) 668 { 669 strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN); 670 presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0'; 671 } 672 else 673 { 674#ifdef READYNAS 675 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, 676 "http://%s/admin/", lan_addr[0].str); 677#else 678 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN, 679 "http://%s:%d/", lan_addr[0].str, runtime_vars.port); 680#endif 681 } 682 683 /* set signal handler */ 684 signal(SIGCLD, SIG_IGN); 685 memset(&sa, 0, sizeof(struct sigaction)); 686 sa.sa_handler = sigterm; 687 if (sigaction(SIGTERM, &sa, NULL)) 688 { 689 DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGTERM handler. EXITING.\n"); 690 } 691 if (sigaction(SIGINT, &sa, NULL)) 692 { 693 DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGINT handler. EXITING.\n"); 694 } 695 696 if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) { 697 DPRINTF(E_FATAL, L_GENERAL, "Failed to ignore SIGPIPE signals. EXITING.\n"); 698 } 699 700 writepidfile(pidfilename, pid); 701 702 return 0; 703} 704 705/* === main === */ 706/* process HTTP or SSDP requests */ 707int 708main(int argc, char * * argv) 709{ 710 int i; 711 int sudp = -1, shttpl = -1; 712 int snotify[MAX_LAN_ADDR]; 713 LIST_HEAD(httplisthead, upnphttp) upnphttphead; 714 struct upnphttp * e = 0; 715 struct upnphttp * next; 716 fd_set readset; /* for select() */ 717 fd_set writeset; 718 struct timeval timeout, timeofday, lastnotifytime = {0, 0}, lastupdatetime = {0, 0}; 719 int max_fd = -1; 720 int last_changecnt = 0; 721 short int new_db = 0; 722 pid_t scanner_pid = 0; 723 pthread_t inotify_thread = 0; 724 struct media_dir_s *media_path, *last_path; 725 struct album_art_name_s *art_names, *last_name; 726#ifdef TIVO_SUPPORT 727 unsigned short int beacon_interval = 5; 728 int sbeacon = -1; 729 struct sockaddr_in tivo_bcast; 730 struct timeval lastbeacontime = {0, 0}; 731#endif 732 733 /* Foxconn, Michael */ 734 int pid = 0; 735 int prio = -20; // I give minidlna the highest priority. 736 737#ifdef ENABLE_NLS 738 setlocale(LC_MESSAGES, ""); 739 setlocale(LC_CTYPE, "en_US.utf8"); 740 textdomain("minidlna"); 741#endif 742 743 if(init(argc, argv) != 0) 744 return 1; 745 746 /* Foxconn, Michael */ 747 pid = getpid(); 748 errno = setpriority(PRIO_PROCESS, pid, prio); 749 750#ifdef READYNAS 751 DPRINTF(E_WARN, L_GENERAL, "Starting ReadyDLNA version " MINIDLNA_VERSION ".\n"); 752 unlink("/ramfs/.upnp-av_scan"); 753#else 754 DPRINTF(E_WARN, L_GENERAL, "Starting MiniDLNA version " MINIDLNA_VERSION " [SQLite %s].\n", sqlite3_libversion()); 755 if( !sqlite3_threadsafe() ) 756 { 757 DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe! " 758 "Scanning must be finished before file serving can begin, " 759 "and inotify will be disabled.\n"); 760 } 761 if( sqlite3_libversion_number() < 3005001 ) 762 { 763 DPRINTF(E_WARN, L_GENERAL, "SQLite library is old. Please use version 3.5.1 or newer.\n"); 764 } 765#endif 766 LIST_INIT(&upnphttphead); 767 768 new_db = open_db(ID_MAINTHREAD); 769 if( !new_db ) 770 { 771 updateID = sql_get_int_field(db, "SELECT UPDATE_ID from SETTINGS"); 772 } 773 if( sql_get_int_field(db, "pragma user_version") != DB_VERSION ) 774 { 775 if( new_db ) 776 { 777 DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n"); 778 } 779 else 780 { 781 DPRINTF(E_WARN, L_GENERAL, "Database version mismatch; need to recreate...\n"); 782 } 783 sqlite3_close(db); 784 char *cmd; 785 asprintf(&cmd, "rm -rf %s/files.db %s/art_cache", db_path, db_path); 786 system(cmd); 787 free(cmd); 788 open_db(ID_MAINTHREAD); 789 if( CreateDatabase() != 0 ) 790 { 791 DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n"); 792 } 793#if USE_FORK 794 scanning = 1; 795 sqlite3_close(db); 796 scanner_pid = fork(); 797 //open_db(); 798 if( !scanner_pid ) // child (scanner) process 799 { 800 open_db(ID_SCANNER); 801 start_scanner(); 802 sqlite3_close(db); 803 media_path = media_dirs; 804 art_names = album_art_names; 805 while( media_path ) 806 { 807 free(media_path->path); 808 last_path = media_path; 809 media_path = media_path->next; 810 free(last_path); 811 } 812 while( art_names ) 813 { 814 free(art_names->name); 815 last_name = art_names; 816 art_names = art_names->next; 817 free(last_name); 818 } 819 freeoptions(); 820 exit(EXIT_SUCCESS); 821 }else{ // father (main) process 822 open_db(ID_MAINTHREAD); 823 } 824#else 825 start_scanner(); 826#endif 827 } 828 if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 && 829 GETFLAG(INOTIFY_MASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) ) 830 { 831 DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify.\n"); 832 } 833 834 sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr); 835 if(sudp < 0) 836 { 837 DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for receiving SSDP. EXITING\n"); 838 } 839 /* open socket for HTTP connections. Listen on the 1st LAN address */ 840 shttpl = OpenAndConfHTTPSocket(runtime_vars.port); 841 if(shttpl < 0) 842 { 843 DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for HTTP. EXITING\n"); 844 } 845 DPRINTF(E_WARN, L_GENERAL, "HTTP listening on port %d\n", runtime_vars.port); 846 847 /* open socket for sending notifications */ 848 if(OpenAndConfSSDPNotifySockets(snotify) < 0) 849 { 850 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending SSDP notify " 851 "messages. EXITING\n"); 852 } 853 854#ifdef TIVO_SUPPORT 855 if( GETFLAG(TIVO_MASK) ) 856 { 857 DPRINTF(E_WARN, L_GENERAL, "TiVo support is enabled.\n"); 858 /* Add TiVo-specific randomize function to sqlite */ 859 if( sqlite3_create_function(db, "tivorandom", 1, SQLITE_UTF8, NULL, &TiVoRandomSeedFunc, NULL, NULL) != SQLITE_OK ) 860 { 861 DPRINTF(E_ERROR, L_TIVO, "ERROR: Failed to add sqlite randomize function for TiVo!\n"); 862 } 863 /* open socket for sending Tivo notifications */ 864 sbeacon = OpenAndConfTivoBeaconSocket(); 865 if(sbeacon < 0) 866 { 867 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify " 868 "messages. EXITING\n"); 869 } 870 tivo_bcast.sin_family = AF_INET; 871 tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress()); 872 tivo_bcast.sin_port = htons(2190); 873 } 874 else 875 { 876 sbeacon = -1; 877 } 878#endif 879 880 /*Foxconn modify start by Hank 12/08/2011*/ 881 /*dismark SendSSDPGoodbye because dlna will fail with no byebye message back 882 test upnp must kill minidlna process*/ 883 /* foxconn removed, zacker, 07/05/2011 */ 884 /* Don't send ssdp:byebye notifications at startup or else 885 * UPnP certification test case 2.0.0.0 and 2.0.0.1 will fail 886 */ 887 SendSSDPGoodbye(snotify, n_lan_addr); 888 /*Foxconn modify end by Hank 12/08/2011*/ 889 890 /* main loop */ 891 while(!quitting) 892 { 893 /* Check if we need to send SSDP NOTIFY messages and do it if 894 * needed */ 895 if(gettimeofday(&timeofday, 0) < 0) 896 { 897 DPRINTF(E_ERROR, L_GENERAL, "gettimeofday(): %s\n", strerror(errno)); 898 timeout.tv_sec = runtime_vars.notify_interval; 899 timeout.tv_usec = 0; 900 } 901 else 902 { 903 /* the comparaison is not very precise but who cares ? */ 904 if(timeofday.tv_sec >= (lastnotifytime.tv_sec + runtime_vars.notify_interval)) 905 { 906 SendSSDPNotifies2(snotify, 907 (unsigned short)runtime_vars.port, 908 (runtime_vars.notify_interval << 1)+10); 909 memcpy(&lastnotifytime, &timeofday, sizeof(struct timeval)); 910 timeout.tv_sec = runtime_vars.notify_interval; 911 timeout.tv_usec = 0; 912 } 913 else 914 { 915 timeout.tv_sec = lastnotifytime.tv_sec + runtime_vars.notify_interval 916 - timeofday.tv_sec; 917 if(timeofday.tv_usec > lastnotifytime.tv_usec) 918 { 919 timeout.tv_usec = 1000000 + lastnotifytime.tv_usec 920 - timeofday.tv_usec; 921 timeout.tv_sec--; 922 } 923 else 924 { 925 timeout.tv_usec = lastnotifytime.tv_usec - timeofday.tv_usec; 926 } 927 } 928#ifdef TIVO_SUPPORT 929 if( GETFLAG(TIVO_MASK) ) 930 { 931 if(timeofday.tv_sec >= (lastbeacontime.tv_sec + beacon_interval)) 932 { 933 sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1); 934 memcpy(&lastbeacontime, &timeofday, sizeof(struct timeval)); 935 if( timeout.tv_sec > beacon_interval ) 936 { 937 timeout.tv_sec = beacon_interval; 938 timeout.tv_usec = 0; 939 } 940 /* Beacons should be sent every 5 seconds or so for the first minute, 941 * then every minute or so thereafter. */ 942 if( beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60 ) 943 { 944 beacon_interval = 60; 945 } 946 } 947 else if( timeout.tv_sec > (lastbeacontime.tv_sec + beacon_interval + 1 - timeofday.tv_sec) ) 948 { 949 timeout.tv_sec = lastbeacontime.tv_sec + beacon_interval - timeofday.tv_sec; 950 } 951 } 952#endif 953 } 954 955 if( scanning ) 956 { 957 int status; 958 if( !scanner_pid || kill(scanner_pid, 0) ) 959 scanning = 0; 960 /* Foxconn, MJ: take a test */ 961 //waitpid(scanner_pid, &status, 0); 962 963 } 964 /* Foxconn, add by MJ., for debugging only. */ 965 #ifdef DEBUG 966 printf(" ======== Goodbye ========.\n"); 967 #endif 968 /* Foxconn, end by MJ. */ 969 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ 970 FD_ZERO(&readset); 971 972 if (sudp >= 0) 973 { 974 FD_SET(sudp, &readset); 975 max_fd = MAX( max_fd, sudp); 976 } 977 978 if (shttpl >= 0) 979 { 980 FD_SET(shttpl, &readset); 981 max_fd = MAX( max_fd, shttpl); 982 } 983 984 i = 0; /* active HTTP connections count */ 985 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) 986 { 987 if((e->socket >= 0) && (e->state <= 2)) 988 { 989 FD_SET(e->socket, &readset); 990 max_fd = MAX( max_fd, e->socket); 991 i++; 992 } 993 } 994 /* for debug */ 995#ifdef DEBUG 996 if(i > 1) 997 { 998 DPRINTF(E_DEBUG, L_GENERAL, "%d active incoming HTTP connections\n", i); 999 } 1000#endif 1001 1002 FD_ZERO(&writeset); 1003 upnpevents_selectfds(&readset, &writeset, &max_fd); 1004 1005 if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0) 1006 { 1007 if(quitting) goto shutdown; 1008 DPRINTF(E_ERROR, L_GENERAL, "select(all): %s\n", strerror(errno)); 1009 DPRINTF(E_FATAL, L_GENERAL, "Failed to select open sockets. EXITING\n"); 1010 } 1011 upnpevents_processfds(&readset, &writeset); 1012 /* process SSDP packets */ 1013 if(sudp >= 0 && FD_ISSET(sudp, &readset)) 1014 { 1015 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/ 1016 ProcessSSDPRequest(sudp, (unsigned short)runtime_vars.port); 1017 } 1018 /* increment SystemUpdateID if the content database has changed, 1019 * and if there is an active HTTP connection, at most once every 2 seconds */ 1020 if( i && (time(NULL) >= (lastupdatetime.tv_sec + 2)) ) 1021 { 1022 if( sqlite3_total_changes(db) != last_changecnt ) 1023 { 1024 updateID++; 1025 last_changecnt = sqlite3_total_changes(db); 1026 upnp_event_var_change_notify(EContentDirectory); 1027 memcpy(&lastupdatetime, &timeofday, sizeof(struct timeval)); 1028 } 1029 } 1030 /* process active HTTP connections */ 1031 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) 1032 { 1033 if( (e->socket >= 0) && (e->state <= 2) 1034 &&(FD_ISSET(e->socket, &readset)) ) 1035 { 1036 Process_upnphttp(e); 1037 } 1038 } 1039 /* process incoming HTTP connections */ 1040 if(shttpl >= 0 && FD_ISSET(shttpl, &readset)) 1041 { 1042 int shttp; 1043 socklen_t clientnamelen; 1044 struct sockaddr_in clientname; 1045 clientnamelen = sizeof(struct sockaddr_in); 1046 shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen); 1047 if(shttp<0) 1048 { 1049 DPRINTF(E_ERROR, L_GENERAL, "accept(http): %s\n", strerror(errno)); 1050 } 1051 else 1052 { 1053 struct upnphttp * tmp = 0; 1054 DPRINTF(E_DEBUG, L_GENERAL, "HTTP connection from %s:%d\n", 1055 inet_ntoa(clientname.sin_addr), 1056 ntohs(clientname.sin_port) ); 1057 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) { 1058 DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK"); 1059 }*/ 1060 /* Create a new upnphttp object and add it to 1061 * the active upnphttp object list */ 1062 tmp = New_upnphttp(shttp); 1063 if(tmp) 1064 { 1065 tmp->clientaddr = clientname.sin_addr; 1066 LIST_INSERT_HEAD(&upnphttphead, tmp, entries); 1067 } 1068 else 1069 { 1070 DPRINTF(E_ERROR, L_GENERAL, "New_upnphttp() failed\n"); 1071 close(shttp); 1072 } 1073 } 1074 } 1075 /* delete finished HTTP connections */ 1076 for(e = upnphttphead.lh_first; e != NULL; ) 1077 { 1078 next = e->entries.le_next; 1079 if(e->state >= 100) 1080 { 1081 LIST_REMOVE(e, entries); 1082 Delete_upnphttp(e); 1083 } 1084 e = next; 1085 } 1086 } 1087 1088shutdown: 1089 /* kill the scanner */ 1090 if( scanning && scanner_pid ) 1091 { 1092 int status; 1093 kill(scanner_pid, 9); 1094 1095 /* Foxconn, MJ: take a test */ 1096 //waitpid(scanner_pid, &status, 0); 1097 } 1098 /* Foxconn, add by MJ., for debugging only. */ 1099#ifdef DEBUG 1100 printf("======= Goodbye 2 ======\n"); 1101#endif 1102 /* Foxconn, end by MJ. */ 1103 /* close out open sockets */ 1104 while(upnphttphead.lh_first != NULL) 1105 { 1106 e = upnphttphead.lh_first; 1107 LIST_REMOVE(e, entries); 1108 Delete_upnphttp(e); 1109 } 1110 1111 if (sudp >= 0) close(sudp); 1112 if (shttpl >= 0) close(shttpl); 1113 #ifdef TIVO_SUPPORT 1114 if (sbeacon >= 0) close(sbeacon); 1115 #endif 1116 1117 if(SendSSDPGoodbye(snotify, n_lan_addr) < 0) 1118 { 1119 DPRINTF(E_ERROR, L_GENERAL, "Failed to broadcast good-bye notifications\n"); 1120 } 1121 for(i=0; i<n_lan_addr; i++) 1122 close(snotify[i]); 1123 1124 if( inotify_thread ) 1125 pthread_join(inotify_thread, NULL); 1126 1127 sql_exec(db, "UPDATE SETTINGS set UPDATE_ID = %u", updateID); 1128 sqlite3_close(db); 1129 1130 media_path = media_dirs; 1131 art_names = album_art_names; 1132 while( media_path ) 1133 { 1134 free(media_path->path); 1135 last_path = media_path; 1136 media_path = media_path->next; 1137 free(last_path); 1138 } 1139 while( art_names ) 1140 { 1141 free(art_names->name); 1142 last_name = art_names; 1143 art_names = art_names->next; 1144 free(last_name); 1145 } 1146 1147 if(unlink(pidfilename) < 0) 1148 { 1149 DPRINTF(E_ERROR, L_GENERAL, "Failed to remove pidfile %s: %s\n", pidfilename, strerror(errno)); 1150 } 1151 1152 freeoptions(); 1153 1154 exit(EXIT_SUCCESS); 1155} 1156 1157