Merge branch 'minidlna' into tomato-ND-USBmod
[tomato.git] / release / src / router / minidlna / minidlna.c
blob77f7d76d149ba4bfd9d00c9505738aee0b27e36c
1 /* MiniDLNA project
3 * http://sourceforge.net/projects/minidlna/
5 * MiniDLNA media server
6 * Copyright (C) 2008-2009 Justin Maggard
8 * This file is part of MiniDLNA.
10 * MiniDLNA is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
14 * MiniDLNA is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with MiniDLNA. If not, see <http://www.gnu.org/licenses/>.
22 * Portions of the code from the MiniUPnP project:
24 * Copyright (c) 2006-2007, Thomas Bernard
25 * All rights reserved.
27 * Redistribution and use in source and binary forms, with or without
28 * modification, are permitted provided that the following conditions are met:
29 * * Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * * Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * * The name of the author may not be used to endorse or promote products
35 * derived from this software without specific prior written permission.
37 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
38 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
39 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
40 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
41 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
43 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
44 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
45 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
47 * POSSIBILITY OF SUCH DAMAGE.
49 #include <stdlib.h>
50 #include <unistd.h>
51 #include <string.h>
52 #include <stdio.h>
53 #include <ctype.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
58 #include <fcntl.h>
59 #include <sys/file.h>
60 #include <sys/time.h>
61 #include <time.h>
62 #include <signal.h>
63 #include <sys/param.h>
64 #include <errno.h>
65 #include <pthread.h>
66 #include <pwd.h>
68 #include "config.h"
70 #ifdef ENABLE_NLS
71 #include <libintl.h>
72 #endif
74 #include "upnpglobalvars.h"
75 #include "sql.h"
76 #include "upnphttp.h"
77 #include "upnpdescgen.h"
78 #include "minidlnapath.h"
79 #include "getifaddr.h"
80 #include "upnpsoap.h"
81 #include "options.h"
82 #include "utils.h"
83 #include "minissdp.h"
84 #include "minidlnatypes.h"
85 #include "daemonize.h"
86 #include "upnpevents.h"
87 #include "scanner.h"
88 #include "inotify.h"
89 #include "log.h"
90 #ifdef TIVO_SUPPORT
91 #include "tivo_beacon.h"
92 #include "tivo_utils.h"
93 #endif
95 #if SQLITE_VERSION_NUMBER < 3005001
96 # warning "Your SQLite3 library appears to be too old! Please use 3.5.1 or newer."
97 # define sqlite3_threadsafe() 0
98 #endif
100 /* OpenAndConfHTTPSocket() :
101 * setup the socket used to handle incoming HTTP connections. */
102 static int
103 OpenAndConfHTTPSocket(unsigned short port)
105 int s;
106 int i = 1;
107 struct sockaddr_in listenname;
109 /* Initialize client type cache */
110 memset(&clients, 0, sizeof(struct client_cache_s));
112 if( (s = socket(PF_INET, SOCK_STREAM, 0)) < 0)
114 DPRINTF(E_ERROR, L_GENERAL, "socket(http): %s\n", strerror(errno));
115 return -1;
118 if(setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)) < 0)
120 DPRINTF(E_WARN, L_GENERAL, "setsockopt(http, SO_REUSEADDR): %s\n", strerror(errno));
123 memset(&listenname, 0, sizeof(struct sockaddr_in));
124 listenname.sin_family = AF_INET;
125 listenname.sin_port = htons(port);
126 listenname.sin_addr.s_addr = htonl(INADDR_ANY);
128 if(bind(s, (struct sockaddr *)&listenname, sizeof(struct sockaddr_in)) < 0)
130 DPRINTF(E_ERROR, L_GENERAL, "bind(http): %s\n", strerror(errno));
131 close(s);
132 return -1;
135 if(listen(s, 6) < 0)
137 DPRINTF(E_ERROR, L_GENERAL, "listen(http): %s\n", strerror(errno));
138 close(s);
139 return -1;
142 return s;
145 /* Handler for the SIGTERM signal (kill)
146 * SIGINT is also handled */
147 static void
148 sigterm(int sig)
150 /*int save_errno = errno;*/
151 signal(sig, SIG_IGN); /* Ignore this signal while we are quitting */
153 DPRINTF(E_WARN, L_GENERAL, "received signal %d, good-bye\n", sig);
155 quitting = 1;
156 /*errno = save_errno;*/
159 /* record the startup time, for returning uptime */
160 static void
161 set_startup_time(void)
163 startup_time = time(NULL);
166 /* parselanaddr()
167 * parse address with mask
168 * ex: 192.168.1.1/24
169 * return value :
170 * 0 : ok
171 * -1 : error */
172 static int
173 parselanaddr(struct lan_addr_s * lan_addr, const char * str)
175 const char * p;
176 int nbits = 24;
177 int n;
178 p = str;
179 while(*p && *p != '/' && !isspace(*p))
180 p++;
181 n = p - str;
182 if(*p == '/')
184 nbits = atoi(++p);
185 while(*p && !isspace(*p))
186 p++;
188 if(n>15)
190 DPRINTF(E_OFF, L_GENERAL, "Error parsing address/mask: %s\n", str);
191 return -1;
193 memcpy(lan_addr->str, str, n);
194 lan_addr->str[n] = '\0';
195 if(!inet_aton(lan_addr->str, &lan_addr->addr))
197 DPRINTF(E_OFF, L_GENERAL, "Error parsing address/mask: %s\n", str);
198 return -1;
200 lan_addr->mask.s_addr = htonl(nbits ? (0xffffffff << (32 - nbits)) : 0);
201 return 0;
204 void
205 getfriendlyname(char * buf, int len)
207 char * dot = NULL;
208 char * hn = calloc(1, 256);
209 if( gethostname(hn, 256) == 0 )
211 strncpy(buf, hn, len-1);
212 buf[len] = '\0';
213 dot = index(buf, '.');
214 if( dot )
215 *dot = '\0';
217 else
219 strcpy(buf, "Unknown");
221 free(hn);
222 strcat(buf, ": ");
223 #ifdef READYNAS
224 strncat(buf, "ReadyNAS", len-strlen(buf)-1);
225 #else
226 char * logname;
227 logname = getenv("LOGNAME");
228 #if 1 // Disable for static linking
229 if( !logname )
231 struct passwd * pwent;
232 pwent = getpwuid(getuid());
233 if( pwent )
234 logname = pwent->pw_name;
236 #endif
237 strncat(buf, logname?logname:"Unknown", len-strlen(buf)-1);
238 #endif
242 open_db(void)
244 char path[PATH_MAX];
245 int new_db = 0;
247 snprintf(path, sizeof(path), "%s/files.db", db_path);
248 if( access(path, F_OK) != 0 )
250 new_db = 1;
251 make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
253 if( sqlite3_open(path, &db) != SQLITE_OK )
255 DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to open sqlite database! Exiting...\n");
257 sqlite3_busy_timeout(db, 5000);
258 sql_exec(db, "pragma page_size = 4096");
259 sql_exec(db, "pragma journal_mode = OFF");
260 sql_exec(db, "pragma synchronous = OFF;");
262 // this sets the sqlite database cache size
263 // original code had 8192 = 32MB - reduce it to 4MB
264 sql_exec(db, "pragma default_cache_size = 1024;");
265 return new_db;
268 /* init phase :
269 * 1) read configuration file
270 * 2) read command line arguments
271 * 3) daemonize
272 * 4) check and write pid file
273 * 5) set startup time stamp
274 * 6) compute presentation URL
275 * 7) set signal handlers */
276 static int
277 init(int argc, char * * argv)
279 int i;
280 int pid;
281 int debug_flag = 0;
282 int options_flag = 0;
283 struct sigaction sa;
284 /*const char * logfilename = 0;*/
285 const char * presurl = 0;
286 const char * optionsfile = "/etc/minidlna.conf";
287 char mac_str[13];
288 char * string, * word;
289 enum media_types type;
290 char * path;
291 char real_path[PATH_MAX];
292 char ext_ip_addr[INET_ADDRSTRLEN] = {'\0'};
294 /* first check if "-f" option is used */
295 for(i=2; i<argc; i++)
297 if(0 == strcmp(argv[i-1], "-f"))
299 optionsfile = argv[i];
300 options_flag = 1;
301 break;
305 /* set up uuid based on mac address */
306 if( getsyshwaddr(mac_str, sizeof(mac_str)) < 0 )
308 DPRINTF(E_OFF, L_GENERAL, "No MAC address found. Falling back to generic UUID.\n");
309 strcpy(mac_str, "554e4b4e4f57");
311 strcpy(uuidvalue+5, "4d696e69-444c-164e-9d41-");
312 strncat(uuidvalue, mac_str, 12);
314 getfriendlyname(friendly_name, FRIENDLYNAME_MAX_LEN);
316 runtime_vars.port = -1;
317 runtime_vars.notify_interval = 895; /* seconds between SSDP announces */
319 /* read options file first since
320 * command line arguments have final say */
321 if(readoptionsfile(optionsfile) < 0)
323 /* only error if file exists or using -f */
324 if(access(optionsfile, F_OK) == 0 || options_flag)
325 fprintf(stderr, "Error reading configuration file %s\n", optionsfile);
327 else
329 for(i=0; i<num_options; i++)
331 switch(ary_options[i].id)
333 case UPNPIFNAME:
334 if(getifaddr(ary_options[i].value, ext_ip_addr, INET_ADDRSTRLEN) >= 0)
336 if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 )
337 n_lan_addr++;
339 else
340 fprintf(stderr, "Interface %s not found, ignoring.\n", ary_options[i].value);
341 break;
342 case UPNPLISTENING_IP:
343 if(n_lan_addr < MAX_LAN_ADDR)
345 if(parselanaddr(&lan_addr[n_lan_addr],
346 ary_options[i].value) == 0)
347 n_lan_addr++;
349 else
351 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
352 MAX_LAN_ADDR, ary_options[i].value);
354 break;
355 case UPNPPORT:
356 runtime_vars.port = atoi(ary_options[i].value);
357 break;
358 case UPNPPRESENTATIONURL:
359 presurl = ary_options[i].value;
360 break;
361 case UPNPNOTIFY_INTERVAL:
362 runtime_vars.notify_interval = atoi(ary_options[i].value);
363 break;
364 case UPNPSERIAL:
365 strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN);
366 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
367 break;
368 case UPNPMODEL_NUMBER:
369 strncpy(modelnumber, ary_options[i].value, MODELNUMBER_MAX_LEN);
370 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
371 break;
372 case UPNPFRIENDLYNAME:
373 strncpy(friendly_name, ary_options[i].value, FRIENDLYNAME_MAX_LEN);
374 friendly_name[FRIENDLYNAME_MAX_LEN-1] = '\0';
375 break;
376 case UPNPMEDIADIR:
377 type = ALL_MEDIA;
378 char * myval = NULL;
379 switch( ary_options[i].value[0] )
381 case 'A':
382 case 'a':
383 if( ary_options[i].value[0] == 'A' || ary_options[i].value[0] == 'a' )
384 type = AUDIO_ONLY;
385 case 'V':
386 case 'v':
387 if( ary_options[i].value[0] == 'V' || ary_options[i].value[0] == 'v' )
388 type = VIDEO_ONLY;
389 case 'P':
390 case 'p':
391 if( ary_options[i].value[0] == 'P' || ary_options[i].value[0] == 'p' )
392 type = IMAGES_ONLY;
393 myval = index(ary_options[i].value, '/');
394 case '/':
395 path = realpath(myval ? myval:ary_options[i].value, real_path);
396 if( !path )
397 path = (myval ? myval:ary_options[i].value);
398 if( access(path, F_OK) != 0 )
400 fprintf(stderr, "Media directory not accessible! [%s]\n",
401 path);
402 break;
404 struct media_dir_s * this_dir = calloc(1, sizeof(struct media_dir_s));
405 this_dir->path = strdup(path);
406 this_dir->type = type;
407 if( !media_dirs )
409 media_dirs = this_dir;
411 else
413 struct media_dir_s * all_dirs = media_dirs;
414 while( all_dirs->next )
415 all_dirs = all_dirs->next;
416 all_dirs->next = this_dir;
418 break;
419 default:
420 fprintf(stderr, "Media directory entry not understood! [%s]\n",
421 ary_options[i].value);
422 break;
424 break;
425 case UPNPALBUMART_NAMES:
426 for( string = ary_options[i].value; (word = strtok(string, "/")); string = NULL ) {
427 struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s));
428 this_name->name = strdup(word);
429 if( !album_art_names )
431 album_art_names = this_name;
433 else
435 struct album_art_name_s * all_names = album_art_names;
436 while( all_names->next )
437 all_names = all_names->next;
438 all_names->next = this_name;
441 break;
442 case UPNPDBDIR:
443 path = realpath(ary_options[i].value, real_path);
444 if( !path )
445 path = (ary_options[i].value);
446 make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
447 if( access(path, F_OK) != 0 )
449 DPRINTF(E_FATAL, L_GENERAL, "Database path not accessible! [%s]\n", path);
450 break;
452 strncpy(db_path, path, PATH_MAX);
453 break;
454 case UPNPLOGDIR:
455 path = realpath(ary_options[i].value, real_path);
456 if( !path )
457 path = (ary_options[i].value);
458 make_dir(path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
459 if( access(path, F_OK) != 0 )
461 DPRINTF(E_FATAL, L_GENERAL, "Log path not accessible! [%s]\n", path);
462 break;
464 strncpy(log_path, path, PATH_MAX);
465 break;
466 case UPNPINOTIFY:
467 if( (strcmp(ary_options[i].value, "yes") != 0) && !atoi(ary_options[i].value) )
468 CLEARFLAG(INOTIFY_MASK);
469 break;
470 case ENABLE_TIVO:
471 if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) )
472 SETFLAG(TIVO_MASK);
473 break;
474 case ENABLE_DLNA_STRICT:
475 if( (strcmp(ary_options[i].value, "yes") == 0) || atoi(ary_options[i].value) )
476 SETFLAG(DLNA_STRICT_MASK);
477 break;
478 default:
479 fprintf(stderr, "Unknown option in file %s\n",
480 optionsfile);
485 /* command line arguments processing */
486 for(i=1; i<argc; i++)
488 if(argv[i][0]!='-')
490 fprintf(stderr, "Unknown option: %s\n", argv[i]);
492 else if(strcmp(argv[i], "--help")==0)
494 runtime_vars.port = -1;
495 break;
497 else switch(argv[i][1])
499 case 't':
500 if(i+1 < argc)
501 runtime_vars.notify_interval = atoi(argv[++i]);
502 else
503 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
504 break;
505 case 's':
506 if(i+1 < argc)
507 strncpy(serialnumber, argv[++i], SERIALNUMBER_MAX_LEN);
508 else
509 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
510 serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0';
511 break;
512 case 'm':
513 if(i+1 < argc)
514 strncpy(modelnumber, argv[++i], MODELNUMBER_MAX_LEN);
515 else
516 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
517 modelnumber[MODELNUMBER_MAX_LEN-1] = '\0';
518 break;
519 /*case 'l':
520 logfilename = argv[++i];
521 break;*/
522 case 'p':
523 if(i+1 < argc)
524 runtime_vars.port = atoi(argv[++i]);
525 else
526 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
527 break;
528 case 'P':
529 if(i+1 < argc)
530 pidfilename = argv[++i];
531 else
532 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
533 break;
534 case 'd':
535 debug_flag = 1;
536 break;
537 case 'w':
538 if(i+1 < argc)
539 presurl = argv[++i];
540 else
541 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
542 break;
543 case 'a':
544 if(i+1 < argc)
546 int address_already_there = 0;
547 int j;
548 i++;
549 for(j=0; j<n_lan_addr; j++)
551 struct lan_addr_s tmpaddr;
552 parselanaddr(&tmpaddr, argv[i]);
553 if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
554 address_already_there = 1;
556 if(address_already_there)
557 break;
558 if(n_lan_addr < MAX_LAN_ADDR)
560 if(parselanaddr(&lan_addr[n_lan_addr], argv[i]) == 0)
561 n_lan_addr++;
563 else
565 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
566 MAX_LAN_ADDR, argv[i]);
569 else
570 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
571 break;
572 case 'i':
573 if(i+1 < argc)
575 int address_already_there = 0;
576 int j;
577 i++;
578 if( getifaddr(argv[i], ext_ip_addr, INET_ADDRSTRLEN) < 0 )
580 fprintf(stderr, "Network interface '%s' not found.\n",
581 argv[i]);
582 exit(-1);
584 for(j=0; j<n_lan_addr; j++)
586 struct lan_addr_s tmpaddr;
587 parselanaddr(&tmpaddr, ext_ip_addr);
588 if(0 == strcmp(lan_addr[j].str, tmpaddr.str))
589 address_already_there = 1;
591 if(address_already_there)
592 break;
593 if(n_lan_addr < MAX_LAN_ADDR)
595 if(parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0)
596 n_lan_addr++;
598 else
600 fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n",
601 MAX_LAN_ADDR, argv[i]);
604 else
605 fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]);
606 break;
607 case 'f':
608 i++; /* discarding, the config file is already read */
609 break;
610 case 'h':
611 runtime_vars.port = -1; // triggers help display
612 break;
613 case 'R':
614 snprintf(real_path, sizeof(real_path), "rm -rf %s/*", db_path);
615 system(real_path);
616 break;
617 case 'V':
618 printf("Version " MINIDLNA_VERSION "\n");
619 exit(0);
620 break;
621 default:
622 fprintf(stderr, "Unknown option: %s\n", argv[i]);
625 /* If no IP was specified, try to detect one */
626 if( n_lan_addr < 1 )
628 if( (getsysaddr(ext_ip_addr, INET_ADDRSTRLEN) < 0) &&
629 (getifaddr("eth0", ext_ip_addr, INET_ADDRSTRLEN) < 0) &&
630 (getifaddr("eth1", ext_ip_addr, INET_ADDRSTRLEN) < 0) )
632 DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n");
634 if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 )
636 n_lan_addr++;
640 if( (n_lan_addr==0) || (runtime_vars.port<0) )
642 fprintf(stderr, "Usage:\n\t"
643 "%s [-d] [-f config_file]\n"
644 "\t\t[-a listening_ip] [-p port]\n"
645 /*"[-l logfile] " not functionnal */
646 "\t\t[-s serial] [-m model_number] \n"
647 "\t\t[-t notify_interval] [-P pid_filename]\n"
648 "\t\t[-w url] [-R] [-V] [-h]\n"
649 "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n"
650 "\tDefault pid file is %s.\n"
651 "\tWith -d minidlna will run in debug mode (not daemonize).\n"
652 "\t-w sets the presentation url. Default is http address on port 80\n"
653 "\t-h displays this text\n"
654 "\t-R forces a full rescan\n"
655 "\t-V print the version number\n",
656 argv[0], pidfilename);
657 return 1;
660 if(debug_flag)
662 pid = getpid();
663 log_init(NULL, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=debug");
665 else
667 #ifdef USE_DAEMON
668 if(daemon(0, 0)<0) {
669 perror("daemon()");
671 pid = getpid();
672 #else
673 pid = daemonize();
674 #endif
675 #ifdef READYNAS
676 log_init("/var/log/upnp-av.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn");
677 #else
678 if( access(db_path, F_OK) != 0 )
679 make_dir(db_path, S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO);
680 sprintf(real_path, "%s/minidlna.log", log_path);
681 log_init(real_path, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn");
682 #endif
685 if(checkforrunning(pidfilename) < 0)
687 DPRINTF(E_ERROR, L_GENERAL, "MiniDLNA is already running. EXITING.\n");
688 return 1;
691 set_startup_time();
693 /* presentation url */
694 if(presurl)
696 strncpy(presentationurl, presurl, PRESENTATIONURL_MAX_LEN);
697 presentationurl[PRESENTATIONURL_MAX_LEN-1] = '\0';
699 else
701 #ifdef READYNAS
702 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
703 "http://%s/admin/", lan_addr[0].str);
704 #else
705 snprintf(presentationurl, PRESENTATIONURL_MAX_LEN,
706 "http://%s/", lan_addr[0].str);
707 #endif
710 /* set signal handler */
711 signal(SIGCLD, SIG_IGN);
712 memset(&sa, 0, sizeof(struct sigaction));
713 sa.sa_handler = sigterm;
714 if (sigaction(SIGTERM, &sa, NULL))
716 DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGTERM handler. EXITING.\n");
718 if (sigaction(SIGINT, &sa, NULL))
720 DPRINTF(E_FATAL, L_GENERAL, "Failed to set SIGINT handler. EXITING.\n");
723 if(signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
724 DPRINTF(E_FATAL, L_GENERAL, "Failed to ignore SIGPIPE signals. EXITING.\n");
727 writepidfile(pidfilename, pid);
729 return 0;
732 /* === main === */
733 /* process HTTP or SSDP requests */
735 main(int argc, char * * argv)
737 int i;
738 int sudp = -1, shttpl = -1;
739 int snotify[MAX_LAN_ADDR];
740 LIST_HEAD(httplisthead, upnphttp) upnphttphead;
741 struct upnphttp * e = 0;
742 struct upnphttp * next;
743 fd_set readset; /* for select() */
744 fd_set writeset;
745 struct timeval timeout, timeofday, lastnotifytime = {0, 0}, lastupdatetime = {0, 0};
746 int max_fd = -1;
747 int last_changecnt = 0;
748 short int new_db = 0;
749 pid_t scanner_pid = 0;
750 pthread_t inotify_thread = 0;
751 struct media_dir_s *media_path, *last_path;
752 struct album_art_name_s *art_names, *last_name;
753 #ifdef TIVO_SUPPORT
754 unsigned short int beacon_interval = 5;
755 int sbeacon = -1;
756 struct sockaddr_in tivo_bcast;
757 struct timeval lastbeacontime = {0, 0};
758 #endif
760 #ifdef ENABLE_NLS
761 setlocale(LC_MESSAGES, "");
762 setlocale(LC_CTYPE, "en_US.utf8");
763 textdomain("minidlna");
764 #endif
766 if(init(argc, argv) != 0)
767 return 1;
769 #ifdef READYNAS
770 DPRINTF(E_WARN, L_GENERAL, "Starting ReadyDLNA version " MINIDLNA_VERSION ".\n");
771 unlink("/ramfs/.upnp-av_scan");
772 #else
773 DPRINTF(E_WARN, L_GENERAL, "Starting MiniDLNA version " MINIDLNA_VERSION " [SQLite %s].\n", sqlite3_libversion());
774 unlink("/var/notice/dlna");
775 if( !sqlite3_threadsafe() )
777 DPRINTF(E_ERROR, L_GENERAL, "SQLite library is not threadsafe! "
778 "Scanning must be finished before file serving can begin, "
779 "and inotify will be disabled.\n");
781 if( sqlite3_libversion_number() < 3005001 )
783 DPRINTF(E_WARN, L_GENERAL, "SQLite library is old. Please use version 3.5.1 or newer.\n");
785 #endif
786 LIST_INIT(&upnphttphead);
788 new_db = open_db();
789 if( !new_db )
791 updateID = sql_get_int_field(db, "SELECT UPDATE_ID from SETTINGS");
793 if( sql_get_int_field(db, "pragma user_version") != DB_VERSION )
795 if( new_db )
797 DPRINTF(E_WARN, L_GENERAL, "Creating new database...\n");
799 else
801 DPRINTF(E_WARN, L_GENERAL, "Database version mismatch; need to recreate...\n");
803 sqlite3_close(db);
804 char *cmd;
805 asprintf(&cmd, "rm -rf %s/files.db %s/art_cache", db_path, db_path);
806 system(cmd);
807 free(cmd);
808 open_db();
809 if( CreateDatabase() != 0 )
811 DPRINTF(E_FATAL, L_GENERAL, "ERROR: Failed to create sqlite database! Exiting...\n");
813 #if USE_FORK
814 scanning = 1;
815 sqlite3_close(db);
816 scanner_pid = fork();
817 open_db();
818 if( !scanner_pid ) // child (scanner) process
820 start_scanner();
821 sqlite3_close(db);
822 media_path = media_dirs;
823 art_names = album_art_names;
824 while( media_path )
826 free(media_path->path);
827 last_path = media_path;
828 media_path = media_path->next;
829 free(last_path);
831 while( art_names )
833 free(art_names->name);
834 last_name = art_names;
835 art_names = art_names->next;
836 free(last_name);
838 freeoptions();
839 exit(EXIT_SUCCESS);
841 #else
842 start_scanner();
843 #endif
845 if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 &&
846 GETFLAG(INOTIFY_MASK) && pthread_create(&inotify_thread, NULL, start_inotify, NULL) )
848 DPRINTF(E_FATAL, L_GENERAL, "ERROR: pthread_create() failed for start_inotify.\n");
851 sudp = OpenAndConfSSDPReceiveSocket(n_lan_addr, lan_addr);
852 if(sudp < 0)
854 DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for receiving SSDP. EXITING\n");
856 /* open socket for HTTP connections. Listen on the 1st LAN address */
857 shttpl = OpenAndConfHTTPSocket((runtime_vars.port > 0) ? runtime_vars.port : 0);
858 if(shttpl < 0)
860 DPRINTF(E_FATAL, L_GENERAL, "Failed to open socket for HTTP. EXITING\n");
862 if(runtime_vars.port <= 0)
864 struct sockaddr_in sockinfo;
865 socklen_t len = sizeof(struct sockaddr_in);
866 if (getsockname(shttpl, (struct sockaddr *)&sockinfo, &len) < 0)
868 DPRINTF(E_FATAL, L_GENERAL, "getsockname(): %s. EXITING\n", strerror(errno));
870 runtime_vars.port = ntohs(sockinfo.sin_port);
872 DPRINTF(E_WARN, L_GENERAL, "HTTP listening on port %d\n", runtime_vars.port);
874 /* open socket for sending notifications */
875 if(OpenAndConfSSDPNotifySockets(snotify) < 0)
877 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending SSDP notify "
878 "messages. EXITING\n");
881 #ifdef TIVO_SUPPORT
882 if( GETFLAG(TIVO_MASK) )
884 DPRINTF(E_WARN, L_GENERAL, "TiVo support is enabled.\n");
885 /* Add TiVo-specific randomize function to sqlite */
886 if( sqlite3_create_function(db, "tivorandom", 1, SQLITE_UTF8, NULL, &TiVoRandomSeedFunc, NULL, NULL) != SQLITE_OK )
888 DPRINTF(E_ERROR, L_TIVO, "ERROR: Failed to add sqlite randomize function for TiVo!\n");
890 /* open socket for sending Tivo notifications */
891 sbeacon = OpenAndConfTivoBeaconSocket();
892 if(sbeacon < 0)
894 DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify "
895 "messages. EXITING\n");
897 tivo_bcast.sin_family = AF_INET;
898 tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress());
899 tivo_bcast.sin_port = htons(2190);
901 else
903 sbeacon = -1;
905 #endif
907 SendSSDPGoodbye(snotify, n_lan_addr);
909 /* main loop */
910 while(!quitting)
912 /* Check if we need to send SSDP NOTIFY messages and do it if
913 * needed */
914 if(gettimeofday(&timeofday, 0) < 0)
916 DPRINTF(E_ERROR, L_GENERAL, "gettimeofday(): %s\n", strerror(errno));
917 timeout.tv_sec = runtime_vars.notify_interval;
918 timeout.tv_usec = 0;
920 else
922 /* the comparaison is not very precise but who cares ? */
923 if(timeofday.tv_sec >= (lastnotifytime.tv_sec + runtime_vars.notify_interval))
925 SendSSDPNotifies2(snotify,
926 (unsigned short)runtime_vars.port,
927 (runtime_vars.notify_interval << 1)+10);
928 memcpy(&lastnotifytime, &timeofday, sizeof(struct timeval));
929 timeout.tv_sec = runtime_vars.notify_interval;
930 timeout.tv_usec = 0;
932 else
934 timeout.tv_sec = lastnotifytime.tv_sec + runtime_vars.notify_interval
935 - timeofday.tv_sec;
936 if(timeofday.tv_usec > lastnotifytime.tv_usec)
938 timeout.tv_usec = 1000000 + lastnotifytime.tv_usec
939 - timeofday.tv_usec;
940 timeout.tv_sec--;
942 else
944 timeout.tv_usec = lastnotifytime.tv_usec - timeofday.tv_usec;
947 #ifdef TIVO_SUPPORT
948 if( GETFLAG(TIVO_MASK) )
950 if(timeofday.tv_sec >= (lastbeacontime.tv_sec + beacon_interval))
952 sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1);
953 memcpy(&lastbeacontime, &timeofday, sizeof(struct timeval));
954 if( timeout.tv_sec > beacon_interval )
956 timeout.tv_sec = beacon_interval;
957 timeout.tv_usec = 0;
959 /* Beacons should be sent every 5 seconds or so for the first minute,
960 * then every minute or so thereafter. */
961 if( beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60 )
963 beacon_interval = 60;
966 else if( timeout.tv_sec > (lastbeacontime.tv_sec + beacon_interval + 1 - timeofday.tv_sec) )
968 timeout.tv_sec = lastbeacontime.tv_sec + beacon_interval - timeofday.tv_sec;
971 #endif
974 if( scanning )
976 if( !scanner_pid || kill(scanner_pid, 0) )
977 scanning = 0;
980 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
981 FD_ZERO(&readset);
983 if (sudp >= 0)
985 FD_SET(sudp, &readset);
986 max_fd = MAX( max_fd, sudp);
989 if (shttpl >= 0)
991 FD_SET(shttpl, &readset);
992 max_fd = MAX( max_fd, shttpl);
995 i = 0; /* active HTTP connections count */
996 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
998 if((e->socket >= 0) && (e->state <= 2))
1000 FD_SET(e->socket, &readset);
1001 max_fd = MAX( max_fd, e->socket);
1002 i++;
1005 /* for debug */
1006 #ifdef DEBUG
1007 if(i > 1)
1009 DPRINTF(E_DEBUG, L_GENERAL, "%d active incoming HTTP connections\n", i);
1011 #endif
1013 FD_ZERO(&writeset);
1014 upnpevents_selectfds(&readset, &writeset, &max_fd);
1016 if(select(max_fd+1, &readset, &writeset, 0, &timeout) < 0)
1018 if(quitting) goto shutdown;
1019 DPRINTF(E_ERROR, L_GENERAL, "select(all): %s\n", strerror(errno));
1020 DPRINTF(E_FATAL, L_GENERAL, "Failed to select open sockets. EXITING\n");
1022 upnpevents_processfds(&readset, &writeset);
1023 /* process SSDP packets */
1024 if(sudp >= 0 && FD_ISSET(sudp, &readset))
1026 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
1027 ProcessSSDPRequest(sudp, (unsigned short)runtime_vars.port);
1029 /* increment SystemUpdateID if the content database has changed,
1030 * and if there is an active HTTP connection, at most once every 2 seconds */
1031 if( i && (time(NULL) >= (lastupdatetime.tv_sec + 2)) )
1033 if( sqlite3_total_changes(db) != last_changecnt )
1035 updateID++;
1036 last_changecnt = sqlite3_total_changes(db);
1037 upnp_event_var_change_notify(EContentDirectory);
1038 memcpy(&lastupdatetime, &timeofday, sizeof(struct timeval));
1041 /* process active HTTP connections */
1042 for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next)
1044 if( (e->socket >= 0) && (e->state <= 2)
1045 &&(FD_ISSET(e->socket, &readset)) )
1047 Process_upnphttp(e);
1050 /* process incoming HTTP connections */
1051 if(shttpl >= 0 && FD_ISSET(shttpl, &readset))
1053 int shttp;
1054 socklen_t clientnamelen;
1055 struct sockaddr_in clientname;
1056 clientnamelen = sizeof(struct sockaddr_in);
1057 shttp = accept(shttpl, (struct sockaddr *)&clientname, &clientnamelen);
1058 if(shttp<0)
1060 DPRINTF(E_ERROR, L_GENERAL, "accept(http): %s\n", strerror(errno));
1062 else
1064 struct upnphttp * tmp = 0;
1065 DPRINTF(E_DEBUG, L_GENERAL, "HTTP connection from %s:%d\n",
1066 inet_ntoa(clientname.sin_addr),
1067 ntohs(clientname.sin_port) );
1068 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
1069 DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK");
1071 /* Create a new upnphttp object and add it to
1072 * the active upnphttp object list */
1073 tmp = New_upnphttp(shttp);
1074 if(tmp)
1076 tmp->clientaddr = clientname.sin_addr;
1077 LIST_INSERT_HEAD(&upnphttphead, tmp, entries);
1079 else
1081 DPRINTF(E_ERROR, L_GENERAL, "New_upnphttp() failed\n");
1082 close(shttp);
1086 /* delete finished HTTP connections */
1087 for(e = upnphttphead.lh_first; e != NULL; )
1089 next = e->entries.le_next;
1090 if(e->state >= 100)
1092 LIST_REMOVE(e, entries);
1093 Delete_upnphttp(e);
1095 e = next;
1099 shutdown:
1100 /* kill the scanner */
1101 if( scanning && scanner_pid )
1103 kill(scanner_pid, 9);
1105 /* close out open sockets */
1106 while(upnphttphead.lh_first != NULL)
1108 e = upnphttphead.lh_first;
1109 LIST_REMOVE(e, entries);
1110 Delete_upnphttp(e);
1113 if (sudp >= 0) close(sudp);
1114 if (shttpl >= 0) close(shttpl);
1115 #ifdef TIVO_SUPPORT
1116 if (sbeacon >= 0) close(sbeacon);
1117 #endif
1119 if(SendSSDPGoodbye(snotify, n_lan_addr) < 0)
1121 DPRINTF(E_ERROR, L_GENERAL, "Failed to broadcast good-bye notifications\n");
1123 for(i=0; i<n_lan_addr; i++)
1124 close(snotify[i]);
1126 if( inotify_thread )
1127 pthread_join(inotify_thread, NULL);
1129 sql_exec(db, "UPDATE SETTINGS set UPDATE_ID = %u", updateID);
1130 sqlite3_close(db);
1132 media_path = media_dirs;
1133 art_names = album_art_names;
1134 while( media_path )
1136 free(media_path->path);
1137 last_path = media_path;
1138 media_path = media_path->next;
1139 free(last_path);
1141 while( art_names )
1143 free(art_names->name);
1144 last_name = art_names;
1145 art_names = art_names->next;
1146 free(last_name);
1149 if(unlink(pidfilename) < 0)
1151 DPRINTF(E_ERROR, L_GENERAL, "Failed to remove pidfile %s: %s\n", pidfilename, strerror(errno));
1154 freeoptions();
1156 exit(EXIT_SUCCESS);