From 94989f8b15b30862a5bf973eb39f428c78d5cc41 Mon Sep 17 00:00:00 2001 From: Justin Maggard Date: Mon, 15 Jun 2009 22:37:49 +0000 Subject: [PATCH] * Take notifications back out of their own thread, and rely on select timeouts. * Increment SystemUpdateID as necessary just before processing new HTTP requests. --- minidlna.c | 160 ++++++++++++++++++++++++++++++----------------- minissdp.c | 88 +------------------------- minissdp.h | 13 ---- upnpglobalvars.h | 3 +- 4 files changed, 103 insertions(+), 161 deletions(-) diff --git a/minidlna.c b/minidlna.c index 644d132..6b71a29 100644 --- a/minidlna.c +++ b/minidlna.c @@ -118,29 +118,9 @@ sigterm(int sig) /* record the startup time, for returning uptime */ static void -set_startup_time(int sysuptime) +set_startup_time(void) { startup_time = time(NULL); - if(sysuptime) - { - /* use system uptime instead of daemon uptime */ - char buff[64]; - int uptime, fd; - fd = open("/proc/uptime", O_RDONLY); - if(fd < 0) - { - DPRINTF(E_ERROR, L_GENERAL, "Error opening /proc/uptime: %s\n", strerror(errno)); - } - else - { - memset(buff, 0, sizeof(buff)); - read(fd, buff, sizeof(buff) - 1); - uptime = atoi(buff); - DPRINTF(E_DEBUG, L_GENERAL, "system uptime is %d seconds\n", uptime); - close(fd); - startup_time -= uptime; - } - } } /* parselanaddr() @@ -304,10 +284,6 @@ init(int argc, char * * argv) case UPNPNOTIFY_INTERVAL: runtime_vars.notify_interval = atoi(ary_options[i].value); break; - case UPNPSYSTEM_UPTIME: - if(strcmp(ary_options[i].value, "yes") == 0) - SETFLAG(SYSUPTIMEMASK); /*sysuptime = 1;*/ - break; case UPNPSERIAL: strncpy(serialnumber, ary_options[i].value, SERIALNUMBER_MAX_LEN); serialnumber[SERIALNUMBER_MAX_LEN-1] = '\0'; @@ -429,10 +405,6 @@ init(int argc, char * * argv) fprintf(stderr, "Option -%c takes one argument.\n", argv[i][1]); modelnumber[MODELNUMBER_MAX_LEN-1] = '\0'; break; - case 'U': - /*sysuptime = 1;*/ - SETFLAG(SYSUPTIMEMASK); - break; /*case 'l': logfilename = argv[++i]; break;*/ @@ -501,20 +473,14 @@ init(int argc, char * * argv) { fprintf(stderr, "Usage:\n\t" "%s [-f config_file] [-i ext_ifname] [-o ext_ip]\n" - "\t\t[-a listening_ip] [-p port] [-d] [-L] [-U] [-S]\n" + "\t\t[-a listening_ip] [-p port] [-d]\n" /*"[-l logfile] " not functionnal */ "\t\t[-s serial] [-m model_number] \n" "\t\t[-t notify_interval] [-P pid_filename]\n" - "\t\t[-B down up] [-w url]\n" - "\nNotes:\n\tThere can be one or several listening_ips.\n" - "\tNotify interval is in seconds. Default is 30 seconds.\n" + "\t\t[-w url]\n" + "\nNotes:\n\tNotify interval is in seconds. Default is 895 seconds.\n" "\tDefault pid file is %s.\n" - "\tWith -d miniupnpd will run as a standard program.\n" - "\t-L sets packet log in pf and ipf on.\n" - "\t-S sets \"secure\" mode : clients can only add mappings to their own ip\n" - "\t-U causes miniupnpd to report system uptime instead " - "of daemon uptime.\n" - "\t-B sets bitrates reported by daemon in bits per second.\n" + "\tWith -d minidlna will run in debug mode (not daemonize).\n" "\t-w sets the presentation url. Default is http address on port 80\n" "\t-V print the version number\n" "", argv[0], pidfilename); @@ -549,7 +515,7 @@ init(int argc, char * * argv) return 1; } - set_startup_time(GETFLAG(SYSUPTIMEMASK)/*sysuptime*/); + set_startup_time(); /* presentation url */ if(presurl) @@ -597,17 +563,24 @@ 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; + struct timeval timeout, timeofday, lastnotifytime = {0, 0}, lastupdatetime = {0, 0}; int max_fd = -1; + int last_changecnt = 0; char * sql; short int new_db = 0; - pthread_t thread[3]; - struct sockets notify; + pthread_t thread[2]; +#ifdef TIVO_SUPPORT + unsigned short int beacon_interval = 5; + int sbeacon = -1; + struct sockaddr_in tivo_bcast; + struct timeval lastbeacontime = {0, 0}; +#endif if(init(argc, argv) != 0) return 1; @@ -696,7 +669,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(notify.snotify) < 0) + if(OpenAndConfSSDPNotifySockets(snotify) < 0) { DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending SSDP notify " "messages. EXITING\n"); @@ -712,31 +685,89 @@ 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 */ - notify.sbeacon = OpenAndConfTivoBeaconSocket(); - if(notify.sbeacon < 0) + sbeacon = OpenAndConfTivoBeaconSocket(); + if(sbeacon < 0) { DPRINTF(E_FATAL, L_GENERAL, "Failed to open sockets for sending Tivo beacon notify " "messages. EXITING\n"); } - 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 ); + tivo_bcast.sin_family = AF_INET; + tivo_bcast.sin_addr.s_addr = htonl(getBcastAddress()); + tivo_bcast.sin_port = htons( 2190 ); } else { - notify.sbeacon = -1; + sbeacon = -1; } #endif - SendSSDPGoodbye(notify.snotify, n_lan_addr); + SendSSDPGoodbye(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 */ + 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 >= (lastnotifytime.tv_sec + runtime_vars.notify_interval)) + { + SendSSDPNotifies2(snotify, + (unsigned short)runtime_vars.port, + (runtime_vars.notify_interval << 1)+10); + memcpy(&lastnotifytime, &timeofday, sizeof(struct timeval)); + timeout.tv_sec = runtime_vars.notify_interval; + timeout.tv_usec = 0; + } + else + { + timeout.tv_sec = lastnotifytime.tv_sec + runtime_vars.notify_interval + - timeofday.tv_sec; + if(timeofday.tv_usec > lastnotifytime.tv_usec) + { + timeout.tv_usec = 1000000 + lastnotifytime.tv_usec + - timeofday.tv_usec; + timeout.tv_sec--; + } + else + { + timeout.tv_usec = lastnotifytime.tv_usec - timeofday.tv_usec; + } + } +#ifdef TIVO_SUPPORT + if( GETFLAG(TIVOMASK) ) + { + if(timeofday.tv_sec >= (lastbeacontime.tv_sec + beacon_interval)) + { + sendBeaconMessage(sbeacon, &tivo_bcast, sizeof(struct sockaddr_in), 1); + memcpy(&lastbeacontime, &timeofday, sizeof(struct timeval)); + if( timeout.tv_sec > beacon_interval ) + { + timeout.tv_sec = beacon_interval; + timeout.tv_usec = 0; + } + /* Beacons should be sent every 5 seconds or so for the first minute, + * then every minute or so thereafter. */ + if( beacon_interval == 5 && (timeofday.tv_sec - startup_time) > 60 ) + { + beacon_interval = 60; + } + } + else if( timeout.tv_sec > (lastbeacontime.tv_sec + beacon_interval + 1 - timeofday.tv_sec) ) + { + timeout.tv_sec = lastbeacontime.tv_sec + beacon_interval - timeofday.tv_sec; + } + } +#endif + } + /* select open sockets (SSDP, HTTP listen, and all HTTP soap sockets) */ FD_ZERO(&readset); @@ -786,8 +817,19 @@ main(int argc, char * * argv) /*DPRINTF(E_DEBUG, L_GENERAL, "Received UDP Packet\n");*/ ProcessSSDPRequest(sudp, (unsigned short)runtime_vars.port); } + /* increment SystemUpdateID if the content database has changed, + * and if there is an active HTTP connection, at most once every 2 seconds */ + if( i && (time(NULL) >= (lastupdatetime.tv_sec + 2)) ) + { + if( sqlite3_total_changes(db) != last_changecnt ) + { + updateID++; + last_changecnt = sqlite3_total_changes(db); + upnp_event_var_change_notify(EContentDirectory); + memcpy(&lastupdatetime, &timeofday, sizeof(struct timeval)); + } + } /* process active HTTP connections */ - /* LIST_FOREACH macro is not available under linux */ for(e = upnphttphead.lh_first; e != NULL; e = e->entries.le_next) { if( (e->socket >= 0) && (e->state <= 2) @@ -857,15 +899,15 @@ shutdown: if (sudp >= 0) close(sudp); if (shttpl >= 0) close(shttpl); #ifdef TIVO_SUPPORT - if (notify.sbeacon >= 0) close(notify.sbeacon); + if (sbeacon >= 0) close(sbeacon); #endif - if(SendSSDPGoodbye(notify.snotify, n_lan_addr) < 0) + if(SendSSDPGoodbye(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" @@ -20,8 +19,6 @@ #include "minidlnapath.h" #include "upnphttp.h" #include "upnpglobalvars.h" -#include "upnpevents.h" -#include "tivo_beacon.h" #include "minissdp.h" #include "log.h" @@ -306,6 +303,7 @@ SendSSDPNotifies2(int * sockets, unsigned int lifetime)*/ { int i; + DPRINTF(E_DEBUG, L_SSDP, "Sending SSDP notifies\n"); for(i=0; itimeout->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 a8627ef..5767f90 100644 --- a/minissdp.h +++ b/minissdp.h @@ -8,16 +8,6 @@ /*#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);*/ @@ -49,8 +39,5 @@ ProcessSSDPRequest(int s, unsigned short port); int SendSSDPGoodbye(int * sockets, int n); -void * -start_notify(void * arg); - #endif diff --git a/upnpglobalvars.h b/upnpglobalvars.h index f9f23b8..dc53fd8 100644 --- a/upnpglobalvars.h +++ b/upnpglobalvars.h @@ -89,8 +89,7 @@ extern struct runtime_vars_s runtime_vars; /* runtime boolean flags */ extern int runtime_flags; #define INOTIFYMASK 0x0001 -#define SYSUPTIMEMASK 0x0002 -#define TIVOMASK 0x0004 +#define TIVOMASK 0x0002 #define SETFLAG(mask) runtime_flags |= mask #define GETFLAG(mask) runtime_flags & mask