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 strncpy(buf
, hn
, len
-1);
215 dot
= strchr(buf
, '.');
221 strcpy(buf
, "Unknown");
226 off
+= snprintf(buf
+off
, len
-off
, ": ");
229 char ibuf
[64], *key
, *val
;
230 snprintf(buf
+off
, len
-off
, "ReadyNAS");
231 info
= fopen("/proc/sys/dev/boot/info", "r");
234 while( (val
= fgets(ibuf
, 64, info
)) != NULL
)
236 key
= strsep(&val
, ": \t");
238 if( strcmp(key
, "model") == 0 )
240 snprintf(buf
+off
, len
-off
, "%s", val
);
241 key
= strchr(val
, ' ');
244 strncpy(modelnumber
, key
+1, MODELNUMBER_MAX_LEN
);
245 modelnumber
[MODELNUMBER_MAX_LEN
-1] = '\0';
248 snprintf(modelname
, MODELNAME_MAX_LEN
,
249 "Windows Media Connect compatible (%s)", val
);
251 else if( strcmp(key
, "serial") == 0 )
253 strncpy(serialnumber
, val
, SERIALNUMBER_MAX_LEN
);
254 serialnumber
[SERIALNUMBER_MAX_LEN
-1] = '\0';
255 if( serialnumber
[0] == '\0' )
258 if( getsyshwaddr(mac_str
, sizeof(mac_str
)) == 0 )
259 strcpy(serialnumber
, mac_str
);
261 strcpy(serialnumber
, "0");
267 memcpy(pnpx_hwid
+4, "01F2", 4);
268 if( strcmp(modelnumber
, "NVX") == 0 )
269 memcpy(pnpx_hwid
+17, "0101", 4);
270 else if( strcmp(modelnumber
, "Pro") == 0 ||
271 strcmp(modelnumber
, "Pro 6") == 0 ||
272 strncmp(modelnumber
, "Ultra 6", 7) == 0 )
273 memcpy(pnpx_hwid
+17, "0102", 4);
274 else if( strcmp(modelnumber
, "Pro 2") == 0 ||
275 strncmp(modelnumber
, "Ultra 2", 7) == 0 )
276 memcpy(pnpx_hwid
+17, "0103", 4);
277 else if( strcmp(modelnumber
, "Pro 4") == 0 ||
278 strncmp(modelnumber
, "Ultra 4", 7) == 0 )
279 memcpy(pnpx_hwid
+17, "0104", 4);
280 else if( strcmp(modelnumber
+1, "100") == 0 )
281 memcpy(pnpx_hwid
+17, "0105", 4);
282 else if( strcmp(modelnumber
+1, "200") == 0 )
283 memcpy(pnpx_hwid
+17, "0106", 4);
285 else if( strcmp(modelnumber
, "Duo v2") == 0 )
286 memcpy(pnpx_hwid
+17, "0108", 4);
287 else if( strcmp(modelnumber
, "NV+ v2") == 0 )
288 memcpy(pnpx_hwid
+17, "0109", 4);
291 logname
= getenv("LOGNAME");
292 #ifndef STATIC // Disable for static linking
295 struct passwd
* pwent
;
296 pwent
= getpwuid(getuid());
298 logname
= pwent
->pw_name
;
301 snprintf(buf
+off
, len
-off
, "%s", logname
?logname
:"Unknown");
311 snprintf(path
, sizeof(path
), "%s/files.db", db_path
);
312 if( access(path
, F_OK
) != 0 )
315 make_dir(db_path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
317 if( sqlite3_open(path
, &db
) != SQLITE_OK
)
319 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: Failed to open sqlite database! Exiting...\n");
321 sqlite3_busy_timeout(db
, 5000);
322 sql_exec(db
, "pragma page_size = 4096");
323 sql_exec(db
, "pragma journal_mode = OFF");
324 sql_exec(db
, "pragma synchronous = OFF;");
326 // this sets the sqlite database cache size
327 // original code had 8192 = 32MB - reduce it to 4MB
328 sql_exec(db
, "pragma default_cache_size = 1024;");
333 * 1) read configuration file
334 * 2) read command line arguments
336 * 4) check and write pid file
337 * 5) set startup time stamp
338 * 6) compute presentation URL
339 * 7) set signal handlers */
341 init(int argc
, char * * argv
)
346 int options_flag
= 0;
348 /*const char * logfilename = 0;*/
349 const char * presurl
= 0;
350 const char * optionsfile
= "/etc/minidlna.conf";
352 char * string
, * word
;
353 enum media_types type
;
355 char real_path
[PATH_MAX
];
356 char ip_addr
[INET_ADDRSTRLEN
+ 3] = {'\0'};
358 /* first check if "-f" option is used */
359 for(i
=2; i
<argc
; i
++)
361 if(0 == strcmp(argv
[i
-1], "-f"))
363 optionsfile
= argv
[i
];
369 /* set up uuid based on mac address */
370 if( getsyshwaddr(mac_str
, sizeof(mac_str
)) < 0 )
372 DPRINTF(E_OFF
, L_GENERAL
, "No MAC address found. Falling back to generic UUID.\n");
373 strcpy(mac_str
, "554e4b4e4f57");
375 strcpy(uuidvalue
+5, "4d696e69-444c-164e-9d41-");
376 strncat(uuidvalue
, mac_str
, 12);
378 getfriendlyname(friendly_name
, FRIENDLYNAME_MAX_LEN
);
380 runtime_vars
.port
= -1;
381 runtime_vars
.notify_interval
= 895; /* seconds between SSDP announces */
382 runtime_vars
.root_container
= NULL
;
384 /* read options file first since
385 * command line arguments have final say */
386 if(readoptionsfile(optionsfile
) < 0)
388 /* only error if file exists or using -f */
389 if(access(optionsfile
, F_OK
) == 0 || options_flag
)
390 fprintf(stderr
, "Error reading configuration file %s\n", optionsfile
);
394 for(i
=0; i
<num_options
; i
++)
396 switch(ary_options
[i
].id
)
399 for( string
= ary_options
[i
].value
; (word
= strtok(string
, ",")); string
= NULL
)
401 if(n_lan_addr
< MAX_LAN_ADDR
)
403 if(getifaddr(word
, ip_addr
, sizeof(ip_addr
)) >= 0)
405 if( *ip_addr
&& parselanaddr(&lan_addr
[n_lan_addr
], ip_addr
) == 0 )
406 if(n_lan_addr
< MAX_LAN_ADDR
)
410 fprintf(stderr
, "Interface %s not found, ignoring.\n", word
);
414 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
419 case UPNPLISTENING_IP
:
420 if(n_lan_addr
< MAX_LAN_ADDR
)
422 if(parselanaddr(&lan_addr
[n_lan_addr
],
423 ary_options
[i
].value
) == 0)
428 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
429 MAX_LAN_ADDR
, ary_options
[i
].value
);
433 runtime_vars
.port
= atoi(ary_options
[i
].value
);
435 case UPNPPRESENTATIONURL
:
436 presurl
= ary_options
[i
].value
;
438 case UPNPNOTIFY_INTERVAL
:
439 runtime_vars
.notify_interval
= atoi(ary_options
[i
].value
);
442 strncpy(serialnumber
, ary_options
[i
].value
, SERIALNUMBER_MAX_LEN
);
443 serialnumber
[SERIALNUMBER_MAX_LEN
-1] = '\0';
446 strncpy(modelname
, ary_options
[i
].value
, MODELNAME_MAX_LEN
);
447 modelname
[MODELNAME_MAX_LEN
-1] = '\0';
449 case UPNPMODEL_NUMBER
:
450 strncpy(modelnumber
, ary_options
[i
].value
, MODELNUMBER_MAX_LEN
);
451 modelnumber
[MODELNUMBER_MAX_LEN
-1] = '\0';
453 case UPNPFRIENDLYNAME
:
454 strncpy(friendly_name
, ary_options
[i
].value
, FRIENDLYNAME_MAX_LEN
);
455 friendly_name
[FRIENDLYNAME_MAX_LEN
-1] = '\0';
460 switch( ary_options
[i
].value
[0] )
464 if( ary_options
[i
].value
[0] == 'A' || ary_options
[i
].value
[0] == 'a' )
468 if( ary_options
[i
].value
[0] == 'V' || ary_options
[i
].value
[0] == 'v' )
472 if( ary_options
[i
].value
[0] == 'P' || ary_options
[i
].value
[0] == 'p' )
474 myval
= index(ary_options
[i
].value
, '/');
476 path
= realpath(myval
? myval
:ary_options
[i
].value
, real_path
);
478 path
= (myval
? myval
:ary_options
[i
].value
);
479 if( access(path
, F_OK
) != 0 )
481 fprintf(stderr
, "Media directory not accessible! [%s]\n",
485 struct media_dir_s
* this_dir
= calloc(1, sizeof(struct media_dir_s
));
486 this_dir
->path
= strdup(path
);
487 this_dir
->type
= type
;
490 media_dirs
= this_dir
;
494 struct media_dir_s
* all_dirs
= media_dirs
;
495 while( all_dirs
->next
)
496 all_dirs
= all_dirs
->next
;
497 all_dirs
->next
= this_dir
;
501 fprintf(stderr
, "Media directory entry not understood! [%s]\n",
502 ary_options
[i
].value
);
506 case UPNPALBUMART_NAMES
:
507 for( string
= ary_options
[i
].value
; (word
= strtok(string
, "/")); string
= NULL
)
509 struct album_art_name_s
* this_name
= calloc(1, sizeof(struct album_art_name_s
));
510 int len
= strlen(word
);
511 if( word
[len
-1] == '*' )
514 this_name
->wildcard
= 1;
516 this_name
->name
= strdup(word
);
517 if( !album_art_names
)
519 album_art_names
= this_name
;
523 struct album_art_name_s
* all_names
= album_art_names
;
524 while( all_names
->next
)
525 all_names
= all_names
->next
;
526 all_names
->next
= this_name
;
531 path
= realpath(ary_options
[i
].value
, real_path
);
533 path
= (ary_options
[i
].value
);
534 make_dir(path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
535 if( access(path
, F_OK
) != 0 )
537 DPRINTF(E_FATAL
, L_GENERAL
, "Database path not accessible! [%s]\n", path
);
540 strncpy(db_path
, path
, PATH_MAX
);
543 path
= realpath(ary_options
[i
].value
, real_path
);
545 path
= (ary_options
[i
].value
);
546 make_dir(path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
547 if( access(path
, F_OK
) != 0 )
549 DPRINTF(E_FATAL
, L_GENERAL
, "Log path not accessible! [%s]\n", path
);
552 strncpy(log_path
, path
, PATH_MAX
);
555 if( (strcmp(ary_options
[i
].value
, "yes") != 0) && !atoi(ary_options
[i
].value
) )
556 CLEARFLAG(INOTIFY_MASK
);
559 if( (strcmp(ary_options
[i
].value
, "yes") == 0) || atoi(ary_options
[i
].value
) )
562 case ENABLE_DLNA_STRICT
:
563 if( (strcmp(ary_options
[i
].value
, "yes") == 0) || atoi(ary_options
[i
].value
) )
564 SETFLAG(DLNA_STRICT_MASK
);
567 switch( ary_options
[i
].value
[0] )
570 runtime_vars
.root_container
= NULL
;
574 runtime_vars
.root_container
= BROWSEDIR_ID
;
578 runtime_vars
.root_container
= MUSIC_ID
;
582 runtime_vars
.root_container
= VIDEO_ID
;
586 runtime_vars
.root_container
= IMAGE_ID
;
589 fprintf(stderr
, "Invalid root container! [%s]\n",
590 ary_options
[i
].value
);
595 fprintf(stderr
, "Unknown option in file %s\n",
600 if( log_path
[0] == '\0' )
602 if( db_path
[0] == '\0' )
603 strncpy(log_path
, DEFAULT_LOG_PATH
, PATH_MAX
);
605 strncpy(log_path
, db_path
, PATH_MAX
);
607 if( db_path
[0] == '\0' )
608 strncpy(db_path
, DEFAULT_DB_PATH
, PATH_MAX
);
610 /* command line arguments processing */
611 for(i
=1; i
<argc
; i
++)
615 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
617 else if(strcmp(argv
[i
], "--help")==0)
619 runtime_vars
.port
= -1;
622 else switch(argv
[i
][1])
626 runtime_vars
.notify_interval
= atoi(argv
[++i
]);
628 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
632 strncpy(serialnumber
, argv
[++i
], SERIALNUMBER_MAX_LEN
);
634 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
635 serialnumber
[SERIALNUMBER_MAX_LEN
-1] = '\0';
639 strncpy(modelnumber
, argv
[++i
], MODELNUMBER_MAX_LEN
);
641 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
642 modelnumber
[MODELNUMBER_MAX_LEN
-1] = '\0';
645 logfilename = argv[++i];
649 runtime_vars
.port
= atoi(argv
[++i
]);
651 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
655 pidfilename
= argv
[++i
];
657 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
666 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
671 int address_already_there
= 0;
674 for(j
=0; j
<n_lan_addr
; j
++)
676 struct lan_addr_s tmpaddr
;
677 parselanaddr(&tmpaddr
, argv
[i
]);
678 if(0 == strcmp(lan_addr
[j
].str
, tmpaddr
.str
))
679 address_already_there
= 1;
681 if(address_already_there
)
683 if(n_lan_addr
< MAX_LAN_ADDR
)
685 if(parselanaddr(&lan_addr
[n_lan_addr
], argv
[i
]) == 0)
690 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
691 MAX_LAN_ADDR
, argv
[i
]);
695 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
700 int address_already_there
= 0;
703 if( getifaddr(argv
[i
], ip_addr
, sizeof(ip_addr
)) < 0 )
705 fprintf(stderr
, "Network interface '%s' not found.\n",
709 for(j
=0; j
<n_lan_addr
; j
++)
711 struct lan_addr_s tmpaddr
;
712 parselanaddr(&tmpaddr
, ip_addr
);
713 if(0 == strcmp(lan_addr
[j
].str
, tmpaddr
.str
))
714 address_already_there
= 1;
716 if(address_already_there
)
718 if(n_lan_addr
< MAX_LAN_ADDR
)
720 if(parselanaddr(&lan_addr
[n_lan_addr
], ip_addr
) == 0)
725 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
726 MAX_LAN_ADDR
, argv
[i
]);
730 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
733 i
++; /* discarding, the config file is already read */
736 runtime_vars
.port
= -1; // triggers help display
739 snprintf(real_path
, sizeof(real_path
), "rm -rf %s/files.db %s/art_cache", db_path
, db_path
);
743 printf("Version " MINIDLNA_VERSION
"\n");
747 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
750 /* If no IP was specified, try to detect one */
753 if( (getsysaddr(ip_addr
, sizeof(ip_addr
)) < 0) &&
754 (getifaddr("eth0", ip_addr
, sizeof(ip_addr
)) < 0) &&
755 (getifaddr("eth1", ip_addr
, sizeof(ip_addr
)) < 0) )
757 DPRINTF(E_OFF
, L_GENERAL
, "No IP address automatically detected!\n");
759 if( *ip_addr
&& parselanaddr(&lan_addr
[n_lan_addr
], ip_addr
) == 0 )
765 if( (n_lan_addr
==0) || (runtime_vars
.port
<0) )
767 fprintf(stderr
, "Usage:\n\t"
768 "%s [-d] [-f config_file]\n"
769 "\t\t[-a listening_ip] [-p port]\n"
770 /*"[-l logfile] " not functionnal */
771 "\t\t[-s serial] [-m model_number] \n"
772 "\t\t[-t notify_interval] [-P pid_filename]\n"
773 "\t\t[-w url] [-R] [-V] [-h]\n"
774 "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n"
775 "\tDefault pid file is %s.\n"
776 "\tWith -d minidlna will run in debug mode (not daemonize).\n"
777 "\t-w sets the presentation url. Default is http address on port 80\n"
778 "\t-h displays this text\n"
779 "\t-R forces a full rescan\n"
780 "\t-V print the version number\n",
781 argv
[0], pidfilename
);
788 log_init(NULL
, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=debug");
801 log_init("/var/log/upnp-av.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn");
803 if( access(db_path
, F_OK
) != 0 )
804 make_dir(db_path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
805 sprintf(real_path
, "%s/minidlna.log", log_path
);
806 log_init(real_path
, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn");
810 if(checkforrunning(pidfilename
) < 0)
812 DPRINTF(E_ERROR
, L_GENERAL
, "MiniDLNA is already running. EXITING.\n");
818 /* presentation url */
821 strncpy(presentationurl
, presurl
, PRESENTATIONURL_MAX_LEN
);
822 presentationurl
[PRESENTATIONURL_MAX_LEN
-1] = '\0';
827 snprintf(presentationurl
, PRESENTATIONURL_MAX_LEN
,
828 "http://%s/admin/", lan_addr
[0].str
);
830 snprintf(presentationurl
, PRESENTATIONURL_MAX_LEN
,
831 "http://%s:%d/", lan_addr
[0].str
);
835 /* set signal handler */
836 signal(SIGCLD
, SIG_IGN
);
837 memset(&sa
, 0, sizeof(struct sigaction
));
838 sa
.sa_handler
= sigterm
;
839 if (sigaction(SIGTERM
, &sa
, NULL
))
841 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to set SIGTERM handler. EXITING.\n");
843 if (sigaction(SIGINT
, &sa
, NULL
))
845 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to set SIGINT handler. EXITING.\n");
848 if(signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) {
849 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to ignore SIGPIPE signals. EXITING.\n");
852 writepidfile(pidfilename
, pid
);
858 /* process HTTP or SSDP requests */
860 main(int argc
, char * * argv
)
863 int sudp
= -1, shttpl
= -1;
864 int snotify
[MAX_LAN_ADDR
];
865 LIST_HEAD(httplisthead
, upnphttp
) upnphttphead
;
866 struct upnphttp
* e
= 0;
867 struct upnphttp
* next
;
868 fd_set readset
; /* for select() */
870 struct timeval timeout
, timeofday
, lastnotifytime
= {0, 0};
871 time_t lastupdatetime
= 0;
873 int last_changecnt
= 0;
874 pid_t scanner_pid
= 0;
875 pthread_t inotify_thread
= 0;
876 struct media_dir_s
*media_path
, *last_path
;
877 struct album_art_name_s
*art_names
, *last_name
;
879 unsigned short int beacon_interval
= 5;
881 struct sockaddr_in tivo_bcast
;
882 struct timeval lastbeacontime
= {0, 0};
886 setlocale(LC_MESSAGES
, "");
887 setlocale(LC_CTYPE
, "en_US.utf8");
888 DPRINTF(E_DEBUG
, L_GENERAL
, "Using locale dir %s\n", bindtextdomain("minidlna", getenv("TEXTDOMAINDIR")));
889 textdomain("minidlna");
892 if(init(argc
, argv
) != 0)
896 DPRINTF(E_WARN
, L_GENERAL
, "Starting " SERVER_NAME
" version " MINIDLNA_VERSION
".\n");
897 unlink("/ramfs/.upnp-av_scan");
899 DPRINTF(E_WARN
, L_GENERAL
, "Starting " SERVER_NAME
" version " MINIDLNA_VERSION
" [SQLite %s].\n", sqlite3_libversion());
900 unlink("/var/notice/dlna");
901 if( !sqlite3_threadsafe() )
903 DPRINTF(E_ERROR
, L_GENERAL
, "SQLite library is not threadsafe! "
904 "Scanning must be finished before file serving can begin, "
905 "and inotify will be disabled.\n");
907 if( sqlite3_libversion_number() < 3005001 )
909 DPRINTF(E_WARN
, L_GENERAL
, "SQLite library is old. Please use version 3.5.1 or newer.\n");
912 LIST_INIT(&upnphttphead
);
916 updateID
= sql_get_int_field(db
, "SELECT UPDATE_ID from SETTINGS");
923 DPRINTF(E_WARN
, L_GENERAL
, "Creating new database...\n");
927 DPRINTF(E_WARN
, L_GENERAL
, "Database version mismatch; need to recreate...\n");
931 asprintf(&cmd
, "rm -rf %s/files.db %s/art_cache", db_path
, db_path
);
935 if( CreateDatabase() != 0 )
937 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: Failed to create sqlite database! Exiting...\n");
942 scanner_pid
= fork();
944 if( !scanner_pid
) // child (scanner) process
948 media_path
= media_dirs
;
949 art_names
= album_art_names
;
952 free(media_path
->path
);
953 last_path
= media_path
;
954 media_path
= media_path
->next
;
959 free(art_names
->name
);
960 last_name
= art_names
;
961 art_names
= art_names
->next
;
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_FATAL
, L_GENERAL
, "Failed to open socket for receiving SSDP. EXITING\n");
982 /* open socket for HTTP connections. Listen on the 1st LAN address */
983 shttpl
= OpenAndConfHTTPSocket((runtime_vars
.port
> 0) ? runtime_vars
.port
: 0);
986 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open socket for HTTP. EXITING\n");
988 if(runtime_vars
.port
<= 0)
990 struct sockaddr_in sockinfo
;
991 socklen_t len
= sizeof(struct sockaddr_in
);
992 if (getsockname(shttpl
, (struct sockaddr
*)&sockinfo
, &len
) < 0)
994 DPRINTF(E_FATAL
, L_GENERAL
, "getsockname(): %s. EXITING\n", strerror(errno
));
996 runtime_vars
.port
= ntohs(sockinfo
.sin_port
);
998 DPRINTF(E_WARN
, L_GENERAL
, "HTTP listening on port %d\n", runtime_vars
.port
);
1000 /* open socket for sending notifications */
1001 if(OpenAndConfSSDPNotifySockets(snotify
) < 0)
1003 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open sockets for sending SSDP notify "
1004 "messages. EXITING\n");
1008 if( GETFLAG(TIVO_MASK
) )
1010 DPRINTF(E_WARN
, L_GENERAL
, "TiVo support is enabled.\n");
1011 /* Add TiVo-specific randomize function to sqlite */
1012 if( sqlite3_create_function(db
, "tivorandom", 1, SQLITE_UTF8
, NULL
, &TiVoRandomSeedFunc
, NULL
, NULL
) != SQLITE_OK
)
1014 DPRINTF(E_ERROR
, L_TIVO
, "ERROR: Failed to add sqlite randomize function for TiVo!\n");
1016 /* open socket for sending Tivo notifications */
1017 sbeacon
= OpenAndConfTivoBeaconSocket();
1020 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open sockets for sending Tivo beacon notify "
1021 "messages. EXITING\n");
1023 tivo_bcast
.sin_family
= AF_INET
;
1024 tivo_bcast
.sin_addr
.s_addr
= htonl(getBcastAddress());
1025 tivo_bcast
.sin_port
= htons(2190);
1033 SendSSDPGoodbye(snotify
, n_lan_addr
);
1038 /* Check if we need to send SSDP NOTIFY messages and do it if
1040 if(gettimeofday(&timeofday
, 0) < 0)
1042 DPRINTF(E_ERROR
, L_GENERAL
, "gettimeofday(): %s\n", strerror(errno
));
1043 timeout
.tv_sec
= runtime_vars
.notify_interval
;
1044 timeout
.tv_usec
= 0;
1048 /* the comparaison is not very precise but who cares ? */
1049 if(timeofday
.tv_sec
>= (lastnotifytime
.tv_sec
+ runtime_vars
.notify_interval
))
1051 SendSSDPNotifies2(snotify
,
1052 (unsigned short)runtime_vars
.port
,
1053 (runtime_vars
.notify_interval
<< 1)+10);
1054 memcpy(&lastnotifytime
, &timeofday
, sizeof(struct timeval
));
1055 timeout
.tv_sec
= runtime_vars
.notify_interval
;
1056 timeout
.tv_usec
= 0;
1060 timeout
.tv_sec
= lastnotifytime
.tv_sec
+ runtime_vars
.notify_interval
1062 if(timeofday
.tv_usec
> lastnotifytime
.tv_usec
)
1064 timeout
.tv_usec
= 1000000 + lastnotifytime
.tv_usec
1065 - timeofday
.tv_usec
;
1070 timeout
.tv_usec
= lastnotifytime
.tv_usec
- timeofday
.tv_usec
;
1074 if( GETFLAG(TIVO_MASK
) )
1076 if(timeofday
.tv_sec
>= (lastbeacontime
.tv_sec
+ beacon_interval
))
1078 sendBeaconMessage(sbeacon
, &tivo_bcast
, sizeof(struct sockaddr_in
), 1);
1079 memcpy(&lastbeacontime
, &timeofday
, sizeof(struct timeval
));
1080 if( timeout
.tv_sec
> beacon_interval
)
1082 timeout
.tv_sec
= beacon_interval
;
1083 timeout
.tv_usec
= 0;
1085 /* Beacons should be sent every 5 seconds or so for the first minute,
1086 * then every minute or so thereafter. */
1087 if( beacon_interval
== 5 && (timeofday
.tv_sec
- startup_time
) > 60 )
1089 beacon_interval
= 60;
1092 else if( timeout
.tv_sec
> (lastbeacontime
.tv_sec
+ beacon_interval
+ 1 - timeofday
.tv_sec
) )
1094 timeout
.tv_sec
= lastbeacontime
.tv_sec
+ beacon_interval
- timeofday
.tv_sec
;
1102 if( !scanner_pid
|| kill(scanner_pid
, 0) )
1109 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
1114 FD_SET(sudp
, &readset
);
1115 max_fd
= MAX(max_fd
, sudp
);
1120 FD_SET(shttpl
, &readset
);
1121 max_fd
= MAX(max_fd
, shttpl
);
1126 FD_SET(sbeacon
, &readset
);
1127 max_fd
= MAX(max_fd
, sbeacon
);
1130 i
= 0; /* active HTTP connections count */
1131 for(e
= upnphttphead
.lh_first
; e
!= NULL
; e
= e
->entries
.le_next
)
1133 if((e
->socket
>= 0) && (e
->state
<= 2))
1135 FD_SET(e
->socket
, &readset
);
1136 max_fd
= MAX(max_fd
, e
->socket
);
1144 DPRINTF(E_DEBUG
, L_GENERAL
, "%d active incoming HTTP connections\n", i
);
1148 upnpevents_selectfds(&readset
, &writeset
, &max_fd
);
1150 if(select(max_fd
+1, &readset
, &writeset
, 0, &timeout
) < 0)
1152 if(quitting
) goto shutdown
;
1153 DPRINTF(E_ERROR
, L_GENERAL
, "select(all): %s\n", strerror(errno
));
1154 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to select open sockets. EXITING\n");
1156 upnpevents_processfds(&readset
, &writeset
);
1157 /* process SSDP packets */
1158 if(sudp
>= 0 && FD_ISSET(sudp
, &readset
))
1160 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
1161 ProcessSSDPRequest(sudp
, (unsigned short)runtime_vars
.port
);
1164 if(sbeacon
>= 0 && FD_ISSET(sbeacon
, &readset
))
1166 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
1167 ProcessTiVoBeacon(sbeacon
);
1170 /* increment SystemUpdateID if the content database has changed,
1171 * and if there is an active HTTP connection, at most once every 2 seconds */
1172 if( i
&& (timeofday
.tv_sec
>= (lastupdatetime
+ 2)) )
1174 if( scanning
|| sqlite3_total_changes(db
) != last_changecnt
)
1177 last_changecnt
= sqlite3_total_changes(db
);
1178 upnp_event_var_change_notify(EContentDirectory
);
1179 lastupdatetime
= timeofday
.tv_sec
;
1182 /* process active HTTP connections */
1183 for(e
= upnphttphead
.lh_first
; e
!= NULL
; e
= e
->entries
.le_next
)
1185 if( (e
->socket
>= 0) && (e
->state
<= 2)
1186 &&(FD_ISSET(e
->socket
, &readset
)) )
1188 Process_upnphttp(e
);
1191 /* process incoming HTTP connections */
1192 if(shttpl
>= 0 && FD_ISSET(shttpl
, &readset
))
1195 socklen_t clientnamelen
;
1196 struct sockaddr_in clientname
;
1197 clientnamelen
= sizeof(struct sockaddr_in
);
1198 shttp
= accept(shttpl
, (struct sockaddr
*)&clientname
, &clientnamelen
);
1201 DPRINTF(E_ERROR
, L_GENERAL
, "accept(http): %s\n", strerror(errno
));
1205 struct upnphttp
* tmp
= 0;
1206 DPRINTF(E_DEBUG
, L_GENERAL
, "HTTP connection from %s:%d\n",
1207 inet_ntoa(clientname
.sin_addr
),
1208 ntohs(clientname
.sin_port
) );
1209 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
1210 DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK\n");
1212 /* Create a new upnphttp object and add it to
1213 * the active upnphttp object list */
1214 tmp
= New_upnphttp(shttp
);
1217 tmp
->clientaddr
= clientname
.sin_addr
;
1218 LIST_INSERT_HEAD(&upnphttphead
, tmp
, entries
);
1222 DPRINTF(E_ERROR
, L_GENERAL
, "New_upnphttp() failed\n");
1227 /* delete finished HTTP connections */
1228 for(e
= upnphttphead
.lh_first
; e
!= NULL
; )
1230 next
= e
->entries
.le_next
;
1233 LIST_REMOVE(e
, entries
);
1241 /* kill the scanner */
1242 if( scanning
&& scanner_pid
)
1244 kill(scanner_pid
, 9);
1246 /* close out open sockets */
1247 while(upnphttphead
.lh_first
!= NULL
)
1249 e
= upnphttphead
.lh_first
;
1250 LIST_REMOVE(e
, entries
);
1254 if (sudp
>= 0) close(sudp
);
1255 if (shttpl
>= 0) close(shttpl
);
1257 if (sbeacon
>= 0) close(sbeacon
);
1260 if(SendSSDPGoodbye(snotify
, n_lan_addr
) < 0)
1262 DPRINTF(E_ERROR
, L_GENERAL
, "Failed to broadcast good-bye notifications\n");
1264 for(i
=0; i
<n_lan_addr
; i
++)
1267 if( inotify_thread
)
1268 pthread_join(inotify_thread
, NULL
);
1270 sql_exec(db
, "UPDATE SETTINGS set UPDATE_ID = %u", updateID
);
1273 media_path
= media_dirs
;
1274 art_names
= album_art_names
;
1277 free(media_path
->path
);
1278 last_path
= media_path
;
1279 media_path
= media_path
->next
;
1284 free(art_names
->name
);
1285 last_name
= art_names
;
1286 art_names
= art_names
->next
;
1290 if(unlink(pidfilename
) < 0)
1292 DPRINTF(E_ERROR
, L_GENERAL
, "Failed to remove pidfile %s: %s\n", pidfilename
, strerror(errno
));