diff --git a/minidlna.c b/minidlna.c index 8fa3c61..6d42d84 100644 --- a/minidlna.c +++ b/minidlna.c @@ -266,7 +266,7 @@ init(int argc, char * * argv) if( parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) n_lan_addr++; runtime_vars.port = -1; - runtime_vars.notify_interval = 30; /* seconds between SSDP announces */ + runtime_vars.notify_interval = 895; /* seconds between SSDP announces */ /* read options file first since * command line arguments have final say */ @@ -597,23 +597,17 @@ main(int argc, char * * argv) { int i; int sudp = -1, shttpl = -1; - int snotify[MAX_LAN_ADDR]; LIST_HEAD(httplisthead, upnphttp) upnphttphead; struct upnphttp * e = 0; struct upnphttp * next; fd_set readset; /* for select() */ fd_set writeset; - struct timeval timeout, timeofday, lasttimeofday = {0, 0}, lastupdatetime = {0, 0}; + struct timeval timeout; int max_fd = -1; - int last_changecnt = 0; char * sql; short int new_db = 0; - pthread_t thread[2]; -#ifdef TIVO_SUPPORT - unsigned short int loop_cnt = 0; - int sbeacon = -1; - struct sockaddr_in tivo_bcast; -#endif + pthread_t thread[3]; + struct sockets notify; if(init(argc, argv) != 0) return 1; @@ -702,7 +696,7 @@ main(int argc, char * * argv) DPRINTF(E_WARN, L_GENERAL, "HTTP listening on port %d\n", runtime_vars.port); /* open socket for sending notifications */ - if(OpenAndConfSSDPNotifySockets(snotify) < 0) + if(OpenAndConfSSDPNotifySockets(notify.snotify) < 0) { DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending SSDP notify " "messages. EXITING\n"); @@ -718,91 +712,27 @@ main(int argc, char * * argv) DPRINTF(E_ERROR, L_TIVO, "ERROR: Failed to add sqlite randomize function for TiVo!\n"); } /* open socket for sending Tivo notifications */ - sbeacon = OpenAndConfTivoBeaconSocket(); - if(sbeacon < 0) + notify.sbeacon = OpenAndConfTivoBeaconSocket(); + if(notify.sbeacon < 0) { DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify " "messages. EXITING\n"); } - tivo_bcast.sin_family = AF_INET; - tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress()); - tivo_bcast.sin_port = htons( 2190 ); + memset(¬ify.tivo_bcast.sin_zero, '\0', sizeof(notify.tivo_bcast.sin_zero)); + notify.tivo_bcast.sin_family = AF_INET; + notify.tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress()); + notify.tivo_bcast.sin_port = htons( 2190 ); } #endif - SendSSDPGoodbye(snotify, n_lan_addr); + SendSSDPGoodbye(notify.snotify, n_lan_addr); + notify.timeout = &timeout; + pthread_create(&thread[2], NULL, start_notify, ¬ify); + sleep(1); /* main loop */ while(!quitting) { - /* Check if we need to send SSDP NOTIFY messages and do it if - * needed */ - /* Also check if we need to increment our SystemUpdateID - * at most once every 2 seconds */ - if(gettimeofday(&timeofday, 0) < 0) - { - DPRINTF(E_ERROR, L_GENERAL, "gettimeofday(): %s\n", strerror(errno)); - timeout.tv_sec = runtime_vars.notify_interval; - timeout.tv_usec = 0; - } - else - { - /* the comparaison is not very precise but who cares ? */ - if(timeofday.tv_sec >= (lasttimeofday.tv_sec + runtime_vars.notify_interval)) - { - SendSSDPNotifies2(snotify, - (unsigned short)runtime_vars.port, - (runtime_vars.notify_interval << 1)+10); - memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval)); - timeout.tv_sec = runtime_vars.notify_interval; - timeout.tv_usec = 0; - } - else - { - timeout.tv_sec = lasttimeofday.tv_sec + runtime_vars.notify_interval - - timeofday.tv_sec; - if(timeofday.tv_usec > lasttimeofday.tv_usec) - { - timeout.tv_usec = 1000000 + lasttimeofday.tv_usec - - timeofday.tv_usec; - timeout.tv_sec--; - } - else - { - timeout.tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec; - } - } - if(timeofday.tv_sec >= (lastupdatetime.tv_sec + 2)) - { - if( sqlite3_total_changes(db) != last_changecnt ) - { - updateID++; - last_changecnt = sqlite3_total_changes(db); - upnp_event_var_change_notify(EContentDirectory); - } - #ifdef TIVO_SUPPORT - if( GETFLAG(TIVOMASK) ) - { - if( loop_cnt < 10 ) - { - sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1); - loop_cnt++; - } - else - { - if( loop_cnt == 30 ) - { - sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1); - loop_cnt = 10; - } - loop_cnt++; - } - } - #endif - memcpy(&lastupdatetime, &timeofday, sizeof(struct timeval)); - } - } - /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ FD_ZERO(&readset); @@ -923,15 +853,15 @@ shutdown: if (sudp >= 0) close(sudp); if (shttpl >= 0) close(shttpl); #ifdef TIVO_SUPPORT - if (sbeacon >= 0) close(sbeacon); + if (notify.sbeacon >= 0) close(notify.sbeacon); #endif - if(SendSSDPGoodbye(snotify, n_lan_addr) < 0) + if(SendSSDPGoodbye(notify.snotify, n_lan_addr) < 0) { DPRINTF(E_ERROR, L_GENERAL, "Failed to broadcast good-bye notifications\n"); } for(i=0; i #include #include +#include #include #include "config.h" @@ -19,6 +20,8 @@ #include "minidlnapath.h" #include "upnphttp.h" #include "upnpglobalvars.h" +#include "upnpevents.h" +#include "tivo_beacon.h" #include "minissdp.h" #include "log.h" @@ -211,7 +214,7 @@ SendSSDPAnnounce2(int s, struct sockaddr_in sockname, int st_no, * follow guideline from document "UPnP Device Architecture 1.0" * put in uppercase. * DATE: is recommended - * SERVER: OS/ver UPnP/1.0 miniupnpd/1.0 + * SERVER: OS/ver UPnP/1.0 minidlna/1.0 * - check what to put in the 'Cache-Control' header * */ char szTime[30]; @@ -219,7 +222,7 @@ SendSSDPAnnounce2(int s, struct sockaddr_in sockname, int st_no, strftime(szTime, 30,"%a, %d %b %Y %H:%M:%S GMT" , gmtime(&tTime)); l = snprintf(buf, sizeof(buf), "HTTP/1.1 200 OK\r\n" - "CACHE-CONTROL: max-age=1810\r\n" + "CACHE-CONTROL: max-age=%u\r\n" "DATE: %s\r\n" "ST: %s%s\r\n" "USN: %s%s%s%s\r\n" @@ -228,6 +231,7 @@ SendSSDPAnnounce2(int s, struct sockaddr_in sockname, int st_no, "LOCATION: http://%s:%u" ROOTDESC_PATH "\r\n" "Content-Length: 0\r\n" "\r\n", + (runtime_vars.notify_interval<<1)+10, szTime, known_service_types[st_no], (st_no>1?"1":""), uuidvalue, (st_no>0?"::":""), (st_no>0?known_service_types[st_no]:""), (st_no>1?"1":""), @@ -463,35 +467,118 @@ SendSSDPGoodbye(int * sockets, int n_sockets) int i, j; char bufr[512]; - memset(&sockname, 0, sizeof(struct sockaddr_in)); - sockname.sin_family = AF_INET; - sockname.sin_port = htons(SSDP_PORT); - sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); + memset(&sockname, 0, sizeof(struct sockaddr_in)); + sockname.sin_family = AF_INET; + sockname.sin_port = htons(SSDP_PORT); + sockname.sin_addr.s_addr = inet_addr(SSDP_MCAST_ADDR); for(j=0; j1?"1":""), - uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") ); - //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr); - n = sendto(sockets[j], bufr, l, 0, - (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); - if(n < 0) + for(i=0; known_service_types[i]; i++) { - DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno)); - return -1; + l = snprintf(bufr, sizeof(bufr), + "NOTIFY * HTTP/1.1\r\n" + "HOST:%s:%d\r\n" + "NT:%s%s\r\n" + "USN:%s%s%s%s\r\n" + "NTS:ssdp:byebye\r\n" + "\r\n", + SSDP_MCAST_ADDR, SSDP_PORT, + known_service_types[i], (i>1?"1":""), + uuidvalue, (i>0?"::":""), (i>0?known_service_types[i]:""), (i>1?"1":"") ); + //DEBUG DPRINTF(E_DEBUG, L_SSDP, "Sending NOTIFY:\n%s", bufr); + n = sendto(sockets[j], bufr, l, 0, + (struct sockaddr *)&sockname, sizeof(struct sockaddr_in) ); + if(n < 0) + { + DPRINTF(E_ERROR, L_SSDP, "sendto(udp_shutdown=%d): %s\n", sockets[j], strerror(errno)); + return -1; + } } - } } return 0; } +void * +start_notify(void * arg) +{ + struct sockets *s = (struct sockets *)arg; + struct timeval timeofday, lasttimeofday = {0, 0}, lastupdatetime = {0, 0}; + int last_changecnt = 0; +#ifdef TIVO_SUPPORT + short int loop_cnt = 0; +#endif + + while(1) + { + /* Check if we need to send SSDP NOTIFY messages and do it if needed */ + /* Also check if we need to increment our SystemUpdateID + * at most once every 2 seconds */ + if(gettimeofday(&timeofday, 0) < 0) + { + DPRINTF(E_ERROR, L_GENERAL, "gettimeofday(): %s\n", strerror(errno)); + s->timeout->tv_sec = runtime_vars.notify_interval; + s->timeout->tv_usec = 0; + sleep(2); + continue; + } + /* the comparaison is not very precise but who cares ? */ + if(timeofday.tv_sec >= (lasttimeofday.tv_sec + runtime_vars.notify_interval)) + { + SendSSDPNotifies2(s->snotify, + runtime_vars.port, + (runtime_vars.notify_interval << 1)+10); + memcpy(&lasttimeofday, &timeofday, sizeof(struct timeval)); + s->timeout->tv_sec = runtime_vars.notify_interval; + s->timeout->tv_usec = 0; + } + else + { + s->timeout->tv_sec = lasttimeofday.tv_sec + runtime_vars.notify_interval + - timeofday.tv_sec; + if(timeofday.tv_usec > lasttimeofday.tv_usec) + { + s->timeout->tv_usec = 1000000 + lasttimeofday.tv_usec + - timeofday.tv_usec; + s->timeout->tv_sec--; + } + else + { + s->timeout->tv_usec = lasttimeofday.tv_usec - timeofday.tv_usec; + } + } + if(timeofday.tv_sec >= (lastupdatetime.tv_sec + 2)) + { + if( sqlite3_total_changes(db) != last_changecnt ) + { + updateID++; + last_changecnt = sqlite3_total_changes(db); + upnp_event_var_change_notify(EContentDirectory); + } +#ifdef TIVO_SUPPORT + if( GETFLAG(TIVOMASK) ) + { + if( loop_cnt < 20 ) + { + if(loop_cnt % 3 == 0) + sendBeaconMessage(s->sbeacon, &(s->tivo_bcast), sizeof(struct sockaddr_in), 1); + loop_cnt++; + } + else + { + if( loop_cnt == 50 ) + { + sendBeaconMessage(s->sbeacon, &(s->tivo_bcast), sizeof(struct sockaddr_in), 1); + loop_cnt = 20; + } + loop_cnt++; + } + } +#endif + memcpy(&lastupdatetime, &timeofday, sizeof(struct timeval)); + } + sleep(1); + } + + return NULL; +} diff --git a/minissdp.h b/minissdp.h index 5767f90..a8627ef 100644 --- a/minissdp.h +++ b/minissdp.h @@ -8,6 +8,16 @@ /*#include "minidlnatypes.h"*/ +struct sockets +{ + int snotify[MAX_LAN_ADDR]; +#ifdef TIVO_SUPPORT + int sbeacon; + struct sockaddr_in tivo_bcast; +#endif + struct timeval *timeout; +}; + int OpenAndConfSSDPReceiveSocket(); /* OpenAndConfSSDPReceiveSocket(int n_lan_addr, struct lan_addr_s * lan_addr);*/ @@ -39,5 +49,8 @@ ProcessSSDPRequest(int s, unsigned short port); int SendSSDPGoodbye(int * sockets, int n); +void * +start_notify(void * arg); + #endif