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