diff options
author | Justin Maggard <jmaggard@users.sourceforce.net> | 2011-05-24 21:20:16 +0400 |
---|---|---|
committer | Justin Maggard <jmaggard@users.sourceforce.net> | 2011-05-24 21:20:16 +0400 |
commit | ccc7e35ee2b0047b7afb4f142387690f7b5f1b8f (patch) | |
tree | ab83b95459b5c171b390c78cd3ebbe3f4ac42231 | |
parent | 2fb59c582306d3792779f3cef3c7f9416130f8e0 (diff) |
* Add support for multiple network interfaces.
-rw-r--r-- | minidlna.c | 41 | ||||
-rw-r--r-- | tivo_beacon.c | 31 | ||||
-rw-r--r-- | upnphttp.c | 19 | ||||
-rw-r--r-- | upnphttp.h | 3 | ||||
-rw-r--r-- | upnpsoap.c | 65 | ||||
-rw-r--r-- | upnpsoap.h | 1 |
6 files changed, 105 insertions, 55 deletions
@@ -344,7 +344,7 @@ init(int argc, char * * argv) enum media_types type; char * path; char real_path[PATH_MAX]; - char ext_ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; + char ip_addr[INET_ADDRSTRLEN + 3] = {'\0'}; /* first check if "-f" option is used */ for(i=2; i<argc; i++) @@ -386,13 +386,25 @@ init(int argc, char * * argv) switch(ary_options[i].id) { case UPNPIFNAME: - if(getifaddr(ary_options[i].value, ext_ip_addr, sizeof(ext_ip_addr)) >= 0) + for( string = ary_options[i].value; (word = strtok(string, ",")); string = NULL ) { - if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) - n_lan_addr++; + if(n_lan_addr < MAX_LAN_ADDR) + { + if(getifaddr(word, ip_addr, sizeof(ip_addr)) >= 0) + { + if( *ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0 ) + if(n_lan_addr < MAX_LAN_ADDR) + n_lan_addr++; + } + else + fprintf(stderr, "Interface %s not found, ignoring.\n", word); + } + else + { + fprintf(stderr, "Too many listening ips (max: %d), ignoring %s\n", + MAX_LAN_ADDR, word); + } } - else - fprintf(stderr, "Interface %s not found, ignoring.\n", ary_options[i].value); break; case UPNPLISTENING_IP: if(n_lan_addr < MAX_LAN_ADDR) @@ -482,7 +494,8 @@ init(int argc, char * * argv) } break; case UPNPALBUMART_NAMES: - for( string = ary_options[i].value; (word = strtok(string, "/")); string = NULL ) { + for( string = ary_options[i].value; (word = strtok(string, "/")); string = NULL ) + { struct album_art_name_s * this_name = calloc(1, sizeof(struct album_art_name_s)); int len = strlen(word); if( word[len-1] == '*' ) @@ -649,7 +662,7 @@ init(int argc, char * * argv) int address_already_there = 0; int j; i++; - if( getifaddr(argv[i], ext_ip_addr, sizeof(ext_ip_addr)) < 0 ) + if( getifaddr(argv[i], ip_addr, sizeof(ip_addr)) < 0 ) { fprintf(stderr, "Network interface '%s' not found.\n", argv[i]); @@ -658,7 +671,7 @@ init(int argc, char * * argv) for(j=0; j<n_lan_addr; j++) { struct lan_addr_s tmpaddr; - parselanaddr(&tmpaddr, ext_ip_addr); + parselanaddr(&tmpaddr, ip_addr); if(0 == strcmp(lan_addr[j].str, tmpaddr.str)) address_already_there = 1; } @@ -666,7 +679,7 @@ init(int argc, char * * argv) break; if(n_lan_addr < MAX_LAN_ADDR) { - if(parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0) + if(parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0) n_lan_addr++; } else @@ -699,13 +712,13 @@ init(int argc, char * * argv) /* If no IP was specified, try to detect one */ if( n_lan_addr < 1 ) { - if( (getsysaddr(ext_ip_addr, sizeof(ext_ip_addr)) < 0) && - (getifaddr("eth0", ext_ip_addr, sizeof(ext_ip_addr)) < 0) && - (getifaddr("eth1", ext_ip_addr, sizeof(ext_ip_addr)) < 0) ) + if( (getsysaddr(ip_addr, sizeof(ip_addr)) < 0) && + (getifaddr("eth0", ip_addr, sizeof(ip_addr)) < 0) && + (getifaddr("eth1", ip_addr, sizeof(ip_addr)) < 0) ) { DPRINTF(E_OFF, L_GENERAL, "No IP address automatically detected!\n"); } - if( *ext_ip_addr && parselanaddr(&lan_addr[n_lan_addr], ext_ip_addr) == 0 ) + if( *ip_addr && parselanaddr(&lan_addr[n_lan_addr], ip_addr) == 0 ) { n_lan_addr++; } diff --git a/tivo_beacon.c b/tivo_beacon.c index 8de73af..5f11132 100644 --- a/tivo_beacon.c +++ b/tivo_beacon.c @@ -51,8 +51,6 @@ #include "upnpglobalvars.h" #include "log.h" -static struct aBeacon* topBeacon = NULL; - /* OpenAndConfHTTPSocket() : * setup the socket used to handle incoming HTTP connections. */ int @@ -187,8 +185,6 @@ rcvBeaconMessage(char * beacon) char * cp; char * scp; char * tokptr; - struct aBeacon * b; - time_t current; cp = strtok_r(beacon, "=\r\n", &tokptr); while( cp != NULL ) @@ -217,6 +213,14 @@ rcvBeaconMessage(char * beacon) if( strcmp(identity, uuidvalue) == 0) return 0; +#ifdef DEBUG + static struct aBeacon* topBeacon = NULL; + struct aBeacon * b; + time_t current; + int len; + char buf[32]; + static time_t lastSummary = 0; + current = time(NULL); for( b = topBeacon; b != NULL; b = b->next ) { @@ -241,10 +245,6 @@ rcvBeaconMessage(char * beacon) platform ? platform : "-", services ? services : "-" ); } -#ifdef DEBUG - int len; - char buf[32]; - static time_t lastSummary = 0; b->lastSeen = current; if( !lastSummary ) @@ -292,6 +292,21 @@ void ProcessTiVoBeacon(int s) (struct sockaddr *)&sendername, &len_r); if( n > 0 ) bufr[n] = '\0'; + + /* find which subnet the client is in */ + for(n = 0; n<n_lan_addr; n++) + { + if( (sendername.sin_addr.s_addr & lan_addr[n].mask.s_addr) + == (lan_addr[n].addr.s_addr & lan_addr[n].mask.s_addr)) + break; + } + if( n == n_lan_addr ) + { + DPRINTF(E_DEBUG, L_TIVO, "Ignoring TiVo beacon on other interface [%s]\n", + inet_ntoa(sendername.sin_addr)); + return; + } + for( cp = bufr; *cp; cp++ ) /* do nothing */; if( cp[-1] == '\r' || cp[-1] == '\n' ) @@ -263,7 +263,24 @@ intervening space) by either an integer or the keyword "infinite". */ } else if(strncasecmp(line, "Host", 4)==0) { + int i; h->reqflags |= FLAG_HOST; + p = colon + 1; + while(isspace(*p)) + p++; + for(n = 0; n<n_lan_addr; n++) + { + for(i=0; lan_addr[n].str[i]; i++) + { + if(lan_addr[n].str[i] != p[i]) + break; + } + if(!lan_addr[n].str[i]) + { + h->iface = n; + break; + } + } } else if(strncasecmp(line, "User-Agent", 10)==0) { @@ -1847,7 +1864,7 @@ SendResp_dlnafile(struct upnphttp * h, char * object) if( sql_get_int_field(db, "SELECT ID from CAPTIONS where ID = '%lld'", id) > 0 ) { strcatf(&str, "CaptionInfo.sec: http://%s:%d/Captions/%lld.srt\r\n", - lan_addr[0].str, runtime_vars.port, id); + lan_addr[h->iface].str, runtime_vars.port, id); } } @@ -57,6 +57,7 @@ enum httpCommands { struct upnphttp { int socket; struct in_addr clientaddr; /* client address */ + int iface; int state; char HttpVer[16]; /* request */ @@ -77,11 +78,11 @@ struct upnphttp { off_t req_RangeEnd; long int req_chunklen; uint32_t reqflags; - uint32_t respflags; /* response */ char * res_buf; int res_buflen; int res_buf_alloclen; + uint32_t respflags; /*int res_contentlen;*/ /*int res_contentoff;*/ /* header length */ LIST_ENTRY(upnphttp) entries; @@ -552,16 +552,16 @@ parse_sort_criteria(char * sortCriteria, int * error) inline static void add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, - char *detailID, struct Response *passed_args) + char *detailID, struct Response *args) { int dstw = reqw; int dsth = reqh; - if( passed_args->flags & FLAG_NO_RESIZE ) + if( args->flags & FLAG_NO_RESIZE ) return; - strcatf(passed_args->str, "<res "); - if( passed_args->filter & FILTER_RES_RESOLUTION ) + strcatf(args->str, "<res "); + if( args->filter & FILTER_RES_RESOLUTION ) { dstw = reqw; dsth = ((((reqw<<10)/srcw)*srch)>>10); @@ -569,42 +569,43 @@ add_resized_res(int srcw, int srch, int reqw, int reqh, char *dlna_pn, dsth = reqh; dstw = (((reqh<<10)/srch) * srcw>>10); } - strcatf(passed_args->str, "resolution=\"%dx%d\" ", dstw, dsth); + strcatf(args->str, "resolution=\"%dx%d\" ", dstw, dsth); } - strcatf(passed_args->str, "protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=%s;DLNA.ORG_CI=1\">" + strcatf(args->str, "protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=%s;DLNA.ORG_CI=1\">" "http://%s:%d/Resized/%s.jpg?width=%d,height=%d" "</res>", - dlna_pn, lan_addr[0].str, runtime_vars.port, detailID, dstw, dsth); + dlna_pn, lan_addr[args->iface].str, runtime_vars.port, + detailID, dstw, dsth); } inline static void add_res(char *size, char *duration, char *bitrate, char *sampleFrequency, char *nrAudioChannels, char *resolution, char *dlna_pn, char *mime, - char *detailID, char *ext, struct Response *passed_args) + char *detailID, char *ext, struct Response *args) { - strcatf(passed_args->str, "<res "); - if( size && (passed_args->filter & FILTER_RES_SIZE) ) { - strcatf(passed_args->str, "size=\"%s\" ", size); + strcatf(args->str, "<res "); + if( size && (args->filter & FILTER_RES_SIZE) ) { + strcatf(args->str, "size=\"%s\" ", size); } - if( duration && (passed_args->filter & FILTER_RES_DURATION) ) { - strcatf(passed_args->str, "duration=\"%s\" ", duration); + if( duration && (args->filter & FILTER_RES_DURATION) ) { + strcatf(args->str, "duration=\"%s\" ", duration); } - if( bitrate && (passed_args->filter & FILTER_RES_BITRATE) ) { - strcatf(passed_args->str, "bitrate=\"%s\" ", bitrate); + if( bitrate && (args->filter & FILTER_RES_BITRATE) ) { + strcatf(args->str, "bitrate=\"%s\" ", bitrate); } - if( sampleFrequency && (passed_args->filter & FILTER_RES_SAMPLEFREQUENCY) ) { - strcatf(passed_args->str, "sampleFrequency=\"%s\" ", sampleFrequency); + if( sampleFrequency && (args->filter & FILTER_RES_SAMPLEFREQUENCY) ) { + strcatf(args->str, "sampleFrequency=\"%s\" ", sampleFrequency); } - if( nrAudioChannels && (passed_args->filter & FILTER_RES_NRAUDIOCHANNELS) ) { - strcatf(passed_args->str, "nrAudioChannels=\"%s\" ", nrAudioChannels); + if( nrAudioChannels && (args->filter & FILTER_RES_NRAUDIOCHANNELS) ) { + strcatf(args->str, "nrAudioChannels=\"%s\" ", nrAudioChannels); } - if( resolution && (passed_args->filter & FILTER_RES_RESOLUTION) ) { - strcatf(passed_args->str, "resolution=\"%s\" ", resolution); + if( resolution && (args->filter & FILTER_RES_RESOLUTION) ) { + strcatf(args->str, "resolution=\"%s\" ", resolution); } - strcatf(passed_args->str, "protocolInfo=\"http-get:*:%s:%s\">" + strcatf(args->str, "protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/MediaItems/%s.%s" "</res>", - mime, dlna_pn, lan_addr[0].str, + mime, dlna_pn, lan_addr[args->iface].str, runtime_vars.port, detailID, ext); } @@ -756,14 +757,14 @@ callback(void *args, int argc, char **argv, char **azColName) ret = strcatf(str, "<res protocolInfo=\"http-get:*:image/jpeg:DLNA.ORG_PN=JPEG_TN\">" "http://%s:%d/AlbumArt/%s-%s.jpg" "</res>", - lan_addr[0].str, runtime_vars.port, album_art, detailID); + lan_addr[passed_args->iface].str, runtime_vars.port, album_art, detailID); } else if( passed_args->filter & FILTER_UPNP_ALBUMARTURI ) { ret = strcatf(str, "<upnp:albumArtURI"); if( passed_args->filter & FILTER_UPNP_ALBUMARTURI_DLNA_PROFILEID ) { ret = strcatf(str, " dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\""); } ret = strcatf(str, ">http://%s:%d/AlbumArt/%s-%s.jpg</upnp:albumArtURI>", - lan_addr[0].str, runtime_vars.port, album_art, detailID); + lan_addr[passed_args->iface].str, runtime_vars.port, album_art, detailID); } } #ifdef PFS_HACK @@ -774,12 +775,12 @@ callback(void *args, int argc, char **argv, char **azColName) ret = strcatf(str, "<upnp:albumArtURI>" "http://%s:%d/Thumbnails/%s.jpg" "</upnp:albumArtURI>", - lan_addr[0].str, runtime_vars.port, detailID); + lan_addr[passed_args->iface].str, runtime_vars.port, detailID); } else { ret = strcatf(str, "<upnp:albumArtURI>" "http://%s:%d/Resized/%s.jpg?width=160,height=160" "</upnp:albumArtURI>", - lan_addr[0].str, runtime_vars.port, detailID); + lan_addr[passed_args->iface].str, runtime_vars.port, detailID); } } #endif @@ -789,7 +790,7 @@ callback(void *args, int argc, char **argv, char **azColName) ret = strcatf(str, "<res protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/Thumbnails/%s.jpg" "</res>", - mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, + mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[passed_args->iface].str, runtime_vars.port, detailID); } add_res(size, duration, bitrate, sampleFrequency, nrAudioChannels, @@ -809,7 +810,7 @@ callback(void *args, int argc, char **argv, char **azColName) ret = strcatf(str, "<res protocolInfo=\"http-get:*:%s:%s\">" "http://%s:%d/Thumbnails/%s.jpg" "</res>", - mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[0].str, + mime, "DLNA.ORG_PN=JPEG_TN", lan_addr[passed_args->iface].str, runtime_vars.port, detailID); } } @@ -886,7 +887,7 @@ callback(void *args, int argc, char **argv, char **azColName) ret = strcatf(str, "<res protocolInfo=\"http-get:*:text/srt:*\">" "http://%s:%d/Captions/%s.srt" "</res>", - lan_addr[0].str, runtime_vars.port, detailID); + lan_addr[passed_args->iface].str, runtime_vars.port, detailID); } break; default: @@ -936,7 +937,7 @@ callback(void *args, int argc, char **argv, char **azColName) ret = strcatf(str, "dlna:profileID=\"JPEG_TN\" xmlns:dlna=\"urn:schemas-dlna-org:metadata-1-0/\""); } ret = strcatf(str, ">http://%s:%d/AlbumArt/%s-%s.jpg</upnp:albumArtURI>", - lan_addr[0].str, runtime_vars.port, album_art, detailID); + lan_addr[passed_args->iface].str, runtime_vars.port, album_art, detailID); } ret = strcatf(str, "</container>"); } @@ -997,6 +998,7 @@ BrowseContentDirectory(struct upnphttp * h, const char * action) str.off = sprintf(str.data, "%s", resp0); args.str = &str; /* See if we need to include DLNA namespace reference */ + args.iface = h->iface; args.filter = set_filter_flags(Filter, h->req_client); if( args.filter & FILTER_DLNA_NAMESPACE ) { @@ -1174,6 +1176,7 @@ SearchContentDirectory(struct upnphttp * h, const char * action) str.size = DEFAULT_RESP_SIZE; str.off = sprintf(str.data, "%s", resp0); /* See if we need to include DLNA namespace reference */ + args.iface = h->iface; args.filter = set_filter_flags(Filter, h->req_client); if( args.filter & FILTER_DLNA_NAMESPACE ) { @@ -37,6 +37,7 @@ struct Response int start; int returned; int requested; + int iface; uint32_t filter; uint32_t flags; enum client_types client; |