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/mask: %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);
209 if( gethostname(hn
, 256) == 0 )
211 strncpy(buf
, hn
, len
-1);
213 dot
= index(buf
, '.');
219 strcpy(buf
, "Unknown");
224 strncat(buf
, "ReadyNAS", len
-strlen(buf
)-1);
227 logname
= getenv("LOGNAME");
228 #if 1 // Disable for static linking
231 struct passwd
* pwent
;
232 pwent
= getpwuid(getuid());
234 logname
= pwent
->pw_name
;
237 strncat(buf
, logname
?logname
:"Unknown", len
-strlen(buf
)-1);
247 snprintf(path
, sizeof(path
), "%s/files.db", db_path
);
248 if( access(path
, F_OK
) != 0 )
251 make_dir(db_path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
253 if( sqlite3_open(path
, &db
) != SQLITE_OK
)
255 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: Failed to open sqlite database! Exiting...\n");
257 sqlite3_busy_timeout(db
, 5000);
258 sql_exec(db
, "pragma page_size = 4096");
259 sql_exec(db
, "pragma journal_mode = OFF");
260 sql_exec(db
, "pragma synchronous = OFF;");
262 // this sets the sqlite database cache size
263 // original code had 8192 = 32MB - reduce it to 4MB
264 sql_exec(db
, "pragma default_cache_size = 1024;");
269 * 1) read configuration file
270 * 2) read command line arguments
272 * 4) check and write pid file
273 * 5) set startup time stamp
274 * 6) compute presentation URL
275 * 7) set signal handlers */
277 init(int argc
, char * * argv
)
282 int options_flag
= 0;
284 /*const char * logfilename = 0;*/
285 const char * presurl
= 0;
286 const char * optionsfile
= "/etc/minidlna.conf";
288 char * string
, * word
;
289 enum media_types type
;
291 char real_path
[PATH_MAX
];
292 char ext_ip_addr
[INET_ADDRSTRLEN
] = {'\0'};
294 /* first check if "-f" option is used */
295 for(i
=2; i
<argc
; i
++)
297 if(0 == strcmp(argv
[i
-1], "-f"))
299 optionsfile
= argv
[i
];
305 /* set up uuid based on mac address */
306 if( getsyshwaddr(mac_str
, sizeof(mac_str
)) < 0 )
308 DPRINTF(E_OFF
, L_GENERAL
, "No MAC address found. Falling back to generic UUID.\n");
309 strcpy(mac_str
, "554e4b4e4f57");
311 strcpy(uuidvalue
+5, "4d696e69-444c-164e-9d41-");
312 strncat(uuidvalue
, mac_str
, 12);
314 getfriendlyname(friendly_name
, FRIENDLYNAME_MAX_LEN
);
316 runtime_vars
.port
= -1;
317 runtime_vars
.notify_interval
= 895; /* seconds between SSDP announces */
319 /* read options file first since
320 * command line arguments have final say */
321 if(readoptionsfile(optionsfile
) < 0)
323 /* only error if file exists or using -f */
324 if(access(optionsfile
, F_OK
) == 0 || options_flag
)
325 fprintf(stderr
, "Error reading configuration file %s\n", optionsfile
);
329 for(i
=0; i
<num_options
; i
++)
331 switch(ary_options
[i
].id
)
334 if(getifaddr(ary_options
[i
].value
, ext_ip_addr
, INET_ADDRSTRLEN
) >= 0)
336 if( *ext_ip_addr
&& parselanaddr(&lan_addr
[n_lan_addr
], ext_ip_addr
) == 0 )
340 fprintf(stderr
, "Interface %s not found, ignoring.\n", ary_options
[i
].value
);
342 case UPNPLISTENING_IP
:
343 if(n_lan_addr
< MAX_LAN_ADDR
)
345 if(parselanaddr(&lan_addr
[n_lan_addr
],
346 ary_options
[i
].value
) == 0)
351 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
352 MAX_LAN_ADDR
, ary_options
[i
].value
);
356 runtime_vars
.port
= atoi(ary_options
[i
].value
);
358 case UPNPPRESENTATIONURL
:
359 presurl
= ary_options
[i
].value
;
361 case UPNPNOTIFY_INTERVAL
:
362 runtime_vars
.notify_interval
= atoi(ary_options
[i
].value
);
365 strncpy(serialnumber
, ary_options
[i
].value
, SERIALNUMBER_MAX_LEN
);
366 serialnumber
[SERIALNUMBER_MAX_LEN
-1] = '\0';
368 case UPNPMODEL_NUMBER
:
369 strncpy(modelnumber
, ary_options
[i
].value
, MODELNUMBER_MAX_LEN
);
370 modelnumber
[MODELNUMBER_MAX_LEN
-1] = '\0';
372 case UPNPFRIENDLYNAME
:
373 strncpy(friendly_name
, ary_options
[i
].value
, FRIENDLYNAME_MAX_LEN
);
374 friendly_name
[FRIENDLYNAME_MAX_LEN
-1] = '\0';
379 switch( ary_options
[i
].value
[0] )
383 if( ary_options
[i
].value
[0] == 'A' || ary_options
[i
].value
[0] == 'a' )
387 if( ary_options
[i
].value
[0] == 'V' || ary_options
[i
].value
[0] == 'v' )
391 if( ary_options
[i
].value
[0] == 'P' || ary_options
[i
].value
[0] == 'p' )
393 myval
= index(ary_options
[i
].value
, '/');
395 path
= realpath(myval
? myval
:ary_options
[i
].value
, real_path
);
397 path
= (myval
? myval
:ary_options
[i
].value
);
398 if( access(path
, F_OK
) != 0 )
400 fprintf(stderr
, "Media directory not accessible! [%s]\n",
404 struct media_dir_s
* this_dir
= calloc(1, sizeof(struct media_dir_s
));
405 this_dir
->path
= strdup(path
);
406 this_dir
->type
= type
;
409 media_dirs
= this_dir
;
413 struct media_dir_s
* all_dirs
= media_dirs
;
414 while( all_dirs
->next
)
415 all_dirs
= all_dirs
->next
;
416 all_dirs
->next
= this_dir
;
420 fprintf(stderr
, "Media directory entry not understood! [%s]\n",
421 ary_options
[i
].value
);
425 case UPNPALBUMART_NAMES
:
426 for( string
= ary_options
[i
].value
; (word
= strtok(string
, "/")); string
= NULL
) {
427 struct album_art_name_s
* this_name
= calloc(1, sizeof(struct album_art_name_s
));
428 this_name
->name
= strdup(word
);
429 if( !album_art_names
)
431 album_art_names
= this_name
;
435 struct album_art_name_s
* all_names
= album_art_names
;
436 while( all_names
->next
)
437 all_names
= all_names
->next
;
438 all_names
->next
= this_name
;
443 path
= realpath(ary_options
[i
].value
, real_path
);
445 path
= (ary_options
[i
].value
);
446 make_dir(path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
447 if( access(path
, F_OK
) != 0 )
449 DPRINTF(E_FATAL
, L_GENERAL
, "Database path not accessible! [%s]\n", path
);
452 strncpy(db_path
, path
, PATH_MAX
);
455 path
= realpath(ary_options
[i
].value
, real_path
);
457 path
= (ary_options
[i
].value
);
458 make_dir(path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
459 if( access(path
, F_OK
) != 0 )
461 DPRINTF(E_FATAL
, L_GENERAL
, "Log path not accessible! [%s]\n", path
);
464 strncpy(log_path
, path
, PATH_MAX
);
467 if( (strcmp(ary_options
[i
].value
, "yes") != 0) && !atoi(ary_options
[i
].value
) )
468 CLEARFLAG(INOTIFY_MASK
);
471 if( (strcmp(ary_options
[i
].value
, "yes") == 0) || atoi(ary_options
[i
].value
) )
474 case ENABLE_DLNA_STRICT
:
475 if( (strcmp(ary_options
[i
].value
, "yes") == 0) || atoi(ary_options
[i
].value
) )
476 SETFLAG(DLNA_STRICT_MASK
);
479 fprintf(stderr
, "Unknown option in file %s\n",
485 /* command line arguments processing */
486 for(i
=1; i
<argc
; i
++)
490 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
492 else if(strcmp(argv
[i
], "--help")==0)
494 runtime_vars
.port
= -1;
497 else switch(argv
[i
][1])
501 runtime_vars
.notify_interval
= atoi(argv
[++i
]);
503 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
507 strncpy(serialnumber
, argv
[++i
], SERIALNUMBER_MAX_LEN
);
509 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
510 serialnumber
[SERIALNUMBER_MAX_LEN
-1] = '\0';
514 strncpy(modelnumber
, argv
[++i
], MODELNUMBER_MAX_LEN
);
516 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
517 modelnumber
[MODELNUMBER_MAX_LEN
-1] = '\0';
520 logfilename = argv[++i];
524 runtime_vars
.port
= atoi(argv
[++i
]);
526 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
530 pidfilename
= argv
[++i
];
532 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
541 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
546 int address_already_there
= 0;
549 for(j
=0; j
<n_lan_addr
; j
++)
551 struct lan_addr_s tmpaddr
;
552 parselanaddr(&tmpaddr
, argv
[i
]);
553 if(0 == strcmp(lan_addr
[j
].str
, tmpaddr
.str
))
554 address_already_there
= 1;
556 if(address_already_there
)
558 if(n_lan_addr
< MAX_LAN_ADDR
)
560 if(parselanaddr(&lan_addr
[n_lan_addr
], argv
[i
]) == 0)
565 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
566 MAX_LAN_ADDR
, argv
[i
]);
570 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
575 int address_already_there
= 0;
578 if( getifaddr(argv
[i
], ext_ip_addr
, INET_ADDRSTRLEN
) < 0 )
580 fprintf(stderr
, "Network interface '%s' not found.\n",
584 for(j
=0; j
<n_lan_addr
; j
++)
586 struct lan_addr_s tmpaddr
;
587 parselanaddr(&tmpaddr
, ext_ip_addr
);
588 if(0 == strcmp(lan_addr
[j
].str
, tmpaddr
.str
))
589 address_already_there
= 1;
591 if(address_already_there
)
593 if(n_lan_addr
< MAX_LAN_ADDR
)
595 if(parselanaddr(&lan_addr
[n_lan_addr
], ext_ip_addr
) == 0)
600 fprintf(stderr
, "Too many listening ips (max: %d), ignoring %s\n",
601 MAX_LAN_ADDR
, argv
[i
]);
605 fprintf(stderr
, "Option -%c takes one argument.\n", argv
[i
][1]);
608 i
++; /* discarding, the config file is already read */
611 runtime_vars
.port
= -1; // triggers help display
614 snprintf(real_path
, sizeof(real_path
), "rm -rf %s/*", db_path
);
618 printf("Version " MINIDLNA_VERSION
"\n");
622 fprintf(stderr
, "Unknown option: %s\n", argv
[i
]);
625 /* If no IP was specified, try to detect one */
628 if( (getsysaddr(ext_ip_addr
, INET_ADDRSTRLEN
) < 0) &&
629 (getifaddr("eth0", ext_ip_addr
, INET_ADDRSTRLEN
) < 0) &&
630 (getifaddr("eth1", ext_ip_addr
, INET_ADDRSTRLEN
) < 0) )
632 DPRINTF(E_OFF
, L_GENERAL
, "No IP address automatically detected!\n");
634 if( *ext_ip_addr
&& parselanaddr(&lan_addr
[n_lan_addr
], ext_ip_addr
) == 0 )
640 if( (n_lan_addr
==0) || (runtime_vars
.port
<0) )
642 fprintf(stderr
, "Usage:\n\t"
643 "%s [-d] [-f config_file]\n"
644 "\t\t[-a listening_ip] [-p port]\n"
645 /*"[-l logfile] " not functionnal */
646 "\t\t[-s serial] [-m model_number] \n"
647 "\t\t[-t notify_interval] [-P pid_filename]\n"
648 "\t\t[-w url] [-R] [-V] [-h]\n"
649 "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n"
650 "\tDefault pid file is %s.\n"
651 "\tWith -d minidlna will run in debug mode (not daemonize).\n"
652 "\t-w sets the presentation url. Default is http address on port 80\n"
653 "\t-h displays this text\n"
654 "\t-R forces a full rescan\n"
655 "\t-V print the version number\n",
656 argv
[0], pidfilename
);
663 log_init(NULL
, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=debug");
676 log_init("/var/log/upnp-av.log", "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn");
678 if( access(db_path
, F_OK
) != 0 )
679 make_dir(db_path
, S_ISVTX
|S_IRWXU
|S_IRWXG
|S_IRWXO
);
680 sprintf(real_path
, "%s/minidlna.log", log_path
);
681 log_init(real_path
, "general,artwork,database,inotify,scanner,metadata,http,ssdp,tivo=warn");
685 if(checkforrunning(pidfilename
) < 0)
687 DPRINTF(E_ERROR
, L_GENERAL
, "MiniDLNA is already running. EXITING.\n");
693 /* presentation url */
696 strncpy(presentationurl
, presurl
, PRESENTATIONURL_MAX_LEN
);
697 presentationurl
[PRESENTATIONURL_MAX_LEN
-1] = '\0';
702 snprintf(presentationurl
, PRESENTATIONURL_MAX_LEN
,
703 "http://%s/admin/", lan_addr
[0].str
);
705 snprintf(presentationurl
, PRESENTATIONURL_MAX_LEN
,
706 "http://%s/", lan_addr
[0].str
);
710 /* set signal handler */
711 signal(SIGCLD
, SIG_IGN
);
712 memset(&sa
, 0, sizeof(struct sigaction
));
713 sa
.sa_handler
= sigterm
;
714 if (sigaction(SIGTERM
, &sa
, NULL
))
716 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to set SIGTERM handler. EXITING.\n");
718 if (sigaction(SIGINT
, &sa
, NULL
))
720 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to set SIGINT handler. EXITING.\n");
723 if(signal(SIGPIPE
, SIG_IGN
) == SIG_ERR
) {
724 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to ignore SIGPIPE signals. EXITING.\n");
727 writepidfile(pidfilename
, pid
);
733 /* process HTTP or SSDP requests */
735 main(int argc
, char * * argv
)
738 int sudp
= -1, shttpl
= -1;
739 int snotify
[MAX_LAN_ADDR
];
740 LIST_HEAD(httplisthead
, upnphttp
) upnphttphead
;
741 struct upnphttp
* e
= 0;
742 struct upnphttp
* next
;
743 fd_set readset
; /* for select() */
745 struct timeval timeout
, timeofday
, lastnotifytime
= {0, 0}, lastupdatetime
= {0, 0};
747 int last_changecnt
= 0;
748 short int new_db
= 0;
749 pid_t scanner_pid
= 0;
750 pthread_t inotify_thread
= 0;
751 struct media_dir_s
*media_path
, *last_path
;
752 struct album_art_name_s
*art_names
, *last_name
;
754 unsigned short int beacon_interval
= 5;
756 struct sockaddr_in tivo_bcast
;
757 struct timeval lastbeacontime
= {0, 0};
761 setlocale(LC_MESSAGES
, "");
762 setlocale(LC_CTYPE
, "en_US.utf8");
763 textdomain("minidlna");
766 if(init(argc
, argv
) != 0)
770 DPRINTF(E_WARN
, L_GENERAL
, "Starting ReadyDLNA version " MINIDLNA_VERSION
".\n");
771 unlink("/ramfs/.upnp-av_scan");
773 DPRINTF(E_WARN
, L_GENERAL
, "Starting MiniDLNA version " MINIDLNA_VERSION
" [SQLite %s].\n", sqlite3_libversion());
774 unlink("/var/notice/dlna");
775 if( !sqlite3_threadsafe() )
777 DPRINTF(E_ERROR
, L_GENERAL
, "SQLite library is not threadsafe! "
778 "Scanning must be finished before file serving can begin, "
779 "and inotify will be disabled.\n");
781 if( sqlite3_libversion_number() < 3005001 )
783 DPRINTF(E_WARN
, L_GENERAL
, "SQLite library is old. Please use version 3.5.1 or newer.\n");
786 LIST_INIT(&upnphttphead
);
791 updateID
= sql_get_int_field(db
, "SELECT UPDATE_ID from SETTINGS");
793 if( sql_get_int_field(db
, "pragma user_version") != DB_VERSION
)
797 DPRINTF(E_WARN
, L_GENERAL
, "Creating new database...\n");
801 DPRINTF(E_WARN
, L_GENERAL
, "Database version mismatch; need to recreate...\n");
805 asprintf(&cmd
, "rm -rf %s/files.db %s/art_cache", db_path
, db_path
);
809 if( CreateDatabase() != 0 )
811 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: Failed to create sqlite database! Exiting...\n");
816 scanner_pid
= fork();
818 if( !scanner_pid
) // child (scanner) process
822 media_path
= media_dirs
;
823 art_names
= album_art_names
;
826 free(media_path
->path
);
827 last_path
= media_path
;
828 media_path
= media_path
->next
;
833 free(art_names
->name
);
834 last_name
= art_names
;
835 art_names
= art_names
->next
;
845 if( sqlite3_threadsafe() && sqlite3_libversion_number() >= 3005001 &&
846 GETFLAG(INOTIFY_MASK
) && pthread_create(&inotify_thread
, NULL
, start_inotify
, NULL
) )
848 DPRINTF(E_FATAL
, L_GENERAL
, "ERROR: pthread_create() failed for start_inotify.\n");
851 sudp
= OpenAndConfSSDPReceiveSocket(n_lan_addr
, lan_addr
);
854 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open socket for receiving SSDP. EXITING\n");
856 /* open socket for HTTP connections. Listen on the 1st LAN address */
857 shttpl
= OpenAndConfHTTPSocket((runtime_vars
.port
> 0) ? runtime_vars
.port
: 0);
860 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open socket for HTTP. EXITING\n");
862 if(runtime_vars
.port
<= 0)
864 struct sockaddr_in sockinfo
;
865 socklen_t len
= sizeof(struct sockaddr_in
);
866 if (getsockname(shttpl
, (struct sockaddr
*)&sockinfo
, &len
) < 0)
868 DPRINTF(E_FATAL
, L_GENERAL
, "getsockname(): %s. EXITING\n", strerror(errno
));
870 runtime_vars
.port
= ntohs(sockinfo
.sin_port
);
872 DPRINTF(E_WARN
, L_GENERAL
, "HTTP listening on port %d\n", runtime_vars
.port
);
874 /* open socket for sending notifications */
875 if(OpenAndConfSSDPNotifySockets(snotify
) < 0)
877 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open sockets for sending SSDP notify "
878 "messages. EXITING\n");
882 if( GETFLAG(TIVO_MASK
) )
884 DPRINTF(E_WARN
, L_GENERAL
, "TiVo support is enabled.\n");
885 /* Add TiVo-specific randomize function to sqlite */
886 if( sqlite3_create_function(db
, "tivorandom", 1, SQLITE_UTF8
, NULL
, &TiVoRandomSeedFunc
, NULL
, NULL
) != SQLITE_OK
)
888 DPRINTF(E_ERROR
, L_TIVO
, "ERROR: Failed to add sqlite randomize function for TiVo!\n");
890 /* open socket for sending Tivo notifications */
891 sbeacon
= OpenAndConfTivoBeaconSocket();
894 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to open sockets for sending Tivo beacon notify "
895 "messages. EXITING\n");
897 tivo_bcast
.sin_family
= AF_INET
;
898 tivo_bcast
.sin_addr
.s_addr
= htonl(getBcastAddress());
899 tivo_bcast
.sin_port
= htons(2190);
907 SendSSDPGoodbye(snotify
, n_lan_addr
);
912 /* Check if we need to send SSDP NOTIFY messages and do it if
914 if(gettimeofday(&timeofday
, 0) < 0)
916 DPRINTF(E_ERROR
, L_GENERAL
, "gettimeofday(): %s\n", strerror(errno
));
917 timeout
.tv_sec
= runtime_vars
.notify_interval
;
922 /* the comparaison is not very precise but who cares ? */
923 if(timeofday
.tv_sec
>= (lastnotifytime
.tv_sec
+ runtime_vars
.notify_interval
))
925 SendSSDPNotifies2(snotify
,
926 (unsigned short)runtime_vars
.port
,
927 (runtime_vars
.notify_interval
<< 1)+10);
928 memcpy(&lastnotifytime
, &timeofday
, sizeof(struct timeval
));
929 timeout
.tv_sec
= runtime_vars
.notify_interval
;
934 timeout
.tv_sec
= lastnotifytime
.tv_sec
+ runtime_vars
.notify_interval
936 if(timeofday
.tv_usec
> lastnotifytime
.tv_usec
)
938 timeout
.tv_usec
= 1000000 + lastnotifytime
.tv_usec
944 timeout
.tv_usec
= lastnotifytime
.tv_usec
- timeofday
.tv_usec
;
948 if( GETFLAG(TIVO_MASK
) )
950 if(timeofday
.tv_sec
>= (lastbeacontime
.tv_sec
+ beacon_interval
))
952 sendBeaconMessage(sbeacon
, &tivo_bcast
, sizeof(struct sockaddr_in
), 1);
953 memcpy(&lastbeacontime
, &timeofday
, sizeof(struct timeval
));
954 if( timeout
.tv_sec
> beacon_interval
)
956 timeout
.tv_sec
= beacon_interval
;
959 /* Beacons should be sent every 5 seconds or so for the first minute,
960 * then every minute or so thereafter. */
961 if( beacon_interval
== 5 && (timeofday
.tv_sec
- startup_time
) > 60 )
963 beacon_interval
= 60;
966 else if( timeout
.tv_sec
> (lastbeacontime
.tv_sec
+ beacon_interval
+ 1 - timeofday
.tv_sec
) )
968 timeout
.tv_sec
= lastbeacontime
.tv_sec
+ beacon_interval
- timeofday
.tv_sec
;
976 if( !scanner_pid
|| kill(scanner_pid
, 0) )
980 /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */
985 FD_SET(sudp
, &readset
);
986 max_fd
= MAX( max_fd
, sudp
);
991 FD_SET(shttpl
, &readset
);
992 max_fd
= MAX( max_fd
, shttpl
);
995 i
= 0; /* active HTTP connections count */
996 for(e
= upnphttphead
.lh_first
; e
!= NULL
; e
= e
->entries
.le_next
)
998 if((e
->socket
>= 0) && (e
->state
<= 2))
1000 FD_SET(e
->socket
, &readset
);
1001 max_fd
= MAX( max_fd
, e
->socket
);
1009 DPRINTF(E_DEBUG
, L_GENERAL
, "%d active incoming HTTP connections\n", i
);
1014 upnpevents_selectfds(&readset
, &writeset
, &max_fd
);
1016 if(select(max_fd
+1, &readset
, &writeset
, 0, &timeout
) < 0)
1018 if(quitting
) goto shutdown
;
1019 DPRINTF(E_ERROR
, L_GENERAL
, "select(all): %s\n", strerror(errno
));
1020 DPRINTF(E_FATAL
, L_GENERAL
, "Failed to select open sockets. EXITING\n");
1022 upnpevents_processfds(&readset
, &writeset
);
1023 /* process SSDP packets */
1024 if(sudp
>= 0 && FD_ISSET(sudp
, &readset
))
1026 /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/
1027 ProcessSSDPRequest(sudp
, (unsigned short)runtime_vars
.port
);
1029 /* increment SystemUpdateID if the content database has changed,
1030 * and if there is an active HTTP connection, at most once every 2 seconds */
1031 if( i
&& (time(NULL
) >= (lastupdatetime
.tv_sec
+ 2)) )
1033 if( sqlite3_total_changes(db
) != last_changecnt
)
1036 last_changecnt
= sqlite3_total_changes(db
);
1037 upnp_event_var_change_notify(EContentDirectory
);
1038 memcpy(&lastupdatetime
, &timeofday
, sizeof(struct timeval
));
1041 /* process active HTTP connections */
1042 for(e
= upnphttphead
.lh_first
; e
!= NULL
; e
= e
->entries
.le_next
)
1044 if( (e
->socket
>= 0) && (e
->state
<= 2)
1045 &&(FD_ISSET(e
->socket
, &readset
)) )
1047 Process_upnphttp(e
);
1050 /* process incoming HTTP connections */
1051 if(shttpl
>= 0 && FD_ISSET(shttpl
, &readset
))
1054 socklen_t clientnamelen
;
1055 struct sockaddr_in clientname
;
1056 clientnamelen
= sizeof(struct sockaddr_in
);
1057 shttp
= accept(shttpl
, (struct sockaddr
*)&clientname
, &clientnamelen
);
1060 DPRINTF(E_ERROR
, L_GENERAL
, "accept(http): %s\n", strerror(errno
));
1064 struct upnphttp
* tmp
= 0;
1065 DPRINTF(E_DEBUG
, L_GENERAL
, "HTTP connection from %s:%d\n",
1066 inet_ntoa(clientname
.sin_addr
),
1067 ntohs(clientname
.sin_port
) );
1068 /*if (fcntl(shttp, F_SETFL, O_NONBLOCK) < 0) {
1069 DPRINTF(E_ERROR, L_GENERAL, "fcntl F_SETFL, O_NONBLOCK");
1071 /* Create a new upnphttp object and add it to
1072 * the active upnphttp object list */
1073 tmp
= New_upnphttp(shttp
);
1076 tmp
->clientaddr
= clientname
.sin_addr
;
1077 LIST_INSERT_HEAD(&upnphttphead
, tmp
, entries
);
1081 DPRINTF(E_ERROR
, L_GENERAL
, "New_upnphttp() failed\n");
1086 /* delete finished HTTP connections */
1087 for(e
= upnphttphead
.lh_first
; e
!= NULL
; )
1089 next
= e
->entries
.le_next
;
1092 LIST_REMOVE(e
, entries
);
1100 /* kill the scanner */
1101 if( scanning
&& scanner_pid
)
1103 kill(scanner_pid
, 9);
1105 /* close out open sockets */
1106 while(upnphttphead
.lh_first
!= NULL
)
1108 e
= upnphttphead
.lh_first
;
1109 LIST_REMOVE(e
, entries
);
1113 if (sudp
>= 0) close(sudp
);
1114 if (shttpl
>= 0) close(shttpl
);
1116 if (sbeacon
>= 0) close(sbeacon
);
1119 if(SendSSDPGoodbye(snotify
, n_lan_addr
) < 0)
1121 DPRINTF(E_ERROR
, L_GENERAL
, "Failed to broadcast good-bye notifications\n");
1123 for(i
=0; i
<n_lan_addr
; i
++)
1126 if( inotify_thread
)
1127 pthread_join(inotify_thread
, NULL
);
1129 sql_exec(db
, "UPDATE SETTINGS set UPDATE_ID = %u", updateID
);
1132 media_path
= media_dirs
;
1133 art_names
= album_art_names
;
1136 free(media_path
->path
);
1137 last_path
= media_path
;
1138 media_path
= media_path
->next
;
1143 free(art_names
->name
);
1144 last_name
= art_names
;
1145 art_names
= art_names
->next
;
1149 if(unlink(pidfilename
) < 0)
1151 DPRINTF(E_ERROR
, L_GENERAL
, "Failed to remove pidfile %s: %s\n", pidfilename
, strerror(errno
));