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.
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <netinet/in.h>
57 #include <arpa/inet.h>
63 #include <sys/param.h>
74 #include "upnpglobalvars.h"
77 #include "upnpdescgen.h"
78 #include "minidlnapath.h"
79 #include "getifaddr.h"
84 #include "minidlnatypes.h"
85 #include "daemonize.h"
86 #include "upnpevents.h"
91 #include "tivo_beacon.h"
92 #include "tivo_utils.h"
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
100 /* OpenAndConfHTTPSocket() :
101 * setup the socket used to handle incoming HTTP connections. */
103 OpenAndConfHTTPSocket(unsigned short port
)
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
));
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
));
137 DPRINTF(E_ERROR
, L_GENERAL
, "listen(http): %s\n", strerror(errno
));
145 /* Handler for the SIGTERM signal (kill)
146 * SIGINT is also handled */
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
);
156 /*errno = save_errno;*/
159 /* record the startup time, for returning uptime */
161 set_startup_time(void)
163 startup_time
= time(NULL
);
167 * parse address with mask
173 parselanaddr(struct lan_addr_s
* lan_addr
, const char * str
)
179 while(*p
&& *p
!= '/' && !isspace(*p
))
185 while(*p
&& !isspace(*p
))
190 DPRINTF(E_OFF
, L_GENERAL
, "Error parsing address/mask: %s\n", str
);
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: %s\n", str
);
200 lan_addr
->mask
.s_addr
= htonl(nbits
? (0xffffffff << (32 - nbits
)) : 0);
205 getfriendlyname(char * buf
, int len
)
208 char * hn
= calloc(1, 256);
211 if( gethostname(hn
, 256) == 0 )
213 strncpyt(buf
, hn
, len
);
214 dot
= strchr(buf
, '.');
220 strcpy(buf
, "Unknown");
225 off
+= snprintf(buf
+off
, len
-off
, ": ");
228 char ibuf
[64], *key
, *val
;
229 snprintf(buf
+off
, len
-off
, "ReadyNAS");
230 info
= fopen("/proc/sys/dev/boot/info", "r");
233 while( (val
= fgets(ibuf
, 64, info
)) != NULL
)
235 key
= strsep(&val
, ": \t");
237 if( strcmp(key
, "model") == 0 )
239 snprintf(buf
+off
, len
-off
, "%s", val
);
240 key
= strchr(val
, ' ');
243 strncpyt(modelnumber
, key
+1, MODELNUMBER_MAX_LEN
);
246 snprintf(modelname
, MODELNAME_MAX_LEN
,
247 "Windows Media Connect compatible (%s)", val
);
249 else if( strcmp(key
, "serial") == 0 )
251 strncpyt(serialnumber
, val
, SERIALNUMBER_MAX_LEN
);
252 if( serialnumber
[0] == '\0' )
255 if( getsyshwaddr(mac_str
, sizeof(mac_str
)) == 0 )
256 strcpy(serialnumber
, mac_str
);
258 strcpy(serialnumber
, "0");
264 memcpy(pnpx_hwid
+4, "01F2", 4);
265 if( strcmp(modelnumber
, "NVX") == 0 )
266 memcpy(pnpx_hwid
+17, "0101", 4);
267 else if( strcmp(modelnumber
, "Pro") == 0 ||
268 strcmp(modelnumber
, "Pro 6") == 0 ||
269 strncmp(modelnumber
, "Ultra 6", 7) == 0 )
270 memcpy(pnpx_hwid
+17, "0102", 4);
271 else if( strcmp(modelnumber
, "Pro 2") == 0 ||
272 strncmp(modelnumber
, "Ultra 2", 7) == 0 )
273 memcpy(pnpx_hwid
+17, "0103", 4);
274 else if( strcmp(modelnumber
, "Pro 4") == 0 ||
275 strncmp(modelnumber
, "Ultra 4", 7) == 0 )
276 memcpy(pnpx_hwid
+17, "0104", 4);
277 else if( strcmp(modelnumber
+1, "100") == 0 )
278 memcpy(pnpx_hwid
+17, "0105", 4);
279 else if( strcmp(modelnumber
+1, "200") == 0 )
280 memcpy(pnpx_hwid
+17, "0106", 4);
282 else if( strcmp(modelnumber
, "Duo v2") == 0 )
283 memcpy(pnpx_hwid
+17, "0108", 4);
284 else if( strcmp(modelnumber
, "NV+ v2") == 0 )
285 memcpy(pnpx_hwid
+17, "0109", 4);
288 logname
= getenv("LOGNAME");
289 #ifndef STATIC // Disable for static linking
292 struct passwd
* pwent
;
293 pwent
= getpwuid(getuid());
295 logname
= pwent
->pw_name
;
298 snprintf(buf
+off
, len
-off
, "%s", logname
?logname
:"Unknown");
308 snprintf(path
, sizeof(path
), "%s/files.db", db_path
);
309 if( access(path
, F_OK
) != 0 )
312 make_dir(db_path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
314 if( sqlite3_open(path
, &db
) != SQLITE_OK
)
316 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: Failed to open sqlite database! Exiting...\n");
318 sqlite3_busy_timeout(db
, 5000);
319 sql_exec(db
, "pragma page_size = 4096");
320 sql_exec(db
, "pragma journal_mode = OFF");
321 sql_exec(db
, "pragma synchronous = OFF;");
323 // this sets the sqlite database cache size
324 // original code had 8192 = 32MB - reduce it to 4MB
325 sql_exec(db
, "pragma default_cache_size = 1024;");
330 * 1) read configuration file
331 * 2) read command line arguments
333 * 4) check and write pid file
334 * 5) set startup time stamp
335 * 6) compute presentation URL
336 * 7) set signal handlers */
338 init(int argc
, char * * argv
)
343 int verbose_flag
= 0;
344 int options_flag
= 0;
346 const char * presurl
= NULL
;
347 const char * optionsfile
= "/etc/minidlna.conf";
349 char * string
, * word
;
350 enum media_types type
;
353 char ip_addr
[INET_ADDRSTRLEN
+ 3] = {'\0'};
354 char log_str
[72] = "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn";
355 char *log_level
= NULL
;
357 /* first check if "-f" option is used */
358 for(i
=2; i
<argc
; i
++)
360 if(0 == strcmp(argv
[i
-1], "-f"))
362 optionsfile
= argv
[i
];
368 /* set up uuid based on mac address */
369 if( getsyshwaddr(mac_str
, sizeof(mac_str
)) < 0 )
371 DPRINTF(E_OFF
, L_GENERAL
, "No MAC address found. Falling back to generic UUID.\n");
372 strcpy(mac_str
, "554e4b4e4f57");
374 strcpy(uuidvalue
+5, "4d696e69-444c-164e-9d41-");
375 strncat(uuidvalue
, mac_str
, 12);
377 getfriendlyname(friendly_name
, FRIENDLYNAME_MAX_LEN
);
379 runtime_vars
.port
= -1;
380 runtime_vars
.notify_interval
= 895; /* seconds between SSDP announces */
381 runtime_vars
.root_container
= NULL
;
383 /* read options file first since
384 * command line arguments have final say */
385 if(readoptionsfile(optionsfile
) < 0)
387 /* only error if file exists or using -f */
388 if(access(optionsfile
, F_OK
) == 0 || options_flag
)
389 DPRINTF(E_ERROR
, L_GENERAL
, "Error reading configuration file %s\n", optionsfile
);
393 for(i
=0; i
<num_options
; i
++)
395 switch(ary_options
[i
].id
)
398 for( string
= ary_options
[i
].value
; (word
= strtok(string
, ",")); string
= NULL
)
400 if(n_lan_addr
< MAX_LAN_ADDR
)
402 if(getifaddr(word
, ip_addr
, sizeof(ip_addr
)) >= 0)
404 if( *ip_addr
&& parselanaddr(&lan_addr
[n_lan_addr
], ip_addr
) == 0 )
405 if(n_lan_addr
< MAX_LAN_ADDR
)
411 DPRINTF(E_ERROR
, L_GENERAL
, "Too many listening ips (max: %d), ignoring %s\n",
416 case UPNPLISTENING_IP
:
417 if(n_lan_addr
< MAX_LAN_ADDR
)
419 if(parselanaddr(&lan_addr
[n_lan_addr
],
420 ary_options
[i
].value
) == 0)
425 DPRINTF(E_ERROR
, L_GENERAL
, "Too many listening ips (max: %d), ignoring %s\n",
426 MAX_LAN_ADDR
, ary_options
[i
].value
);
430 runtime_vars
.port
= atoi(ary_options
[i
].value
);
432 case UPNPPRESENTATIONURL
:
433 presurl
= ary_options
[i
].value
;
435 case UPNPNOTIFY_INTERVAL
:
436 runtime_vars
.notify_interval
= atoi(ary_options
[i
].value
);
439 strncpyt(serialnumber
, ary_options
[i
].value
, SERIALNUMBER_MAX_LEN
);
442 strncpyt(modelname
, ary_options
[i
].value
, MODELNAME_MAX_LEN
);
444 case UPNPMODEL_NUMBER
:
445 strncpyt(modelnumber
, ary_options
[i
].value
, MODELNUMBER_MAX_LEN
);
447 case UPNPFRIENDLYNAME
:
448 strncpyt(friendly_name
, ary_options
[i
].value
, FRIENDLYNAME_MAX_LEN
);
453 switch( ary_options
[i
].value
[0] )
457 if( ary_options
[i
].value
[0] == 'A' || ary_options
[i
].value
[0] == 'a' )
461 if( ary_options
[i
].value
[0] == 'V' || ary_options
[i
].value
[0] == 'v' )
465 if( ary_options
[i
].value
[0] == 'P' || ary_options
[i
].value
[0] == 'p' )
467 myval
= index(ary_options
[i
].value
, '/');
469 path
= realpath(myval
? myval
:ary_options
[i
].value
, buf
);
471 path
= (myval
? myval
:ary_options
[i
].value
);
472 if( access(path
, F_OK
) != 0 )
474 DPRINTF(E_ERROR
, L_GENERAL
, "Media directory \"%s\" not accessible! [%s]\n",
475 path
, strerror(errno
));
478 struct media_dir_s
* this_dir
= calloc(1, sizeof(struct media_dir_s
));
479 this_dir
->path
= strdup(path
);
480 this_dir
->type
= type
;
483 media_dirs
= this_dir
;
487 struct media_dir_s
* all_dirs
= media_dirs
;
488 while( all_dirs
->next
)
489 all_dirs
= all_dirs
->next
;
490 all_dirs
->next
= this_dir
;
494 DPRINTF(E_ERROR
, L_GENERAL
, "Media directory entry not understood! [%s]\n",
495 ary_options
[i
].value
);
499 case UPNPALBUMART_NAMES
:
500 for( string
= ary_options
[i
].value
; (word
= strtok(string
, "/")); string
= NULL
)
502 struct album_art_name_s
* this_name
= calloc(1, sizeof(struct album_art_name_s
));
503 int len
= strlen(word
);
504 if( word
[len
-1] == '*' )
507 this_name
->wildcard
= 1;
509 this_name
->name
= strdup(word
);
510 if( !album_art_names
)
512 album_art_names
= this_name
;
516 struct album_art_name_s
* all_names
= album_art_names
;
517 while( all_names
->next
)
518 all_names
= all_names
->next
;
519 all_names
->next
= this_name
;
524 path
= realpath(ary_options
[i
].value
, buf
);
526 path
= (ary_options
[i
].value
);
527 make_dir(path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
528 if( access(path
, F_OK
) != 0 )
530 DPRINTF(E_FATAL
, L_GENERAL
, "Database path not accessible! [%s]\n", path
);
533 strncpyt(db_path
, path
, PATH_MAX
);
536 path
= realpath(ary_options
[i
].value
, buf
);
538 path
= (ary_options
[i
].value
);
539 make_dir(path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
540 if( access(path
, F_OK
) != 0 )
542 DPRINTF(E_FATAL
, L_GENERAL
, "Log path not accessible! [%s]\n", path
);
545 strncpyt(log_path
, path
, PATH_MAX
);
548 log_level
= ary_options
[i
].value
;
551 if( (strcmp(ary_options
[i
].value
, "yes") != 0) && !atoi(ary_options
[i
].value
) )
552 CLEARFLAG(INOTIFY_MASK
);
555 if( (strcmp(ary_options
[i
].value
, "yes") == 0) || atoi(ary_options
[i
].value
) )
558 case ENABLE_DLNA_STRICT
:
559 if( (strcmp(ary_options
[i
].value
, "yes") == 0) || atoi(ary_options
[i
].value
) )
560 SETFLAG(DLNA_STRICT_MASK
);
563 switch( ary_options
[i
].value
[0] )
566 runtime_vars
.root_container
= NULL
;
570 runtime_vars
.root_container
= BROWSEDIR_ID
;
574 runtime_vars
.root_container
= MUSIC_ID
;
578 runtime_vars
.root_container
= VIDEO_ID
;
582 runtime_vars
.root_container
= IMAGE_ID
;
585 DPRINTF(E_ERROR
, L_GENERAL
, "Invalid root container! [%s]\n",
586 ary_options
[i
].value
);
590 case UPNPMINISSDPDSOCKET
:
591 minissdpdsocketpath
= ary_options
[i
].value
;
594 DPRINTF(E_ERROR
, L_GENERAL
, "Unknown option in file %s\n",
599 if( log_path
[0] == '\0' )
601 if( db_path
[0] == '\0' )
602 strncpyt(log_path
, DEFAULT_LOG_PATH
, PATH_MAX
);
604 strncpyt(log_path
, db_path
, PATH_MAX
);
606 if( db_path
[0] == '\0' )
607 strncpyt(db_path
, DEFAULT_DB_PATH
, PATH_MAX
);
609 /* command line arguments processing */
610 for(i
=1; i
<argc
; i
++)
614 DPRINTF(E_ERROR
, L_GENERAL
, "Unknown option: %s\n", argv
[i
]);
616 else if(strcmp(argv
[i
], "--help")==0)
618 runtime_vars
.port
= -1;
621 else switch(argv
[i
][1])
625 runtime_vars
.notify_interval
= atoi(argv
[++i
]);
627 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
631 strncpyt(serialnumber
, argv
[++i
], SERIALNUMBER_MAX_LEN
);
633 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
637 strncpyt(modelnumber
, argv
[++i
], MODELNUMBER_MAX_LEN
);
639 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
643 runtime_vars
.port
= atoi(argv
[++i
]);
645 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
649 pidfilename
= argv
[++i
];
651 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
659 SETFLAG(NO_PLAYLIST_MASK
);
665 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
670 int address_already_there
= 0;
673 for(j
=0; j
<n_lan_addr
; j
++)
675 struct lan_addr_s tmpaddr
;
676 parselanaddr(&tmpaddr
, argv
[i
]);
677 if(0 == strcmp(lan_addr
[j
].str
, tmpaddr
.str
))
678 address_already_there
= 1;
680 if(address_already_there
)
682 if(n_lan_addr
< MAX_LAN_ADDR
)
684 if(parselanaddr(&lan_addr
[n_lan_addr
], argv
[i
]) == 0)
689 DPRINTF(E_ERROR
, L_GENERAL
, "Too many listening ips (max: %d), ignoring %s\n",
690 MAX_LAN_ADDR
, argv
[i
]);
694 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
699 int address_already_there
= 0;
702 if( getifaddr(argv
[i
], ip_addr
, sizeof(ip_addr
)) < 0 )
704 DPRINTF(E_FATAL
, L_GENERAL
, "Required network interface '%s' not found.\n",
707 for(j
=0; j
<n_lan_addr
; j
++)
709 struct lan_addr_s tmpaddr
;
710 parselanaddr(&tmpaddr
, ip_addr
);
711 if(0 == strcmp(lan_addr
[j
].str
, tmpaddr
.str
))
712 address_already_there
= 1;
714 if(address_already_there
)
716 if(n_lan_addr
< MAX_LAN_ADDR
)
718 if(parselanaddr(&lan_addr
[n_lan_addr
], ip_addr
) == 0)
723 DPRINTF(E_ERROR
, L_GENERAL
, "Too many listening ips (max: %d), ignoring %s\n",
724 MAX_LAN_ADDR
, argv
[i
]);
728 DPRINTF(E_ERROR
, L_GENERAL
, "Option -%c takes one argument.\n", argv
[i
][1]);
731 i
++; /* discarding, the config file is already read */
734 runtime_vars
.port
= -1; // triggers help display
737 snprintf(buf
, sizeof(buf
), "rm -rf %s/files.db %s/art_cache", db_path
, db_path
);
738 if( system(buf
) != 0 )
739 DPRINTF(E_WARN
, L_GENERAL
, "Failed to clean old file cache.\n");
742 printf("Version " MINIDLNA_VERSION
"\n");
746 DPRINTF(E_ERROR
, L_GENERAL
, "Unknown option: %s\n", argv
[i
]);
749 /* If no IP was specified, try to detect one */
752 if( (getsysaddr(ip_addr
, sizeof(ip_addr
)) < 0) &&
753 (getifaddr("eth0", ip_addr
, sizeof(ip_addr
)) < 0) &&
754 (getifaddr("eth1", ip_addr
, sizeof(ip_addr
)) < 0) )
756 DPRINTF(E_OFF
, L_GENERAL
, "No IP address automatically detected!\n");
758 if( *ip_addr
&& parselanaddr(&lan_addr
[n_lan_addr
], ip_addr
) == 0 )
764 if( (n_lan_addr
==0) || (runtime_vars
.port
<0) )
766 DPRINTF(E_ERROR
, L_GENERAL
, "Usage:\n\t"
767 "%s [-d] [-v] [-f config_file]\n"
768 "\t\t[-a listening_ip] [-p port]\n"
769 /*"[-l logfile] " not functionnal */
770 "\t\t[-s serial] [-m model_number] \n"
771 "\t\t[-t notify_interval] [-P pid_filename]\n"
772 "\t\t[-w url] [-R] [-V] [-h]\n"
773 "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n"
774 "\tDefault pid file is %s.\n"
775 "\tWith -d minidlna will run in debug mode (not daemonize).\n"
776 "\t-w sets the presentation url. Default is http address on port 80\n"
777 "\t-h displays this text\n"
778 "\t-R forces a full rescan\n"
779 "\t-L do note create playlists\n"
780 "\t-V print the version number\n",
781 argv
[0], pidfilename
);
787 strcpy(log_str
+65, "debug");
790 else if( !log_level
)
797 log_init(NULL
, log_level
);
803 log_init("/var/log/upnp-av.log", log_level
);
805 if( access(db_path
, F_OK
) != 0 )
806 make_dir(db_path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
807 sprintf(buf
, "%s/minidlna.log", log_path
);
808 log_init(buf
, log_level
);
812 if(checkforrunning(pidfilename
) < 0)
814 DPRINTF(E_ERROR
, L_GENERAL
, "MiniDLNA is already running. EXITING.\n");
820 /* presentation url */
822 strncpyt(presentationurl
, presurl
, PRESENTATIONURL_MAX_LEN
);
824 strcpy(presentationurl
, "/");
826 /* set signal handler */
827 memset(&sa
, 0, sizeof(struct sigaction
));
828 sa
.sa_handler
= sigterm
;
829 if (sigaction(SIGTERM
, &sa
, NULL
))
831 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to set SIGTERM handler. EXITING.\n");
833 if (sigaction(SIGINT
, &sa
, NULL
))
835 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to set SIGINT handler. EXITING.\n");
838 if(signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) {
839 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to ignore SIGPIPE signals. EXITING.\n");
842 writepidfile(pidfilename
, pid
);
848 /* process HTTP or SSDP requests */
850 main(int argc
, char * * argv
)
853 int sudp
= -1, shttpl
= -1;
854 int snotify
[MAX_LAN_ADDR
];
855 LIST_HEAD(httplisthead
, upnphttp
) upnphttphead
;
856 struct upnphttp
* e
= 0;
857 struct upnphttp
* next
;
858 fd_set readset
; /* for select() */
860 struct timeval timeout
, timeofday
, lastnotifytime
= {0, 0};
861 time_t lastupdatetime
= 0;
863 int last_changecnt
= 0;
864 pid_t scanner_pid
= 0;
865 pthread_t inotify_thread
= 0;
866 struct media_dir_s
*media_path
, *last_path
;
867 struct album_art_name_s
*art_names
, *last_name
;
869 unsigned short int beacon_interval
= 5;
871 struct sockaddr_in tivo_bcast
;
872 struct timeval lastbeacontime
= {0, 0};
875 for (i
= 0; i
< L_MAX
; i
++)
876 log_level
[i
] = E_WARN
;
878 setlocale(LC_MESSAGES
, "");
879 setlocale(LC_CTYPE
, "en_US.utf8");
880 DPRINTF(E_DEBUG
, L_GENERAL
, "Using locale dir %s\n", bindtextdomain("minidlna", getenv("TEXTDOMAINDIR")));
881 textdomain("minidlna");
884 if (init(argc
, argv
) != 0)
888 DPRINTF(E_WARN
, L_GENERAL
, "Starting " SERVER_NAME
" version " MINIDLNA_VERSION
".\n");
889 unlink("/ramfs/.upnp-av_scan");
891 DPRINTF(E_WARN
, L_GENERAL
, "Starting " SERVER_NAME
" version " MINIDLNA_VERSION
" [SQLite %s].\n", sqlite3_libversion());
892 unlink("/var/notice/dlna");
893 if( !sqlite3_threadsafe() )
895 DPRINTF(E_ERROR
, L_GENERAL
, "SQLite library is not threadsafe! "
896 "Scanning must be finished before file serving can begin, "
897 "and inotify will be disabled.\n");
899 if( sqlite3_libversion_number() < 3005001 )
901 DPRINTF(E_WARN
, L_GENERAL
, "SQLite library is old. Please use version 3.5.1 or newer.\n");
904 LIST_INIT(&upnphttphead
);
908 updateID
= sql_get_int_field(db
, "SELECT UPDATE_ID from SETTINGS");
915 DPRINTF(E_WARN
, L_GENERAL
, "Creating new database...\n");
919 DPRINTF(E_WARN
, L_GENERAL
, "Database version mismatch; need to recreate...\n");
923 i
= asprintf(&cmd
, "rm -rf %s/files.db %s/art_cache", db_path
, db_path
);
930 DPRINTF(E_WARN
, L_GENERAL
, "Failed to clean old file cache.\n");
934 if( CreateDatabase() != 0 )
936 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: Failed to create sqlite database! Exiting...\n");
941 scanner_pid
= fork();
943 if( !scanner_pid
) // child (scanner) process
947 media_path
= media_dirs
;
948 art_names
= album_art_names
;
951 free(media_path
->path
);
952 last_path
= media_path
;
953 media_path
= media_path
->next
;
958 free(art_names
->name
);
959 last_name
= art_names
;
960 art_names
= art_names
->next
;
970 signal(SIGCHLD
, SIG_IGN
);
971 if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 &&
972 GETFLAG(INOTIFY_MASK
) && pthread_create(&inotify_thread
, NULL
, start_inotify
, NULL
) )
974 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: pthread_create() failed for start_inotify.\n");
977 sudp
= OpenAndConfSSDPReceiveSocket(n_lan_addr
, lan_addr
);
980 DPRINTF(E_INFO
, L_GENERAL
, "Failed to open socket for receiving SSDP. Trying to use MiniSSDPd\n");
981 if(SubmitServicesToMiniSSDPD(lan_addr
[0].str
, runtime_vars
.port
) < 0) {
982 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to connect to MiniSSDPd. EXITING");
986 /* open socket for HTTP connections. Listen on the 1st LAN address */
987 shttpl
= OpenAndConfHTTPSocket((runtime_vars
.port
> 0) ? runtime_vars
.port
: 0);
990 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open socket for HTTP. EXITING\n");
992 if(runtime_vars
.port
<= 0)
994 struct sockaddr_in sockinfo
;
995 socklen_t len
= sizeof(struct sockaddr_in
);
996 if (getsockname(shttpl
, (struct sockaddr
*)&sockinfo
, &len
) < 0)
998 DPRINTF(E_FATAL
, L_GENERAL
, "getsockname(): %s. EXITING\n", strerror(errno
));
1000 runtime_vars
.port
= ntohs(sockinfo
.sin_port
);
1002 DPRINTF(E_WARN
, L_GENERAL
, "HTTP listening on port %d\n", runtime_vars
.port
);
1004 /* open socket for sending notifications */
1005 if(OpenAndConfSSDPNotifySockets(snotify
) < 0)
1007 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open sockets for sending SSDP notify "
1008 "messages. EXITING\n");
1012 if( GETFLAG(TIVO_MASK
) )
1014 DPRINTF(E_WARN
, L_GENERAL
, "TiVo support is enabled.\n");
1015 /* Add TiVo-specific randomize function to sqlite */
1016 if( sqlite3_create_function(db
, "tivorandom", 1, SQLITE_UTF8
, NULL
, &TiVoRandomSeedFunc
, NULL
, NULL
) != SQLITE_OK
)
1018 DPRINTF(E_ERROR
, L_TIVO
, "ERROR: Failed to add sqlite randomize function for TiVo!\n");
1020 /* open socket for sending Tivo notifications */
1021 sbeacon
= OpenAndConfTivoBeaconSocket();
1024 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open sockets for sending Tivo beacon notify "
1025 "messages. EXITING\n");
1027 tivo_bcast
.sin_family
= AF_INET
;
1028 tivo_bcast
.sin_addr
.s_addr
= htonl(getBcastAddress());
1029 tivo_bcast
.sin_port
= htons(2190);
1037 SendSSDPGoodbye(snotify
, n_lan_addr
);
1042 /* Check if we need to send SSDP NOTIFY messages and do it if
1044 if(gettimeofday(&timeofday
, 0) < 0)
1046 DPRINTF(E_ERROR
, L_GENERAL
, "gettimeofday(): %s\n", strerror(errno
));
1047 timeout
.tv_sec
= runtime_vars
.notify_interval
;
1048 timeout
.tv_usec
= 0;
1052 /* the comparaison is not very precise but who cares ? */
1053 if(timeofday
.tv_sec
>= (lastnotifytime
.tv_sec
+ runtime_vars
.notify_interval
))
1055 SendSSDPNotifies2(snotify
,
1056 (unsigned short)runtime_vars
.port
,
1057 (runtime_vars
.notify_interval
<< 1)+10);
1058 memcpy(&lastnotifytime
, &timeofday
, sizeof(struct timeval
));
1059 timeout
.tv_sec
= runtime_vars
.notify_interval
;
1060 timeout
.tv_usec
= 0;
1064 timeout
.tv_sec
= lastnotifytime
.tv_sec
+ runtime_vars
.notify_interval
1066 if(timeofday
.tv_usec
> lastnotifytime
.tv_usec
)
1068 timeout
.tv_usec
= 1000000 + lastnotifytime
.tv_usec
1069 - timeofday
.tv_usec
;
1074 timeout
.tv_usec
= lastnotifytime
.tv_usec
- timeofday
.tv_usec
;
1078 if( GETFLAG(TIVO_MASK
) )
1080 if(timeofday
.tv_sec
>= (lastbeacontime
.tv_sec
+ beacon_interval
))
1082 sendBeaconMessage(sbeacon
, &tivo_bcast
, sizeof(struct sockaddr_in
), 1);
1083 memcpy(&lastbeacontime
, &timeofday
, sizeof(struct timeval
));
1084 if( timeout
.tv_sec
> beacon_interval
)
1086 timeout
.tv_sec
= beacon_interval
;
1087 timeout
.tv_usec
= 0;
1089 /* Beacons should be sent every 5 seconds or so for the first minute,
1090 * then every minute or so thereafter. */
1091 if( beacon_interval
== 5 && (timeofday
.tv_sec
- startup_time
) > 60 )
1093 beacon_interval
= 60;
1096 else if( timeout
.tv_sec
> (lastbeacontime
.tv_sec
+ beacon_interval
+ 1 - timeofday
.tv_sec
) )
1098 timeout
.tv_sec
= lastbeacontime
.tv_sec
+ beacon_interval
- timeofday
.tv_sec
;
1106 if( !scanner_pid
|| kill(scanner_pid
, 0) )
1113 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
1118 FD_SET(sudp
, &readset
);
1119 max_fd
= MAX(max_fd
, sudp
);
1124 FD_SET(shttpl
, &readset
);
1125 max_fd
= MAX(max_fd
, shttpl
);
1130 FD_SET(sbeacon
, &readset
);
1131 max_fd
= MAX(max_fd
, sbeacon
);
1134 i
= 0; /* active HTTP connections count */
1135 for(e
= upnphttphead
.lh_first
; e
!= NULL
; e
= e
->entries
.le_next
)
1137 if((e
->socket
>= 0) && (e
->state
<= 2))
1139 FD_SET(e
->socket
, &readset
);
1140 max_fd
= MAX(max_fd
, e
->socket
);
1148 DPRINTF(E_DEBUG
, L_GENERAL
, "%d active incoming HTTP connections\n", i
);
1152 upnpevents_selectfds(&readset
, &writeset
, &max_fd
);
1154 if(select(max_fd
+1, &readset
, &writeset
, 0, &timeout
) < 0)
1156 if(quitting
) goto shutdown
;
1157 DPRINTF(E_ERROR
, L_GENERAL
, "select(all): %s\n", strerror(errno
));
1158 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to select open sockets. EXITING\n");
1160 upnpevents_processfds(&readset
, &writeset
);
1161 /* process SSDP packets */
1162 if(sudp
>= 0 && FD_ISSET(sudp
, &readset
))
1164 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
1165 ProcessSSDPRequest(sudp
, (unsigned short)runtime_vars
.port
);
1168 if(sbeacon
>= 0 && FD_ISSET(sbeacon
, &readset
))
1170 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
1171 ProcessTiVoBeacon(sbeacon
);
1174 /* increment SystemUpdateID if the content database has changed,
1175 * and if there is an active HTTP connection, at most once every 2 seconds */
1176 if( i
&& (timeofday
.tv_sec
>= (lastupdatetime
+ 2)) )
1178 if( scanning
|| sqlite3_total_changes(db
) != last_changecnt
)
1181 last_changecnt
= sqlite3_total_changes(db
);
1182 upnp_event_var_change_notify(EContentDirectory
);
1183 lastupdatetime
= timeofday
.tv_sec
;
1186 /* process active HTTP connections */
1187 for(e
= upnphttphead
.lh_first
; e
!= NULL
; e
= e
->entries
.le_next
)
1189 if( (e
->socket
>= 0) && (e
->state
<= 2)
1190 &&(FD_ISSET(e
->socket
, &readset
)) )
1192 Process_upnphttp(e
);
1195 /* process incoming HTTP connections */
1196 if(shttpl
>= 0 && FD_ISSET(shttpl
, &readset
))
1199 socklen_t clientnamelen
;
1200 struct sockaddr_in clientname
;
1201 clientnamelen
= sizeof(struct sockaddr_in
);
1202 shttp
= accept(shttpl
, (struct sockaddr
*)&clientname
, &clientnamelen
);
1205 DPRINTF(E_ERROR
, L_GENERAL
, "accept(http): %s\n", strerror(errno
));
1209 struct upnphttp
* tmp
= 0;
1210 DPRINTF(E_DEBUG
, L_GENERAL
, "HTTP connection from %s:%d\n",
1211 inet_ntoa(clientname
.sin_addr
),
1212 ntohs(clientname
.sin_port
) );
1213 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
1214 DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK\n");
1216 /* Create a new upnphttp object and add it to
1217 * the active upnphttp object list */
1218 tmp
= New_upnphttp(shttp
);
1221 tmp
->clientaddr
= clientname
.sin_addr
;
1222 LIST_INSERT_HEAD(&upnphttphead
, tmp
, entries
);
1226 DPRINTF(E_ERROR
, L_GENERAL
, "New_upnphttp() failed\n");
1231 /* delete finished HTTP connections */
1232 for(e
= upnphttphead
.lh_first
; e
!= NULL
; )
1234 next
= e
->entries
.le_next
;
1237 LIST_REMOVE(e
, entries
);
1245 /* kill the scanner */
1246 if( scanning
&& scanner_pid
)
1248 kill(scanner_pid
, 9);
1250 /* close out open sockets */
1251 while(upnphttphead
.lh_first
!= NULL
)
1253 e
= upnphttphead
.lh_first
;
1254 LIST_REMOVE(e
, entries
);
1258 if (sudp
>= 0) close(sudp
);
1259 if (shttpl
>= 0) close(shttpl
);
1261 if (sbeacon
>= 0) close(sbeacon
);
1264 if(SendSSDPGoodbye(snotify
, n_lan_addr
) < 0)
1266 DPRINTF(E_ERROR
, L_GENERAL
, "Failed to broadcast good-bye notifications\n");
1268 for(i
=0; i
<n_lan_addr
; i
++)
1271 if( inotify_thread
)
1272 pthread_join(inotify_thread
, NULL
);
1274 sql_exec(db
, "UPDATE SETTINGS set UPDATE_ID = %u", updateID
);
1277 upnpevents_removeSubscribers();
1279 media_path
= media_dirs
;
1280 art_names
= album_art_names
;
1283 free(media_path
->path
);
1284 last_path
= media_path
;
1285 media_path
= media_path
->next
;
1290 free(art_names
->name
);
1291 last_name
= art_names
;
1292 art_names
= art_names
->next
;
1296 if(unlink(pidfilename
) < 0)
1298 DPRINTF(E_ERROR
, L_GENERAL
, "Failed to remove pidfile %s: %s\n", pidfilename
, strerror(errno
));